#![doc(html_root_url = "https://docs.rs/dyn_clone/1.0.10")]
#![no_std]
#![allow(clippy::missing_panics_doc, clippy::ptr_as_ptr)]
extern crate alloc;
use crate::sealed::{Private, Sealed};
#[macro_use]
mod macros;
#[doc(hidden)]
pub mod __private {
pub use alloc::boxed::Box;
pub use core::clone::Clone;
pub use core::marker::{Send, Sync};
}
mod sealed {
pub trait Sealed {}
impl<T: Clone> Sealed for T {}
impl Sealed for str {}
impl<T: Clone> Sealed for [T] {}
pub struct Private;
}
pub trait DynClone: Sealed {
#[doc(hidden)]
fn __clone_box(&self, _: Private) -> *mut ();
}
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::sync::Arc;
pub fn clone<T>(t: &T) -> T
where
T: DynClone,
{
unsafe { *Box::from_raw(<T as DynClone>::__clone_box(t, Private) 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, Private);
}
unsafe { Box::from_raw(fat_ptr as *mut T) }
}
pub fn arc_make_mut<T>(arc: &mut Arc<T>) -> &mut T
where
T: ?Sized + DynClone,
{
let is_unique = Arc::get_mut(arc).is_some();
if !is_unique {
let clone = Arc::from(clone_box(&**arc));
*arc = clone;
}
let ptr = Arc::as_ptr(arc) as *mut T;
unsafe { &mut *ptr }
}
pub fn rc_make_mut<T>(rc: &mut Rc<T>) -> &mut T
where
T: ?Sized + DynClone,
{
let is_unique = Rc::get_mut(rc).is_some();
if !is_unique {
let clone = Rc::from(clone_box(&**rc));
*rc = clone;
}
let ptr = Rc::as_ptr(rc) as *mut T;
unsafe { &mut *ptr }
}
impl<T> DynClone for T
where
T: Clone,
{
fn __clone_box(&self, _: Private) -> *mut () {
Box::<T>::into_raw(Box::new(self.clone())) as *mut ()
}
}
impl DynClone for str {
fn __clone_box(&self, _: Private) -> *mut () {
Box::<str>::into_raw(Box::from(self)) as *mut ()
}
}
impl<T> DynClone for [T]
where
T: Clone,
{
fn __clone_box(&self, _: Private) -> *mut () {
Box::<[T]>::into_raw(self.iter().cloned().collect()) as *mut ()
}
}