我接收校验和作为二进制协议的一部分,在Rust中以以下形式表示:
enum Crc {
Crc16([u8; 16])
Crc32([u8; 32])
Crc64([u8; 64])
}
我接收到编码为字节数组的枚举变量,其前导判别式为u8,后跟校验和字节数组。(参见内部讨论)结合其它固定大小类型并且serde
具有大小为32的limit for arrays,我想自己实现一个Deserializer
。我知道我必须使用Deserializer::deserialize_tuple
调用的序列访问器手动反序列化数组,但我如何处理不同的变体呢?
1条答案
按热度按时间2w2cym1i1#
无需为此实现自定义
Deserializer
。只要提供自定义Deserialize
实现来指示期望接收的数据,您仍然可以使用bincode'
sDeserializer
。从本质上讲,有两个独立的数据片段,你期望:变量判别式(作为字节)和校验和字节(大小不同,取决于变量)。您可以将其建模为2元组数据:
(discriminant: u8, checksum_bytes: [u8; LEN])
对于某个LEN
,它是16、32或64。我们可以分别对待每一部分:
变体
你是对的,默认情况下,
bincode
不能将变体判别式视为u8
s。但这并不意味着我们不能定义Deserialize
实现来将它们视为u8
s。现在我们已经定义了自己的variant类型(与
serde_derive
派生的类型相反),它将一个字节反序列化为variant,我们可以将这个Variant
类型视为2元组中的第一个类型。校验和字节
正如你提到的,
serde
只提供长度为32的数组的实现。我们可以将这些实现用于16和32字节的数组,但我们需要定义自己的类型来反序列化64字节的数组:这会将一个64字节的数组反序列化为一个
Crc64
struct
。使用的方法与serde
为长度为1-32的数组提供的方法非常相似。把它放在一起
现在我们拥有所需的所有部件:我们可以反序列化变量discriminate,我们可以反序列化任何所需大小的字节数组。最后一步是告诉
serde
我们期望一个2元组,然后在访问者中反序列化该数据。这首先将变量反序列化为我们的
Variant
类型,然后,根据找到的判别式,将剩余的字节反序列化为正确的长度。请注意,我们必须使用Crc64
类型来反序列化64字节数组。完整的代码可以在playground上找到。请注意,您实际上无法在playground上使用
bincode
进行测试,因为bincode
在那里不作为依赖项提供,但它应该可以在bincode
版本1.3.3上正常工作,这是我测试的版本。