outref/
lib.rs

1//! Out reference ([`&'a out T`](Out)).
2#![deny(
3    missing_docs,
4    clippy::all,
5    clippy::cargo,
6    clippy::missing_const_for_fn,
7    clippy::missing_inline_in_public_items,
8    clippy::must_use_candidate
9)]
10#![cfg_attr(not(test), no_std)]
11
12use core::marker::PhantomData;
13use core::mem::MaybeUninit;
14use core::ptr::{self, NonNull};
15use core::slice;
16
17/// Out reference ([`&'a out T`](Out)).
18///
19/// An out reference is similar to a mutable reference, but it may point to uninitialized memory.
20/// An out reference may be used to initialize the pointee or represent a data buffer.
21///
22/// [`&'a out T`](Out) can be converted from:
23/// + [`&'a mut MaybeUninit<T>`](core::mem::MaybeUninit)
24///     and [`&'a mut [MaybeUninit<T>]`](core::mem::MaybeUninit),
25///     where the `T` may be uninitialized.
26/// + [`&'a mut T`](reference) and [`&'a mut [T]`](prim@slice),
27///     where the `T` is initialized and [Copy].
28///
29/// It is not allowed to corrupt or de-initialize the pointee, which may cause unsoundness.
30/// It is the main difference between [`&'a out T`](Out)
31/// and [`&'a mut MaybeUninit<T>`](core::mem::MaybeUninit)
32/// /[`&'a mut [MaybeUninit<T>]`](core::mem::MaybeUninit).
33///
34/// Any reads through an out reference may read uninitialized value(s).
35#[repr(transparent)]
36pub struct Out<'a, T: 'a + ?Sized> {
37    data: NonNull<T>,
38    _marker: PhantomData<&'a mut T>,
39}
40
41unsafe impl<T: Send> Send for Out<'_, T> {}
42unsafe impl<T: Sync> Sync for Out<'_, T> {}
43impl<T: Unpin> Unpin for Out<'_, T> {}
44
45impl<'a, T: ?Sized> Out<'a, T> {
46    /// Forms an [`Out<'a, T>`](Out)
47    ///
48    /// # Safety
49    ///
50    /// * `data` must be valid for writes.
51    /// * `data` must be properly aligned.
52    #[inline(always)]
53    #[must_use]
54    pub unsafe fn new(data: *mut T) -> Self {
55        Self {
56            data: NonNull::new_unchecked(data),
57            _marker: PhantomData,
58        }
59    }
60
61    /// Converts to a mutable (unique) reference to the value.
62    ///
63    /// # Safety
64    /// The referenced value must be initialized when calling this function.
65    #[inline(always)]
66    #[must_use]
67    pub unsafe fn assume_init(mut self) -> &'a mut T {
68        self.data.as_mut()
69    }
70
71    /// Reborrows the out reference for a shorter lifetime.
72    #[inline(always)]
73    #[must_use]
74    pub fn reborrow<'s>(&'s mut self) -> Out<'s, T>
75    where
76        'a: 's,
77    {
78        Self {
79            data: self.data,
80            _marker: PhantomData,
81        }
82    }
83}
84
85impl<'a, T> Out<'a, T> {
86    /// Forms an [`Out<'a, T>`](Out).
87    #[inline(always)]
88    #[must_use]
89    pub fn from_mut(data: &'a mut T) -> Self
90    where
91        T: Copy,
92    {
93        unsafe { Self::new(data) }
94    }
95
96    /// Forms an [`Out<'a, T>`](Out) from an uninitialized value.
97    #[inline(always)]
98    #[must_use]
99    pub fn from_uninit(data: &'a mut MaybeUninit<T>) -> Self {
100        let data: *mut T = MaybeUninit::as_mut_ptr(data);
101        unsafe { Self::new(data.cast()) }
102    }
103
104    /// Converts to [`&'a mut MaybeUninit<T>`](core::mem::MaybeUninit)
105    /// # Safety
106    /// It is not allowed to corrupt or de-initialize the pointee.
107    #[inline(always)]
108    #[must_use]
109    pub unsafe fn into_uninit(self) -> &'a mut MaybeUninit<T> {
110        &mut *self.data.as_ptr().cast()
111    }
112
113    /// Returns an unsafe mutable pointer to the value.
114    #[inline(always)]
115    #[must_use]
116    pub fn as_mut_ptr(&mut self) -> *mut T {
117        self.data.as_ptr().cast()
118    }
119}
120
121impl<'a, T> Out<'a, [T]> {
122    /// Forms an [`Out<'a, [T]>`](Out).
123    #[inline(always)]
124    #[must_use]
125    pub fn from_slice(slice: &'a mut [T]) -> Self
126    where
127        T: Copy,
128    {
129        unsafe { Self::new(slice) }
130    }
131
132    /// Forms an [`Out<'a, [T]>`](Out) from an uninitialized slice.
133    #[inline(always)]
134    #[must_use]
135    pub fn from_uninit_slice(slice: &'a mut [MaybeUninit<T>]) -> Self {
136        let slice: *mut [T] = {
137            let len = slice.len();
138            let data = slice.as_mut_ptr().cast();
139            ptr::slice_from_raw_parts_mut(data, len)
140        };
141        unsafe { Self::new(slice) }
142    }
143
144    /// Converts to [`&'a mut [MaybeUninit<T>]`](core::mem::MaybeUninit)
145    /// # Safety
146    /// It is not allowed to corrupt or de-initialize the pointee.
147    #[inline(always)]
148    #[must_use]
149    pub unsafe fn into_uninit_slice(self) -> &'a mut [MaybeUninit<T>] {
150        let len = self.len();
151        let data = self.data.as_ptr().cast();
152        unsafe { slice::from_raw_parts_mut(data, len) }
153    }
154
155    /// Returns true if the slice has a length of 0.
156    #[inline(always)]
157    #[must_use]
158    pub const fn is_empty(&self) -> bool {
159        self.len() == 0
160    }
161
162    /// Returns the number of elements in the slice.
163    #[inline(always)]
164    #[must_use]
165    pub const fn len(&self) -> usize {
166        NonNull::len(self.data)
167    }
168
169    /// Returns an unsafe mutable pointer to the slice's buffer.
170    #[inline(always)]
171    #[must_use]
172    pub fn as_mut_ptr(&mut self) -> *mut T {
173        self.data.as_ptr().cast()
174    }
175}
176
177/// Extension trait for converting a mutable reference to an out reference.
178///
179/// # Safety
180/// This trait can be trusted to be implemented correctly for all types.
181pub unsafe trait AsOut<T: ?Sized> {
182    /// Returns an out reference to self.
183    fn as_out(&mut self) -> Out<'_, T>;
184}
185
186unsafe impl<T> AsOut<T> for T
187where
188    T: Copy,
189{
190    #[inline(always)]
191    #[must_use]
192    fn as_out(&mut self) -> Out<'_, T> {
193        Out::from_mut(self)
194    }
195}
196
197unsafe impl<T> AsOut<T> for MaybeUninit<T> {
198    #[inline(always)]
199    #[must_use]
200    fn as_out(&mut self) -> Out<'_, T> {
201        Out::from_uninit(self)
202    }
203}
204
205unsafe impl<T> AsOut<[T]> for [T]
206where
207    T: Copy,
208{
209    #[inline(always)]
210    #[must_use]
211    fn as_out(&mut self) -> Out<'_, [T]> {
212        Out::from_slice(self)
213    }
214}
215
216unsafe impl<T> AsOut<[T]> for [MaybeUninit<T>] {
217    #[inline(always)]
218    #[must_use]
219    fn as_out(&mut self) -> Out<'_, [T]> {
220        Out::from_uninit_slice(self)
221    }
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227
228    use core::{mem, ptr};
229
230    unsafe fn raw_fill_copied<T: Copy>(dst: *mut T, len: usize, val: T) {
231        if mem::size_of::<T>() == 0 {
232            return;
233        }
234
235        if len == 0 {
236            return;
237        }
238
239        if mem::size_of::<T>() == 1 {
240            let val: u8 = mem::transmute_copy(&val);
241            dst.write_bytes(val, len);
242        } else {
243            dst.write(val);
244
245            let mut n = 1;
246            while n <= len / 2 {
247                ptr::copy_nonoverlapping(dst, dst.add(n), n);
248                n *= 2;
249            }
250
251            let count = len - n;
252            if count > 0 {
253                ptr::copy_nonoverlapping(dst, dst.add(n), count);
254            }
255        }
256    }
257
258    fn fill<T: Copy>(mut buf: Out<'_, [T]>, val: T) -> &'_ mut [T] {
259        unsafe {
260            let len = buf.len();
261            let dst = buf.as_mut_ptr();
262            raw_fill_copied(dst, len, val);
263            buf.assume_init()
264        }
265    }
266
267    #[test]
268    fn fill_vec() {
269        for n in 0..128 {
270            let mut v: Vec<u32> = Vec::with_capacity(n);
271            fill(v.spare_capacity_mut().as_out(), 0x12345678);
272            unsafe { v.set_len(n) };
273            for &x in &v {
274                assert_eq!(x, 0x12345678);
275            }
276            drop(v);
277        }
278    }
279}