2021-01-02 14:59:23 +01:00
|
|
|
|
extern crate nom;
|
2021-01-31 16:38:21 +01:00
|
|
|
|
extern crate exec_helpers;
|
2021-01-02 14:59:23 +01:00
|
|
|
|
|
|
|
|
|
use std::collections::HashMap;
|
2021-01-29 15:49:29 +01:00
|
|
|
|
use std::io::{Write, Read};
|
2021-02-09 01:36:00 +01:00
|
|
|
|
use std::fmt::{Display, Debug};
|
2021-01-02 14:59:23 +01:00
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
|
|
|
pub enum T {
|
|
|
|
|
// Unit
|
|
|
|
|
Unit,
|
|
|
|
|
// Boolean
|
|
|
|
|
N1(bool),
|
|
|
|
|
// Naturals
|
|
|
|
|
N3(u8),
|
|
|
|
|
N6(u64),
|
|
|
|
|
N7(u128),
|
|
|
|
|
// Integers
|
|
|
|
|
I3(i8),
|
|
|
|
|
I6(i64),
|
|
|
|
|
I7(i128),
|
|
|
|
|
// Text
|
|
|
|
|
// TODO: make into &str
|
|
|
|
|
Text(String),
|
2021-02-09 01:36:00 +01:00
|
|
|
|
// TODO: rename to Bytes
|
2021-01-02 14:59:23 +01:00
|
|
|
|
Binary(Vec<u8>),
|
|
|
|
|
// Tags
|
|
|
|
|
// TODO: make into &str
|
2021-02-13 23:13:20 +01:00
|
|
|
|
// TODO: rename to Tag
|
2021-01-26 11:27:42 +01:00
|
|
|
|
Sum(Tag<String, T>),
|
2021-01-02 14:59:23 +01:00
|
|
|
|
// TODO: make into &str
|
2021-01-26 11:27:42 +01:00
|
|
|
|
Record(HashMap<String, T>),
|
|
|
|
|
List(Vec<T>),
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 22:43:53 +01:00
|
|
|
|
impl T {
|
2021-02-09 01:36:00 +01:00
|
|
|
|
pub fn to_u<'a>(&'a self) -> U<'a> {
|
2021-02-06 22:43:53 +01:00
|
|
|
|
match self {
|
|
|
|
|
T::Unit => U::Unit,
|
|
|
|
|
T::N1(b) => U::N1(*b),
|
|
|
|
|
T::N3(u) => U::N3(*u),
|
|
|
|
|
T::N6(u) => U::N6(*u),
|
|
|
|
|
T::N7(u) => U::N7(*u),
|
|
|
|
|
T::I3(i) => U::I3(*i),
|
|
|
|
|
T::I6(i) => U::I6(*i),
|
|
|
|
|
T::I7(i) => U::I7(*i),
|
|
|
|
|
T::Text(t) => U::Text(t.as_str()),
|
|
|
|
|
T::Binary(v) => U::Binary(v),
|
|
|
|
|
T::Sum(Tag { tag, val }) => U::Sum(
|
|
|
|
|
Tag { tag: tag.as_str(), val: Box::new(val.to_u()) }
|
|
|
|
|
),
|
|
|
|
|
T::Record(map) => U::Record(
|
|
|
|
|
map.iter().map(|(k, v)| (k.as_str(), v.to_u())).collect()
|
|
|
|
|
),
|
|
|
|
|
T::List(l) => U::List(
|
|
|
|
|
l.iter().map(|v| v.to_u()).collect::<Vec<U<'a>>>()
|
|
|
|
|
),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn encode<'a>(&'a self) -> Vec<u8> {
|
|
|
|
|
match self {
|
|
|
|
|
// TODO: don’t go via U, inefficient
|
|
|
|
|
o => o.to_u().encode()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-02 14:59:23 +01:00
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
|
|
|
pub enum U<'a> {
|
|
|
|
|
Unit,
|
|
|
|
|
// Boolean
|
|
|
|
|
N1(bool),
|
|
|
|
|
// Naturals
|
|
|
|
|
N3(u8),
|
|
|
|
|
N6(u64),
|
|
|
|
|
N7(u128),
|
|
|
|
|
// Integers
|
|
|
|
|
I3(i8),
|
|
|
|
|
I6(i64),
|
|
|
|
|
I7(i128),
|
|
|
|
|
// Text
|
2021-02-01 09:16:14 +01:00
|
|
|
|
Text(&'a str),
|
2021-01-02 14:59:23 +01:00
|
|
|
|
Binary(&'a [u8]),
|
2021-02-07 22:44:50 +01:00
|
|
|
|
// TODO: the U-recursion we do here means we can’t be breadth-lazy anymore
|
|
|
|
|
// like we originally planned; maybe we want to go `U<'a>` → `&'a [u8]` again?
|
2021-02-13 23:13:20 +01:00
|
|
|
|
// Tags
|
|
|
|
|
// TODO: rename to Tag
|
2021-01-26 11:27:42 +01:00
|
|
|
|
Sum(Tag<&'a str, U<'a>>),
|
2021-02-06 22:33:39 +01:00
|
|
|
|
Record(HashMap<&'a str, U<'a>>),
|
2021-02-06 20:31:56 +01:00
|
|
|
|
List(Vec<U<'a>>),
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 22:43:53 +01:00
|
|
|
|
impl<'a> U<'a> {
|
|
|
|
|
pub fn encode(&self) -> Vec<u8> {
|
|
|
|
|
let mut c = std::io::Cursor::new(vec![]);
|
|
|
|
|
encode(&mut c, self);
|
|
|
|
|
c.into_inner()
|
|
|
|
|
}
|
2021-02-07 22:44:50 +01:00
|
|
|
|
|
|
|
|
|
pub fn to_t(&self) -> T {
|
|
|
|
|
match self {
|
|
|
|
|
U::Unit => T::Unit,
|
|
|
|
|
U::N1(b) => T::N1(*b),
|
|
|
|
|
U::N3(u) => T::N3(*u),
|
|
|
|
|
U::N6(u) => T::N6(*u),
|
|
|
|
|
U::N7(u) => T::N7(*u),
|
|
|
|
|
U::I3(i) => T::I3(*i),
|
|
|
|
|
U::I6(i) => T::I6(*i),
|
|
|
|
|
U::I7(i) => T::I7(*i),
|
|
|
|
|
U::Text(t) => T::Text((*t).to_owned()),
|
|
|
|
|
U::Binary(v) => T::Binary((*v).to_owned()),
|
|
|
|
|
U::Sum(Tag { tag, val }) => T::Sum(
|
|
|
|
|
Tag { tag: (*tag).to_owned(), val: Box::new(val.to_t()) }
|
|
|
|
|
),
|
|
|
|
|
U::Record(map) => T::Record(
|
|
|
|
|
map.iter().map(|(k, v)| ((*k).to_owned(), v.to_t())).collect::<HashMap<String, T>>()
|
|
|
|
|
),
|
|
|
|
|
U::List(l) => T::List(
|
|
|
|
|
l.iter().map(|v| v.to_t()).collect::<Vec<T>>()
|
|
|
|
|
),
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-06 22:43:53 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-01-02 14:59:23 +01:00
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
|
|
|
pub struct Tag<S, A> {
|
|
|
|
|
// TODO: make into &str
|
|
|
|
|
pub tag: S,
|
2021-01-26 11:27:42 +01:00
|
|
|
|
pub val: Box<A>
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<S, A> Tag<S, A> {
|
|
|
|
|
fn map<F, B>(self, f: F) -> Tag<S, B>
|
|
|
|
|
where F: Fn(A) -> B {
|
|
|
|
|
Tag {
|
|
|
|
|
tag: self.tag,
|
2021-01-26 11:27:42 +01:00
|
|
|
|
val: Box::new(f(*self.val))
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 22:43:53 +01:00
|
|
|
|
fn encode_tag<W: Write>(w: &mut W, tag: &str, val: &U) -> std::io::Result<()> {
|
2021-01-02 14:59:23 +01:00
|
|
|
|
write!(w, "<{}:{}|", tag.len(), tag)?;
|
|
|
|
|
encode(w, val)?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 22:43:53 +01:00
|
|
|
|
pub fn encode<W: Write>(w: &mut W, u: &U) -> std::io::Result<()> {
|
2021-01-02 14:59:23 +01:00
|
|
|
|
match u {
|
|
|
|
|
U::Unit => write!(w, "u,"),
|
2021-02-06 22:43:53 +01:00
|
|
|
|
U::N1(b) => if *b { write!(w, "n1:1,") } else { write!(w, "n1:0,") },
|
2021-01-02 14:59:23 +01:00
|
|
|
|
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());
|
2021-04-24 00:59:48 +02:00
|
|
|
|
w.write_all(s.as_bytes());
|
2021-01-02 14:59:23 +01:00
|
|
|
|
write!(w, ",")
|
|
|
|
|
}
|
|
|
|
|
U::Binary(s) => {
|
|
|
|
|
write!(w, "b{}:", s.len());
|
2021-04-24 00:59:48 +02:00
|
|
|
|
w.write_all(&s);
|
2021-01-02 14:59:23 +01:00
|
|
|
|
write!(w, ",")
|
|
|
|
|
},
|
2021-02-06 22:43:53 +01:00
|
|
|
|
U::Sum(Tag{tag, val}) => encode_tag(w, tag, val),
|
2021-01-02 14:59:23 +01:00
|
|
|
|
U::Record(m) => {
|
|
|
|
|
let mut c = std::io::Cursor::new(vec![]);
|
|
|
|
|
for (k, v) in m {
|
2021-01-26 11:27:42 +01:00
|
|
|
|
encode_tag(&mut c, k, v)?;
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
write!(w, "{{{}:", c.get_ref().len())?;
|
2021-04-24 00:59:48 +02:00
|
|
|
|
w.write_all(c.get_ref())?;
|
2021-01-02 14:59:23 +01:00
|
|
|
|
write!(w, "}}")
|
|
|
|
|
},
|
|
|
|
|
U::List(l) => {
|
2021-02-06 20:31:56 +01:00
|
|
|
|
let mut c = std::io::Cursor::new(vec![]);
|
|
|
|
|
for u in l {
|
|
|
|
|
encode(&mut c, u)?;
|
|
|
|
|
}
|
|
|
|
|
write!(w, "[{}:", c.get_ref().len())?;
|
2021-04-24 00:59:48 +02:00
|
|
|
|
w.write_all(c.get_ref())?;
|
2021-01-02 14:59:23 +01:00
|
|
|
|
write!(w, "]")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn text(s: String) -> T {
|
|
|
|
|
T::Text(s)
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 22:51:29 +01:00
|
|
|
|
pub fn u_from_stdin_or_die_user_error<'a>(prog_name: &'_ str, stdin_buf: &'a mut Vec<u8>) -> U<'a> {
|
|
|
|
|
std::io::stdin().lock().read_to_end(stdin_buf);
|
|
|
|
|
let u = match parse::u_u(stdin_buf) {
|
|
|
|
|
Ok((rest, u)) => match rest {
|
|
|
|
|
b"" => u,
|
2021-02-13 23:13:20 +01:00
|
|
|
|
_ => exec_helpers::die_user_error(prog_name, format!("stdin contained some soup after netencode value: {:?}", String::from_utf8_lossy(rest)))
|
2021-01-29 15:49:29 +01:00
|
|
|
|
},
|
2021-01-31 16:38:21 +01:00
|
|
|
|
Err(err) => exec_helpers::die_user_error(prog_name, format!("unable to parse netencode from stdin: {:?}", err))
|
2021-02-06 22:51:29 +01:00
|
|
|
|
};
|
|
|
|
|
u
|
2021-01-29 15:49:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-01-02 14:59:23 +01:00
|
|
|
|
pub mod parse {
|
|
|
|
|
use super::{T, Tag, U};
|
|
|
|
|
|
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
use std::ops::Neg;
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
|
|
use nom::{IResult};
|
|
|
|
|
use nom::branch::{alt};
|
2021-03-30 04:49:43 +02:00
|
|
|
|
use nom::bytes::streaming::{tag, take};
|
|
|
|
|
use nom::character::streaming::{digit1, char};
|
2021-01-02 14:59:23 +01:00
|
|
|
|
use nom::sequence::{tuple};
|
|
|
|
|
use nom::combinator::{map, map_res, flat_map, map_parser, opt};
|
|
|
|
|
use nom::error::{context, ErrorKind, ParseError};
|
|
|
|
|
|
|
|
|
|
fn unit_t(s: &[u8]) -> IResult<&[u8], ()> {
|
|
|
|
|
let (s, _) = context("unit", tag("u,"))(s)?;
|
|
|
|
|
Ok((s, ()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn usize_t(s: &[u8]) -> IResult<&[u8], usize> {
|
|
|
|
|
context(
|
|
|
|
|
"usize",
|
|
|
|
|
map_res(
|
|
|
|
|
map_res(digit1, |n| std::str::from_utf8(n)),
|
|
|
|
|
|s| s.parse::<usize>())
|
|
|
|
|
)(s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn sized(begin: char, end: char) -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> {
|
|
|
|
|
move |s: &[u8]| {
|
2021-03-30 04:49:43 +02:00
|
|
|
|
// This is the point where we check the descriminator;
|
|
|
|
|
// if the beginning char does not match, we can immediately return.
|
|
|
|
|
let (s, _) = char(begin)(s)?;
|
|
|
|
|
let (s, (len, _)) = tuple((
|
2021-01-02 14:59:23 +01:00
|
|
|
|
usize_t,
|
|
|
|
|
char(':')
|
|
|
|
|
))(s)?;
|
|
|
|
|
let (s, (res, _)) = tuple((
|
|
|
|
|
take(len),
|
|
|
|
|
char(end)
|
|
|
|
|
))(s)?;
|
|
|
|
|
Ok((s, res))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn uint_t<'a, I: FromStr + 'a>(t: &'static str) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], I> {
|
|
|
|
|
move |s: &'a [u8]| {
|
|
|
|
|
let (s, (_, _, int, _)) = tuple((
|
|
|
|
|
tag(t.as_bytes()),
|
|
|
|
|
char(':'),
|
|
|
|
|
map_res(
|
|
|
|
|
map_res(digit1, |n: &[u8]| std::str::from_utf8(n)),
|
|
|
|
|
|s| s.parse::<I>()
|
|
|
|
|
),
|
|
|
|
|
char(',')
|
|
|
|
|
))(s)?;
|
|
|
|
|
Ok((s, int))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn bool_t<'a>() -> impl Fn(&'a [u8]) -> IResult<&'a [u8], bool> {
|
|
|
|
|
context("bool", alt((
|
|
|
|
|
map(tag("n1:0,"), |_| false),
|
|
|
|
|
map(tag("n1:1,"), |_| true),
|
|
|
|
|
)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn int_t<'a, I: FromStr + Neg<Output=I>>(t: &'static str) -> impl Fn(&'a [u8]) -> IResult<&[u8], I> {
|
|
|
|
|
context(
|
|
|
|
|
t,
|
|
|
|
|
move |s: &'a [u8]| {
|
|
|
|
|
let (s, (_, _, neg, int, _)) = tuple((
|
|
|
|
|
tag(t.as_bytes()),
|
|
|
|
|
char(':'),
|
|
|
|
|
opt(char('-')),
|
|
|
|
|
map_res(
|
|
|
|
|
map_res(digit1, |n: &[u8]| std::str::from_utf8(n)),
|
|
|
|
|
|s| s.parse::<I>()
|
|
|
|
|
),
|
|
|
|
|
char(',')
|
|
|
|
|
))(s)?;
|
|
|
|
|
let res = match neg {
|
|
|
|
|
Some(_) => -int,
|
|
|
|
|
None => int,
|
|
|
|
|
};
|
|
|
|
|
Ok((s, res))
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-26 11:27:42 +01:00
|
|
|
|
fn tag_t(s: &[u8]) -> IResult<&[u8], Tag<String, T>> {
|
2021-01-02 14:59:23 +01:00
|
|
|
|
// recurses into the main parser
|
|
|
|
|
map(tag_g(t_t),
|
|
|
|
|
|Tag {tag, val}|
|
|
|
|
|
Tag {
|
|
|
|
|
tag: tag.to_string(),
|
2021-01-26 11:27:42 +01:00
|
|
|
|
val
|
2021-01-02 14:59:23 +01:00
|
|
|
|
})(s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn tag_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Tag<&'a str, O>>
|
|
|
|
|
where
|
|
|
|
|
P: Fn(&'a [u8]) -> IResult<&'a [u8], O>
|
|
|
|
|
{
|
|
|
|
|
move |s: &[u8]| {
|
|
|
|
|
let (s, tag) = sized('<', '|')(s)?;
|
|
|
|
|
let (s, val) = inner(s)?;
|
|
|
|
|
Ok((s, Tag {
|
|
|
|
|
tag: std::str::from_utf8(tag)
|
|
|
|
|
.map_err(|_| nom::Err::Failure((s, ErrorKind::Char)))?,
|
2021-01-26 11:27:42 +01:00
|
|
|
|
val: Box::new(val)
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// parse text scalar (`t5:hello,`)
|
|
|
|
|
fn text(s: &[u8]) -> IResult<&[u8], T> {
|
2021-02-01 09:16:14 +01:00
|
|
|
|
let (s, res) = text_g(s)?;
|
|
|
|
|
Ok((s, T::Text(res.to_string())))
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-01 09:16:14 +01:00
|
|
|
|
fn text_g(s: &[u8]) -> IResult<&[u8], &str> {
|
|
|
|
|
let (s, res) = sized('t', ',')(s)?;
|
|
|
|
|
Ok((s,
|
|
|
|
|
std::str::from_utf8(res)
|
|
|
|
|
.map_err(|_| nom::Err::Failure((s, ErrorKind::Char)))?,
|
|
|
|
|
))
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn binary<'a>() -> impl Fn(&'a [u8]) -> IResult<&'a [u8], T> {
|
|
|
|
|
map(binary_g(), |b| T::Binary(b.to_owned()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn binary_g() -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> {
|
|
|
|
|
sized('b', ',')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn list_t(s: &[u8]) -> IResult<&[u8], Vec<T>> {
|
2021-02-06 20:31:56 +01:00
|
|
|
|
list_g(t_t)(s)
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-30 04:49:43 +02:00
|
|
|
|
/// Wrap the inner parser of an `many0`/`fold_many0`, so that the parser
|
|
|
|
|
/// is not called when the `s` is empty already, preventing it from
|
|
|
|
|
/// returning `Incomplete` on streaming parsing.
|
|
|
|
|
fn inner_no_empty_string<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O>
|
|
|
|
|
where
|
|
|
|
|
O: Clone,
|
|
|
|
|
P: Fn(&'a [u8]) -> IResult<&'a [u8], O>,
|
|
|
|
|
{
|
|
|
|
|
move |s: &'a [u8]| {
|
|
|
|
|
if s.is_empty() {
|
|
|
|
|
// This is a bit hacky, `many0` considers the inside done
|
|
|
|
|
// when a parser returns `Err::Error`, ignoring the actual error content
|
|
|
|
|
Err(nom::Err::Error((s, nom::error::ErrorKind::Many0)))
|
|
|
|
|
} else {
|
|
|
|
|
inner(s)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 20:31:56 +01:00
|
|
|
|
fn list_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<O>>
|
|
|
|
|
where
|
|
|
|
|
O: Clone,
|
2021-03-30 04:49:43 +02:00
|
|
|
|
P: Fn(&'a [u8]) -> IResult<&'a [u8], O>,
|
2021-02-06 20:31:56 +01:00
|
|
|
|
{
|
|
|
|
|
map_parser(
|
|
|
|
|
sized('[', ']'),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
nom::multi::many0(inner_no_empty_string(inner))
|
2021-02-06 20:31:56 +01:00
|
|
|
|
)
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-01-26 11:27:42 +01:00
|
|
|
|
fn record_t<'a>(s: &'a [u8]) -> IResult<&'a [u8], HashMap<String, T>> {
|
2021-01-02 14:59:23 +01:00
|
|
|
|
let (s, r) = record_g(t_t)(s)?;
|
|
|
|
|
Ok((s,
|
|
|
|
|
r.into_iter()
|
|
|
|
|
.map(|(k, v)| (k.to_string(), v))
|
|
|
|
|
.collect::<HashMap<_,_>>()))
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 22:33:39 +01:00
|
|
|
|
fn record_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], HashMap<&'a str, O>>
|
2021-01-02 14:59:23 +01:00
|
|
|
|
where
|
|
|
|
|
O: Clone,
|
|
|
|
|
P: Fn(&'a [u8]) -> IResult<&'a [u8], O>
|
|
|
|
|
{
|
2021-03-30 04:49:43 +02:00
|
|
|
|
move |s: &'a [u8]| {
|
|
|
|
|
let (s, map) = map_parser(
|
|
|
|
|
sized('{', '}'),
|
|
|
|
|
nom::multi::fold_many0(
|
|
|
|
|
inner_no_empty_string(tag_g(&inner)),
|
|
|
|
|
HashMap::new(),
|
|
|
|
|
|mut acc: HashMap<_,_>, Tag { tag, mut val }| {
|
|
|
|
|
// ignore duplicated tag names that appear later
|
|
|
|
|
// according to netencode spec
|
|
|
|
|
if ! acc.contains_key(tag) {
|
|
|
|
|
acc.insert(tag, *val);
|
|
|
|
|
}
|
|
|
|
|
acc
|
2021-02-06 22:33:39 +01:00
|
|
|
|
}
|
2021-03-30 04:49:43 +02:00
|
|
|
|
)
|
|
|
|
|
)(s)?;
|
|
|
|
|
if map.is_empty() {
|
|
|
|
|
// records must not be empty, according to the spec
|
|
|
|
|
Err(nom::Err::Failure((s,nom::error::ErrorKind::Many1)))
|
|
|
|
|
} else {
|
|
|
|
|
Ok((s, map))
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-02 14:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn u_u(s: &[u8]) -> IResult<&[u8], U> {
|
|
|
|
|
alt((
|
2021-02-01 09:16:14 +01:00
|
|
|
|
map(text_g, U::Text),
|
2021-01-02 14:59:23 +01:00
|
|
|
|
map(binary_g(), U::Binary),
|
|
|
|
|
map(unit_t, |()| U::Unit),
|
2021-01-26 11:27:42 +01:00
|
|
|
|
map(tag_g(u_u), |t| U::Sum(t)),
|
2021-02-06 20:31:56 +01:00
|
|
|
|
map(list_g(u_u), U::List),
|
2021-01-02 14:59:23 +01:00
|
|
|
|
map(record_g(u_u), U::Record),
|
|
|
|
|
|
|
|
|
|
map(bool_t(), |u| U::N1(u)),
|
|
|
|
|
map(uint_t("n3"), |u| U::N3(u)),
|
|
|
|
|
map(uint_t("n6"), |u| U::N6(u)),
|
|
|
|
|
map(uint_t("n7"), |u| U::N7(u)),
|
|
|
|
|
map(int_t("i3"), |u| U::I3(u)),
|
|
|
|
|
map(int_t("i6"), |u| U::I6(u)),
|
|
|
|
|
map(int_t("i7"), |u| U::I7(u)),
|
|
|
|
|
|
|
|
|
|
// less common
|
|
|
|
|
map(uint_t("n2"), |u| U::N3(u)),
|
|
|
|
|
map(uint_t("n4"), |u| U::N6(u)),
|
|
|
|
|
map(uint_t("n5"), |u| U::N6(u)),
|
|
|
|
|
map(int_t("i1"), |u| U::I3(u)),
|
|
|
|
|
map(int_t("i2"), |u| U::I3(u)),
|
|
|
|
|
map(int_t("i4"), |u| U::I6(u)),
|
|
|
|
|
map(int_t("i5"), |u| U::I6(u)),
|
|
|
|
|
// TODO: 8, 9 not supported
|
|
|
|
|
))(s)
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-02 17:08:27 +01:00
|
|
|
|
pub fn t_t(s: &[u8]) -> IResult<&[u8], T> {
|
2021-01-02 14:59:23 +01:00
|
|
|
|
alt((
|
|
|
|
|
text,
|
|
|
|
|
binary(),
|
|
|
|
|
map(unit_t, |_| T::Unit),
|
|
|
|
|
map(tag_t, |t| T::Sum(t)),
|
2021-01-26 11:27:42 +01:00
|
|
|
|
map(list_t, |l| T::List(l)),
|
2021-01-02 14:59:23 +01:00
|
|
|
|
map(record_t, |p| T::Record(p)),
|
|
|
|
|
|
|
|
|
|
map(bool_t(), |u| T::N1(u)),
|
|
|
|
|
// 8, 64 and 128 bit
|
|
|
|
|
map(uint_t("n3"), |u| T::N3(u)),
|
|
|
|
|
map(uint_t("n6"), |u| T::N6(u)),
|
|
|
|
|
map(uint_t("n7"), |u| T::N7(u)),
|
|
|
|
|
map(int_t("i3"), |u| T::I3(u)),
|
|
|
|
|
map(int_t("i6"), |u| T::I6(u)),
|
|
|
|
|
map(int_t("i7"), |u| T::I7(u)),
|
|
|
|
|
|
|
|
|
|
// less common
|
|
|
|
|
map(uint_t("n2"), |u| T::N3(u)),
|
|
|
|
|
map(uint_t("n4"), |u| T::N6(u)),
|
|
|
|
|
map(uint_t("n5"), |u| T::N6(u)),
|
|
|
|
|
map(int_t("i1"), |u| T::I3(u)),
|
|
|
|
|
map(int_t("i2"), |u| T::I3(u)),
|
|
|
|
|
map(int_t("i4"), |u| T::I6(u)),
|
|
|
|
|
map(int_t("i5"), |u| T::I6(u)),
|
|
|
|
|
// TODO: 8, 9 not supported
|
|
|
|
|
))(s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parse_unit_t() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
unit_t("u,".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), ()))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parse_bool_t() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
bool_t()("n1:0,".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), false))
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
bool_t()("n1:1,".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), true))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parse_usize_t() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
usize_t("32foo".as_bytes()),
|
|
|
|
|
Ok(("foo".as_bytes(), 32))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parse_int_t() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
uint_t::<u8>("n3")("n3:42,abc".as_bytes()),
|
|
|
|
|
Ok(("abc".as_bytes(), 42))
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
uint_t::<u8>("n3")("n3:1024,abc".as_bytes()),
|
|
|
|
|
Err(nom::Err::Error(("1024,abc".as_bytes(), nom::error::ErrorKind::MapRes)))
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
int_t::<i64>("i6")("i6:-23,abc".as_bytes()),
|
|
|
|
|
Ok(("abc".as_bytes(), -23))
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
int_t::<i128>("i3")("i3:0,:abc".as_bytes()),
|
|
|
|
|
Ok((":abc".as_bytes(), 0))
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
uint_t::<u8>("n7")("n7:09,".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), 9))
|
|
|
|
|
);
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
// length("c"),
|
|
|
|
|
// Err(nom::Err::Error(("c", nom::error::ErrorKind::Digit)))
|
|
|
|
|
// );
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
// length(":"),
|
|
|
|
|
// Err(nom::Err::Error((":", nom::error::ErrorKind::Digit)))
|
|
|
|
|
// );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parse_text() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
text("t5:hello,".as_bytes()),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
Ok(("".as_bytes(), T::Text("hello".to_owned()))),
|
|
|
|
|
"{}", r"t5:hello,"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
2021-03-30 04:49:43 +02:00
|
|
|
|
text("t4:fo".as_bytes()),
|
|
|
|
|
// The content of the text should be 4 long
|
|
|
|
|
Err(nom::Err::Incomplete(nom::Needed::Size(4))),
|
|
|
|
|
"{}", r"t4:fo,"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
text("t9:今日は,".as_bytes()),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
Ok(("".as_bytes(), T::Text("今日は".to_owned()))),
|
|
|
|
|
"{}", r"t9:今日は,"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parse_binary() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
binary()("b5:hello,".as_bytes()),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
Ok(("".as_bytes(), T::Binary(Vec::from("hello".to_owned())))),
|
|
|
|
|
"{}", r"b5:hello,"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
2021-03-30 04:49:43 +02:00
|
|
|
|
binary()("b4:fo".as_bytes()),
|
|
|
|
|
// The content of the byte should be 4 long
|
|
|
|
|
Err(nom::Err::Incomplete(nom::Needed::Size(4))),
|
|
|
|
|
"{}", r"b4:fo,"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
2021-03-30 04:49:43 +02:00
|
|
|
|
assert_eq!(
|
|
|
|
|
binary()("b4:foob".as_bytes()),
|
|
|
|
|
// The content is 4 bytes now, but the finishing , is missing
|
|
|
|
|
Err(nom::Err::Incomplete(nom::Needed::Size(1))),
|
|
|
|
|
"{}", r"b4:fo,"
|
|
|
|
|
);
|
2021-01-02 14:59:23 +01:00
|
|
|
|
assert_eq!(
|
|
|
|
|
binary()("b9:今日は,".as_bytes()),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
Ok(("".as_bytes(), T::Binary(Vec::from("今日は".as_bytes())))),
|
|
|
|
|
"{}", r"b9:今日は,"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_list() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
list_t("[0:]".as_bytes()),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
Ok(("".as_bytes(), vec![])),
|
|
|
|
|
"{}", r"[0:]"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
list_t("[6:u,u,u,]".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), vec![
|
|
|
|
|
T::Unit,
|
|
|
|
|
T::Unit,
|
|
|
|
|
T::Unit,
|
2021-03-30 04:49:43 +02:00
|
|
|
|
])),
|
|
|
|
|
"{}", r"[6:u,u,u,]"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
list_t("[15:u,[7:t3:foo,]u,]".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), vec![
|
|
|
|
|
T::Unit,
|
2021-01-26 11:27:42 +01:00
|
|
|
|
T::List(vec![T::Text("foo".to_owned())]),
|
2021-01-02 14:59:23 +01:00
|
|
|
|
T::Unit,
|
2021-03-30 04:49:43 +02:00
|
|
|
|
])),
|
|
|
|
|
"{}", r"[15:u,[7:t3:foo,]u,]"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_record() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
record_t("{21:<1:a|u,<1:b|u,<1:c|u,}".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), vec![
|
2021-01-26 11:27:42 +01:00
|
|
|
|
("a".to_owned(), T::Unit),
|
|
|
|
|
("b".to_owned(), T::Unit),
|
|
|
|
|
("c".to_owned(), T::Unit),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
].into_iter().collect::<HashMap<String, T>>())),
|
|
|
|
|
"{}", r"{21:<1:a|u,<1:b|u,<1:c|u,}"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
// duplicated keys are ignored (first is taken)
|
|
|
|
|
assert_eq!(
|
|
|
|
|
record_t("{25:<1:a|u,<1:b|u,<1:a|i1:-1,}".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), vec![
|
2021-01-26 11:27:42 +01:00
|
|
|
|
("a".to_owned(), T::Unit),
|
|
|
|
|
("b".to_owned(), T::Unit),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
].into_iter().collect::<HashMap<_,_>>())),
|
|
|
|
|
"{}", r"{25:<1:a|u,<1:b|u,<1:a|i1:-1,}"
|
|
|
|
|
);
|
|
|
|
|
// empty records are not allowed
|
|
|
|
|
assert_eq!(
|
|
|
|
|
record_t("{0:}".as_bytes()),
|
|
|
|
|
Err(nom::Err::Failure(("".as_bytes(), nom::error::ErrorKind::Many1))),
|
|
|
|
|
"{}", r"{0:}"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parse() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
t_t("n3:255,".as_bytes()),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
Ok(("".as_bytes(), T::N3(255))),
|
|
|
|
|
"{}", r"n3:255,"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
t_t("t6:halloo,".as_bytes()),
|
2021-03-30 04:49:43 +02:00
|
|
|
|
Ok(("".as_bytes(), T::Text("halloo".to_owned()))),
|
|
|
|
|
"{}", r"t6:halloo,"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
t_t("<3:foo|t6:halloo,".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), T::Sum (Tag {
|
|
|
|
|
tag: "foo".to_owned(),
|
|
|
|
|
val: Box::new(T::Text("halloo".to_owned()))
|
2021-03-30 04:49:43 +02:00
|
|
|
|
}))),
|
|
|
|
|
"{}", r"<3:foo|t6:halloo,"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
// { a: Unit
|
|
|
|
|
// , foo: List <A: Unit | B: List i3> }
|
|
|
|
|
assert_eq!(
|
|
|
|
|
t_t("{52:<1:a|u,<3:foo|[33:<1:A|u,<1:A|n1:1,<1:B|[7:i3:127,]]}".as_bytes()),
|
|
|
|
|
Ok(("".as_bytes(), T::Record(vec![
|
2021-01-26 11:27:42 +01:00
|
|
|
|
("a".to_owned(), T::Unit),
|
|
|
|
|
("foo".to_owned(), T::List(vec![
|
2021-01-02 14:59:23 +01:00
|
|
|
|
T::Sum(Tag { tag: "A".to_owned(), val: Box::new(T::Unit) }),
|
|
|
|
|
T::Sum(Tag { tag: "A".to_owned(), val: Box::new(T::N1(true)) }),
|
2021-02-06 16:37:14 +01:00
|
|
|
|
T::Sum(Tag { tag: "B".to_owned(), val: Box::new(T::List(vec![T::I3(127)])) }),
|
2021-01-26 11:27:42 +01:00
|
|
|
|
]))
|
2021-03-30 04:49:43 +02:00
|
|
|
|
].into_iter().collect::<HashMap<String, T>>()))),
|
|
|
|
|
"{}", r"{52:<1:a|u,<3:foo|[33:<1:A|u,<1:A|n1:1,<1:B|[7:i3:127,]]}"
|
2021-01-02 14:59:23 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-29 15:55:11 +01:00
|
|
|
|
|
|
|
|
|
pub mod dec {
|
|
|
|
|
use super::*;
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
|
|
pub struct DecodeError(pub String);
|
|
|
|
|
|
2021-02-06 22:51:29 +01:00
|
|
|
|
pub trait Decoder<'a> {
|
2021-01-29 15:55:11 +01:00
|
|
|
|
type A;
|
2021-02-07 19:06:51 +01:00
|
|
|
|
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError>;
|
2021-01-29 15:55:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-01 19:00:34 +02:00
|
|
|
|
/// Any netencode, as `T`.
|
2021-02-07 19:06:51 +01:00
|
|
|
|
#[derive(Clone, Copy)]
|
2021-02-07 09:16:28 +01:00
|
|
|
|
pub struct AnyT;
|
2021-08-01 19:00:34 +02:00
|
|
|
|
/// Any netencode, as `U`.
|
2021-02-07 19:06:51 +01:00
|
|
|
|
#[derive(Clone, Copy)]
|
2021-02-07 09:16:28 +01:00
|
|
|
|
pub struct AnyU;
|
|
|
|
|
|
2021-02-07 22:44:50 +01:00
|
|
|
|
impl<'a> Decoder<'a> for AnyT {
|
|
|
|
|
type A = T;
|
|
|
|
|
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
|
|
|
|
Ok(u.to_t())
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-07 09:16:28 +01:00
|
|
|
|
|
|
|
|
|
impl<'a> Decoder<'a> for AnyU {
|
|
|
|
|
type A = U<'a>;
|
2021-02-07 19:06:51 +01:00
|
|
|
|
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
2021-02-07 09:16:28 +01:00
|
|
|
|
Ok(u)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-01 19:00:34 +02:00
|
|
|
|
/// A text
|
2021-02-09 01:36:00 +01:00
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
|
pub struct Text;
|
2021-08-01 19:00:34 +02:00
|
|
|
|
|
|
|
|
|
/// A bytestring
|
2021-02-09 01:36:00 +01:00
|
|
|
|
// 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))),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-01 19:00:34 +02:00
|
|
|
|
/// Any scalar, converted to bytes.
|
2021-02-07 19:06:51 +01:00
|
|
|
|
#[derive(Clone, Copy)]
|
2021-01-29 15:55:11 +01:00
|
|
|
|
pub struct ScalarAsBytes;
|
|
|
|
|
|
2021-02-06 22:51:29 +01:00
|
|
|
|
impl<'a> Decoder<'a> for ScalarAsBytes {
|
2021-01-29 15:55:11 +01:00
|
|
|
|
type A = Vec<u8>;
|
2021-02-07 19:06:51 +01:00
|
|
|
|
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
2021-02-06 22:51:29 +01:00
|
|
|
|
match u {
|
|
|
|
|
U::N3(u) => Ok(format!("{}", u).into_bytes()),
|
|
|
|
|
U::N6(u) => Ok(format!("{}", u).into_bytes()),
|
|
|
|
|
U::N7(u) => Ok(format!("{}", u).into_bytes()),
|
|
|
|
|
U::I3(i) => Ok(format!("{}", i).into_bytes()),
|
|
|
|
|
U::I6(i) => Ok(format!("{}", i).into_bytes()),
|
|
|
|
|
U::I7(i) => Ok(format!("{}", i).into_bytes()),
|
|
|
|
|
U::Text(t) => Ok(t.as_bytes().to_owned()),
|
|
|
|
|
U::Binary(b) => Ok(b.to_owned()),
|
2021-01-29 15:55:11 +01:00
|
|
|
|
o => Err(DecodeError(format!("Cannot decode {:?} into scalar", o))),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-01 19:00:34 +02:00
|
|
|
|
/// A map of Ts (TODO: rename to map)
|
2021-02-07 19:06:51 +01:00
|
|
|
|
#[derive(Clone, Copy)]
|
2021-01-29 15:55:11 +01:00
|
|
|
|
pub struct Record<T>(pub T);
|
|
|
|
|
|
2021-02-09 01:36:00 +01:00
|
|
|
|
impl<'a, Inner> Decoder<'a> for Record<Inner>
|
|
|
|
|
where Inner: Decoder<'a>
|
|
|
|
|
{
|
2021-02-06 22:51:29 +01:00
|
|
|
|
type A = HashMap<&'a str, Inner::A>;
|
2021-02-07 19:06:51 +01:00
|
|
|
|
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
2021-02-06 22:51:29 +01:00
|
|
|
|
match u {
|
|
|
|
|
U::Record(map) =>
|
2021-01-29 15:55:11 +01:00
|
|
|
|
map.into_iter()
|
2021-02-07 19:06:51 +01:00
|
|
|
|
.map(|(k, v)| self.0.dec(v).map(|v2| (k, v2)))
|
2021-01-29 15:55:11 +01:00
|
|
|
|
.collect::<Result<Self::A, _>>(),
|
|
|
|
|
o => Err(DecodeError(format!("Cannot decode {:?} into record", o)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-07 09:16:28 +01:00
|
|
|
|
|
2021-08-01 19:00:34 +02:00
|
|
|
|
/// Assume a record and project out the field with the given name and type.
|
2021-02-07 19:06:51 +01:00
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
|
pub struct RecordDot<'a, T> {
|
2021-02-09 01:36:00 +01:00
|
|
|
|
pub field: &'a str,
|
|
|
|
|
pub inner: T
|
2021-02-07 19:06:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-09 01:36:00 +01:00
|
|
|
|
impl <'a, Inner> Decoder<'a> for RecordDot<'_, Inner>
|
|
|
|
|
where Inner: Decoder<'a> + Clone
|
|
|
|
|
{
|
2021-02-07 19:06:51 +01:00
|
|
|
|
type A = Inner::A;
|
|
|
|
|
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
2021-02-09 01:36:00 +01:00
|
|
|
|
match Record(self.inner.clone()).dec(u) {
|
2021-02-07 19:06:51 +01:00
|
|
|
|
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),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-01 19:00:34 +02:00
|
|
|
|
/// Equals one of the listed `A`s exactly, after decoding.
|
2021-02-09 01:36:00 +01:00
|
|
|
|
#[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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-01 19:00:34 +02:00
|
|
|
|
/// Try decoding as `T`.
|
2021-02-13 14:23:29 +01:00
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct Try<T>(pub T);
|
|
|
|
|
|
|
|
|
|
impl <'a, Inner> Decoder<'a> for Try<Inner>
|
|
|
|
|
where Inner: Decoder<'a>
|
|
|
|
|
{
|
|
|
|
|
type A = Option<Inner::A>;
|
|
|
|
|
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
|
|
|
|
match self.0.dec(u) {
|
|
|
|
|
Ok(inner) => Ok(Some(inner)),
|
|
|
|
|
Err(err) => Ok(None)
|
|
|
|
|
}
|
2021-02-07 09:16:28 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-13 14:23:29 +01:00
|
|
|
|
|
2021-01-29 15:55:11 +01:00
|
|
|
|
}
|