Update metadata and add safety comments

Signed-off-by: trivernis <trivernis@protonmail.com>
main
trivernis 2 years ago
parent f5dd9c86e7
commit bc3933de92
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -2,6 +2,11 @@
name = "multi-trait-object" name = "multi-trait-object"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
readme = "README.md"
license = "Apache-2.0"
authors = ["trivernis"]
description = "A type to store an object with all associated traits"
repository = "https://github.com/Trivernis/multi-trait-object/tree/main"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

@ -6,6 +6,12 @@ This is done by storing the pointer to the v-table for each
trait implementation on the type as well as the pointer to the trait implementation on the type as well as the pointer to the
data. data.
## Safety
All unsafe parts are perfectly safe as far as my understanding goes.
As this crate is still in an early stage there might be some side effects that haven't
been noticed yet.
## Usage ## Usage
```rust ```rust

@ -33,20 +33,21 @@ pub struct FatPointer {
/// ``` /// ```
#[derive(Debug)] #[derive(Debug)]
pub struct MultitraitObject { pub struct MultitraitObject {
pub data: *mut (), data: *mut (),
pub original_typeid: TypeId, original_typeid: TypeId,
pub any_vtable: *const (), traits: HashMap<TypeId, *const ()>,
pub traits: HashMap<TypeId, *const ()>,
} }
impl MultitraitObject { impl MultitraitObject {
/// Creates a new multitrait object from the given value
/// All traits except Any must be registered on this object
/// in order to access them.
pub fn new<T: 'static + Any>(value: T) -> Self { pub fn new<T: 'static + Any>(value: T) -> Self {
let any_vtable = __fat_pointer!(T as dyn Any).vptr; let any_vtable = __fat_pointer!(T as dyn Any).vptr;
let data = Box::into_raw(Box::new(value)) as *mut (); let data = Box::into_raw(Box::new(value)) as *mut ();
let mut this = Self { let mut this = Self {
data, data,
any_vtable,
original_typeid: TypeId::of::<T>(), original_typeid: TypeId::of::<T>(),
traits: Default::default(), traits: Default::default(),
}; };
@ -104,6 +105,7 @@ impl MultitraitObject {
pub fn downcast<T: Any>(self) -> Option<T> { pub fn downcast<T: Any>(self) -> Option<T> {
if TypeId::of::<T>() == self.original_typeid { if TypeId::of::<T>() == self.original_typeid {
unsafe { unsafe {
// SAFETY: We've checked for the type so it's safe to cast the data and consume it in the process
let typed_ptr = std::mem::transmute::<_, *mut T>(self.data); let typed_ptr = std::mem::transmute::<_, *mut T>(self.data);
let boxed = Box::from_raw(typed_ptr); let boxed = Box::from_raw(typed_ptr);
@ -121,6 +123,7 @@ impl MultitraitObject {
#[doc(hidden)] #[doc(hidden)]
unsafe fn _downcast_trait<T1: 'static + ?Sized>(&self) -> Option<&T1> { unsafe fn _downcast_trait<T1: 'static + ?Sized>(&self) -> Option<&T1> {
// SAFETY: Creating a fat pointer from the given v-table and data has no side effects
let vptr = *self.traits.get(&TypeId::of::<T1>())?; let vptr = *self.traits.get(&TypeId::of::<T1>())?;
let fat_pointer = FatPointer { data: self.data, vptr }; let fat_pointer = FatPointer { data: self.data, vptr };
let value = std::mem::transmute::<_, &&T1>(&fat_pointer); let value = std::mem::transmute::<_, &&T1>(&fat_pointer);
@ -130,6 +133,7 @@ impl MultitraitObject {
#[doc(hidden)] #[doc(hidden)]
unsafe fn _downcast_trait_mut<T1: 'static + ?Sized>(&mut self) -> Option<&mut T1> { unsafe fn _downcast_trait_mut<T1: 'static + ?Sized>(&mut self) -> Option<&mut T1> {
// SAFETY: Creating a fat pointer from the given v-table and data has no side effects
let vptr = *self.traits.get(&TypeId::of::<T1>())?; let vptr = *self.traits.get(&TypeId::of::<T1>())?;
let mut fat_pointer = FatPointer { data: self.data, vptr }; let mut fat_pointer = FatPointer { data: self.data, vptr };
let value = std::mem::transmute::<_, &mut &mut T1>(&mut fat_pointer); let value = std::mem::transmute::<_, &mut &mut T1>(&mut fat_pointer);
@ -139,6 +143,7 @@ impl MultitraitObject {
#[doc(hidden)] #[doc(hidden)]
unsafe fn _downcast_boxed_trait<T1: 'static + ?Sized>(&mut self) -> Option<Box<T1>> { unsafe fn _downcast_boxed_trait<T1: 'static + ?Sized>(&mut self) -> Option<Box<T1>> {
// SAFETY: Creating a fat pointer from the given v-table and data has no side effects
let vptr = *self.traits.get(&TypeId::of::<T1>())?; let vptr = *self.traits.get(&TypeId::of::<T1>())?;
let fat_pointer = FatPointer { data: self.data, vptr }; let fat_pointer = FatPointer { data: self.data, vptr };
let value = std::mem::transmute::<_, *const *mut T1>(&fat_pointer); let value = std::mem::transmute::<_, *const *mut T1>(&fat_pointer);
@ -151,6 +156,7 @@ impl MultitraitObject {
impl Drop for MultitraitObject { impl Drop for MultitraitObject {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
// Safety: The Multitrait object has exclusive access to the data pointer
let raw = Box::from_raw(self.data); let raw = Box::from_raw(self.data);
std::mem::drop(raw); std::mem::drop(raw);
} }

Loading…
Cancel
Save