Better collection serialization

This commit is contained in:
avitex 2019-01-21 15:39:21 +11:00
parent a202514b52
commit 8eeca29ff7
6 changed files with 291 additions and 72 deletions

View File

@ -5,7 +5,10 @@ use core::marker::PhantomData;
use super::{ use super::{
Write, Write,
Serialize, Serialize,
Serializer Serializer,
SerializeDict,
SerializeList,
SerializeMultilineText
}; };
use self::real::{ use self::real::{
@ -27,7 +30,7 @@ impl Config for DefaultConfig {
} }
pub struct BaseSerializer<C: Config, W: Write> { pub struct BaseSerializer<C: Config, W: Write> {
out: W, out: W,
cfg: PhantomData<C> cfg: PhantomData<C>
} }
@ -51,21 +54,19 @@ where
{ {
C::RealSerializer::serialize_real::<W>(&mut self.out, r) C::RealSerializer::serialize_real::<W>(&mut self.out, r)
} }
#[inline]
fn write_delim(&mut self, delim: u8) -> Result<(), W::Error> {
self.out.write(&[delim])
}
#[inline]
fn write_utf8(&mut self, s: &str) -> Result<(), W::Error> {
self.out.write(s.as_bytes())
}
} }
impl<C: Config, W: Write> Serializer for &mut BaseSerializer<C, W> { impl<'se, C, W> Serializer for &'se mut BaseSerializer<C, W>
where
C: Config,
W: Write
{
type Error = W::Error; type Error = W::Error;
type SerializeDict = SerializeDictBase<'se, C, W>;
type SerializeList = SerializeListBase<'se, C, W>;
type SerializeMultilineText = SerializeMultilineTextBase<'se, C, W>;
#[inline] #[inline]
fn serialize_real_u8(self, real: u8) -> Result<(), Self::Error> { fn serialize_real_u8(self, real: u8) -> Result<(), Self::Error> {
self.serialize_real::<u8>(real) self.serialize_real::<u8>(real)
@ -121,32 +122,52 @@ impl<C: Config, W: Write> Serializer for &mut BaseSerializer<C, W> {
where V: Serialize where V: Serialize
{ {
self.serialize_atom(name)?; self.serialize_atom(name)?;
self.write_delim(GRAMMAR_PAREN_OPEN)?; self.out.write_delim(GRAMMAR_PAREN_OPEN)?;
self.serialize_any(value)?; self.serialize_any(value)?;
self.write_delim(GRAMMAR_PAREN_CLOSE) self.out.write_delim(GRAMMAR_PAREN_CLOSE)
} }
#[inline] #[inline]
fn serialize_atom<'a>(self, atom: &'a str) -> Result<(), Self::Error> { fn serialize_atom<'a>(self, atom: &'a str) -> Result<(), Self::Error> {
self.write_utf8(atom) self.out.write_utf8(atom.as_bytes())
} }
#[inline] #[inline]
fn serialize_text<'a>(self, text: &'a str) -> Result<(), Self::Error> { fn serialize_text<'a>(self, text: &'a str) -> Result<(), Self::Error> {
self.write_delim(GRAMMAR_QUOTE)?; self.out.write_delim(GRAMMAR_QUOTE)?;
self.write_utf8(text)?; self.out.write_utf8(text.as_bytes())?;
self.write_delim(GRAMMAR_QUOTE) self.out.write_delim(GRAMMAR_QUOTE)
}
#[inline]
fn serialize_dict_parts(self) -> Result<Self::SerializeDict, Self::Error> {
SerializeDictBase::start(self)
}
#[inline]
fn serialize_list_parts(self) -> Result<Self::SerializeList, Self::Error> {
SerializeListBase::start(self)
}
#[inline]
fn serialize_multiline_text_parts(self) -> Result<Self::SerializeMultilineText, Self::Error> {
SerializeMultilineTextBase::start(self)
} }
#[inline] #[inline]
fn serialize_multiline_text<'a, M>(self, lines: M) -> Result<(), Self::Error> fn serialize_multiline_text<'a, M>(self, lines: M) -> Result<(), Self::Error>
where M: IntoIterator<Item = &'a str> where M: IntoIterator<Item = &'a str>
{ {
self.write_delim(GRAMMAR_BTICK)?; SerializeMultilineTextBase::serialize(self, lines)
for line in lines.into_iter() { }
self.serialize_text(line)?;
} #[inline]
self.write_delim(GRAMMAR_BTICK) fn serialize_list<V, L>(self, list: L) -> Result<(), Self::Error>
where
V: Serialize,
L: IntoIterator<Item = V>
{
SerializeListBase::serialize(self, list)
} }
#[inline] #[inline]
@ -156,37 +177,193 @@ impl<C: Config, W: Write> Serializer for &mut BaseSerializer<C, W> {
V: Serialize, V: Serialize,
D: IntoIterator<Item = (K, V)> D: IntoIterator<Item = (K, V)>
{ {
self.write_delim(GRAMMAR_BRACE_OPEN)?; SerializeDictBase::serialize(self, dict)
let mut first = true; }
for (k, v) in dict.into_iter() { }
if first {
first = false; ///////////////////////////////////////////////////////////////////////////////
} else {
self.write_delim(GRAMMAR_COMMA)?; pub struct SerializeListBase<'se, C, W>
} where
self.serialize_any(&k)?; C: Config,
self.write_delim(GRAMMAR_COLON)?; W: Write
self.serialize_any(&v)?; {
} ser: &'se mut BaseSerializer<C, W>,
self.write_delim(GRAMMAR_BRACE_CLOSE) first: bool
}
impl<'se, C, W> SerializeListBase<'se, C, W>
where
C: Config,
W: Write
{
#[inline]
fn start(ser: &'se mut BaseSerializer<C, W>) -> Result<Self, W::Error> {
ser.out.write_delim(GRAMMAR_PAREN_OPEN)?;
Ok(Self {
ser,
first: true
})
} }
#[inline] #[inline]
fn serialize_list<T, L>(self, list: L) -> Result<(), Self::Error> pub fn serialize<V, L>(ser: &'se mut BaseSerializer<C, W>, list: L) -> Result<(), W::Error>
where where
T: Serialize, V: Serialize,
L: IntoIterator<Item = T> L: IntoIterator<Item = V>
{ {
self.write_delim(GRAMMAR_BRKET_OPEN)?; let mut state = ser.serialize_list_parts()?;
let mut first = true; for item in list.into_iter() {
for v in list.into_iter() { state.serialize_item(item)?;
if first {
first = false;
} else {
self.write_delim(GRAMMAR_COMMA)?;
}
self.serialize_any(&v)?;
} }
self.write_delim(GRAMMAR_BRKET_CLOSE) state.end()
}
}
impl<'se, C, W> SerializeList for SerializeListBase<'se, C, W>
where
C: Config,
W: Write
{
type Error = W::Error;
#[inline]
fn serialize_item<I>(&mut self, item: I) -> Result<(), Self::Error>
where I: Serialize
{
if self.first {
self.first = false;
} else {
self.ser.out.write_delim(GRAMMAR_COMMA)?;
}
self.ser.serialize_any(&item)
}
#[inline]
fn end(self) -> Result<(), Self::Error> {
self.ser.out.write_delim(GRAMMAR_BRACE_CLOSE)
}
}
///////////////////////////////////////////////////////////////////////////////
pub struct SerializeDictBase<'se, C, W>
where
C: Config,
W: Write
{
ser: &'se mut BaseSerializer<C, W>,
first: bool
}
impl<'se, C, W> SerializeDictBase<'se, C, W>
where
C: Config,
W: Write
{
#[inline]
fn start(ser: &'se mut BaseSerializer<C, W>) -> Result<Self, W::Error> {
ser.out.write_delim(GRAMMAR_BRACE_OPEN)?;
Ok(Self {
ser,
first: true
})
}
#[inline]
pub fn serialize<K, V, D>(ser: &'se mut BaseSerializer<C, W>, dict: D) -> Result<(), W::Error>
where
K: Serialize,
V: Serialize,
D: IntoIterator<Item = (K, V)>
{
let mut state = ser.serialize_dict_parts()?;
for (key, value) in dict.into_iter() {
state.serialize_kv(key, value)?;
}
state.end()
}
}
impl<'se, C, W> SerializeDict for SerializeDictBase<'se, C, W>
where
C: Config,
W: Write
{
type Error = W::Error;
#[inline]
fn serialize_kv<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
where
K: Serialize,
V: Serialize
{
if self.first {
self.first = false;
} else {
self.ser.out.write_delim(GRAMMAR_COMMA)?;
}
self.ser.serialize_any(&key)?;
self.ser.out.write_delim(GRAMMAR_COLON)?;
self.ser.serialize_any(&value)
}
#[inline]
fn end(self) -> Result<(), Self::Error> {
self.ser.out.write_delim(GRAMMAR_BRACE_CLOSE)
}
}
///////////////////////////////////////////////////////////////////////////////
pub struct SerializeMultilineTextBase<'se, C, W>
where
C: Config,
W: Write
{
ser: &'se mut BaseSerializer<C, W>
}
impl<'se, C, W> SerializeMultilineTextBase<'se, C, W>
where
C: Config,
W: Write
{
#[inline]
fn start(ser: &'se mut BaseSerializer<C, W>) -> Result<Self, W::Error> {
ser.out.write_delim(GRAMMAR_BTICK)?;
Ok(Self {
ser
})
}
#[inline]
pub fn serialize<'a, L>(ser: &'se mut BaseSerializer<C, W>, lines: L) -> Result<(), W::Error>
where
L: IntoIterator<Item = &'a str>
{
let mut state = ser.serialize_multiline_text_parts()?;
for line in lines.into_iter() {
state.serialize_line(line)?;
}
state.end()
}
}
impl<'se, C, W> SerializeMultilineText for SerializeMultilineTextBase<'se, C, W>
where
C: Config,
W: Write
{
type Error = W::Error;
#[inline]
fn serialize_line(&mut self, line: &str) -> Result<(), Self::Error> {
self.ser.serialize_text(line)
}
#[inline]
fn end(self) -> Result<(), Self::Error> {
self.ser.out.write_delim(GRAMMAR_BTICK)
} }
} }

View File

@ -12,7 +12,7 @@ macro_rules! impl_write_real_int_for_fast_serializer {
fn serialize_real<W: Write>(out: &mut W, r: $prim) -> Result<(), W::Error> { fn serialize_real<W: Write>(out: &mut W, r: $prim) -> Result<(), W::Error> {
let mut buf = itoa::Buffer::new(); let mut buf = itoa::Buffer::new();
let real_str = buf.format(r); let real_str = buf.format(r);
out.write(real_str.as_bytes()) out.write_utf8(real_str.as_bytes())
} }
})* })*
} }
@ -26,7 +26,7 @@ macro_rules! impl_write_real_float_for_fast_serializer {
write!(buf, "{}", r).map_err(|_| write!(buf, "{}", r).map_err(|_|
SerializerError::Unexpected("failed to format real") SerializerError::Unexpected("failed to format real")
)?; )?;
out.write(buf.as_bytes()) out.write_utf8(buf.as_bytes())
} }
})* })*
} }

