1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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 ();
}

/// A trait that tries cloning an object and returns an option
/// with the variant depending on the result. For a multitrait object
/// to be clonable it needs to have the [RawClone] trait registered.
unsafe impl<T: Clone> RawClone for T {
    unsafe fn raw_clone(&self) -> *mut () {
        Box::into_raw(Box::new(self.clone())) as *mut ()
    }
}

impl TryClone for MultitraitObject {
    fn try_clone(&self) -> Option<Self> {
        let clone = self.downcast_trait::<dyn RawClone>()?;
        let data_ptr = unsafe {
            // SAFETY: We're using the pointer in the multitrait object so
            // it won't leak memory
            clone.raw_clone()
        };
        Some(MultitraitObject {
            data: data_ptr,
            original_typeid: self.original_typeid.clone(),
            traits: self.traits.clone(),
        })
    }
}