fix: pr comments

This commit is contained in:
Gabriel Cruz 2026-07-06 11:03:49 -03:00
parent bbe32bfafd
commit e0a3503589
No known key found for this signature in database
GPG Key ID: 3C6977037D5A1EF5
2 changed files with 22 additions and 18 deletions

View File

@ -14,10 +14,11 @@ No hand-written `.h` files, no manual request enums, no shared-memory plumbing.
`{.ffiDtor.}`, `{.ffiEvent.}`).
- You **call `genBindings()` last**, which emits the foreign bindings.
Every request/response crosses the boundary as a single CBOR blob; the ctx
handle returned by the constructor is the only pointer that crosses. Each
`{.ffi.}` proc runs on the library's own chronos event loop, so bodies can
`await` freely.
By default, every request/response crosses the boundary as a single CBOR blob
(the wire format is configurable per library or per annotation — see
[ABI format](#abi-format)); the ctx handle returned by the constructor is the
only pointer that crosses. Each `{.ffi.}` proc runs on the library's own chronos
event loop, so bodies can `await` freely.
## Minimal example
@ -31,7 +32,8 @@ type Counter = object
declareLibrary("counter", Counter)
# 2. Request/response shapes. Any {.ffi.} object type becomes a first-class
# struct/class in the generated bindings and rides the wire as CBOR.
# struct/class in the generated bindings and rides the wire in the library's
# ABI format (CBOR by default).
type BumpRequest {.ffi.} = object
by: int
@ -51,7 +53,7 @@ proc counterBump*(
return ok(BumpResponse(newValue: c.value + req.by))
# 5. Destructor: exactly one param (the library value).
proc counter_destroy*(c: Counter) {.ffiDtor.} =
proc counterDestroy*(c: Counter) {.ffiDtor.} =
discard
# 6. genBindings() must be the LAST FFI call in the file (see below).
@ -66,7 +68,7 @@ The generated C export names are the snake_case form of the proc names, e.g.
| Pragma | Applies to | Purpose |
| --- | --- | --- |
| `declareLibrary(name, LibType[, defaultABIFormat])` | call | Registers the library, its state type, and the default wire format. Must run before any annotation. |
| `{.ffi.}` on a `type` | `object` | Registers the type for binding generation; it serializes via the generic CBOR overloads. |
| `{.ffi.}` on a `type` | `object` | Registers the type for binding generation; it serializes via the library's ABI format (CBOR by default). |
| `{.ffi.}` on a `proc` | proc | Exposes a method. First param is the library value, then typed params; returns `Future[Result[T, string]]`. |
| `{.ffiCtor.}` | proc | The constructor. Returns `Future[Result[LibType, string]]`; creates the FFI context. |
| `{.ffiDtor.}` | proc | The destructor. Exactly one param `(x: LibType)`; tears the context down. |

View File

@ -20,6 +20,18 @@ proc requireLibraryDeclared(where: string) {.compileTime.} =
": declareLibrary(name, LibType[, defaultABIFormat]) must be called before any FFI annotation"
)
proc resolveEventWireName(
leading: seq[NimNode], userProcName: NimNode
): tuple[wireName: string, abiSpecStart: int] {.compileTime.} =
## A leading string that doesn't parse as an `"abi = ..."` spec is the explicit
## wire name; anything else means derive the name from the proc. Returns the
## resolved name and the index where the trailing ABI specs begin.
if leading.len > 0 and leading[0].kind in {nnkStrLit, nnkRStrLit, nnkTripleStrLit} and
($leading[0]).len > 0 and not parseAbiSpec($leading[0]).ok:
($leading[0], 1)
else:
(camelToSnakeCase($userProcName), 0)
proc requireBeforeGenBindings(where: string) {.compileTime.} =
## Enforce that this annotation expands before `genBindings()`. Anything
## registered afterwards never reaches the generator, so turn what used to be
@ -1705,18 +1717,8 @@ macro ffiEvent*(args: varargs[untyped]): untyped =
if procName.kind == nnkPostfix:
userProcName = procName[1]
# Leading args before the proc are an optional explicit wire-name string
# followed by optional `"abi = ..."` specs. A leading string that isn't an
# ABI spec is the wire name; otherwise derive it from the proc name.
let leading = args[0 ..^ 2]
var wireName = ""
var abiSpecStart = 0
if leading.len > 0 and leading[0].kind in {nnkStrLit, nnkRStrLit, nnkTripleStrLit} and
not parseAbiSpec($leading[0]).ok:
wireName = $leading[0]
abiSpecStart = 1
if wireName.len == 0:
wireName = camelToSnakeCase($userProcName)
let (wireName, abiSpecStart) = resolveEventWireName(leading, userProcName)
let abiFormat = resolveABIFormat(leading[abiSpecStart ..^ 1])
gateABIFormat(abiFormat, "`.ffiEvent.` proc")