1use core::marker::Destruct;
2use core::mem::MaybeUninit;
3use core::ops;
4
5use super::ArrayVec;
6
7pub(crate) const fn write_filled_const<T: [const] Clone + [const] Destruct>(
8 slice: &mut [MaybeUninit<T>],
9 value: T,
10) {
11 if slice.is_empty() {
12 return;
13 }
14
15 konst::iter::for_each! { elem in konst::slice::get_up_to_mut(slice, slice.len().wrapping_sub(1)).unwrap() =>
18 elem.write(value.clone());
19 }
20 slice[slice.len().wrapping_sub(1)].write(value);
21}
22
23impl<const C: usize, T> const ops::Deref for ArrayVec<C, T> {
24 type Target = [T];
25
26 #[inline]
27 fn deref(&self) -> &Self::Target {
28 self.as_slice()
29 }
30}
31
32impl<const C: usize, T> const ops::DerefMut for ArrayVec<C, T> {
33 #[inline]
34 fn deref_mut(&mut self) -> &mut Self::Target {
35 self.as_slice_mut()
36 }
37}
38
39impl<const C: usize, T> const ops::Index<usize> for ArrayVec<C, T> {
40 type Output = T;
41
42 #[inline]
43 fn index(&self, index: usize) -> &Self::Output {
44 &self.as_slice()[index]
45 }
46}
47
48impl<const C: usize, T> const ops::IndexMut<usize> for ArrayVec<C, T> {
49 #[inline]
50 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
51 &mut self.as_slice_mut()[index]
52 }
53}
54impl<const C: usize, T> const Default for ArrayVec<C, T> {
55 #[inline]
56 fn default() -> Self {
57 Self::new()
58 }
59}
60
61impl<const C: usize, T: PartialEq> PartialEq for ArrayVec<C, T> {
62 #[inline]
63 default fn eq(&self, other: &ArrayVec<C, T>) -> bool {
64 self.len() == other.len() && self.as_slice().eq(other.as_slice())
65 }
66}
67
68impl<const C: usize, T: [const] PartialEq> const PartialEq for ArrayVec<C, T> {
69 #[inline]
70 fn eq(&self, other: &ArrayVec<C, T>) -> bool {
71 self.len() == other.len() && self.as_slice().eq(other.as_slice())
72 }
73}
74
75impl<const C: usize, T: [const] Eq> const Eq for ArrayVec<C, T> {}
76
77impl<const C: usize, T: PartialOrd> PartialOrd for ArrayVec<C, T> {
78 #[inline]
79 default fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
80 self.as_slice().partial_cmp(other.as_slice())
81 }
82}
83
84impl<const C: usize, T: [const] PartialOrd> const PartialOrd for ArrayVec<C, T> {
85 #[inline]
86 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
87 self.as_slice().partial_cmp(other.as_slice())
88 }
89}
90
91impl<const C: usize, T: Ord> Ord for ArrayVec<C, T> {
92 #[inline]
93 default fn cmp(&self, other: &Self) -> core::cmp::Ordering {
94 self.as_slice().cmp(other.as_slice())
95 }
96}
97
98impl<const C: usize, T: [const] Ord> const Ord for ArrayVec<C, T> {
99 #[inline]
100 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
101 self.as_slice().cmp(other.as_slice())
102 }
103}
104
105impl<const C: usize, T> ArrayVec<C, T> {
106 #[inline]
108 pub const fn from_slice_const(slice: &[T]) -> Option<Self>
109 where
110 T: const Clone, {
111 if slice.len() > C {
112 return None;
113 }
114
115 let mut array = konst::maybe_uninit::UNINIT_ARRAY::<T, C>::V;
116
117 konst::iter::for_each! {idx in 0..slice.len() =>
118 let item = slice[idx].clone();
119 array[idx] = MaybeUninit::new(item);
120 }
121
122 Some(Self {
123 array,
124 len: slice.len(),
125 })
126 }
127
128 #[inline]
130 pub const fn truncate_const(&mut self, len: usize)
131 where
132 T: [const] Destruct, {
133 if len >= self.len {
134 return;
135 }
136
137 unsafe { self.array[len..self.len].assume_init_drop() };
141 self.len = len;
142 }
143
144 #[inline]
152 pub const fn resize_const(&mut self, new_len: usize, value: T)
153 where
154 T: [const] Clone + [const] Destruct, {
155 assert!(new_len <= C, "Tried to resize beyond capacity.");
156
157 if new_len < self.len {
158 self.truncate_const(new_len);
159 } else if new_len > self.len {
160 write_filled_const(&mut self.array[self.len..new_len], value);
161 self.len = new_len;
162 }
163 }
164}
165
166#[cfg(test)]
167#[cfg_attr(coverage_nightly, coverage(off))]
168mod tests {
169
170 use super::*;
171 use proptest::prelude::*;
172
173 fn proptest_config() -> ProptestConfig {
174 ProptestConfig {
175 #[cfg(miri)]
176 failure_persistence: None,
177 #[cfg(miri)]
178 cases: 32,
179 ..ProptestConfig::default()
180 }
181 }
182
183 #[test]
184 fn const_partial_eq() {
185 static A: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 3]);
186 static B: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 3]);
187 static C: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 4]);
188
189 assert_eq!(A, B);
190 assert_ne!(A, C);
191 }
192
193 #[test]
194 fn const_ord() {
195 static A: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 3]);
196 static B: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 4]);
197 assert!(A < B);
198 }
199
200 #[test]
201 fn write_filled_const_empty() {
202 let mut vec: ArrayVec<0, ()> = ArrayVec::default();
203 write_filled_const(&mut vec.array, ());
204 assert!(vec.is_empty());
205 }
206
207 #[test]
208 fn from_slice_const() {
209 const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
210 let vec: ArrayVec<4, u32> = ArrayVec::<4, _>::from_slice_const(&EXPECTED).unwrap();
211 assert_eq!(vec.as_slice(), EXPECTED);
212 }
213
214 #[test]
215 fn from_slice_overflow() {
216 assert!(ArrayVec::<4, u32>::from_slice_const(&[1; 8]).is_none());
217 }
218
219 #[test]
220 fn truncate_const() {
221 let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
222
223 vec.truncate_const(2);
224 assert_eq!(vec.as_slice(), [1, 2]);
225 vec.push(0);
226 assert_eq!(vec.as_slice(), [1, 2, 0]);
227 vec.truncate_const(0);
228 assert_eq!(vec.as_slice(), []);
229 vec.truncate_const(0xcafebabe);
230 assert!(vec.is_empty());
231 }
232
233 #[test]
234 fn truncate_const_heap_types() {
235 let mut vec = ArrayVec::from_array([String::from("hey"), String::from("boy")]);
236
237 vec.truncate_const(1);
238 assert_eq!(vec.as_slice(), [String::from("hey")]);
239 core::mem::drop(vec);
240 }
241
242 #[test]
243 fn truncate_const_noop() {
244 let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
245
246 vec.truncate_const(4);
248 assert_eq!(vec.len(), 4);
249 vec.truncate_const(10);
250 assert_eq!(vec.len(), 4);
251 }
252
253 #[derive(Debug, Clone)]
254 enum Op {
255 Push(u8),
256 TryPush(u8),
257 Pop,
258 Insert(u8, usize),
259 TryInsert(u8, usize),
260 Truncate(usize),
261 Resize(usize, u8),
262 TruncateConst(usize),
263 ResizeConst(usize, u8),
264 }
265
266 fn arbatrary_op() -> impl Strategy<Value = Op> {
267 prop_oneof![
268 any::<u8>().prop_map(Op::Push),
269 any::<u8>().prop_map(Op::TryPush),
270 Just(Op::Pop),
271 (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::Insert(v, i)),
272 (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::TryInsert(v, i)),
273 any::<usize>().prop_map(Op::Truncate),
274 (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::Resize(i, v)),
275 any::<usize>().prop_map(Op::TruncateConst),
276 (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::ResizeConst(i, v)),
277 ]
278 }
279
280 fn model_try_push(v: &mut Vec<u8>, value: u8) -> Result<(), u8> {
281 if v.len() >= v.capacity() {
282 return Err(value);
283 }
284
285 v.push(value);
286 Ok(())
287 }
288
289 fn model_try_insert(v: &mut Vec<u8>, value: u8, idx: usize) -> Result<(), u8> {
290 if v.len() >= v.capacity() || idx > v.len() {
291 return Err(value);
292 }
293
294 v.insert(idx, value);
295 Ok(())
296 }
297
298 proptest! {
299 #![proptest_config(proptest_config())]
300 #[test]
301 fn model_based(ops in prop::collection::vec(arbatrary_op(), 0..50)) {
302 const C: usize = 8;
303 let mut vec: ArrayVec<C, u8> = ArrayVec::new();
304 let mut model: Vec<u8> = Vec::with_capacity(C);
305
306 for op in ops {
307 match op {
308 Op::Push(v) => {
309 if model.len() < C {
310 vec.push(v);
311 model.push(v);
312 }
313 }
314 Op::TryPush(x) => {
315 assert_eq!(vec.try_push(x), model_try_push(&mut model, x));
316 }
317 Op::Pop => {
318 assert_eq!(vec.pop(), model.pop());
319 }
320 Op::Insert(v, i) => {
321 if model.len() < C {
322 let idx = i % (model.len() + 1);
323 vec.insert(v, idx);
324 model.insert(idx, v);
325 }
326 }
327 Op::TryInsert(val, idx) => {
328 assert_eq!(
329 vec.try_insert(val, idx),
330 model_try_insert(&mut model, val, idx)
331 );
332 }
333 Op::Truncate(n) => {
334 let n = n % (C + 1);
335 vec.truncate(n);
336 model.truncate(n);
337 }
338 Op::Resize(n, x) => {
339 let n = n % (C + 1);
340 vec.resize(n, x);
341 model.resize(n,x);
342 }
343 Op::TruncateConst(n) => {
344 let n = n % (C + 1);
345 vec.truncate_const(n);
346 model.truncate(n);
347 }
348 Op::ResizeConst(n, x) => {
349 let n = n % (C + 1);
350 vec.resize_const(n, x);
351 model.resize(n,x);
352 }
353 }
354 assert_eq!(vec.as_slice(), model.as_slice());
355 assert!(vec.len() <= C);
356 }
357 }
358 }
359}