Skip to content

P1: implement real Zig FFI matching the Idris2 ABI#30

Merged
hyperpolymath merged 1 commit into
mainfrom
claude/new-session-1fphit
Jun 26, 2026
Merged

P1: implement real Zig FFI matching the Idris2 ABI#30
hyperpolymath merged 1 commit into
mainfrom
claude/new-session-1fphit

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Problem

The Idris2 ABI is the source of truth for this -iser project. Its %foreign "C:eclexiaiser_*" declarations live in two places:

  • src/interface/abi/Eclexiaiser/ABI/Foreign.idr — 18 symbols
  • the namespace Foreign block inside src/interface/abi/Eclexiaiser/ABI/Types.idr3 more symbols: eclexiaiser_measure_energy, eclexiaiser_query_carbon, eclexiaiser_enforce_budget

The Zig FFI (src/interface/ffi/src/main.zig) exported the 18 from Foreign.idr but was missing all 3 declared in Types.idr. Those symbols have no matching export fn, so they would fail to link when the ABI is compiled against libeclexiaiser. The Zig FFI therefore did not fully match its ABI.

Fix

Added the three missing C-ABI exports, with C signatures matching their %foreign types exactly (Idris Bits64/Bits32 ↔ Zig u64/u32; opaque handle ↔ ?*anyopaque; result Bits32 ↔ the Result enum):

Idris %foreign (Types.idr namespace Foreign) Zig export
eclexiaiser_measure_energy : Bits64 -> PrimIO Bits64 eclexiaiser_measure_energy(handle) u64
eclexiaiser_query_carbon : Bits32 -> PrimIO Bits32 eclexiaiser_query_carbon(zone_id: u32) u32 (handle-free)
eclexiaiser_enforce_budget : Bits64 -> Bits64 -> PrimIO Bits32 eclexiaiser_enforce_budget(budget_uj, measured_uj: u64) Result (handle-free)

The handle-free forms mirror the safe wrappers measureEnergy / queryCarbon / enforceBudget in the Types.idr namespace Foreign block. eclexiaiser_enforce_budget returns the Result enum, whose values already equal Types.idr resultToInt (Ok=0 .. CounterUnavailable=7).

Three test blocks were added covering the new symbols: measure_energy main path + null-handle rejection, handle-free query_carbon, and enforce_budget result codes (ok / budget_exceeded).

Only src/interface/ffi/ is touched.

Verification

  • zig test src/main.zig -lc11/11 pass, no errors/warnings
  • idris2 --build eclexiaiser-abi.ipkgexit 0, clean (build dir removed afterward)
  • All 21 C:eclexiaiser_* ABI symbols now have a matching export fn
  • Result enum values equal resultToInt

CI note

Any rust-ci / Hypatia / governance reds are pre-existing estate-infra checks unrelated to this Zig-only change.

🤖 Generated with Claude Code

https://claude.ai/code/session_019xMKB3T4Vo5FYC7Czx3JSH


Generated by Claude Code

The Idris2 ABI is the source of truth. Its %foreign declarations live in
two places: Foreign.idr (18 symbols) and the `namespace Foreign` block in
Types.idr (3 symbols: eclexiaiser_measure_energy, eclexiaiser_query_carbon,
eclexiaiser_enforce_budget). The Zig FFI exported the 18 from Foreign.idr
but was missing all 3 from Types.idr, so those symbols would fail to link
when the ABI is compiled against libeclexiaiser.

This adds the three missing C-ABI exports with signatures matching their
%foreign types exactly:

  eclexiaiser_measure_energy : Bits64 -> PrimIO Bits64
    (handle: opaque ptr) -> u64 microjoules
  eclexiaiser_query_carbon   : Bits32 -> PrimIO Bits32
    (zone_id: u32) -> u32 mgCO2/kWh   (handle-free)
  eclexiaiser_enforce_budget : Bits64 -> Bits64 -> PrimIO Bits32
    (budget_uj, measured_uj: u64) -> Result   (handle-free)

eclexiaiser_enforce_budget returns the Result enum, whose values already
match Types.idr resultToInt (Ok=0 .. CounterUnavailable=7); the handle-free
forms mirror the safe wrappers measureEnergy/queryCarbon/enforceBudget in
the Types.idr namespace Foreign block.

Adds three `test` blocks covering the new symbols: measure_energy main
path plus null-handle rejection, handle-free query_carbon, and
enforce_budget result codes (ok / budget_exceeded).

Verification:
  - zig test src/main.zig -lc : 11/11 pass, no warnings
  - idris2 --build eclexiaiser-abi.ipkg : exit 0, clean
  - all 21 C:eclexiaiser_* ABI symbols now have a matching export fn
  - Result enum values equal resultToInt

Only src/interface/ffi/ is touched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019xMKB3T4Vo5FYC7Czx3JSH
@hyperpolymath hyperpolymath marked this pull request as ready for review June 26, 2026 22:08
@hyperpolymath hyperpolymath merged commit ce8cdc7 into main Jun 26, 2026
20 of 22 checks passed
@hyperpolymath hyperpolymath deleted the claude/new-session-1fphit branch June 26, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants