无法使用向下转换任何包含引用的数组

时间:2016-12-02 00:33:57

标签: rust

传递一个数组似乎工作正常:

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

1 个答案:

答案 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"