1- // CHECKY-MONKEY — Zig FFI Implementation
1+ // CHECKY_MONKEY FFI Implementation
22//
3- // This module implements the binary interface for the Checky-Monkey bot.
4- // It provides the low-level hooks for system interaction and automation.
3+ // This module implements the C-compatible FFI declared in src/abi/Foreign.idr
4+ // All types and layouts must match the Idris2 ABI definitions.
5+ //
6+ // SPDX-License-Identifier: PMPL-1.0-or-later
57
68const std = @import ("std" );
79
10+ // Version information (keep in sync with project)
811const VERSION = "0.1.0" ;
9- const BUILD_INFO = "Checky-Monkey ( Zig) - Automation Kernel" ;
12+ const BUILD_INFO = "CHECKY_MONKEY built with Zig " ++ @import ( "builtin" ). zig_version_string ;
1013
11- /// THREAD-LOCAL ERRORS: Stores the last error message.
14+ /// Thread-local error storage
1215threadlocal var last_error : ? []const u8 = null ;
1316
17+ /// Set the last error message
18+ fn setError (msg : []const u8 ) void {
19+ last_error = msg ;
20+ }
21+
22+ /// Clear the last error
23+ fn clearError () void {
24+ last_error = null ;
25+ }
26+
1427//==============================================================================
15- // CORE TYPES: ABI-Stable Representations
28+ // Core Types (must match src/abi/Types.idr)
1629//==============================================================================
1730
18- /// RESULT CODES: Must match the ` Result` type in `ABI/Types.idr`.
31+ /// Result codes (must match Idris2 Result type)
1932pub const Result = enum (c_int ) {
2033 ok = 0 ,
2134 @"error" = 1 ,
@@ -24,37 +37,238 @@ pub const Result = enum(c_int) {
2437 null_pointer = 4 ,
2538};
2639
27- /// OPAQUE HANDLE: Internal bot state.
40+ /// Library handle (opaque to prevent direct access)
2841pub const Handle = opaque {
42+ // Internal state hidden from C
2943 allocator : std.mem.Allocator ,
3044 initialized : bool ,
45+ // Add your fields here
3146};
3247
3348//==============================================================================
34- // LIFECYCLE: Setup & Teardown
49+ // Library Lifecycle
3550//==============================================================================
3651
37- /// INITIALIZATION: Prepares the bot kernel.
52+ /// Initialize the library
53+ /// Returns a handle, or null on failure
3854export fn checky_monkey_init () ? * Handle {
3955 const allocator = std .heap .c_allocator ;
4056
4157 const handle = allocator .create (Handle ) catch {
42- last_error = "FFI: Memory allocation failed" ;
58+ setError ( "Failed to allocate handle" ) ;
4359 return null ;
4460 };
4561
62+ // Initialize handle
4663 handle .* = .{
4764 .allocator = allocator ,
4865 .initialized = true ,
4966 };
5067
68+ clearError ();
5169 return handle ;
5270}
5371
54- /// CLEANUP: Stops the bot kernel and releases resources.
72+ /// Free the library handle
5573export fn checky_monkey_free (handle : ? * Handle ) void {
5674 const h = handle orelse return ;
5775 const allocator = h .allocator ;
76+
77+ // Clean up resources
5878 h .initialized = false ;
79+
5980 allocator .destroy (h );
81+ clearError ();
82+ }
83+
84+ //==============================================================================
85+ // Core Operations
86+ //==============================================================================
87+
88+ /// Process data (example operation)
89+ export fn checky_monkey_process (handle : ? * Handle , input : u32 ) Result {
90+ const h = handle orelse {
91+ setError ("Null handle" );
92+ return .null_pointer ;
93+ };
94+
95+ if (! h .initialized ) {
96+ setError ("Handle not initialized" );
97+ return .@"error" ;
98+ }
99+
100+ // Example processing logic
101+ _ = input ;
102+
103+ clearError ();
104+ return .ok ;
105+ }
106+
107+ //==============================================================================
108+ // String Operations
109+ //==============================================================================
110+
111+ /// Get a string result (example)
112+ /// Caller must free the returned string
113+ export fn checky_monkey_get_string (handle : ? * Handle ) ? [* :0 ]const u8 {
114+ const h = handle orelse {
115+ setError ("Null handle" );
116+ return null ;
117+ };
118+
119+ if (! h .initialized ) {
120+ setError ("Handle not initialized" );
121+ return null ;
122+ }
123+
124+ // Example: allocate and return a string
125+ const result = h .allocator .dupeZ (u8 , "Example result" ) catch {
126+ setError ("Failed to allocate string" );
127+ return null ;
128+ };
129+
130+ clearError ();
131+ return result .ptr ;
132+ }
133+
134+ /// Free a string allocated by the library
135+ export fn checky_monkey_free_string (str : ? [* :0 ]const u8 ) void {
136+ const s = str orelse return ;
137+ const allocator = std .heap .c_allocator ;
138+
139+ const slice = std .mem .span (s );
140+ allocator .free (slice );
141+ }
142+
143+ //==============================================================================
144+ // Array/Buffer Operations
145+ //==============================================================================
146+
147+ /// Process an array of data
148+ export fn checky_monkey_process_array (
149+ handle : ? * Handle ,
150+ buffer : ? [* ]const u8 ,
151+ len : u32 ,
152+ ) Result {
153+ const h = handle orelse {
154+ setError ("Null handle" );
155+ return .null_pointer ;
156+ };
157+
158+ const buf = buffer orelse {
159+ setError ("Null buffer" );
160+ return .null_pointer ;
161+ };
162+
163+ if (! h .initialized ) {
164+ setError ("Handle not initialized" );
165+ return .@"error" ;
166+ }
167+
168+ // Access the buffer
169+ const data = buf [0.. len ];
170+ _ = data ;
171+
172+ // Process data here
173+
174+ clearError ();
175+ return .ok ;
176+ }
177+
178+ //==============================================================================
179+ // Error Handling
180+ //==============================================================================
181+
182+ /// Get the last error message
183+ /// Returns null if no error
184+ export fn checky_monkey_last_error () ? [* :0 ]const u8 {
185+ const err = last_error orelse return null ;
186+
187+ // Return C string (static storage, no need to free)
188+ const allocator = std .heap .c_allocator ;
189+ const c_str = allocator .dupeZ (u8 , err ) catch return null ;
190+ return c_str .ptr ;
191+ }
192+
193+ //==============================================================================
194+ // Version Information
195+ //==============================================================================
196+
197+ /// Get the library version
198+ export fn checky_monkey_version () [* :0 ]const u8 {
199+ return VERSION .ptr ;
200+ }
201+
202+ /// Get build information
203+ export fn checky_monkey_build_info () [* :0 ]const u8 {
204+ return BUILD_INFO .ptr ;
205+ }
206+
207+ //==============================================================================
208+ // Callback Support
209+ //==============================================================================
210+
211+ /// Callback function type (C ABI)
212+ pub const Callback = * const fn (u64 , u32 ) callconv (.C ) u32 ;
213+
214+ /// Register a callback
215+ export fn checky_monkey_register_callback (
216+ handle : ? * Handle ,
217+ callback : ? Callback ,
218+ ) Result {
219+ const h = handle orelse {
220+ setError ("Null handle" );
221+ return .null_pointer ;
222+ };
223+
224+ const cb = callback orelse {
225+ setError ("Null callback" );
226+ return .null_pointer ;
227+ };
228+
229+ if (! h .initialized ) {
230+ setError ("Handle not initialized" );
231+ return .@"error" ;
232+ }
233+
234+ // Store callback for later use
235+ _ = cb ;
236+
237+ clearError ();
238+ return .ok ;
239+ }
240+
241+ //==============================================================================
242+ // Utility Functions
243+ //==============================================================================
244+
245+ /// Check if handle is initialized
246+ export fn checky_monkey_is_initialized (handle : ? * Handle ) u32 {
247+ const h = handle orelse return 0 ;
248+ return if (h .initialized ) 1 else 0 ;
249+ }
250+
251+ //==============================================================================
252+ // Tests
253+ //==============================================================================
254+
255+ test "lifecycle" {
256+ const handle = checky_monkey_init () orelse return error .InitFailed ;
257+ defer checky_monkey_free (handle );
258+
259+ try std .testing .expect (checky_monkey_is_initialized (handle ) == 1 );
260+ }
261+
262+ test "error handling" {
263+ const result = checky_monkey_process (null , 0 );
264+ try std .testing .expectEqual (Result .null_pointer , result );
265+
266+ const err = checky_monkey_last_error ();
267+ try std .testing .expect (err != null );
268+ }
269+
270+ test "version" {
271+ const ver = checky_monkey_version ();
272+ const ver_str = std .mem .span (ver );
273+ try std .testing .expectEqualStrings (VERSION , ver_str );
60274}
0 commit comments