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) and cause undefined behavior.
35///
36/// [`AsOut`] provides a shortcut for converting a mutable reference to an out reference.
37///
38/// # Examples
39///
40/// ```rust
41/// use core::ptr;
42/// use core::slice;
43/// use core::mem::MaybeUninit;
44///
45/// use outref::AsOut;
46/// use outref::Out;
47///
48/// fn copy<'d, T: Copy>(src: &[T], mut dst: Out<'d, [T]>) -> &'d mut [T] {
49///     assert_eq!(src.len(), dst.len());
50///     unsafe {
51///         let count = src.len();
52///         let src = src.as_ptr();
53///         let dst = dst.as_mut_ptr();
54///         ptr::copy_nonoverlapping(src, dst, count);
55///         slice::from_raw_parts_mut(dst, count)
56///     }
57/// }
58///
59/// fn copy_init<'d, T: Copy>(src: &[T], dst: &'d mut [T]) -> &'d mut [T] {
60///     copy(src, dst.as_out())
61/// }
62///
63/// fn copy_uninit<'d, T: Copy>(src: &[T], dst: &'d mut [MaybeUninit<T>]) -> &'d mut [T] {
64///     copy(src, dst.as_out())
65/// }
66/// ```
67#[repr(transparent)]
68pub struct Out<'a, T: 'a + ?Sized> {
69    data: NonNull<T>,
70    _marker: PhantomData<&'a mut T>,
71}
72
73unsafe impl<T: Send> Send for Out<'_, T> {}
74unsafe impl<T: Sync> Sync for Out<'_, T> {}
75impl<T: Unpin> Unpin for Out<'_, T> {}
76
77impl<'a, T: ?Sized> Out<'a, T> {
78    /// Forms an [`Out<'a, T>`](Out)
79    ///
80    /// # Safety
81    ///
82    /// * `data` must be valid for writes.
83    /// * `data` must be properly aligned.
84    #[inline(always)]
85    #[must_use]
86    pub unsafe fn new(data: *mut T) -> Self {
87        Self {
88            data: NonNull::new_unchecked(data),
89            _marker: PhantomData,
90        }
91    }
92
93    /// Converts to a mutable (unique) reference to the value.
94    ///
95    /// # Safety
96    /// The referenced value must be initialized when calling this function.
97    #[inline(always)]
98    #[must_use]
99    pub unsafe fn assume_init(mut self) -> &'a mut T {
100        self.data.as_mut()
101    }
102
103    /// Reborrows the out reference for a shorter lifetime.
104    #[inline(always)]
105    #[must_use]
106    pub fn reborrow<'s>(&'s mut self) -> Out<'s, T>
107    where
108        'a: 's,
109    {
110        Self {
111            data: self.data,
112            _marker: PhantomData,
113        }
114    }
115}
116
117impl<'a, T> Out<'a, T> {
118    /// Forms an [`Out<'a, T>`](Out).
119    #[inline(always)]
120    #[must_use]
121    pub fn from_mut(data: &'a mut T) -> Self
122    where
123        T: Copy,
124    {
125        unsafe { Self::new(data) }
126    }
127
128    /// Forms an [`Out<'a, T>`](Out) from an uninitialized value.
129    #[inline(always)]
130    #[must_use]
131    pub fn from_uninit(data: &'a mut MaybeUninit<T>) -> Self {
132        let data: *mut T = MaybeUninit::as_mut_ptr(data);
133        unsafe { Self::new(data.cast()) }
134    }
135
136    /// Converts to [`&'a mut MaybeUninit<T>`](core::mem::MaybeUninit)
137    /// # Safety
138    /// It is not allowed to corrupt or de-initialize the pointee.
139    #[inline(always)]
140    #[must_use]
141    pub unsafe fn into_uninit(self) -> &'a mut MaybeUninit<T> {
142        &mut *self.data.as_ptr().cast()
143    }
144
145    /// Returns an unsafe mutable pointer to the value.
146    #[inline(always)]
147    #[must_use]
148    pub fn as_mut_ptr(&mut self) -> *mut T {
149        self.data.as_ptr().cast()
150    }
151}
152
153impl<'a, T> Out<'a, [T]> {
154    /// Forms an [`Out<'a, [T]>`](Out).
155    #[inline(always)]
156    #[must_use]
157    pub fn from_slice(slice: &'a mut [T]) -> Self
158    where
159        T: Copy,
160    {
161        unsafe { Self::new(slice) }
162    }
163
164    /// Forms an [`Out<'a, [T]>`](Out) from an uninitialized slice.
165    #[inline(always)]
166    #[must_use]
167    pub fn from_uninit_slice(slice: &'a mut [MaybeUninit<T>]) -> Self {
168        let slice: *mut [T] = {
169            let len = slice.len();
170            let data = slice.as_mut_ptr().cast();
171            ptr::slice_from_raw_parts_mut(data, len)
172        };
173        unsafe { Self::new(slice) }
174    }
175
176    /// Converts to [`&'a mut [MaybeUninit<T>]`](core::mem::MaybeUninit)
177    /// # Safety
178    /// It is not allowed to corrupt or de-initialize the pointee.
179    #[inline(always)]
180    #[must_use]
181    pub unsafe fn into_uninit_slice(self) -> &'a mut [MaybeUninit<T>] {
182        let len = self.len();
183        let data = self.data.as_ptr().cast();
184        slice::from_raw_parts_mut(data, len)
185    }
186
187    /// Returns true if the slice has a length of 0.
188    #[inline(always)]
189    #[must_use]
190    pub const fn is_empty(&self) -> bool {
191        self.len() == 0
192    }
193
194    /// Returns the number of elements in the slice.
195    #[inline(always)]
196    #[must_use]
197    pub const fn len(&self) -> usize {
198        NonNull::len(self.data)
199    }
200
201    /// Returns an unsafe mutable pointer to the slice's buffer.
202    #[inline(always)]
203    #[must_use]
204    pub fn as_mut_ptr(&mut self) -> *mut T {
205        self.data.as_ptr().cast()
206    }
207}
208
209/// Extension trait for converting a mutable reference to an out reference.
210///
211/// # Safety
212/// This trait can be trusted to be implemented correctly for all types.
213pub unsafe trait AsOut<T: ?Sized> {
214    /// Returns an out reference to self.
215    fn as_out(&mut self) -> Out<'_, T>;
216}
217
218unsafe impl<T> AsOut<T> for T
219where
220    T: Copy,
221{
222    #[inline(always)]
223    #[must_use]
224    fn as_out(&mut self) -> Out<'_, T> {
225        Out::from_mut(self)
226    }
227}
228
229unsafe impl<T> AsOut<T> for MaybeUninit<T> {
230    #[inline(always)]
231    #[must_use]
232    fn as_out(&mut self) -> Out<'_, T> {
233        Out::from_uninit(self)
234    }
235}
236
237unsafe impl<T> AsOut<[T]> for [T]
238where
239    T: Copy,
240{
241    #[inline(always)]
242    #[must_use]
243    fn as_out(&mut self) -> Out<'_, [T]> {
244        Out::from_slice(self)
245    }
246}
247
248unsafe impl<T> AsOut<[T]> for [MaybeUninit<T>] {
249    #[inline(always)]
250    #[must_use]
251    fn as_out(&mut self) -> Out<'_, [T]> {
252        Out::from_uninit_slice(self)
253    }
254}
255
256#[cfg(test)]
257mod tests {
258    use super::*;
259
260    use core::{mem, ptr};
261
262    unsafe fn raw_fill_copied<T: Copy>(dst: *mut T, len: usize, val: T) {
263        if mem::size_of::<T>() == 0 {
264            return;
265        }
266
267        if len == 0 {
268            return;
269        }
270
271        if mem::size_of::<T>() == 1 {
272            let val: u8 = mem::transmute_copy(&val);
273            dst.write_bytes(val, len);
274        } else {
275            dst.write(val);
276
277            let mut n = 1;
278            while n <= len / 2 {
279                ptr::copy_nonoverlapping(dst, dst.add(n), n);
280                n *= 2;
281            }
282
283            let count = len - n;
284            if count > 0 {
285                ptr::copy_nonoverlapping(dst, dst.add(n), count);
286            }
287        }
288    }
289
290    fn fill<T: Copy>(mut buf: Out<'_, [T]>, val: T) -> &'_ mut [T] {
291        unsafe {
292            let len = buf.len();
293            let dst = buf.as_mut_ptr();
294            raw_fill_copied(dst, len, val);
295            buf.assume_init()
296        }
297    }
298
299    #[test]
300    fn fill_vec() {
301        for n in 0..128 {
302            let mut v: Vec<u32> = Vec::with_capacity(n);
303            fill(v.spare_capacity_mut().as_out(), 0x12345678);
304            unsafe { v.set_len(n) };
305            for &x in &v {
306                assert_eq!(x, 0x12345678);
307            }
308            drop(v);
309        }
310    }
311}