1use core::ffi::{c_uint, c_void};
3
4extern crate alloc;
5
6use alloc::alloc::Layout;
7pub use alloc::boxed::Box;
8use core::{mem, ptr};
9
10#[cfg(not(any(target_os = "macos", all(windows, target_pointer_width = "64"))))]
12const MIN_ALIGN: usize = 8;
13#[cfg(any(target_os = "macos", all(windows, target_pointer_width = "64")))]
15const MIN_ALIGN: usize = 16;
16
17const LAYOUT_OFFSET: usize = mem::size_of::<usize>();
18
19#[cold]
20#[inline(never)]
21fn unlikely_null() -> *mut c_void {
22 ptr::null_mut()
23}
24
25#[inline]
26pub unsafe extern "C" fn compu_malloc(size: usize) -> *mut c_void {
28 if let Ok(layout) = Layout::from_size_align(size + LAYOUT_OFFSET, MIN_ALIGN) {
29 let mem = alloc::alloc::alloc(layout);
30 if !mem.is_null() {
31 ptr::write(mem as *mut usize, size);
32 return mem.add(LAYOUT_OFFSET) as _;
33 }
34 }
35
36 unlikely_null()
37}
38
39#[inline]
40pub unsafe extern "C" fn compu_free(mem: *mut c_void) {
42 if !mem.is_null() {
43 let mem = (mem as *mut u8).offset(-(LAYOUT_OFFSET as isize));
44 let size = ptr::read(mem as *const usize);
45 let layout = Layout::from_size_align_unchecked(size + LAYOUT_OFFSET, MIN_ALIGN);
46 alloc::alloc::dealloc(mem, layout);
47 }
48}
49
50#[allow(unused)]
51pub(crate) unsafe extern "C" fn compu_malloc_with_state(
53 _: *mut c_void,
54 size: usize,
55) -> *mut c_void {
56 compu_malloc(size)
57}
58
59#[allow(unused)]
60pub(crate) unsafe extern "C" fn compu_alloc(
62 _: *mut c_void,
63 items: c_uint,
64 size: c_uint,
65) -> *mut c_void {
66 let size = match (items as usize).checked_mul(size as usize) {
67 Some(0) | None => return unlikely_null(),
68 Some(size) => size,
69 };
70 compu_malloc(size)
71}
72
73#[allow(unused)]
74pub(crate) unsafe extern "C" fn compu_free_with_state(_: *mut c_void, mem: *mut c_void) {
75 compu_free(mem)
76}
77
78#[cfg(feature = "brotli-rust")]
79pub mod brotli_rust {
81 extern crate alloc;
82
83 use super::Box;
84 use alloc::vec::Vec;
85
86 pub struct BoxedSlice<T>(Box<[T]>);
88
89 impl<T> Default for BoxedSlice<T> {
90 #[inline(always)]
91 fn default() -> Self {
92 Self(Vec::new().into_boxed_slice())
93 }
94 }
95 impl<T> brotli::SliceWrapper<T> for BoxedSlice<T> {
96 #[inline(always)]
97 fn slice(&self) -> &[T] {
98 &self.0
99 }
100 }
101
102 impl<T> brotli::SliceWrapperMut<T> for BoxedSlice<T> {
103 #[inline(always)]
104 fn slice_mut(&mut self) -> &mut [T] {
105 &mut self.0
106 }
107 }
108
109 #[derive(Copy, Clone, Default)]
110 pub struct BrotliAllocator;
112
113 impl<T: Default> brotli::Allocator<T> for BrotliAllocator {
114 type AllocatedMemory = BoxedSlice<T>;
115 fn alloc_cell(&mut self, len: usize) -> Self::AllocatedMemory {
116 let mut vec = Vec::with_capacity(len);
117 for _ in 0..len {
118 vec.push(Default::default());
119 }
120 BoxedSlice(vec.into_boxed_slice())
121 }
122
123 fn free_cell(&mut self, _data: Self::AllocatedMemory) {}
124 }
125
126 impl brotli::enc::BrotliAlloc for BrotliAllocator {}
127}