mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-06-21 16:59:30 +00:00
Increment 4: the exported C surface for host callbacks, plus an end-to-end
test that the host can answer from a different thread than the FFI loop.
- declareLibrary now emits two exportc/cdecl procs on every library's
FFIContext (like the event ABI):
<lib>_register_host_fn(ctx, name, fn, userData)
<lib>_host_complete(ctx, token, ret, msg, len)
(the `name` param is spelled `hostFnName` to dodge the macros.name capture
under quote, same class as the existing id/ret collisions.)
- c.nim emits the FFIHostFn typedef + both declarations into <lib>.h
(guarded, format-agnostic), and the timer header is regenerated.
- Verified: the built timer lib exports both symbols.
The e2e (test_ffi_host_e2e) drives the real bridge: a {.ffi.} handler awaits a
{.ffiHost.} call; the host fn (invoked on the FFI thread, non-blocking) hands
the work to a worker thread, which answers via the completion path. The result
resolves on the loop thread and round-trips correctly (orc+refc). It calls the
underlying registerHostFn/completeHostCall directly, since the exported shims
need an --app:lib build; those shims are verified by the symbol check.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
129 lines
3.4 KiB
C
129 lines
3.4 KiB
C
// Generated by nim-ffi C codegen. Do not edit by hand.
|
|
//
|
|
// Native (zero-serialization) C ABI. Each call delivers its result to the
|
|
// callback. On RET_OK:
|
|
// - string-returning procs: (msg, len) is the raw string bytes (not
|
|
// NUL-terminated; use len).
|
|
// - struct-returning procs: msg is a pointer to the returned C struct — cast
|
|
// it to `const <Type>*` (len is sizeof). It is valid ONLY for the duration
|
|
// of the callback; copy out anything you need before returning. The library
|
|
// deep-frees it right after the callback (you free nothing).
|
|
// On RET_ERR, (msg, len) is the raw error text. A `<name>_cbor` variant of each
|
|
// proc also exists for generic/cross-language callers that prefer CBOR.
|
|
#ifndef NIM_FFI_GEN_MY_TIMER_H
|
|
#define NIM_FFI_GEN_MY_TIMER_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#ifndef NIM_FFI_RET_CODES
|
|
#define NIM_FFI_RET_CODES
|
|
#define RET_OK 0
|
|
#define RET_ERR 1
|
|
#define RET_MISSING_CALLBACK 2
|
|
#endif
|
|
|
|
#ifndef NIM_FFI_CALLBACK_T
|
|
#define NIM_FFI_CALLBACK_T
|
|
typedef void (*FFICallBack)(int callerRet, const char *msg, size_t len, void *userData);
|
|
#endif
|
|
|
|
|
|
// --- {.ffi.}-annotated types, exposed as C structs ----------
|
|
typedef struct {
|
|
const char* name;
|
|
} TimerConfig;
|
|
|
|
typedef struct {
|
|
const char* message;
|
|
int64_t delayMs;
|
|
} EchoRequest;
|
|
|
|
typedef struct {
|
|
const char* echoed;
|
|
const char* timerName;
|
|
} EchoResponse;
|
|
|
|
typedef struct {
|
|
EchoRequest *messages;
|
|
size_t messages_len;
|
|
const char* *tags;
|
|
size_t tags_len;
|
|
int note_present;
|
|
const char* note;
|
|
int retries_present;
|
|
int64_t retries;
|
|
} ComplexRequest;
|
|
|
|
typedef struct {
|
|
const char* summary;
|
|
int64_t itemCount;
|
|
int hasNote;
|
|
} ComplexResponse;
|
|
|
|
typedef struct {
|
|
const char* message;
|
|
int64_t echoCount;
|
|
} EchoEvent;
|
|
|
|
typedef struct {
|
|
const char* name;
|
|
const char* *payload;
|
|
size_t payload_len;
|
|
int64_t priority;
|
|
} JobSpec;
|
|
|
|
typedef struct {
|
|
int64_t maxAttempts;
|
|
int64_t backoffMs;
|
|
const char* *retryOn;
|
|
size_t retryOn_len;
|
|
} RetryPolicy;
|
|
|
|
typedef struct {
|
|
int64_t startAtMs;
|
|
int64_t intervalMs;
|
|
int jitter_present;
|
|
int64_t jitter;
|
|
} ScheduleConfig;
|
|
|
|
typedef struct {
|
|
const char* jobId;
|
|
int64_t willRunCount;
|
|
int64_t firstRunAtMs;
|
|
int64_t effectiveBackoffMs;
|
|
} ScheduleResult;
|
|
|
|
|
|
void *my_timer_create(TimerConfig config, FFICallBack callback, void *userData);
|
|
|
|
int my_timer_echo(void *ctx, FFICallBack callback, void *userData, EchoRequest req);
|
|
|
|
int my_timer_version(void *ctx, FFICallBack callback, void *userData);
|
|
|
|
int my_timer_complex(void *ctx, FFICallBack callback, void *userData, ComplexRequest req);
|
|
|
|
int my_timer_schedule(void *ctx, FFICallBack callback, void *userData, JobSpec job, RetryPolicy retry, ScheduleConfig schedule);
|
|
|
|
int my_timer_destroy(void *ctx);
|
|
|
|
uint64_t my_timer_add_event_listener(void *ctx, const char *eventName, FFICallBack callback, void *userData);
|
|
int my_timer_remove_event_listener(void *ctx, uint64_t listenerId);
|
|
|
|
// --- host callbacks ({.ffiHost.}) — host-implemented functions --------
|
|
#ifndef NIM_FFI_HOST_FN_T
|
|
#define NIM_FFI_HOST_FN_T
|
|
typedef void (*FFIHostFn)(uint64_t token, const char *req, size_t reqLen, void *userData);
|
|
#endif
|
|
int my_timer_register_host_fn(void *ctx, const char *name, FFIHostFn fn, void *userData);
|
|
int my_timer_host_complete(void *ctx, uint64_t token, int ret, const char *msg, size_t len);
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
#endif
|
|
|
|
#endif /* NIM_FFI_GEN_MY_TIMER_H */ |