without_alloc/uninit.rs
1//! Safe abstractions around pointing at uninitialized memory without references.
2//!
3//! This solves two issues beyond the standard library: Firstly, `MaybeUninit` does not permitted
4//! unsized types. Secondly, a strict interpretation of pointer provenance implies that once a
5//! reference is created our access is restricted the memory referred to in it. This spoils our
6//! access to any memory in a potential tail of the allocation, which is wasteful.
7//!
8//! It is potentially **UB** to have references to uninitialized memory even if such a reference is
9//! not 'used' in any particular manner. See [the discussion of the unsafe working group][wg-ref].
10//!
11//! TODO: In some next version we'd like to switch to `&'a UnsafeCell<MaybeUninit<T>>` here, or
12//! even replace the UnsafeCell once we've replace the `view` attribute in Uninit. But alas we're
13//! not permitted to have an unsized parameter to `MaybeUninit`.
14//!
15//! More work using unsized type parameter would in particular make it redundant to store the
16//! length as we could refer to memory with a wrapper `Byte(u8)` and the `T = [Byte]` instantiation
17//! for the type parameter of `Uninit`/`UninitView`. Storing additional bytes would be a wrapper
18//! around the main interface.
19//!
20//! [wg-ref]: https://github.com/rust-lang/unsafe-code-guidelines/issues/77
21use core::{fmt, mem, slice, ptr};
22use core::alloc::Layout;
23use core::marker::PhantomData;
24
25use crate::boxed::Box;
26use unsize::CoerciblePtr;
27
28/// Points to an uninitialized place but would otherwise be a valid reference.
29///
30/// This is a `&mut`-like struct that is somewhat of a pendant to `MaybeUninit`. It makes it
31/// possible to deal with uninitialized allocations without requiring an `unsafe` block
32/// initializing them and offers a much safer interface for partial initialization and layout
33/// calculations than raw pointers.
34///
35/// Note that it also supports slices which means it does not use `MaybeUninit` internally but
36/// offers conversion where necessary.
37///
38/// ## Usage
39///
40/// The basic usage is also interacting with `MaybeUninit`:
41///
42/// ```
43/// # #[derive(Default)]
44/// # struct MyStruct { };
45/// use core::mem::MaybeUninit;
46/// use without_alloc::Uninit;
47///
48/// let mut alloc: MaybeUninit<MyStruct> = MaybeUninit::uninit();
49/// let uninit = Uninit::from_maybe_uninit(&mut alloc);
50///
51/// // notice: no unsafe
52/// let instance: &mut MyStruct = uninit.init(MyStruct::default());
53/// ```
54///
55/// But since we are working on arbitrary uninitialized memory it is also possible to reuse the
56/// structure for completely arbitrary other types. Just note that there is no integrated mechanis
57/// for calling `Drop`.
58///
59/// ```
60/// use core::mem::MaybeUninit;
61/// use without_alloc::Uninit;
62///
63/// // Just a generic buffer.
64/// let mut alloc: MaybeUninit<[u32; 1024]> = MaybeUninit::uninit();
65/// let uninit = Uninit::from_maybe_uninit(&mut alloc);
66///
67/// // Now use the first `u32` for a counter:
68/// let mut counter = uninit.cast().unwrap();
69/// let mut tail = counter.split_to_fit();
70/// let counter: &mut u32 = counter.init(0);
71///
72/// // And some more for a few `u64`.
73/// // Note that these are not trivially aligned, but `Uninit` does that for us.
74/// let mut values = tail.split_cast().unwrap();
75/// // No more use, so don't bother with `split_to_fit` and just `init`.
76/// let values: &mut [u64; 2] = values.init([0xdead, 0xbeef]);
77/// ```
78#[must_use = "This is a pointer-like type that has no effect on its own. Use `init` to insert a value."]
79pub struct Uninit<'a, T: ?Sized> {
80 /// The underlying view.
81 ///
82 /// Uninit additional imposes on it that the underlying memory is mutable.
83 view: UninitView<'a, T>,
84
85 /// Reminder for every construction.
86 mutable: PhantomData<&'a mut ()>,
87}
88
89/// A non-mutable view on a region used in an [`Uninit`].
90///
91/// Makes it possible to utilize the traversal methods (`split*`, `cast*`, ..) without requiring a
92/// mutable reference to the original `Uninit`. It will also never expose mutable pointers or
93/// accidentally offer an aliased mutable reference. Prefer this to instead avoiding the borrow of
94/// the `Uninit` and manually managing pointers to the region.
95///
96/// [`Uninit`]: ./struct.Uninit.html
97#[must_use = "This is a pointer-like type that has no effect on its own."]
98pub struct UninitView<'a, T: ?Sized> {
99 /// Pointer to the start of the region.
100 ///
101 /// Note that `len` is always at least as large as the (minimum) size of `T`. Furthermore, the
102 /// pointer is always correctly aligned to a `T`.
103 ptr: ptr::NonNull<T>,
104
105 /// The actual length *in bytes*.
106 ///
107 /// May be larger than required.
108 len: usize,
109
110 /// Virtual lifetime to make this behave more similar to references.
111 ///
112 /// This borrows structures that hand out `Uninit` allocations.
113 lifetime: PhantomData<&'a ()>,
114
115 /// We'll be holding an actual `NonNull<T>` in the future (when dynamically sized pointers to
116 /// slices are more ergonomic). For now, just type ourselves.
117 typed: PhantomData<*mut T>,
118}
119
120impl Uninit<'_, ()> {
121 /// Create a uninit pointer from raw memory.
122 ///
123 /// ## Safety
124 /// A valid allocation must exist at the pointer with length at least `len`. There must be *no*
125 /// references aliasing the memory location, and it must be valid to write uninitialized bytes
126 /// into arbitrary locations of the region.
127 ///
128 /// In particular, it is **UB** to create this from a reference to a variable of a type for
129 /// which a completely uninitialized content is not valid. The standard type for avoiding the
130 /// UB is `core::mem::MaybeUninit`.
131 ///
132 /// When in doubt, refactor code such that utilization of `from_maybe_uninit` is possible.
133 pub unsafe fn from_memory(ptr: ptr::NonNull<u8>, len: usize) -> Self {
134 Uninit::from_presumed_mutable_view(UninitView {
135 ptr: ptr.cast(),
136 len,
137 lifetime: PhantomData,
138 typed: PhantomData,
139 })
140 }
141
142 /// Split so that the second part fits the layout.
143 ///
144 /// Return `Ok` if this is possible in-bounds and `Err` if it is not.
145 pub fn split_layout(&mut self, layout: Layout) -> Option<Self> {
146 self.view.split_layout(layout)
147 .map(Self::from_presumed_mutable_view)
148 }
149}
150
151impl<'a> Uninit<'a, ()> {
152 fn decast<T: ?Sized>(uninit: Uninit<'a, T>) -> Self {
153 Uninit::from_presumed_mutable_view(UninitView {
154 ptr: uninit.view.ptr.cast(),
155 len: uninit.view.len,
156 lifetime: PhantomData,
157 typed: PhantomData,
158 })
159 }
160
161 /// Split so that the tail is aligned and valid for a `U`.
162 ///
163 /// Return `Ok` if this is possible in-bounds (aligned and enough room for at least one `U`)
164 /// and `Err` if it is not. The first tuple element is the `Uninit` pointing to the skipped
165 /// memory.
166 pub fn split_cast<U>(&mut self) -> Option<Uninit<'a, U>> {
167 let split = self.split_layout(Layout::new::<U>())?;
168 let cast = split.cast::<U>().unwrap();
169 Some(cast)
170 }
171
172 /// Split so that the tail is aligned for a slice `[U]`.
173 ///
174 /// Return `Ok` if this is possible in-bounds and `Err` if it is not. The first tuple element
175 /// is the `Uninit` pointing to the skipped memory.
176 ///
177 /// The length of the slice is the arbitrary amount that fits into the tail of the allocation.
178 /// Note that the length always fulfills the safety requirements for `slice::from_raw_parts`
179 /// since the `Uninit` must be contained in a single allocation.
180 pub fn split_slice<U>(&mut self) -> Option<Uninit<'a, [U]>> {
181 let layout = Layout::for_value::<[U]>(&[]);
182 let split = self.split_layout(layout)?;
183 let cast = split.cast_slice::<U>().unwrap();
184 Some(cast)
185 }
186}
187
188impl<T> Uninit<'_, T> {
189 /// Invent a new uninit allocation for a zero-sized type (ZST).
190 ///
191 /// # Panics
192 /// This method panics when the type parameter is not a zero sized type.
193 pub fn invent_for_zst() -> Self {
194 // SAFETY: zst is always unaliased.
195 unsafe { Uninit::from_view(UninitView::invent_for_zst()) }
196 }
197}
198
199impl<'a, T> Uninit<'a, T> {
200 /// Create an `uninit` from a view.
201 ///
202 /// ## Safety
203 /// The caller must prove that the pointed-to memory is mutable and that it is unaliased.
204 pub unsafe fn from_view(view: UninitView<'a, T>) -> Self {
205 Self::from_presumed_mutable_view(view)
206 }
207
208 /// Create an initializable pointer to the inner bytes of a `MaybeUninit`.
209 pub fn from_maybe_uninit(mem: &'a mut mem::MaybeUninit<T>) -> Self {
210 let ptr = ptr::NonNull::new(mem.as_mut_ptr()).unwrap();
211 let raw = unsafe {
212 // SAFETY:
213 // * unaliased as we had a mutable reference
214 // * can write uninitialized bytes as much as we want
215 Uninit::from_memory(ptr.cast(), mem::size_of_val(mem))
216 };
217 raw.cast().unwrap()
218 }
219
220 /// Split the uninit slice at a byte boundary.
221 ///
222 /// Return `Ok` if the location is in-bounds and `Err` if it is out of bounds.
223 pub fn split_at_byte(&mut self, at: usize) -> Option<Uninit<'a, ()>> {
224 self.view.split_at_byte(at)
225 .map(Uninit::from_presumed_mutable_view)
226 }
227
228 /// Try to cast to an `Uninit` for another type.
229 ///
230 /// Return `Ok` if the current `Uninit` is suitably aligned and large enough to hold at least
231 /// one `U` and `Err` if it is not. Note that the successful result points to unused remaining
232 /// memory behind where the instance can be placed.
233 ///
234 /// Use [`split_to_fit`] to get rid of surplus memory at the end.
235 ///
236 /// [`split_to_fit`]: #method.split_to_fit
237 pub fn cast<U>(self) -> Result<Uninit<'a, U>, Self> {
238 self.view.cast()
239 .map(Uninit::from_presumed_mutable_view)
240 .map_err(Self::from_presumed_mutable_view)
241 }
242
243 /// Try to cast to an `Uninit` for a slice type.
244 ///
245 /// Return `Ok` if the current `Uninit` is suitably aligned and large enough to hold at least
246 /// one `U` and `Err` if it is not. Note that the successful result points to unused remaining
247 /// memory behind where the instances can be placed.
248 pub fn cast_slice<U>(self) -> Result<Uninit<'a, [U]>, Self> {
249 self.view.cast_slice::<U>()
250 .map(Uninit::from_presumed_mutable_view)
251 .map_err(Self::from_presumed_mutable_view)
252 }
253
254 /// Split off the tail that is not required for holding an instance of `T`.
255 ///
256 /// This operation is idempotent.
257 pub fn split_to_fit(&mut self) -> Uninit<'a, ()> {
258 self.split_at_byte(mem::size_of::<T>()).unwrap()
259 }
260}
261
262
263impl<'a, T: ?Sized> Uninit<'a, T> {
264 /// Acquires the underlying *mut pointer.
265 pub const fn as_ptr(&self) -> *mut T {
266 self.view.ptr.as_ptr()
267 }
268
269 /// Acquires the underlying pointer as a `NonNull`.
270 pub const fn as_non_null(&self) -> ptr::NonNull<T> {
271 self.view.ptr
272 }
273
274 /// Dereferences the content.
275 ///
276 /// The resulting lifetime is bound to self so this behaves "as if" it were actually an
277 /// instance of T that is getting borrowed. If a longer lifetime is needed, use `into_ref`.
278 ///
279 /// # Safety
280 /// The pointee must have been initialized through other means.
281 pub unsafe fn as_ref(&self) -> &T {
282 self.view.as_ref()
283 }
284
285 /// Mutably dereferences the content.
286 ///
287 /// The resulting lifetime is bound to self so this behaves "as if" it were actually an
288 /// instance of T that is getting borrowed. If a longer lifetime is needed, use `into_mut`.
289 ///
290 /// # Safety
291 /// The pointee must have been initialized through other means.
292 pub unsafe fn as_mut(&mut self) -> &mut T {
293 &mut *self.as_ptr()
294 }
295
296 /// Turn this into a reference to the content.
297 ///
298 /// # Safety
299 /// The pointee must have been initialized through other means.
300 pub unsafe fn into_ref(self) -> &'a T {
301 &*self.as_ptr()
302 }
303
304 /// Turn this into a mutable reference to the content.
305 ///
306 /// # Safety
307 /// The pointee must have been initialized through other means.
308 pub unsafe fn into_mut(self) -> &'a mut T {
309 &mut *self.as_ptr()
310 }
311}
312
313impl<'a, T> Uninit<'a, T> {
314 /// Initialize the place and return a reference to the value.
315 pub fn init(self, val: T) -> &'a mut T {
316 let ptr = self.as_ptr();
317 unsafe {
318 // SAFETY:
319 // * can only create instances where layout of `T` 'fits'
320 // * valid for lifetime `'a` (as per `UninitView`).
321 // * unaliased for lifetime `'a` (as per own invariant from unsafe constructor). No
322 // other method duplicates the pointer or allows a second `Uninit` without borrowing
323 // the first.
324 ptr::write(ptr, val);
325 &mut *ptr
326 }
327 }
328
329 /// Turn this into a reference to standard `MaybeUninit`.
330 ///
331 /// This is mainly useful for interfacing with other consumers which expect standard library
332 /// types. It may also improve ergonomics for writing to the pointee partially initialized
333 /// instances of `T` that are obtained via other means.
334 ///
335 /// Note that the sequence `from_maybe_uninit`, `into_maybe_uninit` is a no-op. The converse is
336 /// however not the case, as it will potentially discard unused padding present in the original
337 /// `Uninit`.
338 pub fn into_maybe_uninit(self) -> &'a mut mem::MaybeUninit<T> {
339 // SAFETY: MaybeUninit is a transparent wrapper and need not be initialized.
340 unsafe { &mut*(self.as_ptr() as *mut mem::MaybeUninit<T>) }
341 }
342
343 /// Read a value from the uninit place without moving it.
344 ///
345 /// The `Uninit` ensures that the inner pointer is correctly aligned, non-null, and points to a
346 /// large enough region for reading a `T`.
347 ///
348 /// ## Safety
349 /// Caller must ensure that the memory is initialized as a valid `T`. It must also avoid double
350 /// `Drop`. Basically, a new instance is created.
351 pub unsafe fn read(&self) -> T {
352 ptr::read(self.as_ptr())
353 }
354
355 /// Utilize this `Uninit` allocation for a boxed value.
356 ///
357 /// Stores the value at the pointed-to location and utilizes the `Box` as a RAII-guard to
358 /// properly drop the value when the box itself is dropped.
359 pub fn into_box(self, val: T) -> Box<'a, T> {
360 Box::new(val, self)
361 }
362}
363
364impl<'a, T> Uninit<'a, [T]> {
365 /// Creates a pointer to an empty slice.
366 pub fn empty() -> Self {
367 Uninit::from_presumed_mutable_view(UninitView {
368 ptr: {
369 let base = ptr::NonNull::<T>::dangling().as_ptr();
370 let slice = ptr::slice_from_raw_parts_mut(base, 0);
371 ptr::NonNull::new(slice).unwrap()
372 },
373 len: 0,
374 lifetime: PhantomData,
375 typed: PhantomData,
376 })
377 }
378
379 /// Create an initializable pointer to the inner bytes of a `MaybeUninit`.
380 pub fn from_maybe_uninit_slice(mem: &'a mut [mem::MaybeUninit<T>]) -> Self {
381 let size = mem::size_of_val(mem);
382 let ptr = ptr::NonNull::from(mem);
383 let raw = unsafe {
384 // SAFETY:
385 // * unaliased as we had a mutable reference
386 // * can write uninitialized bytes as much as we want
387 Uninit::from_memory(ptr.cast(), size)
388 };
389 raw.cast_slice().unwrap()
390 }
391
392 /// Get the pointer to the first element of the slice.
393 ///
394 /// If the slice would be empty then the pointer may be the past-the-end pointer as well.
395 pub const fn as_begin_ptr(&self) -> *mut T {
396 self.view.ptr.as_ptr() as *mut T
397 }
398
399 /// Calculate the theoretical capacity of a slice in the pointed-to allocation.
400 pub fn capacity(&self) -> usize {
401 self.view.capacity()
402 }
403
404 /// Split the slice at an index.
405 ///
406 /// This is the pointer equivalent of `slice::split_at`.
407 pub fn split_at(&mut self, at: usize) -> Option<Self> {
408 self.view.split_at(at)
409 .map(Self::from_presumed_mutable_view)
410 }
411
412 /// Get the trailing bytes behind the slice.
413 ///
414 /// The underlying allocation need not be a multiple of the slice element size which may leave
415 /// unusable bytes. This splits these unusable bytes into an untyped `Uninit` which can be
416 /// reused arbitrarily.
417 ///
418 /// This operation is idempotent.
419 pub fn shrink_to_fit(&mut self) -> Uninit<'a, ()> {
420 Uninit::decast(self.split_at(self.capacity()).unwrap())
421 }
422
423 /// Split the first element from the slice.
424 ///
425 /// This is the pointer equivalent of `slice::split_first`.
426 pub fn split_first(&mut self) -> Option<Uninit<'a, T>> {
427 let mut part = self.split_at(1)?;
428 // Now we are the first part, but we wanted the first to be split off.
429 mem::swap(self, &mut part);
430 // If it is a valid slice of length 1 it is a valid `T`.
431 Some(Uninit::decast(part).cast().unwrap())
432 }
433
434 /// Split the last element from the slice.
435 ///
436 /// This is the pointer equivalent of `slice::split_last`.
437 pub fn split_last(&mut self) -> Option<Uninit<'a, T>> {
438 // Explicitely wrap here: If capacity is 0 then `0 < size_of::<T> ` and the split will fail.
439 let split = self.capacity().wrapping_sub(1);
440 let part = self.split_at(split)?;
441 // If it is a valid slice of length 1 it is a valid `T`.
442 Some(Uninit::decast(part).cast().unwrap())
443 }
444
445 /// Turn this into a slice of standard `MaybeUninit`s.
446 ///
447 /// This is mainly useful for interfacing with other consumers which expect standard library
448 /// types. It may also improve ergonomics for writing to the pointee partially initialized
449 /// instances of `T` that are obtained via other means.
450 ///
451 /// Note that the sequence `from_maybe_uninit_slice`, `into_maybe_uninit_slice` is a no-op. The
452 /// converse is however not the case, as it will potentially discard unused padding present in
453 /// the original `Uninit`.
454 pub fn into_maybe_uninit_slice(self) -> &'a mut [mem::MaybeUninit<T>] {
455 unsafe {
456 // SAFETY: MaybeUninit is a transparent wrapper and need not be initialized.
457 slice::from_raw_parts_mut(
458 self.as_begin_ptr() as *mut mem::MaybeUninit<T>,
459 self.capacity())
460 }
461 }
462}
463
464impl<'a, T: ?Sized> Uninit<'a, T> {
465 /// Create a view to typed uninitialized memory.
466 ///
467 /// It is given a capacity of memory to which it refers in *bytes*.
468 ///
469 /// ## Safety
470 ///
471 /// The `ptr` must describe a valid, *sized* region. Refer to `Layout::for_value_raw` for
472 /// details. This criteria is trivially fulfilled for any sized `T`.
473 ///
474 /// A valid allocation must exist at the pointer with length at least `len`.
475 ///
476 /// In particular, it is **UB** to create this from a reference to a variable of a type for
477 /// which a completely uninitialized content is not valid. The standard type for avoiding the
478 /// UB is `core::mem::MaybeUninit`.
479 ///
480 /// When in doubt, refactor code such that utilization of `from_maybe_uninit` is possible.
481 pub unsafe fn new(ptr: ptr::NonNull<T>, len: usize) -> Self {
482 Uninit {
483 view: UninitView::new(ptr, len),
484 mutable: PhantomData,
485 }
486 }
487
488 /// Return the number of bytes this may view.
489 pub fn byte_capacity(&self) -> usize {
490 self.view.byte_capacity()
491 }
492
493 /// Check if the view fits some layout.
494 ///
495 /// The `cast` to a type of the provided layout will work without error.
496 pub fn fits(&self, layout: Layout) -> bool {
497 self.view.fits(layout)
498 }
499
500 /// View the same uninit as untyped memory.
501 pub fn as_memory(self) -> Uninit<'a, ()> {
502 Uninit::decast(self)
503 }
504
505 /// A private version of the unsafe `from_view`.
506 ///
507 /// This must never be exposed.
508 fn from_presumed_mutable_view(view: UninitView<'a, T>) -> Self {
509 Uninit {
510 view,
511 mutable: PhantomData,
512 }
513 }
514
515 /// Borrow a view of the `Uninit` region.
516 ///
517 /// This is the equivalent of `&*mut_ref as *const _` but never runs afoul of accidentally
518 /// creating an actual reference.
519 pub fn borrow(&self) -> UninitView<'_, T> {
520 self.view
521 }
522
523 /// Borrow the `Uninit` region for a shorter duration.
524 ///
525 /// This is the equivalent of `&mut *mut_ref as *mut _` but never runs afoul of accidentally
526 /// creating an actual reference.
527 pub fn borrow_mut(&mut self) -> Uninit<'_, T> {
528 Uninit::from_presumed_mutable_view(self.view)
529 }
530
531 /// Get the byte size of the total allocation.
532 pub const fn size(&self) -> usize {
533 self.view.size()
534 }
535}
536impl UninitView<'_, ()> {
537 /// Create a uninit view from raw memory.
538 ///
539 /// ## Safety
540 /// A valid allocation must exist at the pointer with length at least `len`.
541 ///
542 /// In particular, it is **UB** to create this from a reference to a variable of a type for
543 /// which a completely uninitialized content is not valid. The standard type for avoiding the
544 /// UB is `core::mem::MaybeUninit`.
545 ///
546 /// When in doubt, refactor code such that utilization of `from_maybe_uninit` is possible.
547 pub unsafe fn from_memory(ptr: ptr::NonNull<u8>, len: usize) -> Self {
548 UninitView {
549 ptr: ptr.cast(),
550 len,
551 lifetime: PhantomData,
552 typed: PhantomData,
553 }
554 }
555
556 /// Split so that the second part fits the layout.
557 ///
558 /// See [`Uninit::split_layout`] for more details.
559 ///
560 /// [`Uninit::split_layout`]: ./struct.Uninit.html#method.split_layout
561 pub fn split_layout(&mut self, layout: Layout) -> Option<Self> {
562 let align = self.ptr.as_ptr()
563 .align_offset(layout.align());
564 let aligned_len = self.len
565 .checked_sub(align)
566 .and_then(|len| len.checked_sub(layout.size()));
567
568 if aligned_len.is_none() {
569 return None;
570 }
571
572 let aligned = self.split_at_byte(align)?;
573 assert!(aligned.fits(layout));
574 Some(aligned)
575 }
576}
577
578impl<'a> UninitView<'a, ()> {
579 fn decast<T: ?Sized>(view: UninitView<'a, T>) -> Self {
580 UninitView {
581 ptr: view.ptr.cast(),
582 len: view.len,
583 lifetime: PhantomData,
584 typed: PhantomData,
585 }
586 }
587
588 /// Split so that the tail is aligned and valid for a `U`.
589 pub fn split_cast<U>(&mut self) -> Option<UninitView<'a, U>> {
590 let split = self.split_layout(Layout::new::<U>())?;
591 let cast = split.cast::<U>().unwrap();
592 Some(cast)
593 }
594
595 /// Split so that the tail is aligned for a slice `[U]`.
596 pub fn split_slice<U>(&mut self) -> Option<UninitView<'a, [U]>> {
597 let layout = Layout::for_value::<[U]>(&[]);
598 let split = self.split_layout(layout)?;
599 let cast = split.cast_slice::<U>().unwrap();
600 Some(cast)
601 }
602}
603
604impl<T> UninitView<'_, T> {
605 /// Invent a new uninit allocation for a zero-sized type (ZST).
606 ///
607 /// # Panics
608 /// This method panics when the type parameter is not a zero sized type.
609 pub fn invent_for_zst() -> Self {
610 assert_eq!(mem::size_of::<T>(), 0, "Invented ZST uninit invoked with non-ZST");
611 let dangling = ptr::NonNull::<T>::dangling();
612 // SAFETY: all bytes are within the allocation.
613 let raw = unsafe { UninitView::from_memory(dangling.cast(), 0) };
614 raw.cast().unwrap()
615 }
616}
617
618impl<'a, T> UninitView<'a, T> {
619 /// Split the uninit view at a byte boundary.
620 ///
621 /// See [`Uninit::split_at_byte`] for more details.
622 ///
623 /// [`Uninit::split_at_byte`]: ./struct.Uninit.html#method.split_at_byte
624 pub fn split_at_byte(&mut self, at: usize) -> Option<UninitView<'a, ()>> {
625 if self.len < at || at < mem::size_of::<T>() {
626 return None;
627 }
628
629 let base = self.ptr.as_ptr();
630 // SAFETY: by `from_memory`, all offsets `< len` are within the allocation.
631 // In particular, no pointer within or one-past-the-end is null.
632 let next_base = unsafe { ptr::NonNull::new_unchecked(base.add(at)) };
633 let next_len = self.len - at;
634 self.len = at;
635
636 // SAFETY: within one allocation, namely the one we are in.
637 let other = unsafe { UninitView::from_memory(next_base.cast(), next_len) };
638 Some(other)
639 }
640
641 /// Create an view to the inner bytes of a `MaybeUninit`.
642 ///
643 /// This is hardly useful on its own but since `UninitView` mirrors the traversal methods of
644 /// `Uninit` it can be used to get pointers to already initialized elements in an immutable
645 /// context.
646 pub fn from_maybe_uninit(mem: &'a mem::MaybeUninit<T>) -> Self {
647 let ptr = ptr::NonNull::new(mem.as_ptr() as *mut T).unwrap();
648 let raw = unsafe {
649 // SAFETY:
650 // * unaliased as we had a mutable reference
651 // * we will not write through the pointer created
652 UninitView::from_memory(ptr.cast(), mem::size_of_val(mem))
653 };
654 raw.cast().unwrap()
655 }
656
657 /// Try to cast to an `UninitView` for a slice type.
658 pub fn cast_slice<U>(self) -> Result<UninitView<'a, [U]>, Self> {
659 let empty = Layout::for_value::<[U]>(&[]);
660
661 if !self.fits(empty) {
662 return Err(self)
663 }
664
665 Ok(UninitView {
666 ptr: {
667 let base = self.ptr.as_ptr() as *mut T;
668 let element = Layout::new::<U>();
669 let slice_len = if element.size() == 0 {
670 usize::MAX
671 } else {
672 self.len / element.size()
673 };
674 let slice = ptr::slice_from_raw_parts_mut(base as *mut U, slice_len);
675 ptr::NonNull::new(slice).unwrap()
676 },
677 len: self.len,
678 lifetime: PhantomData,
679 typed: PhantomData,
680 })
681 }
682
683 /// Split off the tail that is not required for holding an instance of `T`.
684 pub fn split_to_fit(&mut self) -> UninitView<'a, ()> {
685 self.split_at_byte(mem::size_of::<T>()).unwrap()
686 }
687
688 /// Turn this into a reference to standard `MaybeUninit`.
689 ///
690 /// This is mainly useful for interfacing with other consumers which expect standard library
691 /// types and to mirror `Uninit`.
692 ///
693 /// Note that the sequence `from_maybe_uninit`, `into_maybe_uninit` is a no-op. The converse is
694 /// however not the case, as it will potentially discard unused padding present in the original
695 /// `Uninit`.
696 pub fn into_maybe_uninit(self) -> &'a mem::MaybeUninit<T> {
697 // SAFETY: MaybeUninit is a transparent wrapper and need not be initialized.
698 unsafe { &*(self.as_ptr() as *const mem::MaybeUninit<T>) }
699 }
700}
701
702impl<'a, T: ?Sized> UninitView<'a, T> {
703 /// Create a reference to typed uninitialized memory.
704 ///
705 /// It is given a capacity of memory to which it refers in *bytes*.
706 ///
707 /// ## Safety
708 ///
709 /// The `ptr` must describe a valid, *sized* region. Refer to `Layout::for_value_raw` for
710 /// details. This criteria is trivially fulfilled for any sized `T`.
711 ///
712 /// A valid allocation must exist at the pointer with length at least `len`.
713 ///
714 /// In particular, it is **UB** to create this from a reference to a variable of a type for
715 /// which a completely uninitialized content is not valid. The standard type for avoiding the
716 /// UB is `core::mem::MaybeUninit`.
717 ///
718 /// When in doubt, refactor code such that utilization of `from_maybe_uninit` is possible.
719 pub unsafe fn new(ptr: ptr::NonNull<T>, len: usize) -> Self {
720 UninitView {
721 ptr,
722 len,
723 lifetime: PhantomData,
724 typed: PhantomData,
725 }
726 }
727
728 /// Return the number of bytes this may refer to.
729 pub fn byte_capacity(&self) -> usize {
730 self.len
731 }
732
733 /// Try to cast to an `UninitView` for another type.
734 pub fn cast<U>(self) -> Result<UninitView<'a, U>, Self> {
735 if !self.fits(Layout::new::<U>()) {
736 return Err(self);
737 }
738
739 Ok(UninitView {
740 ptr: self.ptr.cast(),
741 len: self.len,
742 lifetime: PhantomData,
743 typed: PhantomData,
744 })
745 }
746
747 /// Acquires the underlying `*const T` pointer.
748 pub const fn as_ptr(&self) -> *const T {
749 self.ptr.as_ptr() as *const T
750 }
751
752 /// Acquires the underlying pointer as a `NonNull`.
753 pub fn as_non_null(&self) -> ptr::NonNull<T> {
754 self.ptr
755 }
756
757 /// Dereferences the content.
758 ///
759 /// The resulting lifetime is bound to self so this behaves "as if" it were actually an
760 /// instance of T that is getting borrowed. If a longer lifetime is needed, use `into_ref`.
761 ///
762 /// ## Safety
763 /// The caller must ensure that the content has already been initialized.
764 pub unsafe fn as_ref(&self) -> &T {
765 self.into_ref()
766 }
767
768 /// Turn this into a reference to the content.
769 ///
770 /// ## Safety
771 /// The caller must ensure that the content has already been initialized.
772 pub unsafe fn into_ref(self) -> &'a T {
773 &*self.as_ptr()
774 }
775}
776
777impl<'a, T> UninitView<'a, [T]> {
778 /// Creates a pointer to an empty slice.
779 ///
780 /// Note that it will **not** be a mutable empty slice which means that it would be **UB** to
781 /// use it as an `Uninit`.
782 pub fn empty() -> Self {
783 UninitView {
784 ptr: {
785 let base = ptr::NonNull::<T>::dangling().as_ptr();
786 let slice = ptr::slice_from_raw_parts_mut(base, 0);
787 ptr::NonNull::new(slice).unwrap()
788 },
789 len: 0,
790 lifetime: PhantomData,
791 typed: PhantomData,
792 }
793 }
794
795 /// Create an view on potentially uninitialized memory bytes of a slice of `MaybeUninit`.
796 pub fn from_maybe_uninit_slice(mem: &'a [mem::MaybeUninit<T>]) -> Self {
797 let ptr = ptr::NonNull::from(mem);
798 let raw = unsafe {
799 // SAFETY:
800 // * can write uninitialized bytes as much as we want
801 UninitView::from_memory(ptr.cast(), mem::size_of_val(mem))
802 };
803 raw.cast_slice().unwrap()
804 }
805
806 /// Get the pointer to the first element of the slice.
807 pub fn as_begin_ptr(&self) -> *const T {
808 self.ptr.as_ptr() as *const T
809 }
810
811 /// Calculate the theoretical capacity of a slice in the pointed-to allocation.
812 pub fn capacity(&self) -> usize {
813 self.size()
814 .checked_div(mem::size_of::<T>())
815 .unwrap_or_else(usize::max_value)
816 }
817
818 /// Split the slice at an index.
819 pub fn split_at(&mut self, at: usize) -> Option<Self> {
820 // NOTE: Slice pointers are blocked by Rust stabilization we can not create one from a real
821 // reference to slice as that would restrict us to the memory covered by the reference.
822 // NOTE: Tracked here https://github.com/rust-lang/rust/issues/36925
823 let bytes = match at.checked_mul(mem::size_of::<T>()) {
824 None => return None,
825 Some(byte) if byte > self.len => return None,
826 Some(byte) => byte,
827 };
828
829 let next_len = self.len - bytes;
830 self.len = bytes;
831
832 let base = self.ptr.as_ptr() as *mut u8;
833 // SAFETY: was previously in bounds.
834 let next_base = unsafe { ptr::NonNull::new_unchecked(base.add(bytes)) };
835
836 // SAFETY: total allocation length at least `self.len + next_len`.
837 let other = unsafe { UninitView::from_memory(next_base, next_len) };
838 Some(other.cast_slice().unwrap())
839 }
840
841 /// Get the trailing bytes behind the slice.
842 ///
843 /// The underlying allocation need not be a multiple of the slice element size which may leave
844 /// unusable bytes. This splits these unusable bytes into an untyped `Uninit` which can be
845 /// reused arbitrarily.
846 ///
847 /// This operation is idempotent.
848 pub fn shrink_to_fit(&mut self) -> UninitView<'a, ()> {
849 UninitView::decast(self.split_at(self.capacity()).unwrap())
850 }
851
852 /// Split the first element from the slice.
853 pub fn split_first(&mut self) -> Option<UninitView<'a, T>> {
854 let mut part = self.split_at(1)?;
855 // Now we are the first part, but we wanted the first to be split off.
856 mem::swap(self, &mut part);
857 // If it is a valid slice of length 1 it is a valid `T`.
858 Some(UninitView::decast(part).cast().unwrap())
859 }
860
861 /// Split the last element from the slice.
862 pub fn split_last(&mut self) -> Option<UninitView<'a, T>> {
863 // Explicitely wrap here: If capacity is 0 then `0 < size_of::<T> ` and the split will fail.
864 let split = self.capacity().wrapping_sub(1);
865 let part = self.split_at(split)?;
866 // If it is a valid slice of length 1 it is a valid `T`.
867 Some(UninitView::decast(part).cast().unwrap())
868 }
869
870 /// Turn this into a slice of standard `MaybeUninit`s.
871 ///
872 /// This is mainly useful for interfacing with other consumers which expect standard library
873 /// types and to mirror `Uninit`.
874 ///
875 /// Note that the sequence `from_maybe_uninit_slice`, `into_maybe_uninit_slice` is a no-op. The
876 /// converse is however not the case, as it will potentially discard unused padding present in
877 /// the original `Uninit`.
878 pub fn into_maybe_uninit_slice(self) -> &'a [mem::MaybeUninit<T>] {
879 unsafe {
880 // SAFETY: MaybeUninit is a transparent wrapper and need not be initialized.
881 slice::from_raw_parts(
882 self.as_begin_ptr() as *const mem::MaybeUninit<T>,
883 self.capacity())
884 }
885 }
886}
887
888impl<'a, T: ?Sized> UninitView<'a, T> {
889 /// Check if the view fits some layout.
890 ///
891 /// The `cast` to a type of the provided layout will work without error.
892 pub fn fits(&self, layout: Layout) -> bool {
893 self.ptr.as_ptr().cast::<u8>().align_offset(layout.align()) == 0
894 && layout.size() <= self.len
895 }
896
897 /// Borrow another view of the `Uninit` region.
898 pub fn borrow(&self) -> UninitView<'_, T> {
899 *self
900 }
901
902 /// Get the byte size of the total allocation.
903 pub const fn size(&self) -> usize {
904 self.len
905 }
906}
907
908impl<'a, T> From<&'a mut mem::MaybeUninit<T>> for Uninit<'a, T> {
909 fn from(mem: &'a mut mem::MaybeUninit<T>) -> Self {
910 Uninit::<T>::from_maybe_uninit(mem)
911 }
912}
913
914impl<'a, T> From<&'a mut [mem::MaybeUninit<T>]> for Uninit<'a, [T]> {
915 fn from(mem: &'a mut [mem::MaybeUninit<T>]) -> Self {
916 Uninit::<[T]>::from_maybe_uninit_slice(mem)
917 }
918}
919
920impl<'a, T> From<&'a mem::MaybeUninit<T>> for UninitView<'a, T> {
921 fn from(mem: &'a mem::MaybeUninit<T>) -> Self {
922 UninitView::from_maybe_uninit(mem)
923 }
924}
925
926impl<'a, T> From<&'a [mem::MaybeUninit<T>]> for UninitView<'a, [T]> {
927 fn from(mem: &'a [mem::MaybeUninit<T>]) -> Self {
928 UninitView::<[T]>::from_maybe_uninit_slice(mem)
929 }
930}
931
932impl<T: ?Sized> fmt::Debug for Uninit<'_, T> {
933 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
934 f.debug_tuple("Uninit")
935 .field(&self.view.ptr)
936 .field(&self.view.len)
937 .finish()
938 }
939}
940
941impl<T: ?Sized> fmt::Debug for UninitView<'_, T> {
942 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
943 f.debug_tuple("UninitView")
944 .field(&self.ptr)
945 .field(&self.len)
946 .finish()
947 }
948}
949
950impl<'a, T> From<Uninit<'a, T>> for UninitView<'a, T> {
951 fn from(uninit: Uninit<'a, T>) -> Self {
952 uninit.view
953 }
954}
955
956impl<T> Default for Uninit<'_, [T]> {
957 fn default() -> Self {
958 Uninit::empty()
959 }
960}
961
962impl<T> Default for UninitView<'_, [T]> {
963 fn default() -> Self {
964 UninitView::empty()
965 }
966}
967
968impl<T: ?Sized> Clone for UninitView<'_, T> {
969 fn clone(&self) -> Self {
970 *self
971 }
972}
973
974impl<T: ?Sized> Copy for UninitView<'_, T> { }
975
976unsafe impl<'a, T, U: ?Sized> CoerciblePtr<U> for UninitView<'a, T> {
977 type Pointee = T;
978 type Output = UninitView<'a, U>;
979 fn as_sized_ptr(&mut self) -> *mut T {
980 self.as_ptr() as *mut T
981 }
982 unsafe fn replace_ptr(self, new: *mut U) -> UninitView<'a, U> {
983 let length = self.byte_capacity();
984 debug_assert_eq!(self.as_ptr() as *const u8, new as *const u8);
985 // SAFETY: caller guarantees this is equal to our pointer, which is non-null
986 let new = ptr::NonNull::new_unchecked(new);
987 UninitView::new(new, length)
988 }
989}
990
991unsafe impl<'a, T, U: ?Sized> CoerciblePtr<U> for Uninit<'a, T> {
992 type Pointee = T;
993 type Output = Uninit<'a, U>;
994
995 fn as_sized_ptr(&mut self) -> *mut T {
996 self.as_ptr()
997 }
998
999 unsafe fn replace_ptr(self, new: *mut U) -> Uninit<'a, U> {
1000 let length = self.byte_capacity();
1001 debug_assert_eq!(self.as_ptr() as *const u8, new as *const u8);
1002 // SAFETY: caller guarantees this is equal to our pointer, which is non-null
1003 let new = ptr::NonNull::new_unchecked(new);
1004 Uninit::new(new, length)
1005 }
1006}
1007
1008#[cfg(test)]
1009mod tests {
1010 use super::Uninit;
1011
1012 #[test]
1013 fn lifetime_longer() {
1014 fn _long<'a, T>(_: Uninit<'a, &'static T>) { }
1015 }
1016
1017 #[test]
1018 fn lifetime_shorter() {
1019 fn _short<'a, T>(_: Uninit<'static, &'a T>) { }
1020 }
1021
1022 #[test]
1023 fn in_a_struct() {
1024 enum _List<T> {
1025 Nil,
1026 Cons(T, Uninit<'static, T>),
1027 }
1028 }
1029}