23 Commits

Author SHA1 Message Date
Ivan FB
725a7b6551
feat(codegen): native (non-CBOR) C++ generator — core
A native C++ binding generator (`cpp_native.nim`), the C++ counterpart of the C
and Go native paths and companion to the CBOR `cpp.nim`. It emits
`<lib>_native.hpp`: an idiomatic C++ struct + `toC`/`fromC` per `{.ffi.}` type,
and a `<Lib>Node` class whose methods marshal typed args into / read typed
struct returns out of the native ABI (`<name>` entry points + flat C structs in
`<lib>.h`) — zero serialization. Wired into genBindings under
`targetLang=cpp` + `-d:ffiMode=native`; emits the native C header alongside so
the binding is self-contained. Task: `genbindings_cpp_native`.

First cut covers scalar/string/bool/nested-struct fields (create/version/echo);
seq/Option params are `// SKIPPED`, and native typed events are next. Filename
is `_native.hpp` for now to coexist with the CBOR `.hpp` (rename is a follow-up).

Verified end-to-end: the generated example builds and round-trips a typed
EchoResponse (`make run`).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:39:19 +02:00
Ivan FB
918dd72390
feat(ffi): native event delivery + dual-ABI event symbol naming
Events now mirror the native/CBOR split already in place for requests, with the
same symbol-naming convention:

- `<lib>_add_event_listener`      -> NATIVE listener (typed `<T>Pod` by pointer)
- `<lib>_add_event_listener_cbor` -> CBOR listener (EventEnvelope bytes)

Framework: `FFIEventListener` gains a `native` flag; `addEventListener` a
`native` param; a new `dispatchFFIEventDual` template builds the `<T>Pod` once
for native listeners (`nimToPod`/`freePod`) and the CBOR envelope once for the
rest, fanning each out — so a single `{.ffiEvent.}` dispatch serves both kinds.
`declareLibrary` exports both registration entry points.

Generators: the bare `<lib>_add_event_listener` is the native symbol; every
CBOR consumer (C/C++/Go/Rust) now targets `<lib>_add_event_listener_cbor`. The
rename and the generator updates ship together so the bare name is never briefly
broken. Bindings regenerated.

Validated: native-event unit test (typed POD to native + CBOR to cbor listener,
orc/refc/ASAN); full unit suite; C++ e2e 19/19; Go example; existing event
tests unchanged. The per-event *typed* native callback + wildcard router (the
ergonomic consumer surface) is a follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:27 +02:00
Ivan FB
9cf4bf0127
feat(ffi): native typed struct returns for the C ABI
A `{.ffi.}` proc that returns a registered struct now delivers it natively
instead of CBOR-encoding it. The FFI-thread handler builds the return's
`<T>Pod` mirror on the heap (`nimToPod`) and stashes it on the request; the
callback receives it as a typed `const <T>*` (msg = pointer, len = sizeof), and
handleRes deep-frees it the instant the callback returns — callback-lifetime
ownership, the caller frees nothing.

Mechanics: FFIThreadRequest gains respPod/respPodLen/respPodFree fields that
handleRes honors ahead of the byte payload; the macro emits a per-proc
cdecl freer (`freePod` + `ffiCFree`) for the response POD. String and
seq[byte] returns still travel as raw bytes; the CBOR path (`<name>_cbor`) is a
separate handler and is unchanged. The C header documents the new return shape.

