From fd0d0764ecd67d82fb331074a47a6f8c089b81ce Mon Sep 17 00:00:00 2001 From: Profpatsch Date: Tue, 9 Feb 2021 01:36:00 +0100 Subject: feat(users/Profpatsch/netencode): add dec::{Text,Binary,OneOf} `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 --- users/Profpatsch/netencode/netencode.rs | 66 ++++++++++++++++++++++++++++++--- 1 file 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), // 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), @@ -649,6 +651,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 { + 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 { + match u { + U::Binary(b) => Ok(b), + other => Err(DecodeError(format!("Cannot decode {:?} into Binary", other))), + } + } + } + #[derive(Clone, Copy)] pub struct ScalarAsBytes; @@ -672,7 +700,9 @@ pub mod dec { #[derive(Clone, Copy)] pub struct Record(pub T); - impl<'a, Inner: Decoder<'a>> Decoder<'a> for Record { + impl<'a, Inner> Decoder<'a> for Record + where Inner: Decoder<'a> + { type A = HashMap<&'a str, Inner::A>; fn dec(&self, u: U<'a>) -> Result { 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 { - 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{ + pub inner: T, + pub list: Vec, + } + + impl <'a, Inner> Decoder<'a> for OneOf + where Inner: Decoder<'a>, + Inner::A: Display + Debug + PartialEq + { + type A = Inner::A; + fn dec(&self, u: U<'a>) -> Result { + 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 { match parse::u_u(b) { Ok((b"", u)) => Ok(u), -- cgit 1.4.1