use std::borrow::Cow;
use std::fmt;
use std::fmt::Debug;
use std::fmt::Display;
use std::num::ParseIntError;
use nom::branch::alt;
use nom::bytes::complete::escaped_transform;
use nom::bytes::complete::is_not;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_while;
use nom::bytes::complete::take_while1;
use nom::character::complete::alphanumeric1;
use nom::character::complete::anychar;
use nom::character::complete::char;
use nom::character::complete::none_of;
use nom::combinator::map;
use nom::combinator::map_res;
use nom::combinator::opt;
use nom::combinator::peek;
use nom::combinator::recognize;
use nom::combinator::value;
use nom::combinator::verify;
use nom::sequence::delimited;
use nom::sequence::pair;
use nom::sequence::tuple;
use nom::AsChar;
use nom::Finish;
use nom::IResult;
use num_traits::Num;
use remain::sorted;
use serde::de;
use serde::Deserialize;
use serde::Deserializer;
use thiserror::Error;
#[derive(Debug, Error, PartialEq, Eq)]
#[sorted]
#[non_exhaustive]
#[allow(missing_docs)]
pub enum ErrorKind {
#[error("unexpected end of input")]
Eof,
#[error("expected a boolean")]
ExpectedBoolean,
#[error("expected ']'")]
ExpectedCloseBracket,
#[error("expected ','")]
ExpectedComma,
#[error("expected '='")]
ExpectedEqual,
#[error("expected an identifier")]
ExpectedIdentifier,
#[error("expected '['")]
ExpectedOpenBracket,
#[error("expected a string")]
ExpectedString,
#[error("\" and ' can only be used in quoted strings")]
InvalidCharInString,
#[error("invalid characters for number or number does not fit into its destination type")]
InvalidNumber,
#[error("serde error: {0}")]
SerdeError(String),
#[error("remaining characters in input")]
TrailingCharacters,
}
#[derive(Debug, Error, PartialEq, Eq)]
pub struct ParseError {
pub kind: ErrorKind,
pub pos: usize,
}
impl Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
ErrorKind::SerdeError(s) => write!(f, "{}", s),
_ => write!(f, "{} at position {}", self.kind, self.pos),
}
}
}
impl de::Error for ParseError {
fn custom<T>(msg: T) -> Self
where
T: fmt::Display,
{
Self {
kind: ErrorKind::SerdeError(msg.to_string()),
pos: 0,
}
}
}
type Result<T> = std::result::Result<T, ParseError>;
fn is_separator(c: Option<char>) -> bool {
matches!(c, Some(',') | Some(']') | None)
}
fn any_separator(s: &str) -> IResult<&str, Option<char>> {
let next_char = s.chars().next();
if is_separator(next_char) {
let pos = if let Some(c) = next_char {
c.len_utf8()
} else {
0
};
Ok((&s[pos..], next_char))
} else {
Err(nom::Err::Error(nom::error::Error::new(
s,
nom::error::ErrorKind::Char,
)))
}
}
fn any_string(s: &str) -> IResult<&str, Cow<str>> {
let double_quoted = delimited(
char('"'),
alt((
map(
escaped_transform(
none_of(r#"\""#),
'\\',
alt((value("\"", char('"')), value("\\", char('\\')))),
),
Cow::Owned,
),
map(tag(""), Cow::Borrowed),
)),
char('"'),
);
let single_quoted = map(
delimited(char('\''), alt((is_not(r#"'"#), tag(""))), char('\'')),
Cow::Borrowed,
);
let unquoted = map(
take_while1(|c: char| c != ',' && c != '"' && c != '\'' && c != '[' && c != ']'),
Cow::Borrowed,
);
alt((double_quoted, single_quoted, unquoted))(s)
}
fn any_number<T>(s: &str) -> IResult<&str, T>
where
T: Num<FromStrRadixErr = ParseIntError>,
{
fn parse_number(s: &str) -> IResult<&str, (Cow<str>, u32)> {
let sign = char('-');
let radix = alt((
value(16, tag("0x")),
value(8, tag("0o")),
value(2, tag("0b")),
));
let separator = peek(any_separator);
map(
tuple((opt(sign), opt(radix), alphanumeric1, separator)),
|(sign, radix, number, _)| {
let num_string = if let Some(sign) = sign {
Cow::Owned(sign.to_string() + number)
} else {
Cow::Borrowed(number)
};
(num_string, radix.unwrap_or(10))
},
)(s)
}
map_res(parse_number, |(num_string, radix)| {
T::from_str_radix(&num_string, radix)
})(s)
}
fn any_bool(s: &str) -> IResult<&str, bool> {
let mut boolean = alt((value(true, tag("true")), value(false, tag("false"))));
boolean(s)
}
fn any_identifier(s: &str) -> IResult<&str, &str> {
let mut ident = recognize(pair(
verify(anychar, |&c| c.is_alphanum() || c == '_'),
take_while(|c: char| c.is_alphanum() || c == '_' || c == '-'),
));
ident(s)
}
pub struct KeyValueDeserializer<'de> {
original_input: &'de str,
input: &'de str,
next_identifier: Option<&'de str>,
has_equal: bool,
top_struct_parsed: bool,
}
impl<'de> From<&'de str> for KeyValueDeserializer<'de> {
fn from(input: &'de str) -> Self {
Self {
original_input: input,
input,
next_identifier: None,
has_equal: false,
top_struct_parsed: false,
}
}
}
impl<'de> KeyValueDeserializer<'de> {
pub fn error_here(&self, kind: ErrorKind) -> ParseError {
ParseError {
kind,
pos: self.original_input.len() - self.input.len(),
}
}
pub fn peek_char(&self) -> Option<char> {
self.input.chars().next()
}
pub fn skip_char(&mut self) {
let _ = self.next_char();
}
pub fn next_char(&mut self) -> Option<char> {
let c = self.peek_char()?;
self.input = &self.input[c.len_utf8()..];
Some(c)
}
fn confirm_separator(&mut self) -> Result<()> {
match self.peek_char() {
Some(',') => {
let _ = self.next_char();
Ok(())
}
Some(']') | None => Ok(()),
Some(_) => Err(self.error_here(ErrorKind::ExpectedComma)),
}
}
pub fn parse_identifier(&mut self) -> Result<&'de str> {
let (remainder, res) = any_identifier(self.input)
.finish()
.map_err(|_| self.error_here(ErrorKind::ExpectedIdentifier))?;
self.input = remainder;
Ok(res)
}
pub fn parse_string(&mut self) -> Result<Cow<'de, str>> {
let (remainder, res) =
any_string(self.input)
.finish()
.map_err(|e: nom::error::Error<_>| {
self.input = e.input;
self.error_here(ErrorKind::ExpectedString)
})?;
self.input = remainder;
if is_separator(self.peek_char()) {
Ok(res)
} else {
Err(self.error_here(ErrorKind::InvalidCharInString))
}
}
pub fn parse_bool(&mut self) -> Result<bool> {
let (remainder, res) =
any_bool(self.input)
.finish()
.map_err(|e: nom::error::Error<_>| {
self.input = e.input;
self.error_here(ErrorKind::ExpectedBoolean)
})?;
self.input = remainder;
Ok(res)
}
pub fn parse_number<T>(&mut self) -> Result<T>
where
T: Num<FromStrRadixErr = ParseIntError>,
{
let (remainder, val) = any_number(self.input)
.finish()
.map_err(|_| self.error_here(ErrorKind::InvalidNumber))?;
self.input = remainder;
Ok(val)
}
pub fn finish(self) -> Result<()> {
if self.input.is_empty() {
Ok(())
} else {
Err(self.error_here(ErrorKind::TrailingCharacters))
}
}
}
impl<'de> de::MapAccess<'de> for KeyValueDeserializer<'de> {
type Error = ParseError;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: de::DeserializeSeed<'de>,
{
match self.peek_char() {
None | Some(']') => return Ok(None),
_ => (),
}
self.has_equal = false;
let had_implicit_identifier = self.next_identifier.is_some();
let val = seed.deserialize(&mut *self).map(Some)?;
if had_implicit_identifier {
self.has_equal = true;
return Ok(val);
}
match self.peek_char() {
Some('=') => {
self.skip_char();
self.has_equal = true;
Ok(val)
}
c if is_separator(c) => Ok(val),
_ => Err(self.error_here(ErrorKind::ExpectedEqual)),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: de::DeserializeSeed<'de>,
{
let val = seed.deserialize(&mut *self)?;
self.confirm_separator()?;
Ok(val)
}
}
struct EmptyMapAccess;
impl<'de> de::MapAccess<'de> for EmptyMapAccess {
type Error = ParseError;
fn next_key_seed<K>(&mut self, _seed: K) -> Result<Option<K::Value>>
where
K: de::DeserializeSeed<'de>,
{
Ok(None)
}
fn next_value_seed<V>(&mut self, _seed: V) -> Result<V::Value>
where
V: de::DeserializeSeed<'de>,
{
unreachable!()
}
}
impl<'a, 'de> de::EnumAccess<'de> for &'a mut KeyValueDeserializer<'de> {
type Error = ParseError;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
where
V: de::DeserializeSeed<'de>,
{
let val = seed.deserialize(&mut *self)?;
Ok((val, self))
}
}
impl<'a, 'de> de::VariantAccess<'de> for &'a mut KeyValueDeserializer<'de> {
type Error = ParseError;
fn unit_variant(self) -> Result<()> {
Ok(())
}
fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value>
where
T: de::DeserializeSeed<'de>,
{
unimplemented!()
}
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
self.deserialize_tuple(len, visitor)
}
fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
if self.peek_char() == Some('[') {
self.next_char();
let val = self.deserialize_map(visitor)?;
if self.peek_char() != Some(']') {
Err(self.error_here(ErrorKind::ExpectedCloseBracket))
} else {
self.next_char();
Ok(val)
}
} else {
visitor
.visit_map(EmptyMapAccess)
.map_err(|_| self.error_here(ErrorKind::ExpectedOpenBracket))
}
}
}
impl<'de> de::SeqAccess<'de> for KeyValueDeserializer<'de> {
type Error = ParseError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: de::DeserializeSeed<'de>,
{
if self.peek_char() == Some(']') {
return Ok(None);
}
let value = seed.deserialize(&mut *self)?;
self.confirm_separator()?;
Ok(Some(value))
}
}
impl<'de, 'a> de::Deserializer<'de> for &'a mut KeyValueDeserializer<'de> {
type Error = ParseError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
match self.peek_char() {
c if is_separator(c) => return self.deserialize_bool(visitor),
Some('[') => return self.deserialize_seq(visitor),
_ => (),
}
if any_number::<i64>(self.input).is_ok() {
self.deserialize_i64(visitor)
} else if any_number::<u64>(self.input).is_ok() {
self.deserialize_u64(visitor)
} else if any_bool(self.input).is_ok() {
self.deserialize_bool(visitor)
} else {
self.deserialize_str(visitor)
}
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
let val = if self.has_equal {
self.parse_bool()?
} else {
true
};
visitor.visit_bool(val)
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i8(self.parse_number()?)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i16(self.parse_number()?)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i32(self.parse_number()?)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i64(self.parse_number()?)
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u8(self.parse_number()?)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u16(self.parse_number()?)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u32(self.parse_number()?)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u64(self.parse_number()?)
}
fn deserialize_f32<V>(self, _visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
unimplemented!()
}
fn deserialize_f64<V>(self, _visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
unimplemented!()
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_char(
self.next_char()
.ok_or_else(|| self.error_here(ErrorKind::Eof))?,
)
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
match self.parse_string()? {
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
Cow::Owned(s) => visitor.visit_string(s),
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
unimplemented!()
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_bytes(visitor)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_some(self)
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
if self.peek_char() == Some('[') {
self.next_char();
let val = visitor.visit_seq(&mut *self)?;
if self.peek_char() != Some(']') {
Err(self.error_here(ErrorKind::ExpectedCloseBracket))
} else {
self.next_char();
Ok(val)
}
} else {
visitor
.visit_map(EmptyMapAccess)
.map_err(|_| self.error_here(ErrorKind::ExpectedOpenBracket))
}
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: usize,
_visitor: V,
) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
unimplemented!()
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
self.top_struct_parsed = true;
visitor.visit_map(self)
}
fn deserialize_struct<V>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
let top_struct_parsed = std::mem::replace(&mut self.top_struct_parsed, true);
if top_struct_parsed {
if self.peek_char() == Some('[') {
self.next_char();
} else {
return visitor
.visit_map(EmptyMapAccess)
.map_err(|_| self.error_here(ErrorKind::ExpectedOpenBracket));
}
}
self.next_identifier = match any_identifier(self.input) {
Ok((_, s)) => match self.input.chars().nth(s.chars().count()) {
Some('=') => None,
_ => {
if fields.contains(&s) {
None
} else {
fields.first().copied()
}
}
},
Err(_) => fields.first().copied(),
};
let ret = visitor.visit_map(&mut *self)?;
if top_struct_parsed {
if self.peek_char() == Some(']') {
self.next_char();
} else {
return Err(self.error_here(ErrorKind::ExpectedCloseBracket));
}
}
Ok(ret)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_enum(self)
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
let identifier = self
.next_identifier
.take()
.map_or_else(|| self.parse_identifier(), Ok)?;
visitor.visit_borrowed_str(identifier)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_any(visitor)
}
}
pub fn from_key_values<'a, T>(input: &'a str) -> Result<T>
where
T: Deserialize<'a>,
{
let mut deserializer = KeyValueDeserializer::from(input);
let ret = T::deserialize(&mut deserializer)?;
deserializer.finish()?;
Ok(ret)
}
#[cfg(test)]
mod tests {
use std::collections::BTreeSet;
use std::path::PathBuf;
use super::*;
#[derive(Deserialize, PartialEq, Debug)]
struct SingleStruct<T> {
m: T,
}
#[test]
fn nom_any_separator() {
let test_str = ",foo";
assert_eq!(any_separator(test_str), Ok((&test_str[1..], Some(','))));
let test_str = "]bar";
assert_eq!(any_separator(test_str), Ok((&test_str[1..], Some(']'))));
let test_str = "";
assert_eq!(any_separator(test_str), Ok((test_str, None)));
let test_str = "something,anything";
assert_eq!(
any_separator(test_str),
Err(nom::Err::Error(nom::error::Error::new(
test_str,
nom::error::ErrorKind::Char
)))
);
}
#[test]
fn deserialize_number() {
let res = from_key_values::<SingleStruct<usize>>("m=54").unwrap();
assert_eq!(res.m, 54);
let res = from_key_values::<SingleStruct<isize>>("m=-54").unwrap();
assert_eq!(res.m, -54);
let res = from_key_values::<SingleStruct<u32>>("m=-54").unwrap_err();
assert_eq!(
res,
ParseError {
kind: ErrorKind::InvalidNumber,
pos: 2
}
);
let val = i32::MAX as u32 + 1;
let res = from_key_values::<SingleStruct<i32>>(&format!("m={}", val)).unwrap_err();
assert_eq!(
res,
ParseError {
kind: ErrorKind::InvalidNumber,
pos: 2
}
);
let res = from_key_values::<SingleStruct<usize>>("m=test").unwrap_err();
assert_eq!(
res,
ParseError {
kind: ErrorKind::InvalidNumber,
pos: 2,
}
);
let res: SingleStruct<usize> =
from_key_values::<SingleStruct<usize>>("m=0x1234abcd").unwrap();
assert_eq!(res.m, 0x1234abcd);
let res: SingleStruct<isize> =
from_key_values::<SingleStruct<isize>>("m=-0x1234abcd").unwrap();
assert_eq!(res.m, -0x1234abcd);
let res: ParseError = from_key_values::<SingleStruct<usize>>("m=0xg").unwrap_err();
assert_eq!(
res,
ParseError {
kind: ErrorKind::InvalidNumber,
pos: 2,
}
);
let res: SingleStruct<usize> = from_key_values::<SingleStruct<usize>>("m=0o755").unwrap();
assert_eq!(res.m, 0o755);
let res: SingleStruct<isize> = from_key_values::<SingleStruct<isize>>("m=-0o755").unwrap();
assert_eq!(res.m, -0o755);
let res: ParseError = from_key_values::<SingleStruct<usize>>("m=0o8").unwrap_err();
assert_eq!(
res,
ParseError {
kind: ErrorKind::InvalidNumber,
pos: 2,
}
);
let res: SingleStruct<usize> = from_key_values::<SingleStruct<usize>>("m=0b1100").unwrap();
assert_eq!(res.m, 0b1100);
let res: SingleStruct<isize> = from_key_values::<SingleStruct<isize>>("m=-0b1100").unwrap();
assert_eq!(res.m, -0b1100);
let res: ParseError = from_key_values::<SingleStruct<usize>>("m=0b2").unwrap_err();
assert_eq!(
res,
ParseError {
kind: ErrorKind::InvalidNumber,
pos: 2,
}
);
}
#[test]
fn deserialize_string() {
let kv = "m=John";
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, "John".to_string());
let kv = "m=John Doe";
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, "John Doe".to_string());
let kv = "m=";
let err = from_key_values::<SingleStruct<String>>(kv).unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::ExpectedString,
pos: 2
}
);
let kv = r#"m="John Doe""#;
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, "John Doe".to_string());
let kv = r#"m='John Doe'"#;
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, "John Doe".to_string());
let kv = r#"m="""#;
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, "".to_string());
let kv = r#"m=''"#;
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, "".to_string());
let kv = r#"m="val = [10, 20, 'a']""#;
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, r#"val = [10, 20, 'a']"#.to_string());
let kv = r#"m=val="a""#;
let err = from_key_values::<SingleStruct<String>>(kv).unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::InvalidCharInString,
pos: 6
}
);
let kv = r#"m=val='a'"#;
let err = from_key_values::<SingleStruct<String>>(kv).unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::InvalidCharInString,
pos: 6
}
);
let kv = r#"m=val=[a]"#;
let err = from_key_values::<SingleStruct<String>>(kv).unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::InvalidCharInString,
pos: 6
}
);
let kv = "m=10";
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, "10".to_string());
let kv = "m=false";
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, "false".to_string());
let kv = r#"m="Escaped \" quote""#;
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, r#"Escaped " quote"#.to_string());
let kv = r#"m="Escaped slash\\""#;
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, r"Escaped slash\".to_string());
let kv = r#"m='Escaped \" quote'"#;
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, r#"Escaped \" quote"#.to_string());
let kv = r"m='Escaped slash\\'";
let res = from_key_values::<SingleStruct<String>>(kv).unwrap();
assert_eq!(res.m, r"Escaped slash\\".to_string());
}
#[test]
fn deserialize_unit() {
from_key_values::<SingleStruct<()>>("m").unwrap();
from_key_values::<SingleStruct<()>>("m=").unwrap();
from_key_values::<SingleStruct<()>>("").unwrap_err();
from_key_values::<SingleStruct<()>>("p").unwrap_err();
from_key_values::<SingleStruct<()>>("m=10").unwrap_err();
}
#[test]
fn deserialize_bool() {
let res = from_key_values::<SingleStruct<bool>>("m=true").unwrap();
assert!(res.m);
let res = from_key_values::<SingleStruct<bool>>("m=false").unwrap();
assert!(!res.m);
let res = from_key_values::<SingleStruct<bool>>("m").unwrap();
assert!(res.m);
let res = from_key_values::<SingleStruct<bool>>("m=10").unwrap_err();
assert_eq!(
res,
ParseError {
kind: ErrorKind::ExpectedBoolean,
pos: 2,
}
);
let res = from_key_values::<SingleStruct<bool>>("m=").unwrap_err();
assert_eq!(
res,
ParseError {
kind: ErrorKind::ExpectedBoolean,
pos: 2,
}
);
}
#[test]
fn deserialize_complex_struct() {
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
num: usize,
path: PathBuf,
enable: bool,
}
let kv = "num=54,path=/dev/foomatic,enable=false";
let res = from_key_values::<TestStruct>(kv).unwrap();
assert_eq!(
res,
TestStruct {
num: 54,
path: "/dev/foomatic".into(),
enable: false,
}
);
let kv = "num=0x54,path=/dev/foomatic,enable=false";
let res = from_key_values::<TestStruct>(kv).unwrap();
assert_eq!(
res,
TestStruct {
num: 0x54,
path: "/dev/foomatic".into(),
enable: false,
}
);
let kv = "enable,path=/usr/lib/libossom.so.1,num=12";
let res = from_key_values::<TestStruct>(kv).unwrap();
assert_eq!(
res,
TestStruct {
num: 12,
path: "/usr/lib/libossom.so.1".into(),
enable: true,
}
);
let kv = "[enable,path=/usr/lib/libossom.so.1,num=12]";
assert!(from_key_values::<TestStruct>(kv).is_err());
}
#[test]
fn deserialize_unknown_field() {
#[derive(Deserialize, PartialEq, Debug)]
#[serde(deny_unknown_fields)]
struct TestStruct {
num: usize,
path: PathBuf,
enable: bool,
}
let kv = "enable,path=/usr/lib/libossom.so.1,num=12,foo=bar";
assert!(from_key_values::<TestStruct>(kv).is_err());
}
#[test]
fn deserialize_option() {
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
num: u32,
opt: Option<u32>,
}
let kv = "num=16,opt=12";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(
res,
TestStruct {
num: 16,
opt: Some(12),
}
);
let kv = "num=16";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(res, TestStruct { num: 16, opt: None });
let kv = "";
assert!(from_key_values::<TestStruct>(kv).is_err());
}
#[test]
fn deserialize_optional_struct_with_default() {
#[derive(Deserialize, PartialEq, Debug)]
struct DefaultStruct {
#[serde(default)]
param: u32,
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
flag: Option<DefaultStruct>,
}
let kv = "flag=[param=12]";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(
res,
TestStruct {
flag: Some(DefaultStruct { param: 12 })
}
);
let kv = "flag=[]";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(
res,
TestStruct {
flag: Some(DefaultStruct { param: 0 })
}
);
let kv = "flag=";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(
res,
TestStruct {
flag: Some(DefaultStruct { param: 0 })
}
);
let kv = "flag";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(
res,
TestStruct {
flag: Some(DefaultStruct { param: 0 })
}
);
let kv = "flag=[";
assert!(from_key_values::<TestStruct>(kv).is_err());
let kv = "flag=]";
assert!(from_key_values::<TestStruct>(kv).is_err());
}
#[test]
fn deserialize_optional_struct_within_flattened() {
#[derive(Deserialize, PartialEq, Debug)]
struct FlatStruct {
a: u32,
#[serde(default)]
b: String,
}
#[derive(Deserialize, PartialEq, Debug)]
struct DefaultStruct {
#[serde(default)]
param: u32,
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
#[serde(flatten)]
flat: FlatStruct,
flag: Option<DefaultStruct>,
}
let kv = "a=10,b=foomatic,flag=[param=24]";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(
res,
TestStruct {
flat: FlatStruct {
a: 10,
b: "foomatic".into(),
},
flag: Some(DefaultStruct { param: 24 })
}
);
let kv = "a=10,b=foomatic,flag";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(
res,
TestStruct {
flat: FlatStruct {
a: 10,
b: "foomatic".into(),
},
flag: Some(DefaultStruct { param: 0 })
}
);
let kv = "a=10,flag=[param=24]";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(
res,
TestStruct {
flat: FlatStruct {
a: 10,
b: Default::default(),
},
flag: Some(DefaultStruct { param: 24 })
}
);
let kv = "a=10";
let res: TestStruct = from_key_values(kv).unwrap();
assert_eq!(
res,
TestStruct {
flat: FlatStruct {
a: 10,
b: Default::default(),
},
flag: None,
}
);
let kv = "b=foomatic,flag=[param=24]";
assert!(from_key_values::<TestStruct>(kv).is_err());
let kv = "[a=10,b=foomatic,flag=[param=24]]";
assert!(from_key_values::<TestStruct>(kv).is_err());
}
#[test]
fn deserialize_enum() {
#[derive(Deserialize, PartialEq, Debug)]
enum TestEnum {
#[serde(rename = "first")]
FirstVariant,
#[serde(rename = "second")]
SecondVariant,
}
let res: TestEnum = from_key_values("first").unwrap();
assert_eq!(res, TestEnum::FirstVariant,);
let res: TestEnum = from_key_values("second").unwrap();
assert_eq!(res, TestEnum::SecondVariant,);
from_key_values::<TestEnum>("third").unwrap_err();
}
#[test]
fn deserialize_embedded_enum() {
#[derive(Deserialize, PartialEq, Debug)]
enum TestEnum {
#[serde(rename = "first")]
FirstVariant,
#[serde(rename = "second")]
SecondVariant,
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
variant: TestEnum,
#[serde(default)]
active: bool,
}
let res: TestStruct = from_key_values("variant=first").unwrap();
assert_eq!(
res,
TestStruct {
variant: TestEnum::FirstVariant,
active: false,
}
);
let res: TestStruct = from_key_values("variant=second,active=true").unwrap();
assert_eq!(
res,
TestStruct {
variant: TestEnum::SecondVariant,
active: true,
}
);
let res: TestStruct = from_key_values("active=true,variant=second").unwrap();
assert_eq!(
res,
TestStruct {
variant: TestEnum::SecondVariant,
active: true,
}
);
let res: TestStruct = from_key_values("active,variant=second").unwrap();
assert_eq!(
res,
TestStruct {
variant: TestEnum::SecondVariant,
active: true,
}
);
let res: TestStruct = from_key_values("active=false,variant=second").unwrap();
assert_eq!(
res,
TestStruct {
variant: TestEnum::SecondVariant,
active: false,
}
);
}
#[test]
fn deserialize_untagged_enum() {
#[derive(Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum TestEnum {
FirstVariant { first: u32 },
SecondVariant { second: bool },
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
#[serde(flatten)]
variant: TestEnum,
}
let res: TestStruct = from_key_values("first=10").unwrap();
assert_eq!(res.variant, TestEnum::FirstVariant { first: 10 });
let res: TestStruct = from_key_values("second=false").unwrap();
assert_eq!(res.variant, TestEnum::SecondVariant { second: false },);
let res: TestStruct = from_key_values("second").unwrap();
assert_eq!(res.variant, TestEnum::SecondVariant { second: true },);
from_key_values::<TestStruct>("third=10").unwrap_err();
from_key_values::<TestStruct>("first=some_string").unwrap_err();
from_key_values::<TestStruct>("second=10").unwrap_err();
}
#[test]
fn deserialize_first_arg_string() {
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
name: String,
num: u8,
}
let res: TestStruct = from_key_values("name=foo,num=12").unwrap();
assert_eq!(
res,
TestStruct {
name: "foo".into(),
num: 12,
}
);
let res: TestStruct = from_key_values("foo,num=12").unwrap();
assert_eq!(
res,
TestStruct {
name: "foo".into(),
num: 12,
}
);
}
#[test]
fn deserialize_first_arg_int() {
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
num: u8,
name: String,
}
let res: TestStruct = from_key_values("name=foo,num=12").unwrap();
assert_eq!(
res,
TestStruct {
num: 12,
name: "foo".into(),
}
);
let res: TestStruct = from_key_values("12,name=foo").unwrap();
assert_eq!(
res,
TestStruct {
num: 12,
name: "foo".into(),
}
);
}
#[test]
fn deserialize_tuple() {
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
size: (u32, u32),
}
let res: TestStruct = from_key_values("size=[320,200]").unwrap();
assert_eq!(res, TestStruct { size: (320, 200) });
let err = from_key_values::<TestStruct>("size=[320]").unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::SerdeError("invalid length 1, expected a tuple of size 2".into()),
pos: 0,
}
);
let err = from_key_values::<TestStruct>("size=[320,200,255]").unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::ExpectedCloseBracket,
pos: 14,
}
);
let err = from_key_values::<TestStruct>("size=[320,200").unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::ExpectedCloseBracket,
pos: 13,
}
);
}
#[test]
fn deserialize_vector() {
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
numbers: Vec<u32>,
}
let res: TestStruct = from_key_values("numbers=[1,2,4,8,16,32,64]").unwrap();
assert_eq!(
res,
TestStruct {
numbers: vec![1, 2, 4, 8, 16, 32, 64],
}
);
}
#[test]
fn deserialize_vector_of_strings() {
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
strs: Vec<String>,
}
let res: TestStruct =
from_key_values(r#"strs=[singleword,camel_cased,kebab-cased]"#).unwrap();
assert_eq!(
res,
TestStruct {
strs: vec![
"singleword".into(),
"camel_cased".into(),
"kebab-cased".into()
],
}
);
let res: TestStruct =
from_key_values(r#"strs=["first string","second string","third string"]"#).unwrap();
assert_eq!(
res,
TestStruct {
strs: vec![
"first string".into(),
"second string".into(),
"third string".into()
],
}
);
let res: TestStruct =
from_key_values(r#"strs=[unquoted,"quoted string",'quoted with escape "']"#).unwrap();
assert_eq!(
res,
TestStruct {
strs: vec![
"unquoted".into(),
"quoted string".into(),
"quoted with escape \"".into()
],
}
);
}
#[test]
fn deserialize_vector_of_structs() {
#[derive(Deserialize, PartialEq, Debug)]
#[serde(deny_unknown_fields)]
struct Display {
size: (u32, u32),
#[serde(default)]
disabled: bool,
}
#[derive(Deserialize, PartialEq, Debug)]
#[serde(deny_unknown_fields)]
struct TestStruct {
displays: Vec<Display>,
hostname: Option<String>,
}
let res: TestStruct = from_key_values("displays=[[size=[640,480]]]").unwrap();
assert_eq!(
res,
TestStruct {
displays: vec![Display {
size: (640, 480),
disabled: false,
}],
hostname: None,
}
);
let res: TestStruct =
from_key_values("hostname=crosmatic,displays=[[size=[800,600],disabled]]").unwrap();
assert_eq!(
res,
TestStruct {
displays: vec![Display {
size: (800, 600),
disabled: true,
}],
hostname: Some("crosmatic".to_string()),
}
);
let res: TestStruct =
from_key_values("displays=[[[640,480]],[[800,600],disabled]]").unwrap();
assert_eq!(
res,
TestStruct {
displays: vec![
Display {
size: (640, 480),
disabled: false,
},
Display {
size: (800, 600),
disabled: true,
}
],
hostname: None,
}
);
let res: TestStruct =
from_key_values("displays=[[[1024,768]],[size=[800,600],disabled]],hostname=crosmatic")
.unwrap();
assert_eq!(
res,
TestStruct {
displays: vec![
Display {
size: (1024, 768),
disabled: false,
},
Display {
size: (800, 600),
disabled: true,
}
],
hostname: Some("crosmatic".to_string()),
}
);
}
#[test]
fn deserialize_set() {
#[derive(Deserialize, PartialEq, Eq, Debug, PartialOrd, Ord)]
#[serde(rename_all = "kebab-case")]
enum Flags {
Awesome,
Fluffy,
Transparent,
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
flags: BTreeSet<Flags>,
}
let res: TestStruct = from_key_values("flags=[awesome,fluffy]").unwrap();
assert_eq!(
res,
TestStruct {
flags: BTreeSet::from([Flags::Awesome, Flags::Fluffy]),
}
);
let err = from_key_values::<TestStruct>("flags=[awesome,spiky]").unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::SerdeError(
"unknown variant `spiky`, expected one of `awesome`, `fluffy`, `transparent`"
.into()
),
pos: 0,
}
);
}
#[test]
fn deserialize_struct_and_tuple_enum() {
#[derive(Deserialize, PartialEq, Debug)]
#[serde(rename_all = "kebab-case")]
enum VideoMode {
Fullscreen,
WindowAsTuple(u32, u32),
WindowAsStruct { width: u32, height: u32 },
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
mode: VideoMode,
}
let res: TestStruct = from_key_values("mode=fullscreen").unwrap();
assert_eq!(
res,
TestStruct {
mode: VideoMode::Fullscreen
}
);
let res: TestStruct = from_key_values("mode=window-as-tuple[640,480]").unwrap();
assert_eq!(
res,
TestStruct {
mode: VideoMode::WindowAsTuple(640, 480),
}
);
let err = from_key_values::<TestStruct>("mode=window-as-tuple").unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::ExpectedOpenBracket,
pos: 20,
}
);
let res: TestStruct =
from_key_values("mode=window-as-struct[width=800,height=600]").unwrap();
assert_eq!(
res,
TestStruct {
mode: VideoMode::WindowAsStruct {
width: 800,
height: 600,
}
}
);
let err = from_key_values::<TestStruct>("mode=window-as-struct").unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::ExpectedOpenBracket,
pos: 21,
}
);
}
#[test]
fn deserialize_struct_enum_with_default() {
#[derive(Deserialize, PartialEq, Debug)]
#[serde(rename_all = "kebab-case")]
enum FlipMode {
Inactive,
Active {
#[serde(default)]
switch1: bool,
#[serde(default)]
switch2: bool,
},
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestStruct {
mode: FlipMode,
}
let res: TestStruct = from_key_values("mode=active[switch1=true]").unwrap();
assert_eq!(
res,
TestStruct {
mode: FlipMode::Active {
switch1: true,
switch2: false
}
}
);
let res: TestStruct = from_key_values("mode=active[switch1,switch2]").unwrap();
assert_eq!(
res,
TestStruct {
mode: FlipMode::Active {
switch1: true,
switch2: true
}
}
);
let res: TestStruct = from_key_values("mode=active[]").unwrap();
assert_eq!(
res,
TestStruct {
mode: FlipMode::Active {
switch1: false,
switch2: false
}
}
);
let res: TestStruct = from_key_values("mode=active").unwrap();
assert_eq!(
res,
TestStruct {
mode: FlipMode::Active {
switch1: false,
switch2: false
}
}
);
let res: TestStruct = from_key_values("mode=inactive").unwrap();
assert_eq!(
res,
TestStruct {
mode: FlipMode::Inactive,
}
);
let err = from_key_values::<TestStruct>("mode=inactive[]").unwrap_err();
assert_eq!(
err,
ParseError {
kind: ErrorKind::ExpectedComma,
pos: 13,
}
);
}
}