1use std::{
3 borrow::Borrow,
4 ffi::c_void,
5 marker::PhantomData,
6 ops::{Deref, DerefMut},
7 ptr::NonNull,
8};
9
10#[cfg(feature = "allocator_api")]
11use allocator_api2::alloc;
12
13use crate::{
14 error::{Error, Result},
15 ffi,
16};
17
18#[derive(Debug)]
28pub struct Allocator<'ctx> {
29 pub(crate) inner: ffi::Allocator,
30 _phan: PhantomData<&'ctx ()>,
31}
32
33impl Allocator<'_> {
34 pub(crate) fn to_raw(&self) -> *const ffi::Allocator {
35 std::ptr::from_ref(&self.inner)
36 }
37 pub(crate) unsafe fn from_raw(raw: *const ffi::Allocator) -> Self {
38 Self {
39 inner: unsafe { *raw },
40 _phan: PhantomData,
41 }
42 }
43}
44
45#[derive(Debug)]
48pub(crate) struct Object<'alloc, T> {
49 pub(crate) ptr: NonNull<T>,
50 _phan: PhantomData<&'alloc ffi::Allocator>,
51}
52
53impl<T> Object<'_, T> {
54 pub(crate) fn new(raw: *mut T) -> Result<Self> {
55 let ptr = NonNull::new(raw).ok_or(Error::OutOfMemory)?;
56 Ok(Self {
57 ptr,
58 _phan: PhantomData,
59 })
60 }
61 pub(crate) fn as_raw(&self) -> *mut T {
62 self.ptr.as_ptr()
63 }
64}
65
66#[derive(Debug)]
68pub(crate) struct Ref<'a, T> {
69 pub(crate) ptr: NonNull<T>,
70 _phan: PhantomData<&'a ()>,
71}
72
73impl<T> Ref<'_, T> {
74 pub(crate) fn new(raw: *mut T) -> Result<Self> {
75 let ptr = NonNull::new(raw).ok_or(Error::OutOfMemory)?;
76 Ok(Self {
77 ptr,
78 _phan: PhantomData,
79 })
80 }
81 pub(crate) fn as_raw(&self) -> *mut T {
82 self.ptr.as_ptr()
83 }
84}
85
86#[derive(Debug)]
88pub struct Bytes<'alloc> {
89 ptr: NonNull<u8>,
90 len: usize,
91 alloc: *const ffi::Allocator,
92 _phan: PhantomData<&'alloc ffi::Allocator>,
93}
94impl<'alloc> Bytes<'alloc> {
95 pub fn new(len: usize) -> Result<Self> {
99 unsafe { Self::new_inner(std::ptr::null(), len) }
101 }
102
103 pub fn new_with_alloc<'ctx: 'alloc>(
107 alloc: &'alloc Allocator<'ctx>,
108 len: usize,
109 ) -> Result<Self> {
110 unsafe { Self::new_inner(alloc.to_raw(), len) }
112 }
113
114 unsafe fn new_inner(alloc: *const ffi::Allocator, len: usize) -> Result<Self> {
115 let raw = unsafe { ffi::ghostty_alloc(alloc, len) };
116 let ptr = NonNull::new(raw).ok_or(Error::OutOfMemory)?;
117 Ok(unsafe { Self::from_raw_parts(ptr, len, alloc) })
118 }
119
120 pub(crate) unsafe fn from_raw_parts(
121 ptr: NonNull<u8>,
122 len: usize,
123 alloc: *const ffi::Allocator,
124 ) -> Self {
125 Self {
126 ptr,
127 len,
128 alloc,
129 _phan: PhantomData,
130 }
131 }
132}
133impl Drop for Bytes<'_> {
134 fn drop(&mut self) {
135 unsafe { ffi::ghostty_free(self.alloc, self.ptr.as_ptr(), self.len) };
139 }
140}
141impl Deref for Bytes<'_> {
142 type Target = [u8];
143
144 #[inline]
145 fn deref(&self) -> &Self::Target {
146 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
148 }
149}
150impl DerefMut for Bytes<'_> {
151 #[inline]
152 fn deref_mut(&mut self) -> &mut Self::Target {
153 unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
155 }
156}
157impl AsRef<[u8]> for Bytes<'_> {
158 fn as_ref(&self) -> &[u8] {
159 self
160 }
161}
162impl AsMut<[u8]> for Bytes<'_> {
163 fn as_mut(&mut self) -> &mut [u8] {
164 self
165 }
166}
167impl Borrow<[u8]> for Bytes<'_> {
168 fn borrow(&self) -> &[u8] {
169 self
170 }
171}
172impl<'a> IntoIterator for &'a Bytes<'_> {
173 type Item = &'a u8;
174 type IntoIter = std::slice::Iter<'a, u8>;
175
176 fn into_iter(self) -> Self::IntoIter {
177 self.deref().iter()
178 }
179}
180
181impl Allocator<'static> {
186 pub const GLOBAL: Self = Self {
189 inner: ffi::Allocator {
190 ctx: std::ptr::null_mut(),
191 vtable: &ffi::AllocatorVtable {
192 alloc: Some(_global_alloc),
193 free: Some(_global_free),
194 resize: Some(_global_resize),
195 remap: Some(_global_remap),
196 },
197 },
198 _phan: PhantomData,
199 };
200}
201
202unsafe extern "C" fn _global_alloc(
203 _allocator: *mut c_void,
204 len: usize,
205 alignment: u8,
206 _ret_addr: usize,
207) -> *mut c_void {
208 let Ok(layout) = std::alloc::Layout::from_size_align(len, 1 << alignment) else {
209 return std::ptr::null_mut();
210 };
211 unsafe { std::alloc::alloc(layout).cast::<c_void>() }
212}
213
214unsafe extern "C" fn _global_free(
215 _allocator: *mut c_void,
216 mem: *mut c_void,
217 len: usize,
218 alignment: u8,
219 _ret_addr: usize,
220) {
221 let Ok(layout) = std::alloc::Layout::from_size_align(len, 1 << alignment) else {
222 return;
223 };
224 unsafe { std::alloc::dealloc(mem.cast::<u8>(), layout) }
225}
226unsafe extern "C" fn _global_resize(
227 _allocator: *mut c_void,
228 _mem: *mut c_void,
229 _old_len: usize,
230 _alignment: u8,
231 _new_len: usize,
232 _ret_addr: usize,
233) -> bool {
234 false
235}
236unsafe extern "C" fn _global_remap(
237 _allocator: *mut c_void,
238 mem: *mut c_void,
239 old_len: usize,
240 alignment: u8,
241 new_len: usize,
242 _ret_addr: usize,
243) -> *mut c_void {
244 let Ok(layout) = std::alloc::Layout::from_size_align(old_len, 1 << alignment) else {
245 return std::ptr::null_mut();
246 };
247 unsafe { std::alloc::realloc(mem.cast::<u8>(), layout, new_len).cast::<c_void>() }
248}
249
250#[cfg(feature = "allocator_api")]
256impl<'ctx, A: alloc::Allocator + 'ctx> From<A> for Allocator<'ctx> {
257 fn from(value: A) -> Self {
258 Self {
259 inner: ffi::Allocator {
260 ctx: std::ptr::from_ref(value.by_ref()) as *mut std::ffi::c_void,
261 vtable: &ffi::AllocatorVtable {
262 alloc: Some(_alloc::<A>),
263 free: Some(_free::<A>),
264 resize: Some(_resize),
265 remap: Some(_remap::<A>),
266 },
267 },
268 _phan: PhantomData,
269 }
270 }
271}
272
273#[cfg(feature = "allocator_api")]
274unsafe extern "C" fn _alloc<A: alloc::Allocator>(
275 allocator: *mut c_void,
276 len: usize,
277 alignment: u8,
278 _ret_addr: usize,
279) -> *mut c_void {
280 let layout = alloc::Layout::from_size_align(len, 1 << alignment).ok();
281
282 unsafe { get_allocator::<A>(allocator) }
283 .and_then(|alloc| alloc.allocate(layout?).ok())
284 .map(|p| p.as_ptr().cast::<c_void>())
285 .unwrap_or(std::ptr::null_mut())
286}
287
288#[cfg(feature = "allocator_api")]
289unsafe extern "C" fn _free<A: alloc::Allocator>(
290 allocator: *mut c_void,
291 mem: *mut c_void,
292 len: usize,
293 alignment: u8,
294 _ret_addr: usize,
295) {
296 let Some(mem) = NonNull::new(mem.cast::<u8>()) else {
297 return;
298 };
299 let Some(layout) = alloc::Layout::from_size_align(len, 1 << alignment).ok() else {
300 return;
301 };
302 if let Some(alloc) = unsafe { get_allocator::<A>(allocator) } {
303 unsafe { alloc.deallocate(mem, layout) };
304 }
305}
306
307#[cfg(feature = "allocator_api")]
315unsafe extern "C" fn _resize(
316 _allocator: *mut c_void,
317 _mem: *mut c_void,
318 _old_len: usize,
319 _alignment: u8,
320 _new_len: usize,
321 _ret_addr: usize,
322) -> bool {
323 false
324}
325
326#[cfg(feature = "allocator_api")]
329unsafe extern "C" fn _remap<A: alloc::Allocator>(
330 allocator: *mut c_void,
331 mem: *mut c_void,
332 old_len: usize,
333 alignment: u8,
334 new_len: usize,
335 _ret_addr: usize,
336) -> *mut c_void {
337 let mem = NonNull::new(mem.cast::<u8>());
338 let old_layout = alloc::Layout::from_size_align(old_len, 1 << alignment).ok();
339 let new_layout = alloc::Layout::from_size_align(new_len, 1 << alignment).ok();
340
341 unsafe { get_allocator::<A>(allocator) }
342 .and_then(|alloc| {
343 if new_len < old_len {
344 unsafe { alloc.shrink(mem?, old_layout?, new_layout?) }.ok()
345 } else {
346 unsafe { alloc.grow(mem?, old_layout?, new_layout?) }.ok()
347 }
348 })
349 .map(|p| p.as_ptr().cast::<c_void>())
350 .unwrap_or(std::ptr::null_mut())
351}
352
353#[inline(always)]
365#[cfg(feature = "allocator_api")]
366unsafe fn get_allocator<'a, A: alloc::Allocator>(ptr: *mut c_void) -> Option<&'a A> {
367 unsafe { ptr.cast::<A>().as_ref() }
368}