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
mod impls;

use ::mischief::{In, Region, Slot};
use ::ptr_meta::{metadata, Pointee};
use ::situ::{DropRaw, Mut, Val};

/// A value emplacer.
///
/// # Safety
///
/// - `emplaced_meta` must return valid metadata for the value emplaced with
///   `emplace_unsized_unchecked`.
/// - `emplace_unsized_unchecked` must initialize its `out` parameter.
pub unsafe trait Emplace<T: DropRaw + Pointee + ?Sized, R: Region> {
    /// Returns the metadata of the `T` that this emplaces.
    ///
    /// For sized `T`, this is always `()`.
    fn emplaced_meta(&self) -> <T as Pointee>::Metadata;

    /// Emplaces a value into a given slot within some memory region.
    ///
    /// # Safety
    ///
    /// `out` must have the metadata returned by `emplaced_meta`.
    unsafe fn emplace_unsized_unchecked(self, out: In<Slot<'_, T>, R>);
}

/// An extension trait for `Emplace` that provides a variety of convenient
/// emplacement methods.
///
/// # Safety
///
/// `emplace_val_unsized` and `emplace_val` must initialize `out` and return it
/// as a `Val`.
pub unsafe trait EmplaceExt<T, R: Region>: Emplace<T, R>
where
    T: DropRaw + Pointee + ?Sized,
{
    /// Emplaces a value into a given slot within some memory region.
    ///
    /// # Panics
    ///
    /// Panics if `out` does not have the metadata returned by `emplaced_meta`.
    fn emplace_unsized(self, out: In<Slot<'_, T>, R>);

    /// Emplaces a sized value into a given slot within some memory region.
    ///
    /// This simply wraps a call to `emplace_unsized_unchecked`. Because `T` is
    /// `Sized`, the metadata of the slot's pointer must always match the
    /// metadata returned from `emplaced_meta`, and so it is safe.
    fn emplace(self, out: In<Slot<'_, T>, R>)
    where
        T: Sized;

    /// Emplaces a value into a given slot within some memory region and returns
    /// a mutable reference.
    ///
    /// # Safety
    ///
    /// `out` must have the metadata returned by `emplaced_meta`.
    unsafe fn emplace_mut_unsized(
        self,
        out: In<Slot<'_, T>, R>,
    ) -> In<Mut<'_, T>, R>;

    /// Emplaces a sized value into a given slot within some memory region and
    /// returns a mutable reference.
    fn emplace_mut(self, out: In<Slot<'_, T>, R>) -> In<Mut<'_, T>, R>;

    /// Emplaces a value into a given slot within some memory region and returns
    /// an initialized value.
    ///
    /// # Safety
    ///
    /// `out` must have the metadata returned by `emplaced_meta`.
    #[must_use]
    unsafe fn emplace_val_unsized(
        self,
        out: In<Slot<'_, T>, R>,
    ) -> In<Val<'_, T>, R>;

    /// Emplaces a sized value into a given slot within some memory region and
    /// returns an initialized value.
    ///
    /// This simply wraps a call to `emplace_val_unsized`. Because `T` is sized,
    /// the metadata of the slot's pointer must always match the metadata
    /// returned from `emplaced_meta`, and so it is safe.
    #[must_use]
    fn emplace_val(self, out: In<Slot<'_, T>, R>) -> In<Val<'_, T>, R>
    where
        T: Sized;
}

// SAFETY: `emplace_val` initializes `out` and returns it as a `Val`.
unsafe impl<E, T, R> EmplaceExt<T, R> for E
where
    E: Emplace<T, R>,
    T: DropRaw + Pointee + ?Sized,
    R: Region,
{
    fn emplace_unsized(self, out: In<Slot<'_, T>, R>) {
        assert!(self.emplaced_meta() == metadata::<T>(out.ptr().as_ptr()));
        // SAFETY: We have asserted that the metadata of `self` and `out` are
        // equal.
        unsafe {
            self.emplace_unsized_unchecked(out);
        }
    }

    #[inline]
    fn emplace(self, out: In<Slot<'_, T>, R>)
    where
        T: Sized,
    {
        // SAFETY: `out` can only have the metadata `()` and so it must be the
        // same as the metadata returned from `emplaced_meta`.
        unsafe { self.emplace_unsized_unchecked(out) }
    }

    unsafe fn emplace_mut_unsized(
        self,
        out: In<Slot<'_, T>, R>,
    ) -> In<Mut<'_, T>, R> {
        // SAFETY: The caller has guaranteed that `out` has the metadata
        // returned by `emplaced_meta`.
        let val = unsafe { self.emplace_val_unsized(out) };
        // SAFETY: `Val::leak` returns a mutable reference to its contained
        // value. Since the value is allocated in `R`, its contained value must
        // also be.
        unsafe { In::map_unchecked(val, Val::leak) }
    }

    #[inline]
    fn emplace_mut(self, out: In<Slot<'_, T>, R>) -> In<Mut<'_, T>, R> {
        // SAFETY: `out` can only have the metadata `()` and so it must be the
        // same as the metadata returned from `emplaced_meta`.
        unsafe { self.emplace_mut_unsized(out) }
    }

    #[must_use]
    unsafe fn emplace_val_unsized(
        self,
        mut out: In<Slot<'_, T>, R>,
    ) -> In<Val<'_, T>, R> {
        // SAFETY: The caller has guaranteed that `out` has the metadata
        // returned by `emplaced_meta`.
        unsafe {
            self.emplace_unsized_unchecked(out.as_mut());
        }
        // SAFETY: `emplace` is guaranteed to initialize `out`.
        let initialize = |s| unsafe { Val::from_slot_unchecked(s) };
        // SAFETY: the `Val` created from `out` points to the same memory and so
        // must be located in the same region.
        unsafe { out.map_unchecked(initialize) }
    }

    #[inline]
    #[must_use]
    fn emplace_val(self, out: In<Slot<'_, T>, R>) -> In<Val<'_, T>, R>
    where
        T: Sized,
    {
        // SAFETY: `out` can only have the metadata `()` and so it must be the
        // same as the metadata returned from `emplaced_meta`.
        unsafe { self.emplace_val_unsized(out) }
    }
}