typst_utils/
fat.rs

1//! Fat pointer handling.
2//!
3//! This assumes the memory representation of fat pointers. Although it is not
4//! guaranteed by Rust, it's improbable that it will change. Still, when the
5//! pointer metadata APIs are stable, we should definitely move to them:
6//! <https://github.com/rust-lang/rust/issues/81513>
7
8use std::alloc::Layout;
9use std::mem;
10use std::ptr::NonNull;
11
12/// Create a fat pointer from a data address and a vtable address.
13///
14/// # Safety
15/// Must only be called when `T` is a `dyn Trait`. The data address must point
16/// to a value whose type implements the trait of `T` and the `vtable` must have
17/// been extracted with [`vtable`].
18#[track_caller]
19pub unsafe fn from_raw_parts<T: ?Sized>(data: *const (), vtable: *const ()) -> *const T {
20    unsafe {
21        let fat = FatPointer { data, vtable };
22        debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>());
23        mem::transmute_copy::<FatPointer, *const T>(&fat)
24    }
25}
26
27/// Create a mutable fat pointer from a data address and a vtable address.
28///
29/// # Safety
30/// Must only be called when `T` is a `dyn Trait`. The data address must point
31/// to a value whose type implements the trait of `T` and the `vtable` must have
32/// been extracted with [`vtable`].
33#[track_caller]
34pub unsafe fn from_raw_parts_mut<T: ?Sized>(data: *mut (), vtable: *const ()) -> *mut T {
35    unsafe {
36        let fat = FatPointer { data, vtable };
37        debug_assert_eq!(Layout::new::<*mut T>(), Layout::new::<FatPointer>());
38        mem::transmute_copy::<FatPointer, *mut T>(&fat)
39    }
40}
41
42/// Extract the address to a trait object's vtable.
43///
44/// # Safety
45/// Must only be called when `T` is a `dyn Trait`.
46#[track_caller]
47pub unsafe fn vtable<T: ?Sized>(ptr: *const T) -> NonNull<()> {
48    unsafe {
49        debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>());
50        NonNull::new_unchecked(
51            mem::transmute_copy::<*const T, FatPointer>(&ptr).vtable as *mut (),
52        )
53    }
54}
55
56/// The memory representation of a trait object pointer.
57///
58/// Although this is not guaranteed by Rust, it's improbable that it will
59/// change.
60#[repr(C)]
61struct FatPointer {
62    data: *const (),
63    vtable: *const (),
64}