我正在为C绑定编写Rust包装器,以便它们看起来更生锈。一个这样的C函数就是:
void mosquitto_connect_callback_set(
struct mosquitto * mosq,
void (*on_connect)(struct mosquitto *, void *, int)
)
我正在使用以下技术将Rust闭包作为用户数据传递给上面的绑定(回调中的void*
),以便在调用C回调时调用Rust闭包。
// Registered callback is called when the broker sends a CONNACK message in response
// to a connection. Will be called even incase of failure. All your sub/pub stuff
// should ideally be done in this callback when connection is successful
pub fn onconnect_callback<F>(&self, callback: F)
where F: Fn(i32)
{
// Convert the rust closure into void* to be used as user_data. This will
// be passed to callback automatically by the library
let cb = &callback as *const _ as *mut libc::c_void;
unsafe {
// Set our closure as user data
bindings::mosquitto_user_data_set(self.mosquitto, cb);
// Register callback
bindings::mosquitto_connect_callback_set(self.mosquitto, Some(onconnect_wrapper::<F>));
}
// Registered callback. user data is our closure
unsafe extern "C" fn onconnect_wrapper<F>(mqtt: *mut bindings::Struct_mosquitto,
closure: *mut libc::c_void,
val: libc::c_int)
where F: Fn(i32)
{
let closure = closure as *mut F;
println!("rc = {:?}", val as i32);
(*closure)(val as i32);
}
}
但问题是用户数据是使用函数设置的,而不是直接将其传递给回调集函数
// Set our closure as user data
bindings::mosquitto_user_data_set(self.mosquitto, cb);
我认为传递给callback: F
的{{1}}闭包可能会在调用实际C回调时被销毁。这可能是我在捕获变量时获取垃圾值的原因。
onconnect_callback
输出:
let i = 100;
client.onconnect_callback(|a: i32|{
println!("i = {:?}", i);
println!("@@@ On connect callback {}@@@", a)
});
match client.connect("localhost"){
Ok(_) => println!("Connection successful --> {:?}", client),
Err(n) => panic!("Connection error = {:?}", n)
}
如何在不传递闭包作为参考的情况下解决此问题?