]> git.proxmox.com Git - rustc.git/blame - library/core/tests/array.rs
New upstream version 1.57.0+dfsg1
[rustc.git] / library / core / tests / array.rs
CommitLineData
17df50a5 1use core::array;
abe05a73 2use core::convert::TryFrom;
c295e0f8 3use core::sync::atomic::{AtomicUsize, Ordering};
e9174d1e 4
1b1a35ee
XL
5#[test]
6fn array_from_ref() {
7 let value: String = "Hello World!".into();
8 let arr: &[String; 1] = array::from_ref(&value);
9 assert_eq!(&[value.clone()], arr);
10}
11
12#[test]
13fn array_from_mut() {
14 let mut value: String = "Hello World".into();
15 let arr: &mut [String; 1] = array::from_mut(&mut value);
16 arr[0].push_str("!");
17 assert_eq!(&value, "Hello World!");
18}
19
abe05a73
XL
20#[test]
21fn array_try_from() {
22 macro_rules! test {
23 ($($N:expr)+) => {
24 $({
25 type Array = [u8; $N];
26 let array: Array = [0; $N];
27 let slice: &[u8] = &array[..];
28
29 let result = <&Array>::try_from(slice);
30 assert_eq!(&array, result.unwrap());
31 })+
32 }
33 }
34 test! {
35 0 1 2 3 4 5 6 7 8 9
36 10 11 12 13 14 15 16 17 18 19
37 20 21 22 23 24 25 26 27 28 29
38 30 31 32
39 }
40}
e74abb32 41
e74abb32
XL
42#[test]
43fn iterator_collect() {
44 let arr = [0, 1, 2, 5, 9];
17df50a5 45 let v: Vec<_> = IntoIterator::into_iter(arr.clone()).collect();
e74abb32
XL
46 assert_eq!(&arr[..], &v[..]);
47}
48
49#[test]
50fn iterator_rev_collect() {
51 let arr = [0, 1, 2, 5, 9];
17df50a5 52 let v: Vec<_> = IntoIterator::into_iter(arr.clone()).rev().collect();
e74abb32
XL
53 assert_eq!(&v[..], &[9, 5, 2, 1, 0]);
54}
55
56#[test]
57fn iterator_nth() {
58 let v = [0, 1, 2, 3, 4];
59 for i in 0..v.len() {
17df50a5 60 assert_eq!(IntoIterator::into_iter(v.clone()).nth(i).unwrap(), v[i]);
e74abb32 61 }
17df50a5 62 assert_eq!(IntoIterator::into_iter(v.clone()).nth(v.len()), None);
e74abb32 63
17df50a5 64 let mut iter = IntoIterator::into_iter(v);
e74abb32
XL
65 assert_eq!(iter.nth(2).unwrap(), v[2]);
66 assert_eq!(iter.nth(1).unwrap(), v[4]);
67}
68
69#[test]
70fn iterator_last() {
71 let v = [0, 1, 2, 3, 4];
17df50a5
XL
72 assert_eq!(IntoIterator::into_iter(v).last().unwrap(), 4);
73 assert_eq!(IntoIterator::into_iter([0]).last().unwrap(), 0);
e74abb32 74
17df50a5 75 let mut it = IntoIterator::into_iter([0, 9, 2, 4]);
e74abb32
XL
76 assert_eq!(it.next_back(), Some(4));
77 assert_eq!(it.last(), Some(2));
78}
79
80#[test]
81fn iterator_clone() {
17df50a5 82 let mut it = IntoIterator::into_iter([0, 2, 4, 6, 8]);
e74abb32
XL
83 assert_eq!(it.next(), Some(0));
84 assert_eq!(it.next_back(), Some(8));
85 let mut clone = it.clone();
86 assert_eq!(it.next_back(), Some(6));
87 assert_eq!(clone.next_back(), Some(6));
88 assert_eq!(it.next_back(), Some(4));
89 assert_eq!(clone.next_back(), Some(4));
90 assert_eq!(it.next(), Some(2));
91 assert_eq!(clone.next(), Some(2));
92}
93
94#[test]
95fn iterator_fused() {
17df50a5 96 let mut it = IntoIterator::into_iter([0, 9, 2]);
e74abb32
XL
97 assert_eq!(it.next(), Some(0));
98 assert_eq!(it.next(), Some(9));
99 assert_eq!(it.next(), Some(2));
100 assert_eq!(it.next(), None);
101 assert_eq!(it.next(), None);
102 assert_eq!(it.next(), None);
103 assert_eq!(it.next(), None);
104 assert_eq!(it.next(), None);
105}
106
107#[test]
108fn iterator_len() {
17df50a5 109 let mut it = IntoIterator::into_iter([0, 1, 2, 5, 9]);
e74abb32
XL
110 assert_eq!(it.size_hint(), (5, Some(5)));
111 assert_eq!(it.len(), 5);
112 assert_eq!(it.is_empty(), false);
113
114 assert_eq!(it.next(), Some(0));
115 assert_eq!(it.size_hint(), (4, Some(4)));
116 assert_eq!(it.len(), 4);
117 assert_eq!(it.is_empty(), false);
118
119 assert_eq!(it.next_back(), Some(9));
120 assert_eq!(it.size_hint(), (3, Some(3)));
121 assert_eq!(it.len(), 3);
122 assert_eq!(it.is_empty(), false);
123
124 // Empty
17df50a5 125 let it = IntoIterator::into_iter([] as [String; 0]);
e74abb32
XL
126 assert_eq!(it.size_hint(), (0, Some(0)));
127 assert_eq!(it.len(), 0);
128 assert_eq!(it.is_empty(), true);
129}
130
131#[test]
132fn iterator_count() {
133 let v = [0, 1, 2, 3, 4];
17df50a5 134 assert_eq!(IntoIterator::into_iter(v.clone()).count(), 5);
e74abb32 135
17df50a5 136 let mut iter2 = IntoIterator::into_iter(v);
e74abb32
XL
137 iter2.next();
138 iter2.next();
139 assert_eq!(iter2.count(), 3);
140}
141
142#[test]
143fn iterator_flat_map() {
17df50a5 144 assert!((0..5).flat_map(|i| IntoIterator::into_iter([2 * i, 2 * i + 1])).eq(0..10));
e74abb32
XL
145}
146
147#[test]
148fn iterator_debug() {
149 let arr = [0, 1, 2, 5, 9];
17df50a5 150 assert_eq!(format!("{:?}", IntoIterator::into_iter(arr)), "IntoIter([0, 1, 2, 5, 9])",);
e74abb32
XL
151}
152
153#[test]
154fn iterator_drops() {
155 use core::cell::Cell;
156
157 // This test makes sure the correct number of elements are dropped. The `R`
158 // type is just a reference to a `Cell` that is incremented when an `R` is
159 // dropped.
160
161 #[derive(Clone)]
162 struct Foo<'a>(&'a Cell<usize>);
163
164 impl Drop for Foo<'_> {
60c5eb7d 165 fn drop(&mut self) {
e74abb32
XL
166 self.0.set(self.0.get() + 1);
167 }
168 }
169
170 fn five(i: &Cell<usize>) -> [Foo<'_>; 5] {
171 // This is somewhat verbose because `Foo` does not implement `Copy`
172 // since it implements `Drop`. Consequently, we cannot write
173 // `[Foo(i); 5]`.
174 [Foo(i), Foo(i), Foo(i), Foo(i), Foo(i)]
175 }
176
177 // Simple: drop new iterator.
178 let i = Cell::new(0);
179 {
17df50a5 180 IntoIterator::into_iter(five(&i));
e74abb32
XL
181 }
182 assert_eq!(i.get(), 5);
183
184 // Call `next()` once.
185 let i = Cell::new(0);
186 {
17df50a5 187 let mut iter = IntoIterator::into_iter(five(&i));
e74abb32
XL
188 let _x = iter.next();
189 assert_eq!(i.get(), 0);
190 assert_eq!(iter.count(), 4);
191 assert_eq!(i.get(), 4);
192 }
193 assert_eq!(i.get(), 5);
194
195 // Check `clone` and calling `next`/`next_back`.
196 let i = Cell::new(0);
197 {
17df50a5 198 let mut iter = IntoIterator::into_iter(five(&i));
e74abb32
XL
199 iter.next();
200 assert_eq!(i.get(), 1);
201 iter.next_back();
202 assert_eq!(i.get(), 2);
203
204 let mut clone = iter.clone();
205 assert_eq!(i.get(), 2);
206
207 iter.next();
208 assert_eq!(i.get(), 3);
209
210 clone.next();
211 assert_eq!(i.get(), 4);
212
213 assert_eq!(clone.count(), 2);
214 assert_eq!(i.get(), 6);
215 }
216 assert_eq!(i.get(), 8);
217
218 // Check via `nth`.
219 let i = Cell::new(0);
220 {
17df50a5 221 let mut iter = IntoIterator::into_iter(five(&i));
e74abb32
XL
222 let _x = iter.nth(2);
223 assert_eq!(i.get(), 2);
224 let _y = iter.last();
225 assert_eq!(i.get(), 3);
226 }
227 assert_eq!(i.get(), 5);
228
229 // Check every element.
230 let i = Cell::new(0);
17df50a5 231 for (index, _x) in IntoIterator::into_iter(five(&i)).enumerate() {
e74abb32
XL
232 assert_eq!(i.get(), index);
233 }
234 assert_eq!(i.get(), 5);
235
236 let i = Cell::new(0);
17df50a5 237 for (index, _x) in IntoIterator::into_iter(five(&i)).rev().enumerate() {
e74abb32
XL
238 assert_eq!(i.get(), index);
239 }
240 assert_eq!(i.get(), 5);
241}
f035d41b
XL
242
243// This test does not work on targets without panic=unwind support.
244// To work around this problem, test is marked is should_panic, so it will
245// be automagically skipped on unsuitable targets, such as
246// wasm32-unknown-unkown.
247//
248// It means that we use panic for indicating success.
249#[test]
250#[should_panic(expected = "test succeeded")]
251fn array_default_impl_avoids_leaks_on_panic() {
252 use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
253 static COUNTER: AtomicUsize = AtomicUsize::new(0);
254 #[derive(Debug)]
255 struct Bomb(usize);
256
257 impl Default for Bomb {
258 fn default() -> Bomb {
259 if COUNTER.load(Relaxed) == 3 {
260 panic!("bomb limit exceeded");
261 }
262
263 COUNTER.fetch_add(1, Relaxed);
264 Bomb(COUNTER.load(Relaxed))
265 }
266 }
267
268 impl Drop for Bomb {
269 fn drop(&mut self) {
270 COUNTER.fetch_sub(1, Relaxed);
271 }
272 }
273
274 let res = std::panic::catch_unwind(|| <[Bomb; 5]>::default());
275 let panic_msg = match res {
276 Ok(_) => unreachable!(),
277 Err(p) => p.downcast::<&'static str>().unwrap(),
278 };
279 assert_eq!(*panic_msg, "bomb limit exceeded");
280 // check that all bombs are successfully dropped
281 assert_eq!(COUNTER.load(Relaxed), 0);
282 panic!("test succeeded")
283}
284
285#[test]
286fn empty_array_is_always_default() {
287 struct DoesNotImplDefault;
288
289 let _arr = <[DoesNotImplDefault; 0]>::default();
290}
3dfed10e
XL
291
292#[test]
293fn array_map() {
294 let a = [1, 2, 3];
295 let b = a.map(|v| v + 1);
296 assert_eq!(b, [2, 3, 4]);
297
298 let a = [1u8, 2, 3];
299 let b = a.map(|v| v as u64);
300 assert_eq!(b, [1, 2, 3]);
301}
302
303// See note on above test for why `should_panic` is used.
304#[test]
305#[should_panic(expected = "test succeeded")]
306fn array_map_drop_safety() {
3dfed10e
XL
307 static DROPPED: AtomicUsize = AtomicUsize::new(0);
308 struct DropCounter;
309 impl Drop for DropCounter {
310 fn drop(&mut self) {
311 DROPPED.fetch_add(1, Ordering::SeqCst);
312 }
313 }
314
315 let num_to_create = 5;
316 let success = std::panic::catch_unwind(|| {
317 let items = [0; 10];
318 let mut nth = 0;
319 items.map(|_| {
320 assert!(nth < num_to_create);
321 nth += 1;
322 DropCounter
323 });
324 });
325 assert!(success.is_err());
326 assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
327 panic!("test succeeded")
328}
1b1a35ee
XL
329
330#[test]
331fn cell_allows_array_cycle() {
332 use core::cell::Cell;
333
334 #[derive(Debug)]
335 struct B<'a> {
336 a: [Cell<Option<&'a B<'a>>>; 2],
337 }
338
339 impl<'a> B<'a> {
340 fn new() -> B<'a> {
341 B { a: [Cell::new(None), Cell::new(None)] }
342 }
343 }
344
345 let b1 = B::new();
346 let b2 = B::new();
347 let b3 = B::new();
348
349 b1.a[0].set(Some(&b2));
350 b1.a[1].set(Some(&b3));
351
352 b2.a[0].set(Some(&b2));
353 b2.a[1].set(Some(&b3));
354
355 b3.a[0].set(Some(&b1));
356 b3.a[1].set(Some(&b2));
357}
c295e0f8
XL
358
359#[test]
360fn array_from_fn() {
361 let array = core::array::from_fn(|idx| idx);
362 assert_eq!(array, [0, 1, 2, 3, 4]);
363}
364
365#[test]
366fn array_try_from_fn() {
367 #[derive(Debug, PartialEq)]
368 enum SomeError {
369 Foo,
370 }
371
372 let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
373 assert_eq!(array, Ok([0, 1, 2, 3, 4]));
374
375 let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
376 assert_eq!(another_array, Err(SomeError::Foo));
377}
378
379#[cfg(not(panic = "abort"))]
380#[test]
381fn array_try_from_fn_drops_inserted_elements_on_err() {
382 static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
383
384 struct CountDrop;
385 impl Drop for CountDrop {
386 fn drop(&mut self) {
387 DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
388 }
389 }
390
391 let _ = catch_unwind_silent(move || {
392 let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| {
393 if idx == 2 {
394 return Err(());
395 }
396 Ok(CountDrop)
397 });
398 });
399
400 assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2);
401}
402
403#[cfg(not(panic = "abort"))]
404#[test]
405fn array_try_from_fn_drops_inserted_elements_on_panic() {
406 static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
407
408 struct CountDrop;
409 impl Drop for CountDrop {
410 fn drop(&mut self) {
411 DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
412 }
413 }
414
415 let _ = catch_unwind_silent(move || {
416 let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| {
417 if idx == 2 {
418 panic!("peek a boo");
419 }
420 Ok(CountDrop)
421 });
422 });
423
424 assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2);
425}
426
427#[cfg(not(panic = "abort"))]
428// https://stackoverflow.com/a/59211505
429fn catch_unwind_silent<F, R>(f: F) -> std::thread::Result<R>
430where
431 F: FnOnce() -> R + core::panic::UnwindSafe,
432{
433 let prev_hook = std::panic::take_hook();
434 std::panic::set_hook(Box::new(|_| {}));
435 let result = std::panic::catch_unwind(f);
436 std::panic::set_hook(prev_hook);
437 result
438}