diff options
Diffstat (limited to 'vendor/triomphe/src/header.rs')
-rw-r--r-- | vendor/triomphe/src/header.rs | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/vendor/triomphe/src/header.rs b/vendor/triomphe/src/header.rs new file mode 100644 index 000000000..e35ec48b0 --- /dev/null +++ b/vendor/triomphe/src/header.rs @@ -0,0 +1,378 @@ +use alloc::alloc::Layout; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; +use core::iter::{ExactSizeIterator, Iterator}; +use core::marker::PhantomData; +use core::mem::{self, ManuallyDrop}; +use core::ptr::{self, addr_of_mut}; +use core::usize; + +use super::{Arc, ArcInner}; + +/// Structure to allow Arc-managing some fixed-sized data and a variably-sized +/// slice in a single allocation. +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd)] +#[repr(C)] +pub struct HeaderSlice<H, T: ?Sized> { + /// The fixed-sized data. + pub header: H, + + /// The dynamically-sized data. + pub slice: T, +} + +impl<H, T> Arc<HeaderSlice<H, [T]>> { + /// Creates an Arc for a HeaderSlice using the given header struct and + /// iterator to generate the slice. The resulting Arc will be fat. + pub fn from_header_and_iter<I>(header: H, mut items: I) -> Self + where + I: Iterator<Item = T> + ExactSizeIterator, + { + assert_ne!(mem::size_of::<T>(), 0, "Need to think about ZST"); + + let num_items = items.len(); + + let inner = Arc::allocate_for_header_and_slice(num_items); + + unsafe { + // Write the data. + // + // Note that any panics here (i.e. from the iterator) are safe, since + // we'll just leak the uninitialized memory. + ptr::write(&mut ((*inner.as_ptr()).data.header), header); + if num_items != 0 { + let mut current = (*inner.as_ptr()).data.slice.as_mut_ptr(); + for _ in 0..num_items { + ptr::write( + current, + items + .next() + .expect("ExactSizeIterator over-reported length"), + ); + current = current.offset(1); + } + assert!( + items.next().is_none(), + "ExactSizeIterator under-reported length" + ); + } + assert!( + items.next().is_none(), + "ExactSizeIterator under-reported length" + ); + } + + // Safety: ptr is valid & the inner structure is fully initialized + Arc { + p: inner, + phantom: PhantomData, + } + } + + /// Creates an Arc for a HeaderSlice using the given header struct and + /// iterator to generate the slice. The resulting Arc will be fat. + pub fn from_header_and_slice(header: H, items: &[T]) -> Self + where + T: Copy, + { + assert_ne!(mem::size_of::<T>(), 0, "Need to think about ZST"); + + let num_items = items.len(); + + let inner = Arc::allocate_for_header_and_slice(num_items); + + unsafe { + // Write the data. + ptr::write(&mut ((*inner.as_ptr()).data.header), header); + let dst = (*inner.as_ptr()).data.slice.as_mut_ptr(); + ptr::copy_nonoverlapping(items.as_ptr(), dst, num_items); + } + + // Safety: ptr is valid & the inner structure is fully initialized + Arc { + p: inner, + phantom: PhantomData, + } + } + + /// Creates an Arc for a HeaderSlice using the given header struct and + /// vec to generate the slice. The resulting Arc will be fat. + pub fn from_header_and_vec(header: H, mut v: Vec<T>) -> Self { + let len = v.len(); + + let inner = Arc::allocate_for_header_and_slice(len); + + unsafe { + // Safety: inner is a valid pointer, so this can't go out of bounds + let dst = addr_of_mut!((*inner.as_ptr()).data.header); + + // Safety: `dst` is valid for writes (just allocated) + ptr::write(dst, header); + } + + unsafe { + let src = v.as_mut_ptr(); + + // Safety: inner is a valid pointer, so this can't go out of bounds + let dst = addr_of_mut!((*inner.as_ptr()).data.slice) as *mut T; + + // Safety: + // - `src` is valid for reads for `len` (got from `Vec`) + // - `dst` is valid for writes for `len` (just allocated, with layout for appropriate slice) + // - `src` and `dst` don't overlap (separate allocations) + ptr::copy_nonoverlapping(src, dst, len); + + // Deallocate vec without dropping `T` + // + // Safety: 0..0 elements are always initialized, 0 <= cap for any cap + v.set_len(0); + } + + // Safety: ptr is valid & the inner structure is fully initialized + Arc { + p: inner, + phantom: PhantomData, + } + } +} + +impl<H> Arc<HeaderSlice<H, str>> { + /// Creates an Arc for a HeaderSlice using the given header struct and + /// a str slice to generate the slice. The resulting Arc will be fat. + pub fn from_header_and_str(header: H, string: &str) -> Self { + let bytes = Arc::from_header_and_slice(header, string.as_bytes()); + + // Safety: `ArcInner` and `HeaderSlice` are `repr(C)`, `str` has the same layout as `[u8]`, + // thus it's ok to "transmute" between `Arc<HeaderSlice<H, [u8]>>` and `Arc<HeaderSlice<H, str>>`. + // + // `bytes` are a valid string since we've just got them from a valid `str`. + unsafe { Arc::from_raw_inner(Arc::into_raw_inner(bytes) as _) } + } +} + +/// Header data with an inline length. Consumers that use HeaderWithLength as the +/// Header type in HeaderSlice can take advantage of ThinArc. +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd)] +#[repr(C)] +pub struct HeaderWithLength<H> { + /// The fixed-sized data. + pub header: H, + + /// The slice length. + pub length: usize, +} + +impl<H> HeaderWithLength<H> { + /// Creates a new HeaderWithLength. + #[inline] + pub fn new(header: H, length: usize) -> Self { + HeaderWithLength { header, length } + } +} + +impl<T: ?Sized> From<Arc<HeaderSlice<(), T>>> for Arc<T> { + fn from(this: Arc<HeaderSlice<(), T>>) -> Self { + debug_assert_eq!( + Layout::for_value::<HeaderSlice<(), T>>(&this), + Layout::for_value::<T>(&this.slice) + ); + + // Safety: `HeaderSlice<(), T>` and `T` has the same layout + unsafe { Arc::from_raw_inner(Arc::into_raw_inner(this) as _) } + } +} + +impl<T: ?Sized> From<Arc<T>> for Arc<HeaderSlice<(), T>> { + fn from(this: Arc<T>) -> Self { + // Safety: `T` and `HeaderSlice<(), T>` has the same layout + unsafe { Arc::from_raw_inner(Arc::into_raw_inner(this) as _) } + } +} + +impl<T: Copy> From<&[T]> for Arc<[T]> { + fn from(slice: &[T]) -> Self { + Arc::from_header_and_slice((), slice).into() + } +} + +impl From<&str> for Arc<str> { + fn from(s: &str) -> Self { + Arc::from_header_and_str((), s).into() + } +} + +impl From<String> for Arc<str> { + fn from(s: String) -> Self { + Self::from(&s[..]) + } +} + +// FIXME: once `pointer::with_metadata_of` is stable or +// implementable on stable without assuming ptr layout +// this will be able to accept `T: ?Sized`. +impl<T> From<Box<T>> for Arc<T> { + fn from(b: Box<T>) -> Self { + let layout = Layout::for_value::<T>(&b); + + // Safety: the closure only changes the type of the pointer + let inner = unsafe { Self::allocate_for_layout(layout, |mem| mem as *mut ArcInner<T>) }; + + unsafe { + let src = Box::into_raw(b); + + // Safety: inner is a valid pointer, so this can't go out of bounds + let dst = addr_of_mut!((*inner.as_ptr()).data); + + // Safety: + // - `src` is valid for reads (got from `Box`) + // - `dst` is valid for writes (just allocated) + // - `src` and `dst` don't overlap (separate allocations) + ptr::copy_nonoverlapping(src, dst, 1); + + // Deallocate box without dropping `T` + // + // Safety: + // - `src` has been got from `Box::into_raw` + // - `ManuallyDrop<T>` is guaranteed to have the same layout as `T` + Box::<ManuallyDrop<T>>::from_raw(src as _); + } + + Arc { + p: inner, + phantom: PhantomData, + } + } +} + +impl<T> From<Vec<T>> for Arc<[T]> { + fn from(v: Vec<T>) -> Self { + Arc::from_header_and_vec((), v).into() + } +} + +pub(crate) type HeaderSliceWithLength<H, T> = HeaderSlice<HeaderWithLength<H>, T>; + +#[cfg(test)] +mod tests { + use alloc::boxed::Box; + use alloc::string::String; + use alloc::vec; + use core::iter; + + use crate::{Arc, HeaderSlice}; + + #[test] + fn from_header_and_iter_smoke() { + let arc = Arc::from_header_and_iter( + (42u32, 17u8), + IntoIterator::into_iter([1u16, 2, 3, 4, 5, 6, 7]), + ); + + assert_eq!(arc.header, (42, 17)); + assert_eq!(arc.slice, [1, 2, 3, 4, 5, 6, 7]); + } + + #[test] + fn from_header_and_slice_smoke() { + let arc = Arc::from_header_and_slice((42u32, 17u8), &[1u16, 2, 3, 4, 5, 6, 7]); + + assert_eq!(arc.header, (42, 17)); + assert_eq!(arc.slice, [1u16, 2, 3, 4, 5, 6, 7]); + } + + #[test] + fn from_header_and_vec_smoke() { + let arc = Arc::from_header_and_vec((42u32, 17u8), vec![1u16, 2, 3, 4, 5, 6, 7]); + + assert_eq!(arc.header, (42, 17)); + assert_eq!(arc.slice, [1u16, 2, 3, 4, 5, 6, 7]); + } + + #[test] + fn from_header_and_iter_empty() { + let arc = Arc::from_header_and_iter((42u32, 17u8), iter::empty::<u16>()); + + assert_eq!(arc.header, (42, 17)); + assert_eq!(arc.slice, []); + } + + #[test] + fn from_header_and_slice_empty() { + let arc = Arc::from_header_and_slice((42u32, 17u8), &[1u16; 0]); + + assert_eq!(arc.header, (42, 17)); + assert_eq!(arc.slice, []); + } + + #[test] + fn from_header_and_vec_empty() { + let arc = Arc::from_header_and_vec((42u32, 17u8), vec![1u16; 0]); + + assert_eq!(arc.header, (42, 17)); + assert_eq!(arc.slice, []); + } + + #[test] + fn issue_13_empty() { + crate::Arc::from_header_and_iter((), iter::empty::<usize>()); + } + + #[test] + fn issue_13_consumption() { + let s: &[u8] = &[0u8; 255]; + crate::Arc::from_header_and_iter((), s.iter().copied()); + } + + #[test] + fn from_header_and_str_smoke() { + let a = Arc::from_header_and_str( + 42, + "The answer to the ultimate question of life, the universe, and everything", + ); + assert_eq!(a.header, 42); + assert_eq!( + &a.slice, + "The answer to the ultimate question of life, the universe, and everything" + ); + + let empty = Arc::from_header_and_str((), ""); + assert_eq!(empty.header, ()); + assert_eq!(&empty.slice, ""); + } + + #[test] + fn erase_and_create_from_thin_air_header() { + let a: Arc<HeaderSlice<(), [u32]>> = Arc::from_header_and_slice((), &[12, 17, 16]); + let b: Arc<[u32]> = a.into(); + + assert_eq!(&*b, [12, 17, 16]); + + let c: Arc<HeaderSlice<(), [u32]>> = b.into(); + + assert_eq!(&c.slice, [12, 17, 16]); + assert_eq!(c.header, ()); + } + + #[test] + fn from_box_and_vec() { + let b = Box::new(String::from("xxx")); + let b = Arc::<String>::from(b); + assert_eq!(&*b, "xxx"); + + let v = vec![String::from("1"), String::from("2"), String::from("3")]; + let v = Arc::<[_]>::from(v); + assert_eq!( + &*v, + [String::from("1"), String::from("2"), String::from("3")] + ); + + let mut v = vec![String::from("1"), String::from("2"), String::from("3")]; + v.reserve(10); + let v = Arc::<[_]>::from(v); + assert_eq!( + &*v, + [String::from("1"), String::from("2"), String::from("3")] + ); + } +} |