【发布时间】:2021-09-04 18:07:47
【问题描述】:
我正在尝试为枚举类型Command 的向量编写反序列化器。我希望它有条件地反序列化;如果无符号字节值小于 100,则它是 Element,并且将像任何其他 Vec<u8> 一样被反序列化。否则,如果无符号字节值介于 100 和 2^8 之间,则它是一个操作,将被反序列化为 u8。我有以下工作实现:
Cargo.toml
[dependencies]
bincode = "1.0"
serde = { version = "1.0.99" }
main.rs
use serde::de::{Deserialize, Deserializer, Visitor, SeqAccess};
use bincode::{DefaultOptions, Options};
use std::fmt;
#[derive(Debug)]
enum Command {
Operation(u8),
Element(Vec<u8>)
}
struct VecVisitor;
impl<'de> Visitor<'de> for VecVisitor {
type Value = Vec<Command>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Commands")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error> where V: SeqAccess<'de>,
{
let length = seq.size_hint().unwrap();
let mut commands: Vec<Command> = Vec::new();
let mut count = 0;
while count < length {
count += 1;
let current: u8 = seq.next_element()?.unwrap();
match current {
1..=100 => {
let mut v: Vec<u8> = Vec::new();
for _ in 0..current {
v.push(seq.next_element()?.unwrap());
}
commands.push(Command::Element(v));
count += current as usize;
}
_ => {
commands.push(Command::Operation(current))
}
}
}
Ok(commands)
}
}
#[derive(Debug)]
struct MyVec(Vec<Command>);
impl<'de> Deserialize<'de> for MyVec {
fn deserialize<D>(deserializer: D) -> Result<MyVec, D::Error> where D: Deserializer<'de>,
{
Ok(MyVec(deserializer.deserialize_seq(VecVisitor)?))
}
}
fn main() {
let bytes = vec![9u8, 150u8, 175u8, 3u8, 1u8, 2u8, 3u8, 2u8, 3u8, 2u8]; // 150 = Operation, 175 = Operation, 3 = Element, 2 = Element
let commands: MyVec = DefaultOptions::new()
.with_varint_encoding()
.deserialize(&bytes).unwrap();
println!("{:?}", commands);
}
输出:
MyVec([Operation(150), Operation(175), Element([1, 2, 3]), Element([3, 2])])
有没有更简洁的写法?
我已尝试将 Element 解析替换为以下内容,但它仅适用于向量长度恒定的情况(例如 3):
match current {
1..=100 => {
let v = seq.next_element::<[u8; 3]>()?.unwrap().to_vec();
commands.push(Command::Element(v));
count += current as usize;
}
我认为最好的解决方案是通过查看seq (SeqAccess) 的下一个元素,以某种方式有条件地消耗seq 中的下一个元素,如果该元素小于100,它应该像任何其他Vec<u8> 一样反序列化。
【问题讨论】: