about summary refs log tree commit diff
path: root/pkgs/profpatsch/netencode
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2020-07-03 13:07:35 +0200
committerProfpatsch <mail@profpatsch.de>2020-07-06 20:13:42 +0200
commite409df3861f48de44d0e37277ce007e348a7a0dc (patch)
tree6e70ad4a7889c2fdc9b9ea6a2b0af51accc97d51 /pkgs/profpatsch/netencode
parent124daced37aaab646c83b75711bf744c1d295a8b (diff)
pkgs/profpatsch/netencode: Encode into U instead of T
This is an experiment about whether we can get away with using the
non-recursive version by default.

The U::Record variant uses a Vec instead of a HashMap by default, to
make encoding from lists easier, and keep the ordering as given.
Diffstat (limited to 'pkgs/profpatsch/netencode')
-rw-r--r--pkgs/profpatsch/netencode/netencode.rs79
-rw-r--r--pkgs/profpatsch/netencode/record-get.rs11
2 files changed, 43 insertions, 47 deletions
diff --git a/pkgs/profpatsch/netencode/netencode.rs b/pkgs/profpatsch/netencode/netencode.rs
index 6e73bbb4..57b0a094 100644
--- a/pkgs/profpatsch/netencode/netencode.rs
+++ b/pkgs/profpatsch/netencode/netencode.rs
@@ -47,7 +47,7 @@ pub enum U<'a> {
     Binary(&'a [u8]),
     // Tags
     Sum(Tag<&'a str, Box<U<'a>>>),
-    Record(HashMap<&'a str, Box<U<'a>>>),
+    Record(Vec<(&'a str, Box<U<'a>>)>),
     List(&'a [u8]),
 }
 
@@ -68,30 +68,34 @@ impl<S, A> Tag<S, A> {
     }
 }
 
