use std::{iter, ptr, vec}; use serde::de::{ self, value::{Error, SeqDeserializer}, Deserializer, IntoDeserializer, }; #[derive(Debug)] pub enum ValOrVec { Val(T), Vec(Vec), } impl ValOrVec { pub fn push(&mut self, new_val: T) { match self { // To transform a Self::Val into a Self::Vec, we take the existing // value out via ptr::read and add it to a vector, together with the // new value. Since setting self to `ValOrVec::Vec` normally would // cause T's Drop implementation to run if it has one (which would // free resources that will now be owned by the first vec element), // we instead use ptr::write to set self to Self::Vec. ValOrVec::Val(val) => { let mut vec = Vec::with_capacity(2); // Safety: since the vec is pre-allocated, push can't panic, so // there is no opportunity for outside code to observe an // invalid state of self. unsafe { let existing_val = ptr::read(val); vec.push(existing_val); vec.push(new_val); ptr::write(self, ValOrVec::Vec(vec)) } } ValOrVec::Vec(vec) => vec.push(new_val), } } } impl IntoIterator for ValOrVec { type Item = T; type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter::new(self) } } pub enum IntoIter { Val(iter::Once), Vec(vec::IntoIter), } impl IntoIter { fn new(vv: ValOrVec) -> Self { match vv { ValOrVec::Val(val) => IntoIter::Val(iter::once(val)), ValOrVec::Vec(vec) => IntoIter::Vec(vec.into_iter()), } } } impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { match self { IntoIter::Val(iter) => iter.next(), IntoIter::Vec(iter) => iter.next(), } } } impl<'de, T> IntoDeserializer<'de> for ValOrVec where T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>, { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } macro_rules! forward_to_part { ($($method:ident,)*) => { $( fn $method(self, visitor: V) -> Result where V: de::Visitor<'de> { match self { ValOrVec::Val(val) => val.$method(visitor), ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } )* } } impl<'de, T> Deserializer<'de> for ValOrVec where T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>, { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { match self { ValOrVec::Val(val) => val.deserialize_any(visitor), ValOrVec::Vec(_) => self.deserialize_seq(visitor), } } fn deserialize_seq(self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_seq(SeqDeserializer::new(self.into_iter())) } fn deserialize_enum( self, name: &'static str, variants: &'static [&'static str], visitor: V, ) -> Result where V: de::Visitor<'de>, { match self { ValOrVec::Val(val) => val.deserialize_enum(name, variants, visitor), ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } fn deserialize_tuple( self, len: usize, visitor: V, ) -> Result where V: de::Visitor<'de>, { match self { ValOrVec::Val(val) => val.deserialize_tuple(len, visitor), ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: de::Visitor<'de>, { match self { ValOrVec::Val(val) => val.deserialize_struct(name, fields, visitor), ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } fn deserialize_unit_struct( self, name: &'static str, visitor: V, ) -> Result where V: de::Visitor<'de>, { match self { ValOrVec::Val(val) => val.deserialize_unit_struct(name, visitor), ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } fn deserialize_tuple_struct( self, name: &'static str, len: usize, visitor: V, ) -> Result where V: de::Visitor<'de>, { match self { ValOrVec::Val(val) => { val.deserialize_tuple_struct(name, len, visitor) } ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } fn deserialize_newtype_struct( self, name: &'static str, visitor: V, ) -> Result where V: de::Visitor<'de>, { match self { ValOrVec::Val(val) => val.deserialize_newtype_struct(name, visitor), ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } forward_to_part! { deserialize_bool, deserialize_char, deserialize_str, deserialize_string, deserialize_bytes, deserialize_byte_buf, deserialize_unit, deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_f32, deserialize_f64, deserialize_option, deserialize_identifier, deserialize_ignored_any, deserialize_map, } }