clone_dyn_types/
lib.rs

1#![ no_std ]
2#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
3#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
4#![ doc( html_root_url = "https://docs.rs/clone_dyn_types/latest/clone_dyn_types/" ) ]
5#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ]
6
7/// Namespace with dependencies.
8#[ cfg( feature = "enabled" ) ]
9pub mod dependency
10{
11}
12
13/// Define a private namespace for all its items.
14// #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ]
15#[ cfg( feature = "enabled" ) ]
16mod private
17{
18
19  // xxx : ?
20  // #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ]
21  extern crate alloc;
22  // #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ]
23  // #[ allow( unused_imports ) ]
24  use alloc::boxed::Box;
25  // #[ cfg( all( feature = "use_std", not( feature = "use_alloc" ) ) ) ]
26  // use std::boxed::Box;
27
28  /// A trait to upcast a clonable entity and clone it.
29  /// It's implemented for all entities which can be cloned.
30  pub trait CloneDyn : Sealed
31  {
32    #[ doc( hidden ) ]
33    fn __clone_dyn( &self, _ : DontCallMe ) -> *mut ();
34  }
35
36  // clonable
37  impl< T > CloneDyn for T
38  where
39    T : Clone,
40  {
41    #[ inline ]
42    #[ allow( clippy::implicit_return, clippy::as_conversions, clippy::ptr_as_ptr ) ]
43    fn __clone_dyn( &self, _ : DontCallMe ) -> *mut ()
44    {
45      Box::< T >::into_raw( Box::new( self.clone() ) ) as *mut ()
46    }
47  }
48
49  // slice
50  impl< T > CloneDyn for [ T ]
51  where
52    T : Clone,
53  {
54    #[ inline ]
55    #[ allow( clippy::implicit_return, clippy::as_conversions, clippy::ptr_as_ptr ) ]
56    fn __clone_dyn( &self, _ : DontCallMe ) -> *mut ()
57    {
58      Box::< [ T ] >::into_raw( self.iter().cloned().collect() ) as *mut ()
59    }
60  }
61
62  // str slice
63  impl CloneDyn for str
64  {
65    #[ inline ]
66    #[ allow( clippy::as_conversions, clippy::ptr_as_ptr, clippy::implicit_return ) ]
67    fn __clone_dyn( &self, _ : DontCallMe ) -> *mut ()
68    {
69      Box::< str >::into_raw( Box::from( self ) ) as *mut ()
70    }
71  }
72
73  ///
74  /// True clone which is applicable not only to clonable entities, but to trait objects implementing `CloneDyn`.
75  ///
76  /// # Example
77  ///
78  /// ```
79  /// use clone_dyn_types::clone;
80  ///
81  /// #[ derive( Clone ) ]
82  /// struct MyStruct
83  /// {
84  ///   value : i32,
85  /// }
86  ///
87  /// let original = MyStruct { value : 42 };
88  /// let cloned = clone( &original );
89  ///
90  /// assert_eq!( original.value, cloned.value );
91  /// ```
92  #[ inline ]
93  pub fn clone< T >( src : &T ) -> T
94  where
95    T : CloneDyn,
96  {
97    // # Safety
98    //
99    // This function uses an `unsafe` block because it performs low-level memory manipulations. Specifically, it handles
100    // raw pointers and converts them to and from `Box< T >`. This is necessary to dynamically clone a trait object, which
101    // does not support cloning through the standard `Clone` trait. The safety of this function depends on the guarantee
102    // that the `CloneDyn` trait is correctly implemented for the given type `T`, ensuring that `__clone_dyn` returns a
103    // valid pointer to a cloned instance of `T`.
104    //
105    #[ allow( unsafe_code, clippy::as_conversions, clippy::ptr_as_ptr, clippy::implicit_return, clippy::undocumented_unsafe_blocks ) ]
106    unsafe
107    {
108      *Box::from_raw( < T as CloneDyn >::__clone_dyn( src, DontCallMe ) as *mut T )
109    }
110  }
111
112  ///
113  /// Clone boxed dyn.
114  ///
115  /// Clones a dynamically sized trait object into a `Box< T >`.
116  ///
117  /// # Example
118  ///
119  /// ```
120  /// use clone_dyn_types::{ CloneDyn, clone_into_box };
121  ///
122  /// #[ derive( Clone ) ]
123  /// struct MyStruct
124  /// {
125  ///   value : i32,
126  /// }
127  ///
128  /// trait MyTrait : CloneDyn
129  /// {
130  ///   fn val( &self ) -> i32;
131  /// }
132  ///
133  /// impl MyTrait for MyStruct
134  /// {
135  ///   fn val( &self ) -> i32
136  ///   {
137  ///     self.value
138  ///   }
139  /// }
140  ///
141  /// #[ allow( non_local_definitions ) ]
142  /// impl < 'c > Clone
143  /// for Box< dyn MyTrait + 'c >
144  /// {
145  ///   #[ inline ]
146  ///   fn clone( &self ) -> Self { clone_into_box( &**self ) }
147  /// }
148  ///
149  /// #[ allow( non_local_definitions ) ]
150  /// impl < 'c > Clone
151  /// for Box< dyn MyTrait + Send + 'c >
152  /// {
153  ///   #[ inline ]
154  ///   fn clone( &self ) -> Self { clone_into_box( &**self ) }
155  /// }
156  ///
157  /// #[ allow( non_local_definitions ) ]
158  /// impl < 'c > Clone
159  /// for Box< dyn MyTrait + Sync + 'c >
160  /// {
161  ///   #[ inline ]
162  ///   fn clone( &self ) -> Self { clone_into_box( &**self ) }
163  /// }
164  ///
165  /// #[ allow( non_local_definitions ) ]
166  /// impl < 'c > Clone
167  /// for Box< dyn MyTrait + Send + Sync + 'c >
168  /// {
169  ///   #[ inline ]
170  ///   fn clone( &self ) -> Self { clone_into_box( &**self ) }
171  /// }
172  ///
173  /// let cloned : Box< dyn MyTrait > = clone_into_box( &MyStruct { value : 42 } );
174  ///
175  /// ```
176  #[ inline ]
177  pub fn clone_into_box< T >( ref_dyn : &T ) -> Box< T >
178  where
179    T : ?Sized + CloneDyn,
180  {
181    // # Safety
182    //
183    // This function uses an `unsafe` block because it performs low-level memory manipulations involving raw pointers.
184    // The `unsafe` block is necessary here because we're manually handling raw pointers and converting them to and from
185    // `Box<T>`. This bypasses Rust's ownership and borrowing rules to achieve dynamic cloning of a boxed trait object.
186    // The safety of this function relies on the correct implementation of the `CloneDyn` trait for the given type `T`.
187    // Specifically, `__clone_dyn` must return a valid pointer to a cloned instance of `T`.
188    //
189    #[ allow( unsafe_code, clippy::implicit_return, clippy::as_conversions, clippy::ptr_cast_constness, clippy::ptr_as_ptr, clippy::multiple_unsafe_ops_per_block, clippy::undocumented_unsafe_blocks, clippy::ref_as_ptr ) ]
190    unsafe
191    {
192      let mut ptr = ref_dyn as *const T;
193      let data_ptr = &mut ptr as *mut *const T as *mut *mut (); // don't change it
194      // let data_ptr = &raw mut ptr as *mut *mut (); // fix clippy
195      *data_ptr = < T as CloneDyn >::__clone_dyn( ref_dyn, DontCallMe );
196      Box::from_raw( ptr as *mut T )
197    }
198  }
199
200  #[ doc( hidden ) ]
201  mod sealed
202  {
203    #[ doc( hidden ) ]
204    #[ allow( missing_debug_implementations ) ]
205    pub struct DontCallMe;
206    #[ doc( hidden ) ]
207    pub trait Sealed {}
208    impl< T : Clone > Sealed for T {}
209    impl< T : Clone > Sealed for [ T ] {}
210    impl Sealed for str {}
211  }
212  use sealed::{ DontCallMe, Sealed };
213
214}
215
216#[ cfg( feature = "enabled" ) ]
217#[ doc( inline ) ]
218#[ allow( unused_imports ) ]
219#[ allow( clippy::pub_use ) ]
220pub use own::*;
221
222/// Own namespace of the module.
223#[ cfg( feature = "enabled" ) ]
224#[ allow( unused_imports ) ]
225pub mod own
226{
227  use super::orphan;
228  #[ doc( inline ) ]
229  #[ allow( clippy::useless_attribute, clippy::pub_use ) ]
230  pub use orphan::*;
231}
232
233/// Orphan namespace of the module.
234#[ cfg( feature = "enabled" ) ]
235#[ allow( unused_imports ) ]
236pub mod orphan
237{
238  use super::exposed;
239  #[ doc( inline ) ]
240  #[ allow( clippy::useless_attribute, clippy::pub_use ) ]
241  pub use exposed::*;
242}
243
244/// Exposed namespace of the module.
245#[ cfg( feature = "enabled" ) ]
246#[ allow( unused_imports ) ]
247pub mod exposed
248{
249  use super::prelude;
250  #[ doc( inline ) ]
251  #[ allow( clippy::useless_attribute, clippy::pub_use ) ]
252  pub use prelude::*;
253}
254
255/// Prelude to use essentials: `use my_module::prelude::*`.
256#[ cfg( feature = "enabled" ) ]
257#[ allow( unused_imports ) ]
258pub mod prelude
259{
260  use super::private;
261  #[ doc( inline ) ]
262  #[ allow( clippy::useless_attribute, clippy::pub_use ) ]
263  pub use private::
264  {
265    CloneDyn,
266    clone_into_box,
267    clone,
268  };
269}