1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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))),
        }
    }
}