rquickjs_core/
allocator.rs1use crate::qjs;
4
5mod rust;
6
7use alloc::boxed::Box;
8pub use rust::RustAllocator;
9
10pub unsafe trait Allocator {
21 fn alloc(&mut self, size: usize) -> *mut u8;
25
26 fn calloc(&mut self, count: usize, size: usize) -> *mut u8;
30
31 unsafe fn dealloc(&mut self, ptr: *mut u8);
37
38 unsafe fn realloc(&mut self, ptr: *mut u8, new_size: usize) -> *mut u8;
44
45 unsafe fn usable_size(ptr: *mut u8) -> usize
51 where
52 Self: Sized;
53}
54
55type DynAllocator = Box<dyn Allocator>;
56
57#[derive(Debug)]
58pub(crate) struct AllocatorHolder(*mut DynAllocator);
59
60impl Drop for AllocatorHolder {
61 fn drop(&mut self) {
62 let _ = unsafe { Box::from_raw(self.0) };
63 }
64}
65
66#[allow(clippy::extra_unused_type_parameters)]
67impl AllocatorHolder {
68 pub(crate) fn functions<A>() -> qjs::JSMallocFunctions
69 where
70 A: Allocator,
71 {
72 qjs::JSMallocFunctions {
73 js_calloc: Some(Self::calloc::<A>),
74 js_malloc: Some(Self::malloc::<A>),
75 js_free: Some(Self::free::<A>),
76 js_realloc: Some(Self::realloc::<A>),
77 js_malloc_usable_size: Some(Self::malloc_usable_size::<A>),
78 }
79 }
80
81 pub(crate) fn new<A>(allocator: A) -> Self
82 where
83 A: Allocator + 'static,
84 {
85 Self(Box::into_raw(Box::new(Box::new(allocator))))
86 }
87
88 pub(crate) fn opaque_ptr(&self) -> *mut DynAllocator {
89 self.0
90 }
91
92 unsafe extern "C" fn calloc<A>(
93 opaque: *mut qjs::c_void,
94 count: qjs::size_t,
95 size: qjs::size_t,
96 ) -> *mut qjs::c_void
97 where
98 A: Allocator,
99 {
100 let allocator = &mut *(opaque as *mut DynAllocator);
101 let rust_size: usize = size.try_into().expect(qjs::SIZE_T_ERROR);
102 let rust_count: usize = count.try_into().expect(qjs::SIZE_T_ERROR);
103 allocator.calloc(rust_count, rust_size) as *mut qjs::c_void
104 }
105
106 unsafe extern "C" fn malloc<A>(opaque: *mut qjs::c_void, size: qjs::size_t) -> *mut qjs::c_void
107 where
108 A: Allocator,
109 {
110 let allocator = &mut *(opaque as *mut DynAllocator);
111 let rust_size: usize = size.try_into().expect(qjs::SIZE_T_ERROR);
112 allocator.alloc(rust_size) as *mut qjs::c_void
113 }
114
115 unsafe extern "C" fn free<A>(opaque: *mut qjs::c_void, ptr: *mut qjs::c_void)
116 where
117 A: Allocator,
118 {
119 if ptr.is_null() {
121 return;
123 }
124
125 let allocator = &mut *(opaque as *mut DynAllocator);
126 allocator.dealloc(ptr as _);
127 }
128
129 unsafe extern "C" fn realloc<A>(
130 opaque: *mut qjs::c_void,
131 ptr: *mut qjs::c_void,
132 size: qjs::size_t,
133 ) -> *mut qjs::c_void
134 where
135 A: Allocator,
136 {
137 let rust_size: usize = size.try_into().expect(qjs::SIZE_T_ERROR);
138 let allocator = &mut *(opaque as *mut DynAllocator);
139 allocator.realloc(ptr as _, rust_size) as *mut qjs::c_void
140 }
141
142 unsafe extern "C" fn malloc_usable_size<A>(ptr: *const qjs::c_void) -> qjs::size_t
143 where
144 A: Allocator,
145 {
146 if ptr.is_null() {
148 return 0;
149 }
150 A::usable_size(ptr as _).try_into().unwrap()
151 }
152}