use crate::{Container, Parsable, UbjsonError, values::string::StringValue, parse_length, parse_one};
#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
#[repr(u8)]
pub enum Marker {
Null = b'Z',
Noop = b'N',
True = b'T',
False = b'F',
Int8 = b'i',
Uint8 = b'U',
Int16 = b'I',
Int32 = b'l',
Int64 = b'L',
Float32 = b'd',
Float64 = b'D',
HighPrecisionNumber = b'H',
Char = b'C',
String = b'S',
ArrayStart = b'[',
ArrayEnd = b']',
ObjectStart = b'{',
ObjectEnd = b'}',
}
impl<'a> Parsable<'a> for Marker {
fn parse(i: &'a [u8]) -> nom::IResult<&'a [u8], Self, UbjsonError> {
use std::convert::TryFrom as _;
let (i, marker) = nom::combinator::map_res(nom::number::streaming::be_u8, Marker::try_from)(i)?;
Ok((i, marker))
}
}
impl Marker {
pub fn parse_to_container(self, i: &[u8]) -> nom::IResult<&[u8], Container, UbjsonError> {
match self {
Marker::Null => Ok((i, Container::Null)),
Marker::Noop => Ok((i, Container::Noop)),
Marker::True => Ok((i, Container::Boolean(true))),
Marker::False => Ok((i, Container::Boolean(false))),
Marker::Int8 => nom::combinator::map(nom::number::streaming::be_i8, |n| Container::Int8(n))(i),
Marker::Uint8 => nom::combinator::map(nom::number::streaming::be_u8, |n| Container::Uint8(n))(i),
Marker::Int16 => nom::combinator::map(nom::number::streaming::be_i16, |n| Container::Int16(n))(i),
Marker::Int32 => nom::combinator::map(nom::number::streaming::be_i32, |n| Container::Int32(n))(i),
Marker::Int64 => nom::combinator::map(nom::number::streaming::be_i64, |n| Container::Int64(n))(i),
Marker::Float32 => nom::combinator::map(nom::number::streaming::be_f32, |n| Container::Float32(n))(i),
Marker::Float64 => nom::combinator::map(nom::number::streaming::be_f64, |n| Container::Float64(n))(i),
Marker::Char => nom::combinator::map(nom::number::streaming::be_u8, |n| Container::Char(n as char))(i),
Marker::HighPrecisionNumber => {
let (i, result) = StringValue::parse(i)?;
Ok((i, Container::HighPrecisionNumber(result.unwrap().into())))
},
Marker::String => {
let (i, result) = StringValue::parse(i)?;
Ok((i, Container::String(result.unwrap().into())))
},
Marker::ArrayStart => {
let (i, mut specialized_parser, mut maybe_count) = {
let (i, maybe_type_marker): (&[u8], Option<&[u8]>) = nom::combinator::opt(nom::bytes::streaming::tag("$"))(i)?;
let (i, mut maybe_type): (&[u8], Option<Marker>) = nom::combinator::cond(maybe_type_marker.is_some(), Marker::parse)(i)?;
let (i, maybe_count_marker): (&[u8], Option<&[u8]>) = nom::combinator::opt(nom::bytes::streaming::tag("#"))(i)?;
let (i, maybe_count): (&[u8], Option<usize>) = nom::combinator::cond(maybe_count_marker.is_some(), parse_length)(i)?;
let specialized_parser = if let Some(mtype) = maybe_type.take() {
Some(move |i| -> nom::IResult<&[u8], Container, UbjsonError> {
let (i, marker) = Marker::parse(i)?;
if marker != mtype {
return Err(nom::Err::Error(UbjsonError::UnexpectedMarker {
expected: mtype,
actual: marker
}));
}
marker.parse_to_container(i)
})
} else {
None
};
(i, specialized_parser, maybe_count)
};
let (i, values) = if let Some(count) = maybe_count.take() {
if let Some(specialized_parser) = specialized_parser.take() {
nom::multi::many_m_n(
count,
count,
specialized_parser,
)(i)
} else {
nom::multi::many_m_n(
count,
count,
parse_one,
)(i)
}
} else {
let (i, (values, _)) = nom::multi::many_till(parse_one, nom::bytes::streaming::tag(&[Marker::ArrayEnd as u8]))(i)?;
Ok((i, values))
}?;
Ok((i, Container::Array(values)))
},
Marker::ObjectStart => {
let (i, mut specialized_value_parser, mut maybe_count) = {
let (i, maybe_type_marker): (&[u8], Option<&[u8]>) = nom::combinator::opt(nom::bytes::streaming::tag("$"))(i)?;
let (i, mut maybe_type): (&[u8], Option<Marker>) = nom::combinator::cond(maybe_type_marker.is_some(), Marker::parse)(i)?;
let (i, maybe_count_marker): (&[u8], Option<&[u8]>) = nom::combinator::opt(nom::bytes::streaming::tag("#"))(i)?;
let (i, maybe_count): (&[u8], Option<usize>) = nom::combinator::cond(maybe_count_marker.is_some(), parse_length)(i)?;
let specialized_parser = if let Some(mtype) = maybe_type.take() {
Some(move |i| -> nom::IResult<&[u8], Container, UbjsonError> {
let (i, marker) = Marker::parse(i)?;
if marker != mtype {
return Err(nom::Err::Error(UbjsonError::UnexpectedMarker {
expected: mtype,
actual: marker
}));
}
marker.parse_to_container(i)
})
} else {
None
};
(i, specialized_parser, maybe_count)
};
let (i, values) = if let Some(count) = maybe_count.take() {
if let Some(specialized_value_parser) = specialized_value_parser.take() {
nom::multi::many_m_n(
count,
count,
nom::sequence::pair(StringValue::parse, specialized_value_parser),
)(i)
} else {
nom::multi::many_m_n(
count,
count,
nom::sequence::pair(StringValue::parse, parse_one),
)(i)
}
} else {
let (i, (values, _)) = nom::multi::many_till(nom::sequence::pair(StringValue::parse, parse_one), nom::bytes::streaming::tag(&[Marker::ObjectEnd as u8]))(i)?;
Ok((i, values))
}?;
let hash: std::collections::HashMap<std::borrow::Cow<str>, Container, _> = values.into_iter().map(|(sval, container)| (sval.unwrap(), container)).collect();
Ok((i, Container::Object(hash)))
},
marker => Err(nom::Err::Error(UbjsonError::ExtraMarker(marker))),
}
}
}