From 7cb5ff2fc2c9a8b06c00126f1bc271d0088f9fc7 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 18 Nov 2022 12:53:14 +0100 Subject: [PATCH] Change `encode` to be a method of Term --- src/enc/mod.rs | 135 +++++++++++++++++++++++++------------------------ src/lib.rs | 8 +-- 2 files changed, 73 insertions(+), 70 deletions(-) diff --git a/src/enc/mod.rs b/src/enc/mod.rs index eb7218b..d299d0e 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -46,7 +46,7 @@ impl<'a, 'b> Encode for dec::Term<'a, 'b> { /// ``` /// use nettext::enc::*; /// -/// assert_eq!(encode(string("Hello world .").unwrap()), b"Hello world ."); +/// assert_eq!(string("Hello world .").unwrap().encode(), b"Hello world ."); /// ``` pub fn string(s: &str) -> Result<'_> { for c in s.as_bytes().iter() { @@ -62,7 +62,7 @@ pub fn string(s: &str) -> Result<'_> { /// ``` /// use nettext::enc::*; /// -/// assert_eq!(encode(raw(b"Hello { a = b, c = d} .").unwrap()), b"Hello { a = b, c = d} ."); +/// assert_eq!(raw(b"Hello { a = b, c = d} .").unwrap().encode(), b"Hello { a = b, c = d} ."); /// ``` pub fn raw(bytes: &[u8]) -> Result<'_> { if decode(bytes).is_err() { @@ -76,10 +76,10 @@ pub fn raw(bytes: &[u8]) -> Result<'_> { /// ``` /// use nettext::enc::*; /// -/// assert_eq!(encode(list([ +/// assert_eq!(list([ /// string("Hello").unwrap(), /// string("world").unwrap() -/// ]).unwrap()), b"Hello world"); +/// ]).unwrap().encode(), b"Hello world"); /// ``` pub fn list<'a, I: IntoIterator>>(terms: I) -> Result<'a> { let mut tmp = Vec::with_capacity(8); @@ -97,10 +97,10 @@ pub fn list<'a, I: IntoIterator>>(terms: I) -> Result<'a> { /// ``` /// use nettext::enc::*; /// -/// assert_eq!(encode(dict([ +/// assert_eq!(dict([ /// ("a", string("Hello").unwrap()), /// ("b", string("world").unwrap()) -/// ])), b"{\n a = Hello,\n b = world,\n}"); +/// ]).encode(), b"{\n a = Hello,\n b = world,\n}"); /// ``` pub fn dict<'a, I: IntoIterator)>>(pairs: I) -> Term<'a> { let mut tmp = HashMap::new(); @@ -118,7 +118,7 @@ pub fn dict<'a, I: IntoIterator)>>(pairs: I) -> Term<' /// ``` /// use nettext::enc::*; /// -/// assert_eq!(encode(bytes(b"hello, world!")), b"aGVsbG8sIHdvcmxkIQ"); +/// assert_eq!(bytes(b"hello, world!").encode(), b"aGVsbG8sIHdvcmxkIQ"); /// ``` pub fn bytes(bytes: &[u8]) -> Term<'static> { Term(T::OwnedStr( @@ -176,7 +176,7 @@ impl<'a> Term<'a> { /// ``` /// use nettext::enc::*; /// - /// assert_eq!(encode(list([string("hello").unwrap(), string("world").unwrap()]).unwrap().nested()), b"{ . = hello world }"); + /// assert_eq!(list([string("hello").unwrap(), string("world").unwrap()]).unwrap().nested().encode(), b"{ . = hello world }"); /// ``` #[must_use] pub fn nested(self) -> Term<'a> { @@ -186,60 +186,64 @@ impl<'a> Term<'a> { // ---- encoding function ---- -/// Generate the nettext representation of a term -pub fn encode(t: Term<'_>) -> Vec { - let mut buf = Vec::with_capacity(128); - encode_aux(&mut buf, t.0, 0, true); - buf +impl<'a> Term<'a> { + /// Generate the nettext representation of a term + pub fn encode(self) -> Vec { + let mut buf = Vec::with_capacity(128); + self.0.encode_aux(&mut buf, 0, true); + buf + } } -fn encode_aux(buf: &mut Vec, term: T<'_>, indent: usize, is_toplevel: bool) { - match term { - T::Str(s) => buf.extend_from_slice(s), - T::OwnedStr(s) => buf.extend_from_slice(&s), - T::Dict(mut d) => { - if d.is_empty() { - buf.extend_from_slice(b"{}"); - } else if d.len() == 1 { - buf.extend_from_slice(b"{ "); - let (k, v) = d.into_iter().next().unwrap(); - buf.extend_from_slice(k); - buf.extend_from_slice(b" = "); - encode_aux(buf, v, indent + 2, false); - buf.extend_from_slice(b" }"); - } else { - buf.extend_from_slice(b"{\n"); - let indent2 = indent + 2; - let mut keys = d.keys().cloned().collect::>(); - keys.sort(); - for k in keys { - let v = d.remove(k).unwrap(); - for _ in 0..indent2 { - buf.push(b' '); - } +impl<'a> T<'a> { + fn encode_aux(self, buf: &mut Vec, indent: usize, is_toplevel: bool) { + match self { + T::Str(s) => buf.extend_from_slice(s), + T::OwnedStr(s) => buf.extend_from_slice(&s), + T::Dict(mut d) => { + if d.is_empty() { + buf.extend_from_slice(b"{}"); + } else if d.len() == 1 { + buf.extend_from_slice(b"{ "); + let (k, v) = d.into_iter().next().unwrap(); buf.extend_from_slice(k); buf.extend_from_slice(b" = "); - encode_aux(buf, v, indent2, false); - buf.extend_from_slice(b",\n"); - } - for _ in 0..indent { - buf.push(b' '); - } - buf.push(b'}'); - } - } - T::List(l) => { - let indent2 = indent + 2; - for (i, v) in l.into_iter().enumerate() { - if !is_toplevel && buf.iter().rev().take_while(|c| **c != b'\n').count() >= 70 { - buf.push(b'\n'); - for _ in 0..indent2 { + v.encode_aux(buf, indent + 2, false); + buf.extend_from_slice(b" }"); + } else { + buf.extend_from_slice(b"{\n"); + let indent2 = indent + 2; + let mut keys = d.keys().cloned().collect::>(); + keys.sort(); + for k in keys { + let v = d.remove(k).unwrap(); + for _ in 0..indent2 { + buf.push(b' '); + } + buf.extend_from_slice(k); + buf.extend_from_slice(b" = "); + v.encode_aux(buf, indent2, false); + buf.extend_from_slice(b",\n"); + } + for _ in 0..indent { buf.push(b' '); } - } else if i > 0 { - buf.push(b' '); + buf.push(b'}'); + } + } + T::List(l) => { + let indent2 = indent + 2; + for (i, v) in l.into_iter().enumerate() { + if !is_toplevel && buf.iter().rev().take_while(|c| **c != b'\n').count() >= 70 { + buf.push(b'\n'); + for _ in 0..indent2 { + buf.push(b' '); + } + } else if i > 0 { + buf.push(b' '); + } + v.encode_aux(buf, indent2, is_toplevel); } - encode_aux(buf, v, indent2, is_toplevel); } } } @@ -266,7 +270,7 @@ mod tests { from = jxx, subject = hello, }"; - let enc = encode(input); + let enc = input.encode(); eprintln!("{}", std::str::from_utf8(&enc).unwrap()); eprintln!("{}", std::str::from_utf8(&expected[..]).unwrap()); assert_eq!(&enc, &expected[..]); @@ -282,16 +286,15 @@ mod tests { .is_err()); assert_eq!( - encode( - list([ - string("a").unwrap(), - string("b").unwrap(), - list([string("c").unwrap(), string("d").unwrap()]) - .unwrap() - .nested() - ]) - .unwrap() - ), + list([ + string("a").unwrap(), + string("b").unwrap(), + list([string("c").unwrap(), string("d").unwrap()]) + .unwrap() + .nested() + ]) + .unwrap() + .encode(), b"a b { . = c d }" ); } diff --git a/src/lib.rs b/src/lib.rs index cfbd447..cbf1acc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ //! let keypair = crypto::generate_keypair(); //! //! // Encode a fist object that represents a payload that will be hashed and signed -//! let text1 = encode(list([ +//! let text1 = list([ //! string("CALL").unwrap(), //! string("myfunction").unwrap(), //! dict([ @@ -18,18 +18,18 @@ //! ("d", bytes_split(&((0..128u8).collect::>()))), //! ]), //! keypair.public.term().unwrap(), -//! ]).unwrap()); +//! ]).unwrap().encode(); //! eprintln!("{}", std::str::from_utf8(&text1).unwrap()); //! //! let hash = crypto::Blake2Sum::compute(&text1); //! let sign = keypair.sign(&text1); //! //! // Encode a second object that represents the signed and hashed payload -//! let text2 = encode(dict([ +//! let text2 = dict([ //! ("hash", hash.term().unwrap()), //! ("signature", sign.term().unwrap()), //! ("payload", raw(&text1).unwrap()), -//! ])); +//! ]).encode(); //! eprintln!("{}", std::str::from_utf8(&text2).unwrap()); //! //! // Decode and check everything is fine