mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-08-05 22:43:17 +00:00
fix: pr comments
This commit is contained in:
parent
bbe32bfafd
commit
e0a3503589
16
README.md
16
README.md
@ -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. |
|
||||
|
||||
@ -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")
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user