1use core::{alloc::Layout, mem::MaybeUninit, ptr::NonNull};
2
3use alloc::{boxed::Box, vec::Vec};
4
5use crate::{alloc_shim::Allocator, Allocation};
6
7#[derive(Debug, Clone)]
9#[non_exhaustive]
10pub enum BoxConversionError {
11 LayoutMismatch {
13 expected: Layout,
15 allocated: Layout,
17 },
18}
19
20impl BoxConversionError {
21 fn layout_mismatch(expected: Layout, allocated: Layout) -> Self {
22 Self::LayoutMismatch {
23 expected,
24 allocated,
25 }
26 }
27}
28
29#[derive(Debug, Clone)]
31#[non_exhaustive]
32pub enum VecConversionError {
33 AlignMismatch {
35 expected: usize,
37 allocated: usize,
39 },
40 SlackCapacity {
43 element_size: usize,
45 allocated: usize,
47 },
48 ZeroSizedElements,
54}
55
56impl VecConversionError {
57 fn align_mismatch(expected: usize, allocated: usize) -> Self {
58 Self::AlignMismatch {
59 expected,
60 allocated,
61 }
62 }
63 fn slack_capacity(element_size: usize, allocated: usize) -> Self {
64 Self::SlackCapacity {
65 element_size,
66 allocated,
67 }
68 }
69 fn zero_sized_elements() -> Self {
70 Self::ZeroSizedElements
71 }
72}
73
74impl<T> TryFrom<crate::Allocation> for Box<MaybeUninit<T>> {
80 type Error = BoxConversionError;
81 fn try_from(alloc: crate::Allocation) -> Result<Self, Self::Error> {
82 alloc.try_into_box::<T>()
83 }
84}
85
86fn check_box_layout<A: Allocator, T>(allocation: &Allocation<A>) -> Result<(), BoxConversionError> {
87 let expected = Layout::new::<T>();
88 let actual = allocation.layout();
89 if expected != actual {
90 return Err(BoxConversionError::layout_mismatch(expected, actual));
91 }
92 Ok(())
93}
94fn check_vec_layout<A: Allocator, T>(
98 allocation: &Allocation<A>,
99) -> Result<usize, VecConversionError> {
100 let expected = Layout::new::<T>();
101 let actual = allocation.layout();
102 let element_align = expected.align();
103 let alloc_align = actual.align();
104 if element_align != alloc_align {
105 return Err(VecConversionError::align_mismatch(
106 element_align,
107 alloc_align,
108 ));
109 }
110 let element_size = expected.size();
111 let byte_capacity = actual.size();
112 #[allow(clippy::manual_is_multiple_of)] if (element_size == 0 && byte_capacity != 0) || byte_capacity % element_size != 0 {
114 return Err(VecConversionError::slack_capacity(
115 element_size,
116 byte_capacity,
117 ));
118 }
119 if element_size == 0 {
120 return Err(VecConversionError::zero_sized_elements());
124 }
125
126 let element_capacity = byte_capacity / element_size;
127 debug_assert!(byte_capacity == element_size * element_capacity);
128 Ok(element_capacity)
129}
130
131impl<T> TryFrom<crate::Allocation> for Vec<T> {
132 type Error = VecConversionError;
133
134 fn try_from(value: crate::Allocation) -> Result<Self, Self::Error> {
135 value.try_into_vec()
136 }
137}
138
139#[cfg(feature = "nightly-std-conversions")]
140mod alloc_allocator_api {
141 macro_rules! box_to_parts {
142 ($value:ident) => {
143 Box::into_raw_with_allocator($value)
144 };
145 }
146 macro_rules! vec_to_parts {
147 ($vec:ident) => {
148 Vec::into_raw_parts_with_alloc($vec)
149 };
150 }
151 macro_rules! box_from_parts {
152 ($ptr:expr, $alloc:expr) => {{
153 Box::from_raw_in($ptr, $alloc)
154 }};
155 }
156 macro_rules! vec_from_parts {
157 ($ptr:expr, $cap:expr, $alloc:expr) => {{
158 Vec::from_raw_parts_in($ptr, 0, $cap, $alloc)
159 }};
160 }
161 macro_rules! allocation_impl {
162 ( $( $imp:tt )* ) => {
163 type ABox<T, A> = alloc::boxed::Box<T, A>;
164 type AVec<T, A> = alloc::vec::Vec<T, A>;
165 impl<A: Allocator> crate::Allocation<A> {
166 $( $imp )*
167 }
168 };
169 }
170 macro_rules! from_box_impl {
171 ( $( #[doc = $doc:literal] )*
172 struct DocAnchor;
173 $( $imp:tt )*
174 ) => {
175 $( #[doc = $doc ] )*
176 impl<T: ?Sized, A: Allocator> From<Box<T, A>> for crate::Allocation<A> {
177 $( $imp )*
178 }
179 };
180 }
181 macro_rules! from_vec_impl {
182 ( $( #[doc = $doc:literal] )*
183 struct DocAnchor;
184 $( $imp:tt )*
185 ) => {
186 $( #[doc = $doc ] )*
187 impl<T, A: Allocator> From<Vec<T, A>> for crate::Allocation<A> {
188 $( $imp )*
189 }
190 };
191 }
192 pub(super) use allocation_impl;
193 pub(super) use box_from_parts;
194 pub(super) use box_to_parts;
195 pub(super) use from_box_impl;
196 pub(super) use from_vec_impl;
197 pub(super) use vec_from_parts;
198 pub(super) use vec_to_parts;
199}
200
201#[cfg(not(feature = "nightly-std-conversions"))]
202mod alloc_no_allocator_api {
203 macro_rules! box_to_parts {
204 ($value:ident) => {
205 (Box::into_raw($value), $crate::alloc_shim::Global)
206 };
207 }
208
209 macro_rules! vec_to_parts {
210 ($vec:ident) => {{
211 let mut $vec = core::mem::ManuallyDrop::new($vec);
212 (
214 $vec.as_mut_ptr(),
215 $vec.len(),
216 $vec.capacity(),
217 $crate::alloc_shim::Global,
218 )
219 }};
220 }
221
222 macro_rules! box_from_parts {
223 ($ptr:expr, $alloc:expr) => {{
224 let _: $crate::alloc_shim::Global = $alloc;
225 alloc::boxed::Box::from_raw($ptr)
226 }};
227 }
228 macro_rules! vec_from_parts {
229 ($ptr:expr, $cap:expr, $alloc:expr) => {{
230 let _: $crate::alloc_shim::Global = $alloc;
231 alloc::vec::Vec::from_raw_parts($ptr, 0, $cap)
232 }};
233 }
234
235 macro_rules! allocation_impl {
236 ( $( $imp:tt )* ) => {
237 pub trait UseA<A> { type This: ?Sized; }
238 impl<A, T: ?Sized> UseA<A> for T { type This = Self; }
239 type ABox<T, A> = <alloc::boxed::Box<T> as UseA<A>>::This;
240 type AVec<T, A> = <alloc::vec::Vec<T> as UseA<A>>::This;
241
242 type A = $crate::alloc_shim::Global;
243 impl<> crate::Allocation<> {
244 $( $imp )*
245 }
246 };
247 }
248 macro_rules! from_box_impl {
249 ( $( #[doc = $doc:literal] )*
250 struct DocAnchor;
251 $( $imp:tt )*
252 ) => {
253 $( #[doc = $doc ] )*
254 impl<T: ?Sized> From<Box<T>> for crate::Allocation {
255 $( $imp )*
256 }
257 };
258 }
259 macro_rules! from_vec_impl {
260 ( $( #[doc = $doc:literal] )*
261 struct DocAnchor;
262 $( $imp:tt )*
263 ) => {
264 $( #[doc = $doc ] )*
265 impl<T> From<Vec<T>> for crate::Allocation {
266 $( $imp )*
267 }
268 };
269 }
270 pub(super) use allocation_impl;
271 pub(super) use box_from_parts;
272 pub(super) use box_to_parts;
273 pub(super) use from_box_impl;
274 pub(super) use from_vec_impl;
275 pub(super) use vec_from_parts;
276 pub(super) use vec_to_parts;
277}
278
279#[cfg(feature = "nightly-std-conversions")]
280use alloc_allocator_api as api_impl;
281#[cfg(not(feature = "nightly-std-conversions"))]
282use alloc_no_allocator_api as api_impl;
283
284api_impl::allocation_impl! {
285 pub fn try_into_box<T>(self) -> Result<ABox<MaybeUninit<T>, A>, BoxConversionError> {
293 let () = check_box_layout::<_, T>(&self)?;
294 let (ptr, _, alloc) = self.into_parts_with_alloc();
296 let ptr = ptr.as_ptr().cast();
297 Ok(unsafe { api_impl::box_from_parts!(ptr, alloc) })
299 }
300
301 pub fn try_into_vec<T>(self) -> Result<AVec<T, A>, VecConversionError> {
311 let capacity = check_vec_layout::<_, T>(&self)?;
312 let (ptr, _, alloc) = self.into_parts_with_alloc();
313 let ptr = ptr.as_ptr().cast();
314 Ok(unsafe { api_impl::vec_from_parts!(ptr, capacity, alloc) })
315 }
316}
317
318api_impl::from_box_impl! {
321 struct DocAnchor;
334
335 fn from(value: ABox<T, A>) -> Self {
336 let layout = Layout::for_value(&*value);
337 let (ptr, alloc) = api_impl::box_to_parts!(value);
338 let ptr = unsafe { NonNull::new_unchecked(ptr) };
339 unsafe { Self::from_parts_in(ptr.cast(), layout, alloc) }
340 }
341}
342
343api_impl::from_vec_impl! {
346 struct DocAnchor;
358
359 fn from(value: AVec<T, A>) -> Self {
360 let mut value = value;
361 unsafe { value.set_len(0) };
362 let layout = Layout::for_value(value.spare_capacity_mut());
363 let (ptr, _, _, alloc) = api_impl::vec_to_parts!(value);
364 let ptr = unsafe { NonNull::new_unchecked(ptr) };
365 unsafe { Self::from_parts_in(ptr.cast(), layout, alloc) }
366 }
367}