#![doc(html_root_url = "https://docs.rs/dyn_clone/1.0.1")]
#[macro_use]
mod macros;
#[doc(hidden)]
pub use std as private;
pub trait DynClone {
#[doc(hidden)]
unsafe fn clone_box(&self) -> *mut ();
}
pub fn clone<T>(t: &T) -> T
where
T: DynClone,
{
unsafe {
*Box::from_raw(<T as DynClone>::clone_box(t) as *mut T)
}
}
pub fn clone_box<T>(t: &T) -> Box<T>
where
T: ?Sized + DynClone,
{
let mut fat_ptr = t as *const T;
unsafe {
let data_ptr = &mut fat_ptr as *mut *const T as *mut *mut ();
assert_eq!(*data_ptr as *const (), t as *const T as *const ());
*data_ptr = <T as DynClone>::clone_box(t);
}
unsafe {
Box::from_raw(fat_ptr as *mut T)
}
}
impl<T> DynClone for T
where
T: std::clone::Clone,
{
unsafe fn clone_box(&self) -> *mut () {
Box::into_raw(Box::new(self.clone())) as *mut ()
}
}
#[cfg(test)]
mod tests {
use super::DynClone;
use std::fmt::{self, Display};
use std::sync::{Arc, Mutex};
struct Log {
id: u64,
events: Arc<Mutex<Vec<String>>>,
}
impl Clone for Log {
fn clone(&self) -> Self {
Log {
id: self.id + 1,
events: self.events.clone(),
}
}
}
impl Display for Log {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "id={}", self.id)
}
}
impl Drop for Log {
fn drop(&mut self) {
self.events.lock().unwrap().push(format!("dropping {}", self))
}
}
#[test]
fn clone_sized() {
let arc = Arc::new(0);
assert_eq!(Arc::strong_count(&arc), 1);
let c = crate::clone(&arc);
assert_eq!(Arc::strong_count(&arc), 2);
drop(c);
assert_eq!(Arc::strong_count(&arc), 1);
}
#[test]
fn clone_trait_object() {
trait MyTrait: Display + Sync + DynClone {}
impl MyTrait for Log {}
let events = Arc::new(Mutex::new(Vec::new()));
let mut expected = Vec::new();
{
let b11: Box<dyn MyTrait> = Box::new(Log {
id: 11,
events: events.clone(),
});
let b12 = crate::clone_box(&*b11);
assert_eq!(b11.to_string(), "id=11");
assert_eq!(b12.to_string(), "id=12");
expected.push("dropping id=12".to_owned());
expected.push("dropping id=11".to_owned());
}
assert_eq!(*events.lock().unwrap(), expected);
}
}