View File

@ -6,12 +6,12 @@ pub enum SerializerError {
} }
impl fmt::Debug for SerializerError { impl fmt::Debug for SerializerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use SerializerError::*; use SerializerError::*;
match self { match self {
Unexpected(ref err) => write!(f, "unexpected error: {}", err) Unexpected(ref err) => write!(f, "unexpected error: {}", err)
} }
} }
} }
pub trait Error: fmt::Debug + From<SerializerError> {} pub trait Error: fmt::Debug + From<SerializerError> {}

View File

@ -4,7 +4,7 @@ use std::collections::BTreeMap;
use super::{Serialize, Serializer}; use super::{Serialize, Serializer};
//////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
macro_rules! real_impl { macro_rules! real_impl {
($prim:ty, $func:ident) => { ($prim:ty, $func:ident) => {
@ -27,7 +27,7 @@ real_impl!(i64, serialize_real_i64);
real_impl!(f32, serialize_real_f32); real_impl!(f32, serialize_real_f32);
real_impl!(f64, serialize_real_f64); real_impl!(f64, serialize_real_f64);
//////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
impl Serialize for str { impl Serialize for str {
fn serialize<S: Serializer>(&self, s: S) -> Result<(), S::Error> { fn serialize<S: Serializer>(&self, s: S) -> Result<(), S::Error> {
@ -35,7 +35,7 @@ impl Serialize for str {
} }
} }
//////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
//#[cfg(any(feature = "std", feature = "alloc"))] //#[cfg(any(feature = "std", feature = "alloc"))]
macro_rules! seq_impl { macro_rules! seq_impl {
@ -74,7 +74,7 @@ seq_impl!(Vec<T>);
// #[cfg(any(feature = "std", feature = "alloc"))] // #[cfg(any(feature = "std", feature = "alloc"))]
// seq_impl!(VecDeque<T>); // seq_impl!(VecDeque<T>);
//////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
impl<T> Serialize for [T] impl<T> Serialize for [T]
where where
@ -89,7 +89,7 @@ where
} }
} }
//////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
//#[cfg(any(feature = "std", feature = "alloc"))] //#[cfg(any(feature = "std", feature = "alloc"))]
macro_rules! dict_impl { macro_rules! dict_impl {
@ -117,7 +117,7 @@ dict_impl!(BTreeMap<K: Ord, V>);
//#[cfg(feature = "std")] //#[cfg(feature = "std")]
dict_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>); dict_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>);
//////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
macro_rules! deref_impl { macro_rules! deref_impl {
( (

View File

@ -10,8 +10,9 @@ pub trait Write {
/// attempting to write. /// attempting to write.
type Error: Error; type Error: Error;
/// The write function used with serialization. fn write_delim(&mut self, delim: u8) -> Result<(), Self::Error>;
fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
fn write_utf8(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
} }
pub trait Serialize { pub trait Serialize {
@ -20,9 +21,41 @@ pub trait Serialize {
S: Serializer; S: Serializer;
} }
pub trait SerializeDict {
type Error: Error;
fn serialize_kv<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
where
K: Serialize,
V: Serialize;
fn end(self) -> Result<(), Self::Error>;
}
pub trait SerializeList {
type Error: Error;
fn serialize_item<I>(&mut self, item: I) -> Result<(), Self::Error>
where I: Serialize;
fn end(self) -> Result<(), Self::Error>;
}
pub trait SerializeMultilineText {
type Error: Error;
fn serialize_line(&mut self, line: &str) -> Result<(), Self::Error>;
fn end(self) -> Result<(), Self::Error>;
}
pub trait Serializer: Sized { pub trait Serializer: Sized {
type Error: Error; type Error: Error;
type SerializeDict: SerializeDict;
type SerializeList: SerializeList;
type SerializeMultilineText: SerializeMultilineText;
fn serialize_any<T>(self, any: T) -> Result<(), Self::Error> fn serialize_any<T>(self, any: T) -> Result<(), Self::Error>
where where
T: Serialize T: Serialize
@ -52,14 +85,18 @@ pub trait Serializer: Sized {
fn serialize_unit<'a, V>(self, name: &'a str, value: V) -> Result<(), Self::Error> fn serialize_unit<'a, V>(self, name: &'a str, value: V) -> Result<(), Self::Error>
where V: Serialize; where V: Serialize;
fn serialize_dict<K, V, D>(self, dict: D) -> Result<(), Self::Error> fn serialize_list_parts(self) -> Result<Self::SerializeList, Self::Error>;
where fn serialize_dict_parts(self) -> Result<Self::SerializeDict, Self::Error>;
K: Serialize, fn serialize_multiline_text_parts(self) -> Result<Self::SerializeMultilineText, Self::Error>;
V: Serialize,
D: IntoIterator<Item = (K, V)>;
fn serialize_list<V, L>(self, list: L) -> Result<(), Self::Error> fn serialize_list<V, L>(self, list: L) -> Result<(), Self::Error>
where where
V: Serialize, V: Serialize,
L: IntoIterator<Item = V>; L: IntoIterator<Item = V>;
fn serialize_dict<K, V, D>(self, dict: D) -> Result<(), Self::Error>
where
K: Serialize,
V: Serialize,
D: IntoIterator<Item = (K, V)>;
} }

View File

@ -30,8 +30,13 @@ impl StringWriter {
impl Write for &mut StringWriter { impl Write for &mut StringWriter {
type Error = SerializerError; type Error = SerializerError;
fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { fn write_utf8(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
self.buf.extend_from_slice(bytes); self.buf.extend_from_slice(buf);
Ok(())
}
fn write_delim(&mut self, delim: u8) -> Result<(), Self::Error> {
self.buf.push(delim);
Ok(()) Ok(())
} }
} }