如何使用serde和bincode映射具有超过32字节填充的C结构体?

4
我正在使用serde和bincode来映射二进制结构。
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate bincode;

#[derive(Serialize, Deserialize)]
struct Superblock {
    magic: [u8; 16],
    //reserved: [u8; 492],
    crc: u32,
}

事情按照预期进行,但我无法映射保留字段。显然,固定大小的数组仅定义了最大32个字节的大小。

我该如何注册我的自定义大小的数组以便填充被反序列化?

serde+bincode是否是正确的方法? 我需要控制字节序(bincode提供)并喜欢声明式风格。


我想我会放弃填充并使用字节顺序单独获取CRC。 - Gabriel
2
如果您确实想使用固定大小的数组,https://github.com/fizyk20/generic-array/ 可能会对您有所帮助。它具有“serde”功能,允许serde反序列化。它不完全是一个固定大小的数组,但实现方式略有不同,但内存表示完全相同,并且应该允许所有相同的用途。 - daboross
3个回答

7

serde_derive支持字段属性#[serde(serialize_with="func")]#[serde(deserialize_with="func")]#[serde(with="module")],这使得可以提供自定义的序列化/反序列化程序:

#[derive(Serialize, Deserialize)]
struct Superblock {
    magic: [u8; 16],
    #[serde(with="array_492")]   // <--
    reserved: [u8; 492],
    crc: u32,
}

mod array_492 {
    use serde::*;

    pub fn serialize<S, T>(array: &[T; 492], ser: S) -> Result<S::Ok, S::Error> 
        where S: Serializer, T: Serialize
    {
        unimplemented!() // fill in yourself.
    }

    pub fn deserialize<'de, D, T>(de: D) -> Result<[T; 492], D::Error> { 
        where D: Deserializer<'de>, T: Deserialize<'de>
    {
        unimplemented!() // fill in yourself.
    }
}

实际实现请参考此gist: https://gist.github.com/kennytm/21403667b5a17172cfcd11f9df9365e2。请注意,这不是针对一次反序列化整个字节数组进行优化的。

谢谢!由于这只是填充,几乎空的实现就可以了。 - Gabriel

4
我建议实现Serialize实现Deserialize来处理自定义类型。
需要注意的重要一点是,您根本不关心数据。这意味着不需要占用内存!我们可以定义一个类型Reserved,它将序列化为一堆字节,并从字节反序列化,但实际上不需要在内存中占用任何空间。
然后,只需填写特征实现即可:
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate bincode;

use std::fmt;
use serde::ser::SerializeTuple;

#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Superblock {
    magic: [u8; 16],
    reserved: Reserved,
    crc: u32,
}

#[derive(Debug, PartialEq)]
struct Reserved;
const RESERVED_LENGTH: usize = 492;

impl serde::Serialize for Reserved {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: serde::Serializer
    {
        let mut tuple = serializer.serialize_tuple(RESERVED_LENGTH)?;
        for _ in 0..RESERVED_LENGTH {
            tuple.serialize_element(&0xA0_u8)?; // Just to see it easily in the output
        }
        tuple.end()
    }
}

impl<'de> serde::Deserialize<'de> for Reserved {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: serde::Deserializer<'de>
    {
        struct Visitor;
        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = Reserved;

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{} bytes", RESERVED_LENGTH)
            }

            fn visit_seq<A>(self, mut tuple: A) -> Result<Self::Value, A::Error>
                where A: serde::de::SeqAccess<'de>,
            {
                for _ in 0..RESERVED_LENGTH {
                    tuple.next_element::<u8>()?;
                }
                Ok(Reserved)
            }
        }

        deserializer.deserialize_tuple(RESERVED_LENGTH, Visitor)
    }
}

fn main() {
    let block = Superblock {
        magic: [
            0x00, 0x01, 0x02, 0x03,
            0x04, 0x05, 0x06, 0x07,
            0x08, 0x09, 0x0a, 0x0b,
            0x0c, 0x0d, 0x0e, 0x0f,
        ],
        reserved: Reserved,
        crc: 0xffffffff,
    };

    let ser = bincode::serialize(&block, bincode::Infinite).expect("Couldn't serialize");
    println!("length: {}", ser.len());
    println!("{:?}", ser);

    let block2: Superblock = bincode::deserialize(&ser).expect("Couldn't deserialize");
    assert_eq!(block, block2);
    println!("{:?}", block2);

    println!("Takes: {} bytes", std::mem::size_of::<Superblock>());
    // prints "Takes: 20 bytes"
}

谢谢!通过将长度作为通用参数,这可能是bincode值得添加的一个有价值的部分。 - Gabriel
很遗憾,类型级数值(type-level numerics)目前还不存在,所以你需要使用类似 typenum 的东西来实现,这会稍微有些不够优雅。不过,当它们出现时,我认为它们将完美地适配 bincode! - Shepmaster

3

作为一种解决方法,您可以构建一个大小合适的不同对象并忽略它。例如:

reserved: ([u64; 32], [u64; 29], u32) // 492 bytes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接