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
134impl<T, E> TryClone for ::core::result::Result<T, E>
135where
136    T: TryClone,
137    E: TryClone,
138{
139    #[inline]
140    fn try_clone(&self) -> Result<Self, Error> {
141        Ok(match self {
142            Ok(value) => Ok(value.try_clone()?),
143            Err(value) => Err(value.try_clone()?),
144        })
145    }
146}
147
148impl<T> TryClone for ::core::option::Option<T>
149where
150    T: TryClone,
151{
152    #[inline]
153    fn try_clone(&self) -> Result<Self, Error> {
154        Ok(match self {
155            Some(value) => Some(value.try_clone()?),
156            None => None,
157        })
158    }
159}
160
161#[cfg(feature = "alloc")]
162impl<T: ?Sized> TryClone for ::rust_alloc::sync::Arc<T> {
163    fn try_clone(&self) -> Result<Self, Error> {
164        Ok(self.clone())
165    }
166}
167
168#[cfg(feature = "alloc")]
169impl<T: ?Sized> TryClone for ::rust_alloc::rc::Rc<T> {
170    fn try_clone(&self) -> Result<Self, Error> {
171        Ok(self.clone())
172    }
173}
174
175#[cfg(feature = "alloc")]
176impl<T> TryClone for ::rust_alloc::boxed::Box<T>
177where
178    T: TryClone,
179{
180    fn try_clone(&self) -> Result<Self, Error> {
181        Ok(::rust_alloc::boxed::Box::new(self.as_ref().try_clone()?))
182    }
183}
184
185#[cfg(feature = "alloc")]
186impl<T> TryClone for ::rust_alloc::boxed::Box<[T]>
187where
188    T: TryClone,
189{
190    fn try_clone(&self) -> Result<Self, Error> {
191        // TODO: use a fallible box allocation.
192        let mut out = ::rust_alloc::vec::Vec::with_capacity(self.len());
193
194        for value in self.iter() {
195            out.push(value.try_clone()?);
196        }
197
198        Ok(out.into())
199    }
200}
201
202#[cfg(feature = "alloc")]
203impl TryClone for ::rust_alloc::string::String {
204    #[inline]
205    fn try_clone(&self) -> Result<Self, Error> {
206        // TODO: use fallible allocations for component.
207        Ok(self.clone())
208    }
209}
210
211#[cfg(all(test, feature = "alloc"))]
212impl<T> TryClone for ::rust_alloc::vec::Vec<T>
213where
214    T: TryClone,
215{
216    #[inline]
217    fn try_clone(&self) -> Result<Self, Error> {
218        let mut out = ::rust_alloc::vec::Vec::with_capacity(self.len());
219
220        for value in self {
221            out.push(value.try_clone()?);
222        }
223
224        Ok(out)
225    }
226}
227
228impl TryClone for crate::path::PathBuf {
229    fn try_clone(&self) -> Result<Self, Error> {
230        Ok(self.clone())
231    }
232}