diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-11-01 16:56:35 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-11-02 09:18:33 +0100 |
| commit | 37ac5d966ebaf97ac79c507028cd5b742b510b89 (patch) | |
| tree | 249d43ff0f8d880cb5d00c236993f8ff0c1f10d8 /src/util | |
| parent | f547c97072881069417acd3b79b08fb7ecf40ba2 (diff) | |
More dynamic content representation
Diffstat (limited to 'src/util')
| -rw-r--r-- | src/util/fat.rs | 64 | ||||
| -rw-r--r-- | src/util/mod.rs | 8 |
2 files changed, 69 insertions, 3 deletions
diff --git a/src/util/fat.rs b/src/util/fat.rs new file mode 100644 index 00000000..bb557bc9 --- /dev/null +++ b/src/util/fat.rs @@ -0,0 +1,64 @@ +//! 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; +use std::mem; + +/// 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`]. +pub unsafe fn from_raw_parts<T: ?Sized>(data: *const (), vtable: *const ()) -> *const T { + debug_assert_eq!( + alloc::Layout::new::<*const T>(), + alloc::Layout::new::<FatPointer>(), + ); + + let fat = FatPointer { data, vtable }; + 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`]. +pub unsafe fn from_raw_parts_mut<T: ?Sized>(data: *mut (), vtable: *const ()) -> *mut T { + debug_assert_eq!( + alloc::Layout::new::<*mut T>(), + alloc::Layout::new::<FatPointer>(), + ); + + let fat = FatPointer { data, vtable }; + 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`. +pub unsafe fn vtable<T: ?Sized>(ptr: *const T) -> *const () { + debug_assert_eq!( + alloc::Layout::new::<*const T>(), + alloc::Layout::new::<FatPointer>(), + ); + + mem::transmute_copy::<*const T, FatPointer>(&ptr).vtable +} + +/// 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 (), +} diff --git a/src/util/mod.rs b/src/util/mod.rs index d549fc5f..bc7aa250 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,12 +1,14 @@ //! Utilities. -#[macro_use] -mod eco; -mod buffer; +pub mod fat; pub use buffer::Buffer; pub use eco::EcoString; +#[macro_use] +mod eco; +mod buffer; + use std::any::TypeId; use std::fmt::{self, Debug, Formatter}; use std::path::{Component, Path, PathBuf}; |
