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
use_prelude!();

use crate::extension_traits::Transpose;
use ::core::mem::ManuallyDrop;

/// Extension trait to convert a `&mut _` into a `&out _` by calling
/// `.as_out()` on it.
///
/// By autoref, this means that you can even just extract a `&out T` reference
/// out of a `mut` element simply by calling `.as_out()` on it.
///
/// There is, however, one restriction: to be able to call `.as_out()` on
/// something, it needs to be either `Copy`, or a value wrapped in a
/// [`MaybeUninit`] / a [`ManuallyDrop`].
///
/// This is by design. Indeed, [`Out`] references do not call the destructor
/// of the overwritten element (since it may not be initialized).
/// This could cause memory leaks when there is an initialized element with
/// [drop glue][core::mem::needs_drop].
///
/// To solve this limitation, one must explicitly call
/// [`.manually_drop_mut()`][`crate::ManuallyDropMut::manually_drop_mut`]
/// to automagically transmute the `&mut _` reference into a
/// `&mut ManuallyDrop<_>`.
///
/// # Examples
///
/// ```rust
/// use ::uninit::prelude::*;
///
/// let mut x = 0;
/// x.as_out().write(42);
///
/// let mut y = ::core::mem::MaybeUninit::uninit();
/// y.as_out().write(42);
/// let y = unsafe { y.assume_init() };
///
/// assert_eq!(x, y);
/// ```
pub trait AsOut<Pointee: ?Sized> {
    #[allow(missing_docs)]
    fn as_out<'out>(self: &'out mut Self) -> Out<'out, Pointee>;
}

impl<T> AsOut<T> for MaybeUninit<T> {
    #[inline]
    fn as_out<'out>(self: &'out mut MaybeUninit<T>) -> Out<'out, T> {
        self.into()
    }
}

impl<T> AsOut<T> for T
where
    T: Copy,
{
    #[inline]
    fn as_out<'out>(self: &'out mut T) -> Out<'out, T> {
        self.into()
    }
}

impl<T> AsOut<[T]> for [MaybeUninit<T>] {
    #[inline]
    fn as_out<'out>(self: &'out mut [MaybeUninit<T>]) -> Out<'out, [T]> {
        self.into()
    }
}

impl<T> AsOut<[T]> for [T]
where
    T: Copy,
{
    #[inline]
    fn as_out<'out>(self: &'out mut [T]) -> Out<'out, [T]> {
        self.into()
    }
}

impl<T: ?Sized> AsOut<T> for ManuallyDrop<T> {
    #[inline]
    fn as_out<'out>(self: &'out mut ManuallyDrop<T>) -> Out<'out, T> {
        self.into()
    }
}

impl<T> AsOut<[T]> for [ManuallyDrop<T>] {
    #[inline]
    fn as_out<'out>(self: &'out mut [ManuallyDrop<T>]) -> Out<'out, [T]> {
        self.into()
    }
}

impl<T, const N: usize> AsOut<[T]> for MaybeUninit<[T; N]> {
    #[inline]
    fn as_out<'out>(self: &'out mut Self) -> Out<'out, [T]> {
        From::from(&mut self.transpose()[..])
    }
}

impl<T, const N: usize> AsOut<[T]> for [MaybeUninit<T>; N] {
    #[inline]
    fn as_out<'out>(self: &'out mut Self) -> Out<'out, [T]> {
        From::from(&mut self[..])
    }
}

impl<T, const N: usize> AsOut<[T]> for [T; N]
where
    T: Copy,
{
    #[inline]
    fn as_out<'out>(self: &'out mut Self) -> Out<'out, [T]> {
        From::from(&mut self[..])
    }
}