From febdc880c9a82d4947f2d7270353d2a050cdf150 Mon Sep 17 00:00:00 2001 From: Adam Cimarosti Date: Tue, 8 Oct 2024 14:02:30 +0100 Subject: [PATCH] claim trait to allow non-fallible cloning --- src/claim.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/vec.rs | 20 +++++++++++++------- 3 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 src/claim.rs diff --git a/src/claim.rs b/src/claim.rs new file mode 100644 index 0000000..aac2ce0 --- /dev/null +++ b/src/claim.rs @@ -0,0 +1,45 @@ +use alloc::rc::Rc; +use alloc::sync::Arc; +use core::convert::Infallible; +use core::marker::PhantomData; + +/// A marker trait for infallible cloneable objects. +/// Only implement this for your type if you can guarantee that cloning it +/// is guaranteed not to panic. +/// +/// For details on the idea, read the [Claiming, auto and +/// otherwise](https://smallcultfollowing.com/babysteps/blog/2024/06/21/claim-auto-and-otherwise/) +/// blog post. +pub trait Claim: Clone {} + +// Anything which is trivially copiable is automatically infallible +// We need to list these out since the compiler will not allow us to `impl impl Claim {}` +impl Claim for () {} +impl Claim for u8 {} +impl Claim for u16 {} +impl Claim for u32 {} +impl Claim for u64 {} +impl Claim for u128 {} +impl Claim for usize {} +impl Claim for i8 {} +impl Claim for i16 {} +impl Claim for i32 {} +impl Claim for i64 {} +impl Claim for i128 {} +impl Claim for isize {} +impl Claim for f32 {} +impl Claim for f64 {} +impl Claim for bool {} +impl Claim for char {} +impl Claim for *const T {} +impl Claim for *mut T {} +impl Claim for [T; N] {} +impl Claim for PhantomData {} +impl Claim for &T {} + +// A few other common impls, non-exhaustive +impl Claim for Arc {} +impl Claim for Rc {} +impl Claim for Infallible {} +impl Claim for Option {} +impl Claim for Result {} diff --git a/src/lib.rs b/src/lib.rs index c144bdf..a048fde 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,5 +5,6 @@ extern crate alloc; extern crate core; +mod claim; pub mod try_clone; pub mod vec; diff --git a/src/vec.rs b/src/vec.rs index 3053e90..7d86c58 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1,3 +1,4 @@ +use crate::claim::Claim; use crate::try_clone::TryClone; use alloc::alloc::Allocator; use alloc::collections::TryReserveError; @@ -147,7 +148,7 @@ impl Vec { } } -impl Vec { +impl Vec { #[inline] pub fn extend_from_slice(&mut self, slice: &[T]) -> Result<(), TryReserveError> { self.reserve(slice.len())?; @@ -186,7 +187,7 @@ impl Vec { } } -impl TryClone for Vec { +impl TryClone for Vec { type Error = TryReserveError; fn try_clone(&self) -> Result { @@ -288,6 +289,7 @@ impl AsMut<[T]> for Vec { #[cfg(test)] mod tests { use super::*; + use crate::claim::Claim; use alloc::alloc::Global; use alloc::boxed::Box; use alloc::collections::TryReserveError; @@ -303,6 +305,8 @@ mod tests { in_use: Arc, } + impl Claim for WatermarkAllocator {} + impl WatermarkAllocator { pub(crate) fn in_use(&self) -> usize { self.in_use.load(Ordering::SeqCst) @@ -496,15 +500,17 @@ mod tests { assert_eq!(vec[3], 4); } - /// A type that implements `Clone` but not `Copy`. + /// A type that implements `Clone` and `Claim`, but not `Copy`. #[derive(Clone, Eq, PartialEq)] - struct Cloneable(i32); + struct Claimable(i32); + + impl Claim for Claimable {} #[test] fn test_extend_from_slice_clone() { let wma = WatermarkAllocator::new(32); let mut vec = Vec::new_in(wma); - vec.extend_from_slice(&[Cloneable(1), Cloneable(2), Cloneable(3), Cloneable(4)]) + vec.extend_from_slice(&[Claimable(1), Claimable(2), Claimable(3), Claimable(4)]) .unwrap(); } @@ -783,12 +789,12 @@ mod tests { } } - fn get_first_elem_vec(vec: impl AsRef>) -> T { + fn get_first_elem_vec(vec: impl AsRef>) -> T { let vec = vec.as_ref(); vec.first().unwrap().clone() } - fn get_first_elem_slice(slice: impl AsRef<[T]>) -> T { + fn get_first_elem_slice(slice: impl AsRef<[T]>) -> T { let vec = slice.as_ref(); vec.first().unwrap().clone() }