use alloc::alloc::Layout;
use core::iter::{ExactSizeIterator, Iterator};
use core::marker::PhantomData;
use core::mem;
use core::ptr;
use core::slice;
use core::sync::atomic;
use core::usize;
use super::{Arc, ArcInner};
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd)]
#[repr(C)]
pub struct HeaderSlice<H, T: ?Sized> {
pub header: H,
pub slice: T,
}
impl<H, T> Arc<HeaderSlice<H, [T]>> {
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_to_data_offset = offset_of!(ArcInner<HeaderSlice<H, [T; 0]>>, data);
let data_to_slice_offset = offset_of!(HeaderSlice<H, [T; 0]>, slice);
let slice_offset = inner_to_data_offset + data_to_slice_offset;
let slice_size = mem::size_of::<T>()
.checked_mul(num_items)
.expect("size overflows");
let usable_size = slice_offset
.checked_add(slice_size)
.expect("size overflows");
let align = mem::align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>();
let size = usable_size.wrapping_add(align - 1) & !(align - 1);
assert!(size >= usable_size, "size overflows");
let layout = Layout::from_size_align(size, align).expect("invalid layout");
let ptr: *mut ArcInner<HeaderSlice<H, [T]>>;
unsafe {
let buffer = alloc::alloc::alloc(layout);
if buffer.is_null() {
alloc::alloc::handle_alloc_error(layout);
}
let fake_slice: &mut [T] = slice::from_raw_parts_mut(buffer as *mut T, num_items);
ptr = fake_slice as *mut [T] as *mut ArcInner<HeaderSlice<H, [T]>>;
let count = atomic::AtomicUsize::new(1);
ptr::write(&mut ((*ptr).count), count);
ptr::write(&mut ((*ptr).data.header), header);
if num_items != 0 {
let mut current = (*ptr).data.slice.as_mut_ptr();
debug_assert_eq!(current as usize - buffer as usize, slice_offset);
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"
);
debug_assert_eq!(current as *mut u8, buffer.add(usable_size));
}
assert!(
items.next().is_none(),
"ExactSizeIterator under-reported length"
);
}
assert_eq!(
mem::size_of::<Self>(),
mem::size_of::<usize>() * 2,
"The Arc will be fat"
);
unsafe {
Arc {
p: ptr::NonNull::new_unchecked(ptr),
phantom: PhantomData,
}
}
}
}
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd)]
#[repr(C)]
pub struct HeaderWithLength<H> {
pub header: H,
pub length: usize,
}
impl<H> HeaderWithLength<H> {
#[inline]
pub fn new(header: H, length: usize) -> Self {
HeaderWithLength { header, length }
}
}
pub(crate) type HeaderSliceWithLength<H, T> = HeaderSlice<HeaderWithLength<H>, T>;