diff --git a/sehn/src/se/base/mod.rs b/sehn/src/se/base/mod.rs index 6318720..5c6ef7f 100644 --- a/sehn/src/se/base/mod.rs +++ b/sehn/src/se/base/mod.rs @@ -5,7 +5,10 @@ use core::marker::PhantomData; use super::{ Write, Serialize, - Serializer + Serializer, + SerializeDict, + SerializeList, + SerializeMultilineText }; use self::real::{ @@ -27,7 +30,7 @@ impl Config for DefaultConfig { } pub struct BaseSerializer { - out: W, + out: W, cfg: PhantomData } @@ -51,21 +54,19 @@ where { C::RealSerializer::serialize_real::(&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 Serializer for &mut BaseSerializer { +impl<'se, C, W> Serializer for &'se mut BaseSerializer +where + C: Config, + W: Write +{ type Error = W::Error; + type SerializeDict = SerializeDictBase<'se, C, W>; + type SerializeList = SerializeListBase<'se, C, W>; + type SerializeMultilineText = SerializeMultilineTextBase<'se, C, W>; + #[inline] fn serialize_real_u8(self, real: u8) -> Result<(), Self::Error> { self.serialize_real::(real) @@ -121,32 +122,52 @@ impl Serializer for &mut BaseSerializer { where V: Serialize { self.serialize_atom(name)?; - self.write_delim(GRAMMAR_PAREN_OPEN)?; + self.out.write_delim(GRAMMAR_PAREN_OPEN)?; self.serialize_any(value)?; - self.write_delim(GRAMMAR_PAREN_CLOSE) + self.out.write_delim(GRAMMAR_PAREN_CLOSE) } #[inline] fn serialize_atom<'a>(self, atom: &'a str) -> Result<(), Self::Error> { - self.write_utf8(atom) + self.out.write_utf8(atom.as_bytes()) } #[inline] fn serialize_text<'a>(self, text: &'a str) -> Result<(), Self::Error> { - self.write_delim(GRAMMAR_QUOTE)?; - self.write_utf8(text)?; - self.write_delim(GRAMMAR_QUOTE) + self.out.write_delim(GRAMMAR_QUOTE)?; + self.out.write_utf8(text.as_bytes())?; + self.out.write_delim(GRAMMAR_QUOTE) + } + + #[inline] + fn serialize_dict_parts(self) -> Result { + SerializeDictBase::start(self) + } + + #[inline] + fn serialize_list_parts(self) -> Result { + SerializeListBase::start(self) + } + + #[inline] + fn serialize_multiline_text_parts(self) -> Result { + SerializeMultilineTextBase::start(self) } #[inline] fn serialize_multiline_text<'a, M>(self, lines: M) -> Result<(), Self::Error> where M: IntoIterator { - self.write_delim(GRAMMAR_BTICK)?; - for line in lines.into_iter() { - self.serialize_text(line)?; - } - self.write_delim(GRAMMAR_BTICK) + SerializeMultilineTextBase::serialize(self, lines) + } + + #[inline] + fn serialize_list(self, list: L) -> Result<(), Self::Error> + where + V: Serialize, + L: IntoIterator + { + SerializeListBase::serialize(self, list) } #[inline] @@ -156,37 +177,193 @@ impl Serializer for &mut BaseSerializer { V: Serialize, D: IntoIterator { - self.write_delim(GRAMMAR_BRACE_OPEN)?; - let mut first = true; - for (k, v) in dict.into_iter() { - if first { - first = false; - } else { - self.write_delim(GRAMMAR_COMMA)?; - } - self.serialize_any(&k)?; - self.write_delim(GRAMMAR_COLON)?; - self.serialize_any(&v)?; - } - self.write_delim(GRAMMAR_BRACE_CLOSE) + SerializeDictBase::serialize(self, dict) + } +} + +/////////////////////////////////////////////////////////////////////////////// + +pub struct SerializeListBase<'se, C, W> +where + C: Config, + W: Write +{ + ser: &'se mut BaseSerializer, + first: bool +} + +impl<'se, C, W> SerializeListBase<'se, C, W> +where + C: Config, + W: Write +{ + #[inline] + fn start(ser: &'se mut BaseSerializer) -> Result { + ser.out.write_delim(GRAMMAR_PAREN_OPEN)?; + Ok(Self { + ser, + first: true + }) } #[inline] - fn serialize_list(self, list: L) -> Result<(), Self::Error> + pub fn serialize(ser: &'se mut BaseSerializer, list: L) -> Result<(), W::Error> where - T: Serialize, - L: IntoIterator + V: Serialize, + L: IntoIterator { - self.write_delim(GRAMMAR_BRKET_OPEN)?; - let mut first = true; - for v in list.into_iter() { - if first { - first = false; - } else { - self.write_delim(GRAMMAR_COMMA)?; - } - self.serialize_any(&v)?; + let mut state = ser.serialize_list_parts()?; + for item in list.into_iter() { + state.serialize_item(item)?; } - 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(&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, + first: bool +} + +impl<'se, C, W> SerializeDictBase<'se, C, W> +where + C: Config, + W: Write +{ + #[inline] + fn start(ser: &'se mut BaseSerializer) -> Result { + ser.out.write_delim(GRAMMAR_BRACE_OPEN)?; + Ok(Self { + ser, + first: true + }) + } + + #[inline] + pub fn serialize(ser: &'se mut BaseSerializer, dict: D) -> Result<(), W::Error> + where + K: Serialize, + V: Serialize, + D: IntoIterator + { + 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(&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 +} + +impl<'se, C, W> SerializeMultilineTextBase<'se, C, W> +where + C: Config, + W: Write +{ + #[inline] + fn start(ser: &'se mut BaseSerializer) -> Result { + ser.out.write_delim(GRAMMAR_BTICK)?; + Ok(Self { + ser + }) + } + + #[inline] + pub fn serialize<'a, L>(ser: &'se mut BaseSerializer, lines: L) -> Result<(), W::Error> + where + L: IntoIterator + { + 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) } } \ No newline at end of file diff --git a/sehn/src/se/base/real/fast.rs b/sehn/src/se/base/real/fast.rs index 90d3779..40fdada 100644 --- a/sehn/src/se/base/real/fast.rs +++ b/sehn/src/se/base/real/fast.rs @@ -12,7 +12,7 @@ macro_rules! impl_write_real_int_for_fast_serializer { fn serialize_real(out: &mut W, r: $prim) -> Result<(), W::Error> { let mut buf = itoa::Buffer::new(); 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(|_| SerializerError::Unexpected("failed to format real") )?; - out.write(buf.as_bytes()) + out.write_utf8(buf.as_bytes()) } })* } diff --git a/sehn/src/se/error.rs b/sehn/src/se/error.rs index 9b0a3cb..504b05e 100644 --- a/sehn/src/se/error.rs +++ b/sehn/src/se/error.rs @@ -6,12 +6,12 @@ pub enum 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::*; match self { Unexpected(ref err) => write!(f, "unexpected error: {}", err) } - } + } } pub trait Error: fmt::Debug + From {} diff --git a/sehn/src/se/impls.rs b/sehn/src/se/impls.rs index a4b9d73..c59b815 100644 --- a/sehn/src/se/impls.rs +++ b/sehn/src/se/impls.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use super::{Serialize, Serializer}; -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// macro_rules! real_impl { ($prim:ty, $func:ident) => { @@ -27,7 +27,7 @@ real_impl!(i64, serialize_real_i64); real_impl!(f32, serialize_real_f32); real_impl!(f64, serialize_real_f64); -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// impl Serialize for str { fn serialize(&self, s: S) -> Result<(), S::Error> { @@ -35,7 +35,7 @@ impl Serialize for str { } } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// //#[cfg(any(feature = "std", feature = "alloc"))] macro_rules! seq_impl { @@ -74,7 +74,7 @@ seq_impl!(Vec); // #[cfg(any(feature = "std", feature = "alloc"))] // seq_impl!(VecDeque); -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// impl Serialize for [T] where @@ -89,7 +89,7 @@ where } } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// //#[cfg(any(feature = "std", feature = "alloc"))] macro_rules! dict_impl { @@ -117,7 +117,7 @@ dict_impl!(BTreeMap); //#[cfg(feature = "std")] dict_impl!(HashMap); -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// macro_rules! deref_impl { ( diff --git a/sehn/src/se/mod.rs b/sehn/src/se/mod.rs index 3ee76a8..479f22e 100644 --- a/sehn/src/se/mod.rs +++ b/sehn/src/se/mod.rs @@ -10,8 +10,9 @@ pub trait Write { /// attempting to write. type Error: Error; - /// The write function used with serialization. - fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error>; + fn write_delim(&mut self, delim: u8) -> Result<(), Self::Error>; + + fn write_utf8(&mut self, buf: &[u8]) -> Result<(), Self::Error>; } pub trait Serialize { @@ -20,9 +21,41 @@ pub trait Serialize { S: Serializer; } +pub trait SerializeDict { + type Error: Error; + + fn serialize_kv(&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(&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 { type Error: Error; + type SerializeDict: SerializeDict; + type SerializeList: SerializeList; + type SerializeMultilineText: SerializeMultilineText; + fn serialize_any(self, any: T) -> Result<(), Self::Error> where T: Serialize @@ -52,14 +85,18 @@ pub trait Serializer: Sized { fn serialize_unit<'a, V>(self, name: &'a str, value: V) -> Result<(), Self::Error> where V: Serialize; - fn serialize_dict(self, dict: D) -> Result<(), Self::Error> - where - K: Serialize, - V: Serialize, - D: IntoIterator; + fn serialize_list_parts(self) -> Result; + fn serialize_dict_parts(self) -> Result; + fn serialize_multiline_text_parts(self) -> Result; fn serialize_list(self, list: L) -> Result<(), Self::Error> - where - V: Serialize, - L: IntoIterator; + where + V: Serialize, + L: IntoIterator; + + fn serialize_dict(self, dict: D) -> Result<(), Self::Error> + where + K: Serialize, + V: Serialize, + D: IntoIterator; } \ No newline at end of file diff --git a/sehn/src/utils/string_writer.rs b/sehn/src/utils/string_writer.rs index 8b42b10..a2a8f5b 100644 --- a/sehn/src/utils/string_writer.rs +++ b/sehn/src/utils/string_writer.rs @@ -30,8 +30,13 @@ impl StringWriter { impl Write for &mut StringWriter { type Error = SerializerError; - fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { - self.buf.extend_from_slice(bytes); + fn write_utf8(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + self.buf.extend_from_slice(buf); + Ok(()) + } + + fn write_delim(&mut self, delim: u8) -> Result<(), Self::Error> { + self.buf.push(delim); Ok(()) } } \ No newline at end of file