use crate::deserialize::numbers::{float, int, uint};
use crate::deserialize::string::string;
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::fmt::Debug;
use nom::branch::alt;
use nom::bytes::streaming::tag_no_case;
use nom::character::streaming::char;
use nom::combinator::{map, value};
use nom::error::ParseError;
use nom::sequence::delimited;
use nom::{AsChar, Compare, IResult, Input, Parser};
mod string;
mod numbers;
#[cfg(feature = "serde")]
mod adapter;
mod error;
#[cfg(feature = "iter")]
pub use adapter::from_iter;
#[cfg(feature = "serde")]
pub use adapter::from_str;
#[cfg(feature = "serde")]
pub use adapter::Deserializer;
pub use error::DeserializeError;
pub type AnnotatedList = (Box<Item>, Vec<Item>);
#[derive(Clone, PartialEq, Debug)]
pub enum Item {
AnnotatedList(AnnotatedList),
List(Vec<Item>),
String(String),
Bool(bool),
Int(i64),
UInt(u64),
Float(f64),
Null
}
pub fn literal<'a, I: Input + ToString + Compare<&'a str>, E: ParseError<I>>(input: I) -> IResult<I, Item, E>
where <I as Input>::Item: AsChar,
String: FromIterator<I>
{
alt((
list::<I, E>,
bool::<I, E>,
float::<I, E>,
uint::<I, E>,
int::<I, E>,
null::<I, E>,
string::<I, E>
)).parse(input)
}
#[test]
pub fn test_literal() {
use nom::Finish;
use alloc::vec;
match literal::<&str, DeserializeError<&str>>("(a(1))").finish() {
Ok(item) => assert_eq!(
item,
("", Item::List(vec![Item::AnnotatedList((
Box::new(Item::String("a".to_string())),
vec![
Item::UInt(1)
],
))]))
),
Err(err) => panic!("{}", err),
}
match literal::<&str, DeserializeError<&str>>("(a(1),b(-2),c(3.14),null(true))").finish() {
Ok(item) => assert_eq!(
item,
("", Item::List(vec![
Item::AnnotatedList((
Box::new(Item::String("a".to_string())),
vec![
Item::UInt(1)
],
)), Item::AnnotatedList((
Box::new(Item::String("b".to_string())),
vec![
Item::Int(-2)
],
)),
Item::AnnotatedList((
Box::new(Item::String("c".to_string())),
vec![
Item::Float(3.14)
],
)),
Item::AnnotatedList((
Box::new(Item::Null),
vec![
Item::Bool(true)
],
)),
]))
),
Err(err) => panic!("{}", err),
}
}
fn process_list<'a, I: Input, E: ParseError<I>, P: Parser<I, Error = E, Output = Item>>(mut parser: P, quit_on: Option<char>) -> impl FnMut(I) -> IResult<I, Vec<Item>, E>
where <I as Input>::Item: AsChar {
move |input| {
let mut outputs: Vec<Item> = Vec::new();
let mut input: I = input;
let mut input_changed = true;
while input_changed {
input_changed = false;
let mut seen_escape = false;
for (index, item) in input.iter_indices() {
match item.as_char() {
'\n' | ',' => {
seen_escape = true;
continue;
},
' ' | '\t' | '\r' => continue,
item => {
match quit_on {
None => {}
Some(quit_on) => if item == quit_on {
return Ok((input.take_from(index), outputs))
}
}
let out = parser.parse(input.take_from(index))?;
input = out.0;
input_changed = true;
if seen_escape {
outputs.push(match out.1 {
Item::List(items) => {
if items.len() == 1 {
match items.into_iter().next() {
None => unreachable!(),
Some(item) => item
}
} else {
Item::List(items)
}
}
i => i
});
} else {
match outputs.pop() {
None => outputs.push(out.1),
Some(last) => match out.1 {
Item::List(v) => outputs.push(Item::AnnotatedList((
Box::new(last),
v
))),
i => {
outputs.push(last);
outputs.push(i);
}
}
}
}
break
}
}
}
}
return Ok((input.take(0), outputs))
}
}
pub fn deserialize<'a, I: Input + ToString + Compare<&'a str>, E: ParseError<I>>(input: I) -> IResult<I, Vec<Item>, E>
where <I as Input>::Item: AsChar,
String: FromIterator<I>
{
process_list(literal::<I, E>, None).parse(input)
}
#[test]
pub fn test_undelimited_list() {
use nom::Finish;
use alloc::vec;
assert_eq!(
deserialize::<&str, DeserializeError<&str>>("a\n b\n nya").finish().unwrap(),
("", vec![
Item::String("a".to_string()),
Item::String("b".to_string()),
Item::String("nya".to_string())
])
);
}
pub fn list<'a, I: Input + ToString + Compare<&'a str>, E: ParseError<I>>(input: I) -> IResult<I, Item, E>
where <I as Input>::Item: AsChar,
String: FromIterator<I>
{
map(delimited(
char('('),
process_list(literal::<I, E>, Some(')')),
char(')')
), Item::List).parse(input)
}
#[test]
pub fn test_list() {
use nom::Finish;
use alloc::vec;
assert_eq!(
list::<&str, DeserializeError<&str>>("(1,-2)nya").finish().unwrap(),
("nya", Item::List(vec![
Item::UInt(1),
Item::Int(-2)
]))
);
assert_eq!(
list::<&str, DeserializeError<&str>>("(a,b)nya").finish().unwrap(),
("nya", Item::List(vec![
Item::String("a".to_string()),
Item::String("b".to_string()),
]))
);
assert_eq!(
list::<&str, DeserializeError<&str>>("(1\n -2 )nya").finish().unwrap(),
("nya", Item::List(vec![
Item::UInt(1),
Item::Int(-2)
]))
);
assert_eq!(
list::<&str, DeserializeError<&str>>("(a\n b )nya").finish().unwrap(),
("nya", Item::List(vec![
Item::String("a".to_string()),
Item::String("b".to_string()),
]))
);
assert_eq!(
list::<&str, DeserializeError<&str>>("(1\n, -2, nya)nya").finish().unwrap(),
("nya", Item::List(vec![
Item::UInt(1),
Item::Int(-2),
Item::String("nya".to_string())
]))
);
assert_eq!(
list::<&str, DeserializeError<&str>>("(a\n b\n nya)nya").finish().unwrap(),
("nya", Item::List(vec![
Item::String("a".to_string()),
Item::String("b".to_string()),
Item::String("nya".to_string())
]))
);
}
pub fn bool<'a, I: Input + Compare<&'a str>, E: ParseError<I> >(input: I) -> IResult<I, Item, E> {
map(alt((
value(true, tag_no_case("true")),
value(false, tag_no_case("false"))
)), Item::Bool).parse(input)
}
#[test]
pub fn test_bool() {
use nom::Finish;
assert_eq!(
bool::<&str, DeserializeError<&str>>("truenya").finish().unwrap(),
("nya", Item::Bool(true))
);
assert_eq!(
bool::<&str, DeserializeError<&str>>("falsenya").finish().unwrap(),
("nya", Item::Bool(false))
);
}
pub fn null<'a, I: Input + Compare<&'a str>, E: ParseError<I>>(input: I) -> IResult<I, Item, E> {
value(Item::Null, tag_no_case("null")).parse(input)
}
#[test]
pub fn test_null() {
use nom::Finish;
assert_eq!(
null::<&str, DeserializeError<&str>>("nullnya").finish().unwrap(),
("nya", Item::Null)
);
}