Skip to content

Commit f42c879

Browse files
P1: fix Zig FFI to build and match the Idris2 ABI (#29)
## Summary The Zig FFI in `src/interface/ffi/src/main.zig` failed `zig test src/main.zig -lc` under Zig 0.14.0, and one test asserted behaviour the ABI contract does not provide. This PR fixes both, keeping the Idris2 ABI (`src/interface/abi/Oblibeniser/ABI/Foreign.idr` + `Types.idr`) as the source of truth. ## Errors found 1. **Compile error** — `array_list.ArrayListAligned` no longer exposes `popOrNull` in Zig 0.14.0. `oblibeniser_undo_pop` called `h.undo_stack.popOrNull()`: ``` src/main.zig:447:31: error: no field or member function named 'popOrNull' in 'array_list.ArrayListAligned(u64,null)' ``` 2. **Test failure** — the `"compute and verify inverse"` test finalised the operation with a null (`0`) post-snapshot pointer, so `post_snapshot` stayed null and `oblibeniser_compute_inverse` correctly returned `not_reversible` (its contract requires both pre- and post-state snapshots). The test asserted `ok`: ``` 3/7 main.test.compute and verify inverse...expected main.Result.ok, found main.Result.not_reversible ``` ## Fixes 1. Replaced `popOrNull()` with `pop()`, which in Zig 0.14.0 already returns an optional (`?T`); the `orelse` empty-stack handling is unchanged. 2. Updated the test to record with a real pre-state snapshot and finalise with a real post-state snapshot, then assert `ok` for `compute_inverse` and additionally `verify_inverse`. This exercises the documented contract instead of weakening the FFI logic. No exported C symbol names or `Result` enum integer values were changed. ## ABI conformance - Every `C:<name>` in `Foreign.idr` has a matching `export fn <name>` (20/20 symbols, verified by diff — no missing/extra symbols). - `Result` enum values match `resultToInt`: `Ok=0, Error=1, InvalidParam=2, OutOfMemory=3, NullPointer=4, NotReversible=5, AuditViolation=6, InverseProofFailed=7`. ## Verification - `cd src/interface/ffi && zig test src/main.zig -lc` → **all 7 tests pass**, zero errors/warnings. - `cd src/interface/abi && idris2 --build oblibeniser-abi.ipkg` → **exit 0** (build dir removed afterwards). Only `src/interface/ffi/src/main.zig` is touched. > Note: any rust-ci / Hypatia / governance red checks are pre-existing estate-infra unrelated to this Zig-only change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019xMKB3T4Vo5FYC7Czx3JSH --- _Generated by [Claude Code](https://claude.ai/code/session_019xMKB3T4Vo5FYC7Czx3JSH)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 74d25e3 commit f42c879

1 file changed

Lines changed: 17 additions & 3 deletions

File tree

src/interface/ffi/src/main.zig

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ export fn oblibeniser_undo_pop(handle: ?*Handle) u64 {
444444
return 0;
445445
};
446446

447-
const op_id = h.undo_stack.popOrNull() orelse {
447+
const op_id = h.undo_stack.pop() orelse {
448448
setError("Undo stack empty");
449449
return 0;
450450
};
@@ -601,10 +601,24 @@ test "compute and verify inverse" {
601601
const handle = oblibeniser_init() orelse return error.InitFailed;
602602
defer oblibeniser_free(handle);
603603

604-
const op_id = oblibeniser_record_forward(handle, 0, 0);
605-
_ = oblibeniser_finalise_forward(handle, op_id, 0);
604+
// Record with a real pre-state snapshot, then finalise with a real
605+
// post-state snapshot: compute_inverse requires both to be present.
606+
var pre = std.mem.zeroes(StateSnapshot);
607+
pre.state_hash = 0x1111;
608+
var post = std.mem.zeroes(StateSnapshot);
609+
post.state_hash = 0x2222;
610+
611+
const op_id = oblibeniser_record_forward(handle, 0, @intFromPtr(&pre));
612+
try std.testing.expect(op_id != 0);
613+
614+
const finalise = oblibeniser_finalise_forward(handle, op_id, @intFromPtr(&post));
615+
try std.testing.expectEqual(Result.ok, finalise);
616+
606617
const compute = oblibeniser_compute_inverse(handle, op_id);
607618
try std.testing.expectEqual(Result.ok, compute);
619+
620+
const verify = oblibeniser_verify_inverse(handle, op_id);
621+
try std.testing.expectEqual(Result.ok, verify);
608622
}
609623

610624
test "undo stack push and pop" {

0 commit comments

Comments
 (0)