Add TryClone implementation

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

@ -8,7 +8,4 @@ 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
[dev-dependencies]
dyn-clone = "1.0.4"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

@ -3,6 +3,8 @@
mod tests;
pub(crate) mod macros;
mod trait_impl;
pub use trait_impl::*;
use std::any::{Any, TypeId};
use std::collections::HashMap;
@ -16,7 +18,7 @@ pub struct FatPointer {
}
/// A container to store data with the associated type and trait objects
/// allowing for casting down to traits or the concrete type
/// allowing for casting down to trait_impl or the concrete type
/// ```rust
/// use multi_trait_object::prelude::*;
/// use std::fmt::{Debug, Display};
@ -33,14 +35,14 @@ pub struct FatPointer {
/// ```
#[derive(Debug)]
pub struct MultitraitObject {
data: *mut (),
original_typeid: TypeId,
traits: HashMap<TypeId, *const ()>,
pub(crate) data: *mut (),
pub(crate) original_typeid: TypeId,
pub(crate) traits: HashMap<TypeId, *const ()>,
}
impl MultitraitObject {
/// Creates a new multitrait object from the given value
/// All traits except Any must be registered on this object
/// All trait_impl except Any must be registered on this object
/// in order to access them.
pub fn new<T: 'static + Any>(value: T) -> Self {
let any_vtable = __fat_pointer!(T as dyn Any).vptr;

@ -30,7 +30,7 @@ macro_rules! impl_trait_object {
}
}
/// Registers multiple traits on a multitrait object
/// Registers multiple trait_impl on a multitrait object
/// ```rust
/// use multi_trait_object::prelude::*;
/// use std::fmt::{Debug, Display};

@ -1,8 +1,7 @@
use dyn_clone::{clone_box, DynClone};
use std::fmt::Debug;
use crate::prelude::*;
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct TestStruct {
a: u32,
test: String,
@ -27,15 +26,15 @@ impl ChangeStruct for TestStruct {
}
}
impl_trait_object!(TestStruct, dyn DynClone, dyn ChangeStruct, dyn Debug);
impl_trait_object!(TestStruct, dyn RawClone, dyn ChangeStruct, dyn Debug);
#[test]
fn it_creates_fat_pointers() {
let debug_vtable1 = __fat_pointer!(TestStruct as dyn Debug).vptr;
let dclone_vtable1 = __fat_pointer!(TestStruct as dyn DynClone).vptr;
let dclone_vtable1 = __fat_pointer!(TestStruct as dyn RawClone).vptr;
let debug_vtable2 = __fat_pointer!(TestStruct as dyn Debug).vptr;
assert_eq!(debug_vtable1, debug_vtable2);
let dclone_vtable2 = __fat_pointer!(TestStruct as dyn DynClone).vptr;
let dclone_vtable2 = __fat_pointer!(TestStruct as dyn RawClone).vptr;
assert_eq!(dclone_vtable1, dclone_vtable2);
}
@ -49,8 +48,6 @@ fn it_downcasts_traits() {
let mto = TestStruct::default().into_multitrait();
let debug = mto.downcast_trait::<dyn Debug>().unwrap();
let _ = format!("{:?}", debug);
let obj = mto.downcast_trait::<dyn DynClone>().unwrap();
let _new_obj = clone_box(&*obj);
}
#[test]
@ -79,4 +76,13 @@ fn it_downcasts_to_original() {
let result = mto.downcast::<TestStruct>().unwrap();
assert_eq!(result.a, 5);
assert_eq!(result.test, String::from("Hello World"));
}
#[test]
fn it_tries_cloning() {
let mto = TestStruct::default().into_multitrait();
let mto2 = mto.try_clone().unwrap();
let obj1 = mto.downcast::<TestStruct>();
let obj2 = mto2.downcast::<TestStruct>();
assert_eq!(obj1, obj2);
}

@ -0,0 +1,2 @@
mod try_clone;
pub use try_clone::*;

@ -0,0 +1,38 @@
use crate::{MultitraitObject};
pub trait TryClone: Sized {
fn try_clone(&self) -> Option<Self>;
}
/// Returns a raw pointer to the cloned data.
/// This will leak the memory of the underlying pointer.
/// This trait is implemented for all types that implement clone
/// so you can pass this trait to the object constructor. This
/// way the given object can be cloned with [TryClone].
pub unsafe trait RawClone {
#[doc(hidden)]
#[must_use]
unsafe fn raw_clone(&self) -> *mut ();
}
unsafe impl<T: Clone> RawClone for T {
unsafe fn raw_clone(&self) -> *mut () {
Box::into_raw(Box::new(self.clone())) as *mut ()
}
}
/// A trait that tries cloning an object and returns an option
/// with the variant depending on the result.
impl TryClone for MultitraitObject {
fn try_clone(&self) -> Option<Self> {
let clone = self.downcast_trait::<dyn RawClone>()?;
let data_ptr = unsafe {
clone.raw_clone()
};
Some(MultitraitObject {
data: data_ptr,
original_typeid: self.original_typeid.clone(),
traits: self.traits.clone(),
})
}
}
Loading…
Cancel
Save