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
//! Basic functions for dealing with relative values in memory.
//!
//! This module contains functions for initializing and manipulating relative
//! values in memory.

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

use crate::Emplace;

/// Replaces the unsized value in `dest` by emplacing `src` into it.
///
/// # Safety
///
/// The caller must guarantee that `dest` must have the metadata returned from
/// `src.emplaced_meta`.
pub unsafe fn replace_unsized_unchecked<T, R, E>(
    dest: In<Mut<'_, T>, R>,
    src: E,
) where
    T: DropRaw + Pointee + ?Sized,
    R: Region,
    E: Emplace<T, R>,
{
    // SAFETY:
    // - We are taking ownership of the value in `dest`, so it is valid for
    //   dropping.
    // - The `Val` is dropped and emplaced over, so nothing can access the `Mut`
    //   between dropping and emplacement.
    let drop_into_slot = |m| unsafe { Val::drop(Mut::take(m)) };
    // SAFETY: `drop_into_slot` returns a slot of the same location as the given
    // `Mut`, so it must be located in the same region.
    let dest = unsafe { In::map_unchecked(dest, drop_into_slot) };
    // SAFETY: The caller has guaranteed that `dest` has the metadata returned
    // by `emplaced_meta`.
    unsafe {
        src.emplace_unsized_unchecked(dest);
    }
}

/// Replaces the unsized value in `dest` by emplacing `src` into it.
pub fn replace_unsized<T, R, E>(dest: In<Mut<'_, T>, R>, src: E)
where
    T: DropRaw + Pointee + ?Sized,
    R: Region,
    E: Emplace<T, R>,
{
    assert!(metadata(dest.ptr().as_ptr()) == src.emplaced_meta());
    // SAFETY: We have asserted that the `dest` has the metadata returned from
    // `src.emplaced_meta`.
    unsafe {
        replace_unsized_unchecked(dest, src);
    }
}

/// Replaces the value in `dest` by emplacing `src` into it.
pub fn replace<T, R, E>(dest: In<Mut<'_, T>, R>, src: E)
where
    T: DropRaw,
    R: Region,
    E: Emplace<T, R>,
{
    // SAFETY: `T` is sized, so `dest` must have the metadata returned from
    // `src.emplaced_meta`.
    unsafe {
        replace_unsized_unchecked(dest, src);
    }
}