mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-08-03 21:43:32 +00:00
Event listener abi (#50)
This commit is contained in:
parent
496a341466
commit
3f19411684
@ -332,7 +332,8 @@ void* echo_create(const uint8_t* req_cbor, size_t req_cbor_len, FFICallback call
|
|||||||
int echo_shout(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
|
int echo_shout(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
|
||||||
int echo_version(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
|
int echo_version(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
|
||||||
int echo_destroy(void* ctx);
|
int echo_destroy(void* ctx);
|
||||||
void echo_set_event_callback(void* ctx, FFICallback callback, void* user_data);
|
uint64_t echo_add_event_listener(void* ctx, const char* event_name, FFICallback callback, void* user_data);
|
||||||
|
int echo_remove_event_listener(void* ctx, uint64_t listener_id);
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|||||||
@ -631,7 +631,8 @@ int my_timer_version(void* ctx, FFICallback callback, void* user_data, const uin
|
|||||||
int my_timer_complex(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
|
int my_timer_complex(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
|
||||||
int my_timer_schedule(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
|
int my_timer_schedule(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
|
||||||
int my_timer_destroy(void* ctx);
|
int my_timer_destroy(void* ctx);
|
||||||
void my_timer_set_event_callback(void* ctx, FFICallback callback, void* user_data);
|
uint64_t my_timer_add_event_listener(void* ctx, const char* event_name, FFICallback callback, void* user_data);
|
||||||
|
int my_timer_remove_event_listener(void* ctx, uint64_t listener_id);
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@ -746,8 +747,13 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void setEventHandlers(Events handlers) {
|
void setEventHandlers(Events handlers) {
|
||||||
|
if (event_listener_id_ != 0) {
|
||||||
|
my_timer_remove_event_listener(ptr_, event_listener_id_);
|
||||||
|
event_listener_id_ = 0;
|
||||||
|
}
|
||||||
events_ = std::make_unique<Events>(std::move(handlers));
|
events_ = std::make_unique<Events>(std::move(handlers));
|
||||||
my_timer_set_event_callback(ptr_, &MyTimerCtx::eventTrampoline, events_.get());
|
event_listener_id_ = my_timer_add_event_listener(
|
||||||
|
ptr_, "", &MyTimerCtx::eventTrampoline, events_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
EchoResponse echo(const EchoRequest& req) const {
|
EchoResponse echo(const EchoRequest& req) const {
|
||||||
@ -806,6 +812,7 @@ private:
|
|||||||
void* ptr_;
|
void* ptr_;
|
||||||
std::chrono::milliseconds timeout_;
|
std::chrono::milliseconds timeout_;
|
||||||
std::unique_ptr<Events> events_;
|
std::unique_ptr<Events> events_;
|
||||||
|
uint64_t event_listener_id_ = 0;
|
||||||
explicit MyTimerCtx(void* p, std::chrono::milliseconds t) : ptr_(p), timeout_(t) {}
|
explicit MyTimerCtx(void* p, std::chrono::milliseconds t) : ptr_(p), timeout_(t) {}
|
||||||
static void eventTrampoline(int ret, const char* msg, std::size_t len, void* ud) {
|
static void eventTrampoline(int ret, const char* msg, std::size_t len, void* ud) {
|
||||||
if (!ud) return;
|
if (!ud) return;
|
||||||
|
|||||||
@ -154,6 +154,7 @@ pub struct MyTimerCtx {
|
|||||||
ptr: *mut c_void,
|
ptr: *mut c_void,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
events: *mut Events,
|
events: *mut Events,
|
||||||
|
event_listener_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: The `ptr` field points to an FFIContext owned by the Nim runtime.
|
// SAFETY: The `ptr` field points to an FFIContext owned by the Nim runtime.
|
||||||
@ -190,7 +191,7 @@ impl MyTimerCtx {
|
|||||||
})?;
|
})?;
|
||||||
let addr_str: String = decode_cbor(&raw_bytes)?;
|
let addr_str: String = decode_cbor(&raw_bytes)?;
|
||||||
let addr: usize = addr_str.parse().map_err(|e: std::num::ParseIntError| e.to_string())?;
|
let addr: usize = addr_str.parse().map_err(|e: std::num::ParseIntError| e.to_string())?;
|
||||||
Ok(Self { ptr: addr as *mut c_void, timeout, events: std::ptr::null_mut() })
|
Ok(Self { ptr: addr as *mut c_void, timeout, events: std::ptr::null_mut(), event_listener_id: 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_async(config: TimerConfig, timeout: Duration) -> Result<Self, String> {
|
pub async fn new_async(config: TimerConfig, timeout: Duration) -> Result<Self, String> {
|
||||||
@ -202,14 +203,19 @@ impl MyTimerCtx {
|
|||||||
}).await?;
|
}).await?;
|
||||||
let addr_str: String = decode_cbor(&raw_bytes)?;
|
let addr_str: String = decode_cbor(&raw_bytes)?;
|
||||||
let addr: usize = addr_str.parse().map_err(|e: std::num::ParseIntError| e.to_string())?;
|
let addr: usize = addr_str.parse().map_err(|e: std::num::ParseIntError| e.to_string())?;
|
||||||
Ok(Self { ptr: addr as *mut c_void, timeout, events: std::ptr::null_mut() })
|
Ok(Self { ptr: addr as *mut c_void, timeout, events: std::ptr::null_mut(), event_listener_id: 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attach typed event handlers. Replacing handlers calls the
|
/// Attach typed event handlers. Each call removes any previous
|
||||||
/// dylib's set_event_callback with a fresh trampoline target.
|
/// listener via `_remove_event_listener` before adding the new
|
||||||
/// The previously-installed Events box (if any) is dropped here,
|
/// one, so the registry never holds a pointer into a freed box.
|
||||||
/// so callbacks in flight on the FFI thread must already be done.
|
|
||||||
pub fn set_event_handlers(&mut self, handlers: Events) {
|
pub fn set_event_handlers(&mut self, handlers: Events) {
|
||||||
|
if self.event_listener_id != 0 {
|
||||||
|
unsafe {
|
||||||
|
let _ = ffi::my_timer_remove_event_listener(self.ptr, self.event_listener_id);
|
||||||
|
}
|
||||||
|
self.event_listener_id = 0;
|
||||||
|
}
|
||||||
if !self.events.is_null() {
|
if !self.events.is_null() {
|
||||||
unsafe { drop(Box::from_raw(self.events)); }
|
unsafe { drop(Box::from_raw(self.events)); }
|
||||||
self.events = std::ptr::null_mut();
|
self.events = std::ptr::null_mut();
|
||||||
@ -217,7 +223,9 @@ impl MyTimerCtx {
|
|||||||
let raw = Box::into_raw(Box::new(handlers));
|
let raw = Box::into_raw(Box::new(handlers));
|
||||||
self.events = raw;
|
self.events = raw;
|
||||||
unsafe {
|
unsafe {
|
||||||
ffi::my_timer_set_event_callback(self.ptr, my_timer_event_trampoline, raw as *mut c_void);
|
self.event_listener_id = ffi::my_timer_add_event_listener(
|
||||||
|
self.ptr, b"\0".as_ptr() as *const c_char,
|
||||||
|
my_timer_event_trampoline, raw as *mut c_void);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,5 +15,6 @@ extern "C" {
|
|||||||
pub fn my_timer_complex(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
|
pub fn my_timer_complex(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
|
||||||
pub fn my_timer_schedule(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
|
pub fn my_timer_schedule(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
|
||||||
pub fn my_timer_destroy(ctx: *mut c_void) -> c_int;
|
pub fn my_timer_destroy(ctx: *mut c_void) -> c_int;
|
||||||
pub fn my_timer_set_event_callback(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void);
|
pub fn my_timer_add_event_listener(ctx: *mut c_void, event_name: *const c_char, callback: FFICallback, user_data: *mut c_void) -> u64;
|
||||||
|
pub fn my_timer_remove_event_listener(ctx: *mut c_void, listener_id: u64) -> c_int;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -161,10 +161,18 @@ proc emitEventDispatcher(
|
|||||||
lines.add(" };")
|
lines.add(" };")
|
||||||
lines.add("")
|
lines.add("")
|
||||||
lines.add(" void setEventHandlers(Events handlers) {")
|
lines.add(" void setEventHandlers(Events handlers) {")
|
||||||
lines.add(" events_ = std::make_unique<Events>(std::move(handlers));")
|
# Drop the previously-registered listener so the registry never holds
|
||||||
|
# a dangling pointer into a freed `Events` heap object.
|
||||||
|
lines.add(" if (event_listener_id_ != 0) {")
|
||||||
lines.add(
|
lines.add(
|
||||||
" $1_set_event_callback(ptr_, &$2::eventTrampoline, events_.get());" %
|
" $1_remove_event_listener(ptr_, event_listener_id_);" % [libName]
|
||||||
[libName, ctxTypeName]
|
)
|
||||||
|
lines.add(" event_listener_id_ = 0;")
|
||||||
|
lines.add(" }")
|
||||||
|
lines.add(" events_ = std::make_unique<Events>(std::move(handlers));")
|
||||||
|
lines.add(" event_listener_id_ = $1_add_event_listener(" % [libName])
|
||||||
|
lines.add(
|
||||||
|
" ptr_, \"\", &$1::eventTrampoline, events_.get());" % [ctxTypeName]
|
||||||
)
|
)
|
||||||
lines.add(" }")
|
lines.add(" }")
|
||||||
lines.add("")
|
lines.add("")
|
||||||
@ -303,13 +311,15 @@ proc generateCppHeader*(
|
|||||||
)
|
)
|
||||||
of FFIKind.DTOR:
|
of FFIKind.DTOR:
|
||||||
lines.add("int $1(void* ctx);" % [p.procName])
|
lines.add("int $1(void* ctx);" % [p.procName])
|
||||||
# The event-callback setter is always exported by the dylib (via
|
# `declareLibrary` always exports the listener-registration ABI;
|
||||||
# declareLibrary). Declare it here so the typed event-handler wiring
|
# declare it here so the typed event-handler wiring below can call in.
|
||||||
# below can call into it.
|
|
||||||
lines.add(
|
lines.add(
|
||||||
"void $1_set_event_callback(void* ctx, FFICallback callback, void* user_data);" %
|
"uint64_t $1_add_event_listener(void* ctx, const char* event_name, FFICallback callback, void* user_data);" %
|
||||||
[libName]
|
[libName]
|
||||||
)
|
)
|
||||||
|
lines.add(
|
||||||
|
"int $1_remove_event_listener(void* ctx, uint64_t listener_id);" % [libName]
|
||||||
|
)
|
||||||
lines.add("} // extern \"C\"")
|
lines.add("} // extern \"C\"")
|
||||||
lines.add("")
|
lines.add("")
|
||||||
|
|
||||||
@ -501,6 +511,7 @@ proc generateCppHeader*(
|
|||||||
lines.add(" std::chrono::milliseconds timeout_;")
|
lines.add(" std::chrono::milliseconds timeout_;")
|
||||||
if events.len > 0:
|
if events.len > 0:
|
||||||
lines.add(" std::unique_ptr<Events> events_;")
|
lines.add(" std::unique_ptr<Events> events_;")
|
||||||
|
lines.add(" uint64_t event_listener_id_ = 0;")
|
||||||
lines.add(
|
lines.add(
|
||||||
" explicit $1(void* p, std::chrono::milliseconds t) : ptr_(p), timeout_(t) {}" %
|
" explicit $1(void* p, std::chrono::milliseconds t) : ptr_(p), timeout_(t) {}" %
|
||||||
[ctxTypeName]
|
[ctxTypeName]
|
||||||
|
|||||||
@ -207,10 +207,14 @@ proc generateFFIRs*(procs: seq[FFIProcMeta]): string =
|
|||||||
params.add("ctx: *mut c_void")
|
params.add("ctx: *mut c_void")
|
||||||
lines.add(" pub fn $1($2) -> c_int;" % [p.procName, params.join(", ")])
|
lines.add(" pub fn $1($2) -> c_int;" % [p.procName, params.join(", ")])
|
||||||
|
|
||||||
# Event-callback setter — emitted on the Nim side by `declareLibrary`,
|
# Listener-registration ABI — emitted by `declareLibrary`, always
|
||||||
# always present in the dylib.
|
# present in the dylib.
|
||||||
lines.add(
|
lines.add(
|
||||||
" pub fn $1_set_event_callback(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void);" %
|
" pub fn $1_add_event_listener(ctx: *mut c_void, event_name: *const c_char, callback: FFICallback, user_data: *mut c_void) -> u64;" %
|
||||||
|
[linkLibName]
|
||||||
|
)
|
||||||
|
lines.add(
|
||||||
|
" pub fn $1_remove_event_listener(ctx: *mut c_void, listener_id: u64) -> c_int;" %
|
||||||
[linkLibName]
|
[linkLibName]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -523,6 +527,7 @@ proc generateApiRs*(
|
|||||||
lines.add(" timeout: Duration,")
|
lines.add(" timeout: Duration,")
|
||||||
if events.len > 0:
|
if events.len > 0:
|
||||||
lines.add(" events: *mut Events,")
|
lines.add(" events: *mut Events,")
|
||||||
|
lines.add(" event_listener_id: u64,")
|
||||||
lines.add("}")
|
lines.add("}")
|
||||||
lines.add("")
|
lines.add("")
|
||||||
# SAFETY block applies to both impls below (PR #23 Rust review, item 7).
|
# SAFETY block applies to both impls below (PR #23 Rust review, item 7).
|
||||||
@ -622,7 +627,7 @@ proc generateApiRs*(
|
|||||||
" let addr: usize = addr_str.parse().map_err(|e: std::num::ParseIntError| e.to_string())?;"
|
" let addr: usize = addr_str.parse().map_err(|e: std::num::ParseIntError| e.to_string())?;"
|
||||||
)
|
)
|
||||||
if events.len > 0:
|
if events.len > 0:
|
||||||
lines.add(" Ok(Self { ptr: addr as *mut c_void, timeout, events: std::ptr::null_mut() })")
|
lines.add(" Ok(Self { ptr: addr as *mut c_void, timeout, events: std::ptr::null_mut(), event_listener_id: 0 })")
|
||||||
else:
|
else:
|
||||||
lines.add(" Ok(Self { ptr: addr as *mut c_void, timeout })")
|
lines.add(" Ok(Self { ptr: addr as *mut c_void, timeout })")
|
||||||
lines.add(" }")
|
lines.add(" }")
|
||||||
@ -648,7 +653,7 @@ proc generateApiRs*(
|
|||||||
" let addr: usize = addr_str.parse().map_err(|e: std::num::ParseIntError| e.to_string())?;"
|
" let addr: usize = addr_str.parse().map_err(|e: std::num::ParseIntError| e.to_string())?;"
|
||||||
)
|
)
|
||||||
if events.len > 0:
|
if events.len > 0:
|
||||||
lines.add(" Ok(Self { ptr: addr as *mut c_void, timeout, events: std::ptr::null_mut() })")
|
lines.add(" Ok(Self { ptr: addr as *mut c_void, timeout, events: std::ptr::null_mut(), event_listener_id: 0 })")
|
||||||
else:
|
else:
|
||||||
lines.add(" Ok(Self { ptr: addr as *mut c_void, timeout })")
|
lines.add(" Ok(Self { ptr: addr as *mut c_void, timeout })")
|
||||||
lines.add(" }")
|
lines.add(" }")
|
||||||
@ -656,11 +661,25 @@ proc generateApiRs*(
|
|||||||
|
|
||||||
# ── Typed event registration ───────────────────────────────────────────
|
# ── Typed event registration ───────────────────────────────────────────
|
||||||
if events.len > 0:
|
if events.len > 0:
|
||||||
lines.add(" /// Attach typed event handlers. Replacing handlers calls the")
|
lines.add(
|
||||||
lines.add(" /// dylib's set_event_callback with a fresh trampoline target.")
|
" /// Attach typed event handlers. Each call removes any previous"
|
||||||
lines.add(" /// The previously-installed Events box (if any) is dropped here,")
|
)
|
||||||
lines.add(" /// so callbacks in flight on the FFI thread must already be done.")
|
lines.add(
|
||||||
|
" /// listener via `_remove_event_listener` before adding the new"
|
||||||
|
)
|
||||||
|
lines.add(
|
||||||
|
" /// one, so the registry never holds a pointer into a freed box."
|
||||||
|
)
|
||||||
lines.add(" pub fn set_event_handlers(&mut self, handlers: Events) {")
|
lines.add(" pub fn set_event_handlers(&mut self, handlers: Events) {")
|
||||||
|
lines.add(" if self.event_listener_id != 0 {")
|
||||||
|
lines.add(" unsafe {")
|
||||||
|
lines.add(
|
||||||
|
" let _ = ffi::$1_remove_event_listener(self.ptr, self.event_listener_id);" %
|
||||||
|
[libName]
|
||||||
|
)
|
||||||
|
lines.add(" }")
|
||||||
|
lines.add(" self.event_listener_id = 0;")
|
||||||
|
lines.add(" }")
|
||||||
lines.add(" if !self.events.is_null() {")
|
lines.add(" if !self.events.is_null() {")
|
||||||
lines.add(" unsafe { drop(Box::from_raw(self.events)); }")
|
lines.add(" unsafe { drop(Box::from_raw(self.events)); }")
|
||||||
lines.add(" self.events = std::ptr::null_mut();")
|
lines.add(" self.events = std::ptr::null_mut();")
|
||||||
@ -669,9 +688,13 @@ proc generateApiRs*(
|
|||||||
lines.add(" self.events = raw;")
|
lines.add(" self.events = raw;")
|
||||||
lines.add(" unsafe {")
|
lines.add(" unsafe {")
|
||||||
lines.add(
|
lines.add(
|
||||||
" ffi::$1_set_event_callback(self.ptr, $1_event_trampoline, raw as *mut c_void);" %
|
" self.event_listener_id = ffi::$1_add_event_listener(" %
|
||||||
[libName]
|
[libName]
|
||||||
)
|
)
|
||||||
|
lines.add(" self.ptr, b\"\\0\".as_ptr() as *const c_char,")
|
||||||
|
lines.add(
|
||||||
|
" $1_event_trampoline, raw as *mut c_void);" % [libName]
|
||||||
|
)
|
||||||
lines.add(" }")
|
lines.add(" }")
|
||||||
lines.add(" }")
|
lines.add(" }")
|
||||||
lines.add("")
|
lines.add("")
|
||||||
|
|||||||
@ -108,51 +108,85 @@ macro declareLibraryBase*(libraryName: static[string]): untyped =
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
macro declareLibrary*(libraryName: static[string], libType: untyped): untyped =
|
macro declareLibrary*(libraryName: static[string], libType: untyped): untyped =
|
||||||
## Declares a library with the given name and automatically generates
|
## Declares a library with the given name and emits the C-exported event
|
||||||
## `{libraryName}_set_event_callback`, a C-exported function that stores the
|
## ABI on its `FFIContext`:
|
||||||
## caller's event callback on the FFIContext.
|
|
||||||
##
|
##
|
||||||
## `libType` is the Nim type of the main library object (e.g. `Waku`). It is used
|
## - `{libraryName}_add_event_listener(ctx, event_name, cb, ud) -> uint64`
|
||||||
## to type the `ctx: ptr FFIContext[libType]` parameter of the generated
|
## — registers `cb` for `event_name` and returns its stable id. An
|
||||||
## `{libraryName}_set_event_callback` proc.
|
## empty `event_name` subscribes `cb` to *every* event (catch-all).
|
||||||
|
## - `{libraryName}_remove_event_listener(ctx, id) -> cint` — returns 0 on
|
||||||
|
## success, non-zero if no listener with that id exists.
|
||||||
|
##
|
||||||
|
## `libType` is the Nim type of the main library object, used to type
|
||||||
|
## the `ctx: ptr FFIContext[libType]` parameter. See
|
||||||
|
## `examples/timer/timer.nim` for a working call site.
|
||||||
var stmts = newStmtList()
|
var stmts = newStmtList()
|
||||||
|
|
||||||
# Emit the base bootstrap (pragmas, linker flags, NimMain, initializeLibrary)
|
# Emit the base bootstrap (pragmas, linker flags, NimMain, initializeLibrary)
|
||||||
stmts.add(newCall(ident("declareLibraryBase"), newStrLitNode(libraryName)))
|
stmts.add(newCall(ident("declareLibraryBase"), newStrLitNode(libraryName)))
|
||||||
|
|
||||||
let funcName = libraryName & "_set_event_callback"
|
|
||||||
let funcIdent = ident(funcName)
|
|
||||||
let errorMsg = "error: invalid context in " & funcName
|
|
||||||
|
|
||||||
let ctxType = nnkPtrTy.newTree(nnkBracketExpr.newTree(ident("FFIContext"), libType))
|
let ctxType = nnkPtrTy.newTree(nnkBracketExpr.newTree(ident("FFIContext"), libType))
|
||||||
|
let cdeclExportPragma = newTree(
|
||||||
let procBody = quote:
|
nnkPragma,
|
||||||
if isNil(ctx):
|
ident("dynlib"),
|
||||||
echo `errorMsg`
|
ident("exportc"),
|
||||||
return
|
ident("cdecl"),
|
||||||
removeAllEventListeners(ctx[].eventRegistry)
|
newTree(nnkExprColonExpr, ident("raises"), newTree(nnkBracket)),
|
||||||
if not callback.isNil():
|
)
|
||||||
discard addEventListener(
|
|
||||||
ctx[].eventRegistry, WildcardEventName, callback, userData
|
# {libraryName}_add_event_listener
|
||||||
)
|
let addName = libraryName & "_add_event_listener"
|
||||||
|
let addErr = "error: invalid context in " & addName
|
||||||
let procNode = newProc(
|
let addBody = quote:
|
||||||
name = funcIdent,
|
var ret: uint64 = 0
|
||||||
params = @[
|
if isNil(ctx):
|
||||||
newEmptyNode(),
|
echo `addErr`
|
||||||
newIdentDefs(ident("ctx"), ctxType),
|
return ret
|
||||||
newIdentDefs(ident("callback"), ident("FFICallBack")),
|
let evtName = if eventName.isNil(): "" else: $eventName
|
||||||
newIdentDefs(ident("userData"), ident("pointer")),
|
ret = addEventListener(ctx[].eventRegistry, evtName, callback, userData)
|
||||||
],
|
return ret
|
||||||
body = procBody,
|
|
||||||
pragmas = newTree(
|
stmts.add(
|
||||||
nnkPragma,
|
newProc(
|
||||||
ident("dynlib"),
|
name = ident(addName),
|
||||||
ident("exportc"),
|
params = @[
|
||||||
ident("cdecl"),
|
ident("uint64"),
|
||||||
newTree(nnkExprColonExpr, ident("raises"), newTree(nnkBracket)),
|
newIdentDefs(ident("ctx"), ctxType),
|
||||||
),
|
newIdentDefs(ident("eventName"), ident("cstring")),
|
||||||
|
newIdentDefs(ident("callback"), ident("FFICallBack")),
|
||||||
|
newIdentDefs(ident("userData"), ident("pointer")),
|
||||||
|
],
|
||||||
|
body = addBody,
|
||||||
|
pragmas = cdeclExportPragma,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- {libraryName}_remove_event_listener --------------------------------
|
||||||
|
# Param is `listenerId`, not `id` — `id` collides with chronos's
|
||||||
|
# `futures.id` template under quote injection rules and the captured
|
||||||
|
# symbol wins over the injected one.
|
||||||
|
let removeName = libraryName & "_remove_event_listener"
|
||||||
|
let removeErr = "error: invalid context in " & removeName
|
||||||
|
let removeBody = quote:
|
||||||
|
var ret: cint = 1
|
||||||
|
if isNil(ctx):
|
||||||
|
echo `removeErr`
|
||||||
|
return ret
|
||||||
|
if removeEventListener(ctx[].eventRegistry, listenerId):
|
||||||
|
ret = 0
|
||||||
|
return ret
|
||||||
|
|
||||||
|
stmts.add(
|
||||||
|
newProc(
|
||||||
|
name = ident(removeName),
|
||||||
|
params = @[
|
||||||
|
ident("cint"),
|
||||||
|
newIdentDefs(ident("ctx"), ctxType),
|
||||||
|
newIdentDefs(ident("listenerId"), ident("uint64")),
|
||||||
|
],
|
||||||
|
body = removeBody,
|
||||||
|
pragmas = cdeclExportPragma,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
stmts.add(procNode)
|
|
||||||
return stmts
|
return stmts
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user