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
//! Generic over borrow mutability.

use core::mem::{ManuallyDrop, MaybeUninit};

/// A higher kinded type.
pub trait HigherKinded<'a> {
    /// The type with `T` applied.
    type ForT<T: ?Sized + 'a>: Unpin + 'a;
}

/// A pointer like type.
///
/// Allows being generic over `&T` and `&mut T`.
///
/// Implemented by marker types [`Ref`] and [`Mut`].
pub trait Indirect<'a>: HigherKinded<'a> + sealed::Sealed<'a> {}

pub(super) mod sealed {
    use crate::hkt::{Invariant, Marker};

    use super::*;

    /// Sealed trait to prevent users from implementing Indirect and provides conversion
    /// to and from a raw indirect.
    pub trait Sealed<'a>: HigherKinded<'a> + Sized {
        /// Convert the pointer into a raw indirection.
        fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> MaybeUninit<[u8; INDIRECT_SIZE]>;

        /// Convert a raw indirection back into the pointer.
        ///
        /// # Safety
        /// `value` must have been created by `Self::into_raw`.
        /// This function must not be called twice for the same `value`.
        /// The type `T` must be the one given to `Self::into_raw`.
        unsafe fn from_raw<T: ?Sized + 'a>(
            value: MaybeUninit<[u8; INDIRECT_SIZE]>,
        ) -> Self::ForT<T>;
    }

    /// An opaque set of bytes the size of a fat pointer.
    ///
    /// Repr wise this is exactly `MaybeUninit<[u8; { size of a fat pointer }]>`.
    #[repr(transparent)]
    pub struct RawIndirect<'a, I> {
        indirect: MaybeUninit<[u8; INDIRECT_SIZE]>,
        _lifetime: Invariant<'a>,
        _generic: Marker<I>,
    }

    impl<'a, I: Indirect<'a>> RawIndirect<'a, I> {
        pub fn new<T: ?Sized>(indirect: I::ForT<T>) -> Self {
            Self {
                indirect: I::into_raw(indirect),
                _lifetime: Default::default(),
                _generic: Default::default(),
            }
        }

        /// # Safety
        /// The type `T` must be the same one used in `Self::new`.
        pub unsafe fn into_inner<T: ?Sized>(self) -> I::ForT<T> {
            // SAFETY: indirect was created with this I's into_raw in Self::new.
            // This function cannot be called twice because we take ownership of self and
            // this type is not clone or copy.
            // The caller makes sure that the T is the same.
            // Also the lifetime 'a must be the same because Self is invariant over it.
            unsafe { I::from_raw(self.indirect) }
        }
    }

    /// Size of a fat pointer.
    const INDIRECT_SIZE: usize = core::mem::size_of::<usize>() * 2;

    /// Helper trait for double checking the sizes of fat pointers.
    trait Helper {
        fn run(&self);
    }

    const _: () = assert!(
        core::mem::size_of::<&dyn Helper>() <= core::mem::size_of::<RawIndirect<'_, Ref>>()
    );

    // Borrow doesn't need to be dropped.
    const _: () = assert!(!core::mem::needs_drop::<&i32>());

    const _: () = assert!(
        core::mem::size_of::<&mut dyn Helper>()
            <= core::mem::size_of::<sealed::RawIndirect<'_, Mut>>()
    );

    // Mutable borrow doesn't need to be dropped.
    const _: () = assert!(!core::mem::needs_drop::<&mut i32>());

    impl<'a> Sealed<'a> for Ref {
        fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> MaybeUninit<[u8; INDIRECT_SIZE]> {
            // SAFETY: A possibly fat borrow can be stores in a 2 usize wide maybe uninit array.
            unsafe { transmute::<&'a T, MaybeUninit<[u8; INDIRECT_SIZE]>>(value) }
        }

        unsafe fn from_raw<T: ?Sized + 'a>(any: MaybeUninit<[u8; INDIRECT_SIZE]>) -> Self::ForT<T> {
            // SAFETY: We know the value is from Self::into_raw because of the caller invariants.
            unsafe { transmute::<MaybeUninit<[u8; INDIRECT_SIZE]>, &'a T>(any) }
        }
    }

    impl<'a> Sealed<'a> for Mut {
        fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> MaybeUninit<[u8; INDIRECT_SIZE]> {
            // SAFETY: A possibly fat borrow can be stores in a 2 usize wide maybe uninit array.
            unsafe { transmute::<&'a mut T, MaybeUninit<[u8; INDIRECT_SIZE]>>(value) }
        }

        unsafe fn from_raw<T: ?Sized + 'a>(any: MaybeUninit<[u8; INDIRECT_SIZE]>) -> Self::ForT<T> {
            // SAFETY: We know the value is from Self::into_raw because of the caller invariants.
            unsafe { transmute::<MaybeUninit<[u8; INDIRECT_SIZE]>, &'a mut T>(any) }
        }
    }
}

/// Marker type for [`AnyTraitObject`](super::AnyTraitObject) for a borrow `&T`.
pub enum Ref {}

impl<'a> HigherKinded<'a> for Ref {
    type ForT<T: ?Sized + 'a> = &'a T;
}

impl<'a> Indirect<'a> for Ref {}

/// Marker type for [`AnyTraitObject`](super::AnyTraitObject) for a mutable borrow `&mut T`.
pub enum Mut {}

impl<'a> HigherKinded<'a> for Mut {
    type ForT<T: ?Sized + 'a> = &'a mut T;
}

impl<'a> Indirect<'a> for Mut {}

/// # Safety
/// Same rules as [`core::mem::transmute()`].
unsafe fn transmute<T, U>(value: T) -> U {
    // Create union type that can store a `T` or a `U`.
    // We can then use this to convert between them.
    //
    // The repr(C) layout forces no offset between `t` and `u` as talked about here
    // https://rust-lang.github.io/unsafe-code-guidelines/layout/unions.html#c-compatible-layout-repr-c
    #[repr(C)]
    union Transmute<T, U> {
        t: ManuallyDrop<T>,
        u: ManuallyDrop<U>,
    }

    // Create the union in the `T` state.
    let value = Transmute {
        t: ManuallyDrop::new(value),
    };

    // Read from the union in the `U` state.
    // SAFETY: This is safe because the caller has promised that `T` can be transmuted to `U`.
    // The following reference link talks about repr(C) unions being used this way.
    // https://doc.rust-lang.org/reference/items/unions.html#reading-and-writing-union-fields
    ManuallyDrop::into_inner(unsafe { value.u })
}

#[cfg(test)]
mod test {
    use super::*;

    use sealed::RawIndirect;

    #[test]
    fn can_type_erase_borrow() {
        let x = 42;
        let y: &i32 = &x;
        let z = RawIndirect::<Ref>::new(y);

        // SAFETY: Same type as y which we made it from.
        let w: &i32 = unsafe { z.into_inner() };

        assert_eq!(w, y);
    }

    trait AsInt {
        fn as_int(&self) -> i32;
    }

    impl AsInt for i32 {
        fn as_int(&self) -> i32 {
            *self
        }
    }

    #[test]
    fn can_type_erase_unsized_borrow() {
        let x = 42;
        let y: &dyn AsInt = &x;
        let z = RawIndirect::<Ref>::new(y);

        // SAFETY: Same type as y which we made it from.
        let w: &i32 = unsafe { z.into_inner() };

        assert_eq!(w.as_int(), x);
    }

    #[test]
    fn can_type_erase_mut_borrow() {
        let mut x = 42;
        let y: &mut i32 = &mut x;
        let z = RawIndirect::<Mut>::new(y);

        // SAFETY: Same type as y which we made it from.
        let w: &mut i32 = unsafe { z.into_inner() };

        *w += 1;
        assert_eq!(x, 43);
    }

    trait AddOne {
        fn add_one(&mut self);
    }

    impl AddOne for i32 {
        fn add_one(&mut self) {
            *self += 1;
        }
    }

    #[test]
    fn can_type_erase_unsized_mut_borrow() {
        let mut x = 42;
        let y: &mut dyn AddOne = &mut x;
        let z = RawIndirect::<Mut>::new(y);

        // SAFETY: Same type as y which we made it from.
        let w: &mut dyn AddOne = unsafe { z.into_inner() };

        w.add_one();

        assert_eq!(x, 43);
    }
}