use crate::prelude::{Box, String, Vec};
use core::{
ffi::{CStr, c_char},
mem, ptr, slice,
};
type RustJson = crate::Json;
#[repr(C)]
pub enum Json {
Array { elems: *mut Json, len: usize },
Object { elems: *mut Pair, len: usize },
String(JsonString),
Number(f64),
True,
False,
Null,
Error,
}
#[repr(C)]
pub struct JsonString {
buf: *mut u8,
len: usize,
}
impl JsonString {
fn new(mut o: String) -> Self {
let len = o.len();
o.push('\0');
let mut data = o.into_boxed_str();
let buf = data.as_mut_ptr();
mem::forget(data);
Self { buf, len }
}
}
impl Drop for JsonString {
fn drop(&mut self) {
let elems = ptr::slice_from_raw_parts_mut(self.buf, self.len);
let b = unsafe { Box::from_raw(elems) };
mem::drop(b);
}
}
#[repr(C)]
pub struct Pair {
key: JsonString,
val: *mut Json,
}
impl Json {
fn from_json(json: RustJson) -> Self {
match json {
RustJson::Array(arr) => {
let elems = arr
.into_vec()
.into_iter()
.map(Json::from_json)
.collect::<Vec<_>>();
let len = elems.len();
let elems = vec_2_ptr(elems);
Json::Array { elems, len }
}
RustJson::Object(obj) => {
let elems = obj
.into_iter()
.map(|(k, v)| {
let string = JsonString::new(k.into_string());
let v = Json::from_json(v);
let v = Box::new(v);
Pair {
key: string,
val: Box::into_raw(v),
}
})
.collect::<Vec<_>>();
let len = elems.len();
let elems = vec_2_ptr(elems);
Json::Object { elems, len }
}
RustJson::String(s) => Json::String(JsonString::new(s.into_string())),
RustJson::Number(n) => Json::Number(n),
RustJson::True => Json::True,
RustJson::False => Json::False,
RustJson::Null => Json::Null,
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn json_deserialize(ptr: *const c_char) -> Json {
let cstr = unsafe { CStr::from_ptr(ptr) };
if let Ok(s) = cstr.to_str() {
if let Ok(json) = crate::Json::deserialize(s) {
return Json::from_json(json);
}
}
Json::Error
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn json_deserialize_with_config(
ptr: *const c_char,
conf: crate::JsonConfig,
) -> Json {
let cstr = unsafe { CStr::from_ptr(ptr) };
if let Ok(s) = cstr.to_str() {
if let Ok(json) = crate::Json::deserialize_with_config(s, conf) {
return Json::from_json(json);
}
}
Json::Error
}
fn ptr_2_vec<T>(ptr: *mut T, len: usize) -> Vec<T> {
let elems = unsafe {
let elems = slice::from_raw_parts_mut(ptr, len);
Box::from_raw(elems)
};
elems.into_vec()
}
fn vec_2_ptr<T>(vec: Vec<T>) -> *mut T {
let mut data = vec.into_boxed_slice();
let elems = data.as_mut_ptr();
mem::forget(data);
elems
}
#[unsafe(no_mangle)]
pub extern "C" fn json_free(json: Json) {
match json {
Json::Array { elems, len } => {
let elems = ptr_2_vec(elems, len);
for e in elems {
json_free(e);
}
}
Json::Object { elems, len } => {
let elems = ptr_2_vec(elems, len);
for Pair { key, val } in elems {
mem::drop(key);
let val = unsafe { Box::from_raw(val) };
json_free(*val);
}
}
Json::String(s) => {
mem::drop(s);
}
Json::Number(_) | Json::True | Json::False | Json::Null | Json::Error => {}
}
}