about summary refs log tree commit diff
path: root/users/Profpatsch/netencode/netencode.rs
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2021-02-07T18·06+0100
committerProfpatsch <mail@profpatsch.de>2021-02-09T01·36+0000
commit7d9c30ab3d9a9cb72cfcdec0ef060059edca7b1e (patch)
tree47f6d4436315d387ab0ec9b2406b1393abe489f2 /users/Profpatsch/netencode/netencode.rs
parent3226e6243f453d2171787e5a5bfbecda9ab469fb (diff)
feat(users/Profpatsch/netencode): add `dec::RecordDot` r/2190
`dec::RecordDot` accesses a specific field of a netencode record.

In order to implement this, either we’d have to introduce a type-level
string, but in all honesty this kind of typelevel circlejerking never
leads anywhere, so let’s change the trait to use `&self` after all.
Usage is pretty much the same, except actually more like you’d expect.

Change-Id: I5a7f1a3f587256c50df1b65c2969e5a7194bba70
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2494
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
Diffstat (limited to 'users/Profpatsch/netencode/netencode.rs')
-rw-r--r--users/Profpatsch/netencode/netencode.rs33
1 files changed, 28 insertions, 5 deletions
diff --git a/users/Profpatsch/netencode/netencode.rs b/users/Profpatsch/netencode/netencode.rs
index e15cd8b383..7099506f6d 100644
--- a/users/Profpatsch/netencode/netencode.rs
+++ b/users/Profpatsch/netencode/netencode.rs
@@ -601,10 +601,12 @@ pub mod dec {
 
     pub trait Decoder<'a> {
         type A;
-        fn dec(u: U<'a>) -> Result<Self::A, DecodeError>;
+        fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError>;
     }
 
+    #[derive(Clone, Copy)]
     pub struct AnyT;
+    #[derive(Clone, Copy)]
     pub struct AnyU;
 
     // impl Decoder for AnyT {
@@ -617,16 +619,17 @@ pub mod dec {
 
     impl<'a> Decoder<'a> for AnyU {
         type A = U<'a>;
-        fn dec(u: U<'a>) -> Result<Self::A, DecodeError> {
+        fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
             Ok(u)
         }
     }
 
+    #[derive(Clone, Copy)]
     pub struct ScalarAsBytes;
 
     impl<'a> Decoder<'a> for ScalarAsBytes {
         type A = Vec<u8>;
-        fn dec(u: U<'a>) -> Result<Self::A, DecodeError> {
+        fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
             match u {
                 U::N3(u) => Ok(format!("{}", u).into_bytes()),
                 U::N6(u) => Ok(format!("{}", u).into_bytes()),
@@ -641,21 +644,41 @@ pub mod dec {
         }
     }
 
+    #[derive(Clone, Copy)]
     pub struct Record<T>(pub T);
 
     impl<'a, Inner: Decoder<'a>> Decoder<'a> for Record<Inner> {
         type A = HashMap<&'a str, Inner::A>;
-        fn dec(u: U<'a>) -> Result<Self::A, DecodeError> {
+        fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
             match u {
                 U::Record(map) =>
                     map.into_iter()
-                    .map(|(k, v)| Inner::dec(v).map(|v2| (k, v2)))
+                    .map(|(k, v)| self.0.dec(v).map(|v2| (k, v2)))
                     .collect::<Result<Self::A, _>>(),
                 o => Err(DecodeError(format!("Cannot decode {:?} into record", o)))
             }
         }
     }
 
+    #[derive(Clone, Copy)]
+    pub struct RecordDot<'a, T> {
+        field: &'a str,
+        inner: T
+    }
+
+    impl <'a, Inner: Decoder<'a> + Copy> Decoder<'a> for RecordDot<'_, Inner> {
+        type A = Inner::A;
+        fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
+            match Record(self.inner).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))),
+                },
+                Err(err) => Err(err),
+            }
+        }
+    }
+
     fn dec_u(b: &[u8]) -> Result<U, DecodeError> {
         match parse::u_u(b) {
             Ok((b"", u)) => Ok(u),