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