libbz2_rs_sys/
allocator.rs1#[cfg(feature = "rust-allocator")]
17extern crate alloc;
18
19use core::ffi::{c_int, c_void};
20
21use crate::bzlib::{BzStream, StreamState};
22
23type AllocFunc = unsafe extern "C" fn(*mut c_void, c_int, c_int) -> *mut c_void;
24type FreeFunc = unsafe extern "C" fn(*mut c_void, *mut c_void) -> ();
25
26pub(crate) enum Allocator {
27 #[cfg(feature = "rust-allocator")]
28 Rust,
29 #[cfg(feature = "c-allocator")]
30 C,
31 Custom {
32 allocate: AllocFunc,
33 deallocate: FreeFunc,
34 opaque: *mut c_void,
35 },
36}
37
38impl Allocator {
39 #[allow(unreachable_code)]
40 pub(crate) const DEFAULT: Option<Self> = 'blk: {
41 #[cfg(feature = "rust-allocator")]
42 break 'blk Some(Self::Rust);
43
44 #[cfg(feature = "c-allocator")]
45 break 'blk Some(Self::C);
46
47 None
48 };
49
50 #[allow(unreachable_code)]
51 pub(crate) fn default_function_pointers() -> Option<(AllocFunc, FreeFunc)> {
52 #[cfg(feature = "rust-allocator")]
53 return Some(rust_allocator::ALLOCATOR);
54
55 #[cfg(feature = "c-allocator")]
56 return Some(c_allocator::ALLOCATOR);
57
58 None
59 }
60
61 pub(crate) unsafe fn from_bz_stream<S: StreamState>(strm: &BzStream<S>) -> Option<Self> {
68 let bzalloc = strm.bzalloc?;
69 let bzfree = strm.bzfree?;
70
71 #[cfg(feature = "rust-allocator")]
72 if (bzalloc, bzfree) == rust_allocator::ALLOCATOR {
73 return Some(Self::Rust);
74 }
75
76 #[cfg(feature = "c-allocator")]
77 if (bzalloc, bzfree) == c_allocator::ALLOCATOR {
78 return Some(Self::C);
79 }
80
81 Some(Self::custom(bzalloc, bzfree, strm.opaque))
82 }
83
84 pub(crate) fn custom(allocate: AllocFunc, deallocate: FreeFunc, opaque: *mut c_void) -> Self {
91 Self::Custom {
92 allocate,
93 deallocate,
94 opaque,
95 }
96 }
97}
98
99#[cfg(feature = "c-allocator")]
100pub(crate) mod c_allocator {
101 use super::*;
102
103 pub(crate) static ALLOCATOR: (AllocFunc, FreeFunc) = (self::allocate, self::deallocate);
107
108 unsafe extern "C" fn allocate(_opaque: *mut c_void, count: c_int, size: c_int) -> *mut c_void {
109 unsafe { libc::malloc((count * size) as usize) }
110 }
111
112 unsafe extern "C" fn deallocate(_opaque: *mut c_void, ptr: *mut c_void) {
113 if !ptr.is_null() {
114 unsafe {
115 libc::free(ptr);
116 }
117 }
118 }
119}
120
121#[cfg(feature = "rust-allocator")]
122mod rust_allocator {
123 use super::*;
124
125 pub(crate) static ALLOCATOR: (AllocFunc, FreeFunc) = (self::allocate, self::deallocate);
129
130 unsafe extern "C" fn allocate(
131 _opaque: *mut c_void,
132 _count: c_int,
133 _size: c_int,
134 ) -> *mut c_void {
135 unreachable!("the default rust allocation function should never be called directly");
136 }
137
138 unsafe extern "C" fn deallocate(_opaque: *mut c_void, _ptr: *mut c_void) {
139 unreachable!("the default rust deallocation function should never be called directly");
140 }
141}
142
143impl Allocator {
144 pub(crate) fn allocate_zeroed<T>(&self, count: usize) -> Option<*mut T> {
146 const {
147 assert!(size_of::<T>() != 0);
148 }
149 assert_ne!(count, 0);
150
151 match self {
152 #[cfg(feature = "rust-allocator")]
153 Allocator::Rust => {
154 let layout = core::alloc::Layout::array::<T>(count).unwrap();
155 let ptr = unsafe { alloc::alloc::alloc_zeroed(layout) };
156 (!ptr.is_null()).then_some(ptr.cast())
157 }
158 #[cfg(feature = "c-allocator")]
159 Allocator::C => {
160 let ptr = unsafe { libc::calloc(count, core::mem::size_of::<T>()) };
161 (!ptr.is_null()).then_some(ptr.cast())
162 }
163 Allocator::Custom {
164 allocate, opaque, ..
165 } => unsafe {
166 let ptr = (allocate)(*opaque, count as i32, core::mem::size_of::<T>() as i32);
167 let ptr = ptr.cast::<T>();
168
169 if ptr.is_null() {
170 return None;
171 }
172
173 core::ptr::write_bytes(ptr, 0, count);
174
175 Some(ptr)
176 },
177 }
178 }
179
180 pub(crate) unsafe fn deallocate<T>(&self, ptr: *mut T, count: usize) {
181 if ptr.is_null() || count == 0 {
182 return;
183 }
184
185 match self {
186 #[cfg(feature = "rust-allocator")]
187 Allocator::Rust => {
188 let layout = core::alloc::Layout::array::<T>(count).unwrap();
189 unsafe { alloc::alloc::dealloc(ptr.cast(), layout) }
190 }
191 #[cfg(feature = "c-allocator")]
192 Allocator::C => {
193 unsafe { libc::free(ptr.cast()) };
194 }
195 Allocator::Custom {
196 deallocate, opaque, ..
197 } => {
198 unsafe { deallocate(*opaque, ptr.cast()) };
199 }
200 }
201 }
202}