1
use std::cell::Cell;
2
use std::marker::PhantomData;
3
use std::ptr::NonNull;
4

            
5
/// Intrusive node requirements for use in [`FreeList`].
6
///
7
/// # Safety
8
///
9
/// Implementors must guarantee that `get_next` and `set_next` read and write
10
/// the same link field, and that the field is valid for all nodes managed by
11
/// a corresponding freelist.
12
pub unsafe trait FreeListEntry: Sized {
13
    /// Returns the next pointer for `ptr` (or null).
14
    ///
15
    /// # Safety
16
    ///
17
    /// `ptr` must be a valid pointer to a node managed by the corresponding
18
    /// freelist.
19
    unsafe fn get_next(ptr: *mut Self) -> *mut Self;
20

            
21
    /// Sets the next pointer for `ptr`.
22
    ///
23
    /// # Safety
24
    ///
25
    /// `ptr` must be a valid pointer to a node managed by the corresponding
26
    /// freelist, and `next` must be either null or a valid pointer to a node
27
    /// managed by the same freelist.
28
    unsafe fn set_next(ptr: *mut Self, next: *mut Self);
29
}
30

            
31
/// Intrusive freelist based on a stack.
32
pub struct FreeList<T: FreeListEntry> {
33
    /// The head of the freelist. Null means empty.
34
    head: Cell<*mut T>,
35

            
36
    /// We implement Send and Sync manually.
37
    _marker: PhantomData<*mut T>,
38
}
39

            
40
// Safety: Transferring a FreeList to another thread is safe if T is Send.
41
unsafe impl<T: FreeListEntry + Send> Send for FreeList<T> {}
42

            
43
impl<T: FreeListEntry> Default for FreeList<T> {
44
    fn default() -> Self {
45
        Self::new()
46
    }
47
}
48

            
49
impl<T: FreeListEntry> FreeList<T> {
50
8680
    pub fn new() -> Self {
51
8680
        Self {
52
8680
            head: Cell::new(std::ptr::null_mut()),
53
8680
            _marker: PhantomData,
54
8680
        }
55
8680
    }
56

            
57
    /// Pops one entry from the freelist.
58
    ///
59
    /// Relies on the freelist invariant that every node on the list is valid, which is
60
    /// guaranteed by the contracts of [`FreeList::push`] and [`FreeList::set_head`].
61
20727192
    pub fn try_pop(&self) -> Option<NonNull<T>> {
62
20727192
        let node = NonNull::new(self.head.get())?;
63

            
64
        // Safety: `head` is non-null, and nodes on the list are valid per the push/set_head contracts.
65
14283821
        let next = unsafe { T::get_next(node.as_ptr()) };
66
14283821
        self.head.set(next);
67

            
68
14283821
        Some(node)
69
20727192
    }
70

            
71
    /// Pushes an entry onto the freelist.
72
    ///
73
    /// # Safety
74
    ///
75
    /// `entry` must point to a valid node whose link field may be written, and the node must
76
    /// remain valid until it is popped from the list (the list takes ownership of it).
77
19805982
    pub unsafe fn push(&self, entry: NonNull<T>) {
78
19805982
        let ptr = entry.as_ptr();
79
19805982
        let head = self.head.get();
80

            
81
        // Safety: caller transfers ownership of a valid node; writing its next link is valid.
82
19805982
        unsafe { T::set_next(ptr, head) };
83
19805982
        self.head.set(ptr);
84
19805982
    }
85

            
86
    /// Returns an iterator over freelist entries.
87
    ///
88
    /// # Safety
89
    ///
90
    /// The list must not be mutated while the iterator is live, and every node
91
    /// reachable from the head must remain valid for the duration of the walk.
92
2862680
    pub unsafe fn iter(&self) -> FreeListIterator<T> {
93
2862680
        FreeListIterator {
94
2862680
            current: NonNull::new(self.head.get()),
95
2862680
        }
96
2862680
    }
97

            
98
    /// Returns a mutable iterator over freelist entries.
99
    ///
100
    /// # Safety
101
    ///
102
    /// Every node reachable from the head must remain valid for the duration of
103
    /// the walk, and no two yielded `&mut T` may alias (the list must be acyclic).
104
    pub unsafe fn iter_mut(&mut self) -> FreeListIteratorMut<'_, T> {
105
        FreeListIteratorMut {
106
            current: NonNull::new(self.head.get()),
107
            marker: PhantomData,
108
        }
109
    }
110

            
111
    /// Clears the freelist head.
112
2862680
    pub fn clear(&mut self) {
113
2862680
        self.head.set(std::ptr::null_mut());
114
2862680
    }
115

            
116
    /// Returns whether the freelist is currently empty.
117
450203
    pub fn is_empty(&self) -> bool {
118
450203
        self.head.get().is_null()
119
450203
    }
120

            
121
    /// Replaces the freelist head with `head`.
122
    ///
123
    /// # Safety
124
    ///
125
    /// `head` must be either null or a valid linked list of nodes
126
    /// managed by this freelist.
