#![doc = crate::doc_macro::make_svgbobdoc!(
//! A variable-length array with inline storage.
//!
//! This consists of an integer `length` field, followed immediately (subject to alignment) by the
//! array payload of the specified length. For example, the `VBox<Array<u8>>` representation of `[10u8, 11, 12]` is:
)]
use crate::array_init::{ArrayInitializer, CloneFrom};
use crate::marker::ArrayMarker;
use crate::{impl_initializer_as_newtype, Initializer, Layout, VClone, VCopy, VarLen};
use core::pin::Pin;
use core::ptr::NonNull;
#[doc = crate::doc_macro::make_svgbobdoc!(
/// An variable-length array with inline storage.
///
/// This consists of an integer length field, followed immediately (subject to alignment) by the
/// array payload of the specified length. For example, the [`crate::VBox<Array<u8>>`] representation of `[10u8, 11, 12]` is:
)]
pub struct Array<T, Len: ArrayLen = usize> {
len: Len,
_array: ArrayMarker<T>,
}
#[derive(PartialEq, Eq)]
pub struct ArrayLayout {
array_offset: usize,
array_len: usize,
size: usize,
}
impl Layout for ArrayLayout {
#[inline(always)]
fn size(&self) -> usize {
self.size
}
}
unsafe impl<T, Len: ArrayLen> VarLen for Array<T, Len> {
type Layout = ArrayLayout;
#[inline(always)]
fn calculate_layout(&self) -> ArrayLayout {
let offset = core::mem::size_of::<Self>();
let (array_offset, array_len, size) =
crate::macro_support::cat_array_field_fast::<T>(self.len.as_usize(), offset);
ArrayLayout {
array_offset,
array_len,
size,
}
}
const ALIGN: usize = crate::macro_support::array_max(&[
core::mem::align_of::<Self>(),
core::mem::align_of::<T>(),
]);
const NEEDS_VDROP: bool = core::mem::needs_drop::<T>();
#[inline(always)]
unsafe fn vdrop(self: core::pin::Pin<&mut Self>, layout: Self::Layout) {
crate::macro_support::drop_array::<T>(
self.get_unchecked_mut() as *mut _ as *mut u8,
layout.array_offset,
layout.array_len,
);
}
}
impl<T, Len: ArrayLen> core::ops::Deref for Array<T, Len> {
type Target = [T];
fn deref(&self) -> &[T] {
let layout = self.calculate_layout();
unsafe { crate::macro_support::ref_array(self, layout.array_offset, layout.array_len) }
}
}
#[allow(rustdoc::missing_doc_code_examples)]
impl<T> Array<T> {
pub fn copy(src: &[T]) -> SizedInit<crate::array_init::CopyFrom<T>>
where
T: Copy,
{
Array::try_copy(src).unwrap()
}
pub fn clone_from_slice(src: &[T]) -> SizedInit<crate::array_init::CloneFrom<T>>
where
T: Clone,
{
Array::try_clone_from_slice(src).unwrap()
}
}
#[allow(rustdoc::missing_doc_code_examples)]
impl<T, Len: ArrayLen> Array<T, Len> {
#[inline]
pub fn len_short(&self) -> Len {
self.len
}
#[inline]
pub fn mut_slice(self: Pin<&mut Self>) -> &mut [T] {
let layout = self.calculate_layout();
unsafe {
crate::macro_support::mut_array(
self.get_unchecked_mut() as *mut _,
layout.array_offset,
layout.array_len,
)
}
}
#[inline]
pub fn try_copy(src: &[T]) -> Option<SizedInit<crate::array_init::CopyFrom<T>, Len>>
where
T: Copy,
{
let len = Len::from_usize(src.len())?;
Some(SizedInit(len, crate::array_init::CopyFrom(src)))
}
pub fn try_clone_from_slice(
src: &[T],
) -> Option<SizedInit<crate::array_init::CloneFrom<T>, Len>>
where
T: Clone,
{
let len = Len::from_usize(src.len())?;
Some(SizedInit(len, crate::array_init::CloneFrom(src)))
}
}
pub struct ArrayCloner<'a, T, Len: ArrayLen>(SizedInit<CloneFrom<'a, T>, Len>);
impl_initializer_as_newtype! {
impl<('a), (T: Clone), (Len: ArrayLen)> Initializer<Array<T, Len>> for ArrayCloner<'a, T, Len> { _ }
}
impl<'a, T: 'a + Clone, Len: ArrayLen> VClone<'a> for Array<T, Len> {
type Cloner = ArrayCloner<'a, T, Len>;
fn vclone(&'a self) -> Self::Cloner {
ArrayCloner(SizedInit(self.len_short(), CloneFrom(&self[..])))
}
}
unsafe impl<'a, T: 'a + Copy, Len: ArrayLen> VCopy<'a> for Array<T, Len> {}
pub struct SizedInit<Init, Len: ArrayLen = usize>(pub Len, pub Init);
unsafe impl<T, Len: ArrayLen, Init: ArrayInitializer<T>> Initializer<Array<T, Len>>
for SizedInit<Init, Len>
{
#[inline(always)]
fn calculate_layout_cautious(&self) -> Option<ArrayLayout> {
let offset = core::mem::size_of::<Array<T, Len>>();
let (array_offset, array_len, size) =
crate::macro_support::cat_array_field_cautious::<T>(self.0.as_usize(), offset)?;
Some(ArrayLayout {
array_offset,
array_len,
size,
})
}
unsafe fn initialize(self, dst: NonNull<Array<T, Len>>, layout: ArrayLayout) {
let header = Array {
len: self.0,
_array: crate::macro_support::init_array(
self.1,
dst.cast::<u8>(),
layout.array_offset,
layout.array_len,
),
};
core::ptr::write(dst.as_ptr(), header);
}
}
pub trait ArrayLen: 'static + Copy + private::Sealed {
fn as_usize(self) -> usize;
fn from_usize(x: usize) -> Option<Self>;
}
impl ArrayLen for usize {
#[inline(always)]
fn as_usize(self) -> usize {
self
}
#[inline(always)]
fn from_usize(x: usize) -> Option<Self> {
Some(x)
}
}
impl private::Sealed for usize {}
macro_rules! impl_arraylen {
($t:ty) => {
impl ArrayLen for $t {
#[inline(always)]
fn as_usize(self) -> usize {
self as usize
}
#[inline(always)]
fn from_usize(x: usize) -> Option<Self> {
Self::try_from(x).ok()
}
}
impl private::Sealed for $t {}
};
}
impl_arraylen!(u8);
impl_arraylen!(u16);
impl_arraylen!(u32);
impl_arraylen!(u64);
mod private {
pub trait Sealed {}
}