wref 1.0.2

Write-only references.
Documentation
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
//! Write-only references.
//!
//! A library solution to a useful language feature: write-only references. At the moment, there is
//! a gap in the functionality of Rust's borrows:
//!
//! |                     |Read|Write|
//! |--------------------:|:--:|:---:|
//! |[`&mut T`][reference]|✔   |✔    |
//! |[`&T`][reference]    |✔   |     |
//! |[`WRef<'_, T>`]      |    |✔    |
//! |don't write any code |    |     |
//!
//! This kind of functionality is useful because it doesn't care whether the reference points to
//! initialized memory; it's always sound to *write* to memory regardless of whether it's
//! initialized, and it's only [unsound to *read*][undefined.invalid] [uninitialized memory][undefined.validity.undef].
//!
//! [undefined.invalid]: https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html#r-undefined.invalid
//! [undefined.validity.undef]: https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html#r-undefined.validity.undef
//!
//! You might think this is possible with [`MaybeUninit`], but it's actually not: with `&mut
//! MaybeUninit<T>`, you can write a value to the memory to initialize it, but you can also
//! *de-initialize* it by writing a value of type `MaybeUninit<T>` directly:
//!
//! ```
//! # use core::mem::MaybeUninit;
//! // initialized
//! let data = &mut MaybeUninit::new(1);
//!
//! // now de-initialized!
//! *data = MaybeUninit::uninit();
//! ```
//!
//! Since `&mut MaybeUninit<T>` can de-initialize data, it cannot be used as a general
//! write-reference for data that must be initialized. So, this crate exists.
//!
//! While the crate itself uses unsafe code to ensure its invariants without triggering undefined
//! behaviour, it can be used by other code to safely generalize between `&mut T` and `&mut
//! MaybeUninit<T>` in cases where only writing is needed.
#![cfg_attr(not(test), no_std)]
#![cfg_attr(feature = "nightly", feature(slice_ptr_get))]
#![cfg_attr(feature = "nightly", feature(doc_cfg))]
#![cfg_attr(feature = "nightly", doc(auto_cfg))]

use core::{
    fmt,
    iter::FusedIterator,
    marker::PhantomData,
    mem::MaybeUninit,
    ptr::{self, NonNull},
    slice,
};

#[cfg(feature = "nightly")]
use core::slice::SliceIndex;

/// Iterator returned by [`<WRef<'_, [T]>>::iter`][WRef::iter].
pub struct Iter<'a, T> {
    /// Inner iterator.
    inner: slice::IterMut<'a, MaybeUninit<T>>,
}
impl<T> fmt::Debug for Iter<'_, T> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Iter")
            .field("len", &self.inner.len())
            .finish_non_exhaustive()
    }
}
impl<'a, T> Iterator for Iter<'a, T> {
    type Item = WRef<'a, T>;

    #[inline]
    fn next(&mut self) -> Option<WRef<'a, T>> {
        self.inner.next().map(WRef::from_maybe_uninit_mut)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
    #[inline]
    fn next_back(&mut self) -> Option<WRef<'a, T>> {
        self.inner.next_back().map(WRef::from_maybe_uninit_mut)
    }
}
impl<T> ExactSizeIterator for Iter<'_, T> {
    #[inline]
    fn len(&self) -> usize {
        self.inner.len()
    }
}
impl<T> FusedIterator for Iter<'_, T> {}

/// Alias for [`WRef::from_mut`].
#[inline]
pub const fn from_mut<T: ?Sized>(value: &mut T) -> WRef<'_, T> {
    WRef::from_mut(value)
}

/// Alias for [`WRef::from_maybe_uninit_mut`].
#[inline]
pub const fn from_maybe_uninit_mut<T>(maybe: &mut MaybeUninit<T>) -> WRef<'_, T> {
    WRef::from_maybe_uninit_mut(maybe)
}

/// Alias for [`WRef::from_maybe_uninit_slice_mut`].
#[inline]
pub const fn from_maybe_uninit_slice_mut<T>(slice: &mut [MaybeUninit<T>]) -> WRef<'_, [T]> {
    WRef::from_maybe_uninit_slice_mut(slice)
}

