1pub mod raw;
2use std::slice;
3use std::ffi::CStr;
4use std::os::raw::c_void;
5
6#[derive(Debug)]
7pub enum MochaError {
8 MissingField,
9 DuplicateField,
10 RootReference,
11 OutOfMemory,
12 InvalidCharacter,
13 Overflow,
14 EndOfStream,
15 UnexpectedToken,
16 UnexpectedCharacter
17}
18
19#[derive(Debug)]
20pub enum Value<'a> {
21 String(&'a [u8]),
22 Ref(Reference<'a>),
23 Bool(bool),
24 Object(Object),
25 Array(Array),
26 Float(f64),
27 Int(i64),
28 Nil,
29}
30
31#[derive(Debug)]
32pub struct Reference<'a> {
33 child: *const c_void,
34 pub name: &'a [u8],
35 pub index: usize,
36}
37
38#[derive(Debug)]
39pub struct Field<'a> {
40 pub name: &'a [u8],
41 pub value: Value<'a>,
42}
43
44#[derive(Debug)]
45pub struct Array {
46 array: *mut c_void,
47 pub len: usize,
48}
49
50#[derive(Debug)]
51pub struct Object {
52 obj: *mut c_void,
53 pub len: usize,
54}
55
56#[derive(Debug)]
57pub struct Mocha {
58 obj: *mut c_void,
59 pub len: usize,
60}
61
62impl Drop for Mocha {
63 fn drop(&mut self) {
64 unsafe { raw::mocha_deinit(&mut raw::mocha_object_t{fields: self.obj, fields_len: self.len}) }
65 }
66}
67
68impl Mocha {
69 pub fn parse(src: &str) -> Result<Self, MochaError> {
70 unsafe {
71 let mut object = raw::mocha_object_t{fields: 0 as _, fields_len: 0};
72 let mocha = raw::mocha_nparse(&mut object as _, src.as_ptr() as _, src.len());
73 if let Some(err) = handle_mocha_error(mocha) {
74 Err(err)
75 } else {
76 Ok(Self {obj: object.fields, len: object.fields_len})
77 }
78 }
79 }
80
81 pub fn get(&self, index: usize) -> Option<Field> {
82 unsafe {
83 if index >= self.len { return None }
84 let field = raw::mocha_field(&raw::mocha_object_t{fields: self.obj, fields_len: self.len} as _, index);
85 match field.type_ {
86 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_NIL => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
87 value: Value::Nil }),
88 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_STRING => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
89 value: Value::String(CStr::from_ptr(field.value.string).to_bytes()) }),
90 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_REFERENCE => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
91 value: Value::Ref(Reference{child: field.value.reference.child,
92 name: slice::from_raw_parts(field.value.reference.name as _,
93 field.value.reference.name_len),
94 index: field.value.reference.index}) }),
95 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_BOOLEAN => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
96 value: Value::Bool(if field.value.boolean == 0 { false } else { true }) }),
97 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_OBJECT => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
98 value: Value::Object(Object{obj: field.value.object.fields,
99 len: field.value.object.fields_len}) }),
100 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_ARRAY => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
101 value: Value::Array(Array{array: field.value.array.items,
102 len: field.value.array.items_len}) }),
103 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_FLOAT64 => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
104 value: Value::Float(field.value.float64) }),
105 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_INTEGER64 => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
106 value: Value::Int(field.value.integer64) }),
107 _ => None
108 }
109 }
110 }
111}
112
113impl Object {
114 pub fn get(&self, index: usize) -> Option<Field> {
115 unsafe {
116 if index >= self.len { return None }
117 let field = raw::mocha_field(&raw::mocha_object_t{fields: self.obj, fields_len: self.len} as _, index);
118 match field.type_ {
119 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_NIL => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
120 value: Value::Nil }),
121 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_STRING => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
122 value: Value::String(CStr::from_ptr(field.value.string).to_bytes()) }),
123 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_REFERENCE => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
124 value: Value::Ref(Reference{child: field.value.reference.child,
125 name: slice::from_raw_parts(field.value.reference.name as _,
126 field.value.reference.name_len),
127 index: field.value.reference.index}) }),
128 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_BOOLEAN => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
129 value: Value::Bool(if field.value.boolean == 0
130 { false } else { true })}),
131 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_OBJECT => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
132 value: Value::Object(Object{obj: field.value.object.fields,
133 len: field.value.object.fields_len}) }),
134 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_ARRAY => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
135 value: Value::Array(Array{array: field.value.array.items,
136 len: field.value.array.items_len}) }),
137 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_FLOAT64 => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
138 value: Value::Float(field.value.float64) }),
139 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_INTEGER64 => Some(Field { name: CStr::from_ptr(field.name).to_bytes(),
140 value: Value::Int(field.value.integer64) }),
141 _ => None
142 }
143 }
144 }
145}
146
147impl Array {
148 pub fn get(&self, index: usize) -> Option<Value> {
149 unsafe {
150 if index >= self.len { return None }
151 let mut value = raw::mocha_value_t{boolean: 0};
152 let type_ = raw::mocha_array(&raw::mocha_array_t{ items: self.array, items_len: self.len}, &mut value as _, index);
153 match type_ {
154 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_NIL => Some(Value::Nil),
155 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_STRING => Some(Value::String(CStr::from_ptr(value.string).to_bytes())),
156 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_REFERENCE => Some(Value::Ref(Reference{child: value.reference.child,
157 name: slice::from_raw_parts(value.reference.name as _,
158 value.reference.name_len),
159 index: value.reference.index})),
160 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_BOOLEAN => Some(Value::Bool(if value.boolean == 0 { false } else { true })),
161 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_OBJECT => Some(Value::Object(Object{obj: value.object.fields,
162 len: value.object.fields_len})),
163 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_ARRAY => Some(Value::Array(Array{array: value.array.items, len: value.array.items_len})),
164 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_FLOAT64 => Some(Value::Float(value.float64)),
165 raw::mocha_value_type_t_MOCHA_VALUE_TYPE_INTEGER64 => Some(Value::Int(value.integer64)),
166 _ => None
167 }
168 }
169 }
170}
171
172impl Reference<'_> {
173 pub fn next(&self) -> Option<Self> {
174 unsafe {
175 let mut reference = raw::mocha_reference_t{name: 0 as _,
176 name_len: 0,
177 child: self.child,index: 0};
178 let err = raw::mocha_reference_next(&mut reference as _);
179 if err == 0 {
180 Some(Self{child: reference.child,
181 name: slice::from_raw_parts(reference.name as _,
182 reference.name_len),
183 index: reference.index})
184 } else {
185 None
186 }
187 }
188 }
189}
190
191#[inline(always)]
192fn handle_mocha_error(err: raw::mocha_error_t) -> Option<MochaError> {
193 match err {
194 raw::mocha_error_t_MOCHA_ERROR_NONE => None,
195 raw::mocha_error_t_MOCHA_ERROR_MISSING_FIELD => Some(MochaError::MissingField),
196 raw::mocha_error_t_MOCHA_ERROR_DUPLICATE_FIELD => Some(MochaError::DuplicateField),
197 raw::mocha_error_t_MOCHA_ERROR_ROOT_REFERENCE => Some(MochaError::RootReference),
198 raw::mocha_error_t_MOCHA_ERROR_OUT_OF_MEMORY => Some(MochaError::OutOfMemory),
199 raw::mocha_error_t_MOCHA_ERROR_INVALID_CHARACTER => Some(MochaError::InvalidCharacter),
200 raw::mocha_error_t_MOCHA_ERROR_OVERFLOW => Some(MochaError::Overflow),
201 raw::mocha_error_t_MOCHA_ERROR_END_OF_STREAM => Some(MochaError::EndOfStream),
202 raw::mocha_error_t_MOCHA_ERROR_UNEXPECTED_TOKEN => Some(MochaError::UnexpectedToken),
203 raw::mocha_error_t_MOCHA_ERROR_UNEXPECTED_CHARACTER => Some(MochaError::UnexpectedCharacter),
204 _ => None,
205 }
206}