代码之家  ›  专栏  ›  技术社区  ›  Kevin

将具有动态大小数据的“struct”序列化为“&[u8]”

  •  0
  • Kevin  · 技术社区  · 3 年前

    thread ,我有以下设置:

    #[repr(packed)]
    struct MyStruct {
        bytes: [u8; 4]
    }
    
    unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
        ::std::slice::from_raw_parts(
            (p as *const T) as *const u8,
            ::std::mem::size_of::<T>(),
        )
    }
    
    fn main() {
        let s = MyStruct { bytes: [0u8, 1u8, 2u8, 3u8].to_owned() };
        
        let bytes: &[u8] = unsafe { any_as_u8_slice(&s) };
        
        println!("{:?}", bytes);
    }
    

    playground )

    输出:

    [0, 1, 2, 3]
    

    这非常有效,但是它不考虑动态调整大小的结构成员,如 Vec<u8> 它们的大小需要在运行时确定。理想情况下,我希望对 Vec<u8>

    目前,我有以下几点:

    #[repr(packed)]
    struct MyStruct {
        bytes: Vec<u8>
    }
    
    unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
        ::std::slice::from_raw_parts(
            (p as *const T) as *const u8,
            ::std::mem::size_of::<T>(),
        )
    }
    
    fn main() {
        let s = MyStruct { bytes: [0u8, 1u8, 2u8, 3u8].to_vec() };
        
        let bytes: &[u8] = unsafe { any_as_u8_slice(&s) };
        
        println!("{:?}", bytes);
    }
    

    ( playground

    输出:

    [208, 25, 156, 239, 136, 85, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]
    

    我假设上面的输出引用了某种指针,但我不确定。

    目前, bincode serde 板条箱,但它将向量的长度序列化为 usize . 我更愿意指定这个,并将长度编码为 u8 this thread . 不幸的是,这里最好的解决方案是重写 Bincode 图书馆,这使我寻找任何替代解决方案。

    编辑

    塞德 二进制码

    use serde::{Serialize};
    
    #[derive(Clone, Debug, Serialize)]
    struct MyStruct {
        bytes: Vec<u8>
    }
    
    fn main() {
        let s = MyStruct { bytes: [0u8, 1u8, 2u8, 3u8].to_vec() };
        
        let bytes = bincode::serialize(&s).unwrap();
        
        println!("{:?}", bytes);
    }
    

    输出:

    [4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3]
    

    想要的输出:

    [4, 0, 1, 2, 3]
    
    0 回复  |  直到 3 年前
        1
  •  3
  •   jonasbb    3 年前

    您看到的 Vec 这正是我们所期望的。A. 有三个元素,一个指针、长度和容量。这是 guaranteed by the standard library . 在你的例子中,你有一个指针,长度和容量都是little endian中的数字4。

    Vec 进入 &[u8] 你想要的方式。A. & 片是一个连续的内存块,但是 Vec 基本上是间接的,这意味着它的元素不是与结构的其余部分相邻存储的。
    至少,您需要将字节收集到 Vec<u8> 或者类似,因为您需要从多个位置复制数据。

        2
  •  2
  •   kmdreko    3 年前

    如果你唯一的问题是 bincode usize configure 通过使用 with_varint_encoding 选项

    use bincode::{DefaultOptions, Options};
    use serde::Serialize;
    
    #[derive(Clone, Debug, Serialize)]
    struct MyStruct {
        bytes: Vec<u8>,
    }
    
    fn main() {
        let s = MyStruct {
            bytes: [0u8, 1u8, 2u8, 3u8].to_vec(),
        };
    
        let bytes = DefaultOptions::new()
            .with_varint_encoding()
            .serialize(&s);
    
        println!("{:?}", bytes);
    }
    

    输出:

    [4, 0, 1, 2, 3]