about summary refs log tree commit diff
path: root/users
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2021-02-09T00·36+0100
committerProfpatsch <mail@profpatsch.de>2021-02-09T01·36+0000
commitfd0d0764ecd67d82fb331074a47a6f8c089b81ce (patch)
tree35504720aa61fa64ae9850ecac532a032240b18b /users
parent8ff77f0b9f2c903b5025c8fa961f9c02be02ec9c (diff)
feat(users/Profpatsch/netencode): add dec::{Text,Binary,OneOf} r/2194
`Text` and `Binary` should be self-explaining, they just match on the
primitive and throw an error otherwise.

OneOf is cool, because it allows the user to match on the
result type of decoding `inner`, and give a list of values that should
be allowed as the result type (the associated type `A` in the
`Decoder` trait).

Change-Id: Ia252e25194610555c17c37640a96953142f0a165
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2498
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
Diffstat (limited to 'users')
-rw-r--r--users/Profpatsch/netencode/netencode.rs66
1 files changed, 60 insertions, 6 deletions
diff --git a/users/Profpatsch/netencode/netencode.rs b/users/Profpatsch/netencode/netencode.rs
index 282eaf74bcea..f2fef1e109ed 100644
--- a/users/Profpatsch/netencode/netencode.rs
+++ b/users/Profpatsch/netencode/netencode.rs
@@ -3,6 +3,7 @@ extern crate exec_helpers;
 
 use std::collections::HashMap;
 use std::io::{Write, Read};
+use std::fmt::{Display, Debug};
 
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum T {
@@ -21,6 +22,7 @@ pub enum T {
     // Text
     // TODO: make into &str
     Text(String),
+    // TODO: rename to Bytes
     Binary(Vec<u8>),
     // Tags
     // TODO: make into &str
@@ -31,7 +33,7 @@ pub enum T {
 }
 
 impl T {
-    fn to_u<'a>(&'a self) -> U<'a> {
+    pub fn to_u<'a>(&'a self) -> U<'a> {
         match self {
             T::Unit => U::Unit,
             T::N1(b) => U::N1(*b),
@@ -650,6 +652,32 @@ pub mod dec {
     }
 
     #[derive(Clone, Copy)]
+    pub struct Text;
+    // TODO: rename to Bytes
+    #[derive(Clone, Copy)]
+    pub struct Binary;
+
+    impl<'a> Decoder<'a> for Text {
+        type A = &'a str;
+        fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
+            match u {
+                U::Text(t) => Ok(t),
+                other => Err(DecodeError(format!("Cannot decode {:?} into Text", other))),
+            }
+        }
+    }
+
+    impl<'a> Decoder<'a> for Binary {
+        type A = &'a [u8];
+        fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
+            match u {
+                U::Binary(b) => Ok(b),
+                other => Err(DecodeError(format!("Cannot decode {:?} into Binary", other))),
+            }
+        }
+    }
+
+    #[derive(Clone, Copy)]
     pub struct ScalarAsBytes;
 
     impl<'a> Decoder<'a> for ScalarAsBytes {
@@ -672,7 +700,9 @@ pub mod dec {
     #[derive(Clone, Copy)]
     pub struct Record<T>(pub T);
 
-    impl<'a, Inner: Decoder<'a>> Decoder<'a> for Record<Inner> {
+    impl<'a, Inner> Decoder<'a> for Record<Inner>
+        where Inner: Decoder<'a>
+    {
         type A = HashMap<&'a str, Inner::A>;
         fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
             match u {
@@ -687,14 +717,16 @@ pub mod dec {
 
     #[derive(Clone, Copy)]
     pub struct RecordDot<'a, T> {
-        field: &'a str,
-        inner: T
+        pub field: &'a str,
+        pub inner: T
     }
 
-    impl <'a, Inner: Decoder<'a> + Copy> Decoder<'a> for RecordDot<'_, Inner> {
+    impl <'a, Inner> Decoder<'a> for RecordDot<'_, Inner>
+        where Inner: Decoder<'a> + Clone
+    {
         type A = Inner::A;
         fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
-            match Record(self.inner).dec(u) {
+            match Record(self.inner.clone()).dec(u) {
                 Ok(mut map) => match map.remove(self.field) {
                     Some(inner) => Ok(inner),
                     None => Err(DecodeError(format!("Cannot find `{}` in record map", self.field))),
@@ -704,6 +736,28 @@ pub mod dec {
         }
     }
 
+    #[derive(Clone)]
+    pub struct OneOf<T, A>{
+        pub inner: T,
+        pub list: Vec<A>,
+    }
+
+    impl <'a, Inner> Decoder<'a> for OneOf<Inner, Inner::A>
+        where Inner: Decoder<'a>,
+              Inner::A: Display + Debug + PartialEq
+    {
+        type A = Inner::A;
+        fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
+            match self.inner.dec(u) {
+                Ok(inner) => match self.list.iter().any(|x| x.eq(&inner)) {
+                    true => Ok(inner),
+                    false => Err(DecodeError(format!("{} is not one of {:?}", inner, self.list)))
+                },
+                Err(err) => Err(err)
+            }
+        }
+    }
+
     fn dec_u(b: &[u8]) -> Result<U, DecodeError> {
         match parse::u_u(b) {
             Ok((b"", u)) => Ok(u),