传递一个数组似乎工作正常:
fn set_zero<'a>(u: &'a u32, ms: &mut [Option<&'a u32>; 4]) {
ms[0] = Some(u);
}
我试图包装传递void *
的C回调函数
所以我使用std::any::Any
而不是数组:
fn set_zero<'a>(u: &'a u32, ma: &mut Any) {
if let Some(ms) = ma.downcast_mut::<[Option<&'a u32>; 4]>() {
ms[0] = Some(u);
}
}
这会导致与生命周期相关的错误:
error[E0477]: the type `[std::option::Option<&'a u32>; 4]`
does not fulfill the required lifetime
--> option.rs:18:26
|
18 | if let Some(ms) = ma.downcast_mut::<[Option<&'a u32>; 4]>() {
| ^^^^^^^^^^^^
|
= note: type must outlive the static lifetime
我该如何解决这个问题?应该阅读哪些文档才能更好地理解错误?
更新:更详细的背景资料:
一个人为设计的C原型是 - foo.c:
#include <stdint.h>
typedef int (*cb_t)(const uint32_t *obj, void *arg);
int32_t cb_run(uint32_t const objs[], uint32_t len, cb_t cb, void *arg)
{
int i;
for (i = 0; i < len; i++)
if (cb(&objs[i], arg) < 0)
return -1;
return 0;
}
然后,我尝试使用Any
包裹:
extern crate libc;
use libc::{c_int, size_t, c_void};
use std::any::Any;
type CbT = extern "C" fn(obj: *const u32, arg: *mut c_void) -> c_int;
extern { fn cb_run(objs: *const u32, len: size_t, cb: CbT, arg: *mut c_void) -> c_int; }
type Cb = fn(obj: &u32, arg: &mut Any) -> i32;
struct CbData <'a> {
cb: Cb,
arg: &'a mut Any,
}
extern fn rust_cb(obj: *const u32, arg: *mut c_void) -> c_int {
unsafe {
let s = &mut *(arg as *mut CbData);
(s.cb)(&*obj, s.arg)
}
}
fn cb_run_rs(objs: &[u32], cb: Cb, arg: &mut Any) -> i32 {
let mut arg = &mut CbData{ cb: cb, arg: arg } ;
unsafe { cb_run(objs.as_ptr() as *const u32, objs.len() as size_t,
rust_cb, arg as *mut _ as *mut c_void) as i32 }
}
//// the above is lib, the below is bin
// set_zero() in the above
fn my_cb<'a>(obj: &'a u32, arg: &mut Any) -> i32 {
if let Some(data) = arg.downcast_mut::<[Option<&'a u32>; 4]>() {
data[0] = Some(obj);
}
0
}
fn main() {
let objs = [0u32, 1, 2, 3];
let mut arg = [None; 4];
println!("pre : {:?}", arg);
cb_run_rs(&objs, my_cb, &mut arg);
println!("post : {:?}", arg);
}
它导致note: type must outlive the static lifetime
。
如果没有来自库用户的void *
,我该如何以良好的方式处理这种unsafe
?
答案 0 :(得分:0)
我只能告诉它似乎有效。 main.rs
extern crate libc;
use libc::{c_int, size_t, c_void};
type CbT = extern "C" fn(obj: *const u32, arg: *mut c_void) -> c_int;
extern { fn cb_run(objs: *const u32, len: size_t, cb: CbT, arg: *mut c_void) -> c_int; }
type Cb <'a, T: ?Sized> = fn(obj: &'a u32, arg: &mut T) -> i32;
struct CbData <'a, 'b, T: 'a + 'b + ?Sized> {
cb: Cb<'a, T>,
arg: &'b mut T,
}
extern fn rust_cb<T: ?Sized>(obj: *const u32, arg: *mut c_void) -> c_int {
unsafe {
let s = &mut *(arg as *mut CbData<T>);
(s.cb)(&*obj, s.arg)
}
}
fn cb_run_rs<'a, 'b, T: 'a + ?Sized>(objs: &[u32], cb: Cb<'a, T>, arg: &'b mut T) -> i32 {
let mut arg = &mut CbData{ cb: cb, arg: arg } ;
unsafe { cb_run(objs.as_ptr() as *const u32, objs.len() as size_t,
rust_cb::<T>, arg as *mut _ as *mut c_void) as i32 }
}
//// the above is lib, the below is bin
fn my_cb<'a>(obj: &'a u32, arg: &mut [Option<&'a u32>]) -> i32 {
arg[*obj as usize] = Some(obj);
0
}
fn main() {
let objs = [0u32, 1, 2, 3];
let mut arg = [None; 4];
println!("pre : {:?}", arg);
cb_run_rs(&objs, my_cb, &mut arg);
println!("post : {:?}", arg);
}
FYI build.rs:
extern crate gcc;
fn main() {
gcc::compile_library("libfoo.a", &["src/foo.c"]);
}
Cargo.toml:
[package]
name = "sof"
version = "0.1.0"
authors = ["author@example.com"]
build = "build.rs"
[build-dependencies]
gcc = "0.3"
[dependencies]
libc = "0.2"