Coverage Report

Created: 2026-04-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/moka-0.12.15/src/common/deque.rs
Line
Count
Source
1
// License and Copyright Notice:
2
//
3
// Some of the code and doc comments in this module were copied from
4
// `std::collections::LinkedList` in the Rust standard library.
5
// https://github.com/rust-lang/rust/blob/master/src/liballoc/collections/linked_list.rs
6
//
7
// The original code/comments from LinkedList are dual-licensed under
8
// the Apache License, Version 2.0 <https://github.com/rust-lang/rust/blob/master/LICENSE-APACHE>
9
// or the MIT license <https://github.com/rust-lang/rust/blob/master/LICENSE-MIT>
10
//
11
// Copyrights of the original code/comments are retained by their contributors.
12
// For full authorship information, see the version control history of
13
// https://github.com/rust-lang/rust/ or https://thanks.rust-lang.org
14
15
use std::{marker::PhantomData, ptr::NonNull};
16
17
use super::CacheRegion;
18
19
#[cfg(feature = "unstable-debug-counters")]
20
use crate::common::concurrent::debug_counters;
21
22
// `crate::{sync,unsync}::DeqNodes` uses a `tagptr::TagNonNull<DeqNode<T>, 2>`
23
// pointer. To reserve the space for the 2-bit tag, use 4 bytes as the *minimum*
24
// alignment.
25
// https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers
26
#[repr(align(4))]
27
#[derive(PartialEq, Eq)]
28
pub(crate) struct DeqNode<T> {
29
    next: Option<NonNull<DeqNode<T>>>,
30
    prev: Option<NonNull<DeqNode<T>>>,
31
    pub(crate) element: T,
32
}
33
34
impl<T> std::fmt::Debug for DeqNode<T> {
35
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36
0
        f.debug_struct("DeqNode")
37
0
            .field("next", &self.next)
38
0
            .field("prev", &self.prev)
39
0
            .finish()
40
0
    }
Unexecuted instantiation: <moka::common::deque::DeqNode<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>> as core::fmt::Debug>::fmt
Unexecuted instantiation: <moka::common::deque::DeqNode<_> as core::fmt::Debug>::fmt
41
}
42
43
impl<T> DeqNode<T> {
44
0
    pub(crate) fn new(element: T) -> Self {
45
        #[cfg(feature = "unstable-debug-counters")]
46
        debug_counters::InternalGlobalDebugCounters::deq_node_created();
47
48
0
        Self {
49
0
            next: None,
50
0
            prev: None,
51
0
            element,
52
0
        }
53
0
    }
Unexecuted instantiation: <moka::common::deque::DeqNode<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::new
Unexecuted instantiation: <moka::common::deque::DeqNode<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::new
Unexecuted instantiation: <moka::common::deque::DeqNode<_>>::new
54
55
0
    pub(crate) fn next_node_ptr(this: NonNull<Self>) -> Option<NonNull<DeqNode<T>>> {
56
0
        unsafe { this.as_ref() }.next
57
0
    }
Unexecuted instantiation: <moka::common::deque::DeqNode<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::next_node_ptr
Unexecuted instantiation: <moka::common::deque::DeqNode<_>>::next_node_ptr
58
}
59
60
#[cfg(feature = "unstable-debug-counters")]
61
impl<T> Drop for DeqNode<T> {
62
    fn drop(&mut self) {
63
        debug_counters::InternalGlobalDebugCounters::deq_node_dropped();
64
    }
65
}
66
67
/// Cursor is used to remember the current iterating position.
68
enum DeqCursor<T> {
69
    Node(NonNull<DeqNode<T>>),
70
    Done,
71
}
72
73
pub(crate) struct Deque<T> {
74
    region: CacheRegion,
75
    len: usize,
76
    head: Option<NonNull<DeqNode<T>>>,
77
    tail: Option<NonNull<DeqNode<T>>>,
78
    cursor: Option<DeqCursor<T>>,
79
    marker: PhantomData<Box<DeqNode<T>>>,
80
}
81
82
impl<T> Drop for Deque<T> {
83
0
    fn drop(&mut self) {
84
        struct DropGuard<'a, T>(&'a mut Deque<T>);
85
86
        impl<T> Drop for DropGuard<'_, T> {
87
0
            fn drop(&mut self) {
88
                // Continue the same loop we do below. This only runs when a destructor has
89
                // panicked. If another one panics this will abort.
90
0
                while self.0.pop_front().is_some() {}
91
0
            }
Unexecuted instantiation: <<moka::common::deque::Deque<_> as core::ops::drop::Drop>::drop::DropGuard<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <<moka::common::deque::Deque<_> as core::ops::drop::Drop>::drop::DropGuard<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <<moka::common::deque::Deque<_> as core::ops::drop::Drop>::drop::DropGuard<_> as core::ops::drop::Drop>::drop
92
        }
