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