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
use ::core::marker::PhantomData;
use ::mischief::{In, Region, Slot};
use ::situ::{ops::IndexMutRaw, Mut, Val};

use crate::{Move, MoveExt};

macro_rules! impl_builtin {
    ($($ty:ty),*) => {
        $(
            // SAFETY: `move_unsized_unchecked` initializes `out` by emplacing
            // to it.
            unsafe impl<R: Region> Move<R> for $ty {
                unsafe fn move_unsized_unchecked(
                    this: In<Val<'_, Self>, R>,
                    out: In<Slot<'_, Self>, R>,
                ) {
                    // SAFETY: `$ty` is `Sized`, so it has metadata `()` and
                    // `out` must have the same metadata as it.
                    unsafe {
                        Val::read_unsized_unchecked(
                            In::into_inner(this),
                            In::into_inner(out),
                        );
                    }
                }
            }
        )*
    };
}

impl_builtin!(i8, u8, bool, ());

// SAFETY: `move_unsized_unchecked` initializes its `out` parameter by emplacing
// to every element in it.
unsafe impl<T, R: Region, const N: usize> Move<R> for [T; N]
where
    T: Move<R>,
{
    unsafe fn move_unsized_unchecked(
        this: In<Val<'_, Self>, R>,
        out: In<Slot<'_, Self>, R>,
    ) {
        let mut this = Val::leak(In::into_inner(this));
        let mut out = In::into_inner(out);

        for i in 0..N {
            // SAFETY: `i` is in bounds because it must be less than the length
            // of the array, `N`.
            let this_i = unsafe {
                IndexMutRaw::index_mut_raw_unchecked(this.as_mut(), i)
            };
            // SAFETY:
            // - `this_i` is an element of `this`, which we own and may drop.
            // - `this_i` is only taken once, and `this` is leaked so its
            //   elements will not be accessed again.
            let this_i = unsafe { Mut::take(this_i) };
            // SAFETY: `this_i` is an element of `this`, which is located in
            // `R`, so `this_i` must also be located in `R`.
            let this_i = unsafe { In::new_unchecked(this_i) };
            // SAFETY: `i` is in bounds because it must be less than the length
            // of the array, `N`.
            let out_i = unsafe { out.as_mut().get_unchecked(i) };
            // SAFETY: `out_i` is an element of `out`, which is located in `R`,
            // so `out_i` must also be located in `R`.
            let out_i = unsafe { In::new_unchecked(out_i) };
            T::r#move(this_i, out_i);
        }
    }
}

// SAFETY: `move_unsized_unchecked` initializes its `out` parameter by emplacing
// to every element in it.
unsafe impl<T, R: Region> Move<R> for [T]
where
    T: Move<R>,
{
    unsafe fn move_unsized_unchecked(
        this: In<Val<'_, Self>, R>,
        out: In<Slot<'_, Self>, R>,
    ) {
        let len = this.len();
        let mut this = Val::leak(In::into_inner(this));
        let mut out = In::into_inner(out);

        for i in 0..len {
            // SAFETY: `i` is in bounds because it must be less than the length
            // of the array, `len`.
            let this_i = unsafe {
                IndexMutRaw::index_mut_raw_unchecked(this.as_mut(), i)
            };
            // SAFETY:
            // - `this_i` is an element of `this`, which we own and may drop.
            // - `this_i` is only taken once, and `this` is leaked so its
            //   elements will not be accessed again.
            let this_i = unsafe { Mut::take(this_i) };
            // SAFETY: `this_i` is an element of `this`, which is located in
            // `R`, so `this_i` must also be located in `R`.
            let this_i = unsafe { In::new_unchecked(this_i) };
            // SAFETY: `i` is in bounds because it must be less than the length
            // of the array, `len`.
            let out_i = unsafe { out.as_mut().get_unchecked(i) };
            // SAFETY: `out_i` is an element of `out`, which is located in `R`,
            // so `out_i` must also be located in `R`.
            let out_i = unsafe { In::new_unchecked(out_i) };
            T::r#move(this_i, out_i);
        }
    }
}

// SAFETY: `move_unsized_unchecked` does not have to initialize `out` because
// `PhantomData` is zero-sized and so always initialized.
unsafe impl<T: ?Sized, R: Region> Move<R> for PhantomData<T> {
    unsafe fn move_unsized_unchecked(
        _: In<Val<'_, Self>, R>,
        _: In<Slot<'_, Self>, R>,
    ) {
    }
}