#![cfg_attr(feature = "allocator-api", feature(allocator_api))]
#![cfg_attr(feature = "dropck", feature(dropck_eyepatch))]
#![warn(missing_docs)]
#![no_std]
mod try_me;
mod guard;
#[cfg(feature = "serde")]
extern crate serde;
extern crate alloc;
use core::{
ptr::{self, NonNull},
fmt::{Debug, Formatter},
mem::{self, ManuallyDrop, MaybeUninit},
ops::{Deref, DerefMut, ControlFlow},
cmp::Ordering,
slice::{Iter, IterMut},
marker::PhantomData,
panic::{RefUnwindSafe, UnwindSafe},
alloc::Layout,
fmt
};
use alloc::{
boxed::Box,
vec::Vec,
alloc::{handle_alloc_error},
vec::IntoIter,
vec
};
#[cfg(feature = "allocator-api")]
use alloc::alloc::{Allocator, Global};
use core::slice::SliceIndex;
use core::ops::{Index, IndexMut};
use core::hash::{Hash, Hasher};
use likely_stable::unlikely;
use crate::guard::Guard;
use crate::try_me::{NeverShortCircuit, Try};
#[cfg(not(feature = "allocator-api"))]
pub struct HeapArray<T> {
ptr: NonNull<T>,
len: usize,
__marker: PhantomData<T>
}
#[cfg(feature = "allocator-api")]
pub struct HeapArray<T, #[cfg(feature = "allocator-api")] A: Allocator = Global> {
ptr: NonNull<T>,
len: usize,
#[cfg(feature = "allocator-api")]
alloc: ManuallyDrop<A>,
__marker: PhantomData<T>
}
macro_rules! assume {
($cond:expr $(,)?) => {
match cfg!(debug_assertions) {
true => assert!($cond, "bad assumption"),
false => if !$cond { core::hint::unreachable_unchecked() },
}
};
}
pub(crate) use assume;
macro_rules! try_from_fn_impl {
($T: ty, $R: ty, $len:expr, $f: expr $(, $alloc:ident)?) => {{
let len = $len;
if mem::size_of::<$T>() == 0 {
for i in 0..len {
unsafe { assume!(i < len) }
if let ControlFlow::Break(r) = $f(i).branch() {
return <$R>::from_residual(r)
}
}
let ret = 'scope: {
#[cfg(feature = "allocator-api")]
break 'scope (unsafe { Self::from_raw_parts_in(NonNull::dangling(), len, $($alloc)?) });
#[cfg(not(feature = "allocator-api"))]
break 'scope (unsafe { Self::from_raw_parts(NonNull::dangling(), len) });
};
return <$R>::from_element(ret);
}
let ptr: NonNull<MaybeUninit<$T>> = match alloc_uninit(len $(, &$alloc)?) {
Some(ptr) => ptr,
None => {
#[cfg(feature = "allocator-api")]
return <$R>::from_element(Self::new_in($($alloc)?));
#[cfg(not(feature = "allocator-api"))]
return <$R>::from_element(Self::new());
},
};
let mut guard = Guard {
ptr,
len,
$(alloc: $alloc,)?
initialized: 0
};
for i in 0..len {
unsafe { assume!(i < len) }
match $f(i).branch() {
ControlFlow::Continue(output) => unsafe { guard.push_unchecked(output) }
ControlFlow::Break(r) => { return <$R>::from_residual(r) }
}
}
<$R>::from_element(unsafe { guard.into_heap_array_unchecked() })
}};
}
macro_rules! from_array_impl {
($T:ty, $array:ident, $N:ident $(, $alloc:ident)?) => {{
if mem::size_of::<$T>() == 0 {
#[cfg(feature = "allocator-api")]
return unsafe { Self::from_raw_parts_in(NonNull::dangling(), $N, $($alloc)?) };
#[cfg(not(feature = "allocator-api"))]
return unsafe { Self::from_raw_parts(NonNull::dangling(), $N) };
}
let ptr: NonNull<MaybeUninit<$T>> = match alloc_uninit($N $(, &$alloc)?) {
Some(ptr) => ptr,
None => {
#[cfg(feature = "allocator-api")]
return Self::new_in($($alloc)?);
#[cfg(not(feature = "allocator-api"))]
return Self::new();
}
};
let array = ManuallyDrop::new($array);
unsafe { ptr::copy_nonoverlapping(array.as_ptr(), ptr.as_ptr() as *mut $T, $N) }
#[cfg(feature = "allocator-api")]
return unsafe { Self::from_raw_parts_in(ptr.cast(), $N, $($alloc)?) };
#[cfg(not(feature = "allocator-api"))]
return unsafe { Self::from_raw_parts(ptr.cast(), $N) };
}};
}
macro_rules! impl_heap_array_inner {
() => {};
($(#[$($meta_data:tt)*])* both $item:item $($rest:tt)*) => {
$(#[$($meta_data)*])*
$item
impl_heap_array_inner! {$($rest)*}
};
($(#[$($meta_data:tt)*])* allocator-api $item:item $($rest:tt)*) => {
#[cfg(feature = "allocator-api")]
$(#[$($meta_data)*])*
$item
impl_heap_array_inner! {$($rest)*}
};
($(#[$($meta_data:tt)*])* not(allocator-api) $item:item $($rest:tt)*) => {
#[cfg(not(feature = "allocator-api"))]
$(#[$($meta_data)*])*
$item
impl_heap_array_inner! {$($rest)*}
};
}
macro_rules! impl_heap_array {
(impl<$T:ident, Maybe<$A:ident>> HeapArray { $($rest:tt)* } ) => {
#[cfg(feature = "allocator-api")]
impl<$T, $A: Allocator> HeapArray<$T, $A> {
impl_heap_array_inner! {$($rest)*}
}
#[cfg(not(feature = "allocator-api"))]
impl<$T> HeapArray<$T> {
impl_heap_array_inner! {$($rest)*}
}
};
}
impl_heap_array! {
impl<T, Maybe<A>> HeapArray {
#[inline]
allocator-api pub const fn new_in(alloc: A) -> Self {
unsafe { Self::from_raw_parts_in(NonNull::<T>::dangling(), 0, alloc) }
}
#[inline]
both pub const fn is_empty(&self) -> bool { self.len == 0 }
#[inline]
both pub const fn len(&self) -> usize { self.len }
#[inline]
allocator-api pub fn allocator(&self) -> &A { &self.alloc }
#[inline(always)]
both pub fn as_mut_ptr(&mut self) -> *mut T {
self.ptr.as_ptr()
}
#[inline(always)]
both pub const fn as_ptr(&self) -> *const T {
self.ptr.as_ptr()
}
#[inline(always)]
both pub fn as_slice(&self) -> &[T] { self }
#[inline(always)]
both pub fn as_mut_slice(&mut self) -> &mut [T] { self }
allocator-api pub fn leak<'a>(self) -> &'a mut [T] where A: 'a {
let (ptr, len) = self.into_raw_parts();
unsafe { core::slice::from_raw_parts_mut(ptr.as_ptr(), len) }
}
#[inline]
not(allocator-api) pub fn leak<'a>(self) -> &'a mut [T] {
let (ptr, len) = self.into_raw_parts();
unsafe { core::slice::from_raw_parts_mut(ptr.as_ptr(), len) }
}
#[inline]
both pub fn into_raw_parts(self) -> (NonNull<T>, usize) {
let this = ManuallyDrop::new(self);
(this.ptr, this.len)
}
#[inline]
allocator-api pub fn into_raw_parts_with_alloc(self) -> (NonNull<T>, usize, A) {
let this = ManuallyDrop::new(self);
(this.ptr, this.len, unsafe { ptr::read(&*this.alloc) })
}
#[inline(always)]
allocator-api pub const unsafe fn from_raw_parts_in(ptr: NonNull<T>, len: usize, alloc: A) -> Self {
Self { ptr, len, __marker: PhantomData, alloc: ManuallyDrop::new(alloc) }
}
#[inline(always)]
not(allocator-api) pub const unsafe fn from_raw_parts(ptr: NonNull<T>, len: usize) -> Self {
Self { ptr, len, __marker: PhantomData }
}
#[inline]
allocator-api pub fn into_boxed_slice(self) -> Box<[T], A> {
let (ptr, len, alloc) = self.into_raw_parts_with_alloc();
let ptr = ptr::slice_from_raw_parts_mut(ptr.as_ptr(), len);
unsafe { Box::from_raw_in(ptr, alloc) }
}
#[inline]
not(allocator-api) pub fn into_boxed_slice(self) -> Box<[T]> {
let (ptr, len) = self.into_raw_parts();
let ptr = ptr::slice_from_raw_parts_mut(ptr.as_ptr(), len);
unsafe { Box::from_raw(ptr) }
}
#[inline]
allocator-api pub fn into_vec(self) -> Vec<T, A> {
self.into()
}
#[inline]
not(allocator-api) pub fn into_vec(self) -> Vec<T> {
self.into()
}
#[inline]
allocator-api pub fn from_fn_in(len: usize, f: impl FnMut(usize) -> T, alloc: A) -> Self {
Self::try_from_fn_in(len, NeverShortCircuit::wrap_fn(f), alloc)
}
allocator-api pub fn try_from_fn_in<R>(
len: usize,
mut f: impl FnMut(usize) -> R,
alloc: A
) -> R::TryType<Self> where R: Try<Output=T>
{ try_from_fn_impl!(T, R, len, f, alloc) }
#[inline]
allocator-api pub fn from_element_in(len: usize, element: T, alloc: A) -> Self
where T: Clone
{
vec::from_elem_in(element, len, alloc).into()
}
#[inline]
allocator-api pub fn from_slice_in(slice: &[T], alloc: A) -> HeapArray<T, A>
where T: Clone
{
<[T]>::to_vec_in(slice, alloc).into()
}
allocator-api pub fn from_array_in<const N: usize>(array: [T; N], alloc: A) -> HeapArray<T, A> {
from_array_impl!(T, array, N, alloc)
}
#[inline(always)]
not(allocator-api) pub const fn new() -> Self {
unsafe { HeapArray::from_raw_parts(NonNull::<T>::dangling(), 0) }
}
#[inline]
not(allocator-api) pub fn from_fn(len: usize, f: impl FnMut(usize) -> T) -> Self {
HeapArray::try_from_fn(len, NeverShortCircuit::wrap_fn(f))
}
not(allocator-api) pub fn try_from_fn<R>(len: usize, mut f: impl FnMut(usize) -> R) -> R::TryType<Self>
where R: Try<Output=T>
{
try_from_fn_impl!(T, R, len, f)
}
#[inline(always)]
not(allocator-api) pub fn from_element(len: usize, element: T) -> Self
where T: Clone
{
vec::from_elem(element, len).into()
}
#[inline(always)]
not(allocator-api) pub fn from_slice(slice: &[T]) -> Self
where T: Clone
{
<[T]>::to_vec(slice).into()
}
not(allocator-api) pub fn from_array<const N: usize>(array: [T; N]) -> Self {
from_array_impl!(T, array, N)
}
#[inline]
both pub(crate) unsafe fn drop_memory(&mut self) {
if self.len != 0 {
let size = mem::size_of::<T>().unchecked_mul(self.len);
let align = mem::align_of::<T>();
let layout = Layout::from_size_align_unchecked(size, align);
#[cfg(feature = "allocator-api")]
self.alloc.deallocate(self.ptr.cast(), layout);
#[cfg(not(feature = "allocator-api"))]
alloc::alloc::dealloc(self.ptr.as_ptr() as *mut u8, layout);
}
#[cfg(feature = "allocator-api")]
if mem::needs_drop::<A>() { unsafe { ManuallyDrop::drop(&mut self.alloc) } }
}
}
}
#[cfg(feature = "allocator-api")]
impl<T> HeapArray<T, Global> {
#[inline(always)]
pub fn from_slice(slice: &[T]) -> Self
where T: Clone
{ HeapArray::<T, Global>::from_slice_in(slice, Global) }
#[inline(always)]
pub fn from_element(len: usize, element: T) -> Self
where T: Clone
{ HeapArray::<T, Global>::from_element_in(len, element, Global) }
#[inline(always)]
pub fn from_array<const N: usize>(array: [T; N]) -> Self
{ HeapArray::<T, Global>::from_array_in(array, Global) }
#[inline(always)]
pub fn try_from_fn<R>(len: usize, f: impl FnMut(usize) -> R) -> R::TryType<Self>
where R: Try<Output=T>
{ HeapArray::<T, Global>::try_from_fn_in(len, f, Global) }
#[inline(always)]
pub fn from_fn(len: usize, f: impl FnMut(usize) -> T) -> Self {
HeapArray::<T, Global>::from_fn_in(len, f, Global)
}
#[inline(always)]
pub const fn new() -> Self {
HeapArray::<T, Global>::new_in(Global)
}
#[inline(always)]
pub const unsafe fn from_raw_parts(ptr: NonNull<T>, len: usize) -> HeapArray<T> {
HeapArray::<T, Global>::from_raw_parts_in(ptr, len, Global)
}
}
macro_rules! identical_impl {
() => { };
(
impl<$($time: lifetime, )? T $(: {$($t_restrict:tt)+})?, $({$($generics:tt)*},)? Maybe<A $(: {$( $($alloc_restrict:tt)+ )&+})?>> {$($Trait:tt)+} for HeapArray<T, Maybe<A>> $(where {$($restrict:tt)*})? {
$($r#impl:tt)*
}
$($rest:tt)*
) => {
#[cfg(not(feature = "allocator-api"))]
impl<$($time, )? T $(: $($t_restrict)+)?, $($($generics)*,)?> $($Trait)+ for HeapArray<T> $(where $($restrict)*)? {
$($r#impl)*
}
#[cfg(feature = "allocator-api")]
impl<$($time, )? T $(: $($t_restrict)+)?, $($($generics)*,)? A: Allocator $(+ $($($alloc_restrict)*)+)?> $($Trait)+ for HeapArray<T, A> $(where $($restrict)*)? {
$($r#impl)*
}
identical_impl! { $($rest)* }
};
(
impl<$($time: lifetime, )? T $(: {$($t_restrict:tt)+})?, $({$($generics:tt)*},)? Maybe<A $(: {$( $($alloc_restrict:tt)+ )&+})?>> {$($Trait:tt)+} for &$other_time:lifetime $(($mut:tt))? HeapArray<T, Maybe<A>> $(where {$($restrict:tt)*})? {
$($r#impl:tt)*
}
$($rest:tt)*
) => {
#[cfg(not(feature = "allocator-api"))]
impl<$($time, )? T $(: $($t_restrict)+)?, $($($generics)*,)?> $($Trait)+ for &$other_time $($mut)? HeapArray<T> $(where $($restrict)*)? {
$($r#impl)*
}
#[cfg(feature = "allocator-api")]
impl<$($time, )? T $(: $($t_restrict)+)?, $($($generics)*,)? A: Allocator $(+ $($($alloc_restrict)*)+)?> $($Trait)+ for &$other_time $($mut)? HeapArray<T, A> $(where $($restrict)*)? {
$($r#impl)*
}
identical_impl! { $($rest)* }
};
(
unsafe impl<$($time: lifetime, )? T $(: {$($t_restrict:tt)+})?, $({$($generics:tt)*},)? Maybe<A$(: {$( $($alloc_restrict:tt)+ )&+})?>> {$($Trait:tt)+} for HeapArray<T, Maybe<A>> $(where {$($restrict:tt)*})? {
$($r#impl:tt)*
}
$($rest:tt)*
) => {
#[cfg(not(feature = "allocator-api"))]
unsafe impl<$($time, )? T $(: $($t_restrict)+)?, $($($generics)*,)?> $($Trait)+ for HeapArray<T> $(where $($restrict)*)? {
$($r#impl)*
}
#[cfg(feature = "allocator-api")]
unsafe impl<$($time, )? T $(: $($t_restrict)+)?, $($($generics)*,)? A: Allocator $(+ $($($alloc_restrict)*)+)?> $($Trait)+ for HeapArray<T, A> $(where $($restrict)*)? {
$($r#impl)*
}
identical_impl! {$($rest)*}
};
}
impl<T> Default for HeapArray<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T: Clone> From<&[T]> for HeapArray<T> {
#[inline(always)]
fn from(slice: &[T]) -> Self { HeapArray::from_slice(slice) }
}
impl<T, const N: usize> From<[T; N]> for HeapArray<T> {
fn from(values: [T; N]) -> Self {
Self::from_array(values)
}
}
#[cfg(not(feature = "allocator-api"))]
impl<T> From<Box<[T]>> for HeapArray<T> {
#[inline]
fn from(value: Box<[T]>) -> Self {
let raw = Box::into_raw(value);
unsafe {
Self::from_raw_parts(NonNull::new_unchecked(raw.cast()), (*raw).len())
}
}
}
#[cfg(feature = "allocator-api")]
impl<T, A: Allocator> From<Box<[T], A>> for HeapArray<T, A> {
#[inline]
fn from(value: Box<[T], A>) -> Self {
let (parts, alloc) = Box::into_raw_with_allocator(value);
unsafe {
Self::from_raw_parts_in(NonNull::new_unchecked(parts.cast()), (*parts).len(), alloc)
}
}
}
#[cfg(not(feature = "allocator-api"))]
impl<T> From<Vec<T>> for HeapArray<T> {
#[inline]
fn from(value: Vec<T>) -> Self {
Self::from(value.into_boxed_slice())
}
}
#[cfg(feature = "allocator-api")]
impl<T, A: Allocator> From<Vec<T, A>> for HeapArray<T, A> {
#[inline]
fn from(value: Vec<T, A>) -> Self {
Self::from(value.into_boxed_slice())
}
}
impl<T> From<HeapArray<T>> for Box<[T]> {
#[inline]
fn from(value: HeapArray<T>) -> Self {
value.into_boxed_slice()
}
}
impl<T, const N: usize> TryFrom<HeapArray<T>> for Box<[T; N]> {
type Error = HeapArray<T>;
fn try_from(value: HeapArray<T>) -> Result<Self, Self::Error> {
if value.len != N {
Err(value)
} else {
let value = ManuallyDrop::new(value);
let ptr = value.ptr;
let ptr = ptr.as_ptr() as *mut [T; N];
Ok(unsafe { Box::from_raw(ptr) })
}
}
}
#[cfg(not(feature = "allocator-api"))]
impl<T> From<HeapArray<T>> for Vec<T> {
#[inline]
fn from(value: HeapArray<T>) -> Self {
let (ptr, len) = value.into_raw_parts();
unsafe { Vec::from_raw_parts(ptr.as_ptr(), len, len) }
}
}
#[cfg(feature = "allocator-api")]
impl<T, A: Allocator> From<HeapArray<T, A>> for Vec<T, A> {
#[inline]
fn from(value: HeapArray<T, A>) -> Self {
let (ptr, len, alloc) = value.into_raw_parts_with_alloc();
unsafe { Vec::from_raw_parts_in(ptr.as_ptr(), len, len, alloc) }
}
}
macro_rules! try_to_array_impl {
($T: ty, $N: expr, $value: ident) => {{
if $value.len != $N {
return Err($value)
}
let mut value = ManuallyDrop::new($value);
let data: [$T; $N] = unsafe { ptr::read(value.as_ptr() as *const [$T; $N]) };
unsafe { value.drop_memory() }
Ok(data)
}};
}
#[cfg(feature = "allocator-api")]
impl<T, A: Allocator, const N: usize> TryFrom<HeapArray<T, A>> for [T; N] {
type Error = HeapArray<T, A>;
fn try_from(value: HeapArray<T, A>) -> Result<[T; N], Self::Error> {
try_to_array_impl! (T, N, value)
}
}
#[cfg(not(feature = "allocator-api"))]
impl<T, const N: usize> TryFrom<HeapArray<T>> for [T; N] {
type Error = HeapArray<T>;
fn try_from(value: HeapArray<T>) -> Result<[T; N], Self::Error> {
try_to_array_impl! (T, N, value)
}
}
identical_impl! {
impl<T: {Clone}, Maybe<A: {Clone}>> {Clone} for HeapArray<T, Maybe<A>> {
fn clone(&self) -> Self {
#[cfg(not(feature = "allocator-api"))]
{HeapArray::from_slice(self)}
#[cfg(feature = "allocator-api")]
{HeapArray::from_slice_in(self, self.allocator().clone())}
}
}
}
identical_impl! {
impl<T: {Hash}, Maybe<A>> {Hash} for HeapArray<T, Maybe<A>> {
fn hash<H: Hasher>(&self, state: &mut H) {
<[T] as Hash>::hash(self.deref(), state)
}
}
impl<T, Maybe<A>> {Deref} for HeapArray<T, Maybe<A>> {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
}
impl<T, Maybe<A>> {DerefMut} for HeapArray<T, Maybe<A>> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
}
}
impl<T, Maybe<A>> {AsRef<[T]>} for HeapArray<T, Maybe<A>> {
fn as_ref(&self) -> &[T] { self }
}
impl<T, Maybe<A>> {AsMut<[T]>} for HeapArray<T, Maybe<A>> {
fn as_mut(&mut self) -> &mut [T] { self }
}
impl<T: {Debug}, Maybe<A>> {Debug} for HeapArray<T, Maybe<A>> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.deref().fmt(f) }
}
impl<T, {I: SliceIndex<[T]>}, Maybe<A>> {Index<I>} for HeapArray<T, Maybe<A>> {
type Output = I::Output;
fn index(&self, index: I) -> &Self::Output {
<[T] as Index<I>>::index(self.deref(), index)
}
}
impl<T, {I: SliceIndex<[T]>}, Maybe<A>> {IndexMut<I>} for HeapArray<T, Maybe<A>> {
fn index_mut(&mut self, index: I) -> &mut Self::Output {
<[T] as IndexMut<I>>::index_mut(self.deref_mut(), index)
}
}
}
macro_rules! impl_deref_comp_trait {
($trait_name: ident |> fn $fn_name:ident(&self, other: &Self) -> $t: ty) => {
identical_impl! {
impl<T: {$trait_name}, Maybe<A>> {$trait_name} for HeapArray<T, Maybe<A>> {
fn $fn_name(&self, other: &Self) -> $t { self.deref().$fn_name(other.deref()) }
}
}
};
}
impl_deref_comp_trait!(PartialEq |> fn eq(&self, other: &Self) -> bool);
impl_deref_comp_trait!(Ord |> fn cmp(&self, other: &Self) -> Ordering);
impl_deref_comp_trait!(PartialOrd |> fn partial_cmp(&self, other: &Self) -> Option<Ordering>);
identical_impl! {
impl<T: {Eq}, Maybe<A>> {Eq} for HeapArray<T, Maybe<A>> {}
}
macro_rules! drop_impl {
() => {
fn drop(&mut self) {
if mem::needs_drop::<T>() {
unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len)) };
}
unsafe { self.drop_memory() }
}
};
}
#[allow(missing_docs)]
#[cfg(all(feature = "dropck", feature = "allocator-api"))]
unsafe impl<#[may_dangle] T, A: Allocator> Drop for HeapArray<T, A> {
drop_impl! { }
}
#[allow(missing_docs)]
#[cfg(all(feature = "dropck", not(feature = "allocator-api")))]
unsafe impl<#[may_dangle] T> Drop for HeapArray<T> {
drop_impl! { }
}
#[allow(missing_docs)]
#[cfg(all(not(feature = "dropck"), feature = "allocator-api"))]
impl<T, A: Allocator> Drop for HeapArray<T, A> {
drop_impl! { }
}
#[allow(missing_docs)]
#[cfg(all(not(feature = "dropck"), not(feature = "allocator-api")))]
impl<T> Drop for HeapArray<T> {
drop_impl! { }
}
#[allow(unused)]
fn validate() {
#[allow(drop_bounds)]
fn check<T: Drop>() {};
check::<HeapArray<u8>>();
}
identical_impl! {
unsafe impl<T: {Send}, Maybe<A: {Send}>> {Send} for HeapArray<T, Maybe<A>> {}
unsafe impl<T: {Sync}, Maybe<A: {Sync}>> {Sync} for HeapArray<T, Maybe<A>> {}
impl<T: {Unpin}, Maybe<A: {Unpin}>> {Unpin} for HeapArray<T, Maybe<A>>{}
impl<T: {RefUnwindSafe}, Maybe<A: {RefUnwindSafe}>> {RefUnwindSafe} for HeapArray<T, Maybe<A>> {}
impl<T: {UnwindSafe}, Maybe<A: {UnwindSafe}>> {UnwindSafe} for HeapArray<T, Maybe<A>> {}
}
#[allow(missing_docs)]
impl<T> FromIterator<T> for HeapArray<T> {
fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> Self {
Vec::from_iter(iter).into()
}
}
#[cfg(feature = "allocator-api")]
#[allow(missing_docs)]
impl<T, A: Allocator> IntoIterator for HeapArray<T, A> {
type Item = T;
type IntoIter = IntoIter<Self::Item, A>;
fn into_iter(self) -> Self::IntoIter {
self.into_vec().into_iter()
}
}
#[cfg(not(feature = "allocator-api"))]
#[allow(missing_docs)]
impl<T> IntoIterator for HeapArray<T> {
type Item = T;
type IntoIter = IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.into_vec().into_iter()
}
}
identical_impl! {
impl<'a, T, Maybe<A>> {IntoIterator} for &'a HeapArray<T, Maybe<A>> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T, Maybe<A>> {IntoIterator} for &'a (mut) HeapArray<T, Maybe<A>> {
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
}
#[allow(missing_docs)]
#[doc(hidden)]
#[inline]
fn alloc_uninit<T, #[cfg(feature = "allocator-api")] A: Allocator>(
len: usize,
#[cfg(feature = "allocator-api")]
alloc: &A
) -> Option<NonNull<MaybeUninit<T>>>
{
if len == 0 {
return None
}
#[cold]
const fn capacity_overflow() -> ! {
panic!("capacity overflow")
}
let layout = match Layout::array::<T>(len) {
Ok(layout) => layout,
Err(_) => capacity_overflow(),
};
if usize::BITS < 64 && unlikely(layout.size() > isize::MAX as usize) {
capacity_overflow()
}
#[cfg(feature = "allocator-api")]
{
Some(match A::allocate(alloc, layout) {
Ok(ptr) => NonNull::<[u8]>::cast::<MaybeUninit<T>>(ptr),
Err(_) => handle_alloc_error(layout)
})
}
#[cfg(not(feature = "allocator-api"))]
{
Some(match NonNull::new(unsafe { alloc::alloc::alloc(layout) }) {
Some(ptr) => ptr.cast(),
None => handle_alloc_error(layout)
})
}
}
#[cfg(feature = "serde")]
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{SeqAccess, Visitor, Error, Expected},
};
#[cfg(feature = "serde")]
identical_impl! {
impl<T: {Serialize}, Maybe<A>> {Serialize} for HeapArray<T, Maybe<A>> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
serializer.collect_seq(self)
}
}
}
#[cfg(feature = "serde")]
impl<'a, T: Deserialize<'a>> HeapArray<T> {
pub fn from_sequence<A: SeqAccess<'a>>(mut sequence: A) -> Result<Self, A::Error> {
#[repr(transparent)]
struct ExpectedLen(usize);
impl Expected for ExpectedLen {
#[inline]
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a length of ")?;
fmt::Display::fmt(&self.0, formatter)
}
}
if let Some(len) = sequence.size_hint() {
HeapArray::try_from_fn(len, |i| sequence.next_element::<T>().and_then(|res| match res {
Some(out) => Ok(out),
None => Err(Error::invalid_length(i+1, &ExpectedLen(len)))
}))
} else {
let mut values = Vec::<T>::new();
while let Some(value) = sequence.next_element()? {
values.push(value);
}
Ok(HeapArray::from(values))
}
}
}
#[cfg(feature = "serde")]
impl<'de, T: Deserialize<'de>> Deserialize<'de> for HeapArray<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
struct HeapArrayVisitor<T> {
marker: PhantomData<T>,
}
impl<'a, T: Deserialize<'a>> Visitor<'a> for HeapArrayVisitor<T> {
type Value = HeapArray<T>;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a sequence")
}
#[inline(always)]
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
where A: SeqAccess<'a>,
{ HeapArray::from_sequence(seq) }
}
let visitor = HeapArrayVisitor {
marker: PhantomData
};
deserializer.deserialize_seq(visitor)
}
}
#[cfg(feature = "simd-json")]
use simd_json_derive::{Serialize as SimdSerialize, Deserialize as SimdDeserialize, Tape};
#[cfg(feature = "simd-json")]
extern crate std;
#[cfg(feature = "simd-json")]
identical_impl! {
impl<T: {SimdSerialize}, Maybe<A>> {SimdSerialize} for HeapArray<T, Maybe<A>> {
fn json_write<W>(&self, writer: &mut W) -> simd_json_derive::Result where W: std::io::Write {
let mut i = self.iter();
if let Some(first) = i.next() {
writer.write_all(b"[")?;
first.json_write(writer)?;
for e in i {
writer.write_all(b",")?;
e.json_write(writer)?;
}
writer.write_all(b"]")
} else {
writer.write_all(b"[]")
}
}
}
}
#[cfg(feature = "simd-json")]
impl<'input, T: SimdDeserialize<'input> + 'input> SimdDeserialize<'input> for HeapArray<T> {
fn from_tape(tape: &mut Tape<'input>) -> simd_json::Result<Self> {
if let Some(simd_json::Node::Array { len, .. }) = tape.next() {
HeapArray::try_from_fn(len, |_| T::from_tape(tape))
} else {
Err(simd_json::Error::generic(simd_json::ErrorType::ExpectedArray))
}
}
}
#[macro_export]
macro_rules! heap_array {
[] => { $crate::HeapArray::new() };
[$($x:expr),+] => { $crate::HeapArray::from([$($x),+]) };
[$elem:expr; 0] => {{$elem; $crate::HeapArray::new()}};
[$elem:expr; $n:expr] => { $crate::HeapArray::from_element($n, $elem) };
}