summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-11-01 16:56:35 +0100
committerLaurenz <laurmaedje@gmail.com>2022-11-02 09:18:33 +0100
commit37ac5d966ebaf97ac79c507028cd5b742b510b89 (patch)
tree249d43ff0f8d880cb5d00c236993f8ff0c1f10d8 /src/util
parentf547c97072881069417acd3b79b08fb7ecf40ba2 (diff)
More dynamic content representation
Diffstat (limited to 'src/util')
-rw-r--r--src/util/fat.rs64
-rw-r--r--src/util/mod.rs8
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};