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}