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
mod error;

pub use error::*;

mod marker;
pub use marker::*;
mod container;
pub use container::*;

mod values;
pub use crate::values::*;

pub const MIME_TYPE: &str = "application/ubjson";
pub const FILE_EXT: &str = "ubj";

pub trait Parsable<'a>: Sized {
    fn parse(i: &'a [u8]) -> nom::IResult<&'a [u8], Self, UbjsonError>;
}


/// Main entry point. Will parse one whole UBJSON value, whatever it is
#[inline(always)]
pub fn parse_one<'a>(i: &'a [u8]) -> nom::IResult<&'a [u8], Container, UbjsonError> {
    Marker::parse(i).and_then(|(i, marker)| marker.parse_to_container(i))
}

/// Utility to parse length and convert it to a `usize`
#[inline(always)]
fn parse_length(i: &[u8]) -> nom::IResult<&[u8], usize, UbjsonError> {
    use std::convert::TryInto as _;
    let (i, marker) = Marker::parse(i)?;
    let (i, container) = marker.parse_to_container(i)?;
    let length = container.try_into().map_err(nom::Err::Failure)?;
    Ok((i, length))
}

#[cfg(test)]
mod test {
    use crate::parse_one;

    const COMPLEX_COUCHDB: &[u8] = include_bytes!("../test/samples/complex/CouchDB4k.ubj");
    const COMPLEX_MEDIA: &[u8] = include_bytes!("../test/samples/complex/MediaContent.ubj");
    const COMPLEX_TWITTER: &[u8] = include_bytes!("../test/samples/complex/TwitterTimeline.ubj");

    #[test]
    fn test_complex_couchdb() {
        let (_, _container) = parse_one(COMPLEX_COUCHDB).unwrap();
    }

    #[test]
    fn test_complex_media() {
        let (_, _container) = parse_one(COMPLEX_MEDIA).unwrap();
    }

    #[test]
    fn test_complex_twitter() {
        let (_, _container) = parse_one(COMPLEX_TWITTER).unwrap();
    }
}