93
94
0
        while let Some(node) = self.pop_front() {
95
0
            let guard = DropGuard(self);
96
0
            drop(node);
97
0
            std::mem::forget(guard);
98
0
        }
99
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <moka::common::deque::Deque<_> as core::ops::drop::Drop>::drop
100
}
101
102
// Inner crate public function/methods
103
impl<T> Deque<T> {
104
0
    pub(crate) fn new(region: CacheRegion) -> Self {
105
0
        Self {
106
0
            region,
107
0
            len: 0,
108
0
            head: None,
109
0
            tail: None,
110
0
            cursor: None,
111
0
            marker: PhantomData,
112
0
        }
113
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::new
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::new
Unexecuted instantiation: <moka::common::deque::Deque<_>>::new
114
115
0
    pub(crate) fn region(&self) -> CacheRegion {
116
0
        self.region
117
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::region
Unexecuted instantiation: <moka::common::deque::Deque<_>>::region
118
119
0
    pub(crate) fn len(&self) -> usize {
120
0
        self.len
121
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::len
Unexecuted instantiation: <moka::common::deque::Deque<_>>::len
122
123
0
    pub(crate) fn contains(&self, node: &DeqNode<T>) -> bool {
124
0
        node.prev.is_some() || self.is_head(node)
125
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::contains
Unexecuted instantiation: <moka::common::deque::Deque<_>>::contains
126
127
0
    pub(crate) fn peek_front(&self) -> Option<&DeqNode<T>> {
128
0
        self.head.as_ref().map(|node| unsafe { node.as_ref() })
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::peek_front::{closure#0}
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::peek_front::{closure#0}
Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_front::{closure#0}
129
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::peek_front
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::peek_front
Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_front
130
131
0
    pub(crate) fn peek_front_ptr(&self) -> Option<NonNull<DeqNode<T>>> {
132
0
        self.head.as_ref().copied()
133
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::peek_front_ptr
Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_front_ptr
134
135
    /// Removes and returns the node at the front of the list.
136
0
    pub(crate) fn pop_front(&mut self) -> Option<Box<DeqNode<T>>> {
137
        // This method takes care not to create mutable references to whole nodes,
138
        // to maintain validity of aliasing pointers into `element`.
139
0
        self.head.map(|node| unsafe {
140
0
            if self.is_at_cursor(node.as_ref()) {
141
0
                self.advance_cursor();
142
0
            }
143
144
0
            let mut node = Box::from_raw(node.as_ptr());
145
0
            self.head = node.next;
146
147
0
            match self.head {
148
0
                None => self.tail = None,
149
                // Not creating new mutable (unique!) references overlapping `element`.
150
0
                Some(head) => (*head.as_ptr()).prev = None,
151
            }
152
153
0
            self.len -= 1;
154
155
0
            node.prev = None;
156
0
            node.next = None;
157
0
            node
158
0
        })
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::pop_front::{closure#0}
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::pop_front::{closure#0}
Unexecuted instantiation: <moka::common::deque::Deque<_>>::pop_front::{closure#0}
159
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::pop_front
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::pop_front
Unexecuted instantiation: <moka::common::deque::Deque<_>>::pop_front
160
161
0
    pub(crate) fn peek_back(&self) -> Option<&DeqNode<T>> {
162
0
        self.tail.as_ref().map(|node| unsafe { node.as_ref() })
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::peek_back::{closure#0}
Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_back::{closure#0}
163
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::peek_back
Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_back
164
165
    /// Adds the given node to the back of the list.
166
0
    pub(crate) fn push_back(&mut self, mut node: Box<DeqNode<T>>) -> NonNull<DeqNode<T>> {
167
        // This method takes care not to create mutable references to whole nodes,
168
        // to maintain validity of aliasing pointers into `element`.
169
        unsafe {
170
0
            node.next = None;
171
0
            node.prev = self.tail;
172
0
            let node = NonNull::new(Box::into_raw(node)).expect("Got a null ptr");
173
174
0
            match self.tail {
175
0
                None => self.head = Some(node),
176
                // Not creating new mutable (unique!) references overlapping `element`.
177
0
                Some(tail) => (*tail.as_ptr()).next = Some(node),
178
            }
179
180
0
            self.tail = Some(node);
181
0
            self.len += 1;
182
0
            node
183
        }
184
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::push_back
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::push_back
Unexecuted instantiation: <moka::common::deque::Deque<_>>::push_back
185
186
0
    pub(crate) unsafe fn move_to_back(&mut self, mut node: NonNull<DeqNode<T>>) {
187
0
        if self.is_tail(node.as_ref()) {
188
            // Already at the tail. Nothing to do.
189
0
            return;
190
0
        }
191
192
0
        if self.is_at_cursor(node.as_ref()) {
193
0
            self.advance_cursor();
194
0
        }
195
196
        // Extract the prev and next pointers before we start modifying the node
197
0
        let (prev, next) = {
198
0
            let node_ref = node.as_ref();
199
0
            (node_ref.prev, node_ref.next)
200
0
        };
201
202
        // Not creating new mutable (unique!) references overlapping `element`.
203
0
        match prev {
204
0
            Some(prev_node) if next.is_some() => (*prev_node.as_ptr()).next = next,
205
0
            Some(..) => (),
206
            // This node is the head node.
207
0
            None => self.head = next,
208
        };
209
210
        // This node is not the tail node.
211
0
        if let Some(next_node) = next {
212
0
            (*next_node.as_ptr()).prev = prev;
213
214
            // Update the node's pointers directly without creating conflicting references
215
0
            let node_mut = node.as_mut();
216
0
            node_mut.prev = self.tail;
217
0
            node_mut.next = None;
218
219
0
            match self.tail {
220
                // Not creating new mutable (unique!) references overlapping `element`.
221
0
                Some(tail) => (*tail.as_ptr()).next = Some(node),
222
0
                None => unreachable!(),
223
            }
224
0
            self.tail = Some(node);
225
0
        }
226
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::move_to_back
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::move_to_back
Unexecuted instantiation: <moka::common::deque::Deque<_>>::move_to_back
227
228
0
    pub(crate) fn move_front_to_back(&mut self) {
229
0
        if let Some(node) = self.head {
230
0
            unsafe { self.move_to_back(node) };
231
0
        }
232
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::move_front_to_back
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::move_front_to_back
Unexecuted instantiation: <moka::common::deque::Deque<_>>::move_front_to_back
233
234
    /// Unlinks the specified node from the current list.
235
    ///
236
    /// This method takes care not to create mutable references to `element`, to
237
    /// maintain validity of aliasing pointers.
238
    ///
239
    /// IMPORTANT: This method does not drop the node. If the node is no longer
240
    /// needed, use `unlink_and_drop` instead, or drop it at the caller side.
241
    /// Otherwise, the node will leak.
242
0
    pub(crate) unsafe fn unlink(&mut self, mut node: NonNull<DeqNode<T>>) {
243
0
        if self.is_at_cursor(node.as_ref()) {
244
0
            self.advance_cursor();
245
0
        }
246
247
0
        let node = node.as_mut(); // this one is ours now, we can create an &mut.
248
249
        // Not creating new mutable (unique!) references overlapping `element`.
250
0
        match node.prev {
251
0
            Some(prev) => (*prev.as_ptr()).next = node.next,
252
            // this node is the head node
253
0
            None => self.head = node.next,
254
        };
255
256
0
        match node.next {
257
0
            Some(next) => (*next.as_ptr()).prev = node.prev,
258
            // this node is the tail node
259
0
            None => self.tail = node.prev,
260
        };
261
262
0
        node.prev = None;
263
0
        node.next = None;
264
265
0
        self.len -= 1;
266
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::unlink
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::unlink
Unexecuted instantiation: <moka::common::deque::Deque<_>>::unlink
267
268
    /// Unlinks the specified node from the current list, and then drop the node.
269
    ///
270
    /// This method takes care not to create mutable references to `element`, to
271
    /// maintain validity of aliasing pointers.
272
    ///
273
    /// Panics:
274
0
    pub(crate) unsafe fn unlink_and_drop(&mut self, node: NonNull<DeqNode<T>>) {
275
0
        self.unlink(node);
276
0
        std::mem::drop(Box::from_raw(node.as_ptr()));
277
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::unlink_and_drop
Unexecuted instantiation: <moka::common::deque::Deque<_>>::unlink_and_drop
278
279
0
    pub(crate) fn reset_cursor(&mut self) {
280
0
        self.cursor = None;
281
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::reset_cursor
Unexecuted instantiation: <moka::common::deque::Deque<_>>::reset_cursor
282
}
283
284
impl<'a, T> Iterator for &'a mut Deque<T> {
285
    type Item = &'a T;
286
287
0
    fn next(&mut self) -> Option<Self::Item> {
288
0
        if self.cursor.is_none() {
289
0
            if let Some(head) = self.head {
290
0
                self.cursor = Some(DeqCursor::Node(head));
291
0
            }
292
0
        }
293
0
        let elem = if let Some(DeqCursor::Node(node)) = self.cursor {
294
0
            unsafe { Some(&(*node.as_ptr()).element) }
295
        } else {
296
0
            None
297
        };
298
0
        self.advance_cursor();
299
0
        elem
300
0
    }
Unexecuted instantiation: <&mut moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <&mut moka::common::deque::Deque<_> as core::iter::traits::iterator::Iterator>::next
301
}
302
303
// Private function/methods
304
impl<T> Deque<T> {
305
0
    fn is_head(&self, node: &DeqNode<T>) -> bool {
306
0
        if let Some(head) = self.head {
307
0
            std::ptr::eq(unsafe { head.as_ref() }, node)
308
        } else {
309
0
            false
310
        }
311
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::is_head
Unexecuted instantiation: <moka::common::deque::Deque<_>>::is_head
312
313
0
    fn is_tail(&self, node: &DeqNode<T>) -> bool {
314
0
        if let Some(tail) = self.tail {
315
0
            std::ptr::eq(unsafe { tail.as_ref() }, node)
316
        } else {
317
0
            false
318
        }
319
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::is_tail
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::is_tail
Unexecuted instantiation: <moka::common::deque::Deque<_>>::is_tail
320
321
0
    fn is_at_cursor(&self, node: &DeqNode<T>) -> bool {
322
0
        if let Some(DeqCursor::Node(cur_node)) = self.cursor {
323
0
            std::ptr::eq(unsafe { cur_node.as_ref() }, node)
324
        } else {
325
0
            false
326
        }
327
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::is_at_cursor
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::is_at_cursor
Unexecuted instantiation: <moka::common::deque::Deque<_>>::is_at_cursor
328
329
0
    fn advance_cursor(&mut self) {
330
0
        match self.cursor.take() {
331
0
            None => (),
332
0
            Some(DeqCursor::Node(node)) => unsafe {
333
0
                if let Some(next) = (*node.as_ptr()).next {
334
0
                    self.cursor = Some(DeqCursor::Node(next));
335
0
                } else {
336
0
                    self.cursor = Some(DeqCursor::Done);
337
0
                }
338
            },
339
0
            Some(DeqCursor::Done) => {
340
0
                self.cursor = None;
341
0
            }
342
        }
343
0
    }
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::advance_cursor
Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::advance_cursor
Unexecuted instantiation: <moka::common::deque::Deque<_>>::advance_cursor
344
}
345
346
#[cfg(test)]
347
mod tests {
348
    use super::{CacheRegion::MainProbation, DeqNode, Deque};
349
350
    #[test]
351
    #[allow(clippy::cognitive_complexity)]
352
    fn basics() {
353
        let mut deque: Deque<String> = Deque::new(MainProbation);
354
        assert_eq!(deque.len(), 0);
355
        assert!(deque.peek_front().is_none());
356
        assert!(deque.peek_back().is_none());
357
358
        // push_back(node1)
359
        let node1 = DeqNode::new("a".to_string());
360
        assert!(!deque.contains(&node1));
361
        let node1 = Box::new(node1);
362
        let node1_ptr = deque.push_back(node1);
363
        assert_eq!(deque.len(), 1);
364
365
        // peek_front() -> node1
366
        let head_a = deque.peek_front().unwrap();
367
        assert!(deque.contains(head_a));
368
        assert!(deque.is_head(head_a));
369
        assert!(deque.is_tail(head_a));
370
        assert_eq!(head_a.element, "a".to_string());
371
372
        // move_to_back(node1)
373
        unsafe { deque.move_to_back(node1_ptr) };
374
        assert_eq!(deque.len(), 1);
375
376
        // peek_front() -> node1
377
        let head_b = deque.peek_front().unwrap();
378
        assert!(deque.contains(head_b));
379
        assert!(deque.is_head(head_b));
380
        assert!(deque.is_tail(head_b));
381
        assert!(std::ptr::eq(head_b, node1_ptr.as_ptr()));
382
        assert!(head_b.prev.is_none());
383
        assert!(head_b.next.is_none());
384
385
        // peek_back() -> node1
386
        let tail_a = deque.peek_back().unwrap();
387
        assert!(deque.contains(tail_a));
388
        assert!(deque.is_head(tail_a));
389
        assert!(deque.is_tail(tail_a));
390
        assert!(std::ptr::eq(tail_a, node1_ptr.as_ptr()));
391
        assert!(tail_a.prev.is_none());
392
        assert!(tail_a.next.is_none());
393
394
        // push_back(node2)
395
        let node2 = DeqNode::new("b".to_string());
396
        assert!(!deque.contains(&node2));
397
        let node2_ptr = deque.push_back(Box::new(node2));
398
        assert_eq!(deque.len(), 2);
399
400
        // peek_front() -> node1
401
        let head_c = deque.peek_front().unwrap();
402
        assert!(deque.contains(head_c));
403
        assert!(deque.is_head(head_c));
404
        assert!(!deque.is_tail(head_c));
405
        assert!(std::ptr::eq(head_c, node1_ptr.as_ptr()));
406
        assert!(head_c.prev.is_none());
407
        assert!(std::ptr::eq(
408
            head_c.next.unwrap().as_ptr(),
409
            node2_ptr.as_ptr()
410
        ));
411
412
        // move_to_back(node2)
413
        unsafe { deque.move_to_back(node2_ptr) };
414
        assert_eq!(deque.len(), 2);
415
416
        // peek_front() -> node1
417
        let head_d = deque.peek_front().unwrap();
418
        assert!(deque.contains(head_d));
419
        assert!(deque.is_head(head_d));
420
        assert!(!deque.is_tail(head_d));
421
        assert!(std::ptr::eq(head_d, node1_ptr.as_ptr()));
422
        assert!(head_d.prev.is_none());
423
        assert!(std::ptr::eq(
424
            head_d.next.unwrap().as_ptr(),
425
            node2_ptr.as_ptr()
426
        ));
427
428
        // peek_back() -> node2
429
        let tail_b = deque.peek_back().unwrap();
430
        assert!(deque.contains(tail_b));
431
        assert!(!deque.is_head(tail_b));
432
        assert!(deque.is_tail(tail_b));
433
        assert!(std::ptr::eq(tail_b, node2_ptr.as_ptr()));
434
        assert!(std::ptr::eq(
435
            tail_b.prev.unwrap().as_ptr(),
436
            node1_ptr.as_ptr()
437
        ));
438
        assert_eq!(tail_b.element, "b".to_string());
439
        assert!(tail_b.next.is_none());
440
441
        // move_to_back(node1)
442
        unsafe { deque.move_to_back(node1_ptr) };
443
        assert_eq!(deque.len(), 2);
444
445
        // peek_front() -> node2
446
        let head_e = deque.peek_front().unwrap();
447
        assert!(deque.contains(head_e));
448
        assert!(deque.is_head(head_e));
449
        assert!(!deque.is_tail(head_e));
450
        assert!(std::ptr::eq(head_e, node2_ptr.as_ptr()));
451
        assert!(head_e.prev.is_none());
452
        assert!(std::ptr::eq(
453
            head_e.next.unwrap().as_ptr(),
454
            node1_ptr.as_ptr()
455
        ));
456
457
        // peek_back() -> node1
458
        let tail_c = deque.peek_back().unwrap();
459
        assert!(deque.contains(tail_c));
460
        assert!(!deque.is_head(tail_c));
461
        assert!(deque.is_tail(tail_c));
462
        assert!(std::ptr::eq(tail_c, node1_ptr.as_ptr()));
463
        assert!(std::ptr::eq(
464
            tail_c.prev.unwrap().as_ptr(),
465
            node2_ptr.as_ptr()
466
        ));
467
        assert!(tail_c.next.is_none());
468
469
        // push_back(node3)
470
        let node3 = DeqNode::new("c".to_string());
471
        assert!(!deque.contains(&node3));
472
        let node3_ptr = deque.push_back(Box::new(node3));
473
        assert_eq!(deque.len(), 3);
474
475
        // peek_front() -> node2
476
        let head_f = deque.peek_front().unwrap();
477
        assert!(deque.contains(head_f));
478
        assert!(deque.is_head(head_f));
479
        assert!(!deque.is_tail(head_f));
480
        assert!(std::ptr::eq(head_f, node2_ptr.as_ptr()));
481
        assert!(head_f.prev.is_none());
482
        assert!(std::ptr::eq(
483
            head_f.next.unwrap().as_ptr(),
484
            node1_ptr.as_ptr()
485
        ));
486
487
        // peek_back() -> node3
488
        let tail_d = deque.peek_back().unwrap();
489
        assert!(std::ptr::eq(tail_d, node3_ptr.as_ptr()));
490
        assert_eq!(tail_d.element, "c".to_string());
491
        assert!(deque.contains(tail_d));
492
        assert!(!deque.is_head(tail_d));
493
        assert!(deque.is_tail(tail_d));
494
        assert!(std::ptr::eq(tail_d, node3_ptr.as_ptr()));
495
        assert!(std::ptr::eq(
496
            tail_d.prev.unwrap().as_ptr(),
497
            node1_ptr.as_ptr()
498
        ));
499
        assert!(tail_d.next.is_none());
500
501
        // move_to_back(node1)
502
        unsafe { deque.move_to_back(node1_ptr) };
503
        assert_eq!(deque.len(), 3);
504
505
        // peek_front() -> node2
506
        let head_g = deque.peek_front().unwrap();
507
        assert!(deque.contains(head_g));
508
        assert!(deque.is_head(head_g));
509
        assert!(!deque.is_tail(head_g));
510
        assert!(std::ptr::eq(head_g, node2_ptr.as_ptr()));
511
        assert!(head_g.prev.is_none());
512
        assert!(std::ptr::eq(
513
            head_g.next.unwrap().as_ptr(),
514
            node3_ptr.as_ptr()
515
        ));
516
517
        // peek_back() -> node1
518
        let tail_e = deque.peek_back().unwrap();
519
        assert!(deque.contains(tail_e));
520
        assert!(!deque.is_head(tail_e));
521
        assert!(deque.is_tail(tail_e));
522
        assert!(std::ptr::eq(tail_e, node1_ptr.as_ptr()));
523
        assert!(std::ptr::eq(
524
            tail_e.prev.unwrap().as_ptr(),
525
            node3_ptr.as_ptr()
526
        ));
527
        assert!(tail_e.next.is_none());
528
529
        // unlink(node3)
530
        unsafe { deque.unlink(node3_ptr) };
531
        assert_eq!(deque.len(), 2);
532
        let node3_ref = unsafe { node3_ptr.as_ref() };
533
        assert!(!deque.contains(node3_ref));
534
        assert!(node3_ref.next.is_none());
535
        assert!(node3_ref.next.is_none());
536
        std::mem::drop(unsafe { Box::from_raw(node3_ptr.as_ptr()) });
537
538
        // peek_front() -> node2
539
        let head_h = deque.peek_front().unwrap();
540
        assert!(deque.contains(head_h));
541
        assert!(deque.is_head(head_h));
542
        assert!(!deque.is_tail(head_h));
543
        assert!(std::ptr::eq(head_h, node2_ptr.as_ptr()));
544
        assert!(head_h.prev.is_none());
545
        assert!(std::ptr::eq(
546
            head_h.next.unwrap().as_ptr(),
547
            node1_ptr.as_ptr()
548
        ));
549
550
        // peek_back() -> node1
551
        let tail_f = deque.peek_back().unwrap();
552
        assert!(deque.contains(tail_f));
553
        assert!(!deque.is_head(tail_f));
554
        assert!(deque.is_tail(tail_f));
555
        assert!(std::ptr::eq(tail_f, node1_ptr.as_ptr()));
556
        assert!(std::ptr::eq(
557
            tail_f.prev.unwrap().as_ptr(),
558
            node2_ptr.as_ptr()
559
        ));
560
        assert!(tail_f.next.is_none());
561
562
        // unlink(node2)
563
        unsafe { deque.unlink(node2_ptr) };
564
        assert_eq!(deque.len(), 1);
565
        let node2_ref = unsafe { node2_ptr.as_ref() };
566
        assert!(!deque.contains(node2_ref));
567
        assert!(node2_ref.next.is_none());
568
        assert!(node2_ref.next.is_none());
569
        std::mem::drop(unsafe { Box::from_raw(node2_ptr.as_ptr()) });
570
571
        // peek_front() -> node1
572
        let head_g = deque.peek_front().unwrap();
573
        assert!(deque.contains(head_g));
574
        assert!(deque.is_head(head_g));
575
        assert!(deque.is_tail(head_g));
576
        assert!(std::ptr::eq(head_g, node1_ptr.as_ptr()));
577
        assert!(head_g.prev.is_none());
578
        assert!(head_g.next.is_none());
579
580
        // peek_back() -> node1
581
        let tail_g = deque.peek_back().unwrap();
582
        assert!(deque.contains(tail_g));
583
        assert!(deque.is_head(tail_g));
584
        assert!(deque.is_tail(tail_g));
585
        assert!(std::ptr::eq(tail_g, node1_ptr.as_ptr()));
586
        assert!(tail_g.next.is_none());
587
        assert!(tail_g.next.is_none());
588
589
        // unlink(node1)
590
        unsafe { deque.unlink(node1_ptr) };
591
        assert_eq!(deque.len(), 0);
592
        let node1_ref = unsafe { node1_ptr.as_ref() };
593
        assert!(!deque.contains(node1_ref));
594
        assert!(node1_ref.next.is_none());
595
        assert!(node1_ref.next.is_none());
596
        std::mem::drop(unsafe { Box::from_raw(node1_ptr.as_ptr()) });
597
598
        // peek_front() -> node1
599
        let head_h = deque.peek_front();
600
        assert!(head_h.is_none());
601
602
        // peek_back() -> node1
603
        let tail_e = deque.peek_back();
604
        assert!(tail_e.is_none());
605
    }
606
607
    #[test]
608
    fn iter() {
609
        let mut deque: Deque<String> = Deque::new(MainProbation);
610
        assert!((&mut deque).next().is_none());
611
612
        let node1 = DeqNode::new("a".into());
613
        deque.push_back(Box::new(node1));
614
        let node2 = DeqNode::new("b".into());
615
        let node2_ptr = deque.push_back(Box::new(node2));
616
        let node3 = DeqNode::new("c".into());
617
        let node3_ptr = deque.push_back(Box::new(node3));
618
619
        // -------------------------------------------------------
620
        // First iteration.
621
        assert_eq!((&mut deque).next(), Some(&"a".into()));
622
        assert_eq!((&mut deque).next(), Some(&"b".into()));
623
        assert_eq!((&mut deque).next(), Some(&"c".into()));
624
        assert!((&mut deque).next().is_none());
625
626
        // -------------------------------------------------------
627
        // Ensure the iterator restarts.
628
        assert_eq!((&mut deque).next(), Some(&"a".into()));
629
        assert_eq!((&mut deque).next(), Some(&"b".into()));
630
        assert_eq!((&mut deque).next(), Some(&"c".into()));
631
        assert!((&mut deque).next().is_none());
632
633
        // -------------------------------------------------------
634
        // Ensure reset_cursor works.
635
        assert_eq!((&mut deque).next(), Some(&"a".into()));
636
        assert_eq!((&mut deque).next(), Some(&"b".into()));
637
        deque.reset_cursor();
638
        assert_eq!((&mut deque).next(), Some(&"a".into()));
639
        assert_eq!((&mut deque).next(), Some(&"b".into()));
640
        assert_eq!((&mut deque).next(), Some(&"c".into()));
641
        assert!((&mut deque).next().is_none());
642
643
        // -------------------------------------------------------
644
        // Try to move_to_back during iteration.
645
        assert_eq!((&mut deque).next(), Some(&"a".into()));
646
        // Next will be "b", but we move it to the back.
647
        unsafe { deque.move_to_back(node2_ptr) };
648
        // Now, next should be "c", and then "b".
649
        assert_eq!((&mut deque).next(), Some(&"c".into()));
650
        assert_eq!((&mut deque).next(), Some(&"b".into()));
651
        assert!((&mut deque).next().is_none());
652
653
        // -------------------------------------------------------
654
        // Try to unlink during iteration.
655
        assert_eq!((&mut deque).next(), Some(&"a".into()));
656
        // Next will be "c", but we unlink it.
657
        unsafe { deque.unlink_and_drop(node3_ptr) };
658
        // Now, next should be "b".
659
        assert_eq!((&mut deque).next(), Some(&"b".into()));
660
        assert!((&mut deque).next().is_none());
661
662
        // -------------------------------------------------------
663
        // Try pop_front during iteration.
664
        let node3 = DeqNode::new("c".into());
665
        deque.push_back(Box::new(node3));
666
667
        assert_eq!((&mut deque).next(), Some(&"a".into()));
668
        // Next will be "b", but we call pop_front twice to remove "a" and "b".
669
        deque.pop_front(); // "a"
670
        deque.pop_front(); // "b"
671
                           // Now, next should be "c".
672
        assert_eq!((&mut deque).next(), Some(&"c".into()));
673
        assert!((&mut deque).next().is_none());
674
675
        // -------------------------------------------------------
676
        // Check iterating on an empty deque.
677
        deque.pop_front(); // "c"
678
        assert!((&mut deque).next().is_none());
679
        assert!((&mut deque).next().is_none());
680
    }
681
682
    #[test]
683
    fn next_node() {
684
        let mut deque: Deque<String> = Deque::new(MainProbation);
685
686
        let node1 = DeqNode::new("a".into());
687
        deque.push_back(Box::new(node1));
688
        let node2 = DeqNode::new("b".into());
689
        let node2_ptr = deque.push_back(Box::new(node2));
690
        let node3 = DeqNode::new("c".into());
691
        let node3_ptr = deque.push_back(Box::new(node3));
692
693
        // -------------------------------------------------------
694
        // First iteration.
695
        // peek_front() -> node1
696
        let node1a = deque.peek_front_ptr().unwrap();
697
        assert_eq!(unsafe { node1a.as_ref() }.element, "a".to_string());
698
        let node2a = DeqNode::next_node_ptr(node1a).unwrap();
699
        assert_eq!(unsafe { node2a.as_ref() }.element, "b".to_string());
700
        let node3a = DeqNode::next_node_ptr(node2a).unwrap();
701
        assert_eq!(unsafe { node3a.as_ref() }.element, "c".to_string());
702
        assert!(DeqNode::next_node_ptr(node3a).is_none());
703
704
        // -------------------------------------------------------
705
        // Iterate after a move_to_back.
706
        // Move "b" to the back. So now "a" -> "c" -> "b".
707
        unsafe { deque.move_to_back(node2_ptr) };
708
        let node1a = deque.peek_front_ptr().unwrap();
709
        assert_eq!(unsafe { node1a.as_ref() }.element, "a".to_string());
710
        let node3a = DeqNode::next_node_ptr(node1a).unwrap();
711
        assert_eq!(unsafe { node3a.as_ref() }.element, "c".to_string());
712
        let node2a = DeqNode::next_node_ptr(node3a).unwrap();
713
        assert_eq!(unsafe { node2a.as_ref() }.element, "b".to_string());
714
        assert!(DeqNode::next_node_ptr(node2a).is_none());
715
716
        // -------------------------------------------------------
717
        // Iterate after an unlink.
718
        // Unlink the second node "c". Now "a" -> "c".
719
        unsafe { deque.unlink_and_drop(node3_ptr) };
720
        let node1a = deque.peek_front_ptr().unwrap();
721
        assert_eq!(unsafe { node1a.as_ref() }.element, "a".to_string());
722
        let node2a = DeqNode::next_node_ptr(node1a).unwrap();
723
        assert_eq!(unsafe { node2a.as_ref() }.element, "b".to_string());
724
        assert!(DeqNode::next_node_ptr(node2a).is_none());
725
    }
726
727
    #[test]
728
    fn peek_and_move_to_back() {
729
        let mut deque: Deque<String> = Deque::new(MainProbation);
730
731
        let node1 = DeqNode::new("a".into());
732
        deque.push_back(Box::new(node1));
733
        let node2 = DeqNode::new("b".into());
734
        let _ = deque.push_back(Box::new(node2));
735
        let node3 = DeqNode::new("c".into());
736
        let _ = deque.push_back(Box::new(node3));
737
        // "a" -> "b" -> "c"
738
739
        let node1a = deque.peek_front_ptr().unwrap();
740
        assert_eq!(unsafe { node1a.as_ref() }.element, "a".to_string());
741
        unsafe { deque.move_to_back(node1a) };
742
        // "b" -> "c" -> "a"
743
744
        let node2a = deque.peek_front_ptr().unwrap();
745
        assert_eq!(unsafe { node2a.as_ref() }.element, "b".to_string());
746
747
        let node3a = DeqNode::next_node_ptr(node2a).unwrap();
748
        assert_eq!(unsafe { node3a.as_ref() }.element, "c".to_string());
749
        unsafe { deque.move_to_back(node3a) };
750
        // "b" -> "a" -> "c"
751
752
        deque.move_front_to_back();
753
        // "a" -> "c" -> "b"
754
755
        let node1b = deque.peek_front().unwrap();
756
        assert_eq!(node1b.element, "a".to_string());
757
    }
758
759
    #[test]
760
    fn drop() {
761
        use std::{cell::RefCell, rc::Rc};
762
763
        struct X(u32, Rc<RefCell<Vec<u32>>>);
764
765
        impl Drop for X {
766
            fn drop(&mut self) {
767
                self.1.borrow_mut().push(self.0)
768
            }
769
        }
770
771
        let mut deque: Deque<X> = Deque::new(MainProbation);
772
        let dropped = Rc::new(RefCell::new(Vec::default()));
773
774
        let node1 = DeqNode::new(X(1, Rc::clone(&dropped)));
775
        let node2 = DeqNode::new(X(2, Rc::clone(&dropped)));
776
        let node3 = DeqNode::new(X(3, Rc::clone(&dropped)));
777
        let node4 = DeqNode::new(X(4, Rc::clone(&dropped)));
778
        deque.push_back(Box::new(node1));
779
        deque.push_back(Box::new(node2));
780
        deque.push_back(Box::new(node3));
781
        deque.push_back(Box::new(node4));
782
        assert_eq!(deque.len(), 4);
783
784
        std::mem::drop(deque);
785
786
        assert_eq!(*dropped.borrow(), &[1, 2, 3, 4]);
787
    }
788
}