diff --git a/Cargo.toml b/Cargo.toml index 89d0b93..b49baa8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "sehn", "sehn-serde", "sehn-std" ] \ No newline at end of file diff --git a/sehn/Cargo.toml b/sehn/Cargo.toml new file mode 100644 index 0000000..28469ef --- /dev/null +++ b/sehn/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "sehn" +version = "0.1.0" +authors = ["James Dyson "] +edition = "2018" + +[dependencies] +itoa = "0.4" \ No newline at end of file diff --git a/sehn/examples/basic.rs b/sehn/examples/basic.rs new file mode 100644 index 0000000..b68389f --- /dev/null +++ b/sehn/examples/basic.rs @@ -0,0 +1,38 @@ +extern crate sehn; + +use std::collections::BTreeMap; + +use sehn::*; + +fn print_and_clear(s: BaseSerializer) { + let out = s.into_inner(); + println!("{}", out.as_str().unwrap()); + out.clear(); +} + +fn main() { + let mut w = StringWriter::new(); + + /////////////////////////////////////////////////////////////////////////// + + let mut s = default_base_serializer(&mut w); + let mut obj = BTreeMap::new(); + + obj.insert("hello", Tag::new("one", vec![1])); + obj.insert("world", Tag::new("two", vec![2])); + + s.serialize_any(obj).unwrap(); + print_and_clear(s); + + /////////////////////////////////////////////////////////////////////////// + + let mut s = default_base_serializer(&mut w); + + let lines = vec![ + "hello", + "world" + ]; + + s.serialize_multiline_text(lines).unwrap(); + print_and_clear(s); +} diff --git a/sehn/src/de/base/mod.rs b/sehn/src/de/base/mod.rs new file mode 100644 index 0000000..c257162 --- /dev/null +++ b/sehn/src/de/base/mod.rs @@ -0,0 +1,48 @@ +use super::{ + Read, + Deserializer +}; + +pub struct BaseDeserializer { + src: R, + peeked_byte: Option +} + +impl<'de, R> BaseDeserializer + where R: Read<'de> +{ + pub fn new(src: R) -> Self { + Self { + src, + peeked_byte: None + } + } + + fn peek_byte(&mut self) -> Result { + match self.peeked_byte { + Some(byte) => Ok(byte), + None => { + let byte = self.src.read()?; + self.peeked_byte = Some(byte); + Ok(byte) + } + } + } + + fn read_byte(&mut self) -> Result { + match self.peeked_byte.take() { + Some(byte) => Ok(byte), + None => self.src.read() + } + } +} + +impl<'de, R> Deserializer<'de> for &mut BaseDeserializer + where R: Read<'de> +{ + type Error = R::Error; + + // fn deserialize_str(self) -> Result<&'de str, Self::Error> { + + // } +} \ No newline at end of file diff --git a/sehn/src/de/error.rs b/sehn/src/de/error.rs new file mode 100644 index 0000000..12cec3f --- /dev/null +++ b/sehn/src/de/error.rs @@ -0,0 +1,20 @@ +use core::fmt; + +pub enum DeserializerError { + /// A unexpected error (should never get this). + Unexpected(&'static str) +} + +impl fmt::Debug for DeserializerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use DeserializerError::*; + match self { + Unexpected(ref err) => write!(f, "unexpected error: {}", err) + } + } +} + +pub trait Error: fmt::Debug + From {} + +impl Error for T where + T: fmt::Debug + From {} \ No newline at end of file diff --git a/sehn/src/de/mod.rs b/sehn/src/de/mod.rs new file mode 100644 index 0000000..989453f --- /dev/null +++ b/sehn/src/de/mod.rs @@ -0,0 +1,52 @@ +mod base; +mod error; + +pub use self::base::*; +pub use self::error::*; + +pub trait Read<'a> { + /// The error that a read can return. + type Error: Error; + + /// Read a single byte. + fn read(&mut self) -> Result; + + /// Start mark. + fn start_mark(&mut self); + + /// Zero-copy drain from mark. + fn drain_mark(&mut self) -> Result<&'a [u8], Self::Error>; +} + +pub trait Deserialize: Sized { + fn deserialize<'de, D>(d: D) -> Result + where D: Deserializer<'de>; +} + +// pub trait Unit { +// fn from_name_value(name: &str, value: T) -> Result +// where +// T: Deserialize, +// E: Error; +// } + +// pub enum MaybeUnit<'a, T> { +// Raw(T), +// Wrapped(&'a str, T) +// } + +pub trait Deserializer<'de> { + type Error: Error; + + //fn deserialize_real_u8(self) -> Result; + //fn deserialize_real_u16(self) -> Result; + //fn deserialize_real_u32(self) -> Result; + //fn deserialize_real_u64(self) -> Result; + //fn deserialize_real_i8(self) -> Result; + + //fn deserialize_str(self) -> Result<&'de str, Self::Error>; + + //fn deserialize_unit(self) -> Result + // where U: Unit; + //fn deserialize_maybe_unit(self) -> Result; +} \ No newline at end of file diff --git a/sehn/src/grammar.rs b/sehn/src/grammar.rs new file mode 100644 index 0000000..e892052 --- /dev/null +++ b/sehn/src/grammar.rs @@ -0,0 +1,24 @@ +// Braces +pub const GRAMMAR_BRACE_OPEN: u8 = b'{'; +pub const GRAMMAR_BRACE_CLOSE: u8 = b'}'; + +// Parentheses +pub const GRAMMAR_PAREN_OPEN: u8 = b'('; +pub const GRAMMAR_PAREN_CLOSE: u8 = b')'; + +// Brackets +pub const GRAMMAR_BRKET_OPEN: u8 = b'['; +pub const GRAMMAR_BRKET_CLOSE: u8 = b']'; + +// Whitespace +pub const GRAMMAR_LF: u8 = b'\n'; +pub const GRAMMAR_CR: u8 = b'\r'; +pub const GRAMMAR_TAB: u8 = b'\t'; +pub const GRAMMAR_SPACE: u8 = b' '; + +// Other +pub const GRAMMAR_BTICK: u8 = b'`'; +pub const GRAMMAR_QUOTE: u8 = b'"'; +pub const GRAMMAR_COMMA: u8 = b','; +pub const GRAMMAR_COLON: u8 = b':'; +pub const GRAMMAR_BSLSH: u8 = b'\\'; \ No newline at end of file diff --git a/sehn/src/lib.rs b/sehn/src/lib.rs new file mode 100644 index 0000000..3ffd664 --- /dev/null +++ b/sehn/src/lib.rs @@ -0,0 +1,15 @@ +pub mod se; +pub mod de; +pub mod value; +pub mod grammar; +pub mod utils; + +// Serialization/Deserialization +pub use self::de::*; +pub use self::se::*; + +// Supporting values +pub use self::value::*; + +// Utilities +pub use self::utils::*; \ No newline at end of file diff --git a/sehn/src/se/base/mod.rs b/sehn/src/se/base/mod.rs new file mode 100644 index 0000000..6318720 --- /dev/null +++ b/sehn/src/se/base/mod.rs @@ -0,0 +1,192 @@ +mod real; + +use core::marker::PhantomData; + +use super::{ + Write, + Serialize, + Serializer +}; + +use self::real::{ + RealSerializer, + PrimitiveRealSerializer, + FastRealSerializer +}; + +use crate::grammar::*; + +pub trait Config { + type RealSerializer: RealSerializer; +} + +pub struct DefaultConfig {} + +impl Config for DefaultConfig { + type RealSerializer = FastRealSerializer; +} + +pub struct BaseSerializer { + out: W, + cfg: PhantomData +} + +impl BaseSerializer +where + C: Config, + W: Write +{ + pub fn new(out: W) -> Self { + Self { out, cfg: PhantomData } + } + + pub fn into_inner(self) -> W { + self.out + } + + #[inline] + pub fn serialize_real(&mut self, r: R) -> Result<(), W::Error> + where + C::RealSerializer: PrimitiveRealSerializer + { + 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 { + type Error = W::Error; + + #[inline] + fn serialize_real_u8(self, real: u8) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_real_u16(self, real: u16) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_real_u32(self, real: u32) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_real_u64(self, real: u64) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_real_i8(self, real: i8) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_real_i16(self, real: i16) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_real_i32(self, real: i32) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_real_i64(self, real: i64) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_real_f32(self, real: f32) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_real_f64(self, real: f64) -> Result<(), Self::Error> { + self.serialize_real::(real) + } + + #[inline] + fn serialize_unit<'a, V>(self, name: &'a str, value: V) -> Result<(), Self::Error> + where V: Serialize + { + self.serialize_atom(name)?; + self.write_delim(GRAMMAR_PAREN_OPEN)?; + self.serialize_any(value)?; + self.write_delim(GRAMMAR_PAREN_CLOSE) + } + + #[inline] + fn serialize_atom<'a>(self, atom: &'a str) -> Result<(), Self::Error> { + self.write_utf8(atom) + } + + #[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) + } + + #[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) + } + + #[inline] + fn serialize_dict(self, dict: D) -> Result<(), Self::Error> + where + K: Serialize, + 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) + } + + #[inline] + fn serialize_list(self, list: L) -> Result<(), Self::Error> + where + T: 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)?; + } + self.write_delim(GRAMMAR_BRKET_CLOSE) + } +} \ No newline at end of file diff --git a/sehn/src/se/base/real/dec_buf.rs b/sehn/src/se/base/real/dec_buf.rs new file mode 100644 index 0000000..50a84f1 --- /dev/null +++ b/sehn/src/se/base/real/dec_buf.rs @@ -0,0 +1,54 @@ +use core::fmt; + +// Should be greater than MAX_SIG_DIGITS = 17 +const DEC_BUF_SIZE: usize = 32; + +pub struct DecBuf { + buf: [u8; DEC_BUF_SIZE], + len: usize +} + +impl DecBuf { + pub fn new() -> Self { + Self { + buf: unsafe { core::mem::uninitialized() }, + len: 0 + } + } + + pub fn as_bytes(&self) -> &[u8] { + &self.buf[0..self.len] + } + + fn extend_mut_slice(&mut self, add_len: usize) -> Result<&mut [u8], fmt::Error> { + let cur_len = self.len; + let new_len = cur_len + add_len; + if new_len > self.buf.len() { + Err(fmt::Error) + } else { + self.len = new_len; + Ok(&mut self.buf[cur_len..new_len]) + } + } +} + +impl fmt::Write for DecBuf { + #[inline] + fn write_str(&mut self, s: &str) -> fmt::Result { + if s.is_empty() { + Ok(()) + } else { + let new_bytes = s.as_bytes(); + self.extend_mut_slice(new_bytes.len()).map(|b| { + b.copy_from_slice(new_bytes); + }) + } + } + + #[inline] + fn write_char(&mut self, c: char) -> fmt::Result { + self.extend_mut_slice(c.len_utf8()).map(|b| { + c.encode_utf8(b); + }) + } +} \ No newline at end of file diff --git a/sehn/src/se/base/real/fast.rs b/sehn/src/se/base/real/fast.rs new file mode 100644 index 0000000..90d3779 --- /dev/null +++ b/sehn/src/se/base/real/fast.rs @@ -0,0 +1,47 @@ +use core::fmt::Write as FmtWrite; +use crate::se::{Write, SerializerError}; +use super::{ + dec_buf::DecBuf, + RealSerializer, + PrimitiveRealSerializer +}; + +macro_rules! impl_write_real_int_for_fast_serializer { + ($($prim:ident)*) => { + $(impl PrimitiveRealSerializer<$prim> for FastRealSerializer { + 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()) + } + })* + } +} + +macro_rules! impl_write_real_float_for_fast_serializer { + ($($prim:ident)*) => { + $(impl PrimitiveRealSerializer<$prim> for FastRealSerializer { + fn serialize_real(out: &mut W, r: $prim) -> Result<(), W::Error> { + let mut buf = DecBuf::new(); + write!(buf, "{}", r).map_err(|_| + SerializerError::Unexpected("failed to format real") + )?; + out.write(buf.as_bytes()) + } + })* + } +} + +pub struct FastRealSerializer; + +impl_write_real_int_for_fast_serializer!( + u8 u16 u32 u64 + i8 i16 i32 i64 +); + +impl_write_real_float_for_fast_serializer!( + f32 + f64 +); + +impl RealSerializer for FastRealSerializer {} \ No newline at end of file diff --git a/sehn/src/se/base/real/mod.rs b/sehn/src/se/base/real/mod.rs new file mode 100644 index 0000000..4827701 --- /dev/null +++ b/sehn/src/se/base/real/mod.rs @@ -0,0 +1,24 @@ +mod fast; +mod dec_buf; + +pub use self::fast::*; + +use crate::se::Write; + +pub trait PrimitiveRealSerializer { + fn serialize_real(w: &mut W, i: T) -> Result<(), W::Error> + where + W: Write; +} + +pub trait RealSerializer: + PrimitiveRealSerializer + + PrimitiveRealSerializer + + PrimitiveRealSerializer + + PrimitiveRealSerializer + + PrimitiveRealSerializer + + PrimitiveRealSerializer + + PrimitiveRealSerializer + + PrimitiveRealSerializer + + PrimitiveRealSerializer + + PrimitiveRealSerializer {} \ No newline at end of file diff --git a/sehn/src/se/error.rs b/sehn/src/se/error.rs new file mode 100644 index 0000000..9b0a3cb --- /dev/null +++ b/sehn/src/se/error.rs @@ -0,0 +1,20 @@ +use core::fmt; + +pub enum SerializerError { + /// A unexpected error (should never get this). + Unexpected(&'static str) +} + +impl fmt::Debug for SerializerError { + 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 {} + +impl Error for T where + T: fmt::Debug + From {} \ No newline at end of file diff --git a/sehn/src/se/impls.rs b/sehn/src/se/impls.rs new file mode 100644 index 0000000..a4b9d73 --- /dev/null +++ b/sehn/src/se/impls.rs @@ -0,0 +1,144 @@ +use std::hash::{Hash, BuildHasher}; +use std::collections::HashMap; +use std::collections::BTreeMap; + +use super::{Serialize, Serializer}; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! real_impl { + ($prim:ty, $func:ident) => { + impl Serialize for $prim { + fn serialize(&self, s: S) -> Result<(), S::Error> { + s.$func(*self) + } + } + } +} + +real_impl!(u8, serialize_real_u8); +real_impl!(u16, serialize_real_u16); +real_impl!(u32, serialize_real_u32); +real_impl!(u64, serialize_real_u64); +real_impl!(i8, serialize_real_i8); +real_impl!(i16, serialize_real_i16); +real_impl!(i32, serialize_real_i32); +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> { + s.serialize_text(self) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +//#[cfg(any(feature = "std", feature = "alloc"))] +macro_rules! seq_impl { + ($ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)* >) => { + impl Serialize for $ty + where + T: Serialize $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound,)* + { + #[inline] + fn serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: Serializer, + { + serializer.serialize_list(self) + } + } + } +} + +//#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!(Vec); + +// #[cfg(any(feature = "std", feature = "alloc"))] +// seq_impl!(BinaryHeap); + +// #[cfg(any(feature = "std", feature = "alloc"))] +// seq_impl!(BTreeSet); + +// #[cfg(feature = "std")] +// seq_impl!(HashSet); + +// #[cfg(any(feature = "std", feature = "alloc"))] +// seq_impl!(LinkedList); + +// #[cfg(any(feature = "std", feature = "alloc"))] +// seq_impl!(VecDeque); + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for [T] +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: Serializer, + { + serializer.serialize_list(self) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +//#[cfg(any(feature = "std", feature = "alloc"))] +macro_rules! dict_impl { + ($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => { + impl Serialize for $ty + where + K: Serialize $(+ $kbound1 $(+ $kbound2)*)*, + V: Serialize, + $($typaram: $bound,)* + { + #[inline] + fn serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: Serializer, + { + serializer.serialize_dict(self) + } + } + } +} + +//#[cfg(any(feature = "std", feature = "alloc"))] +dict_impl!(BTreeMap); + +//#[cfg(feature = "std")] +dict_impl!(HashMap); + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! deref_impl { + ( + $(#[doc = $doc:tt])* + <$($desc:tt)+ + ) => { + $(#[doc = $doc])* + impl <$($desc)+ { + #[inline] + fn serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: Serializer, + { + (**self).serialize(serializer) + } + } + }; +} + +deref_impl!(<'a, T: ?Sized> Serialize for &'a T where T: Serialize); +deref_impl!(<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize); + +//#[cfg(any(feature = "std", feature = "alloc"))] +deref_impl!( Serialize for Box where T: Serialize); \ No newline at end of file diff --git a/sehn/src/se/mod.rs b/sehn/src/se/mod.rs new file mode 100644 index 0000000..3ee76a8 --- /dev/null +++ b/sehn/src/se/mod.rs @@ -0,0 +1,65 @@ +mod base; +mod error; +mod impls; + +pub use self::base::*; +pub use self::error::*; + +pub trait Write { + /// The core error that may bubble from + /// attempting to write. + type Error: Error; + + /// The write function used with serialization. + fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error>; +} + +pub trait Serialize { + fn serialize(&self, s: S) -> Result<(), S::Error> + where + S: Serializer; +} + +pub trait Serializer: Sized { + type Error: Error; + + fn serialize_any(self, any: T) -> Result<(), Self::Error> + where + T: Serialize + { + any.serialize(self) + } + + fn serialize_real_u8(self, real: u8) -> Result<(), Self::Error>; + fn serialize_real_u16(self, real: u16) -> Result<(), Self::Error>; + fn serialize_real_u32(self, real: u32) -> Result<(), Self::Error>; + fn serialize_real_u64(self, real: u64) -> Result<(), Self::Error>; + + fn serialize_real_i8(self, real: i8) -> Result<(), Self::Error>; + fn serialize_real_i16(self, real: i16) -> Result<(), Self::Error>; + fn serialize_real_i32(self, real: i32) -> Result<(), Self::Error>; + fn serialize_real_i64(self, real: i64) -> Result<(), Self::Error>; + + fn serialize_real_f32(self, real: f32) -> Result<(), Self::Error>; + fn serialize_real_f64(self, real: f64) -> Result<(), Self::Error>; + + fn serialize_atom<'a>(self, atom: &'a str) -> Result<(), Self::Error>; + fn serialize_text<'a>(self, text: &'a str) -> Result<(), Self::Error>; + + fn serialize_multiline_text<'a, M>(self, lines: M) -> Result<(), Self::Error> + where M: IntoIterator; + + 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(self, list: L) -> Result<(), Self::Error> + where + V: Serialize, + L: IntoIterator; +} \ No newline at end of file diff --git a/sehn/src/utils/mod.rs b/sehn/src/utils/mod.rs new file mode 100644 index 0000000..cdd9d99 --- /dev/null +++ b/sehn/src/utils/mod.rs @@ -0,0 +1,5 @@ +mod to_string; +mod string_writer; + +pub use self::to_string::*; +pub use self::string_writer::*; \ No newline at end of file diff --git a/sehn/src/utils/string_writer.rs b/sehn/src/utils/string_writer.rs new file mode 100644 index 0000000..8b42b10 --- /dev/null +++ b/sehn/src/utils/string_writer.rs @@ -0,0 +1,37 @@ +use std::str::Utf8Error; +use std::string::FromUtf8Error; + +use crate::se::{Write, SerializerError}; + +pub struct StringWriter { + buf: Vec +} + +impl StringWriter { + pub fn new() -> Self { + Self { + buf: Vec::new() + } + } + + pub fn clear(&mut self) { + self.buf.clear(); + } + + pub fn as_str(&self) -> Result<&str, Utf8Error> { + std::str::from_utf8(self.buf.as_ref()) + } + + pub fn to_string(self) -> Result { + String::from_utf8(self.buf) + } +} + +impl Write for &mut StringWriter { + type Error = SerializerError; + + fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { + self.buf.extend_from_slice(bytes); + Ok(()) + } +} \ No newline at end of file diff --git a/sehn/src/utils/to_string.rs b/sehn/src/utils/to_string.rs new file mode 100644 index 0000000..29bdedc --- /dev/null +++ b/sehn/src/utils/to_string.rs @@ -0,0 +1,17 @@ +use crate::se::*; +use super::StringWriter; + +pub fn default_base_serializer(w: W) -> BaseSerializer + where W: Write +{ + BaseSerializer::new(w) +} + +pub fn to_string(value: T) -> Result + where T: Serialize +{ + let mut w = StringWriter::new(); + let mut s = default_base_serializer(&mut w); + value.serialize(&mut s)?; + Ok(w.to_string().unwrap()) +} \ No newline at end of file diff --git a/sehn/src/value/mod.rs b/sehn/src/value/mod.rs new file mode 100644 index 0000000..aaef2a1 --- /dev/null +++ b/sehn/src/value/mod.rs @@ -0,0 +1,3 @@ +mod tag; + +pub use self::tag::*; \ No newline at end of file diff --git a/sehn/src/value/tag.rs b/sehn/src/value/tag.rs new file mode 100644 index 0000000..574da78 --- /dev/null +++ b/sehn/src/value/tag.rs @@ -0,0 +1,23 @@ +use crate::se::{Serializer, Serialize}; + +pub struct Tag<'a, T> { + name: &'a str, + value: T +} + +impl<'a, T> Tag<'a, T> { + pub fn new(name: &'a str, value: T) -> Self { + Self { name, value } + } +} + +impl<'a, T> Serialize for Tag<'a, T> +where + T: Serialize +{ + fn serialize(&self, s: S) -> Result<(), S::Error> + where S: Serializer + { + s.serialize_unit(self.name, &self.value) + } +} \ No newline at end of file