use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::vec::Vec;
use nom::IResult;
use nom::branch::alt;
use nom::bytes::complete::{take_till1, take_until};
use nom::character::complete::{char, i64, line_ending, multispace0, not_line_ending};
use nom::combinator::map;
use nom::multi::{many0, separated_list0};
use nom::sequence::{delimited, preceded, tuple};
use serde::de::value::StrDeserializer;
use serde::{de, forward_to_deserialize_any};
#[derive(Debug)]
pub enum MetadataValue {
String(String),
Number(i64),
Array(Vec<MetadataValue>),
}
impl MetadataValue {
pub fn parse(input: &str) -> IResult<&str, Self> {
delimited(
whitespace,
alt((
map(i64, MetadataValue::Number),
map(
delimited(
char('['),
separated_list0(char(','), MetadataValue::parse),
char(']'),
),
MetadataValue::Array,
),
map(
delimited(char('"'), take_until("\""), char('"')),
|x: &str| MetadataValue::String(x.to_owned()),
),
)),
whitespace,
)(input)
}
}
#[derive(Debug)]
pub struct MetadataElements<'a>(Vec<MetadataElement<'a>>);
impl<'a> MetadataElements<'a> {
pub fn parse(input: &'a str) -> IResult<&'a str, Self> {
map(many0(MetadataElement::parse), MetadataElements)(input)
}
}
#[derive(Debug)]
pub enum MetadataElement<'a> {
Group {
name: &'a str,
contents: MetadataElements<'a>,
},
Value {
name: &'a str,
value: MetadataValue,
},
}
fn parse_ident(input: &str) -> IResult<&str, &str> {
take_till1(|x| " \r\n\t{}=[]".contains(x))(input)
}
fn comment(input: &str) -> IResult<&str, &str> {
preceded(
multispace0,
delimited(char('#'), not_line_ending, line_ending),
)(input)
}
fn whitespace(input: &str) -> IResult<&str, ()> {
let (input, _) = many0(comment)(input)?;
let (input, _) = multispace0(input)?;
Ok((input, ()))
}
impl<'a> MetadataElement<'a> {
pub fn name(&self) -> &'a str {
match self {
MetadataElement::Group { name, .. } | MetadataElement::Value { name, .. } => name,
}
}
pub fn parse(input: &'a str) -> IResult<&'a str, Self> {
delimited(
whitespace,
alt((
map(
tuple((
parse_ident,
whitespace,
char('='),
whitespace,
MetadataValue::parse,
)),
|(name, (), _, (), v)| MetadataElement::Value { name, value: v },
),
map(
tuple((
parse_ident,
whitespace,
char('{'),
MetadataElements::parse,
char('}'),
)),
|(name, (), _, contents, _)| MetadataElement::Group { name, contents },
),
)),
whitespace,
)(input)
}
}
impl<'de> de::Deserializer<'de> for &MetadataElements<'de> {
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
type Error = serde::de::value::Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_map(MetadataElementsAccess(self.0.iter().peekable()))
}
}
pub struct MetadataElementsAccess<'a, 'de>(
core::iter::Peekable<alloc::slice::Iter<'a, MetadataElement<'de>>>,
);
impl<'de> de::MapAccess<'de> for MetadataElementsAccess<'_, 'de> {
type Error = serde::de::value::Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: de::DeserializeSeed<'de>,
{
match self.0.peek() {
None => Ok(None),
Some(x) => seed.deserialize(StrDeserializer::new(x.name())).map(Some),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: de::DeserializeSeed<'de>,
{
match self.0.next() {
None => panic!("deserializing value before key"),
Some(MetadataElement::Group { contents, .. }) => seed.deserialize(contents),
Some(MetadataElement::Value { value, .. }) => seed.deserialize(value),
}
}
}
impl<'de> de::Deserializer<'de> for &MetadataValue {
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
type Error = serde::de::value::Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
match self {
MetadataValue::String(s) => visitor.visit_str(s),
&MetadataValue::Number(n) => visitor.visit_i64(n),
MetadataValue::Array(a) => visitor.visit_seq(MetadataValuesAccess(a.iter())),
}
}
}
pub struct MetadataValuesAccess<'a>(alloc::slice::Iter<'a, MetadataValue>);
impl<'de> de::SeqAccess<'de> for MetadataValuesAccess<'_> {
type Error = serde::de::value::Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: de::DeserializeSeed<'de>,
{
match self.0.next() {
None => Ok(None),
Some(x) => seed.deserialize(x).map(Some),
}
}
}