/// Write-only reference type.
///
/// See [crate docs][crate] for more info.
#[repr(transparent)]
pub struct WRef<'a, T: ?Sized> {
    /// Pointer to data.
    ///
    /// We can't actually use a mutable reference due to conflicting constraints:
    ///
    /// * The data might be uninitialized, so, we can't have a regular mutable reference.
    /// * [`MaybeUninit`] doesn't support unsized types, and we want to support slices.
    inner: NonNull<T>,

    /// Ownership/lifetime marker.
    marker: PhantomData<&'a mut T>,
}
impl<'a, T: ?Sized> WRef<'a, T> {
    /// Converts a mutable reference to a write-only reference.
    #[inline]
    pub const fn from_mut(value: &mut T) -> WRef<'a, T> {
        WRef {
            inner: NonNull::from_mut(value),
            marker: PhantomData,
        }
    }

    /// Converts the reference to a mutable pointer.
    ///
    /// While this method itself is safe, the caller must take care to only write to the pointer
    /// while it has exclusive access to the write reference, since breaking this invariant leads
    /// to [undefined behaivour][undefined.alias].
    ///
    /// [undefined.alias]: https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html#r-undefined.alias
    #[inline]
    pub const fn as_mut_ptr(&mut self) -> *mut T {
        self.inner.as_ptr()
    }

    /// Converts the reference to a non-null pointer.
    ///
    /// While this method itself is safe, the caller must take care to only write to the pointer
    /// while it has exclusive access to the write reference, since breaking this invariant leads
    /// to [undefined behaivour][undefined.alias].
    ///
    /// [undefined.alias]: https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html#r-undefined.alias
    #[inline]
    pub const fn as_non_null_ptr(&mut self) -> NonNull<T> {
        self.inner
    }

    /// Reborrows the [`WRef`] for a shorter lifetime.
    ///
    /// By default, most methods on write-references take the reference by value, applying for the
    /// remainder of the reference's lifetime. If you wish to perform multiple operations on a
    /// write-reference, you should reborrow it to do so:
    ///
    /// ```
    /// let mut val = 1;
    /// let mut wr = wref::from_mut(&mut val);
    /// assert_eq!(wr.reborrow().write(2), &mut 2);
    /// assert_eq!(wr.reborrow().write(3), &mut 3);
    /// assert_eq!(val, 3);
    /// ```
    #[inline]
    pub const fn reborrow(&mut self) -> WRef<'_, T> {
        WRef {
            inner: self.inner,
            marker: PhantomData,
        }
    }
}
impl<'a, T> WRef<'a, T> {
    /// Converts a mutable, maybe-uninit reference to a write-only reference.
    ///
    /// Due to restrictions on [`MaybeUninit`], the target of the reference must be sized.
    /// If you want to make a write-reference to a maybe-uninit slice, see
    /// [`WRef::from_maybe_uninit_slice_mut`].
    #[inline]
    pub const fn from_maybe_uninit_mut(maybe: &'a mut MaybeUninit<T>) -> WRef<'a, T> {
        WRef {
            inner: NonNull::from_mut(maybe).cast::<T>(),
            marker: PhantomData,
        }
    }

    /// Converts the write-reference to a mutable, maybe-uninit reference.
    ///
    /// Due to restrictions on [`MaybeUninit`], the target of the reference must be sized.
    /// If you want to make a maybe-uninit slice, see
    /// [`WRef::as_maybe_uninit_slice`].
    ///
    /// # Safety
    ///
    /// Simply calling this function is always safe, but writing uninitialized data to the reference
    /// might result in undefined behaviour. In particular, if this write-reference originates from
    /// an initialized reference `&mut T` instead of a maybe-uninit reference `&mut MaybeUninit<T>`,
    /// then writing uninitialized data would result in an [invalid value], which is undefined
    /// behaviour.
    ///
    /// [invalid value]: https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html#r-undefined.validity.undef
    pub const unsafe fn as_maybe_uninit(self) -> &'a mut MaybeUninit<T> {
        // SAFETY: We have a valid reference to the data, and the caller promises to not
        //   de-initialize the data.
        unsafe { &mut *self.inner.cast::<MaybeUninit<T>>().as_ptr() }
    }

