fallacy_clone/
lib.rs

1//! Fallible clone.
2
3#![cfg_attr(nightly, feature(allocator_api))]
4
5pub use fallacy_alloc::AllocError;
6use std::sync::{Arc, Weak};
7
8#[cfg(feature = "derive")]
9pub use fallacy_clone_derive::TryClone;
10
11/// Tries to clone, return an error instead of panic if allocation failed.
12pub trait TryClone: Sized {
13    fn try_clone(&self) -> Result<Self, AllocError>;
14
15    /// Performs copy-assignment from `source`.
16    ///
17    /// `a.try_clone_from(&b)` is equivalent to `a = b.try_clone()` in functionality,
18    /// but can be overridden to reuse the resources of `a` to avoid unnecessary
19    /// allocations.
20    #[inline]
21    fn try_clone_from(&mut self, source: &Self) -> Result<(), AllocError> {
22        *self = source.try_clone()?;
23        Ok(())
24    }
25}
26
27macro_rules! impl_try_clone {
28    ($($val: ty),*) => {
29        $(impl TryClone for $val {
30            #[inline(always)]
31            fn try_clone(&self) -> Result<Self, AllocError> {
32                Ok(*self)
33            }
34            #[inline(always)]
35            fn try_clone_from(&mut self, source: &Self) -> Result<(), AllocError> {
36                *self = *source;
37                Ok(())
38            }
39        })*
40    }
41}
42
43impl_try_clone!(bool, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
44
45impl<T: ?Sized> TryClone for &T {
46    #[inline(always)]
47    fn try_clone(&self) -> Result<Self, AllocError> {
48        Ok(*self)
49    }
50
51    #[inline(always)]
52    fn try_clone_from(&mut self, source: &Self) -> Result<(), AllocError> {
53        *self = *source;
54        Ok(())
55    }
56}
57
58impl<T: TryClone> TryClone for Option<T> {
59    #[inline]
60    fn try_clone(&self) -> Result<Self, AllocError> {
61        Ok(match self {
62            Some(t) => Some(t.try_clone()?),
63            None => None,
64        })
65    }
66
67    #[inline]
68    fn try_clone_from(&mut self, source: &Self) -> Result<(), AllocError> {
69        match source {
70            None => *self = None,
71            Some(src) => match self {
72                None => *self = Some(src.try_clone()?),
73                Some(dest) => dest.try_clone_from(src)?,
74            },
75        }
76        Ok(())
77    }
78}
79
80impl TryClone for String {
81    #[inline]
82    fn try_clone(&self) -> Result<Self, AllocError> {
83        let mut s = String::new();
84        s.try_reserve(s.len())?;
85        s.push_str(self);
86        Ok(s)
87    }
88
89    #[inline]
90    fn try_clone_from(&mut self, source: &Self) -> Result<(), AllocError> {
91        self.clear();
92        self.try_reserve(source.len())?;
93        self.push_str(source);
94        Ok(())
95    }
96}
97
98impl<T: ?Sized> TryClone for Arc<T> {
99    #[inline]
100    fn try_clone(&self) -> Result<Self, AllocError> {
101        Ok(self.clone())
102    }
103}
104
105impl<T: ?Sized> TryClone for Weak<T> {
106    #[inline]
107    fn try_clone(&self) -> Result<Self, AllocError> {
108        Ok(self.clone())
109    }
110}
111
112#[cfg(nightly)]
113mod nightly {
114    use crate::TryClone;
115    use fallacy_alloc::AllocError;
116    use std::alloc::{Allocator, Global, Layout};
117
118    impl TryClone for Global {
119        #[inline(always)]
120        fn try_clone(&self) -> Result<Self, AllocError> {
121            Ok(Global)
122        }
123    }
124
125    impl<T: TryClone, A: Allocator + TryClone> TryClone for Box<T, A> {
126        #[inline]
127        fn try_clone(&self) -> Result<Self, AllocError> {
128            let alloc = Box::allocator(self).try_clone()?;
129            let t = self.as_ref().try_clone()?;
130            let b = Box::try_new_in(t, alloc).map_err(|_| AllocError::new(Layout::new::<T>()))?;
131            Ok(b)
132        }
133    }
134}