-fn encode_tag<W: Write>(w: &mut W, tag: String, val: T) -> std::io::Result<()> {
+fn encode_tag<W: Write>(w: &mut W, tag: &str, val: U) -> std::io::Result<()> {
     write!(w, "<{}:{}|", tag.len(), tag)?;
     encode(w, val)?;
     Ok(())
 }
 
-pub fn encode<W: Write>(w: &mut W, t: T) -> std::io::Result<()> {
-  match t {
-      T::Unit => write!(w, "u,"),
-      T::N1(b) => if b { write!(w, "n1:1,") } else { write!(w, "n1:0,") },
-      T::N3(n) => write!(w, "n3:{},", n),
-      T::N6(n) => write!(w, "n6:{},", n),
-      T::N7(n) => write!(w, "n7:{},", n),
-      T::I3(i) => write!(w, "i3:{},", i),
-      T::I6(i) => write!(w, "i6:{},", i),
-      T::I7(i) => write!(w, "i7:{},", i),
-      T::Text(s) => write!(w, "t{}:{},", s.len(), s),
-      T::Binary(s) => {
+pub fn encode<W: Write>(w: &mut W, u: U) -> std::io::Result<()> {
+  match u {
+      U::Unit => write!(w, "u,"),
+      U::N1(b) => if b { write!(w, "n1:1,") } else { write!(w, "n1:0,") },
+      U::N3(n) => write!(w, "n3:{},", n),
+      U::N6(n) => write!(w, "n6:{},", n),
+      U::N7(n) => write!(w, "n7:{},", n),
+      U::I3(i) => write!(w, "i3:{},", i),
+      U::I6(i) => write!(w, "i6:{},", i),
+      U::I7(i) => write!(w, "i7:{},", i),
+      U::Text(s) => {
+          write!(w, "t{}:", s.len());
+          w.write(&s);
+          write!(w, ",")
+      }
+      U::Binary(s) => {
           write!(w, "b{}:", s.len());
           w.write(&s);
           write!(w, ",")
       },
-      T::Sum(Tag{tag, val}) => encode_tag(w, tag, *val),
-      T::Record(m) => {
+      U::Sum(Tag{tag, val}) => encode_tag(w, tag, *val),
+      U::Record(m) => {
           let mut c = std::io::Cursor::new(vec![]);
           for (k, v) in m {
               encode_tag(&mut c, k, *v)?;
@@ -100,27 +104,14 @@ pub fn encode<W: Write>(w: &mut W, t: T) -> std::io::Result<()> {
           w.write(c.get_ref())?;
           write!(w, "}}")
       },
-      T::List(l) => {
-          let mut c = std::io::Cursor::new(vec![]);
-          for v in *l {
-              encode(&mut c, v)?;
-          };
-          write!(w, "[{}:", c.get_ref().len())?;
-          w.write(c.get_ref())?;
+      U::List(l) => {
+          write!(w, "[{}:", l.len())?;
+          w.write(l)?;
           write!(w, "]")
       }
   }
 }
 
-pub fn dict(d: Vec<(String, T)>) -> T {
-    T::Record(
-        d.into_iter()
-            .map(|(k,v)| (k, Box::new(v)))
-            // to ignore duplicate entries after the first
-            .rev()
-            .collect::<HashMap<_,_>>())
-}
-
 pub fn text(s: String) -> T {
     T::Text(s)
 }
@@ -289,17 +280,18 @@ pub mod parse {
         map_parser(list_g(), nom::multi::many_m_n(n, n, u_u))
     }
 
-    // fn record_get<'a>(key: usize
-
     fn record_t<'a>(s: &'a [u8]) -> IResult<&'a [u8], HashMap<String, Box<T>>> {
-        let (s, hm) = record_g(t_t)(s)?;
+        let (s, r) = record_g(t_t)(s)?;
         Ok((s,
-            hm.into_iter().map(
-                |(k, v)| (k.to_string(), v)
-            ).collect::<HashMap<_,_>>()))
+            r.into_iter()
+            // ignore duplicated tag names that appear later
+            // by reverting the vector now
+            .rev()
+            .map(|(k, v)| (k.to_string(), v))
+            .collect::<HashMap<_,_>>()))
     }
 
-    fn record_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], HashMap<&'a str, Box<O>>>
+    fn record_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<(&'a str, Box<O>)>>
     where
         O: Clone,
         P: Fn(&'a [u8]) -> IResult<&'a [u8], O>
@@ -308,12 +300,9 @@ pub mod parse {
             sized('{', '}'),
             nom::multi::fold_many1(
                 tag_g(inner),
-                HashMap::new(),
-                |mut acc: HashMap<_, _>, Tag { tag, mut val }| {
-                    // ignore duplicated tag names that appear later
-                    if !acc.contains_key(&tag) {
-                        acc.insert(tag, Box::new(val));
-                    }
+                Vec::new(),
+                |mut acc: Vec<_>, Tag { tag, mut val }| {
+                    acc.push((tag, Box::new(val)));
                     acc
                 }
             )
diff --git a/pkgs/profpatsch/netencode/record-get.rs b/pkgs/profpatsch/netencode/record-get.rs
index bf4db3dd..c823249d 100644
--- a/pkgs/profpatsch/netencode/record-get.rs
+++ b/pkgs/profpatsch/netencode/record-get.rs
@@ -6,7 +6,7 @@ use std::io::Read;
 use std::ffi::{CString, OsStr};
 use std::os::unix::ffi::{OsStringExt, OsStrExt};
 use el_semicolon::{el_semicolon, Arg};
-use netencode::{U};
+use netencode::{U, encode};
 use netencode::parse::{u_u};
 
 fn main() {
@@ -30,9 +30,16 @@ fn main() {
                         // only set if it appears in the block of values.
                         // If the block is empty, don’t filter.
                         if vars.is_empty() || vars.contains(&key.as_bytes()) {
+                            // TODO this is a super unprincipled special casing of some values
+                            // We should have a way of destructuring stuff
                             match *val {
                                 U::Binary(b) => std::env::set_var(key, OsStr::from_bytes(b)),
-                                _ => panic!("the value of {:?} was not a binary value!", key)
+                                U::Text(t) => std::env::set_var(key, OsStr::from_bytes(t)),
+                                u => {
+                                    let mut c = std::io::Cursor::new(vec![]);
+                                    encode(&mut c, u);
+                                    std::env::set_var(key, OsStr::from_bytes(&c.into_inner()))
+                                }
                             }
                         }
                     }