1 | #![cfg (feature = "extern_crate_alloc" )]
|
2 |
|
3 | //! Stuff to boost things in the `alloc` crate.
|
4 | //!
|
5 | //! * You must enable the `extern_crate_alloc` feature of `bytemuck` or you will
|
6 | //! not be able to use this module! This is generally done by adding the
|
7 | //! feature to the dependency in Cargo.toml like so:
|
8 | //!
|
9 | //! `bytemuck = { version = "VERSION_YOU_ARE_USING", features =
|
10 | //! ["extern_crate_alloc"]}`
|
11 |
|
12 | use super::*;
|
13 | #[cfg (target_has_atomic = "ptr" )]
|
14 | use alloc::sync::Arc;
|
15 | use alloc::{
|
16 | alloc::{alloc_zeroed, Layout},
|
17 | boxed::Box,
|
18 | rc::Rc,
|
19 | vec,
|
20 | vec::Vec,
|
21 | };
|
22 | use core::ops::{Deref, DerefMut};
|
23 |
|
24 | /// As [`try_cast_box`](try_cast_box), but unwraps for you.
|
25 | #[inline ]
|
26 | pub fn cast_box<A: NoUninit, B: AnyBitPattern>(input: Box<A>) -> Box<B> {
|
27 | try_cast_box(input).map_err(|(e: PodCastError, _v: Box)| e).unwrap()
|
28 | }
|
29 |
|
30 | /// Attempts to cast the content type of a [`Box`](alloc::boxed::Box).
|
31 | ///
|
32 | /// On failure you get back an error along with the starting `Box`.
|
33 | ///
|
34 | /// ## Failure
|
35 | ///
|
36 | /// * The start and end content type of the `Box` must have the exact same
|
37 | /// alignment.
|
38 | /// * The start and end size of the `Box` must have the exact same size.
|
39 | #[inline ]
|
40 | pub fn try_cast_box<A: NoUninit, B: AnyBitPattern>(
|
41 | input: Box<A>,
|
42 | ) -> Result<Box<B>, (PodCastError, Box<A>)> {
|
43 | if align_of::<A>() != align_of::<B>() {
|
44 | Err((PodCastError::AlignmentMismatch, input))
|
45 | } else if size_of::<A>() != size_of::<B>() {
|
46 | Err((PodCastError::SizeMismatch, input))
|
47 | } else {
|
48 | // Note(Lokathor): This is much simpler than with the Vec casting!
|
49 | let ptr: *mut B = Box::into_raw(input) as *mut B;
|
50 | Ok(unsafe { Box::from_raw(ptr) })
|
51 | }
|
52 | }
|
53 |
|
54 | /// Allocates a `Box<T>` with all of the contents being zeroed out.
|
55 | ///
|
56 | /// This uses the global allocator to create a zeroed allocation and _then_
|
57 | /// turns it into a Box. In other words, it's 100% assured that the zeroed data
|
58 | /// won't be put temporarily on the stack. You can make a box of any size
|
59 | /// without fear of a stack overflow.
|
60 | ///
|
61 | /// ## Failure
|
62 | ///
|
63 | /// This fails if the allocation fails.
|
64 | #[inline ]
|
65 | pub fn try_zeroed_box<T: Zeroable>() -> Result<Box<T>, ()> {
|
66 | if size_of::<T>() == 0 {
|
67 | // This will not allocate but simply create a dangling pointer.
|
68 | let dangling: *mut T = core::ptr::NonNull::dangling().as_ptr();
|
69 | return Ok(unsafe { Box::from_raw(dangling) });
|
70 | }
|
71 | let layout: Layout = Layout::new::<T>();
|
72 | let ptr: *mut u8 = unsafe { alloc_zeroed(layout) };
|
73 | if ptr.is_null() {
|
74 | // we don't know what the error is because `alloc_zeroed` is a dumb API
|
75 | Err(())
|
76 | } else {
|
77 | Ok(unsafe { Box::<T>::from_raw(ptr as *mut T) })
|
78 | }
|
79 | }
|
80 |
|
81 | /// As [`try_zeroed_box`], but unwraps for you.
|
82 | #[inline ]
|
83 | pub fn zeroed_box<T: Zeroable>() -> Box<T> {
|
84 | try_zeroed_box().unwrap()
|
85 | }
|
86 |
|
87 | /// Allocates a `Vec<T>` of length and capacity exactly equal to `length` and
|
88 | /// all elements zeroed.
|
89 | ///
|
90 | /// ## Failure
|
91 | ///
|
92 | /// This fails if the allocation fails, or if a layout cannot be calculated for
|
93 | /// the allocation.
|
94 | pub fn try_zeroed_vec<T: Zeroable>(length: usize) -> Result<Vec<T>, ()> {
|
95 | if length == 0 {
|
96 | Ok(Vec::new())
|
97 | } else {
|
98 | let boxed_slice: Box<[T]> = try_zeroed_slice_box(length)?;
|
99 | Ok(boxed_slice.into_vec())
|
100 | }
|
101 | }
|
102 |
|
103 | /// As [`try_zeroed_vec`] but unwraps for you
|
104 | pub fn zeroed_vec<T: Zeroable>(length: usize) -> Vec<T> {
|
105 | try_zeroed_vec(length).unwrap()
|
106 | }
|
107 |
|
108 | /// Allocates a `Box<[T]>` with all contents being zeroed out.
|
109 | ///
|
110 | /// This uses the global allocator to create a zeroed allocation and _then_
|
111 | /// turns it into a Box. In other words, it's 100% assured that the zeroed data
|
112 | /// won't be put temporarily on the stack. You can make a box of any size
|
113 | /// without fear of a stack overflow.
|
114 | ///
|
115 | /// ## Failure
|
116 | ///
|
117 | /// This fails if the allocation fails, or if a layout cannot be calculated for
|
118 | /// the allocation.
|
119 | #[inline ]
|
120 | pub fn try_zeroed_slice_box<T: Zeroable>(
|
121 | length: usize,
|
122 | ) -> Result<Box<[T]>, ()> {
|
123 | if size_of::<T>() == 0 || length == 0 {
|
124 | // This will not allocate but simply create a dangling slice pointer.
|
125 | let dangling: *mut T = core::ptr::NonNull::dangling().as_ptr();
|
126 | let dangling_slice: *mut [T] = core::ptr::slice_from_raw_parts_mut(data:dangling, len:length);
|
127 | return Ok(unsafe { Box::from_raw(dangling_slice) });
|
128 | }
|
129 | let layout: Layout = core::alloc::Layout::array::<T>(length).map_err(|_| ())?;
|
130 | let ptr: *mut u8 = unsafe { alloc_zeroed(layout) };
|
131 | if ptr.is_null() {
|
132 | // we don't know what the error is because `alloc_zeroed` is a dumb API
|
133 | Err(())
|
134 | } else {
|
135 | let slice: &mut [T] =
|
136 | unsafe { core::slice::from_raw_parts_mut(data:ptr as *mut T, len:length) };
|
137 | Ok(unsafe { Box::<[T]>::from_raw(slice) })
|
138 | }
|
139 | }
|
140 |
|
141 | /// As [`try_zeroed_slice_box`](try_zeroed_slice_box), but unwraps for you.
|
142 | pub fn zeroed_slice_box<T: Zeroable>(length: usize) -> Box<[T]> {
|
143 | try_zeroed_slice_box(length).unwrap()
|
144 | }
|
145 |
|
146 | /// As [`try_cast_slice_box`](try_cast_slice_box), but unwraps for you.
|
147 | #[inline ]
|
148 | pub fn cast_slice_box<A: NoUninit, B: AnyBitPattern>(
|
149 | input: Box<[A]>,
|
150 | ) -> Box<[B]> {
|
151 | try_cast_slice_box(input).map_err(|(e: PodCastError, _v: Box<[A]>)| e).unwrap()
|
152 | }
|
153 |
|
154 | /// Attempts to cast the content type of a `Box<[T]>`.
|
155 | ///
|
156 | /// On failure you get back an error along with the starting `Box<[T]>`.
|
157 | ///
|
158 | /// ## Failure
|
159 | ///
|
160 | /// * The start and end content type of the `Box<[T]>` must have the exact same
|
161 | /// alignment.
|
162 | /// * The start and end content size in bytes of the `Box<[T]>` must be the
|
163 | /// exact same.
|
164 | #[inline ]
|
165 | pub fn try_cast_slice_box<A: NoUninit, B: AnyBitPattern>(
|
166 | input: Box<[A]>,
|
167 | ) -> Result<Box<[B]>, (PodCastError, Box<[A]>)> {
|
168 | if align_of::<A>() != align_of::<B>() {
|
169 | Err((PodCastError::AlignmentMismatch, input))
|
170 | } else if size_of::<A>() != size_of::<B>() {
|
171 | if size_of::<A>() * input.len() % size_of::<B>() != 0 {
|
172 | // If the size in bytes of the underlying buffer does not match an exact
|
173 | // multiple of the size of B, we cannot cast between them.
|
174 | Err((PodCastError::SizeMismatch, input))
|
175 | } else {
|
176 | // Because the size is an exact multiple, we can now change the length
|
177 | // of the slice and recreate the Box
|
178 | // NOTE: This is a valid operation because according to the docs of
|
179 | // std::alloc::GlobalAlloc::dealloc(), the Layout that was used to alloc
|
180 | // the block must be the same Layout that is used to dealloc the block.
|
181 | // Luckily, Layout only stores two things, the alignment, and the size in
|
182 | // bytes. So as long as both of those stay the same, the Layout will
|
183 | // remain a valid input to dealloc.
|
184 | let length = size_of::<A>() * input.len() / size_of::<B>();
|
185 | let box_ptr: *mut A = Box::into_raw(input) as *mut A;
|
186 | let ptr: *mut [B] =
|
187 | unsafe { core::slice::from_raw_parts_mut(box_ptr as *mut B, length) };
|
188 | Ok(unsafe { Box::<[B]>::from_raw(ptr) })
|
189 | }
|
190 | } else {
|
191 | let box_ptr: *mut [A] = Box::into_raw(input);
|
192 | let ptr: *mut [B] = box_ptr as *mut [B];
|
193 | Ok(unsafe { Box::<[B]>::from_raw(ptr) })
|
194 | }
|
195 | }
|
196 |
|
197 | /// As [`try_cast_vec`](try_cast_vec), but unwraps for you.
|
198 | #[inline ]
|
199 | pub fn cast_vec<A: NoUninit, B: AnyBitPattern>(input: Vec<A>) -> Vec<B> {
|
200 | try_cast_vec(input).map_err(|(e: PodCastError, _v: Vec)| e).unwrap()
|
201 | }
|
202 |
|
203 | /// Attempts to cast the content type of a [`Vec`](alloc::vec::Vec).
|
204 | ///
|
205 | /// On failure you get back an error along with the starting `Vec`.
|
206 | ///
|
207 | /// ## Failure
|
208 | ///
|
209 | /// * The start and end content type of the `Vec` must have the exact same
|
210 | /// alignment.
|
211 | /// * The start and end content size in bytes of the `Vec` must be the exact
|
212 | /// same.
|
213 | /// * The start and end capacity in bytes of the `Vec` must be the exact same.
|
214 | #[inline ]
|
215 | pub fn try_cast_vec<A: NoUninit, B: AnyBitPattern>(
|
216 | input: Vec<A>,
|
217 | ) -> Result<Vec<B>, (PodCastError, Vec<A>)> {
|
218 | if align_of::<A>() != align_of::<B>() {
|
219 | Err((PodCastError::AlignmentMismatch, input))
|
220 | } else if size_of::<A>() != size_of::<B>() {
|
221 | if size_of::<A>() * input.len() % size_of::<B>() != 0
|
222 | || size_of::<A>() * input.capacity() % size_of::<B>() != 0
|
223 | {
|
224 | // If the size in bytes of the underlying buffer does not match an exact
|
225 | // multiple of the size of B, we cannot cast between them.
|
226 | // Note that we have to pay special attention to make sure that both
|
227 | // length and capacity are valid under B, as we do not want to
|
228 | // change which bytes are considered part of the initialized slice
|
229 | // of the Vec
|
230 | Err((PodCastError::SizeMismatch, input))
|
231 | } else {
|
232 | // Because the size is an exact multiple, we can now change the length and
|
233 | // capacity and recreate the Vec
|
234 | // NOTE: This is a valid operation because according to the docs of
|
235 | // std::alloc::GlobalAlloc::dealloc(), the Layout that was used to alloc
|
236 | // the block must be the same Layout that is used to dealloc the block.
|
237 | // Luckily, Layout only stores two things, the alignment, and the size in
|
238 | // bytes. So as long as both of those stay the same, the Layout will
|
239 | // remain a valid input to dealloc.
|
240 |
|
241 | // Note(Lokathor): First we record the length and capacity, which don't
|
242 | // have any secret provenance metadata.
|
243 | let length: usize = size_of::<A>() * input.len() / size_of::<B>();
|
244 | let capacity: usize = size_of::<A>() * input.capacity() / size_of::<B>();
|
245 | // Note(Lokathor): Next we "pre-forget" the old Vec by wrapping with
|
246 | // ManuallyDrop, because if we used `core::mem::forget` after taking the
|
247 | // pointer then that would invalidate our pointer. In nightly there's a
|
248 | // "into raw parts" method, which we can switch this too eventually.
|
249 | let mut manual_drop_vec = ManuallyDrop::new(input);
|
250 | let vec_ptr: *mut A = manual_drop_vec.as_mut_ptr();
|
251 | let ptr: *mut B = vec_ptr as *mut B;
|
252 | Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) })
|
253 | }
|
254 | } else {
|
255 | // Note(Lokathor): First we record the length and capacity, which don't have
|
256 | // any secret provenance metadata.
|
257 | let length: usize = input.len();
|
258 | let capacity: usize = input.capacity();
|
259 | // Note(Lokathor): Next we "pre-forget" the old Vec by wrapping with
|
260 | // ManuallyDrop, because if we used `core::mem::forget` after taking the
|
261 | // pointer then that would invalidate our pointer. In nightly there's a
|
262 | // "into raw parts" method, which we can switch this too eventually.
|
263 | let mut manual_drop_vec = ManuallyDrop::new(input);
|
264 | let vec_ptr: *mut A = manual_drop_vec.as_mut_ptr();
|
265 | let ptr: *mut B = vec_ptr as *mut B;
|
266 | Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) })
|
267 | }
|
268 | }
|
269 |
|
270 | /// This "collects" a slice of pod data into a vec of a different pod type.
|
271 | ///
|
272 | /// Unlike with [`cast_slice`] and [`cast_slice_mut`], this will always work.
|
273 | ///
|
274 | /// The output vec will be of a minimal size/capacity to hold the slice given.
|
275 | ///
|
276 | /// ```rust
|
277 | /// # use bytemuck::*;
|
278 | /// let halfwords: [u16; 4] = [5, 6, 7, 8];
|
279 | /// let vec_of_words: Vec<u32> = pod_collect_to_vec(&halfwords);
|
280 | /// if cfg!(target_endian = "little" ) {
|
281 | /// assert_eq!(&vec_of_words[..], &[0x0006_0005, 0x0008_0007][..])
|
282 | /// } else {
|
283 | /// assert_eq!(&vec_of_words[..], &[0x0005_0006, 0x0007_0008][..])
|
284 | /// }
|
285 | /// ```
|
286 | pub fn pod_collect_to_vec<A: NoUninit, B: NoUninit + AnyBitPattern>(
|
287 | src: &[A],
|
288 | ) -> Vec<B> {
|
289 | let src_size: usize = size_of_val(src);
|
290 | // Note(Lokathor): dst_count is rounded up so that the dest will always be at
|
291 | // least as many bytes as the src.
|
292 | let dst_count: usize = src_size / size_of::<B>()
|
293 | + if src_size % size_of::<B>() != 0 { 1 } else { 0 };
|
294 | let mut dst: Vec = vec![B::zeroed(); dst_count];
|
295 |
|
296 | let src_bytes: &[u8] = cast_slice(src);
|
297 | let dst_bytes: &mut [u8] = cast_slice_mut(&mut dst[..]);
|
298 | dst_bytes[..src_size].copy_from_slice(src_bytes);
|
299 | dst
|
300 | }
|
301 |
|
302 | /// As [`try_cast_rc`](try_cast_rc), but unwraps for you.
|
303 | #[inline ]
|
304 | pub fn cast_rc<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(
|
305 | input: Rc<A>,
|
306 | ) -> Rc<B> {
|
307 | try_cast_rc(input).map_err(|(e: PodCastError, _v: Rc)| e).unwrap()
|
308 | }
|
309 |
|
310 | /// Attempts to cast the content type of a [`Rc`](alloc::rc::Rc).
|
311 | ///
|
312 | /// On failure you get back an error along with the starting `Rc`.
|
313 | ///
|
314 | /// The bounds on this function are the same as [`cast_mut`], because a user
|
315 | /// could call `Rc::get_unchecked_mut` on the output, which could be observable
|
316 | /// in the input.
|
317 | ///
|
318 | /// ## Failure
|
319 | ///
|
320 | /// * The start and end content type of the `Rc` must have the exact same
|
321 | /// alignment.
|
322 | /// * The start and end size of the `Rc` must have the exact same size.
|
323 | #[inline ]
|
324 | pub fn try_cast_rc<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(
|
325 | input: Rc<A>,
|
326 | ) -> Result<Rc<B>, (PodCastError, Rc<A>)> {
|
327 | if align_of::<A>() != align_of::<B>() {
|
328 | Err((PodCastError::AlignmentMismatch, input))
|
329 | } else if size_of::<A>() != size_of::<B>() {
|
330 | Err((PodCastError::SizeMismatch, input))
|
331 | } else {
|
332 | // Safety: Rc::from_raw requires size and alignment match, which is met.
|
333 | let ptr: *const B = Rc::into_raw(this:input) as *const B;
|
334 | Ok(unsafe { Rc::from_raw(ptr) })
|
335 | }
|
336 | }
|
337 |
|
338 | /// As [`try_cast_arc`](try_cast_arc), but unwraps for you.
|
339 | #[inline ]
|
340 | #[cfg (target_has_atomic = "ptr" )]
|
341 | pub fn cast_arc<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(
|
342 | input: Arc<A>,
|
343 | ) -> Arc<B> {
|
344 | try_cast_arc(input).map_err(|(e: PodCastError, _v: Arc)| e).unwrap()
|
345 | }
|
346 |
|
347 | /// Attempts to cast the content type of a [`Arc`](alloc::sync::Arc).
|
348 | ///
|
349 | /// On failure you get back an error along with the starting `Arc`.
|
350 | ///
|
351 | /// The bounds on this function are the same as [`cast_mut`], because a user
|
352 | /// could call `Rc::get_unchecked_mut` on the output, which could be observable
|
353 | /// in the input.
|
354 | ///
|
355 | /// ## Failure
|
356 | ///
|
357 | /// * The start and end content type of the `Arc` must have the exact same
|
358 | /// alignment.
|
359 | /// * The start and end size of the `Arc` must have the exact same size.
|
360 | #[inline ]
|
361 | #[cfg (target_has_atomic = "ptr" )]
|
362 | pub fn try_cast_arc<
|
363 | A: NoUninit + AnyBitPattern,
|
364 | B: NoUninit + AnyBitPattern,
|
365 | >(
|
366 | input: Arc<A>,
|
367 | ) -> Result<Arc<B>, (PodCastError, Arc<A>)> {
|
368 | if align_of::<A>() != align_of::<B>() {
|
369 | Err((PodCastError::AlignmentMismatch, input))
|
370 | } else if size_of::<A>() != size_of::<B>() {
|
371 | Err((PodCastError::SizeMismatch, input))
|
372 | } else {
|
373 | // Safety: Arc::from_raw requires size and alignment match, which is met.
|
374 | let ptr: *const B = Arc::into_raw(this:input) as *const B;
|
375 | Ok(unsafe { Arc::from_raw(ptr) })
|
376 | }
|
377 | }
|
378 |
|
379 | /// As [`try_cast_slice_rc`](try_cast_slice_rc), but unwraps for you.
|
380 | #[inline ]
|
381 | pub fn cast_slice_rc<
|
382 | A: NoUninit + AnyBitPattern,
|
383 | B: NoUninit + AnyBitPattern,
|
384 | >(
|
385 | input: Rc<[A]>,
|
386 | ) -> Rc<[B]> {
|
387 | try_cast_slice_rc(input).map_err(|(e: PodCastError, _v: Rc<[A]>)| e).unwrap()
|
388 | }
|
389 |
|
390 | /// Attempts to cast the content type of a `Rc<[T]>`.
|
391 | ///
|
392 | /// On failure you get back an error along with the starting `Rc<[T]>`.
|
393 | ///
|
394 | /// The bounds on this function are the same as [`cast_mut`], because a user
|
395 | /// could call `Rc::get_unchecked_mut` on the output, which could be observable
|
396 | /// in the input.
|
397 | ///
|
398 | /// ## Failure
|
399 | ///
|
400 | /// * The start and end content type of the `Rc<[T]>` must have the exact same
|
401 | /// alignment.
|
402 | /// * The start and end content size in bytes of the `Rc<[T]>` must be the exact
|
403 | /// same.
|
404 | #[inline ]
|
405 | pub fn try_cast_slice_rc<
|
406 | A: NoUninit + AnyBitPattern,
|
407 | B: NoUninit + AnyBitPattern,
|
408 | >(
|
409 | input: Rc<[A]>,
|
410 | ) -> Result<Rc<[B]>, (PodCastError, Rc<[A]>)> {
|
411 | if align_of::<A>() != align_of::<B>() {
|
412 | Err((PodCastError::AlignmentMismatch, input))
|
413 | } else if size_of::<A>() != size_of::<B>() {
|
414 | if size_of::<A>() * input.len() % size_of::<B>() != 0 {
|
415 | // If the size in bytes of the underlying buffer does not match an exact
|
416 | // multiple of the size of B, we cannot cast between them.
|
417 | Err((PodCastError::SizeMismatch, input))
|
418 | } else {
|
419 | // Because the size is an exact multiple, we can now change the length
|
420 | // of the slice and recreate the Rc
|
421 | // NOTE: This is a valid operation because according to the docs of
|
422 | // std::rc::Rc::from_raw(), the type U that was in the original Rc<U>
|
423 | // acquired from Rc::into_raw() must have the same size alignment and
|
424 | // size of the type T in the new Rc<T>. So as long as both the size
|
425 | // and alignment stay the same, the Rc will remain a valid Rc.
|
426 | let length = size_of::<A>() * input.len() / size_of::<B>();
|
427 | let rc_ptr: *const A = Rc::into_raw(input) as *const A;
|
428 | // Must use ptr::slice_from_raw_parts, because we cannot make an
|
429 | // intermediate const reference, because it has mutable provenance,
|
430 | // nor an intermediate mutable reference, because it could be aliased.
|
431 | let ptr = core::ptr::slice_from_raw_parts(rc_ptr as *const B, length);
|
432 | Ok(unsafe { Rc::<[B]>::from_raw(ptr) })
|
433 | }
|
434 | } else {
|
435 | let rc_ptr: *const [A] = Rc::into_raw(input);
|
436 | let ptr: *const [B] = rc_ptr as *const [B];
|
437 | Ok(unsafe { Rc::<[B]>::from_raw(ptr) })
|
438 | }
|
439 | }
|
440 |
|
441 | /// As [`try_cast_slice_arc`](try_cast_slice_arc), but unwraps for you.
|
442 | #[inline ]
|
443 | #[cfg (target_has_atomic = "ptr" )]
|
444 | pub fn cast_slice_arc<
|
445 | A: NoUninit + AnyBitPattern,
|
446 | B: NoUninit + AnyBitPattern,
|
447 | >(
|
448 | input: Arc<[A]>,
|
449 | ) -> Arc<[B]> {
|
450 | try_cast_slice_arc(input).map_err(|(e: PodCastError, _v: Arc<[A]>)| e).unwrap()
|
451 | }
|
452 |
|
453 | /// Attempts to cast the content type of a `Arc<[T]>`.
|
454 | ///
|
455 | /// On failure you get back an error along with the starting `Arc<[T]>`.
|
456 | ///
|
457 | /// The bounds on this function are the same as [`cast_mut`], because a user
|
458 | /// could call `Rc::get_unchecked_mut` on the output, which could be observable
|
459 | /// in the input.
|
460 | ///
|
461 | /// ## Failure
|
462 | ///
|
463 | /// * The start and end content type of the `Arc<[T]>` must have the exact same
|
464 | /// alignment.
|
465 | /// * The start and end content size in bytes of the `Arc<[T]>` must be the
|
466 | /// exact same.
|
467 | #[inline ]
|
468 | #[cfg (target_has_atomic = "ptr" )]
|
469 | pub fn try_cast_slice_arc<
|
470 | A: NoUninit + AnyBitPattern,
|
471 | B: NoUninit + AnyBitPattern,
|
472 | >(
|
473 | input: Arc<[A]>,
|
474 | ) -> Result<Arc<[B]>, (PodCastError, Arc<[A]>)> {
|
475 | if align_of::<A>() != align_of::<B>() {
|
476 | Err((PodCastError::AlignmentMismatch, input))
|
477 | } else if size_of::<A>() != size_of::<B>() {
|
478 | if size_of::<A>() * input.len() % size_of::<B>() != 0 {
|
479 | // If the size in bytes of the underlying buffer does not match an exact
|
480 | // multiple of the size of B, we cannot cast between them.
|
481 | Err((PodCastError::SizeMismatch, input))
|
482 | } else {
|
483 | // Because the size is an exact multiple, we can now change the length
|
484 | // of the slice and recreate the Arc
|
485 | // NOTE: This is a valid operation because according to the docs of
|
486 | // std::sync::Arc::from_raw(), the type U that was in the original Arc<U>
|
487 | // acquired from Arc::into_raw() must have the same size alignment and
|
488 | // size of the type T in the new Arc<T>. So as long as both the size
|
489 | // and alignment stay the same, the Arc will remain a valid Arc.
|
490 | let length = size_of::<A>() * input.len() / size_of::<B>();
|
491 | let arc_ptr: *const A = Arc::into_raw(input) as *const A;
|
492 | // Must use ptr::slice_from_raw_parts, because we cannot make an
|
493 | // intermediate const reference, because it has mutable provenance,
|
494 | // nor an intermediate mutable reference, because it could be aliased.
|
495 | let ptr = core::ptr::slice_from_raw_parts(arc_ptr as *const B, length);
|
496 | Ok(unsafe { Arc::<[B]>::from_raw(ptr) })
|
497 | }
|
498 | } else {
|
499 | let arc_ptr: *const [A] = Arc::into_raw(input);
|
500 | let ptr: *const [B] = arc_ptr as *const [B];
|
501 | Ok(unsafe { Arc::<[B]>::from_raw(ptr) })
|
502 | }
|
503 | }
|
504 |
|
505 | /// An extension trait for `TransparentWrapper` and alloc types.
|
506 | pub trait TransparentWrapperAlloc<Inner: ?Sized>:
|
507 | TransparentWrapper<Inner>
|
508 | {
|
509 | /// Convert a vec of the inner type into a vec of the wrapper type.
|
510 | fn wrap_vec(s: Vec<Inner>) -> Vec<Self>
|
511 | where
|
512 | Self: Sized,
|
513 | Inner: Sized,
|
514 | {
|
515 | let mut s = core::mem::ManuallyDrop::new(s);
|
516 |
|
517 | let length = s.len();
|
518 | let capacity = s.capacity();
|
519 | let ptr = s.as_mut_ptr();
|
520 |
|
521 | unsafe {
|
522 | // SAFETY:
|
523 | // * ptr comes from Vec (and will not be double-dropped)
|
524 | // * the two types have the identical representation
|
525 | // * the len and capacity fields are valid
|
526 | Vec::from_raw_parts(ptr as *mut Self, length, capacity)
|
527 | }
|
528 | }
|
529 |
|
530 | /// Convert a box to the inner type into a box to the wrapper
|
531 | /// type.
|
532 | #[inline ]
|
533 | fn wrap_box(s: Box<Inner>) -> Box<Self> {
|
534 | assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
535 |
|
536 | unsafe {
|
537 | // A pointer cast doesn't work here because rustc can't tell that
|
538 | // the vtables match (because of the `?Sized` restriction relaxation).
|
539 | // A `transmute` doesn't work because the sizes are unspecified.
|
540 | //
|
541 | // SAFETY:
|
542 | // * The unsafe contract requires that pointers to Inner and Self have
|
543 | // identical representations
|
544 | // * Box is guaranteed to have representation identical to a (non-null)
|
545 | // pointer
|
546 | // * The pointer comes from a box (and thus satisfies all safety
|
547 | // requirements of Box)
|
548 | let inner_ptr: *mut Inner = Box::into_raw(s);
|
549 | let wrapper_ptr: *mut Self = transmute!(inner_ptr);
|
550 | Box::from_raw(wrapper_ptr)
|
551 | }
|
552 | }
|
553 |
|
554 | /// Convert an [`Rc`](alloc::rc::Rc) to the inner type into an `Rc` to the
|
555 | /// wrapper type.
|
556 | #[inline ]
|
557 | fn wrap_rc(s: Rc<Inner>) -> Rc<Self> {
|
558 | assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
559 |
|
560 | unsafe {
|
561 | // A pointer cast doesn't work here because rustc can't tell that
|
562 | // the vtables match (because of the `?Sized` restriction relaxation).
|
563 | // A `transmute` doesn't work because the layout of Rc is unspecified.
|
564 | //
|
565 | // SAFETY:
|
566 | // * The unsafe contract requires that pointers to Inner and Self have
|
567 | // identical representations, and that the size and alignment of Inner
|
568 | // and Self are the same, which meets the safety requirements of
|
569 | // Rc::from_raw
|
570 | let inner_ptr: *const Inner = Rc::into_raw(s);
|
571 | let wrapper_ptr: *const Self = transmute!(inner_ptr);
|
572 | Rc::from_raw(wrapper_ptr)
|
573 | }
|
574 | }
|
575 |
|
576 | /// Convert an [`Arc`](alloc::sync::Arc) to the inner type into an `Arc` to
|
577 | /// the wrapper type.
|
578 | #[inline ]
|
579 | #[cfg (target_has_atomic = "ptr" )]
|
580 | fn wrap_arc(s: Arc<Inner>) -> Arc<Self> {
|
581 | assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
582 |
|
583 | unsafe {
|
584 | // A pointer cast doesn't work here because rustc can't tell that
|
585 | // the vtables match (because of the `?Sized` restriction relaxation).
|
586 | // A `transmute` doesn't work because the layout of Arc is unspecified.
|
587 | //
|
588 | // SAFETY:
|
589 | // * The unsafe contract requires that pointers to Inner and Self have
|
590 | // identical representations, and that the size and alignment of Inner
|
591 | // and Self are the same, which meets the safety requirements of
|
592 | // Arc::from_raw
|
593 | let inner_ptr: *const Inner = Arc::into_raw(s);
|
594 | let wrapper_ptr: *const Self = transmute!(inner_ptr);
|
595 | Arc::from_raw(wrapper_ptr)
|
596 | }
|
597 | }
|
598 |
|
599 | /// Convert a vec of the wrapper type into a vec of the inner type.
|
600 | fn peel_vec(s: Vec<Self>) -> Vec<Inner>
|
601 | where
|
602 | Self: Sized,
|
603 | Inner: Sized,
|
604 | {
|
605 | let mut s = core::mem::ManuallyDrop::new(s);
|
606 |
|
607 | let length = s.len();
|
608 | let capacity = s.capacity();
|
609 | let ptr = s.as_mut_ptr();
|
610 |
|
611 | unsafe {
|
612 | // SAFETY:
|
613 | // * ptr comes from Vec (and will not be double-dropped)
|
614 | // * the two types have the identical representation
|
615 | // * the len and capacity fields are valid
|
616 | Vec::from_raw_parts(ptr as *mut Inner, length, capacity)
|
617 | }
|
618 | }
|
619 |
|
620 | /// Convert a box to the wrapper type into a box to the inner
|
621 | /// type.
|
622 | #[inline ]
|
623 | fn peel_box(s: Box<Self>) -> Box<Inner> {
|
624 | assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
625 |
|
626 | unsafe {
|
627 | // A pointer cast doesn't work here because rustc can't tell that
|
628 | // the vtables match (because of the `?Sized` restriction relaxation).
|
629 | // A `transmute` doesn't work because the sizes are unspecified.
|
630 | //
|
631 | // SAFETY:
|
632 | // * The unsafe contract requires that pointers to Inner and Self have
|
633 | // identical representations
|
634 | // * Box is guaranteed to have representation identical to a (non-null)
|
635 | // pointer
|
636 | // * The pointer comes from a box (and thus satisfies all safety
|
637 | // requirements of Box)
|
638 | let wrapper_ptr: *mut Self = Box::into_raw(s);
|
639 | let inner_ptr: *mut Inner = transmute!(wrapper_ptr);
|
640 | Box::from_raw(inner_ptr)
|
641 | }
|
642 | }
|
643 |
|
644 | /// Convert an [`Rc`](alloc::rc::Rc) to the wrapper type into an `Rc` to the
|
645 | /// inner type.
|
646 | #[inline ]
|
647 | fn peel_rc(s: Rc<Self>) -> Rc<Inner> {
|
648 | assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
649 |
|
650 | unsafe {
|
651 | // A pointer cast doesn't work here because rustc can't tell that
|
652 | // the vtables match (because of the `?Sized` restriction relaxation).
|
653 | // A `transmute` doesn't work because the layout of Rc is unspecified.
|
654 | //
|
655 | // SAFETY:
|
656 | // * The unsafe contract requires that pointers to Inner and Self have
|
657 | // identical representations, and that the size and alignment of Inner
|
658 | // and Self are the same, which meets the safety requirements of
|
659 | // Rc::from_raw
|
660 | let wrapper_ptr: *const Self = Rc::into_raw(s);
|
661 | let inner_ptr: *const Inner = transmute!(wrapper_ptr);
|
662 | Rc::from_raw(inner_ptr)
|
663 | }
|
664 | }
|
665 |
|
666 | /// Convert an [`Arc`](alloc::sync::Arc) to the wrapper type into an `Arc` to
|
667 | /// the inner type.
|
668 | #[inline ]
|
669 | #[cfg (target_has_atomic = "ptr" )]
|
670 | fn peel_arc(s: Arc<Self>) -> Arc<Inner> {
|
671 | assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
672 |
|
673 | unsafe {
|
674 | // A pointer cast doesn't work here because rustc can't tell that
|
675 | // the vtables match (because of the `?Sized` restriction relaxation).
|
676 | // A `transmute` doesn't work because the layout of Arc is unspecified.
|
677 | //
|
678 | // SAFETY:
|
679 | // * The unsafe contract requires that pointers to Inner and Self have
|
680 | // identical representations, and that the size and alignment of Inner
|
681 | // and Self are the same, which meets the safety requirements of
|
682 | // Arc::from_raw
|
683 | let wrapper_ptr: *const Self = Arc::into_raw(s);
|
684 | let inner_ptr: *const Inner = transmute!(wrapper_ptr);
|
685 | Arc::from_raw(inner_ptr)
|
686 | }
|
687 | }
|
688 | }
|
689 |
|
690 | impl<I: ?Sized, T: ?Sized + TransparentWrapper<I>> TransparentWrapperAlloc<I>
|
691 | for T
|
692 | {
|
693 | }
|
694 |
|
695 | /// As `Box<[u8]>`, but remembers the original alignment.
|
696 | pub struct BoxBytes {
|
697 | // SAFETY: `ptr` is owned, was allocated with `layout`, and points to
|
698 | // `layout.size()` initialized bytes.
|
699 | ptr: NonNull<u8>,
|
700 | layout: Layout,
|
701 | }
|
702 |
|
703 | impl Deref for BoxBytes {
|
704 | type Target = [u8];
|
705 |
|
706 | fn deref(&self) -> &Self::Target {
|
707 | // SAFETY: See type invariant.
|
708 | unsafe {
|
709 | core::slice::from_raw_parts(self.ptr.as_ptr(), self.layout.size())
|
710 | }
|
711 | }
|
712 | }
|
713 |
|
714 | impl DerefMut for BoxBytes {
|
715 | fn deref_mut(&mut self) -> &mut Self::Target {
|
716 | // SAFETY: See type invariant.
|
717 | unsafe {
|
718 | core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.layout.size())
|
719 | }
|
720 | }
|
721 | }
|
722 |
|
723 | impl Drop for BoxBytes {
|
724 | fn drop(&mut self) {
|
725 | // SAFETY: See type invariant.
|
726 | unsafe { alloc::alloc::dealloc(self.ptr.as_ptr(), self.layout) };
|
727 | }
|
728 | }
|
729 |
|
730 | impl<T: ?Sized + sealed::BoxBytesOf> From<Box<T>> for BoxBytes {
|
731 | fn from(value: Box<T>) -> Self {
|
732 | value.box_bytes_of()
|
733 | }
|
734 | }
|
735 |
|
736 | mod sealed {
|
737 | use crate::{BoxBytes, PodCastError};
|
738 | use alloc::boxed::Box;
|
739 |
|
740 | pub trait BoxBytesOf {
|
741 | fn box_bytes_of(self: Box<Self>) -> BoxBytes;
|
742 | }
|
743 |
|
744 | pub trait FromBoxBytes {
|
745 | fn try_from_box_bytes(
|
746 | bytes: BoxBytes,
|
747 | ) -> Result<Box<Self>, (PodCastError, BoxBytes)>;
|
748 | }
|
749 | }
|
750 |
|
751 | impl<T: NoUninit> sealed::BoxBytesOf for T {
|
752 | fn box_bytes_of(self: Box<Self>) -> BoxBytes {
|
753 | let layout: Layout = Layout::new::<T>();
|
754 | let ptr: *mut u8 = Box::into_raw(self) as *mut u8;
|
755 | // SAFETY: Box::into_raw() returns a non-null pointer.
|
756 | let ptr: NonNull = unsafe { NonNull::new_unchecked(ptr) };
|
757 | BoxBytes { ptr, layout }
|
758 | }
|
759 | }
|
760 |
|
761 | impl<T: NoUninit> sealed::BoxBytesOf for [T] {
|
762 | fn box_bytes_of(self: Box<Self>) -> BoxBytes {
|
763 | let layout: Layout = Layout::for_value::<[T]>(&self);
|
764 | let ptr: *mut u8 = Box::into_raw(self) as *mut u8;
|
765 | // SAFETY: Box::into_raw() returns a non-null pointer.
|
766 | let ptr: NonNull = unsafe { NonNull::new_unchecked(ptr) };
|
767 | BoxBytes { ptr, layout }
|
768 | }
|
769 | }
|
770 |
|
771 | impl sealed::BoxBytesOf for str {
|
772 | fn box_bytes_of(self: Box<Self>) -> BoxBytes {
|
773 | self.into_boxed_bytes().box_bytes_of()
|
774 | }
|
775 | }
|
776 |
|
777 | impl<T: AnyBitPattern> sealed::FromBoxBytes for T {
|
778 | fn try_from_box_bytes(
|
779 | bytes: BoxBytes,
|
780 | ) -> Result<Box<Self>, (PodCastError, BoxBytes)> {
|
781 | let layout: Layout = Layout::new::<T>();
|
782 | if bytes.layout.align() != layout.align() {
|
783 | Err((PodCastError::AlignmentMismatch, bytes))
|
784 | } else if bytes.layout.size() != layout.size() {
|
785 | Err((PodCastError::SizeMismatch, bytes))
|
786 | } else {
|
787 | let (ptr: NonNull, _) = bytes.into_raw_parts();
|
788 | // SAFETY: See BoxBytes type invariant.
|
789 | Ok(unsafe { Box::from_raw(ptr.as_ptr() as *mut T) })
|
790 | }
|
791 | }
|
792 | }
|
793 |
|
794 | impl<T: AnyBitPattern> sealed::FromBoxBytes for [T] {
|
795 | fn try_from_box_bytes(
|
796 | bytes: BoxBytes,
|
797 | ) -> Result<Box<Self>, (PodCastError, BoxBytes)> {
|
798 | let single_layout: Layout = Layout::new::<T>();
|
799 | if bytes.layout.align() != single_layout.align() {
|
800 | Err((PodCastError::AlignmentMismatch, bytes))
|
801 | } else if single_layout.size() == 0 {
|
802 | Err((PodCastError::SizeMismatch, bytes))
|
803 | } else if bytes.layout.size() % single_layout.size() != 0 {
|
804 | Err((PodCastError::OutputSliceWouldHaveSlop, bytes))
|
805 | } else {
|
806 | let (ptr: NonNull, layout: Layout) = bytes.into_raw_parts();
|
807 | let length: usize = layout.size() / single_layout.size();
|
808 | let ptr: *mut [T] =
|
809 | core::ptr::slice_from_raw_parts_mut(data:ptr.as_ptr() as *mut T, len:length);
|
810 | // SAFETY: See BoxBytes type invariant.
|
811 | Ok(unsafe { Box::from_raw(ptr) })
|
812 | }
|
813 | }
|
814 | }
|
815 |
|
816 | /// Re-interprets `Box<T>` as `BoxBytes`.
|
817 | ///
|
818 | /// `T` must be either [`Sized`] and [`NoUninit`],
|
819 | /// [`[U]`](slice) where `U: NoUninit`, or [`str`].
|
820 | #[inline ]
|
821 | pub fn box_bytes_of<T: sealed::BoxBytesOf + ?Sized>(input: Box<T>) -> BoxBytes {
|
822 | input.box_bytes_of()
|
823 | }
|
824 |
|
825 | /// Re-interprets `BoxBytes` as `Box<T>`.
|
826 | ///
|
827 | /// `T` must be either [`Sized`] + [`AnyBitPattern`], or
|
828 | /// [`[U]`](slice) where `U: AnyBitPattern`.
|
829 | ///
|
830 | /// ## Panics
|
831 | ///
|
832 | /// This is [`try_from_box_bytes`] but will panic on error and the input will be
|
833 | /// dropped.
|
834 | #[inline ]
|
835 | pub fn from_box_bytes<T: sealed::FromBoxBytes + ?Sized>(
|
836 | input: BoxBytes,
|
837 | ) -> Box<T> {
|
838 | try_from_box_bytes(input).map_err(|(error: PodCastError, _)| error).unwrap()
|
839 | }
|
840 |
|
841 | /// Re-interprets `BoxBytes` as `Box<T>`.
|
842 | ///
|
843 | /// `T` must be either [`Sized`] + [`AnyBitPattern`], or
|
844 | /// [`[U]`](slice) where `U: AnyBitPattern`.
|
845 | ///
|
846 | /// Returns `Err`:
|
847 | /// * If the input isn't aligned for `T`.
|
848 | /// * If `T: Sized` and the input's length isn't exactly the size of `T`.
|
849 | /// * If `T = [U]` and the input's length isn't exactly a multiple of the size
|
850 | /// of `U`.
|
851 | #[inline ]
|
852 | pub fn try_from_box_bytes<T: sealed::FromBoxBytes + ?Sized>(
|
853 | input: BoxBytes,
|
854 | ) -> Result<Box<T>, (PodCastError, BoxBytes)> {
|
855 | T::try_from_box_bytes(input)
|
856 | }
|
857 |
|
858 | impl BoxBytes {
|
859 | /// Constructs a `BoxBytes` from its raw parts.
|
860 | ///
|
861 | /// # Safety
|
862 | ///
|
863 | /// The pointer is owned, has been allocated with the provided layout, and
|
864 | /// points to `layout.size()` initialized bytes.
|
865 | pub unsafe fn from_raw_parts(ptr: NonNull<u8>, layout: Layout) -> Self {
|
866 | BoxBytes { ptr, layout }
|
867 | }
|
868 |
|
869 | /// Deconstructs a `BoxBytes` into its raw parts.
|
870 | ///
|
871 | /// The pointer is owned, has been allocated with the provided layout, and
|
872 | /// points to `layout.size()` initialized bytes.
|
873 | pub fn into_raw_parts(self) -> (NonNull<u8>, Layout) {
|
874 | let me = ManuallyDrop::new(self);
|
875 | (me.ptr, me.layout)
|
876 | }
|
877 |
|
878 | /// Returns the original layout.
|
879 | pub fn layout(&self) -> Layout {
|
880 | self.layout
|
881 | }
|
882 | }
|
883 | |