You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Rust Deserializer处理带u8判别式的Crc枚举反序列化

手动实现Crc枚举的Serde反序列化

核心思路

你的二进制格式是首字节为判别式,后续为对应长度的校验和字节数组,反序列化的关键逻辑如下:

  • 先读取第一个u8判别式,确定目标枚举变体
  • 根据判别式读取对应长度的字节,转换成固定大小数组
  • 构造对应的Crc枚举实例

具体代码实现

首先确保Cargo.toml中包含依赖:

[dependencies]
serde = { version = "1.0", features = ["derive"] }

完整实现代码:

use serde::{Deserialize, Deserializer, de::{Visitor, SeqAccess, Error}};
use std::fmt;

#[derive(Debug, PartialEq)]
enum Crc {
    Crc16([u8; 16]),
    Crc32([u8; 32]),
    Crc64([u8; 64]),
}

// 自定义Visitor处理变体区分与数组反序列化
struct CrcVisitor;

impl<'de> Visitor<'de> for CrcVisitor {
    type Value = Crc;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("CRC判别式(u8) + 对应长度的校验和字节数组")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        // 第一步:读取判别式
        let discriminant: u8 = seq.next_element()?.ok_or_else(|| Error::custom("缺少判别式"))?;

        // 第二步:根据判别式读取对应长度的字节数组
        match discriminant {
            0 => {
                let mut bytes = [0u8; 16];
                for i in 0..16 {
                    bytes[i] = seq.next_element()?.ok_or_else(|| Error::custom(format!("Crc16缺失第{}个字节", i)))?;
                }
                Ok(Crc::Crc16(bytes))
            }
            1 => {
                let mut bytes = [0u8; 32];
                for i in 0..32 {
                    bytes[i] = seq.next_element()?.ok_or_else(|| Error::custom(format!("Crc32缺失第{}个字节", i)))?;
                }
                Ok(Crc::Crc32(bytes))
            }
            2 => {
                let mut bytes = [0u8; 64];
                for i in 0..64 {
                    bytes[i] = seq.next_element()?.ok_or_else(|| Error::custom(format!("Crc64缺失第{}个字节", i)))?;
                }
                Ok(Crc::Crc64(bytes))
            }
            _ => Err(Error::custom(format!("未知CRC判别式: {}", discriminant))),
        }
    }
}

// 为Crc实现Deserialize trait
impl<'de> Deserialize<'de> for Crc {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // 传入最大序列长度(1个判别式+64个字节),适配所有变体
        deserializer.deserialize_tuple(1 + 64, CrcVisitor)
    }
}

关键细节说明

  • 判别式映射:示例中用0对应Crc16、1对应Crc32、2对应Crc64,可根据实际协议调整数值
  • 数组读取逻辑:通过循环逐个填充固定大小数组,避开serde原生对数组大小的32限制
  • 错误处理:覆盖了判别式缺失、字节缺失、非法判别式等场景,符合serde错误规范
  • 序列长度参数:deserialize_tuple传入1+64是因为最大变体需要1个判别式+64个字节,确保反序列化器能处理所有情况

测试示例

用bincode验证实现逻辑:

use bincode;

fn main() {
    // 测试Crc16:判别式0 + 16个0字节
    let test_data = [0u8; 17];
    let crc: Crc = bincode::deserialize(&test_data).unwrap();
    assert_eq!(crc, Crc::Crc16([0u8; 16]));

    // 测试Crc64:判别式2 + 64个1字节
    let mut crc64_data = vec![2u8];
    crc64_data.extend(vec![1u8; 64]);
    let crc: Crc = bincode::deserialize(&crc64_data).unwrap();
    assert_eq!(crc, Crc::Crc64([1u8; 64]));
}

内容的提问来源于stack exchange,提问作者Phidelux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 17:47:26