From abc27adea42e4bc9038d02980efbb5a4d2073f55 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Thu, 15 Dec 2022 14:45:27 +0100 Subject: [PATCH] Remove nested structs and add list syntax --- README.md | 23 ++++++--- src/dec/decode.rs | 116 ++++++++++++++++++++++++++++++++++++++++++++- src/dec/mod.rs | 51 +++++++++++++------- src/enc/mod.rs | 117 ++++++++++++++++++++++------------------------ src/lib.rs | 7 +++ src/serde/de.rs | 10 ++-- src/serde/mod.rs | 105 ++++++++++++++++++++++++++--------------- src/serde/ser.rs | 52 +++++++++++---------- 8 files changed, 325 insertions(+), 156 deletions(-) diff --git a/README.md b/README.md index 6769a0a..ab93692 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,9 @@ A term can be of any of the following kinds: - a string, which may contain only ASCII alphanumeric terms and `.-_*?` - a dict, which maps strings (as defined above) to any term type +- a list, which may contain any number of any kind of terms (can be mixed) - a sequence, consistuted of at least two of the above (can be mixed), simply separated by whitespace; sequences cannot be nested -Nested sequences can be represented using a special dictionnary with a single key, `.`, -for instance `TEST a { . = 0 4 2 1 9 7 0 } c`. - Dicts are represented as follows: ``` @@ -29,6 +27,12 @@ Dicts are represented as follows: } ``` +Dicts are represented as follows: + +``` +[ term1, term2 ] +``` + Sequences are represented as follows: ``` @@ -38,8 +42,12 @@ term1 term2 term3 As a consequence, complex data structures can be defined as follows: ``` -SENDTO alex { +SEND MESSAGE { topic = blah, + to = [ + TOPIC hello, + USER john + ], body = blah blah } ``` @@ -52,7 +60,8 @@ In the complex stance example above, here are the sequence and dicts and their r - the toplevel term is a sequence, whose raw representation is the entire encoded string (assuming no whitespace at beginning or end) - the third term of the sequence is a dict, whose raw representation starts at `{` and ends at `}` -- the second mapping of the dict is a sequence, whose raw representation is exactly `blah blah`. +- the second mapping of the dict is a list, whose raw representation starts at `[` and ends at `]` +- the third mapping of the dict is a sequence, whose raw representation is exactly `blah blah`. Since strings cannot contain whitespace, they are always equivalent to their raw representation. @@ -66,8 +75,8 @@ Terms can be interpreted in a number of different ways, depending on the context - a discriminator (the first item) - a value, which is either the second item in case there are only two items, or the sequence composed of all items starting from the second if there are more than two - DICT: if the term is a dict, interpret it as such -- SEQ: if the term is a string or a dict, interpret it as a sequence composed of that single term. Otherwise, the term is a sequence, interpret it as a sequence of terms. -- NESTED: if the term is a dict with a single key `.`, interpret it as the term associated to that key +- LIST: if the term is a list, interpret it as such +- SEQ: if the term is a string, a list, or a dict, interpret it as a sequence composed of that single term. Otherwise, the term is a sequence, interpret it as a sequence of terms. ## Data mappings diff --git a/src/dec/decode.rs b/src/dec/decode.rs index 7eafb73..717c798 100644 --- a/src/dec/decode.rs +++ b/src/dec/decode.rs @@ -9,7 +9,10 @@ use nom::{ }; use crate::dec::{AnyTerm, DecodeError, NonSeqTerm, Term}; -use crate::{is_string_char, is_whitespace, DICT_ASSIGN, DICT_CLOSE, DICT_DELIM, DICT_OPEN}; +use crate::{ + is_string_char, is_whitespace, DICT_ASSIGN, DICT_CLOSE, DICT_DELIM, DICT_OPEN, LIST_CLOSE, + LIST_DELIM, LIST_OPEN, +}; // ---- @@ -40,6 +43,7 @@ fn decode_nonseq_term(input: &[u8]) -> IResult<&'_ [u8], NonSeqTerm<'_, '_>> { let (rest, term) = alt(( map(decode_str, NonSeqTerm::Str), map(decode_dict, |(raw, d)| NonSeqTerm::Dict(raw, d)), + map(decode_list, |(raw, l)| NonSeqTerm::List(raw, l)), ))(input)?; Ok((rest, term)) } @@ -81,6 +85,27 @@ fn decode_dict_item(d: &[u8]) -> IResult<&'_ [u8], (&'_ [u8], AnyTerm<'_, '_>)> Ok((d, (key, value))) } +type ListType<'a> = (&'a [u8], Vec>); + +fn decode_list(list_begin: &[u8]) -> IResult<&'_ [u8], ListType<'_>> { + let (d, _) = tag(&[LIST_OPEN][..])(list_begin)?; + let (d, list) = separated_list0(list_separator, decode_term)(d)?; + let (d, _) = opt(list_separator)(d)?; + let (d, _) = take_while(is_whitespace)(d)?; + let (list_end, _) = tag(&[LIST_CLOSE][..])(d)?; + + let raw_len = list_begin.input_len() - list_end.input_len(); + let list_raw = &list_begin[..raw_len]; + + Ok((list_end, (list_raw, list))) +} + +fn list_separator(d: &[u8]) -> IResult<&'_ [u8], ()> { + let (d, _) = take_while(is_whitespace)(d)?; + let (d, _) = tag(&[LIST_DELIM][..])(d)?; + Ok((d, ())) +} + // ---- #[cfg(test)] @@ -161,6 +186,48 @@ mod tests { ); } + #[test] + fn simple_list() { + let bytes = b" [ hello, bojzkz pipo, ke ] "; + assert_eq!( + decode(bytes), + Ok(AnyTerm::List( + b"[ hello, bojzkz pipo, ke ]", + [ + AnyTerm::Str(b"hello"), + AnyTerm::Seq( + b"bojzkz pipo", + vec![NonSeqTerm::Str(b"bojzkz"), NonSeqTerm::Str(b"pipo")] + ), + AnyTerm::Str(b"ke"), + ] + .to_vec() + ) + .into()) + ); + } + + #[test] + fn simple_list_2() { + let bytes = b" [ hello, bojzkz pipo , ke , ] "; + assert_eq!( + decode(bytes), + Ok(AnyTerm::List( + b"[ hello, bojzkz pipo , ke , ]", + [ + AnyTerm::Str(b"hello"), + AnyTerm::Seq( + b"bojzkz pipo", + vec![NonSeqTerm::Str(b"bojzkz"), NonSeqTerm::Str(b"pipo")] + ), + AnyTerm::Str(b"ke"), + ] + .to_vec() + ) + .into()) + ); + } + #[test] fn real_world_1() { let bytes = b"HEAD alexpubkey"; @@ -209,4 +276,51 @@ mod tests { ]).into(), )); } + + #[test] + fn real_world_3() { + let bytes = b"[ USER john, USER luke, GROUP strategy { owner = USER john, members = [ USER john, USER luke ] } ]"; + let user_john = AnyTerm::Seq( + b"USER john", + vec![NonSeqTerm::Str(b"USER"), NonSeqTerm::Str(b"john")], + ); + let user_luke = AnyTerm::Seq( + b"USER luke", + vec![NonSeqTerm::Str(b"USER"), NonSeqTerm::Str(b"luke")], + ); + + assert_eq!( + decode(bytes), + Ok(AnyTerm::List( + &bytes[..], + vec![ + user_john.clone(), + user_luke.clone(), + AnyTerm::Seq( + b"GROUP strategy { owner = USER john, members = [ USER john, USER luke ] }", + vec![ + NonSeqTerm::Str(b"GROUP"), + NonSeqTerm::Str(b"strategy"), + NonSeqTerm::Dict( + b"{ owner = USER john, members = [ USER john, USER luke ] }", + [ + (&b"owner"[..], user_john.clone()), + ( + &b"members"[..], + AnyTerm::List( + b"[ USER john, USER luke ]", + vec![user_john, user_luke,] + ) + ) + ] + .into_iter() + .collect() + ) + ] + ), + ] + ) + .into()) + ); + } } diff --git a/src/dec/mod.rs b/src/dec/mod.rs index 2bacf11..32457d2 100644 --- a/src/dec/mod.rs +++ b/src/dec/mod.rs @@ -8,6 +8,8 @@ use std::collections::HashMap; #[cfg(any(feature = "dryoc"))] use crate::crypto; +use crate::debug; + pub use decode::*; pub use error::*; @@ -26,6 +28,8 @@ pub(crate) enum AnyTerm<'a, 'b> { Str(&'a [u8]), Dict(&'a [u8], HashMap<&'a [u8], AnyTerm<'a, 'b>>), DictRef(&'a [u8], &'b HashMap<&'a [u8], AnyTerm<'a, 'b>>), + List(&'a [u8], Vec>), + ListRef(&'a [u8], &'b [AnyTerm<'a, 'b>]), Seq(&'a [u8], Vec>), SeqRef(&'a [u8], &'b [NonSeqTerm<'a, 'b>]), } @@ -35,6 +39,8 @@ pub(crate) enum NonSeqTerm<'a, 'b> { Str(&'a [u8]), Dict(&'a [u8], HashMap<&'a [u8], AnyTerm<'a, 'b>>), DictRef(&'a [u8], &'b HashMap<&'a [u8], AnyTerm<'a, 'b>>), + List(&'a [u8], Vec>), + ListRef(&'a [u8], &'b [AnyTerm<'a, 'b>]), } impl<'a, 'b> From> for AnyTerm<'a, 'b> { @@ -43,6 +49,8 @@ impl<'a, 'b> From> for AnyTerm<'a, 'b> { NonSeqTerm::Str(s) => AnyTerm::Str(s), NonSeqTerm::Dict(raw, d) => AnyTerm::Dict(raw, d), NonSeqTerm::DictRef(raw, d) => AnyTerm::DictRef(raw, d), + NonSeqTerm::List(raw, l) => AnyTerm::List(raw, l), + NonSeqTerm::ListRef(raw, l) => AnyTerm::ListRef(raw, l), } } } @@ -54,6 +62,8 @@ impl<'a, 'b> TryFrom> for NonSeqTerm<'a, 'b> { AnyTerm::Str(s) => Ok(NonSeqTerm::Str(s)), AnyTerm::Dict(raw, d) => Ok(NonSeqTerm::Dict(raw, d)), AnyTerm::DictRef(raw, d) => Ok(NonSeqTerm::DictRef(raw, d)), + AnyTerm::List(raw, l) => Ok(NonSeqTerm::List(raw, l)), + AnyTerm::ListRef(raw, l) => Ok(NonSeqTerm::ListRef(raw, l)), _ => Err(()), } } @@ -353,28 +363,23 @@ impl<'a, 'b> Term<'a, 'b> { } } - /// Checks term is a dictionary with a single key `.`, - /// and returns the associated value. + /// Checks if the term is a list, and if so, return its elements in a vec. /// /// Example: /// /// ``` /// use nettext::dec::decode; /// - /// let term = decode(b"{ . = a b c d e }").unwrap(); - /// assert_eq!(term.nested().unwrap().raw(), b"a b c d e"); + /// let term2 = decode(b"[ hello, world ]").unwrap(); + /// let seq2 = term2.list().unwrap(); + /// assert_eq!(seq2.len(), 2); + /// assert_eq!(seq2[0].str().unwrap(), "hello"); + /// assert_eq!(seq2[1].str().unwrap(), "world"); /// ``` - pub fn nested(&self) -> Result, TypeError> { + pub fn list(&self) -> Result>, TypeError> { match self.0.mkref() { - AnyTerm::DictRef(_, d) if d.len() == 1 => { - let (k, v) = d.iter().next().unwrap(); - if k != b"." { - Err(TypeError::WrongType("NESTED")) - } else { - Ok(Term(v.mkref())) - } - } - _ => Err(TypeError::WrongType("NESTED")), + AnyTerm::ListRef(_r, l) => Ok(l.iter().map(|x| Term(x.mkref().into())).collect::>()), + _ => Err(TypeError::WrongType("LIST")), } } @@ -508,6 +513,8 @@ impl<'a, 'b> AnyTerm<'a, 'b> { AnyTerm::Str(s) => s, AnyTerm::Dict(r, _) | AnyTerm::DictRef(r, _) + | AnyTerm::List(r, _) + | AnyTerm::ListRef(r, _) | AnyTerm::Seq(r, _) | AnyTerm::SeqRef(r, _) => r, } @@ -518,6 +525,8 @@ impl<'a, 'b> AnyTerm<'a, 'b> { AnyTerm::Str(s) => AnyTerm::Str(s), AnyTerm::Dict(r, d) => AnyTerm::DictRef(r, d), AnyTerm::DictRef(r, d) => AnyTerm::DictRef(r, d), + AnyTerm::List(r, l) => AnyTerm::ListRef(r, l), + AnyTerm::ListRef(r, l) => AnyTerm::ListRef(r, l), AnyTerm::Seq(r, l) => AnyTerm::SeqRef(r, &l[..]), AnyTerm::SeqRef(r, l) => AnyTerm::SeqRef(r, l), } @@ -529,6 +538,7 @@ impl<'a, 'b> NonSeqTerm<'a, 'b> { match &self { NonSeqTerm::Str(s) => s, NonSeqTerm::Dict(r, _) | NonSeqTerm::DictRef(r, _) => r, + NonSeqTerm::List(r, _) | NonSeqTerm::ListRef(r, _) => r, } } @@ -537,6 +547,8 @@ impl<'a, 'b> NonSeqTerm<'a, 'b> { NonSeqTerm::Str(s) => NonSeqTerm::Str(s), NonSeqTerm::Dict(r, d) => NonSeqTerm::DictRef(r, d), NonSeqTerm::DictRef(r, d) => NonSeqTerm::DictRef(r, d), + NonSeqTerm::List(r, l) => NonSeqTerm::ListRef(r, l), + NonSeqTerm::ListRef(r, l) => NonSeqTerm::ListRef(r, l), } } } @@ -561,10 +573,6 @@ impl<'a, 'b> std::fmt::Display for Term<'a, 'b> { // ---- DEBUG REPR ---- -pub(crate) fn debug(x: &[u8]) -> &str { - std::str::from_utf8(x).unwrap_or("") -} - impl<'a, 'b> std::fmt::Debug for AnyTerm<'a, 'b> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { match self.mkref() { @@ -576,6 +584,13 @@ impl<'a, 'b> std::fmt::Debug for AnyTerm<'a, 'b> { } write!(f, ">") } + AnyTerm::ListRef(raw, l) => { + write!(f, "List[`{}`", debug(raw))?; + for i in l.iter() { + write!(f, "\n {:?}", i)?; + } + write!(f, "]") + } AnyTerm::SeqRef(raw, l) => { write!(f, "Seq[`{}`", debug(raw))?; for i in l.iter() { diff --git a/src/enc/mod.rs b/src/enc/mod.rs index fb05ce6..37ac4c5 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -34,6 +34,7 @@ enum T<'a> { Str(&'a [u8]), OwnedStr(Vec), Dict(HashMap, T<'a>>), + List(Vec>), Seq(Vec>), } @@ -95,7 +96,7 @@ pub fn raw(bytes: &[u8]) -> Result<'_> { Ok(Term(T::Str(bytes))) } -/// Term corresponding to a sequence of terms +/// Term corresponding to a sequence of terms. Subsequences are banned and will raise an error. /// /// ``` /// use nettext::enc::*; @@ -117,7 +118,7 @@ pub fn seq<'a, I: IntoIterator>>(terms: I) -> Result<'a> { } /// Term corresponding to a sequence of terms. Sub-sequences are flattenned. -pub fn seq_flatten<'a, I: IntoIterator>>(terms: I) -> Result<'a> { +pub fn seq_flatten<'a, I: IntoIterator>>(terms: I) -> Term<'a> { let mut tmp = Vec::with_capacity(8); for t in terms { match t.0 { @@ -125,19 +126,22 @@ pub fn seq_flatten<'a, I: IntoIterator>>(terms: I) -> Result<'a> x => tmp.push(x), } } - Ok(Term(T::Seq(tmp))) + Term(T::Seq(tmp)) } -/// Term corresponding to a sequence of terms. Sub-sequences are represented as NESTED: `{.= sub sequence items }`. -pub fn seq_nested<'a, I: IntoIterator>>(terms: I) -> Result<'a> { - let mut tmp = Vec::with_capacity(8); - for t in terms { - match t.0 { - T::Seq(t) => tmp.push(Term(T::Seq(t)).nested().0), - x => tmp.push(x), - } - } - Ok(Term(T::Seq(tmp))) +/// Term corresponding to a list of terms. +/// +/// ``` +/// use nettext::enc::*; +/// +/// assert_eq!(list([ +/// string("Hello").unwrap(), +/// string("world").unwrap() +/// ]).encode(), b"[\n Hello,\n world,\n]"); +/// ``` +pub fn list<'a, I: IntoIterator>>(terms: I) -> Term<'a> { + let terms = terms.into_iter().map(|x| x.0).collect::>(); + Term(T::List(terms)) } /// Term corresponding to a dictionnary of items @@ -219,21 +223,6 @@ impl<'a> Term<'a> { _ => Err(Error::NotADictionnary), } } - - /// Makes a NESTED term of this term, by putting it in a dict - /// with a single key `.`. - /// - /// Example: - /// - /// ``` - /// use nettext::enc::*; - /// - /// assert_eq!(seq([string("hello").unwrap(), string("world").unwrap()]).unwrap().nested().encode(), b"{.= hello world }"); - /// ``` - #[must_use] - pub fn nested(self) -> Term<'a> { - dict([(".", self)]).unwrap() - } } // ---- additional internal functions for serde module ---- @@ -285,13 +274,9 @@ impl<'a> T<'a> { buf.extend_from_slice(b"{}"); } else if d.len() == 1 { let (k, v) = d.into_iter().next().unwrap(); - if k.as_ref() == b"." { - buf.extend_from_slice(b"{.= "); - } else { - buf.extend_from_slice(b"{ "); - buf.extend_from_slice(k.borrow()); - buf.extend_from_slice(b" = "); - } + buf.extend_from_slice(b"{ "); + buf.extend_from_slice(k.borrow()); + buf.extend_from_slice(b" = "); v.encode_aux(buf, indent + 2, false); buf.extend_from_slice(b" }"); } else { @@ -315,6 +300,29 @@ impl<'a> T<'a> { buf.push(b'}'); } } + T::List(l) => { + if l.len() == 0 { + buf.extend_from_slice(b"[]"); + } else if l.len() == 1 { + buf.extend_from_slice(b"[ "); + l.into_iter().next().unwrap().encode_aux(buf, indent + 2, false); + buf.extend_from_slice(b" ]"); + } else { + let indent2 = indent + 2; + buf.extend_from_slice(b"[\n"); + for item in l { + for _ in 0..indent2 { + buf.push(b' '); + } + item.encode_aux(buf, indent2, false); + buf.extend_from_slice(b",\n"); + } + for _ in 0..indent { + buf.push(b' '); + } + buf.push(b']'); + } + } T::Seq(l) => { let indent2 = indent + 2; for (i, v) in l.into_iter().enumerate() { @@ -335,6 +343,7 @@ impl<'a> T<'a> { #[cfg(test)] mod tests { + use crate::debug; use super::*; #[test] @@ -342,6 +351,10 @@ mod tests { let input = seq([ string("HELLO").unwrap(), string("alexhelloworld").unwrap(), + list([ + string("dude").unwrap(), + string("why").unwrap(), + ]), dict([ ("from", string("jxx").unwrap()), ("subject", string("hello").unwrap()), @@ -350,37 +363,17 @@ mod tests { .unwrap(), ]) .unwrap(); - let expected = b"HELLO alexhelloworld { + let expected = "HELLO alexhelloworld [ + dude, + why, + ] { data = { f1 = plop, f2 = kuko }, from = jxx, subject = hello, }"; let enc = input.encode(); - eprintln!("{}", std::str::from_utf8(&enc).unwrap()); - eprintln!("{}", std::str::from_utf8(&expected[..]).unwrap()); - assert_eq!(&enc, &expected[..]); - } - - #[test] - fn nested() { - assert!(seq([ - string("a").unwrap(), - string("b").unwrap(), - seq([string("c").unwrap(), string("d").unwrap()]).unwrap() - ]) - .is_err()); - - assert_eq!( - seq([ - string("a").unwrap(), - string("b").unwrap(), - seq([string("c").unwrap(), string("d").unwrap()]) - .unwrap() - .nested() - ]) - .unwrap() - .encode(), - b"a b {.= c d }" - ); + eprintln!("{}", debug(&enc)); + eprintln!("{}", expected); + assert_eq!(debug(&enc), expected); } } diff --git a/src/lib.rs b/src/lib.rs index 5dc2417..b2aef2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,6 +100,9 @@ pub(crate) const DICT_OPEN: u8 = b'{'; pub(crate) const DICT_CLOSE: u8 = b'}'; pub(crate) const DICT_ASSIGN: u8 = b'='; pub(crate) const DICT_DELIM: u8 = b','; +pub(crate) const LIST_OPEN: u8 = b'['; +pub(crate) const LIST_CLOSE: u8 = b']'; +pub(crate) const LIST_DELIM: u8 = b','; pub(crate) const STR_EXTRA_CHARS: &[u8] = b"._-+*?@:"; pub(crate) fn is_string_char(c: u8) -> bool { @@ -109,3 +112,7 @@ pub(crate) fn is_string_char(c: u8) -> bool { pub(crate) fn is_whitespace(c: u8) -> bool { c.is_ascii_whitespace() } + +pub(crate) fn debug(x: &[u8]) -> &str { + std::str::from_utf8(x).unwrap_or("") +} diff --git a/src/serde/de.rs b/src/serde/de.rs index 83e0cbe..3a1b427 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -6,7 +6,7 @@ use serde::de::{ }; use serde::Deserialize; -use crate::dec::debug as fmtdebug; +use crate::debug as fmtdebug; use crate::dec::*; use crate::serde::error::{Error, Result}; @@ -15,11 +15,7 @@ pub struct Deserializer<'de, 'a>(Term<'de, 'a>); impl<'de, 'a> Deserializer<'de, 'a> { fn from_term(input: &'a Term<'de, 'a>) -> Deserializer<'de, 'a> { - if let Ok(nested) = input.nested() { - Deserializer(nested) - } else { - Deserializer(Term(input.0.mkref())) - } + Deserializer(Term(input.0.mkref())) } } @@ -244,7 +240,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de, 'a> { where V: Visitor<'de>, { - visitor.visit_seq(&mut Seq(&self.0.seq())) + visitor.visit_seq(&mut Seq(&self.0.list()?)) } fn deserialize_tuple(self, _len: usize, visitor: V) -> Result diff --git a/src/serde/mod.rs b/src/serde/mod.rs index fb15bf6..3a292c6 100644 --- a/src/serde/mod.rs +++ b/src/serde/mod.rs @@ -13,15 +13,18 @@ mod tests { use super::*; use serde::{Deserialize, Serialize}; use std::collections::HashMap; + use crate::debug; fn test_bidir Deserialize<'de> + PartialEq + std::fmt::Debug>( input: T, - expected: &[u8], + expected: &str, ) { + eprintln!("Expecting: {}", expected); let ser = to_bytes(&input).unwrap(); - eprintln!("Serialized: {}", std::str::from_utf8(&ser).unwrap()); - assert_eq!(&ser, expected); - assert_eq!(&from_bytes::(&ser).unwrap(), &input); + let ser = debug(&ser); + eprintln!("Serialized: {}", ser); + assert_eq!(ser, expected); + assert_eq!(from_bytes::(ser.as_bytes()).unwrap(), input); } #[test] @@ -36,9 +39,12 @@ mod tests { int: 1, seq: vec!["a".to_string(), "b".to_string()], }; - let expected = br#"Test { + let expected = r#"Test { int = 1, - seq = YQ Yg, + seq = [ + YQ, + Yg, + ], }"#; test_bidir(input, expected); @@ -52,13 +58,22 @@ mod tests { seq: vec!["c".to_string(), "d".to_string()], }, ]; - let expected = br#"{.= Test { - int = 1, - seq = YQ Yg, - } } {.= Test { - int = 2, - seq = Yw ZA, - } }"#; + let expected = r#"[ + Test { + int = 1, + seq = [ + YQ, + Yg, + ], + }, + Test { + int = 2, + seq = [ + Yw, + ZA, + ], + }, +]"#; test_bidir(input, expected); } @@ -73,19 +88,19 @@ mod tests { } let input = E::Unit; - let expected = br#"E.Unit"#; + let expected = r#"E.Unit"#; test_bidir(input, expected); let input = E::Newtype(1); - let expected = br#"E.Newtype 1"#; + let expected = r#"E.Newtype 1"#; test_bidir(input, expected); let input = E::Tuple(1, 2); - let expected = br#"E.Tuple 1 2"#; + let expected = r#"E.Tuple 1 2"#; test_bidir(input, expected); let input = E::Struct { a: 1 }; - let expected = br#"E.Struct { a = 1 }"#; + let expected = r#"E.Struct { a = 1 }"#; test_bidir(input, expected); let input = vec![ @@ -97,36 +112,45 @@ mod tests { E::Tuple(3, 2), ]; let expected = - br#"E.Unit E.Unit {.= E.Newtype 1 } {.= E.Tuple 1 2 } {.= E.Struct { a = 1 } } {.= - E.Tuple 3 2 }"#; + r#"[ + E.Unit, + E.Unit, + E.Newtype 1, + E.Tuple 1 2, + E.Struct { a = 1 }, + E.Tuple 3 2, +]"#; test_bidir(input, expected); } #[test] fn test_seq1() { let input = (1, 2, 3, 4); - let expected = br#"1 2 3 4"#; + let expected = r#"1 2 3 4"#; test_bidir(input, expected); } #[test] - fn test_seq2() { - let input = (1, 2, (2, 3, 4), 5, 6); - let expected = br#"1 2 {.= 2 3 4 } 5 6"#; + fn test_list() { + let input = vec![1, 2, 3, 4]; + let expected = r#"[ + 1, + 2, + 3, + 4, +]"#; test_bidir(input, expected); } #[test] - fn test_seq3() { - let input = [1, 2, 3, 4]; - let expected = br#"1 2 3 4"#; - test_bidir(input, expected); - } - - #[test] - fn test_seq4() { - let input = [[1, 2], [2, 3], [3, 4]]; - let expected = br#"{.= 1 2 } {.= 2 3 } {.= 3 4 }"#; + fn test_seqlist() { + let input = vec![(1, 2), (2, 3), (3, 4), (5, 6)]; + let expected = r#"[ + 1 2, + 2 3, + 3 4, + 5 6, +]"#; test_bidir(input, expected); } @@ -135,7 +159,7 @@ mod tests { let mut input = HashMap::new(); input.insert("hello".to_string(), "world".to_string()); input.insert("dont".to_string(), "panic".to_string()); - let expected = br#"{ + let expected = r#"{ ZG9udA = cGFuaWM, aGVsbG8 = d29ybGQ, }"#; @@ -144,9 +168,16 @@ mod tests { let mut input = HashMap::new(); input.insert(12, vec![42, 125]); input.insert(33, vec![19, 22, 21]); - let expected = br#"{ - 12 = 42 125, - 33 = 19 22 21, + let expected = r#"{ + 12 = [ + 42, + 125, + ], + 33 = [ + 19, + 22, + 21, + ], }"#; test_bidir(input, expected); } diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 8c83977..2de2fe9 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -28,7 +28,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { type Error = Error; - type SerializeSeq = SeqSerializer; + type SerializeSeq = ListSerializer; type SerializeTuple = SeqSerializer; type SerializeTupleStruct = SeqSerializer; type SerializeTupleVariant = SeqSerializer; @@ -104,7 +104,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { where T: ?Sized + Serialize, { - Ok(value.serialize(self)?.nested()) + Ok(value.serialize(self)?) } fn serialize_unit(self) -> Result { @@ -128,7 +128,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { where T: ?Sized + Serialize, { - Ok(seq_flatten([string(name)?, value.serialize(self)?])?) + Ok(seq_flatten([string(name)?, value.serialize(self)?])) } fn serialize_newtype_variant( @@ -144,11 +144,11 @@ impl<'a> ser::Serializer for &'a mut Serializer { Ok(seq_flatten([ string_owned(format!("{}.{}", name, variant))?, value.serialize(self)?, - ])?) + ])) } fn serialize_seq(self, _len: Option) -> Result { - Ok(SeqSerializer { items: vec![] }) + Ok(ListSerializer { items: vec![] }) } fn serialize_tuple(self, len: usize) -> Result { @@ -213,22 +213,6 @@ impl<'a> ser::Serializer for &'a mut Serializer { pub struct SeqSerializer { items: Vec>, } -impl ser::SerializeSeq for SeqSerializer { - type Ok = Term<'static>; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - self.items.push(value.serialize(&mut Serializer)?); - Ok(()) - } - - fn end(self) -> Result { - Ok(seq_nested(self.items.into_iter())?) - } -} impl ser::SerializeTuple for SeqSerializer { type Ok = Term<'static>; @@ -243,7 +227,7 @@ impl ser::SerializeTuple for SeqSerializer { } fn end(self) -> Result { - Ok(seq_nested(self.items.into_iter())?) + Ok(seq(self.items.into_iter())?) } } @@ -260,7 +244,7 @@ impl ser::SerializeTupleStruct for SeqSerializer { } fn end(self) -> Result { - Ok(seq_nested(self.items.into_iter())?) + Ok(seq(self.items.into_iter())?) } } @@ -277,7 +261,27 @@ impl ser::SerializeTupleVariant for SeqSerializer { } fn end(self) -> Result { - Ok(seq_nested(self.items.into_iter())?) + Ok(seq(self.items.into_iter())?) + } +} + +pub struct ListSerializer { + items: Vec>, +} +impl ser::SerializeSeq for ListSerializer { + type Ok = Term<'static>; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.items.push(value.serialize(&mut Serializer)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(list(self.items.into_iter())) } }