Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upHow to serialize/deserialize based on another field? #253
Comments
|
This is not possible with bincode. |
|
For parsing binary data, I recommend |
|
I would write this as: use std::fmt;
use serde::de::{self, Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
use serde::ser::{Serialize, SerializeTuple, Serializer};
#[derive(Debug)]
struct TestStruct {
list_one: Vec<u8>,
list_two: Vec<u8>,
}
impl Serialize for TestStruct {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
struct BytesToFixedSize<'a>(&'a [u8]);
impl<'a> Serialize for BytesToFixedSize<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut bytes = serializer.serialize_tuple(self.0.len())?;
for x in self.0 {
bytes.serialize_element(x)?;
}
bytes.end()
}
}
let len_one = self.list_one.len();
let len_two = self.list_two.len();
assert!(len_one <= u8::max_value() as usize);
assert!(len_two <= u8::max_value() as usize);
let mut bytes = serializer.serialize_tuple(4)?;
bytes.serialize_element(&(len_one as u8))?;
bytes.serialize_element(&(len_two as u8))?;
bytes.serialize_element(&BytesToFixedSize(&self.list_one))?;
bytes.serialize_element(&BytesToFixedSize(&self.list_two))?;
bytes.end()
}
}
impl<'de> Deserialize<'de> for TestStruct {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FixedSizeToBytes(usize);
impl<'de> DeserializeSeed<'de> for FixedSizeToBytes {
type Value = Vec<u8>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_tuple(self.0 as usize, self)
}
}
impl<'de> Visitor<'de> for FixedSizeToBytes {
type Value = Vec<u8>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{} bytes", self.0)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut bytes = Vec::new();
for i in 0..self.0 {
let x = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(i, &self))?;
bytes.push(x);
}
Ok(bytes)
}
}
struct TestStructVisitor;
impl<'de> Visitor<'de> for TestStructVisitor {
type Value = TestStruct;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct TestStruct")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let len_one: u8 = seq
.next_element()?
.ok_or_else(|| de::Error::missing_field("len_one"))?;
let len_two: u8 = seq
.next_element()?
.ok_or_else(|| de::Error::missing_field("len_two"))?;
let list_one = seq
.next_element_seed(FixedSizeToBytes(len_one as usize))?
.ok_or_else(|| de::Error::missing_field("list_one"))?;
let list_two = seq
.next_element_seed(FixedSizeToBytes(len_two as usize))?
.ok_or_else(|| de::Error::missing_field("list_two"))?;
Ok(TestStruct { list_one, list_two })
}
}
deserializer.deserialize_tuple(4, TestStructVisitor)
}
}
fn main() {
let test_struct = TestStruct {
list_one: vec![3],
list_two: vec![4, 5],
};
// [0x01, 0x02, 0x03, 0x04, 0x05]
let bytes = bincode::serialize(&test_struct).unwrap();
println!("{:?}", bytes);
let back = bincode::deserialize::<TestStruct>(&bytes).unwrap();
println!("{:#?}", back);
} |
|
@dtolnay : I completely missed your post until today. That's awesome! Thank you for the in-depth reply. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi guys,
Very awesome product btw! I'm using it to make a network coprocessor API wrapper and it's worked great for 99% of a massive API.
The couple structures that are giving me a bit of problems are like this:
Is there a good way to express this with serde/bincode?
With a lot of time I was able to come up with a
#[serde(with="")serializer/deserializer that would prepend each vector with au8of its length. But, I wasn't able to figure out how to look back more than one field on the struct.Any help you guys could give would be really appreciated!!