mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-08-05 14:33:13 +00:00
feat: empty-string scalar return
This commit is contained in:
parent
8dcdcdc76a
commit
8cbe1cb82f
@ -177,9 +177,9 @@ func ffiScalarRetBytes*[T](x: T): seq[byte] =
|
||||
## Serializes a scalar handler result into the raw response payload the
|
||||
## callback carries — no CBOR envelope. A `string`/`cstring` rides as its
|
||||
## own UTF-8 bytes (like the error path); every other scalar rides as the
|
||||
## 8-byte native-endian image of `ffiPackScalar(x)`. Note: an empty string
|
||||
## yields a 0-length payload, which `handleRes` sends as the CBOR-null
|
||||
## sentinel — the foreign scalar reader (a follow-up) must special-case it.
|
||||
## 8-byte native-endian image of `ffiPackScalar(x)`. An empty string yields a
|
||||
## 0-length payload, which `handleRes` delivers as a genuine 0-length
|
||||
## `RET_OK` buffer (not the CBOR-null sentinel), so it reads back as "".
|
||||
when T is string:
|
||||
var b = newSeq[byte](x.len)
|
||||
if x.len > 0:
|
||||
@ -231,6 +231,13 @@ proc fireCallback*(res: Result[seq[byte], string], request: ptr FFIThreadRequest
|
||||
cast[csize_t](bytes.len),
|
||||
request[].userData,
|
||||
)
|
||||
elif request[].isScalar:
|
||||
# A scalar return of 0 bytes is a real empty string, not "no value":
|
||||
# hand back a genuine empty buffer, not the CBOR-null sentinel.
|
||||
var empty: byte
|
||||
request[].callback(
|
||||
RET_OK, cast[ptr cchar](addr empty), 0.csize_t, request[].userData
|
||||
)
|
||||
else:
|
||||
# Always hand the callback a real buffer; CBOR null marks "no value".
|
||||
var sentinel = CborNullByte
|
||||
|
||||
@ -61,7 +61,14 @@ proc scalarfast_checked*(
|
||||
return err("negative not allowed")
|
||||
return ok(n * 2)
|
||||
|
||||
## --- C-shape callback harness (mirrors test_ffi_context.nim) ----------------
|
||||
proc scalarfast_blank*(
|
||||
lib: ScalarLib
|
||||
): Future[Result[string, string]] {.ffi: "abi = c".} =
|
||||
## Empty-string return — must ride back as a genuine 0-length RET_OK payload,
|
||||
## not the CBOR-null sentinel.
|
||||
return ok("")
|
||||
|
||||
## C-shape callback harness (mirrors test_ffi_context.nim).
|
||||
|
||||
type CallbackData = object
|
||||
lock: Lock
|
||||
@ -122,10 +129,7 @@ proc scalarStr(d: CallbackData): string =
|
||||
s
|
||||
|
||||
proc callbackErr(d: CallbackData): string =
|
||||
var msg = newString(d.msgLen)
|
||||
if d.msgLen > 0:
|
||||
copyMem(addr msg[0], unsafeAddr d.msg[0], d.msgLen)
|
||||
msg
|
||||
scalarStr(d)
|
||||
|
||||
proc encodedPtr(bytes: var seq[byte]): ptr byte =
|
||||
if bytes.len == 0:
|
||||
@ -183,6 +187,22 @@ suite "scalar fast path — C export shape":
|
||||
check d.retCode == RET_OK
|
||||
check scalarStr(d) == "scalarfast v1"
|
||||
|
||||
test "empty string return rides back as a real 0-length RET_OK payload":
|
||||
let ctx = makeCtx(0)
|
||||
defer:
|
||||
check ScalarLibFFIPool.destroyFFIContext(ctx).isOk()
|
||||
|
||||
var d: CallbackData
|
||||
initCallbackData(d)
|
||||
defer:
|
||||
deinitCallbackData(d)
|
||||
|
||||
check scalarfast_blank(ctx, testCallback, addr d) == RET_OK
|
||||
waitCallback(d)
|
||||
check d.retCode == RET_OK
|
||||
check d.msgLen == 0 # NOT 1 (would be the 0xf6 sentinel)
|
||||
check scalarStr(d) == ""
|
||||
|
||||
test "float param round-trips through the uint64 slot":
|
||||
let ctx = makeCtx(0)
|
||||
defer:
|
||||
@ -250,13 +270,17 @@ suite "scalar fast path — Nim-native shape":
|
||||
check bad.isErr()
|
||||
check bad.error == "negative not allowed"
|
||||
|
||||
let blank = waitFor scalarfast_blank(ScalarLib(base: 0))
|
||||
check blank.isOk()
|
||||
check blank.value == ""
|
||||
|
||||
# `ffiProcRegistry` is a compile-time var, so its assertions run in a static
|
||||
# block (mirrors test_abi_format.nim). A scalar-only `abi = c` proc must be
|
||||
# flagged, recognised by `isScalarOnly`, and dropped from `bindableProcs`.
|
||||
static:
|
||||
const scalarNames = [
|
||||
"scalarfast_add", "scalarfast_version", "scalarfast_scale", "scalarfast_positive",
|
||||
"scalarfast_checked",
|
||||
"scalarfast_checked", "scalarfast_blank",
|
||||
]
|
||||
var seen = 0
|
||||
for p in ffiProcRegistry:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user