use std::alloc::{self, Layout};
use std::ffi::c_void;
use std::ptr;
use yyjson_sys as ffi;
#[repr(transparent)]
pub struct YyjsonAllocator<'a> {
pub(crate) p: *mut ffi::yyjson_alc,
pub(crate) _lifetime: std::marker::PhantomData<&'a ()>,
}
pub trait YyjsonAllocProvider {
fn get_allocator<'a>(&'a self) -> YyjsonAllocator<'a>;
}
pub struct BasicAllocProvider {}
impl Default for BasicAllocProvider {
fn default() -> Self {
return BasicAllocProvider {};
}
}
impl YyjsonAllocProvider for BasicAllocProvider {
fn get_allocator<'a>(&'a self) -> YyjsonAllocator<'a> {
YyjsonAllocator {
p: ptr::null_mut(),
_lifetime: std::marker::PhantomData,
}
}
}
pub struct PoolAllocProvider {
alc: *mut ffi::yyjson_alc,
buf: *mut u8,
layout: Layout,
}
impl Drop for PoolAllocProvider {
fn drop(&mut self) {
unsafe { alloc::dealloc(self.buf, self.layout) };
let _ = unsafe { Box::from_raw(self.alc) };
}
}
impl YyjsonAllocProvider for PoolAllocProvider {
#[inline(always)]
fn get_allocator<'a>(&'a self) -> YyjsonAllocator<'a> {
YyjsonAllocator {
p: self.alc,
_lifetime: std::marker::PhantomData,
}
}
}
impl PoolAllocProvider {
pub fn new(
expected_json_size: usize,
options: Option<&crate::ReadOptions>,
) -> Result<Self, &'static str> {
let flag = if let Some(v) = options {
v.to_read_flag()
} else {
ffi::YYJSON_READ_NOFLAG
};
let buf_size = unsafe { ffi::yyjson_read_max_memory_usage(expected_json_size, flag) };
let layout = match Layout::from_size_align(buf_size, 64) {
Ok(l) => l,
Err(_) => {
return Err("align should be non-zero and a power of 2, size should not overflow")
}
};
let buf: *mut u8 = unsafe { alloc::alloc(layout) };
if buf.is_null() {
return Err("allocator returned null");
}
let alc: *mut ffi::yyjson_alc = {
let b = Box::new(ffi::yyjson_alc {
malloc: None,
realloc: None,
free: None,
ctx: ptr::null_mut(),
});
Box::into_raw(b)
};
let sb = PoolAllocProvider { alc, buf, layout };
let ok: bool = unsafe { ffi::yyjson_alc_pool_init(alc, buf.cast::<c_void>(), buf_size) };
if !ok {
return Err("Failed to initialized pool allocator, buf or size invalid");
}
Ok(sb)
}
}
#[repr(transparent)]
pub struct DynamicAllocProvider {
alc: *mut ffi::yyjson_alc,
}
impl Default for DynamicAllocProvider {
fn default() -> Self {
let alc: *mut ffi::yyjson_alc = unsafe { ffi::yyjson_alc_dyn_new() };
Self { alc }
}
}
impl YyjsonAllocProvider for DynamicAllocProvider {
#[inline(always)]
fn get_allocator<'a>(&'a self) -> YyjsonAllocator<'a> {
YyjsonAllocator {
p: self.alc,
_lifetime: std::marker::PhantomData,
}
}
}
impl Drop for DynamicAllocProvider {
fn drop(&mut self) {
unsafe { ffi::yyjson_alc_dyn_free(self.alc) }
}
}