    /// Writes a value to the reference.
    ///
    /// Although the reference is only valid for writing initially, after a write, it is valid to be
    /// read as well, since doing so would simply reveal the immediately-written value.
    ///
    /// If you want to reuse the write-reference after writing, you must either [reconstruct it]
    /// after writing or [reborrow it] before writing.
    ///
    /// If the reference pointed to an initialized value before the write, that value is [forgotten]
    /// and never dropped.
    ///
    /// [reconstruct it]: WRef::from_mut
    /// [reborrow it]: WRef::reborrow
    /// [forgotten]: core::mem::forget
    #[inline]
    pub const fn write(self, value: T) -> &'a mut T {
        // SAFETY: The inner pointer is valid and aligned.
        unsafe { self.inner.write(value) }

        // SAFETY: We just initialized the inner pointer.
        unsafe { self.assume_init_mut() }
    }
}
impl<'a, T: ?Sized> WRef<'a, T> {
    /// Converts the write-reference to a read-write reference.
    ///
    /// # Safety
    ///
    /// This is only safe if the reference actually contains an initialized value, which can only be
    /// ensured in general if a [`write`] has been performed beforehand.
    ///
    /// [`write`]: WRef::write
    #[inline]
    pub const unsafe fn assume_init_mut(mut self) -> &'a mut T {
        // SAFETY: We've explicitly initialized the value.
        unsafe { self.inner.as_mut() }
    }
}
impl<'a, T> WRef<'a, [T]> {
    /// Converts a mutable, maybe-uninit slice to a write-only slice.
    ///
    /// Due to restrictions on [`MaybeUninit`], maybe-uninit slices work differently from values.
    /// If you want to make a write-reference to a regular, sized value, see
    /// [`WRef::from_maybe_uninit_mut`].
    #[inline]
    pub const fn from_maybe_uninit_slice_mut(slice: &mut [MaybeUninit<T>]) -> WRef<'a, [T]> {
        // SAFETY: We can't use `NonNull::from_mut` here because we can't cast to `[T]`, even
        //   though this is otherwise safe.
        let inner =
            unsafe { NonNull::new_unchecked(ptr::from_mut::<[MaybeUninit<T>]>(slice) as *mut [T]) };
        WRef {
            inner,
            marker: PhantomData,
        }
    }

    /// Converts a write-only slice to a maybe-uninit slice.
    ///
    /// Due to restrictions on [`MaybeUninit`], maybe-uninit slices work differently from values.
    /// If you want to make a maybe-uninit reference to a regular, sized value, see
    /// [`WRef::as_maybe_uninit`].
    ///
    /// # Safety
    ///
    /// Simply calling this function is always safe, but writing uninitialized data to the slice
    /// might result in undefined behaviour. In particular, if this write-only slice originates from
    /// an initialized slice `&mut [T]` instead of a maybe-uninit slice `&mut [MaybeUninit<T>]`,
    /// then writing uninitialized data would result in an [invalid value], which is undefined
    /// behaviour.
    ///
    /// [invalid value]: https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html#r-undefined.validity.undef
    pub const unsafe fn as_maybe_uninit_slice(self) -> &'a mut [MaybeUninit<T>] {
        // SAFETY: We have a valid reference to the data, and the caller promises to not
        //   de-initialize the data.
        unsafe { &mut *(self.inner.as_ptr() as *mut [MaybeUninit<T>]) }
    }

    /// Returns a write-reference to an element or subslice depending on the type of index.
    ///
    /// Requires the unstable [`pointer::get_unchecked_mut`] method.
    ///
    /// This works identically to the regular [`Index`] operator, but operates on a write-only
    /// slice. The `SliceIndex<[MaybeUninit<T>]>` bound is unfortunate, but required due to a lack
    /// of a way to perform the bounds check on pointers.
    ///
    /// [`Index`]: core::ops::Index
    /// [`pointer::get_unchecked_mut`]: *mut ()
    #[cfg(feature = "nightly")]
    pub fn index<I: Clone + SliceIndex<[T]> + SliceIndex<[MaybeUninit<T>]>>(
        mut self,
        index: I,
    ) -> WRef<'a, <I as SliceIndex<[T]>>::Output> {
        // SAFETY: We don't mutate the slice.
        let _ = unsafe { &self.reborrow().as_maybe_uninit_slice()[index.clone()] };

        // SAFETY: This is okay since we don't dereference the pointer
        //   and already verified the bounds.
        let inner = unsafe { self.inner.get_unchecked_mut(index.clone()) };

        // get the new pointer, and wrap that inside our result
        WRef {
            inner,
            marker: PhantomData,
        }
    }

    /// Divides one slice into two at an index.
    ///
    /// This works identically to the regular [`split_at_mut`] method, but operates on a write-only
    /// slice.
    ///
    /// [`split_at_mut`]: slice::split_at_mut
    pub const fn split_at(self, index: usize) -> (WRef<'a, [T]>, WRef<'a, [T]>) {
        // SAFETY: We don't mutate the slice.
        let (lo, hi) = unsafe { self.as_maybe_uninit_slice().split_at_mut(index) };

        (
            WRef::from_maybe_uninit_slice_mut(lo),
            WRef::from_maybe_uninit_slice_mut(hi),
        )
    }

    /// Returns the length of a write-only slice.
    ///
    /// Although the *data* for the slice is write-only, the length is not part of this data,
    /// and is thus readable.
    #[inline]
    pub const fn len(&self) -> usize {
        self.inner.len()
    }

    /// Returns `true` if the write-only slice has a length of 0.
    ///
    /// Although the *data* for the slice is write-only, the length is not part of this data,
    /// and is thus readable.
    #[inline]
    pub const fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Returns an iterator over the write-only slice.
    ///
    /// This is similar to [`slice::iter_mut`], but returns write-only references to the elements
    /// instead.
    #[inline]
    pub fn iter(self) -> Iter<'a, T> {
        Iter {
            // SAFETY: We return only forward-init references from the iterator.
            inner: unsafe { self.as_maybe_uninit_slice().iter_mut() },
        }
    }
}
impl<'a, T: Clone> WRef<'a, [T]> {
    /// Writes clones of the elements from `src` to the write-only slice.
    ///
    /// If `T` implements `Copy`, use [`write_copy_of_slice`] instead.
    ///
    /// [`write_copy_of_slice`]: WRef::write_copy_of_slice
    ///
    /// Although the slice is only valid for writing initially, after a write, it is valid to be
    /// read as well, since doing so would simply reveal the immediately-written slice.
    ///
    /// If you want to reuse the write-reference after writing, you must either [reconstruct it]
    /// after writing or [reborrow it] before writing.
    ///
    /// If any values in the slice were initialized before the write, those values are [forgotten]
    /// and never dropped.
    ///
    /// [reconstruct it]: WRef::from_mut
    /// [reborrow it]: WRef::reborrow
    /// [forgotten]: core::mem::forget
    ///
    /// # Panics
    ///
    /// Panics if `self` and `src` are different lengths.
    #[inline]
    pub fn write_clone_of_slice(self, src: &[T]) -> &'a mut [T] {
        // SAFETY: We don't de-initialize the slice.
        unsafe { self.as_maybe_uninit_slice().write_clone_of_slice(src) }
    }
}
impl<'a, T: Copy> WRef<'a, [T]> {
    /// Writes copies of the elements from `src` to the write-only slice.
    ///
    /// If `T` implements `Clone`, use [`write_clone_of_slice`] instead.
    ///
    /// [`write_clone_of_slice`]: WRef::write_clone_of_slice
    ///
    /// Although the slice is only valid for writing initially, after a write, it is valid to be
    /// read as well, since doing so would simply reveal the immediately-written slice.
    ///
    /// If you want to reuse the write-reference after writing, you must either [reconstruct it]
    /// after writing or [reborrow it] before writing.
    ///
    /// [reconstruct it]: WRef::from_mut
    /// [reborrow it]: WRef::reborrow
    /// [forgotten]: core::mem::forget
    ///
    /// # Panics
    ///
    /// Panics if `self` and `src` are different lengths.
    #[inline]
    pub const fn write_copy_of_slice(self, src: &[T]) -> &'a mut [T] {
        // SAFETY: We don't de-initialize the slice.
        unsafe { self.as_maybe_uninit_slice().write_copy_of_slice(src) }
    }
}
impl<T> fmt::Debug for WRef<'_, T> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&<MaybeUninit<T>>::uninit(), f)
    }
}

