]> git.lizzy.rs Git - rust.git/blob - src/librustc_middle/ty/list.rs
Auto merge of #75560 - Mark-Simulacrum:rustc-docs, r=matthiaskrgr
[rust.git] / src / librustc_middle / ty / list.rs
1 use crate::arena::Arena;
2
3 use rustc_serialize::{Encodable, Encoder};
4
5 use std::alloc::Layout;
6 use std::cmp::Ordering;
7 use std::fmt;
8 use std::hash::{Hash, Hasher};
9 use std::iter;
10 use std::mem;
11 use std::ops::Deref;
12 use std::ptr;
13 use std::slice;
14
15 extern "C" {
16     /// A dummy type used to force `List` to be unsized while not requiring references to it be wide
17     /// pointers.
18     type OpaqueListContents;
19 }
20
21 /// A wrapper for slices with the additional invariant
22 /// that the slice is interned and no other slice with
23 /// the same contents can exist in the same context.
24 /// This means we can use pointer for both
25 /// equality comparisons and hashing.
26 ///
27 /// Unlike slices, The types contained in `List` are expected to be `Copy`
28 /// and iterating over a `List` returns `T` instead of a reference.
29 ///
30 /// Note: `Slice` was already taken by the `Ty`.
31 #[repr(C)]
32 pub struct List<T> {
33     len: usize,
34     data: [T; 0],
35     opaque: OpaqueListContents,
36 }
37
38 unsafe impl<T: Sync> Sync for List<T> {}
39
40 impl<T: Copy> List<T> {
41     #[inline]
42     pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> {
43         assert!(!mem::needs_drop::<T>());
44         assert!(mem::size_of::<T>() != 0);
45         assert!(!slice.is_empty());
46
47         let (layout, _offset) =
48             Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap();
49         let mem = arena.dropless.alloc_raw(layout);
50         unsafe {
51             let result = &mut *(mem as *mut List<T>);
52             // Write the length
53             result.len = slice.len();
54
55             // Write the elements
56             let arena_slice = slice::from_raw_parts_mut(result.data.as_mut_ptr(), result.len);
57             arena_slice.copy_from_slice(slice);
58
59             result
60         }
61     }
62
63     // If this method didn't exist, we would use `slice.iter` due to
64     // deref coercion.
65     //
66     // This would be weird, as `self.into_iter` iterates over `T` directly.
67     #[inline(always)]
68     pub fn iter(&self) -> <&'_ List<T> as IntoIterator>::IntoIter {
69         self.into_iter()
70     }
71 }
72
73 impl<T: fmt::Debug> fmt::Debug for List<T> {
74     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75         (**self).fmt(f)
76     }
77 }
78
79 impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> {
80     #[inline]
81     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
82         (**self).encode(s)
83     }
84 }
85
86 impl<S: Encoder, T: Encodable<S>> Encodable<S> for &List<T> {
87     #[inline]
88     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
89         (**self).encode(s)
90     }
91 }
92
93 impl<T> Ord for List<T>
94 where
95     T: Ord,
96 {
97     fn cmp(&self, other: &List<T>) -> Ordering {
98         if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) }
99     }
100 }
101
102 impl<T> PartialOrd for List<T>
103 where
104     T: PartialOrd,
105 {
106     fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> {
107         if self == other {
108             Some(Ordering::Equal)
109         } else {
110             <[T] as PartialOrd>::partial_cmp(&**self, &**other)
111         }
112     }
113 }
114
115 impl<T: PartialEq> PartialEq for List<T> {
116     #[inline]
117     fn eq(&self, other: &List<T>) -> bool {
118         ptr::eq(self, other)
119     }
120 }
121 impl<T: Eq> Eq for List<T> {}
122
123 impl<T> Hash for List<T> {
124     #[inline]
125     fn hash<H: Hasher>(&self, s: &mut H) {
126         (self as *const List<T>).hash(s)
127     }
128 }
129
130 impl<T> Deref for List<T> {
131     type Target = [T];
132     #[inline(always)]
133     fn deref(&self) -> &[T] {
134         self.as_ref()
135     }
136 }
137
138 impl<T> AsRef<[T]> for List<T> {
139     #[inline(always)]
140     fn as_ref(&self) -> &[T] {
141         unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
142     }
143 }
144
145 impl<'a, T: Copy> IntoIterator for &'a List<T> {
146     type Item = T;
147     type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>;
148     #[inline(always)]
149     fn into_iter(self) -> Self::IntoIter {
150         self[..].iter().copied()
151     }
152 }
153
154 impl<T> List<T> {
155     #[inline(always)]
156     pub fn empty<'a>() -> &'a List<T> {
157         #[repr(align(64), C)]
158         struct EmptySlice([u8; 64]);
159         static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]);
160         assert!(mem::align_of::<T>() <= 64);
161         unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
162     }
163 }