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
use ::core::{alloc::Layout, hash::Hash};
use ::ptr_meta::{metadata, DynMetadata, Pointee};

/// Pointer metadata that can determine the memory layout of its pointee.
///
/// # Safety
///
/// `pointee_layout` must return the correct layout of a `T` pointee with this
/// metadata.
pub unsafe trait Metadata<T: Pointee<Metadata = Self> + ?Sized>:
    Copy + Send + Sync + Ord + Hash + Unpin
{
    /// Returns the layout of a `T` pointee with the this metadata.
    ///
    /// # Safety
    ///
    /// `self` must be valid metadata for `T`.
    unsafe fn pointee_layout(self) -> Layout;
}

// SAFETY: `Layout::new` returns the correct layout for `T`.
unsafe impl<T> Metadata<T> for () {
    unsafe fn pointee_layout(self) -> Layout {
        Layout::new::<T>()
    }
}

// SAFETY: `Layout::array` returns the correct layout for `[T]` because slices
// have the same layouts as arrays of the same length.
unsafe impl<T> Metadata<[T]> for usize {
    unsafe fn pointee_layout(self) -> Layout {
        // SAFETY: `Layout::array` cannot fail because `self` is valid metadata
        // for `[T]`.
        unsafe { Layout::array::<T>(self).unwrap_unchecked() }
    }
}

// SAFETY: `Layout::array` returns the correct layout for `str` because string
// slices have the same layouts as byte arrays of the same length.
unsafe impl Metadata<str> for usize {
    unsafe fn pointee_layout(self) -> Layout {
        // SAFETY: `Layout::array` cannot fail because `self` is valid metadata
        // for `str`.
        unsafe { Layout::array::<u8>(self).unwrap_unchecked() }
    }
}

// SAFETY: `DynMetadata::layout` returns the layout of the corresponding value.
unsafe impl<T> Metadata<T> for DynMetadata<T>
where
    T: Pointee<Metadata = DynMetadata<T>> + ?Sized,
{
    unsafe fn pointee_layout(self) -> Layout {
        self.layout()
    }
}

/// Returns the layout of the value pointed to by the given pointer.
pub fn layout_of_val_raw<T: Pointee + ?Sized>(ptr: *const T) -> Layout
where
    T::Metadata: Metadata<T>,
{
    let metadata = metadata(ptr);
    // SAFETY: `metadata` is the metadata of a pointer, and all pointers must
    // have valid metadata. So the metadata is guaranteed to be valid.
    unsafe { metadata.pointee_layout() }
}