1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! Write-only references and slices.
#![deny(
    missing_docs,
    clippy::all,
    clippy::cargo,
    clippy::missing_const_for_fn,
    clippy::missing_inline_in_public_items
)]
#![no_std]

use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ptr::NonNull;

/// A write-only reference of `T`.
pub struct OutRef<'a, T> {
    data: NonNull<T>,
    _marker: PhantomData<&'a mut MaybeUninit<T>>,
}

unsafe impl<T: Send> Send for OutRef<'_, T> {}
unsafe impl<T: Sync> Sync for OutRef<'_, T> {}

impl<'a, T> OutRef<'a, T> {
    /// Forms an `OutRef<'a, T>`.
    ///
    /// # Safety
    ///
    /// Behavior is undefined if any of the following conditions are violated:
    ///
    /// * `data` must be valid for writes.
    ///
    /// * `data` must be properly aligned.
    #[inline(always)]
    pub unsafe fn from_raw(data: *mut T) -> Self {
        Self {
            data: NonNull::new_unchecked(data),
            _marker: PhantomData,
        }
    }

    /// Forms an `OutBuf` from an initialized value.
    #[inline(always)]
    pub fn new(val: &'a mut T) -> Self {
        let data: *mut T = val;
        unsafe { Self::from_raw(data) }
    }

    /// Forms an `OutBuf` from an uninitialized value.
    #[inline(always)]
    pub fn uninit(val: &'a mut MaybeUninit<T>) -> Self {
        let data: *mut T = MaybeUninit::as_mut_ptr(val);
        unsafe { Self::from_raw(data.cast()) }
    }

    /// Returns an unsafe mutable pointer to the value.
    #[inline(always)]
    pub fn as_mut_ptr(&mut self) -> *mut T {
        self.data.as_ptr().cast()
    }

    /// Sets the value of the `OutRef`.
    #[inline(always)]
    pub fn write(mut self, val: T) -> &'a mut T {
        unsafe {
            self.data.as_ptr().write(val);
            self.data.as_mut()
        }
    }
}

/// A write-only slice of `T`.
pub struct OutBuf<'a, T> {
    data: NonNull<MaybeUninit<T>>,
    len: usize,
    _marker: PhantomData<&'a mut [MaybeUninit<T>]>,
}

unsafe impl<T: Send> Send for OutBuf<'_, T> {}
unsafe impl<T: Sync> Sync for OutBuf<'_, T> {}

impl<'a, T> OutBuf<'a, T> {
    /// Forms an `OutBuf<'a, T>`
    ///
    /// # Safety
    ///
    /// Behavior is undefined if any of the following conditions are violated:
    ///
    /// * `data` must be `valid` for writes for `len * mem::size_of::<T>()` many bytes,
    ///   and it must be properly aligned. This means in particular:
    ///
    ///     * The entire memory range of this slice must be contained within a single allocated object!
    ///       Slices can never span across multiple allocated objects.
    ///     * `data` must be non-null and aligned even for zero-length slices. One
    ///       reason for this is that enum layout optimizations may rely on references
    ///       (including slices of any length) being aligned and non-null to distinguish
    ///       them from other data. You can obtain a pointer that is usable as `data`
    ///       for zero-length slices using `NonNull::dangling()`.
    ///
    /// * `data` must point to `len` consecutive places for type `T`.
    ///
    /// * The memory referenced by the returned slice must not be accessed through any other pointer
    ///   (not derived from the return value) for the duration of lifetime `'a`.
    ///   Both read and write accesses are forbidden.
    ///
    /// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
    ///   See the safety documentation of `pointer::offset`.
    #[inline(always)]
    pub unsafe fn from_raw(data: *mut T, len: usize) -> Self {
        Self {
            data: NonNull::new_unchecked(data as *mut MaybeUninit<T>),
            len,
            _marker: PhantomData,
        }
    }

    /// Forms an `OutBuf` from an initialized slice.
    #[inline(always)]
    pub fn new(slice: &'a mut [T]) -> Self {
        let len = slice.len();
        let data = slice.as_mut_ptr();
        unsafe { Self::from_raw(data, len) }
    }

    /// Forms an `OutBuf` from an uninitialized slice.
    #[inline(always)]
    pub fn uninit(slice: &'a mut [MaybeUninit<T>]) -> Self {
        let len = slice.len();
        let data = slice.as_mut_ptr();
        unsafe { Self::from_raw(data.cast(), len) }
    }

    /// Returns true if the buffer has a length of 0.
    #[inline(always)]
    pub const fn is_empty(&self) -> bool {
        self.len == 0
    }

    /// Returns the number of elements in the buffer.
    #[inline(always)]
    pub const fn len(&self) -> usize {
        self.len
    }

    /// Returns an unsafe mutable pointer to the buffer.
    #[inline(always)]
    pub fn as_mut_ptr(&mut self) -> *mut T {
        self.data.as_ptr().cast()
    }
}