1use core::borrow::{Borrow, BorrowMut};
3use core::marker::PhantomData;
4use core::ops::{Deref, DerefMut};
5use core::ptr::NonNull;
6
7use osom_lib_alloc::traits::Allocator;
8use osom_lib_reprc::traits::ReprC;
9use osom_lib_try_clone::TryClone;
10
11use crate::errors::CBoxTryCloneError;
12
13use super::errors::CBoxError;
14use super::layout::CBoxLayout;
15
16#[repr(transparent)]
19#[must_use]
20#[derive(Debug)]
21pub struct CBox<T, TAllocator: Allocator> {
22 data: *mut u8,
23 _phantom: PhantomData<(T, TAllocator)>,
24}
25
26unsafe impl<T: ReprC, TAllocator: Allocator> ReprC for CBox<T, TAllocator> {
27 const CHECK: () = const {
28 osom_lib_reprc::hidden::is_reprc::<T>();
29 osom_lib_reprc::hidden::is_reprc::<TAllocator>();
30 };
31}
32
33impl<T, TAllocator: Allocator> CBox<T, TAllocator> {
34 const LAYOUT: CBoxLayout<T, TAllocator> = CBoxLayout::new();
35
36 #[inline]
42 pub fn new(value: T) -> Result<Self, CBoxError>
43 where
44 TAllocator: Default,
45 {
46 Self::with_allocator(value, TAllocator::default())
47 }
48
49 #[inline]
55 pub fn with_allocator(value: T, allocator: TAllocator) -> Result<Self, CBoxError> {
56 #[allow(unused_mut)]
57 let mut allocator = allocator;
58 let ptr = allocator
59 .allocate(Self::LAYOUT.total_layout)
60 .map_err(|_| CBoxError::AllocationError)?;
61 let mut result = Self {
62 data: ptr.as_ptr(),
63 _phantom: PhantomData,
64 };
65
66 unsafe {
67 CBox::allocator_ptr_mut(&mut result).write(allocator);
68 CBox::data_ptr_mut(&mut result).write(value);
69 }
70
71 Ok(result)
72 }
73
74 #[inline(always)]
76 #[must_use]
77 pub const fn data(box_: &Self) -> &T {
78 unsafe { &*CBox::data_ptr(box_) }
79 }
80
81 #[inline(always)]
83 #[must_use]
84 pub const fn data_mut(box_: &mut Self) -> &mut T {
85 unsafe { &mut *CBox::data_ptr_mut(box_) }
86 }
87
88 #[inline(always)]
92 #[must_use]
93 pub const fn data_ptr(box_: &Self) -> *const T {
94 unsafe { box_.data.add(Self::LAYOUT.data_offset).cast::<T>() }
95 }
96
97 #[inline(always)]
104 #[must_use]
105 pub const fn into_raw_ptr(box_: Self) -> *mut u8 {
106 let ptr = box_.data;
107 core::mem::forget(box_);
108 ptr
109 }
110
111 #[inline(always)]
122 pub const unsafe fn from_raw_ptr(ptr: *mut u8) -> Self {
123 Self {
124 data: ptr,
125 _phantom: PhantomData,
126 }
127 }
128
129 #[inline(always)]
133 #[must_use]
134 pub const fn data_ptr_mut(box_: &mut Self) -> *mut T {
135 unsafe { box_.data.add(Self::LAYOUT.data_offset).cast::<T>() }
136 }
137
138 #[inline]
141 #[must_use]
142 pub fn unpack(mut box_: Self) -> T {
143 let result = unsafe { CBox::drop(&mut box_) };
144 core::mem::forget(box_);
145 result
146 }
147
148 #[inline(always)]
149 const fn allocator_ref(box_: &Self) -> &TAllocator {
150 unsafe { &*CBox::allocator_ptr(box_) }
151 }
152
153 #[inline(always)]
154 #[must_use]
155 const fn allocator_ptr_mut(box_: &mut Self) -> *mut TAllocator {
156 unsafe { box_.data.add(Self::LAYOUT.allocator_offset).cast::<TAllocator>() }
157 }
158
159 #[inline(always)]
160 #[must_use]
161 const fn allocator_ptr(box_: &Self) -> *const TAllocator {
162 unsafe { box_.data.add(Self::LAYOUT.allocator_offset).cast::<TAllocator>() }
163 }
164
165 #[inline]
166 unsafe fn drop(box_: &mut Self) -> T {
167 unsafe {
168 let data = CBox::data_ptr(box_).read();
169 let mut allocator = CBox::allocator_ptr(box_).read();
170 allocator.deallocate(NonNull::new_unchecked(box_.data), Self::LAYOUT.total_layout);
171 data
172 }
173 }
174}
175
176impl<T, TAllocator: Allocator> Drop for CBox<T, TAllocator> {
177 fn drop(&mut self) {
178 let _ = unsafe { CBox::drop(self) };
179 }
180}
181
182impl<T, TAllocator: Allocator> AsRef<T> for CBox<T, TAllocator> {
183 fn as_ref(&self) -> &T {
184 CBox::data(self)
185 }
186}
187
188impl<T, TAllocator: Allocator> AsMut<T> for CBox<T, TAllocator> {
189 fn as_mut(&mut self) -> &mut T {
190 CBox::data_mut(self)
191 }
192}
193
194impl<T, TAllocator: Allocator> Borrow<T> for CBox<T, TAllocator> {
195 fn borrow(&self) -> &T {
196 CBox::data(self)
197 }
198}
199
200impl<T, TAllocator: Allocator> BorrowMut<T> for CBox<T, TAllocator> {
201 fn borrow_mut(&mut self) -> &mut T {
202 CBox::data_mut(self)
203 }
204}
205
206impl<T, TAllocator> TryClone for CBox<T, TAllocator>
207where
208 T: TryClone,
209 TAllocator: Allocator + TryClone,
210{
211 type Error = CBoxTryCloneError;
212
213 #[inline]
214 fn try_clone(&self) -> Result<Self, Self::Error> {
215 let data = CBox::data(self)
216 .try_clone()
217 .map_err(|_| CBoxTryCloneError::ItemCloningError)?;
218 let allocator = CBox::allocator_ref(self)
219 .try_clone()
220 .map_err(|_| CBoxTryCloneError::AllocatorCloningError)?;
221 Self::with_allocator(data, allocator).map_err(CBoxTryCloneError::from)
222 }
223}
224
225impl<T, TAllocator> Clone for CBox<T, TAllocator>
226where
227 T: TryClone,
228 TAllocator: Allocator + TryClone,
229{
230 fn clone(&self) -> Self {
231 self.try_clone().expect("Couldn't clone CBox")
232 }
233}
234
235impl<T, TAllocator: Allocator> Deref for CBox<T, TAllocator> {
236 type Target = T;
237
238 fn deref(&self) -> &Self::Target {
239 CBox::data(self)
240 }
241}
242
243impl<T, TAllocator: Allocator> DerefMut for CBox<T, TAllocator> {
244 fn deref_mut(&mut self) -> &mut Self::Target {
245 CBox::data_mut(self)
246 }
247}