Skip to main content

relibc/
out.rs

1//! Wrapper for the "out pointer" pattern.
2//!
3//! This is functionally equivalent to `&Cell<MaybeUninit<T>>` except the only allowed operation is
4//! to write a `T`. Using `MaybeUninit` directly would not have been equally general; a
5//! `&mut MaybeUninit<T>` could never then be created from a `&mut T` and passed to safe code,
6//! which can safely replace it with `MaybeUninit::uninit` and make the existence of `&mut T` UB.
7//!
8//! As for the "`&Cell<...>`", this is to be slightly weaker than Rust's normally strict
9//! requirement that `&mut` references are never aliased, which can typically not be assumed when
10//! getting pointers from C.
11
12use core::{cell::UnsafeCell, fmt, marker::PhantomData, mem::MaybeUninit, ptr::NonNull};
13
14/// Wrapper for write-only "out pointers" that are safe to write to
15// TODO: We may want to change this to &mut MaybeUninit, or have a generic parameter deciding
16// whether it should be noalias or not
17#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
18pub struct Out<'a, T: ?Sized> {
19    ptr: NonNull<T>,
20    _marker: PhantomData<&'a UnsafeCell<T>>,
21}
22impl<'a, T: ?Sized> Out<'a, T> {
23    /// # Safety
24    ///
25    /// - pointer must either be NULL, or be valid for the duration of lifetime `'a`
26    #[inline]
27    pub unsafe fn nullable(ptr: *mut T) -> Option<Self> {
28        Some(Self {
29            ptr: NonNull::new(ptr)?,
30            _marker: PhantomData,
31        })
32    }
33    /// # Safety
34    ///
35    /// - pointer must be valid for the duration of lifetime `'a`
36    #[inline]
37    pub unsafe fn nonnull(ptr: *mut T) -> Self {
38        if cfg!(debug_assertions) {
39            assert!(!ptr.is_null());
40        }
41        Self {
42            ptr: unsafe { NonNull::new_unchecked(ptr) },
43            _marker: PhantomData,
44        }
45    }
46    #[inline]
47    pub fn from_mut(r: &'a mut T) -> Self {
48        // SAFETY:
49        //
50        // - `r` will obviously have the same lifetime as Self
51        // - a Rust reference is obviously valid as a pointer, and the lifetime is tied to that of
52        // this struct
53        unsafe { Self::nonnull(r) }
54    }
55    #[inline]
56    pub fn as_mut_ptr(&mut self) -> *mut T {
57        self.ptr.as_ptr()
58    }
59}
60impl<'a, T> Out<'a, T> {
61    #[inline]
62    pub fn from_uninit_mut(r: &'a mut MaybeUninit<T>) -> Self {
63        // SAFETY:
64        //
65        // Same as for from_mut. It's fine if *r is uninitialized, as this wrapper only allows
66        // writes.
67        unsafe { Self::nonnull(r.as_mut_ptr()) }
68    }
69    #[inline]
70    pub fn write(&mut self, t: T) {
71        unsafe {
72            self.ptr.as_ptr().write(t);
73        }
74    }
75}
76impl<'a, T, const N: usize> Out<'a, [T; N]> {
77    #[inline]
78    pub fn as_slice_mut<'b>(&'b mut self) -> Out<'b, [T]> {
79        unsafe {
80            let ptr: *mut [T; N] = self.as_mut_ptr();
81            Out::from_raw_parts(ptr.cast::<T>(), N)
82        }
83    }
84}
85impl<'a, T> Out<'a, [T]> {
86    /// # Safety
87    ///
88    /// If `len > 0`, `ptr` be valid for `len` elements of `T`, during lifetime `'a`.
89    pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
90        // Empty slices must be non-NULL in Rust, but C typically does not force this for
91        // pointer-length pairs.
92        let ptr = if len == 0 {
93            core::ptr::dangling_mut::<T>()
94        } else {
95            ptr
96        };
97        unsafe { Self::nonnull(core::ptr::slice_from_raw_parts_mut(ptr, len)) }
98    }
99    pub fn len(&self) -> usize {
100        self.ptr.as_ptr().len()
101    }
102    pub fn is_empty(&self) -> bool {
103        self.len() == 0
104    }
105    // TODO: Maybe strengthen lifetimes?
106    #[inline]
107    pub fn split_at_checked<'b>(&'b mut self, n: usize) -> Option<[Out<'b, [T]>; 2]> {
108        let l = self.ptr.len();
109        if n > l {
110            return None;
111        }
112        Some([
113            Out {
114                ptr: unsafe {
115                    NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
116                        self.ptr.as_mut_ptr(),
117                        n,
118                    ))
119                },
120                _marker: PhantomData,
121            },
122            Out {
123                ptr: unsafe {
124                    NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
125                        self.ptr.as_mut_ptr().add(n),
126                        l - n,
127                    ))
128                },
129                _marker: PhantomData,
130            },
131        ])
132    }
133    #[inline]
134    pub fn copy_from_slice(&mut self, src: &[T])
135    where
136        T: Copy,
137    {
138        assert_eq!(
139            self.ptr.len(),
140            src.len(),
141            "Out::copy_from_slice size mismatch"
142        );
143        unsafe {
144            // SAFETY:
145            //
146            // - we have already know from the existence of self that the slice is a valid writable
147            // pointer
148            // - src is similarly also a valid readable pointer of the same type
149            // - because of `T: Copy`, it is valid to copy bytes directly
150            // - although self.ptr may alias, src must not alias with any writable pointer, and the
151            // Copy bound ensures T cannot have interior mutability since `UnsafeCell: !Copy`
152            self.ptr
153                .as_mut_ptr()
154                .copy_from_nonoverlapping(src.as_ptr(), src.len());
155        }
156    }
157    pub fn copy_common_length_from_slice(&mut self, src: &[T]) -> usize
158    where
159        T: Copy,
160    {
161        let l = src.len().min(self.len());
162        self.split_at_checked(l).unwrap()[0].copy_from_slice(&src[..l]);
163        l
164    }
165    // TODO: better API, impl RangeBounds, also fn get(usize) -> Out<T>
166    pub fn subslice<'b>(&'b mut self, start: usize, end: usize) -> Out<'b, [T]> {
167        assert!(start <= end);
168        assert!(end <= self.len());
169        unsafe { Self::from_raw_parts(self.as_mut_ptr().as_mut_ptr().add(start), end - start) }
170    }
171    pub fn index<'b>(&'b mut self, i: usize) -> Out<'b, T> {
172        assert!(i <= self.len());
173        unsafe { Out::nonnull(self.as_mut_ptr().as_mut_ptr().add(i)) }
174    }
175}
176// TODO: use bytemuck
177impl<T: plain::Plain> Out<'_, [T]> {
178    pub fn zero(&mut self) {
179        let l = self.ptr.len();
180        unsafe {
181            // SAFETY:
182            // - already know the pointer is valid up to its length
183            // - the Plain trait ensures zero is a valid bit pattern
184            self.ptr.as_mut_ptr().write_bytes(0, l)
185        }
186    }
187    #[inline]
188    pub fn cast_slice_to<'b, U>(mut self) -> Out<'b, [U]>
189    where
190        T: CastSlice<U>,
191    {
192        assert_eq!(self.as_mut_ptr().as_mut_ptr() as usize % align_of::<U>(), 0);
193
194        let byte_length = self.as_mut_ptr().len() * size_of::<T>();
195
196        unsafe {
197            Out::from_raw_parts(
198                self.as_mut_ptr().as_mut_ptr().cast(),
199                byte_length / size_of::<U>(),
200            )
201        }
202    }
203}
204// TODO: use bytemuck
205pub unsafe trait CastSlice<U> {}
206unsafe impl CastSlice<i8> for u8 {}
207unsafe impl CastSlice<u8> for i8 {}
208unsafe impl CastSlice<u8> for u8 {}
209unsafe impl CastSlice<i8> for i8 {}
210
211impl<T: ?Sized> fmt::Pointer for Out<'_, T> {
212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213        write!(f, "{:p}", self.ptr)
214    }
215}
216impl<T: ?Sized> fmt::Debug for Out<'_, T> {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218        write!(f, "[Out: {:p}]", self.ptr)
219    }
220}
221/// Marker trait for types where it is sound to turn `Out<struct { ... }>` into `struct { ...:
222/// Out<...> }` by simply referencing fields. This is safe for any struct but must not be
223/// implemented for `Deref` types so that `Out<&struct { ... }>` is never projected in a way that
224/// adds mutability.
225pub unsafe trait OutProject {}
226
227impl<'a, T: ?Sized> Out<'a, T> {
228    pub unsafe fn with_lifetime_of<'b, U: ?Sized>(mut self, u: &'b U) -> Out<'b, T> {
229        unsafe { Out::nonnull(self.as_mut_ptr()) }
230    }
231}