Rust 如何将*mut*mut c_void转换为&;str不带Box::从_raw开始?

Rust 如何将*mut*mut c_void转换为&;str不带Box::从_raw开始?,rust,ffi,Rust,Ffi,我一直在用Rust编写Redis模块。这是我第一次尝试使用Rust FFI和绑定。我如何调用此方法,并在不破坏Redis指针的情况下以Rust中的数据值结束 extern "C" { pub static mut RedisModule_GetTimerInfo: ::std::option::Option< unsafe extern "C" fn( ctx: *mut RedisModuleCtx, id: Red

我一直在用Rust编写Redis模块。这是我第一次尝试使用Rust FFI和绑定。我如何调用此方法,并在不破坏Redis指针的情况下以Rust中的数据值结束

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,
    >;
}
这不起作用,因为
Box::from_raw
是如何拥有原始指针的,并且在删除该框时指针会被销毁

我尝试了无数种方法,在不使用
Box::into_raw
Box::from_raw
的情况下实现了这一点,所有时候,它们要么崩溃了Redis,要么变成了我不知道如何转换为
&str
的指针

更新:我最初有一个使用
RedisModule\u StopTimer
的例子,这是一个错误。更正为使用我询问的方法。

使用添加的@Shepmaster之一,我终于能够解决这个问题。我发誓我试过一些变化,但没有想到尝试双拳击

以下是我所做的:

    let val = Box::new(Box::new("") as Box<&str>);
    let ptr = Box::into_raw(val);
    let ok = unsafe { RedisModule_GetTimerInfo.unwrap()(ctx, id, &mut ms, ptr as *mut *mut c_void) };
    let mut data: Option<String> = None;
    if ok == 0 {
        let val = unsafe {**ptr as &str};
        data = Some(val.trim_matches(char::from(0)).to_string());
    }
让val=Box::new(Box::new(“”)作为Box);
让ptr=Box::输入原始值(val);
让ok=unsafe{RedisModule_GetTimerInfo.unwrap()(ctx,id,&mut-ms,ptr-as*mut*mut-c_-void)};
让mut数据:选项=无;
如果ok==0{
设val=unsafe{**ptr as&str};
data=Some(val.trim_匹配(char::from(0)).to_string());
}
谢谢大家的帮助

使用@Shepmaster添加的其中一个,我终于能够解决这个问题。我发誓我试过一些变化,但没有想到尝试双拳击

以下是我所做的:

    let val = Box::new(Box::new("") as Box<&str>);
    let ptr = Box::into_raw(val);
    let ok = unsafe { RedisModule_GetTimerInfo.unwrap()(ctx, id, &mut ms, ptr as *mut *mut c_void) };
    let mut data: Option<String> = None;
    if ok == 0 {
        let val = unsafe {**ptr as &str};
        data = Some(val.trim_matches(char::from(0)).to_string());
    }
让val=Box::new(Box::new(“”)作为Box);
让ptr=Box::输入原始值(val);
让ok=unsafe{RedisModule_GetTimerInfo.unwrap()(ctx,id,&mut-ms,ptr-as*mut*mut-c_-void)};
让mut数据:选项=无;
如果ok==0{
设val=unsafe{**ptr as&str};
data=Some(val.trim_匹配(char::from(0)).to_string());
}

谢谢大家的帮助

我是板条箱的维护者之一,板条箱为编写Redis模块提供了一个高级的Rust API

在您的问题的提示下,我考虑以安全的方式将这些计时器API添加到板条箱中,并将在完成后将代码推送到repo

以下代码显示了如何安全地检索数据:

// 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);
}

我是板条箱的维护人员之一,板条箱为编写Redis模块提供了高级Rust API

在您的问题的提示下,我考虑以安全的方式将这些计时器API添加到板条箱中,并将在完成后将代码推送到repo

以下代码显示了如何安全地检索数据:

// 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);
}


&str
是一个胖指针,它永远不能放在
*mut c_void
中。您需要添加更多间接寻址,如。同样相关的是,我想知道你是如何得到
数据的:*mut*mut::std::os::raw::c_void,
在c中。它看起来像是坏的c代码。不清楚你是如何使用这个API的。通过浏览文档,您似乎需要将原始指针传递到
RedisModule\u CreateTimer
,当您使用非空
数据
指针调用
RedisModule\u CreateTimerInfo
时,它会将原始指针复制到指针对象中。所以您使用什么值创建计时器?你链接到的函数和问题中的代码示例之间有什么联系?(你是无意中链接错了吗?@trentcl抱歉,是的。你说得对。我已经纠正了这个例子。
RedisModule\u StopTimer
使用
*mut*mut c\u void
读取数据进行类似的操作。
&str
是一个胖指针,它永远无法放入
*mut c\u void
中。您需要添加更多间接寻址,如。同样相关的是,我想知道你是如何得到
数据的:*mut*mut::std::os::raw::c_void,
在c中。它看起来像是坏的c代码。不清楚你是如何使用这个API的。通过浏览文档,您似乎需要将原始指针传递到
RedisModule\u CreateTimer
,当您使用非空
数据
指针调用
RedisModule\u CreateTimerInfo
时,它会将原始指针复制到指针对象中。所以您使用什么值创建计时器?你链接到的函数和问题中的代码示例之间有什么联系?(你是无意中链接错了吗?@trentcl抱歉,是的。你说得对。我已经纠正了这个例子。
RedisModule\u StopTimer
使用
*mut*mut c\u void
读取数据来执行类似的操作。
Box::from_raw
+
Box::leak
当您已经有了
*mut字符串时,似乎有点迂回;有没有理由不简单地取消引用<代码>让数据:&String=&*(数据为*mut_389;)这是一个很好的观点。我相信这样写可以让代码的读者清楚地看到,数据源于
。我还猜想编译后的代码会非常相似。接下来,我又考虑了一些,并考虑将我的代码改为使用常规引用,而不是
Box
es,这只是一个特例。我来看看它是如何工作的。我突然意识到,与
框::from_raw
相比,取消引用还有一个优势,即您可以从同一个
*mut String
创建多个共享引用,而
框的别名是不合理的,因此,当任何
数据仍然挂起时,您必须小心不要再次调用
Box::from_raw
。(当然,这只适用于您不需要
&mut
访问
字符串的情况)是的,这确实是一个显著的优势。
Box::from_raw
+
Box::leak
在您已经拥有
*mut字符串的情况下似乎有点迂回;有没有理由不简单地取消引用<代码>让数据:&String=&*(数据为*mut_389;)这是一个很好的观点。我相信是这样写的