use crate::arena::Arena; use rustc_serialize::{Encodable, Encoder}; use std::alloc::Layout; use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; use std::iter; use std::mem; use std::ops::Deref; use std::ptr; use std::slice; extern "C" { /// A dummy type used to force `List` to be unsized while not requiring references to it be wide /// pointers. type OpaqueListContents; } /// A wrapper for slices with the additional invariant /// that the slice is interned and no other slice with /// the same contents can exist in the same context. /// This means we can use pointer for both /// equality comparisons and hashing. /// /// Unlike slices, The types contained in `List` are expected to be `Copy` /// and iterating over a `List` returns `T` instead of a reference. /// /// Note: `Slice` was already taken by the `Ty`. #[repr(C)] pub struct List { len: usize, data: [T; 0], opaque: OpaqueListContents, } unsafe impl Sync for List {} impl List { #[inline] pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List { assert!(!mem::needs_drop::()); assert!(mem::size_of::() != 0); assert!(!slice.is_empty()); let (layout, _offset) = Layout::new::().extend(Layout::for_value::<[T]>(slice)).unwrap(); let mem = arena.dropless.alloc_raw(layout); unsafe { let result = &mut *(mem as *mut List); // Write the length result.len = slice.len(); // Write the elements let arena_slice = slice::from_raw_parts_mut(result.data.as_mut_ptr(), result.len); arena_slice.copy_from_slice(slice); result } } // If this method didn't exist, we would use `slice.iter` due to // deref coercion. // // This would be weird, as `self.into_iter` iterates over `T` directly. #[inline(always)] pub fn iter(&self) -> <&'_ List as IntoIterator>::IntoIter { self.into_iter() } } impl fmt::Debug for List { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl> Encodable for List { #[inline] fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } impl> Encodable for &List { #[inline] fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } impl Ord for List where T: Ord, { fn cmp(&self, other: &List) -> Ordering { if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) } } } impl PartialOrd for List where T: PartialOrd, { fn partial_cmp(&self, other: &List) -> Option { if self == other { Some(Ordering::Equal) } else { <[T] as PartialOrd>::partial_cmp(&**self, &**other) } } } impl PartialEq for List { #[inline] fn eq(&self, other: &List) -> bool { ptr::eq(self, other) } } impl Eq for List {} impl Hash for List { #[inline] fn hash(&self, s: &mut H) { (self as *const List).hash(s) } } impl Deref for List { type Target = [T]; #[inline(always)] fn deref(&self) -> &[T] { self.as_ref() } } impl AsRef<[T]> for List { #[inline(always)] fn as_ref(&self) -> &[T] { unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) } } } impl<'a, T: Copy> IntoIterator for &'a List { type Item = T; type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>; #[inline(always)] fn into_iter(self) -> Self::IntoIter { self[..].iter().copied() } } impl List { #[inline(always)] pub fn empty<'a>() -> &'a List { #[repr(align(64), C)] struct EmptySlice([u8; 64]); static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]); assert!(mem::align_of::() <= 64); unsafe { &*(&EMPTY_SLICE as *const _ as *const List) } } }