typst_utils/
fat.rs

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
//! Fat pointer handling.
//!
//! This assumes the memory representation of fat pointers. Although it is not
//! guaranteed by Rust, it's improbable that it will change. Still, when the
//! pointer metadata APIs are stable, we should definitely move to them:
//! <https://github.com/rust-lang/rust/issues/81513>

use std::alloc::Layout;
use std::mem;
use std::ptr::NonNull;

/// Create a fat pointer from a data address and a vtable address.
///
/// # Safety
/// Must only be called when `T` is a `dyn Trait`. The data address must point
/// to a value whose type implements the trait of `T` and the `vtable` must have
/// been extracted with [`vtable`].
#[track_caller]
pub unsafe fn from_raw_parts<T: ?Sized>(data: *const (), vtable: *const ()) -> *const T {
    let fat = FatPointer { data, vtable };
    debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>());
    mem::transmute_copy::<FatPointer, *const T>(&fat)
}

/// Create a mutable fat pointer from a data address and a vtable address.
///
/// # Safety
/// Must only be called when `T` is a `dyn Trait`. The data address must point
/// to a value whose type implements the trait of `T` and the `vtable` must have
/// been extracted with [`vtable`].
#[track_caller]
pub unsafe fn from_raw_parts_mut<T: ?Sized>(data: *mut (), vtable: *const ()) -> *mut T {
    let fat = FatPointer { data, vtable };
    debug_assert_eq!(Layout::new::<*mut T>(), Layout::new::<FatPointer>());
    mem::transmute_copy::<FatPointer, *mut T>(&fat)
}

/// Extract the address to a trait object's vtable.
///
/// # Safety
/// Must only be called when `T` is a `dyn Trait`.
#[track_caller]
pub unsafe fn vtable<T: ?Sized>(ptr: *const T) -> NonNull<()> {
    debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>());
    NonNull::new_unchecked(
        mem::transmute_copy::<*const T, FatPointer>(&ptr).vtable as *mut (),
    )
}

/// The memory representation of a trait object pointer.
///
/// Although this is not guaranteed by Rust, it's improbable that it will
/// change.
#[repr(C)]
struct FatPointer {
    data: *const (),
    vtable: *const (),
}