use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use core::alloc::Layout;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ops::Deref;
use core::{fmt, iter, mem, ptr, slice};
use crate::rustc_serialize::{Encodable, Encoder};
use crate::rustc_type_ir::FlagComputation;
use super::{DebruijnIndex, TyCtxt, TypeFlags};
use crate::rustc_middle::arena::Arena;
pub type List<T> = RawList<(), T>;
#[repr(C)]
pub struct RawList<H, T> {
skel: ListSkeleton<H, T>,
_not_send: PhantomData<*const ()>,
}
#[repr(C)]
struct ListSkeleton<H, T> {
header: H,
len: usize,
data: [T; 0],
}
impl<T> Default for &List<T> {
fn default() -> Self {
List::empty()
}
}
impl<H, T> RawList<H, T> {
#[inline(always)]
pub fn len(&self) -> usize {
self.skel.len
}
#[inline(always)]
pub fn as_slice(&self) -> &[T] {
self
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.as_slice().is_empty()
}
#[inline(always)]
pub fn get<I>(&self, index: I) -> Option<&I::Output>
where
I: core::slice::SliceIndex<[T]>,
{
self.as_slice().get(index)
}
#[inline(always)]
pub fn first(&self) -> Option<&T> {
self.as_slice().first()
}
#[inline(always)]
pub fn last(&self) -> Option<&T> {
self.as_slice().last()
}
#[inline(always)]
pub fn split_first(&self) -> Option<(&T, &[T])> {
self.as_slice().split_first()
}
#[inline(always)]
pub fn split_last(&self) -> Option<(&T, &[T])> {
self.as_slice().split_last()
}
#[inline(always)]
pub fn contains(&self, x: &T) -> bool
where
T: PartialEq,
{
self.as_slice().contains(x)
}
#[inline(always)]
pub fn to_vec(&self) -> Vec<T>
where
T: Clone,
{
self.as_slice().to_vec()
}
#[inline]
pub(super) fn from_arena<'tcx>(
arena: &'tcx Arena<'tcx>,
header: H,
slice: &[T],
) -> &'tcx RawList<H, T>
where
T: Copy,
{
assert!(!mem::needs_drop::<T>());
assert!(size_of::<T>() != 0);
assert!(!slice.is_empty());
let (layout, _offset) =
Layout::new::<ListSkeleton<H, T>>().extend(Layout::for_value::<[T]>(slice)).unwrap();
let mem = arena.dropless.alloc_raw(layout) as *mut RawList<H, T>;
unsafe {
(&raw mut (*mem).skel.header).write(header);
(&raw mut (*mem).skel.len).write(slice.len());
(&raw mut (*mem).skel.data)
.cast::<T>()
.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
&*mem
}
}
#[inline(always)]
pub fn iter(&self) -> <&'_ RawList<H, T> as IntoIterator>::IntoIter
where
T: Copy,
{
self.into_iter()
}
}
impl<'a, H, T: Copy> crate::rustc_type_ir::inherent::SliceLike for &'a RawList<H, T> {
type Item = T;
type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>;
fn iter(self) -> Self::IntoIter {
(*self).iter()
}
fn as_slice(&self) -> &[Self::Item] {
(*self).as_slice()
}
}
impl<'tcx> crate::rustc_type_ir::inherent::BoundVarKinds<TyCtxt<'tcx>>
for &'tcx RawList<(), crate::rustc_middle::ty::BoundVariableKind<'tcx>>
{
fn from_vars(
tcx: TyCtxt<'tcx>,
iter: impl IntoIterator<Item = crate::rustc_middle::ty::BoundVariableKind<'tcx>>,
) -> Self {
tcx.mk_bound_variable_kinds_from_iter(iter.into_iter())
}
}
macro_rules! impl_list_empty {
($header_ty:ty, $header_init:expr) => {
impl<T> RawList<$header_ty, T> {
#[inline(always)]
pub fn empty<'a>() -> &'a RawList<$header_ty, T> {
#[repr(align(64))]
struct MaxAlign;
static EMPTY: ListSkeleton<$header_ty, MaxAlign> =
ListSkeleton { header: $header_init, len: 0, data: [] };
assert!(core::mem::align_of::<T>() <= core::mem::align_of::<MaxAlign>());
unsafe { &*((&raw const EMPTY) as *const RawList<$header_ty, T>) }
}
}
};
}
impl_list_empty!((), ());
impl<H, T: fmt::Debug> fmt::Debug for RawList<H, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<H, S: Encoder, T: Encodable<S>> Encodable<S> for RawList<H, T> {
#[inline]
fn encode(&self, s: &mut S) {
(**self).encode(s);
}
}
impl<H, T: PartialEq> PartialEq for RawList<H, T> {
#[inline]
fn eq(&self, other: &RawList<H, T>) -> bool {
ptr::eq(self, other)
}
}
impl<H, T: Eq> Eq for RawList<H, T> {}
impl<H, T> Ord for RawList<H, T>
where
T: Ord,
{
fn cmp(&self, other: &RawList<H, T>) -> Ordering {
if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) }
}
}
impl<H, T> PartialOrd for RawList<H, T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &RawList<H, T>) -> Option<Ordering> {
if self == other {
Some(Ordering::Equal)
} else {
<[T] as PartialOrd>::partial_cmp(&**self, &**other)
}
}
}
impl<Hdr, T> Hash for RawList<Hdr, T> {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
ptr::from_ref(self).hash(s)
}
}
impl<H, T> Deref for RawList<H, T> {
type Target = [T];
#[inline(always)]
fn deref(&self) -> &[T] {
self.as_ref()
}
}
impl<H, T> AsRef<[T]> for RawList<H, T> {
#[inline(always)]
fn as_ref(&self) -> &[T] {
let data_ptr = (&raw const self.skel.data).cast::<T>();
unsafe { slice::from_raw_parts(data_ptr, self.skel.len) }
}
}
impl<'a, H, T: Copy> IntoIterator for &'a RawList<H, T> {
type Item = T;
type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self[..].iter().copied()
}
}
unsafe impl<H: Sync, T: Sync> Sync for RawList<H, T> {}
pub type ListWithCachedTypeInfo<T> = RawList<TypeInfo, T>;
impl<T> ListWithCachedTypeInfo<T> {
#[inline(always)]
pub fn flags(&self) -> TypeFlags {
self.skel.header.flags
}
#[inline(always)]
pub fn outer_exclusive_binder(&self) -> DebruijnIndex {
self.skel.header.outer_exclusive_binder
}
}
impl_list_empty!(TypeInfo, TypeInfo::empty());
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TypeInfo {
flags: TypeFlags,
outer_exclusive_binder: DebruijnIndex,
}
impl TypeInfo {
const fn empty() -> Self {
Self { flags: TypeFlags::empty(), outer_exclusive_binder: super::INNERMOST }
}
}
impl<'tcx> From<FlagComputation<TyCtxt<'tcx>>> for TypeInfo {
fn from(computation: FlagComputation<TyCtxt<'tcx>>) -> TypeInfo {
TypeInfo {
flags: computation.flags,
outer_exclusive_binder: computation.outer_exclusive_binder,
}
}
}
#[cfg(target_pointer_width = "64")]
mod size_asserts {
use crate::static_assert_size;
use super::*;
static_assert_size!(&List<u32>, 8); static_assert_size!(&RawList<u8, u32>, 8); }