127
450203
    pub unsafe fn set_head(&self, head: *mut T) {
128
450203
        self.head.set(head);
129
450203
    }
130
}
131

            
132
/// Iterator over entries in a [`FreeList`].
133
pub struct FreeListIterator<T: FreeListEntry> {
134
    current: Option<NonNull<T>>,
135
}
136

            
137
impl<T: FreeListEntry> Iterator for FreeListIterator<T> {
138
    type Item = NonNull<T>;
139

            
140
191147896
    fn next(&mut self) -> Option<Self::Item> {
141
191147896
        if let Some(current) = self.current {
142
            // Safety: `current` is a freelist node; its link field is valid to read.
143
188285216
            unsafe {
144
188285216
                self.current = NonNull::new(T::get_next(current.as_ptr()));
145
188285216
            }
146
188285216
            Some(current)
147
        } else {
148
2862680
            None
149
        }
150
191147896
    }
151
}
152

            
153
/// Mutable iterator over entries in a [`FreeList`].
154
pub struct FreeListIteratorMut<'a, T: FreeListEntry> {
155
    current: Option<NonNull<T>>,
156
    marker: PhantomData<&'a mut T>,
157
}
158

            
159
impl<'a, T: FreeListEntry> Iterator for FreeListIteratorMut<'a, T> {
160
    type Item = &'a mut T;
161

            
162
    fn next(&mut self) -> Option<Self::Item> {
163
        if let Some(current) = self.current {
164
            // Safety: `current` is a freelist node; its link field is valid to read.
165
            unsafe {
166
                let current_ptr = current.as_ptr();
167
                self.current = NonNull::new(T::get_next(current_ptr));
168
                Some(&mut *current_ptr)
169
            }
170
        } else {
171
            None
172
        }
173
    }
174
}
175

            
176
#[cfg(kani)]
177
mod verification {
178
    use super::*;
179

            
180
    /// A minimal `FreeListEntry` node holding only the intrusive link.
181
    struct Node {
182
        next: Cell<*mut Node>,
183
    }
184

            
185
    impl Node {
186
        fn new() -> Self {
187
            Self {
188
                next: Cell::new(std::ptr::null_mut()),
189
            }
190
        }
191
    }
192

            
193
    // Safety: `next` is the single link field; both methods read and write it.
194
    unsafe impl FreeListEntry for Node {
195
        unsafe fn get_next(ptr: *mut Self) -> *mut Self {
196
            // SAFETY: caller guarantees `ptr` points to a valid node.
197
            unsafe { (*ptr).next.get() }
198
        }
199

            
200
        unsafe fn set_next(ptr: *mut Self, next: *mut Self) {
201
            // SAFETY: caller guarantees `ptr` points to a valid node.
202
            unsafe { (*ptr).next.set(next) };
203
        }
204
    }
205

            
206
    #[kani::proof]
207
    fn freelist_new_is_empty() {
208
        let fl: FreeList<Node> = FreeList::new();
209
        assert!(fl.is_empty());
210
        assert!(fl.try_pop().is_none());
211
    }
212

            
213
    #[kani::proof]
214
    fn freelist_push_pop_roundtrip() {
215
        let fl: FreeList<Node> = FreeList::new();
216
        let mut node = Node::new();
217
        let ptr = NonNull::from(&mut node);
218

            
219
        // SAFETY: `node` is a valid local node that outlives the freelist operations.
220
        unsafe {
221
            fl.push(ptr);
222
        }
223
        assert!(!fl.is_empty());
224

            
225
        let popped = fl.try_pop().expect("freelist contains exactly one entry");
226
        assert!(std::ptr::eq(popped.as_ptr(), ptr.as_ptr()));
227
        assert!(fl.is_empty());
228
    }
229

            
230
    #[kani::proof]
231
    #[kani::unwind(4)]
232
    fn freelist_push_two_pops_lifo() {
233
        let fl: FreeList<Node> = FreeList::new();
234
        let mut a = Node::new();
235
        let mut b = Node::new();
236
        let pa = NonNull::from(&mut a);
237
        let pb = NonNull::from(&mut b);
238

            
239
        // SAFETY: `a` and `b` are valid local nodes that outlive the freelist operations.
240
        unsafe {
241
            fl.push(pa);
242
            fl.push(pb);
243
        }
244

            
245
        let first = fl.try_pop().expect("non-empty");
246
        let second = fl.try_pop().expect("non-empty");
247
        assert!(std::ptr::eq(first.as_ptr(), pb.as_ptr()));
248
        assert!(std::ptr::eq(second.as_ptr(), pa.as_ptr()));
249
        assert!(fl.is_empty());
250
    }
251

            
252
    #[kani::proof]
253
    fn freelist_clear_makes_empty() {
254
        let mut fl: FreeList<Node> = FreeList::new();
255
        let mut node = Node::new();
256
        // SAFETY: `node` is a valid local node that outlives the freelist operations.
257
        unsafe {
258
            fl.push(NonNull::from(&mut node));
259
        }
260
        fl.clear();
261
        assert!(fl.is_empty());
262
        assert!(fl.try_pop().is_none());
263
    }
264
}