Skip to content

Commit 5d914d4

Browse files
committed
chore: M5 CI/Workflow Sweep - final synchronisation
1 parent 5319998 commit 5d914d4

1 file changed

Lines changed: 269 additions & 37 deletions

File tree

ffi/zig/src/main.zig

Lines changed: 269 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,274 @@
1+
// HTTP_CAPABILITY_GATEWAY FFI Implementation
2+
//
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+
//
16
// SPDX-License-Identifier: PMPL-1.0-or-later
2-
// Main entry point for gateway FFI library
3-
// Exports functions matching src/abi/Protocol.idr interface
47

58
const std = @import("std");
69

7-
/// Platform endianness detection
8-
/// Exported for Idris2: platform_endian
9-
pub export fn platform_endian() callconv(.c) u8 {
10-
return switch (@import("builtin").target.cpu.arch.endian()) {
11-
.little => 0, // LittleEndian
12-
.big => 1, // BigEndian
13-
};
14-
}
15-
16-
/// Serialize response to wire format
17-
/// Exported for Idris2: serialize_response
18-
pub export fn serialize_response(
19-
status_code: u32,
20-
headers_ptr: [*]const u8,
21-
headers_len: usize,
22-
body_ptr: [*]const u8,
23-
body_len: usize,
24-
out_ptr: *[*]u8,
25-
out_len: *usize,
26-
) callconv(.c) bool {
27-
_ = status_code;
28-
_ = headers_ptr;
29-
_ = headers_len;
30-
_ = body_ptr;
31-
_ = body_len;
32-
_ = out_ptr;
33-
_ = out_len;
34-
35-
// TODO: Implement HTTP/2 frame serialization
36-
return false;
37-
}
38-
39-
test "endian detection" {
40-
const endian = platform_endian();
41-
try std.testing.expect(endian == 0 or endian == 1);
10+
// Version information (keep in sync with project)
11+
const VERSION = "0.1.0";
12+
const BUILD_INFO = "HTTP_CAPABILITY_GATEWAY built with Zig " ++ @import("builtin").zig_version_string;
13+
14+
/// Thread-local error storage
15+
threadlocal var last_error: ?[]const u8 = null;
16+
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+
27+
//==============================================================================
28+
// Core Types (must match src/abi/Types.idr)
29+
//==============================================================================
30+
31+
/// Result codes (must match Idris2 Result type)
32+
pub const Result = enum(c_int) {
33+
ok = 0,
34+
@"error" = 1,
35+
invalid_param = 2,
36+
out_of_memory = 3,
37+
null_pointer = 4,
38+
};
39+
40+
/// Library handle (opaque to prevent direct access)
41+
pub const Handle = opaque {
42+
// Internal state hidden from C
43+
allocator: std.mem.Allocator,
44+
initialized: bool,
45+
// Add your fields here
46+
};
47+
48+
//==============================================================================
49+
// Library Lifecycle
50+
//==============================================================================
51+
52+
/// Initialize the library
53+
/// Returns a handle, or null on failure
54+
export fn http_capability_gateway_init() ?*Handle {
55+
const allocator = std.heap.c_allocator;
56+
57+
const handle = allocator.create(Handle) catch {
58+
setError("Failed to allocate handle");
59+
return null;
60+
};
61+
62+
// Initialize handle
63+
handle.* = .{
64+
.allocator = allocator,
65+
.initialized = true,
66+
};
67+
68+
clearError();
69+
return handle;
70+
}
71+
72+
/// Free the library handle
73+
export fn http_capability_gateway_free(handle: ?*Handle) void {
74+
const h = handle orelse return;
75+
const allocator = h.allocator;
76+
77+
// Clean up resources
78+
h.initialized = false;
79+
80+
allocator.destroy(h);
81+
clearError();
82+
}
83+
84+
//==============================================================================
85+
// Core Operations
86+
//==============================================================================
87+
88+
/// Process data (example operation)
89+
export fn http_capability_gateway_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 http_capability_gateway_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 http_capability_gateway_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 http_capability_gateway_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 http_capability_gateway_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 http_capability_gateway_version() [*:0]const u8 {
199+
return VERSION.ptr;
200+
}
201+
202+
/// Get build information
203+
export fn http_capability_gateway_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 http_capability_gateway_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 http_capability_gateway_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 = http_capability_gateway_init() orelse return error.InitFailed;
257+
defer http_capability_gateway_free(handle);
258+
259+
try std.testing.expect(http_capability_gateway_is_initialized(handle) == 1);
260+
}
261+
262+
test "error handling" {
263+
const result = http_capability_gateway_process(null, 0);
264+
try std.testing.expectEqual(Result.null_pointer, result);
265+
266+
const err = http_capability_gateway_last_error();
267+
try std.testing.expect(err != null);
268+
}
269+
270+
test "version" {
271+
const ver = http_capability_gateway_version();
272+
const ver_str = std.mem.span(ver);
273+
try std.testing.expectEqualStrings(VERSION, ver_str);
42274
}

0 commit comments

Comments
 (0)