1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//! The generated `Vec` must drop its rows in forward (insertion) order, like
//! `Vec<T>`. Previously the custom `Drop` drained with `pop()`, dropping
//! last-in first. A `Tracker` records its id on drop into a shared log so the
//! order is observable.
use std::sync::{Arc, Mutex};
use layout::SOA;
struct Tracker {
id: u32,
log: Arc<Mutex<Vec<u32>>>,
}
impl Drop for Tracker {
fn drop(&mut self) {
if let Ok(mut g) = self.log.lock() {
g.push(self.id);
}
}
}
#[derive(SOA)]
struct Row {
tracker: Tracker,
}
#[test]
fn rows_drop_in_forward_order() {
let log = Arc::new(Mutex::new(Vec::new()));
{
let mut v = RowVec::new();
for i in 0..5_u32 {
v.push(Row {
tracker: Tracker {
id: i,
log: log.clone(),
},
});
}
// `v` drops here; rows must drop as 0, 1, 2, 3, 4 (forward order).
}
let recorded = log.lock().unwrap();
let expected: Vec<u32> = (0..5).collect();
assert_eq!(
*recorded, expected,
"rows should drop in insertion order like Vec<T>"
);
}
// A no-`Drop` row type must still drop cleanly via the `needs_drop` fast path.
#[derive(SOA)]
struct Plain {
a: u64,
b: u64,
}
#[test]
fn no_drop_type_drops_cleanly() {
let mut v = PlainVec::new();
for i in 0..1000 {
v.push(Plain { a: i, b: i * 2 });
}
drop(v);
// Reaching here without double-free / UB is the assertion.
}