我一直在尝试用 Rust 编写 Redis 模块。这是我第一次尝试使用 Rust FFI 和绑定(bind)。如何在 Rust 中调用此方法并最终得到数据值而不破坏 Redis 指针?
extern "C" {
pub static mut RedisModule_GetTimerInfo: ::std::option::Option<
unsafe extern "C" fn(
ctx: *mut RedisModuleCtx,
id: RedisModuleTimerID,
remaining: *mut u64,
data: *mut *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int,
>;
}
请参阅RedisModule_GetTimerInfo API Docs了解更多详情。
我最终让它工作,但如果我使用相同的 id
调用它两次,它会抛出错误:
let mut ms = 0 as u64;
let val = "";
let ptr = Box::into_raw(Box::new(&mut val)) as *mut *mut c_void;
let ok = unsafe { RedisModule_GetTimerInfo.unwrap()(ctx, id, &mut ms, ptr) };
let mut data: Option<String> = None;
if ok == 0 {
let val = unsafe { Box::from_raw(*ptr as *mut &str) };
// trim nul bytes
data = Some(val.trim_matches(char::from(0)).to_string());
}
这不起作用,因为 Box::from_raw
拥有原始指针,并且当盒子被放下时指针会被销毁。
我在不使用 Box::into_raw 和 Box::from_raw 的情况下尝试了无数种方法来完成这项工作,但每次它们要么导致 Redis 崩溃,要么最终成为一个我不知道如何转换为 &str
的指针。
更新:我最初有一个使用 RedisModule_StopTimer
的示例,这是一个错误。已更正为使用我询问的方法。
最佳答案
我是 redismodule-rs 的维护者之一crate,它提供了用于编写 Redis 模块的高级 Rust API。
根据您的问题,我考虑以安全的方式将这些计时器 API 添加到包中,并在完成后将代码推送到存储库。
以下代码展示了如何安全地检索数据:
// Create local variables to hold the returned values
let mut remaining: u64 = 0;
let mut data: *mut c_void = std::ptr::null_mut();
// Call the API and retrieve the values into the local variables
let status = unsafe {
RedisModule_GetTimerInfo.unwrap()(ctx, timer_id, &mut remaining, &mut data)
};
if status == REDISMODULE_OK {
// Cast the *mut c_void supplied by the Redis API to
// a raw pointer of our custom type:
let data = data as *mut T; // T is the type of the data, e.g. String
// Dereference the raw pointer (we know this is safe,
// since Redis should return our original pointer which
// we know to be good), and turn in into a safe reference:
let data = unsafe { &*data };
println!("Remaining: {}, data: {:?}", remaining, data);
}
关于rust - 如何在没有 Box::from_raw 的情况下将 *mut *mut c_void 转换为 &str?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60963130/