rune_alloc/clone.rs
1//! The `TryClone` trait for types that cannot be 'implicitly copied'.
2//!
3//! In Rust, some simple types are "implicitly copyable" and when you assign
4//! them or pass them as arguments, the receiver will get a copy, leaving the
5//! original value in place. These types do not require allocation to copy and
6//! do not have finalizers (i.e., they do not contain owned boxes or implement
7//! [`Drop`]), so the compiler considers them cheap and safe to copy. For other
8//! types copies must be made explicitly, by convention implementing the
9//! [`TryClone`] trait and calling the [`try_clone`] method.
10//!
11//! [`try_clone`]: TryClone::try_clone
12//!
13//! Basic usage example:
14//!
15//! ```
16//! use rune::alloc::String;
17//! use rune::alloc::prelude::*;
18//!
19//! // String type implements TryClone
20//! let s = String::new();
21//! // ... so we can clone it
22//! let copy = s.try_clone()?;
23//! # Ok::<_, rune::alloc::Error>(())
24//! ```
25//!
26//! To easily implement the TryClone trait, you can also use
27//! `#[derive(TryClone)]`. Example:
28//!
29//! ```
30//! use rune::alloc::prelude::*;
31//!
32//! // we add the TryClone trait to Morpheus struct
33//! #[derive(TryClone)]
34//! struct Morpheus {
35//! blue_pill: f32,
36//! red_pill: i64,
37//! }
38//!
39//! let f = Morpheus { blue_pill: 0.0, red_pill: 0 };
40//! // and now we can clone it!
41//! let copy = f.try_clone()?;
42//! # Ok::<_, rune::alloc::Error>(())
43//! ```
44
45use crate::error::Error;
46
47/// Derive to implement the `TryClone` trait.
48///
49/// <br>
50///
51/// # Examples
52///
53/// Basic usage example:
54///
55/// ```
56/// use rune::alloc::String;
57/// use rune::alloc::clone::TryClone;
58///
59/// // String type implements TryClone
60/// let s = String::new();
61/// // ... so we can clone it
62/// let copy = s.try_clone()?;
63/// # Ok::<_, rune::alloc::Error>(())
64/// ```
65///
66/// To easily implement the TryClone trait, you can also use
67/// `#[derive(TryClone)]`. Example:
68///
69/// ```
70/// use rune::alloc::clone::TryClone;
71///
72/// // we add the TryClone trait to Morpheus struct
73/// #[derive(TryClone)]
74/// struct Morpheus {
75/// blue_pill: f32,
76/// red_pill: i64,
77/// }
78///
79/// let f = Morpheus { blue_pill: 0.0, red_pill: 0 };
80/// // and now we can clone it!
81/// let copy = f.try_clone()?;
82/// # Ok::<_, rune::alloc::Error>(())
83/// ```
84///
85/// <br>
86///
87/// ## Attributes
88///
89/// <br>
90///
91/// ### `try_clone(with = <path>)`
92///
93/// Specify a custom method when cloning a field.
94///
95/// ```
96/// use rune::alloc::clone::TryClone;
97///
98/// #[derive(Debug, TryClone)]
99/// #[non_exhaustive]
100/// pub struct Struct {
101/// #[try_clone(with = String::clone)]
102/// string: String,
103/// }
104/// ```
105///
106/// <br>
107///
108/// ### `try_clone(try_with = <path>)`
109///
110/// Specify a custom fallible method when cloning a field.
111///
112/// ```
113/// use rune::alloc::clone::TryClone;
114///
115/// #[derive(Debug, TryClone)]
116/// #[non_exhaustive]
117/// pub struct Struct {
118/// #[try_clone(try_with = rune::alloc::String::try_clone)]
119/// string: rune::alloc::String,
120/// }
121/// ```
122///
123/// <br>
124///
125/// ### `try_clone(copy)`
126///
127/// Specify that a field is `Copy`.
128///
129/// ```
130/// use rune::alloc::prelude::*;
131///
132/// #[derive(Debug, TryClone)]
133/// #[non_exhaustive]
134/// pub struct Struct {
135/// #[try_clone(copy)]
136/// number: u32,
137/// }
138/// ```
139pub use rune_alloc_macros::TryClone;
140
141/// Fallible `TryClone` trait.
142pub trait TryClone: Sized {
143 /// Try to clone the current value, raising an allocation error if it's unsuccessful.
144 fn try_clone(&self) -> Result<Self, Error>;
145
146 /// Performs copy-assignment from `source`.
147 ///
148 /// `a.try_clone_from(&b)` is equivalent to `a = b.clone()` in
149 /// functionality, but can be overridden to reuse the resources of `a` to
150 /// avoid unnecessary allocations.
151 #[inline]
152 fn try_clone_from(&mut self, source: &Self) -> Result<(), Error> {
153 *self = source.try_clone()?;
154 Ok(())
155 }
156}
157
158/// Marker trait for types which are `Copy`.
159#[cfg_attr(rune_nightly, rustc_specialization_trait)]
160pub trait TryCopy: TryClone {}
161
162impl<T: ?Sized> TryClone for &T {
163 fn try_clone(&self) -> Result<Self, Error> {
164 Ok(*self)
165 }
166}
167
168macro_rules! impl_tuple {
169 ($count:expr $(, $ty:ident $var:ident $num:expr)*) => {
170 impl<$($ty,)*> TryClone for ($($ty,)*) where $($ty: TryClone,)* {
171 #[inline]
172 fn try_clone(&self) -> Result<Self, Error> {
173 let ($($var,)*) = self;
174 Ok(($($var.try_clone()?,)*))
175 }
176 }
177 }
178}
179
180repeat_macro!(impl_tuple);
181
182macro_rules! impl_copy {
183 ($ty:ty) => {
184 impl TryClone for $ty {
185 #[inline]
186 fn try_clone(&self) -> Result<Self, Error> {
187 Ok(*self)
188 }
189 }
190
191 impl TryCopy for $ty {}
192 };
193}
194
195impl_copy!(char);
196impl_copy!(bool);
197impl_copy!(usize);
198impl_copy!(isize);
199impl_copy!(u8);
200impl_copy!(u16);
201impl_copy!(u32);
202impl_copy!(u64);
203impl_copy!(u128);
204impl_copy!(i8);
205impl_copy!(i16);
206impl_copy!(i32);
207impl_copy!(i64);
208impl_copy!(i128);
209impl_copy!(f32);
210impl_copy!(f64);
211
212impl_copy!(core::num::NonZeroUsize);
213impl_copy!(core::num::NonZeroIsize);
214impl_copy!(core::num::NonZeroU8);
215impl_copy!(core::num::NonZeroU16);
216impl_copy!(core::num::NonZeroU32);
217impl_copy!(core::num::NonZeroU64);
218impl_copy!(core::num::NonZeroU128);
219impl_copy!(core::num::NonZeroI8);
220impl_copy!(core::num::NonZeroI16);
221impl_copy!(core::num::NonZeroI32);
222impl_copy!(core::num::NonZeroI64);
223impl_copy!(core::num::NonZeroI128);
224
225#[cfg(feature = "std")]
226impl_copy!(::std::process::ExitStatus);
227
228impl<T, E> TryClone for core::result::Result<T, E>
229where
230 T: TryClone,
231 E: TryClone,
232{
233 #[inline]
234 fn try_clone(&self) -> Result<Self, Error> {
235 Ok(match self {
236 Ok(value) => Ok(value.try_clone()?),
237 Err(value) => Err(value.try_clone()?),
238 })
239 }
240}
241
242impl<T> TryClone for core::option::Option<T>
243where
244 T: TryClone,
245{
246 #[inline]
247 fn try_clone(&self) -> Result<Self, Error> {
248 Ok(match self {
249 Some(value) => Some(value.try_clone()?),
250 None => None,
251 })
252 }
253}
254
255#[cfg(feature = "alloc")]
256impl<T: ?Sized> TryClone for rust_alloc::sync::Arc<T> {
257 fn try_clone(&self) -> Result<Self, Error> {
258 Ok(self.clone())
259 }
260}
261
262#[cfg(feature = "alloc")]
263impl<T: ?Sized> TryClone for rust_alloc::rc::Rc<T> {
264 fn try_clone(&self) -> Result<Self, Error> {
265 Ok(self.clone())
266 }
267}
268
269#[cfg(feature = "alloc")]
270impl<T> TryClone for rust_alloc::boxed::Box<T>
271where
272 T: TryClone,
273{
274 fn try_clone(&self) -> Result<Self, Error> {
275 Ok(rust_alloc::boxed::Box::new(self.as_ref().try_clone()?))
276 }
277}
278
279#[cfg(feature = "alloc")]
280impl<T> TryClone for rust_alloc::boxed::Box<[T]>
281where
282 T: TryClone,
283{
284 fn try_clone(&self) -> Result<Self, Error> {
285 // TODO: use a fallible box allocation.
286 let mut out = rust_alloc::vec::Vec::with_capacity(self.len());
287
288 for value in self.iter() {
289 out.push(value.try_clone()?);
290 }
291
292 Ok(out.into())
293 }
294}
295
296#[cfg(feature = "alloc")]
297impl TryClone for rust_alloc::string::String {
298 #[inline]
299 fn try_clone(&self) -> Result<Self, Error> {
300 // TODO: use fallible allocations for component.
301 Ok(self.clone())
302 }
303}
304
305#[cfg(all(test, feature = "alloc"))]
306impl<T> TryClone for rust_alloc::vec::Vec<T>
307where
308 T: TryClone,
309{
310 #[inline]
311 fn try_clone(&self) -> Result<Self, Error> {
312 let mut out = rust_alloc::vec::Vec::with_capacity(self.len());
313
314 for value in self {
315 out.push(value.try_clone()?);
316 }
317
318 Ok(out)
319 }
320}
321
322impl TryClone for crate::path::PathBuf {
323 fn try_clone(&self) -> Result<Self, Error> {
324 Ok(self.clone())
325 }
326}