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
use super::element::Element;
use super::parser::Parser;
use crate::error::SimdJsonError;
use crate::libsimdjson::ffi;
use cxx::UniquePtr;
use std::fmt;
use std::marker::PhantomData;

pub type ObjectIterPtr = UniquePtr<ffi::ObjectIterator>;
pub type ObjectPtr = UniquePtr<ffi::object>;

pub struct Object<'a> {
    ptr: ObjectPtr,
    _phantom: PhantomData<&'a Parser>,
}

impl<'a> Object<'a> {
    pub fn new(ptr: ObjectPtr) -> Self {
        Object {
            ptr,
            _phantom: PhantomData,
        }
    }

    pub fn at_pointer(&self, json_pointer: &str) -> Result<Element, SimdJsonError> {
        let result = ffi::object_at_pointer(&self.ptr, json_pointer);
        // if result.code < 2 {
        //     Ok(Element::from(result.value))
        // } else {
        //     Err(SimdJsonError::from(result.code))
        // }

        check_result!(result, Element)
    }

    pub fn at_key(&self, key: &str) -> Result<Element, SimdJsonError> {
        let result = ffi::object_at_key(&self.ptr, key);
        check_result!(result, Element)
    }

    pub fn at_key_case_insensitive(&self, key: &str) -> Result<Element, SimdJsonError> {
        let result = ffi::object_at_key_case_insensitive(&self.ptr, key);
        check_result!(result, Element)
    }

    pub fn minify(&self) -> String {
        ffi::object_minify(&self.ptr)
    }
}

impl<'a> From<ObjectPtr> for Object<'a> {
    fn from(ptr: ObjectPtr) -> Self {
        Object::new(ptr)
    }
}

pub struct ObjectIter<'a> {
    pub ptr: ObjectIterPtr,
    #[allow(dead_code)]
    object: &'a Object<'a>,
}

impl<'a> ObjectIter<'a> {
    pub fn new(object: &'a Object<'a>) -> Self {
        let ptr = ffi::object_get_iterator(&object.ptr);
        ObjectIter { ptr, object }
    }

    pub fn has_next(&self) -> bool {
        ffi::object_iterator_has_next(&self.ptr)
    }

    pub fn key(&self) -> String {
        ffi::object_iterator_key(&self.ptr)
    }

    pub fn value(&self) -> Element<'a> {
        ffi::object_iterator_value(&self.ptr).into()
    }
}

impl<'a> Iterator for ObjectIter<'a> {
    type Item = (String, Element<'a>);

    fn next(&mut self) -> Option<Self::Item> {
        ffi::object_iterator_next(self.ptr.pin_mut());
        if self.has_next() {
            None
        } else {
            Some((self.key(), self.value()))
        }
    }
}

impl<'a> IntoIterator for &'a Object<'a> {
    type Item = (String, Element<'a>);
    type IntoIter = ObjectIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        ObjectIter::new(self)
    }
}

#[cfg(test)]
mod tests {

    use crate::dom::parser::Parser;
    // use super::element::GetValue;

    #[test]
    fn object_iter() -> Result<(), Box<dyn std::error::Error>> {
        let mut parser = Parser::default();
        let elm = parser.parse(r#"{"a": true, "b": true}"#)?;
        let obj = elm.get_object()?;

        for (k, v) in &obj {
            println!("k={}, v={}", k, v.get_bool()?);
        }

        Ok(())
    }
}

impl<'a> fmt::Display for Object<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.minify())
    }
}