I’m trying to make these c functions easier to use:
pub extern fn z_closure_sample(
this_: [*c]struct_z_owned_closure_sample_t,
call: ?*const fn ([*c]struct_z_loaned_sample_t, ?*anyopaque) callconv(.c) void,
drop: ?*const fn (?*anyopaque) callconv(.c) void,
context: ?*anyopaque,
) void;
pub extern fn z_declare_subscriber(
session: [*c]const struct_z_loaned_session_t,
subscriber: [*c]struct_z_owned_subscriber_t,
key_expr: [*c]const struct_z_loaned_keyexpr_t,
callback: [*c]struct_z_moved_closure_sample_t,
options: [*c]struct_z_subscriber_options_t,
) z_result_t;
Here is what the unimproved example code looks like (without any improved bindings):
var got_message: bool = false;
fn data_handler(sample: [*c]zenoh.c.z_loaned_sample_t, arg: ?*anyopaque) callconv(.c) void {
_ = sample;
_ = arg;
std.log.info("Got sample!", .{});
got_message = true;
}
fn subscribe() !void {
var config: zenoh.c.z_owned_config_t = undefined;
_ = zenoh.c.z_config_default(&config);
defer zenoh.c.z_config_drop(zenoh.c.z_config_move(&config));
var options: zenoh.c.z_open_options_t = undefined;
zenoh.c.z_open_options_default(&options);
var session: zenoh.c.z_owned_session_t = undefined;
if (zenoh.c.z_open(&session, zenoh.c.z_config_move(&config), &options) != 0) {
std.log.err("Failed to open zenoh session.", .{});
return error.OpenSessionFailure;
}
defer zenoh.c.z_session_drop(zenoh.c.z_session_move(&session));
var callback: zenoh.c.z_owned_closure_sample_t = undefined;
zenoh.c.z_closure_sample(&callback, &data_handler, null, null);
var key_expr: zenoh.c.z_view_keyexpr_t = undefined;
_ = zenoh.c.z_view_keyexpr_from_str(&key_expr, "key/expression");
var subscriber: zenoh.c.z_owned_subscriber_t = undefined;
if (zenoh.c.z_declare_subscriber(
zenoh.c.z_session_loan_mut(&session),
&subscriber,
zenoh.c.z_view_keyexpr_loan(&key_expr),
zenoh.c.z_closure_sample_move(&callback),
null,
) != 0) {
std.log.err("Failed to create zenoh subscriber", .{});
return error.DeclareSubscriberFailure;
}
defer zenoh.c.z_subscriber_drop(zenoh.c.z_subscriber_move(&subscriber));
var timer = std.time.Timer.start() catch @panic("timer unsupported");
while (timer.read() <= std.time.ns_per_s * 10) {
if (got_message) {
break;
}
std.Thread.sleep(std.time.ns_per_s * 1);
} else {
return error.NoMessage;
}
}
How do I write bindings for registering a callback with a c function?
I have so far been constructing wrapper types on the c types:
pub const Config = struct {
_c: c.z_owned_config_t,
pub fn initDefault() Error!Config {
var c_config: c.z_owned_config_t = undefined;
try err(c.z_config_default(&c_config));
return Config{ ._c = c_config };
}
}
The docs for the function are:
void z_closure_sample(struct z_owned_closure_sample_t *this_, void (*call)(struct z_loaned_sample_t *sample, void *context), void (*drop)(void *context), void *context)
Constructs closure.
Closures are not guaranteed not to be called concurrently.
It is guaranteed that:
call will never be called once drop has started.
drop will only be called once, and after every call has ended.
The two previous guarantees imply that call and drop are never called concurrently.
Parameters:
this_ – uninitialized memory location where new closure will be constructed.
call – a closure body.
drop – an optional function to be called once on closure drop.
context – closure context.
- How can I “register a callback” with the C API so that it returns a zig type?
- Does anyone have any examples of bindings that register callbacks with c functions?
- Why is there a drop callback?