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
use super::document_stream::DocumentStream;
use super::element::Element;
use crate::error::SimdJsonError;
use crate::libsimdjson::{ffi, DEFAULT_BATCH_SIZE, SIMDJSON_MAXSIZE_BYTES};
use crate::padded_string::PaddedString;
use cxx::UniquePtr;

use std::path::Path;

pub struct Parser {
    ptr: UniquePtr<ffi::parser>,
}

impl Parser {
    pub fn new(max_capacity: usize) -> Parser {
        let parser = ffi::parser_new(max_capacity);
        Parser { ptr: parser }
    }

    pub fn load<P: AsRef<Path>>(&mut self, path: P) -> Result<Element, SimdJsonError> {
        let result = ffi::parser_load(self.ptr.pin_mut(), path.as_ref().to_str().unwrap());
        check_result!(result, Element)
    }

    pub fn parse(&mut self, s: &str) -> Result<Element, SimdJsonError> {
        let result = ffi::parser_parse(self.ptr.pin_mut(), s);
        check_result!(result, Element)
    }

    pub fn parse_padded(&mut self, s: &PaddedString) -> Result<Element, SimdJsonError> {
        let result = ffi::parser_parse_padded(self.ptr.pin_mut(), s.as_ptr());
        check_result!(result, Element)
    }

    pub fn load_many<P: AsRef<Path>>(
        &mut self,
        path: P,
        batch_size: usize,
    ) -> Result<DocumentStream, SimdJsonError> {
        let stream = ffi::parser_load_many(
            self.ptr.pin_mut(),
            path.as_ref()
                .to_str()
                .ok_or(SimdJsonError::InvalidUriFragment)?,
            batch_size,
        );
        check_result!(stream, DocumentStream)
    }

    pub fn load_many_default<P: AsRef<Path>>(
        &mut self,
        path: P,
    ) -> Result<DocumentStream, SimdJsonError> {
        self.load_many(path, DEFAULT_BATCH_SIZE)
    }

    pub fn parse_many(
        &mut self,
        s: &str,
        batch_size: usize,
    ) -> Result<DocumentStream, SimdJsonError> {
        let stream = ffi::parser_parse_many(self.ptr.pin_mut(), s, batch_size);
        check_result!(stream, DocumentStream)
    }

    pub fn parse_many_default(&mut self, s: &str) -> Result<DocumentStream, SimdJsonError> {
        self.parse_many(s, DEFAULT_BATCH_SIZE)
    }

    pub fn parse_many_padded(
        &mut self,
        s: &PaddedString,
        batch_size: usize,
    ) -> Result<DocumentStream, SimdJsonError> {
        let stream = ffi::parser_parse_many_padded(self.ptr.pin_mut(), s.as_ptr(), batch_size);
        check_result!(stream, DocumentStream)
    }

    pub fn parse_many_padded_default(
        &mut self,
        s: &PaddedString,
    ) -> Result<DocumentStream, SimdJsonError> {
        self.parse_many_padded(s, DEFAULT_BATCH_SIZE)
    }
}

impl Default for Parser {
    fn default() -> Self {
        let parser = ffi::parser_new(SIMDJSON_MAXSIZE_BYTES);
        Parser { ptr: parser }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    // use super::element::GetValue;

    #[test]
    fn parse_padded_string() {
        let mut parser = Parser::default();
        let value: bool = parser
            .parse_padded(&"true".into())
            .unwrap()
            .get_bool()
            .unwrap();
        assert!(value);
    }

    #[test]
    fn parse_parse_many() {
        let mut parser = Parser::default();
        let input = "22\n33\n\"hello world\"\n\n\"goodbye world\"\n\n\n[1, 2, 3]\n{\"a\": -0.5}";
        let mut docs = parser.parse_many_default(input).unwrap();
        assert_eq!(docs.next().unwrap().unwrap().get_u64().unwrap(), 22);
        assert_eq!(
            docs.nth(1).unwrap().unwrap().get_string().unwrap(),
            "hello world"
        );
    }

    #[test]
    fn borrow_checker() {
        let mut parser = Parser::default();
        let elm = parser.parse_padded(&"true".into()).unwrap();
        assert!(elm.get_bool().unwrap());
        let new_elm = parser.parse("false").unwrap();
        assert!(!new_elm.get_bool().unwrap());
    }
}