结构的通用反序列化(类型 - 惩罚)(与借用检查器对抗)

时间:2014-10-28 18:09:08

标签: rust

我正在使用打包的结构,我需要能够从原始的 字节到结构,反之亦然,没有任何解码/编码开销。

我写了一些似乎有用的代码:

#[packed]
struct Test {
    data: u64
}
impl Test {
    fn from_byte_slice(bs: &[u8]) -> Option<Test> {
        if bs.len() != std::mem::size_of::<Test>() {
            None
        } else {
            let p: *const u8 = &bs[0];
            let p2: *const Test = p as *const Test;
            unsafe {
                Some(*p2)
            }
        }
    }
}

但是我有几个不同的结构需要序列化/去序列化 所以我想使用通用函数来减少代码重复。

以下代码无法使用错误消息进行编译:“错误:无法移出*的引用 - 指针”

fn from_byte_slice<T>(bs: &[u8]) -> Option<T> {
    if bs.len() != std::mem::size_of::<T>() {
        None
    } else {
        let p: *const u8 = &bs[0];
        let p2: *const T = p as *const T;
        unsafe {
            Some(*p2)
        }
    }
}

奇怪的是,如果我没有返回选项,则返回选项&lt;&amp; T&gt;然后代码编译:

fn from_byte_slice<'a, T>(bs: &'a [u8]) -> Option<&'a T> {
    if bs.len() != std::mem::size_of::<T>() {
        None
    } else {
        let p: *const u8 = &bs[0];
        let p2: *const T = p as *const T;
        unsafe {
            Some(&*p2)
        }
    }
}

我做错了什么或者我在借阅检查器中遇到了错误?

1 个答案:

答案 0 :(得分:3)

参数bs: &[u8]是一个切片,并且借用。这是一种临时所有权形式,您无法将数据移出。 *p2就是这样做的,它会移除该数据的所有权。

你需要克隆它:

fn from_byte_slice<T: Clone>(bs: &[u8]) -> Option<T> {
    if bs.len() != std::mem::size_of::<T>() {
        None
    } else {
        let p: *const u8 = &bs[0];
        let p2: *const T = p as *const T;
        unsafe {
            Some((*p2).clone())
        }
    }
}

如果你不介意将拥有的向量移动到函数中,那么使用transmute你可能会使用Vec<u8>来完成这项工作。

第一种情况中的直接impl有效,因为Test包含所有Copy字段,因此被隐式复制(而不是需要显式的clone())。

probably will change soonCopy将来必须明确派生。