Skip to content

Commit a24c1ea

Browse files
committed
chore: M5 CI/Workflow Sweep - final synchronisation
1 parent e992c66 commit a24c1ea

2 files changed

Lines changed: 417 additions & 24 deletions

File tree

ffi/zig/src/main.zig

Lines changed: 226 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
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

68
const std = @import("std");
79

10+
// Version information (keep in sync with project)
811
const 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
1215
threadlocal 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)
1932
pub 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)
2841
pub 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
3854
export 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
5573
export 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

Comments
 (0)