#[cfg(test)]
mod tests {
    #![allow(clippy::undocumented_unsafe_blocks)]
    use core::mem::MaybeUninit;

    use crate::WRef;

    #[test]
    fn init_maybe_uninit_int() {
        let mut maybe = MaybeUninit::uninit();
        let fwd = WRef::from_maybe_uninit_mut(&mut maybe);
        fwd.write(1);
        assert_eq!(unsafe { maybe.assume_init() }, 1);
    }

    #[test]
    fn init_init_int() {
        let mut init = 4;
        let fwd = WRef::from_mut(&mut init);
        fwd.write(1);
        assert_eq!(init, 1);
    }

    #[test]
    fn assume_init_int() {
        let mut init = 4;
        let fwd = WRef::from_mut(&mut init);
        assert_eq!(*unsafe { fwd.assume_init_mut() }, 4);
    }

    #[test]
    fn init_maybe_uninit_int_slice() {
        let mut maybe = [MaybeUninit::uninit(); 10];
        let fwd = WRef::from_maybe_uninit_slice_mut(&mut maybe);
        fwd.write_copy_of_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(
            maybe.map(|x| unsafe { x.assume_init() }),
            [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        );
    }

    #[test]
    fn init_init_int_slice() {
        let mut init = [0; 10];
        let fwd = WRef::from_mut(&mut init[..]);
        fwd.write_copy_of_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(init, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    }

    #[test]
    fn assume_init_int_slice() {
        let mut init = [0; 10];
        let fwd = WRef::from_mut(&mut init[..]);
        assert_eq!(unsafe { fwd.assume_init_mut() }, &[0; 10]);
    }

    #[test]
    fn init_maybe_uninit_char() {
        let mut maybe = MaybeUninit::uninit();
        let fwd = WRef::from_maybe_uninit_mut(&mut maybe);
        fwd.write('');
        assert_eq!(unsafe { maybe.assume_init() }, '');
    }

    #[test]
    fn init_init_char() {
        let mut init = 'A';
        let fwd = WRef::from_mut(&mut init);
        fwd.write('');
        assert_eq!(init, '');
    }

    #[test]
    fn assume_init_char() {
        let mut init = 'A';
        let fwd = WRef::from_mut(&mut init);
        assert_eq!(*unsafe { fwd.assume_init_mut() }, 'A');
    }

    #[test]
    fn init_maybe_uninit_char_slice() {
        let mut maybe = [MaybeUninit::uninit(); 5];
        let fwd = WRef::from_maybe_uninit_slice_mut(&mut maybe);
        fwd.write_clone_of_slice(&['', '', '', '', '']);
        assert_eq!(
            maybe.map(|x| unsafe { x.assume_init() }),
            ['', '', '', '', '']
        );
    }

    #[test]
    fn init_init_char_slice() {
        let mut init = ['\0'; 5];
        let fwd = WRef::from_mut(&mut init[..]);
        fwd.write_clone_of_slice(&['', '', '', '', '']);
        assert_eq!(init, ['', '', '', '', '']);
    }

    #[test]
    fn assume_init_char_slice() {
        let mut init = ['\0'; 5];
        let fwd = WRef::from_mut(&mut init[..]);
        assert_eq!(unsafe { fwd.assume_init_mut() }, &['\0'; 5]);
    }
}