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#[doc(inline)]
48pub use rune_alloc_macros::TryClone;
49
50/// Fallible `TryClone` trait.
51pub trait TryClone: Sized {
52    /// Try to clone the current value, raising an allocation error if it's unsuccessful.
53    fn try_clone(&self) -> Result<Self, Error>;
54
55    /// Performs copy-assignment from `source`.
56    ///
57    /// `a.try_clone_from(&b)` is equivalent to `a = b.clone()` in
58    /// functionality, but can be overridden to reuse the resources of `a` to
59    /// avoid unnecessary allocations.
60    #[inline]
61    fn try_clone_from(&mut self, source: &Self) -> Result<(), Error> {
62        *self = source.try_clone()?;
63        Ok(())
64    }
65}
66
67/// Marker trait for types which are `Copy`.
68#[cfg_attr(rune_nightly, rustc_specialization_trait)]
69pub trait TryCopy: TryClone {}
70
71impl<T: ?Sized> TryClone for &T {
72    fn try_clone(&self) -> Result<Self, Error> {
73        Ok(*self)
74    }
75}
76
77macro_rules! impl_tuple {
78    ($count:expr $(, $ty:ident $var:ident $num:expr)*) => {
79        impl<$($ty,)*> TryClone for ($($ty,)*) where $($ty: TryClone,)* {
80            #[inline]
81            fn try_clone(&self) -> Result<Self, Error> {
82                let ($($var,)*) = self;
83                Ok(($($var.try_clone()?,)*))
84            }
85        }
86    }
87}
88
89repeat_macro!(impl_tuple);
90
91macro_rules! impl_copy {
92    ($ty:ty) => {
93        impl TryClone for $ty {
94            #[inline]
95            fn try_clone(&self) -> Result<Self, Error> {
96                Ok(*self)
97            }
98        }
99
100        impl TryCopy for $ty {}
101    };
102}
103
104impl_copy!(char);
105impl_copy!(bool);
106impl_copy!(usize);
107impl_copy!(isize);
108impl_copy!(u8);
109impl_copy!(u16);
110impl_copy!(u32);
111impl_copy!(u64);
112impl_copy!(u128);
113impl_copy!(i8);
114impl_copy!(i16);
115impl_copy!(i32);
116impl_copy!(i64);
117impl_copy!(i128);
118impl_copy!(f32);
119impl_copy!(f64);
120
121impl_copy!(core::num::NonZeroUsize);
122impl_copy!(core::num::NonZeroIsize);
123impl_copy!(core::num::NonZeroU8);
124impl_copy!(core::num::NonZeroU16);
125impl_copy!(core::num::NonZeroU32);
126impl_copy!(core::num::NonZeroU64);
127impl_copy!(core::num::NonZeroU128);
128impl_copy!(core::num::NonZeroI8);
129impl_copy!(core::num::NonZeroI16);
130impl_copy!(core::num::NonZeroI32);
131impl_copy!(core::num::NonZeroI64);
132impl_copy!(core::num::NonZeroI128);
133
134#[cfg(feature = "std")]
135impl_copy!(::std::process::ExitStatus);
136
137impl<T, E> TryClone for core::result::Result<T, E>
138where
139    T: TryClone,
140    E: TryClone,
141{
142    #[inline]
143    fn try_clone(&self) -> Result<Self, Error> {
144        Ok(match self {
145            Ok(value) => Ok(value.try_clone()?),
146            Err(value) => Err(value.try_clone()?),
147        })
148    }
149}
150
151impl<T> TryClone for core::option::Option<T>
152where
153    T: TryClone,
154{
155    #[inline]
156    fn try_clone(&self) -> Result<Self, Error> {
157        Ok(match self {
158            Some(value) => Some(value.try_clone()?),
159            None => None,
160        })
161    }
162}
163
164#[cfg(feature = "alloc")]
165impl<T: ?Sized> TryClone for ::rust_alloc::sync::Arc<T> {
166    fn try_clone(&self) -> Result<Self, Error> {
167        Ok(self.clone())
168    }
169}
170
171#[cfg(feature = "alloc")]
172impl<T: ?Sized> TryClone for ::rust_alloc::rc::Rc<T> {
173    fn try_clone(&self) -> Result<Self, Error> {
174        Ok(self.clone())
175    }
176}
177
178#[cfg(feature = "alloc")]
179impl<T> TryClone for ::rust_alloc::boxed::Box<T>
180where
181    T: TryClone,
182{
183    fn try_clone(&self) -> Result<Self, Error> {
184        Ok(::rust_alloc::boxed::Box::new(self.as_ref().try_clone()?))
185    }
186}
187
188#[cfg(feature = "alloc")]
189impl<T> TryClone for ::rust_alloc::boxed::Box<[T]>
190where
191    T: TryClone,
192{
193    fn try_clone(&self) -> Result<Self, Error> {
194        // TODO: use a fallible box allocation.
195        let mut out = ::rust_alloc::vec::Vec::with_capacity(self.len());
196
197        for value in self.iter() {
198            out.push(value.try_clone()?);
199        }
200
201        Ok(out.into())
202    }
203}
204
205#[cfg(feature = "alloc")]
206impl TryClone for ::rust_alloc::string::String {
207    #[inline]
208    fn try_clone(&self) -> Result<Self, Error> {
209        // TODO: use fallible allocations for component.
210        Ok(self.clone())
211    }
212}
213
214#[cfg(all(test, feature = "alloc"))]
215impl<T> TryClone for ::rust_alloc::vec::Vec<T>
216where
217    T: TryClone,
218{
219    #[inline]
220    fn try_clone(&self) -> Result<Self, Error> {
221        let mut out = ::rust_alloc::vec::Vec::with_capacity(self.len());
222
223        for value in self {
224            out.push(value.try_clone()?);
225        }
226
227        Ok(out)
228    }
229}
230
231impl TryClone for crate::path::PathBuf {
232    fn try_clone(&self) -> Result<Self, Error> {
233        Ok(self.clone())
234    }
235}