mocha_rs/
lib.rs

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}