diff --git a/Cargo.toml b/Cargo.toml index a620835..45d0038 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "alloc-checked" description = "Collections that don't panic on alloc failures" authors = ["Adam Cimarosti "] -version = "0.1.0" +version = "0.1.1" edition = "2021" repository = "https://github.com/questdb/alloc-checked" keywords = ["alloc", "collections", "no-std", "safe-allocation", "container"] diff --git a/src/lib.rs b/src/lib.rs index c28096c..c144bdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,4 +5,5 @@ extern crate alloc; extern crate core; +pub mod try_clone; pub mod vec; diff --git a/src/try_clone.rs b/src/try_clone.rs new file mode 100644 index 0000000..62387f1 --- /dev/null +++ b/src/try_clone.rs @@ -0,0 +1,10 @@ +/// A variant of the `Clone` trait which can fail. +pub trait TryClone: Sized { + type Error; + + fn try_clone(&self) -> Result; + fn try_clone_from(&mut self, source: &Self) -> Result<(), Self::Error> { + *self = source.try_clone()?; + Ok(()) + } +} diff --git a/src/vec.rs b/src/vec.rs index d0f988e..3053e90 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1,3 +1,4 @@ +use crate::try_clone::TryClone; use alloc::alloc::Allocator; use alloc::collections::TryReserveError; use alloc::vec::Vec as InnerVec; @@ -5,7 +6,6 @@ use core::fmt::Debug; use core::ops::{Deref, DerefMut, Index, IndexMut}; use core::slice::SliceIndex; -#[derive(Clone)] pub struct Vec { inner: InnerVec, } @@ -186,6 +186,16 @@ impl Vec { } } +impl TryClone for Vec { + type Error = TryReserveError; + + fn try_clone(&self) -> Result { + let mut cloned = Self::with_capacity_in(self.len(), self.allocator().clone())?; + cloned.extend_from_slice(self.inner.as_slice())?; + Ok(cloned) + } +} + impl, A: Allocator> Index for Vec { type Output = I::Output; @@ -316,7 +326,7 @@ mod tests { return Err(AllocError); } let allocated = Global.allocate(layout)?; - let true_new_in_use = self.in_use.fetch_add(layout.size(), Ordering::SeqCst); + let true_new_in_use = self.in_use.fetch_add(allocated.len(), Ordering::SeqCst); unsafe { if true_new_in_use > self.watermark { let ptr = allocated.as_ptr() as *mut u8; @@ -788,7 +798,7 @@ mod tests { let wma = WatermarkAllocator::new(128); let mut vec1 = Vec::new_in(wma); vec1.extend(vec![1, 2, 3]).unwrap(); - let vec2 = vec1.clone(); + let vec2 = vec1.try_clone().unwrap(); assert_eq!(vec1, vec2); let e0vec1 = get_first_elem_vec(vec1); @@ -814,7 +824,8 @@ mod tests { let wma = WatermarkAllocator::new(128); let mut vec1 = Vec::new_in(wma); vec1.extend(vec![1, 2, 3]).unwrap(); - let vec2 = vec1.clone(); + let vec2 = vec1.try_clone().unwrap(); + assert_eq!(vec1, vec2); let d0vec1 = doubled_first_elem_vec(vec1); let d0vec2 = doubled_first_elem_slice(vec2); @@ -822,4 +833,15 @@ mod tests { assert_eq!(d0vec1, 2); assert_eq!(d0vec2, 2); } + + #[test] + fn test_try_clone() { + let wma = WatermarkAllocator::new(64); + let mut vec1 = Vec::new_in(wma.clone()); + vec1.extend([1usize, 2, 3, 4, 5, 6, 7, 8]).unwrap(); + assert_eq!(vec1.len(), 8); + assert_eq!(vec1.capacity(), 8); + assert_eq!(wma.in_use(), 64); + assert!(vec1.try_clone().is_err()); + } }