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

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

/// An emplaced value that can be moved.
///
/// # Safety
///
/// `move_unsized_unchecked` must initialize its `out` parameter.
pub unsafe trait Move<R: Region>: DropRaw {
    /// Moves a value into a given slot within some memory region.
    ///
    /// # Safety
    ///
    /// `out` must have the same metadata as `this`.
    unsafe fn move_unsized_unchecked(
        this: In<Val<'_, Self>, R>,
        out: In<Slot<'_, Self>, R>,
    );
}

/// An extension trait for `Move` that provides a variety of convenient movement
/// methods.
///
/// # Safety
///
/// `move_unsized` and `r#move`/`move_` must initialize their `out` parameters.
pub unsafe trait MoveExt<R: Region>: Move<R> {
    /// Moves a value into a given slot within some memory region.
    ///
    /// # Panics
    ///
    /// Panics if `out` does not have the same metadata as `this`.
    fn move_unsized(this: In<Val<'_, Self>, R>, out: In<Slot<'_, Self>, R>);

    /// Moves a `Sized` value into a given slot within some memory region.
    fn r#move(this: In<Val<'_, Self>, R>, out: In<Slot<'_, Self>, R>)
    where
        Self: Sized;

    /// Moves a `Sized` value into a given slot within some memory region.
    ///
    /// This is an alternate name for [`move`](MoveExt::move), which uses a
    /// raw identifier in the name.
    fn move_(this: In<Val<'_, Self>, R>, out: In<Slot<'_, Self>, R>)
    where
        Self: Sized;
}

// SAFETY: `move_unsized` and `r#move`/`move_` initialize their `out` paramters
// by calling `move_unsized_unchecked`.
unsafe impl<T: Move<R> + Pointee + ?Sized, R: Region> MoveExt<R> for T {
    fn move_unsized(this: In<Val<'_, Self>, R>, out: In<Slot<'_, Self>, R>) {
        assert!(metadata(this.ptr().as_ptr()) == metadata(out.ptr().as_ptr()));
        // SAFETY: We have asserted that `out` has the same metadata as `this`.
        unsafe {
            Move::move_unsized_unchecked(this, out);
        }
    }

    fn r#move(this: In<Val<'_, Self>, R>, out: In<Slot<'_, Self>, R>)
    where
        Self: Sized,
    {
        // SAFETY: Because `Self: Sized`, its pointer metadata is `()` and so
        // the metadata of `this` and `out` must be the same because there is
        // only one possible value of `()`.
        unsafe {
            Move::move_unsized_unchecked(this, out);
        }
    }

    fn move_(this: In<Val<'_, Self>, R>, out: In<Slot<'_, Self>, R>)
    where
        Self: Sized,
    {
        Self::r#move(this, out);
    }
}