mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-07-17 05:19:36 +00:00
10 KiB
10 KiB
Changelog
All notable changes to this project are documented in this file.
[Unreleased]
Changed
- User event callbacks now run on a dedicated event thread fed by a
bounded SPSC queue (default capacity 1024), so a slow listener can no
longer block the FFI thread or concurrent
add_event_listener/remove_event_listenercalls (#6). - Replaced the dedicated watchdog thread with a heartbeat check that
runs on the event thread. The FFI thread advances an atomic heartbeat
each loop iteration; if it stalls for more than 1s past the start-up
grace window, the event thread emits the
not_respondingevent. declareLibraryno longer emits the shared-librarysoname/install_namelinker flags when building as an executable (--app:libguard), so FFI code can be unit-tested as a plain binary — fatal on macOS, where-install_namerequires-dynamiclib.
Added
{.ffiEvent.}no longer requires an explicit wire-name string: when omitted it is derived from the proc name viacamelToSnakeCase(onPeerConnected→on_peer_connected), matching how{.ffi.}derives its C export symbol. Pass a string literal only to override it.- FFI annotations (
{.ffi.},{.ffiCtor.},{.ffiDtor.},{.ffiEvent.},{.ffiHandle.},{.ffiRaw.}) that expand aftergenBindings()now produce a loud compile error instead of being silently dropped from the generated bindings. - C binding generator (
-d:targetLang=c): emits a header-only C binding (<lib>.h) plus aCMakeLists.txt, alongside the existing Rust / C++ / CDDL backends. Requests/responses travel as CBOR using the same vendored TinyCBOR the C++ backend uses. C has no generics or overloading, so eachseq[T]/Option[T]is monomorphised into its own struct + encode/decode/free triple. The high-level<lib>_ctx_*API is asynchronous: each method/constructor takes a typed result callback and the binding owns and reclaims all reply data and error strings (valid only for the duration of the callback), so the caller never frees anything — there is no blocking wait and no manual-free contract. Shared codegen helpers were extracted intoffi/codegen/common.nim(used by both the C and C++ backends). Newnimble genbindings_c/genbindings_c_echo/check_bindings_c/test_c_e2etasks, atests/e2e/cctest harness, and atests/unit/test_c_codegen.nimunit suite. - Configurable per-request handler timeout with a finite default: each
FFIContextnow carries adefaultRequestTimeout(5s) applied to every handler, replacing the previous unbounded wait so a wedged handler can no longer hang a foreign caller forever. On trip the caller is unblocked with anffi request timed out after <n>mserr; the handler is left running (not cancelled, since a hard-cancel mid-call into the underlying library can leave it partial), and the callback still fires exactly once. Override per proc with a"timeout = <ms>"spec (e.g.{.ffi: "timeout = 30000".}), parsed like theabi = ...spec; runtime-only, codegen ignores it (#93). - Per-interaction ABI-format annotations:
declareLibrarynow takes an optionaldefaultABIFormat("cbor"default, or"c") that every{.ffi.}/{.ffiCtor.}/{.ffiDtor.}/{.ffiRaw.}/{.ffiEvent.}inherits, and each annotation can override it with an"abi = c"/"abi = cbor"spec (e.g.{.ffi: "abi = cbor".}).declareLibraryis now required before any FFI annotation (#78). c(flat C-struct) ABI codec: every{.ffi: "abi = c".}type gets a<T>_CWirecompanion pluscwirePack/cwireUnpack/cwireFree. This first slice covers the flat path — POD scalars andstring(ascstring); composite fields follow. (Thecproc-dispatch path and its CBOR-free C generator landed later in this release — see the-d:targetLang=c_abientry below;cevents remain CBOR-only.)- CBOR-free
abi = cC binding generator (-d:targetLang=c_abi): emits a single self-contained<lib>.hwhose flat_CWirestructs are the C ABI, so the C consumer passes native structs and links no CBOR at all (contrast the CBOR-d:targetLang=cbackend). Thecproc-dispatch path is now wired end-to-end: the generated exported wrapperscwireUnpackthe request into a Nim object, reuse the existing CBOR thread transport internally, and a Nim reply trampolinecwirePacks the response back into a flat struct for the caller's typed callback.abiCodegenImplementednow acceptscfor proc/ctor/dtor annotations (events remain CBOR-only). Newexamples/echo/c_abi_bindings/(checked in beside the CBORc_bindings/for comparison),nimble genbindings_c_abi_echo/check_bindings_c_abi/test_c_abi_e2e/test_c_abi_e2e_sanitizedtasks, and atests/e2e/c_abictest harness (#105). tests/bench/bench_codec.nim(+nimble bench_codec): a single-process microbenchmark comparing thecborandccodecs across payload shapes, isolating codec cost from the (identical) thread/callback round-trip.- Queue-overflow handling: when the bounded event queue is full, the
library sets a sticky "stuck" flag, logs an error, fires
not_respondingfrom the event thread, and rejects subsequentsendRequestToFFIThreadcalls withevent queue stuck - library cannot accept new requests.
[0.2.0] - 2026-06-04
Major release introducing the CBOR-based wire format, CBOR-backed FFI events with a multi-listener registry, multi-language binding generation (C++, Rust, CDDL), CI hardening with sanitizers, and several robustness fixes around context lifetime and memory safety.
Added
- CBOR serialization as the FFI wire format, replacing the previous
JSON/string-based
serial.nim(#23). - CBOR-backed FFI events: event payloads are now serialized with CBOR (#39).
- Multi-listener event registry (
FFIEventRegistry) and its wiring intoFFIContext(#45, #49). - Event-listener ABI with per-event typed listeners (#50).
- C++ typed per-event listeners in the generated bindings (#51).
- Rust per-event typed listeners (
add_on_<x>_listener+ wildcardadd_event_listener) (#52) and Rust event example bindings/clients (#53). - C++ binding generator with end-to-end tests driven by CMake/CTest (#27), later expanded with multi-context, cross-library, pipeline, and stress tests (#42).
- CDDL schema generator for the FFI types (#24).
- CI pipeline: parallel test execution (#26), AddressSanitizer / UndefinedBehaviorSanitizer / ThreadSanitizer jobs (#34), and a cross-platform OS matrix for the C++ e2e suite (#38).
- CBOR type-coverage tests (#41).
Changed
- Removed the redundant
ffiTypemacro; theffimacro is now the single authoring entry point (#22). - Generated C++ avoids move constructors and assignment operators (#36) and no longer throws exceptions across the binding boundary (#46).
- Removed the wildcard event listener; event dispatch is now strictly per-event (#70).
Fixed
- Use-after-free in the event/context lifetime path (#47).
[0.1.4] - 2026-05-13
Added
- Simplified FFI authoring with auto-generated C++ and Rust language bindings,
including new
ffi/codegen/cpp.nim,ffi/codegen/rust.nimand sharedffi/codegen/meta.nimhelpers (#15). - Rust example bindings and clients under
examples/nim_timer/(rust_bindingsandrust_client, the latter with a Tokio async variant) (#15). - JSON/string-based FFI (de)serialization via
ffi/serial.nim(ffiSerialize/ffiDeserialize), withtests/test_serial.nimcoverage. (CBOR replaced this layer later, in 0.2.0.) - FFI context pool (
ffi/ffi_context_pool.nim) using a fixed array of contexts. - Test suite expansion:
test_alloc.nim,test_ctx_validation.nim,test_ffi_context.nim,test_gc_compat.nim. - Continuous integration pipeline (#12).
Fixed
- Context buffer overflow (#21).
- Use a fixed array of contexts to avoid consuming all file descriptors (#14).
- Memory leaks (#11).
- Add
install_namefor macOS shared libraries (#8).
Changed
- Run tests with the
refcgarbage collector (#20). - Remove
CatchableErrorusage (#19). - Update license files to comply with Logos licensing requirements.
[0.1.3] - 2026-01-23
Fixed
- Properly import and re-export
chroniclesso downstream packages get the logging macros transitively.
[0.1.2] - 2026-01-23
Fixed
- Re-export
chroniclesandstd/tableswhen theffimodule is imported, so generated code resolves these symbols at the call site.
[0.1.1] - 2026-01-23
Initial tagged release.
Added
- Core
ffimacro for declaring procs exposed across the FFI boundary. FFIContextwith a dedicated worker thread, request dispatch, and a watchdog with configurable timeout (#7).- License files updated to comply with Logos licensing requirements.