diff options
author | Profpatsch <mail@profpatsch.de> | 2021-02-07T18·06+0100 |
---|---|---|
committer | Profpatsch <mail@profpatsch.de> | 2021-02-09T01·36+0000 |
commit | 7d9c30ab3d9a9cb72cfcdec0ef060059edca7b1e (patch) | |
tree | 47f6d4436315d387ab0ec9b2406b1393abe489f2 /users | |
parent | 3226e6243f453d2171787e5a5bfbecda9ab469fb (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')
-rw-r--r-- | users/Profpatsch/netencode/default.nix | 2 | ||||
-rw-r--r-- | users/Profpatsch/netencode/netencode.rs | 33 |
2 files changed, 29 insertions, 6 deletions
diff --git a/users/Profpatsch/netencode/default.nix b/users/Profpatsch/netencode/default.nix index 31cd822061b6..3b62c8aaac59 100644 --- a/users/Profpatsch/netencode/default.nix +++ b/users/Profpatsch/netencode/default.nix @@ -108,7 +108,7 @@ let let mut buf = vec![]; let u = netencode::u_from_stdin_or_die_user_error("record-splice-env", &mut buf); let (_, prog) = exec_helpers::args_for_exec("record-splice-env", 0); - match Record::<ScalarAsBytes>::dec(u) { + match Record(ScalarAsBytes).dec(u) { Ok(map) => { exec_helpers::exec_into_args("record-splice-env", prog, map); }, diff --git a/users/Profpatsch/netencode/netencode.rs b/users/Profpatsch/netencode/netencode.rs index e15cd8b38327..7099506f6df2 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), |