fix(codegen): Rust bindings target the *_cbor request exports

The Rust wrapper speaks CBOR, but after the native/CBOR split it still declared
and called the bare `<name>` request symbols — which are now the *native*
(typed-args) entry points, so every Rust request hit the wrong ABI (struct/ptr
mismatch). This is the Rust counterpart of the C++ fix (914c70a), which was
missed at the time. Point the ffi.rs externs and the api.rs ctor/method calls at
`<name>_cbor`; the destructor has no CBOR variant and the event registration is
unchanged here.

Verified at runtime: the rust_client now creates a context and round-trips
version / echo / schedule over CBOR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ivan FB 2026-05-31 18:34:30 +02:00
parent 914c70a131
commit 4af031c421
No known key found for this signature in database
GPG Key ID: DF0C67A04C543270
3 changed files with 24 additions and 21 deletions

View File

@ -191,7 +191,7 @@ impl MyTimerCtx {
let req = MyTimerCreateCtorReq { config };
let req_bytes = encode_cbor(&req)?;
let raw_bytes = ffi_call_sync(timeout, |cb, ud| unsafe {
let _ = ffi::my_timer_create(req_bytes.as_ptr(), req_bytes.len(), cb, ud);
let _ = ffi::my_timer_create_cbor(req_bytes.as_ptr(), req_bytes.len(), cb, ud);
0
})?;
let addr_str: String = decode_cbor(&raw_bytes)?;
@ -203,7 +203,7 @@ impl MyTimerCtx {
let req = MyTimerCreateCtorReq { config };
let req_bytes = encode_cbor(&req)?;
let raw_bytes = ffi_call_async(timeout, move |cb, ud| unsafe {
let _ = ffi::my_timer_create(req_bytes.as_ptr(), req_bytes.len(), cb, ud);
let _ = ffi::my_timer_create_cbor(req_bytes.as_ptr(), req_bytes.len(), cb, ud);
0
}).await?;
let addr_str: String = decode_cbor(&raw_bytes)?;
@ -265,7 +265,7 @@ impl MyTimerCtx {
let req = MyTimerEchoReq { req };
let req_bytes = encode_cbor(&req)?;
let raw_bytes = ffi_call_sync(self.timeout, |cb, ud| unsafe {
ffi::my_timer_echo(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())
ffi::my_timer_echo_cbor(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())
})?;
decode_cbor::<EchoResponse>(&raw_bytes)
}
@ -275,7 +275,7 @@ impl MyTimerCtx {
let req_bytes = encode_cbor(&req)?;
let ptr = self.ptr as usize;
let raw_bytes = ffi_call_async(self.timeout, move |cb, ud| unsafe {
ffi::my_timer_echo(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())
ffi::my_timer_echo_cbor(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())
}).await?;
decode_cbor::<EchoResponse>(&raw_bytes)
}
@ -284,7 +284,7 @@ impl MyTimerCtx {
let req = MyTimerVersionReq {};
let req_bytes = encode_cbor(&req)?;
let raw_bytes = ffi_call_sync(self.timeout, |cb, ud| unsafe {
ffi::my_timer_version(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())
ffi::my_timer_version_cbor(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())
})?;
decode_cbor::<String>(&raw_bytes)
}
@ -294,7 +294,7 @@ impl MyTimerCtx {
let req_bytes = encode_cbor(&req)?;
let ptr = self.ptr as usize;
let raw_bytes = ffi_call_async(self.timeout, move |cb, ud| unsafe {
ffi::my_timer_version(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())
ffi::my_timer_version_cbor(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())
}).await?;
decode_cbor::<String>(&raw_bytes)
}
@ -303,7 +303,7 @@ impl MyTimerCtx {
let req = MyTimerComplexReq { req };
let req_bytes = encode_cbor(&req)?;
let raw_bytes = ffi_call_sync(self.timeout, |cb, ud| unsafe {
ffi::my_timer_complex(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())
ffi::my_timer_complex_cbor(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())
})?;
decode_cbor::<ComplexResponse>(&raw_bytes)
}
@ -313,7 +313,7 @@ impl MyTimerCtx {
let req_bytes = encode_cbor(&req)?;
let ptr = self.ptr as usize;
let raw_bytes = ffi_call_async(self.timeout, move |cb, ud| unsafe {
ffi::my_timer_complex(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())
ffi::my_timer_complex_cbor(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())
}).await?;
decode_cbor::<ComplexResponse>(&raw_bytes)
}
@ -322,7 +322,7 @@ impl MyTimerCtx {
let req = MyTimerScheduleReq { job, retry, schedule };
let req_bytes = encode_cbor(&req)?;
let raw_bytes = ffi_call_sync(self.timeout, |cb, ud| unsafe {
ffi::my_timer_schedule(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())
ffi::my_timer_schedule_cbor(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())
})?;
decode_cbor::<ScheduleResult>(&raw_bytes)
}
@ -332,7 +332,7 @@ impl MyTimerCtx {
let req_bytes = encode_cbor(&req)?;
let ptr = self.ptr as usize;
let raw_bytes = ffi_call_async(self.timeout, move |cb, ud| unsafe {
ffi::my_timer_schedule(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())
ffi::my_timer_schedule_cbor(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())
}).await?;
decode_cbor::<ScheduleResult>(&raw_bytes)
}

View File

@ -9,11 +9,11 @@ pub type FFICallback = unsafe extern "C" fn(
#[link(name = "my_timer")]
extern "C" {
pub fn my_timer_create(req_cbor: *const u8, req_cbor_len: usize, callback: FFICallback, user_data: *mut c_void) -> *mut c_void;
pub fn my_timer_echo(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_version(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_create_cbor(req_cbor: *const u8, req_cbor_len: usize, callback: FFICallback, user_data: *mut c_void) -> *mut c_void;
pub fn my_timer_echo_cbor(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_version_cbor(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_cbor(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_cbor(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_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;

View File

@ -195,15 +195,18 @@ proc generateFFIRs*(procs: seq[FFIProcMeta]): string =
params.add("user_data: *mut c_void")
params.add("req_cbor: *const u8")
params.add("req_cbor_len: usize")
lines.add(" pub fn $1($2) -> c_int;" % [p.procName, params.join(", ")])
# The Rust wrapper speaks CBOR, so it targets the `<name>_cbor` exports;
# the bare `<name>` symbol is the native (typed-args) entry point.
lines.add(" pub fn $1_cbor($2) -> c_int;" % [p.procName, params.join(", ")])
of FFIKind.CTOR:
# Constructor: no ctx; returns the freshly-allocated handle
params.add("req_cbor: *const u8")
params.add("req_cbor_len: usize")
params.add("callback: FFICallback")
params.add("user_data: *mut c_void")
lines.add(" pub fn $1($2) -> *mut c_void;" % [p.procName, params.join(", ")])
lines.add(" pub fn $1_cbor($2) -> *mut c_void;" % [p.procName, params.join(", ")])
of FFIKind.DTOR:
# The destructor takes no request payload, so it has no `_cbor` variant.
params.add("ctx: *mut c_void")
lines.add(" pub fn $1($2) -> c_int;" % [p.procName, params.join(", ")])
@ -646,7 +649,7 @@ proc generateApiRs*(
# on the callback.
lines.add(" let raw_bytes = ffi_call_sync(timeout, |cb, ud| unsafe {")
lines.add(
" let _ = ffi::$1(req_bytes.as_ptr(), req_bytes.len(), cb, ud);" %
" let _ = ffi::$1_cbor(req_bytes.as_ptr(), req_bytes.len(), cb, ud);" %
[ctor.procName]
)
lines.add(" 0")
@ -673,7 +676,7 @@ proc generateApiRs*(
# and rely on the callback to deliver the ctx address.
lines.add(" let raw_bytes = ffi_call_async(timeout, move |cb, ud| unsafe {")
lines.add(
" let _ = ffi::$1(req_bytes.as_ptr(), req_bytes.len(), cb, ud);" %
" let _ = ffi::$1_cbor(req_bytes.as_ptr(), req_bytes.len(), cb, ud);" %
[ctor.procName]
)
lines.add(" 0")
@ -846,7 +849,7 @@ proc generateApiRs*(
lines.add(" let req_bytes = encode_cbor(&req)?;")
lines.add(" let raw_bytes = ffi_call_sync(self.timeout, |cb, ud| unsafe {")
lines.add(
" ffi::$1(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())" %
" ffi::$1_cbor(self.ptr, cb, ud, req_bytes.as_ptr(), req_bytes.len())" %
[m.procName]
)
lines.add(" })?;")
@ -868,7 +871,7 @@ proc generateApiRs*(
" let raw_bytes = ffi_call_async(self.timeout, move |cb, ud| unsafe {"
)
lines.add(
" ffi::$1(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())" %
" ffi::$1_cbor(ptr as *mut c_void, cb, ud, req_bytes.as_ptr(), req_bytes.len())" %
[m.procName]
)
lines.add(" }).await?;")