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 if (element_size == 0 && byte_capacity != 0) || byte_capacity % element_size != 0 {
113 return Err(VecConversionError::slack_capacity(
114 element_size,
115 byte_capacity,
116 ));
117 }
118 if element_size == 0 {
119 return Err(VecConversionError::zero_sized_elements());
123 }
124
125 let element_capacity = byte_capacity / element_size;
126 debug_assert!(byte_capacity == element_size * element_capacity);
127 Ok(element_capacity)
128}
129
130impl<T> TryFrom<crate::Allocation> for Vec<T> {
131 type Error = VecConversionError;
132
133 fn try_from(value: crate::Allocation) -> Result<Self, Self::Error> {
134 value.try_into_vec()
135 }
136}
137
138#[cfg(feature = "nightly-std-conversions")]
139mod alloc_allocator_api {
140 macro_rules! box_to_parts {
141 ($value:ident) => {
142 Box::into_raw_with_allocator($value)
143 };
144 }
145 macro_rules! vec_to_parts {
146 ($vec:ident) => {
147 Vec::into_raw_parts_with_alloc($vec)
148 };
149 }
150 macro_rules! box_from_parts {
151 ($ptr:expr, $alloc:expr) => {{
152 Box::from_raw_in($ptr, $alloc)
153 }};
154 }
155 macro_rules! vec_from_parts {
156 ($ptr:expr, $cap:expr, $alloc:expr) => {{
157 Vec::from_raw_parts_in($ptr, 0, $cap, $alloc)
158 }};
159 }
160 macro_rules! allocation_impl {
161 ( $( $imp:tt )* ) => {
162 type ABox<T, A> = alloc::boxed::Box<T, A>;
163 type AVec<T, A> = alloc::vec::Vec<T, A>;
164 impl<A: Allocator> crate::Allocation<A> {
165 $( $imp )*
166 }
167 };
168 }
169 macro_rules! from_box_impl {
170 ( $( #[doc = $doc:literal] )*
171 struct DocAnchor;
172 $( $imp:tt )*
173 ) => {
174 $( #[doc = $doc ] )*
175 impl<T: ?Sized, A: Allocator> From<Box<T, A>> for crate::Allocation<A> {
176 $( $imp )*
177 }
178 };
179 }
180 macro_rules! from_vec_impl {
181 ( $( #[doc = $doc:literal] )*
182 struct DocAnchor;
183 $( $imp:tt )*
184 ) => {
185 $( #[doc = $doc ] )*
186 impl<T, A: Allocator> From<Vec<T, A>> for crate::Allocation<A> {
187 $( $imp )*
188 }
189 };
190 }
191 pub(super) use allocation_impl;
192 pub(super) use box_from_parts;
193 pub(super) use box_to_parts;
194 pub(super) use from_box_impl;
195 pub(super) use from_vec_impl;
196 pub(super) use vec_from_parts;
197 pub(super) use vec_to_parts;
198}
199
200#[cfg(not(feature = "nightly-std-conversions"))]
201mod alloc_no_allocator_api {
202 macro_rules! box_to_parts {
203 ($value:ident) => {
204 (Box::into_raw($value), $crate::alloc_shim::Global)
205 };
206 }
207
208 macro_rules! vec_to_parts {
209 ($vec:ident) => {{
210 let mut $vec = core::mem::ManuallyDrop::new($vec);
211 (
213 $vec.as_mut_ptr(),
214 $vec.len(),
215 $vec.capacity(),
216 $crate::alloc_shim::Global,
217 )
218 }};
219 }
220
221 macro_rules! box_from_parts {
222 ($ptr:expr, $alloc:expr) => {{
223 let _: $crate::alloc_shim::Global = $alloc;
224 alloc::boxed::Box::from_raw($ptr)
225 }};
226 }
227 macro_rules! vec_from_parts {
228 ($ptr:expr, $cap:expr, $alloc:expr) => {{
229 let _: $crate::alloc_shim::Global = $alloc;
230 alloc::vec::Vec::from_raw_parts($ptr, 0, $cap)
231 }};
232 }
233
234 macro_rules! allocation_impl {
235 ( $( $imp:tt )* ) => {
236 pub trait UseA<A> { type This: ?Sized; }
237 impl<A, T: ?Sized> UseA<A> for T { type This = Self; }
238 type ABox<T, A> = <alloc::boxed::Box<T> as UseA<A>>::This;
239 type AVec<T, A> = <alloc::vec::Vec<T> as UseA<A>>::This;
240
241 type A = $crate::alloc_shim::Global;
242 impl<> crate::Allocation<> {
243 $( $imp )*
244 }
245 };
246 }
247 macro_rules! from_box_impl {
248 ( $( #[doc = $doc:literal] )*
249 struct DocAnchor;
250 $( $imp:tt )*
251 ) => {
252 $( #[doc = $doc ] )*
253 impl<T: ?Sized> From<Box<T>> for crate::Allocation {
254 $( $imp )*
255 }
256 };
257 }
258 macro_rules! from_vec_impl {
259 ( $( #[doc = $doc:literal] )*
260 struct DocAnchor;
261 $( $imp:tt )*
262 ) => {
263 $( #[doc = $doc ] )*
264 impl<T> From<Vec<T>> for crate::Allocation {
265 $( $imp )*
266 }
267 };
268 }
269 pub(super) use allocation_impl;
270 pub(super) use box_from_parts;
271 pub(super) use box_to_parts;
272 pub(super) use from_box_impl;
273 pub(super) use from_vec_impl;
274 pub(super) use vec_from_parts;
275 pub(super) use vec_to_parts;
276}
277
278#[cfg(feature = "nightly-std-conversions")]
279use alloc_allocator_api as api_impl;
280#[cfg(not(feature = "nightly-std-conversions"))]
281use alloc_no_allocator_api as api_impl;
282
283api_impl::allocation_impl! {
284 pub fn try_into_box<T>(self) -> Result<ABox<MaybeUninit<T>, A>, BoxConversionError> {
292 let () = check_box_layout::<_, T>(&self)?;
293 let (ptr, _, alloc) = self.into_parts_with_alloc();
295 let ptr = ptr.as_ptr().cast();
296 Ok(unsafe { api_impl::box_from_parts!(ptr, alloc) })
298 }
299
300 pub fn try_into_vec<T>(self) -> Result<AVec<T, A>, VecConversionError> {
310 let capacity = check_vec_layout::<_, T>(&self)?;
311 let (ptr, _, alloc) = self.into_parts_with_alloc();
312 let ptr = ptr.as_ptr().cast();
313 Ok(unsafe { api_impl::vec_from_parts!(ptr, capacity, alloc) })
314 }
315}
316
317api_impl::from_box_impl! {
320 struct DocAnchor;
333
334 fn from(value: ABox<T, A>) -> Self {
335 let layout = Layout::for_value(&*value);
336 let (ptr, alloc) = api_impl::box_to_parts!(value);
337 let ptr = unsafe { NonNull::new_unchecked(ptr) };
338 unsafe { Self::from_parts_in(ptr.cast(), layout, alloc) }
339 }
340}
341
342api_impl::from_vec_impl! {
345 struct DocAnchor;
357
358 fn from(value: AVec<T, A>) -> Self {
359 let mut value = value;
360 unsafe { value.set_len(0) };
361 let layout = Layout::for_value(value.spare_capacity_mut());
362 let (ptr, _, _, alloc) = api_impl::vec_to_parts!(value);
363 let ptr = unsafe { NonNull::new_unchecked(ptr) };
364 unsafe { Self::from_parts_in(ptr.cast(), layout, alloc) }
365 }
366}