serde-intermediate 1.6.2

Intermediate representation of Serde serialization
Documentation
use crate::{
    de::intermediate::{deserialize_as, DeserializeMode},
    error::*,
    value::intermediate::Intermediate,
};
use pest::{iterators::Pair, Parser};
use pest_derive::Parser;
use serde::de::DeserializeOwned;

pub fn from_str<T>(value: &str) -> Result<T>
where
    T: DeserializeOwned,
{
    from_str_as(value, Default::default())
}

pub fn from_str_as<T>(value: &str, mode: DeserializeMode) -> Result<T>
where
    T: DeserializeOwned,
{
    let value = intermediate_from_str(value)?;
    deserialize_as(&value, mode)
}

#[derive(Parser)]
#[grammar = "de/text.grammar.pest"]
struct TextParser;

pub fn intermediate_from_str(content: &str) -> Result<Intermediate> {
    let ast = TextParser::parse(Rule::main, content)
        .map_err(|error| Error::Message(format!("{}", error)))?
        .next()
        .ok_or(Error::NoNextTokens)?;
    parse(ast)
}

macro_rules! impl_parse {
    ($variant:ident : $ast:expr) => {{
        let t = $ast.into_inner().next().unwrap().as_str();
        match t.parse() {
            Ok(value) => Ok(Intermediate::$variant(value)),
            Err(_) => Err(Error::CannotParse(t.to_owned())),
        }
    }};
}

fn parse(ast: Pair<Rule>) -> Result<Intermediate> {
    match ast.as_rule() {
        Rule::unit => Ok(Intermediate::Unit),
        Rule::bool => match ast.as_str() {
            "true" => Ok(Intermediate::Bool(true)),
            "false" => Ok(Intermediate::Bool(false)),
            t => Err(Error::InvalidTokens(t.to_owned())),
        },
        Rule::i8 => impl_parse!(I8: ast),
        Rule::i16 => impl_parse!(I16: ast),
        Rule::i32 => impl_parse!(I32: ast),
        Rule::i64 => impl_parse!(I64: ast),
        Rule::i128 => impl_parse!(I128: ast),
        Rule::u8 => impl_parse!(U8: ast),
        Rule::u16 => impl_parse!(U16: ast),
        Rule::u32 => impl_parse!(U32: ast),
        Rule::u64 => impl_parse!(U64: ast),
        Rule::u128 => impl_parse!(U128: ast),
        Rule::f32 => impl_parse!(F32: ast),
        Rule::f64 => impl_parse!(F64: ast),
        Rule::char => impl_parse!(Char: ast),
        Rule::signed_integer => {
            let t = ast.as_str();
            match t.parse() {
                Ok(value) => Ok(Intermediate::I64(value)),
                Err(_) => Err(Error::CannotParse(t.to_owned())),
            }
        }
        Rule::unsigned_integer => {
            let t = ast.as_str();
            match t.parse() {
                Ok(value) => Ok(Intermediate::U64(value)),
                Err(_) => Err(Error::CannotParse(t.to_owned())),
            }
        }
        Rule::real => {
            let t = ast.as_str();
            match t.parse() {
                Ok(value) => Ok(Intermediate::F64(value)),
                Err(_) => Err(Error::CannotParse(t.to_owned())),
            }
        }
        Rule::string => Ok(Intermediate::String(
            ast.into_inner().next().unwrap().as_str().to_owned(),
        )),
        Rule::bytes => {
            let t = ast.into_inner().next().unwrap().as_str();
            let bytes = (0..t.len())
                .step_by(2)
                .map(|i| u8::from_str_radix(&t[i..(i + 2)], 16))
                .collect::<std::result::Result<Vec<_>, _>>();
            match bytes {
                Ok(bytes) => Ok(Intermediate::Bytes(bytes)),
                Err(_) => Err(Error::CannotParse(t.to_owned())),
            }
        }
        Rule::none => Ok(Intermediate::Option(None)),
        Rule::some => {
            let value = parse(ast.into_inner().next().unwrap())?;
            Ok(Intermediate::Option(Some(Box::new(value))))
        }
        Rule::unit_struct => Ok(Intermediate::UnitStruct),
        Rule::newtype_struct => {
            let value = parse(ast.into_inner().next().unwrap())?;
            Ok(Intermediate::NewTypeStruct(Box::new(value)))
        }
        Rule::seq => {
            let list = ast.into_inner().map(parse).collect::<Result<Vec<_>>>()?;
            Ok(Intermediate::Seq(list))
        }
        Rule::tuple => {
            let list = ast.into_inner().map(parse).collect::<Result<Vec<_>>>()?;
            Ok(Intermediate::Tuple(list))
        }
        Rule::tuple_struct => {
            let list = ast.into_inner().map(parse).collect::<Result<Vec<_>>>()?;
            Ok(Intermediate::TupleStruct(list))
        }
        Rule::map => {
            let pairs = ast
                .into_inner()
                .map(|ast| {
                    let mut pairs = ast.into_inner();
                    let key = parse(pairs.next().unwrap())?;
                    let value = parse(pairs.next().unwrap())?;
                    Ok((key, value))
                })
                .collect::<Result<Vec<_>>>()?;
            Ok(Intermediate::Map(pairs))
        }
        Rule::structure => {
            let pairs = ast
                .into_inner()
                .map(|ast| {
                    let mut pairs = ast.into_inner();
                    let key = pairs.next().unwrap().as_str().to_owned();
                    let value = parse(pairs.next().unwrap())?;
                    Ok((key, value))
                })
                .collect::<Result<Vec<_>>>()?;
            Ok(Intermediate::Struct(pairs))
        }
        Rule::variant => {
            let mut pairs = ast.into_inner();
            let name = pairs.next().unwrap().as_str().to_owned();
            let content = pairs.next().unwrap();
            match content.as_rule() {
                Rule::unit => Ok(Intermediate::UnitVariant(name)),
                Rule::newtype_struct => Ok(Intermediate::NewTypeVariant(
                    name,
                    Box::new(parse(content)?),
                )),
                Rule::tuple => {
                    let list = content
                        .into_inner()
                        .map(parse)
                        .collect::<Result<Vec<_>>>()?;
                    Ok(Intermediate::TupleVariant(name, list))
                }
                Rule::structure => {
                    let pairs = content
                        .into_inner()
                        .map(|ast| {
                            let mut pairs = ast.into_inner();
                            let key = pairs.next().unwrap().as_str().to_owned();
                            let value = parse(pairs.next().unwrap())?;
                            Ok((key, value))
                        })
                        .collect::<Result<Vec<_>>>()?;
                    Ok(Intermediate::StructVariant(name, pairs))
                }
                _ => Err(Error::InvalidTokens(content.as_str().to_owned())),
            }
        }
        _ => Err(Error::InvalidTokens(ast.as_str().to_owned())),
    }
}