From db608c8eb1a6b0ca3156f77732b1a66c923a1435 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sun, 13 Mar 2022 20:37:57 +0100 Subject: [PATCH] Change register_traits to create_object to not associate wrong v-tables Signed-off-by: trivernis --- Cargo.toml | 2 +- src/lib.rs | 12 ++++++++++-- src/macros.rs | 49 ++++++++++++++++++++++++++++++------------------- src/tests.rs | 4 +++- 4 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 052d03a..c6d76cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multi-trait-object" -version = "0.1.3" +version = "0.2.0" edition = "2021" readme = "README.md" license = "Apache-2.0" diff --git a/src/lib.rs b/src/lib.rs index 908db16..9d55232 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,14 +20,21 @@ pub struct FatPointer { pub vptr: *const (), } +#[allow(unused)] +#[doc(hidden)] +#[inline] +pub unsafe fn null_ptr(_value: &T) -> *const T { + // creates a typed clone that is actually null + std::ptr::null::() as *const T +} + /// A container to store data with the associated type and trait objects /// allowing for casting down to trait_impl or the concrete type /// ```rust /// use multi_trait_object::*; /// use std::fmt::{Debug, Display}; /// -/// let mut mto = MultitraitObject::new(String::new()); -/// register_traits!(mto, String, dyn Debug, dyn Display); +/// let mto = create_object!(String::new(), dyn Debug, dyn Display); /// /// let debug = mto.downcast_trait::().unwrap(); /// println!("{:?}", debug); @@ -46,6 +53,7 @@ impl MultitraitObject { /// Creates a new multitrait object from the given value /// All trait_impl except Any must be registered on this object /// in order to access them. + #[doc(hidden)] 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 (); diff --git a/src/macros.rs b/src/macros.rs index 1e1a62d..854e07b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -20,7 +20,7 @@ macro_rules! impl_trait_object { fn into_multitrait(self) -> $crate::MultitraitObject { let mut mto = $crate::MultitraitObject::new(self); $( - $crate::register_traits!(mto, $obj, $trt); + mto._register::<$trt>($crate::__fat_pointer!($obj as $trt).vptr); )* mto @@ -29,24 +29,6 @@ macro_rules! impl_trait_object { } } -/// Registers multiple trait_impl on a multitrait object -/// ```rust -/// use multi_trait_object::*; -/// use std::fmt::{Debug, Display}; -/// -/// let value = String::new(); -/// let mut mto = MultitraitObject::new(value); -/// register_traits!(mto, String, dyn Debug, dyn Display); -/// ``` -#[macro_export] -macro_rules! register_traits { - ($r:expr, $v:ty, $($t:ty), +) => { - $( - $r._register::<$t>($crate::__fat_pointer!($v as $t).vptr); - )+ - } -} - #[doc(hidden)] #[macro_export] macro_rules! __fat_pointer { @@ -58,3 +40,32 @@ macro_rules! __fat_pointer { } }} } + +/// Registers multiple trait_impl on a multitrait object +/// ```rust +/// use multi_trait_object::*; +/// use std::fmt::{Debug, Display}; +/// +/// let mto = create_object!(String::new(), dyn Debug, dyn Display); +/// ``` +#[macro_export] +macro_rules! create_object { + ($v:expr, $($t:ty), +) => { + { + let null_ptr = unsafe { + // SAFETY: We're never accessing the null value + $crate::null_ptr(&$v) + }; + let mut mto = $crate::MultitraitObject::new($v); + $( + let vptr = unsafe { + // SAFETY: We're never accessing the null value + let ptr = $crate::null_ptr(&*null_ptr) as *const $t; + std::mem::transmute::<_, $crate::FatPointer>(ptr).vptr + }; + mto._register::<$t>(vptr); + )+ + mto + } + } +} \ No newline at end of file diff --git a/src/tests.rs b/src/tests.rs index 94d9e1f..32015f5 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,5 +1,5 @@ use std::fmt::Debug; -use crate::{__fat_pointer, impl_trait_object, IntoMultitrait, TryClone, TryPartialEq, RawClone, PartialEqAny}; +use crate::{__fat_pointer, impl_trait_object, IntoMultitrait, TryClone, TryPartialEq, RawClone, PartialEqAny, create_object}; #[derive(Clone, Debug, Eq, PartialEq)] struct TestStruct { @@ -42,6 +42,8 @@ fn it_creates_fat_pointers() { fn it_constructs() { TestStruct::default().into_multitrait(); String::from("test").into_multitrait(); + let mto = create_object!(String::from("test"), dyn Debug); + assert!(mto.is::()) } #[test]