Validated end-to-end from C (EchoResponse, ComplexResponse with nested
seq/option graphs) including under ASAN — no UAF or double-free.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:18 +02:00
Ivan FB
ad493d6f9d
feat(ffi): cross struct/seq/Option params natively via POD
The native (zero-serialization) path previously handed `{.ffi.}` struct
params to the FFI thread using the Nim object layout (GC'd `string` fields),
which does not match the C-POD layout the generated header declares — an ABI
mismatch that left struct-param procs uncallable from C and skipped by the Go
codegen.

Wire the generated POD machinery into both the `{.ffi.}` and `{.ffiCtor.}`
native paths: a registered `{.ffi.}` struct now travels as its `<T>Pod`
mirror — `clonePod` deep-copies it off the caller's buffers into shared
(`c_malloc`) memory on the caller thread, `podToNim` rebuilds the Nim value on
the FFI thread, and `freePod` releases it from the CArgs free proc. `string`
collapses to `cstring` (alloc/ffiCFree); scalars copy direct. New classifiers
(`nativeWireType` / `nativeArgCopyStmt` / `nativeArgUnpackStmt`) keep both
paths and the CArgs alloc/free in lockstep so ownership can't drift.

The load-bearing invariant: the `<T>Pod` `{.bycopy.}` layout is identical to
the C struct emitted by `codegen/c.emitCStructs`, so the `exportc` symbol's
ABI matches the header even though Nim's own struct name differs. Keep the two
emitters in sync.

Validated end-to-end from C (TimerConfig, EchoRequest, and a nested
ComplexRequest with seq-of-structs, seq-of-strings and two Options) and clean
under ASAN. Struct *returns* still travel as CBOR on the native path; that is
left for a follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:05 +02:00
Ivan FB
f3206c30b8
feat(ffi): emit a native (zero-serialization) C ABI alongside CBOR
A single {.ffi.} definition now produces BOTH interfaces, chosen by the
caller at link time rather than by a global compile flag:

- `<name>`      — native typed-arg C export. Args travel to the FFI thread in
                  a c_malloc'd C-POD struct passed by pointer (no CBOR), and the
                  result is delivered to the callback as raw bytes. This is the
                  preferred path for same-process callers: no serialization on
                  either side.
- `<name>_cbor` — the existing CBOR-buffer dispatcher, kept for generic /
                  cross-language callers.

Both share the user's helper proc; they register distinct handlers keyed by
"<Camel>Req" (CBOR) and "<Camel>ReqNative". FFIThreadRequest gains a `cborMode`
flag and a `payloadFree` hook so the native C-POD payload (which owns duplicated
cstring fields) is released correctly and an empty native result is delivered as
a zero-length buffer instead of the CBOR null sentinel. alloc.nim gains
ffiCMalloc/ffiCFree (prefixed to avoid Nim's style-insensitive clash with
ansi_c.c_malloc/c_free).

Verified end-to-end on a scalar-param lib: native calls return raw strings
("calc v1", "sum=42"); the _cbor variant still returns CBOR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 02:02:39 +02:00
Ivan FB
028dbb56e6
feat(codegen): add C and Go (cgo) binding generators
0.2.0 carries each request as a single CBOR buffer over the exported ABI,
which is awkward for hand-written host bindings (every consumer would have
to encode CBOR and decode responses by hand). These two generators emit
ergonomic, ready-to-use bindings from the same {.ffi.} registry the C++/Rust
generators already consume.

- c.nim (targetLang=c): a self-contained <lib>.h with a small CBOR encoder,
  ffi_decode_text(), and `static inline <lib>_<proc>(ctx, cb, ud, args...)`
  wrappers that CBOR-encode and forward to the real export. The wrapper keeps
  the export's source name but is given a distinct symbol via an __asm__ label
  so the raw export's asm alias doesn't bind back to the wrapper (which would
  recurse). Scalar/string params only; others fall back to the raw CBOR decl.

- go.nim (targetLang=go): a single <lib>.go cgo package that #includes the
  generated <lib>.h and adds a condvar-backed response capture. This is the
  key bit: 0.2.0 removed the synchronous fast-path, so a caller can no longer
  read a result right after the call — the generated bridges block on the
  callback, turning each async export into a blocking Go method. Also emits a
  go.mod for importability.

Wired both into genBindings dispatch (targetLang "c"/"go") and added
genbindings_c / genbindings_go tasks. Both verified end-to-end against a
scalar-param test lib (build + run) and the real libwaku surface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 00:06:46 +02:00
Ivan FB
6a7e4616fd
Adjust events to cbor (#39) 2026-05-25 15:51:56 +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
Ivan FB
6d31fa30bd
use fixed array of ctx to avoid consuming all fds (#14) 2026-05-13 00:02:23 +02:00
Gabriel Cruz
81c62c263e
fix: context buffer overflow (#21) 2026-05-11 19:21:40 -03:00
Ivan FB
a52c4facd9
Simplified FFI authoring with auto-generated C++ and Rust bindings (#15) 2026-05-11 23:28:17 +02:00
Ivan FB
df2277e726
Fix memleaks (#11)
* protect against mem leak in case of failures sending requests to ffi thread
* better cleanup if failures in createFFIContext
* avoid dangling cstring in handleRes under ARC/ORC
* better resource cleanup in destroyFFIContext
* invoke onNotResponding if failure in destroyFFIContext
* correct seq copy in alloc
* make sure the lock is init before cleanUpResources
* better possible exception handling in processReq
* guard allocSharedSeq if given seq is empty
* enhance error handling in ffi_context
* add new tests and some corrections
2026-04-27 21:22:45 +02:00
Ivan Folgueira Bande
d7a5492121
avoid use gc ed types in FFIContext and better macro documentation 2025-12-13 23:53:59 +01:00
Ivan Folgueira Bande
5964e287a9
rm useless comments 2025-12-11 17:21:47 +01:00
Ivan Folgueira Bande
e0cf0c8842
fixes for proper proc exposure to c 2025-12-11 17:11:59 +01:00
Ivan Folgueira Bande
da3251aa1a
evolving more 2025-12-10 17:43:26 +01:00
Ivan Folgueira Bande
86dc58e7c2
add ffi macro 2025-12-09 18:51:50 +01:00
Ivan Folgueira Bande
b974eab39c
comment echo repr lines 2025-09-17 14:38:01 +02:00
Ivan Folgueira Bande
a1a6536b3c
general ffi increments 2025-09-17 14:37:45 +02:00
Ivan Folgueira Bande
356f0ccc1b
working simplification 2025-09-17 14:37:36 +02:00
Ivan Folgueira Bande
46e51e45a6
more positive progress. Getting closer 2025-09-17 14:37:28 +02:00
Ivan Folgueira Bande
bbddf6925b
First commit 2025-09-17 14:37:11 +02:00