use serde_json::{json, Value};
use nom::{
alt, call, char, complete, count, delimited, eof, many0, many1, map, named, named_args, opt,
pair, separated_pair, tag, take_till, take_till1,
terminated,
character::complete::line_ending
};
named!(
pub(crate) parse_indent_string<&str, Value>,
terminated!(
map!(opt!(call!(parse_value_array, 0)), |v| v
.unwrap_or_default()),
eof!()
)
);
named_args!(
parse_value_array(indent_level: usize)<&str, Value>,
map!(many1!(
complete!(terminated!(
alt!(
alt!(call!(parse_colon_pair, indent_level) | call!(parse_value_pair_array, indent_level)) |
map!(
call!(parse_string, indent_level),
|s| (s, Value::Null)
)
),
many0!(line_ending)
))
),
|mut s| {
if s.iter().any(|m| m.1.is_null()) {
json!(s.drain(..).map(|(k, v)| if v.is_null() {json!(k)} else {json!({k: v})}).collect::<Vec<_>>())
} else {
json!(s.drain(..).map(|(k, v)| (k.into(), v)).collect::<serde_json::Map<_, _>>())
}
})
);
named_args!(
parse_colon_pair(indent_level: usize)<&str, (&str, Value)>,
map!(
delimited!(
count!(parse_indent, indent_level),
separated_pair!(
take_till!(|ch| ch == '\n' || ch == ':'),
pair!(tag!(":"), many1!(char!(' '))),
take_till1!(|ch| ch == '\n' || ch == ':')
),
line_ending
),
|(k, v)| (k.into(), json!(v))
)
);
named_args!(
parse_value_pair_array(indent_level: usize)<&str, (&str, Value)>,
pair!(
call!(parse_string, indent_level),
call!(parse_value_array, indent_level + 1)
)
);
named_args!(
parse_string(indent_level: usize)<&str, &str>,
delimited!(
count!(parse_indent, indent_level),
terminated!(
take_till!(|ch| ch == '\n' || ch == ':'),
opt!(char!(':'))
),
line_ending
)
);
named!(
parse_indent<&str, &str>,
alt!(
tag!(" ") |
tag!("\t")
)
);