use core::mem;
use std::iter::FromIterator;
use crate::{maybe_shrink, ExcessShrink, RcCounter, RcMeta, SizeHintExtendingIter};
pub struct RcUtils;
impl RcUtils {
#[inline]
pub(crate) fn vec_with_capacity_for_rc_from_iter<TCounter: RcCounter, TIter>(
iter: TIter,
) -> Vec<u8>
where
TIter: IntoIterator<Item = u8>,
{
let extend_size_by = Self::meta_overhead::<TCounter>();
let new_iter = SizeHintExtendingIter::new(iter.into_iter(), extend_size_by);
Vec::from_iter(new_iter)
}
#[inline]
pub fn maybe_shrink_vec<TCounter: RcCounter, T: ExcessShrink>(vec: &mut Vec<u8>) {
let overhead = Self::meta_overhead::<TCounter>();
maybe_shrink::<T>(vec, overhead);
}
#[inline]
pub(crate) unsafe fn add_padding_and_metadata<TCounter: RcCounter>(
vec: &mut Vec<u8>,
meta: RcMeta<TCounter>,
) -> *const RcMeta<TCounter> {
Self::add_padding_and_metadata_inner::<TCounter>(vec, meta, true)
}
#[inline]
unsafe fn add_padding_and_metadata_inner<TCounter: RcCounter>(
vec: &mut Vec<u8>,
meta: RcMeta<TCounter>,
first_try: bool,
) -> *const RcMeta<TCounter> {
let len = vec.len();
let meta_size = mem::size_of::<RcMeta<TCounter>>();
{
let vec_ptr = vec.as_ptr();
let meta_ptr_candidate = vec_ptr.add(vec.len());
let required_padding =
Self::padding(meta_ptr_candidate, mem::align_of::<RcMeta<TCounter>>());
let additional_capacity_for_metadata = required_padding + meta_size;
if vec.capacity() >= vec.len() + additional_capacity_for_metadata {
let padding_buf = [0u8; 16];
let padding_buf = &padding_buf[0..required_padding];
vec.extend_from_slice(padding_buf);
let meta_ptr =
meta_ptr_candidate.add(required_padding) as *mut u8 as *mut RcMeta<TCounter>;
*meta_ptr = meta;
vec.set_len(len);
return meta_ptr;
}
}
if first_try {
vec.reserve(Self::meta_overhead::<TCounter>());
Self::add_padding_and_metadata_inner(vec, meta, false)
} else {
panic!(
"Implementation error: We just reserved enough capacity but this method \
tells us there's still not enough capacity."
);
}
}
pub(crate) fn slice_to_vec_with_meta_overhead<TCounter: RcCounter>(slice: &[u8]) -> Vec<u8> {
let slice_len = slice.len();
let mut vec = Vec::with_capacity(slice_len + Self::meta_overhead::<TCounter>());
vec.extend_from_slice(slice);
vec
}
#[inline]
pub(crate) fn meta_overhead<TCounter: RcCounter>() -> usize {
let alignment = mem::align_of::<RcMeta<TCounter>>();
let size = mem::size_of::<RcMeta<TCounter>>();
alignment - 1 + size
}
#[inline]
fn padding(ptr: *const u8, alignment: usize) -> usize {
let target = ptr as usize;
let remainder = target % alignment;
if remainder == 0 {
0
} else {
let padding = alignment - remainder;
assert!(padding <= (alignment - 1));
padding
}
}
}