From bc3933de92f56724baae4c9794763e6bcd26f801 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sun, 13 Mar 2022 15:24:29 +0100 Subject: [PATCH] Update metadata and add safety comments Signed-off-by: trivernis --- Cargo.toml | 5 +++++ README.md | 6 ++++++ src/lib.rs | 16 +++++++++++----- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7674c4c..b774263 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,11 @@ name = "multi-trait-object" version = "0.1.0" 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 diff --git a/README.md b/README.md index 678a2de..6098a9b 100644 --- a/README.md +++ b/README.md @@ -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 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 ```rust diff --git a/src/lib.rs b/src/lib.rs index 0db3cfa..9be3f8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,20 +33,21 @@ pub struct FatPointer { /// ``` #[derive(Debug)] pub struct MultitraitObject { - pub data: *mut (), - pub original_typeid: TypeId, - pub any_vtable: *const (), - pub traits: HashMap, + data: *mut (), + original_typeid: TypeId, + traits: HashMap, } 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(value: T) -> Self { let any_vtable = __fat_pointer!(T as dyn Any).vptr; let data = Box::into_raw(Box::new(value)) as *mut (); let mut this = Self { data, - any_vtable, original_typeid: TypeId::of::(), traits: Default::default(), }; @@ -104,6 +105,7 @@ impl MultitraitObject { pub fn downcast(self) -> Option { if TypeId::of::() == self.original_typeid { 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 boxed = Box::from_raw(typed_ptr); @@ -121,6 +123,7 @@ impl MultitraitObject { #[doc(hidden)] unsafe fn _downcast_trait(&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::())?; let fat_pointer = FatPointer { data: self.data, vptr }; let value = std::mem::transmute::<_, &&T1>(&fat_pointer); @@ -130,6 +133,7 @@ impl MultitraitObject { #[doc(hidden)] unsafe fn _downcast_trait_mut(&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::())?; let mut fat_pointer = FatPointer { data: self.data, vptr }; let value = std::mem::transmute::<_, &mut &mut T1>(&mut fat_pointer); @@ -139,6 +143,7 @@ impl MultitraitObject { #[doc(hidden)] unsafe fn _downcast_boxed_trait(&mut self) -> Option> { + // SAFETY: Creating a fat pointer from the given v-table and data has no side effects let vptr = *self.traits.get(&TypeId::of::())?; let fat_pointer = FatPointer { data: self.data, vptr }; let value = std::mem::transmute::<_, *const *mut T1>(&fat_pointer); @@ -151,6 +156,7 @@ impl MultitraitObject { impl Drop for MultitraitObject { fn drop(&mut self) { unsafe { + // Safety: The Multitrait object has exclusive access to the data pointer let raw = Box::from_raw(self.data); std::mem::drop(raw); }