24 Commits

Author SHA1 Message Date
Ivan FB
d554443121
feat(examples): Android example consumes the generated Kotlin/JNI wrapper
Regenerates the wrapper (MyTimerNode.kt) and JNI shim (my_timer_jni.c) via
`nimble genbindings_kotlin`, removing the hand-written sources, and points
the instrumented test at the derived MyTimerNode class.

Validated by cross-compiling both ABIs with the NDK: arm64-v8a + x86_64 build
clean, the four Java_org_logos_mytimer_MyTimerNode_* symbols are exported, and
libmy_timer_jni.so correctly NEEDS libmy_timer.so. (The Kotlin/Gradle layer
still runs on a device/emulator.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 16:54:31 +02:00
Ivan FB
c51f313cd2
docs(examples): add Android (Kotlin/JNI) example over the native C ABI
An Android library module wrapping the timer library's native ABI behind an
idiomatic Kotlin `TimerNode` class via a JNI shim. `build-libs.sh` cross-compiles
two native libraries per ABI (arm64-v8a + x86_64) into src/main/jniLibs/:
libmy_timer.so (the Nim library) and libmy_timer_jni.so (the JNI bridge, which
NEEDs the former). The shim turns each Kotlin `external fun` into a blocking call
and reads the typed EchoResponse struct out of the result callback.

Gradle packages everything under jniLibs/ automatically; an instrumented test
covers create/version/echo on a device/emulator. Native build validated for
both ABIs (correct aarch64/x86_64 ELF, JNI symbols exported, libmy_timer.so
linked).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:20 +02:00
Ivan FB
2ec514cf9f
docs(examples): make clear the CBOR ABI is for IPC only
Every generated library exports both ABIs side by side; spell out the choice in
the example READMEs: the native (pure-C) ABI is the default for same-process /
local calls (flat C structs, zero serialization), while the CBOR ABI exists
solely for inter-process communication (different process or machine). In a
shared address space CBOR is pure overhead, so prefer native locally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:19 +02:00
Ivan FB
0bba42d2a2
docs(examples): Go example reads typed struct returns
Echo/Complex/Schedule now return typed Go structs (EchoResponse,
ComplexResponse, ScheduleResult); print their fields instead of an "ok" line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:19 +02:00
Ivan FB
0a8b53a06d
feat(codegen): Go bindings return typed structs natively
Struct-returning methods now hand back a typed Go struct instead of the raw
CBOR/bytes. Since the native return POD is freed right after the callback, the
POD->Go conversion must happen in-callback: the generator emits a `fromC()`
reader per {.ffi.} type and, per struct-returning proc, an exported Go result
callback. The method calls the native entry point directly with that callback
and a `runtime/cgo.Handle` (boxed in a small C allocation so it travels through
the void* userData checkptr-safe), then blocks until the callback delivers the
typed value or error on the result slot.

String/raw-returning procs keep the existing C-bridge + condvar path. Validated
end-to-end (Echo/Complex/Schedule) including under `go run -race`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:19 +02:00
Ivan FB
98e8e8829f
docs(examples): C example reads typed struct returns
Update the native C example to cast each struct return's callback msg to its
`const <Type>*` and read it in-callback (EchoResponse, ComplexResponse), instead
of scanning opaque bytes. Regenerate the headers with the new return-shape note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:19 +02:00
Ivan FB
7902fa050b
docs(examples): add native Go example exercising struct params
A runnable main.go that constructs the timer with a TimerConfig, then calls
Echo (struct param), Complex (slice-of-structs + slice + two optionals) and
Schedule (three struct params) with idiomatic Go values — the methods the Go
generator used to skip. The Makefile builds the dylib next to the package
(cgo's ${SRCDIR} rpath finds it at runtime); README documents the Nim->Go type
mapping. Verified end-to-end with `go run`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:18 +02:00
Ivan FB
965fd68785
feat(codegen): Go bindings support struct/seq/Option params
The Go generator previously emitted a `// SKIPPED` stub for any proc with a
struct, sequence or optional parameter, leaving Echo/Complex/Schedule
uncallable. Now that the native ABI carries those as flat C-POD structs, the Go
side can marshal them: emit an idiomatic Go struct per {.ffi.} type plus a
`toC()` that builds the matching `C.<Type>` (C.CString for strings, a C array
for seqs, present-flags for options, recursively for nested structs) and
returns cleanup funcs run via defer once the call returns. The native path
deep-copies every argument, so releasing the C buffers immediately is safe.

The C bridge already accepted struct-by-value params via the pass-through type
mapping; only the Go-side conversion and the `allSupported` gate needed work.
Bare seq/Option *top-level* params (not wrapped in a struct) remain skipped, as
the native ABI does not expose them either.

The generated package is now self-contained: the native `<lib>.h` is emitted
beside the `.go`, and the cgo directives use ${SRCDIR} so the header and the
staged library resolve without extra env vars. genbindings_go runs gofmt to
finalize column alignment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:18 +02:00
Ivan FB
efadf11660
docs(examples): add CBOR-over-socket IPC example (same + separate machines)
The native C ABI only works in-process. This example demonstrates the other
half — the CBOR ABI crossing a process (and machine) boundary — since the `ctx`
pointer is process-local and cannot travel over the wire.

A server links libmy_timer, owns one context, and serves method calls; a client
links nothing (it only needs the FfiCbor encoder/ffi_decode_text in
my_timer_cbor.h) and speaks the same CBOR over a socket. Both binaries accept
`--unix <path>` for two processes on one host and `--tcp <host> <port>` for two
machines — the only difference is the socket family, so one client/server pair
covers both scenarios. Framing is length-prefixed in network byte order so the
endpoints may differ in OS, arch, or endianness.

`proto.h` carries the shared framing, the CBOR request builders, and a small
CBOR map reader so the client can pull text fields out of a response without a
full CBOR library. Verified end-to-end over both AF_UNIX and TCP loopback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:06 +02:00
Ivan FB
c5c7c373b4
docs(examples): add native (same-process) C example
The C codegen already emitted `my_timer.h` / `my_timer_cbor.h`, but the example
had no runnable driver. Add `example.c` exercising the native ABI end-to-end
(ctor with a struct param, string-returning version, struct-param echo, and a
deeply nested ComplexRequest), plus a Makefile that builds the Nim dylib from
the repo root — where the vendored Nimble deps resolve — and links the driver.

Native is the same-process path; the companion CBOR headers are for crossing a
process/machine boundary (see the forthcoming ipc example).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:06 +02:00
Ivan FB
4af031c421
fix(codegen): Rust bindings target the *_cbor request exports
The Rust wrapper speaks CBOR, but after the native/CBOR split it still declared
and called the bare `<name>` request symbols — which are now the *native*
(typed-args) entry points, so every Rust request hit the wrong ABI (struct/ptr
mismatch). This is the Rust counterpart of the C++ fix (914c70a), which was
missed at the time. Point the ffi.rs externs and the api.rs ctor/method calls at
`<name>_cbor`; the destructor has no CBOR variant and the event registration is
unchanged here.

Verified at runtime: the rust_client now creates a context and round-trips
version / echo / schedule over CBOR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:34:30 +02:00
Ivan FB
914c70a131
fix(codegen): C++ bindings target the *_cbor exports
The C++ wrapper speaks CBOR, but after the native/CBOR split it still called the
bare `<name>` symbols — which are now the *native* (typed-args) entry points, so
every C++ call hit the wrong ABI and the C++ e2e failed 19/19 (also reddening
the ASan/TSan jobs, which run the same suite). Point the generated extern
declarations and call sites at `<name>_cbor` for `{.ffi.}` procs and the ctor;
the destructor has no CBOR variant and stays bare. Regenerated the timer and
echo C++ bindings. C++ e2e back to 19/19.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:31:12 +02:00
Ivan FB
c43563f82f
rust codegen: per-event typed add_on_<x>_listener + wildcard add_event_listener (#52) 2026-05-29 20:40:28 +02:00
Gabriel Cruz
7ccf34591d
chore: avoid throwing exceptions in C++ bindings (#46) 2026-05-29 12:35:49 -03:00
Ivan FB
e394166c46
Cpp typed event listeners (#51) 2026-05-28 22:40:33 +02:00
Ivan FB
3f19411684
Event listener abi (#50) 2026-05-28 16:00:28 +02:00
Gabriel Cruz
436c0d760b
test(cpp-e2e): add multi-context, cross-library, pipeline, stress tests (#30) (#42) 2026-05-26 09:18:12 -03:00
Ivan FB
6a7e4616fd
Adjust events to cbor (#39) 2026-05-25 15:51:56 +02:00
Gabriel Cruz
31d0ebfa51
chore(ci): extend cpp-e2e to OS matrix (#38) 2026-05-22 11:43:37 -03:00
Ivan FB
c7cf46bdea
avoid move ctor and assing operator in cpp generated code (#36) 2026-05-21 16:38:13 +02:00
Ivan FB
5e6e58e7d1
Increase version to v0.2.0 (#37) 2026-05-21 16:33:38 +02:00
Ivan FB
584e818ac9
Add basic cpp e2e tests (#27) 2026-05-19 12:43:34 +02:00
Ivan FB
e12745e85c
Add cddl generator (#24) 2026-05-18 20:00:57 +02:00
Ivan FB
ac303a707e
Start using CBOR (#23)
Co-authored-by: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com>
Co-authored-by: Gabriel Cruz <8129788+gmelodie@users.noreply.github.com>
2026-05-16 01:08:42 +02:00