Solved using the suggestion from mcarton about storing elements in the sequence serializer.
This stores each serialized sequence of bytes in a Vec (i.e. as a Vec<Vec<u8>>), and checks whether all items are of equal length before serializing into output.
This looks something like:
/// Main top level serializer.
pub struct Serializer {
output: Vec<u8>
}
impl<'a> ser::Serializer for &'a mut Serializer {
// ... skipped ...
type SerializeSeq = ArraySerializer<'a>;
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
let array_ser = ArraySerializer {
items: Vec::new(),
output: &mut self.output,
};
Ok(array_ser)
}
// ... skipped ...
}
pub struct ArraySerializer<'a> {
/// Temporary storage for individual serialized array elements.
items: Vec<Vec<u8>>,
/// Storage for final serialized output of header plus all elements. This is
/// typically a reference to the full output buffer being serialized into.
output: &'a mut Vec<u8>,
}
impl <'a> ser::SerializeSeq for ArraySerializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_element<T>(&mut self, value: &T) -> Result<Self::Ok> where
T: ?Sized + Serialize {
// default serializer used for serializing array elements
let mut serializer = Serializer::default();
// serialize individual item and add to `items`
value.serialize(&mut serializer)?;
self.items.push(serializer.output);
Ok(())
}
fn end(self) -> Result<Self::Ok> {
if self.items.is_empty() {
self.output.push(EMPTY_ARRAY_HEADER);
return Ok(());
}
let all_elems_same_length = self.items
.iter()
.all(|ref v| v.len() == self.items[0].len());
};
if all_elems_same_length {
self.output.push(SAME_LENGTH_HEADER);
for item in &mut self.items.iter_mut() {
self.output.append(item);
}
} else {
self.output.push(VARIABLE_LENGTH_HEADER);
// ... skipped: encode rest of items using more complicated serialization ...
}
Ok(())
}
}
SerializeSeqinstance until the call toend, where you would do the actual serialization. - mcarton