Skip to main content

embed_dlist/
lib.rs

1#![allow(rustdoc::redundant_explicit_links)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![cfg_attr(docsrs, allow(unused_attributes))]
4#![cfg_attr(not(feature = "std"), no_std)]
5
6//! An intrusive doubly linked list implementation.
7//!
8//! This module provides `DLinkedList`, a doubly linked list where elements
9//! embed the list nodes themselves. This design offers memory efficiency
10//! and explicit control over allocation, suitable for scenarios like
11//! building LRU caches directly within data structures.
12//!
13//! # Features
14//! - O(1) push and pop from both front and back.
15//! - Generic over pointer types (`Box`, `Arc`, `NonNull`, raw pointers).
16//! - Supports multiple lists for the same item via `Tag`.
17//!
18//! # Example
19//!
20//! ```rust
21//! use embed_dlist::{DLinkedList, DListItem, DListNode};
22//! use core::cell::UnsafeCell;
23//! use std::sync::Arc;
24//! use core::ptr::NonNull;
25//!
26//! struct MyTag ();
27//!
28//! struct MyItem {
29//!     id: u32,
30//!     data: String,
31//!     node: UnsafeCell<DListNode<MyTag>>,
32//! }
33//!
34//! impl MyItem {
35//!     fn new(id: u32, data: &str) -> Self {
36//!         MyItem {
37//!             id,
38//!             data: data.to_string(),
39//!             node: UnsafeCell::new(DListNode::default()),
40//!         }
41//!     }
42//! }
43//!
44//! unsafe impl DListItem<MyTag> for MyItem {
45//!     fn get_node(&self) -> &mut DListNode<MyTag> {
46//!         unsafe { &mut *self.node.get() }
47//!     }
48//! }
49//!
50//! // Using Box<T> (owned pointers)
51//! {
52//!     let mut list = DLinkedList::<Box<MyItem>, MyTag>::new();
53//!     list.push_back(Box::new(MyItem::new(1, "First")));
54//!     list.push_front(Box::new(MyItem::new(2, "Second")));
55//!     list.push_back(Box::new(MyItem::new(3, "Third")));
56//!     assert_eq!(list.len(), 3);
57//!     assert_eq!(list.pop_front().unwrap().id, 2);
58//!     assert_eq!(list.pop_back().unwrap().id, 3);
59//!     assert_eq!(list.pop_front().unwrap().id, 1);
60//!     assert!(list.is_empty());
61//! }
62//!
63//! // Using Arc<T> (shared ownership)
64//! {
65//!     let mut list = DLinkedList::<Arc<MyItem>, MyTag>::new();
66//!     list.push_back(Arc::new(MyItem::new(1, "First")));
67//!     list.push_front(Arc::new(MyItem::new(2, "Second")));
68//!     list.push_back(Arc::new(MyItem::new(3, "Third")));
69//!     assert_eq!(list.len(), 3);
70//!     assert_eq!(list.pop_front().unwrap().id, 2);
71//!     assert_eq!(list.pop_back().unwrap().id, 3);
72//!     assert_eq!(list.pop_front().unwrap().id, 1);
73//!     assert!(list.is_empty());
74//! }
75//!
76//! // Using NonNull<T> (ignore ownership)
77//! {
78//!     let mut list = DLinkedList::<NonNull<MyItem>, MyTag>::new();
79//!     let item1 = Box::into_raw(Box::new(MyItem::new(1, "First")));
80//!     let item2 = Box::into_raw(Box::new(MyItem::new(2, "Second")));
81//!     let item3 = Box::into_raw(Box::new(MyItem::new(3, "Third")));
82//!     list.push_back(unsafe{NonNull::new_unchecked(item1)});
83//!     list.push_front(unsafe{NonNull::new_unchecked(item2)});
84//!     list.push_back(unsafe{NonNull::new_unchecked(item3)});
85//!     assert_eq!(list.len(), 3);
86//!     assert_eq!(unsafe { list.pop_front().unwrap().as_ref().id }, 2);
87//!     assert_eq!(unsafe { list.pop_back().unwrap().as_ref().id }, 3);
88//!     assert_eq!(unsafe { list.pop_front().unwrap().as_ref().id }, 1);
89//!     assert!(list.is_empty());
90//!     unsafe{
91//!         let _ = Box::from_raw(item1);
92//!         let _ = Box::from_raw(item2);
93//!         let _ = Box::from_raw(item3);
94//!     }
95//! }
96//! ```
97//!
98//! # Mixed Types
99//!
100//! This example show mixed multiple types (which have the same DListNode field) in one list,
101//! with custom pointer type.
102//!
103//! ```
104//! use embed_dlist::{DLinkedList, DListItem, DListNode};
105//! use pointers::Pointer;
106//! use core::cell::UnsafeCell;
107//! use std::sync::Arc;
108//!
109//! enum MixedPointer {
110//!     Multi(Arc<ArcNode>),
111//!     One(Box<BoxNode>),
112//! }
113//!
114//! impl MixedPointer {
115//!
116//!     fn as_multi(&self) -> &Arc<ArcNode> {
117//!         if let Self::Multi(inner) = self {
118//!             inner
119//!         } else {
120//!             panic!("not Multi")
121//!         }
122//!     }
123//!
124//!     fn as_one(&self) -> &Box<BoxNode> {
125//!         if let Self::One(inner) = self {
126//!             inner
127//!         } else {
128//!             panic!("not One")
129//!         }
130//!     }
131//! }
132//!
133//! const IS_ARC: usize = 0x1;
134//! const TYPE_MASK: usize = IS_ARC;
135//!
136//! struct ArcNode {
137//!     _node: UnsafeCell<DListNode<()>>,
138//!     v: usize,
139//! }
140//!
141//! struct BoxNode {
142//!     _node: UnsafeCell<DListNode<()>>,
143//!     v: String,
144//! }
145//!
146//! impl ArcNode {
147//!     fn new(v: usize) -> Arc<Self> {
148//!         Arc::new(Self{
149//!             _node: Default::default(),
150//!             v,
151//!         })
152//!     }
153//! }
154//!
155//! impl BoxNode {
156//!     fn new(v: String) -> Box<Self> {
157//!         Box::new(Self{
158//!             _node: Default::default(),
159//!             v,
160//!         })
161//!     }
162//! }
163//!
164//! struct MixedAddr (usize);
165//!
166//! impl Pointer for MixedPointer {
167//!     type Target = MixedAddr;
168//!
169//!     fn as_ref(&self) -> &MixedAddr {
170//!         unreachable!("we don't call as_ref in DLinkedList");
171//!     }
172//!
173//!     /// # Safety
174//!     ///
175//!     /// just a mock
176//!     unsafe fn from_raw(p: *const MixedAddr) -> Self {
177//!         let real_p = (p as usize) & (!TYPE_MASK);
178//!         debug_assert!(real_p != 0);
179//!         let type_flag = (p as usize) & TYPE_MASK;
180//!         if type_flag == IS_ARC {
181//!             Self::Multi(unsafe{Arc::from_raw(real_p as *mut ArcNode)})
182//!         } else {
183//!             Self::One(unsafe{Box::from_raw(real_p as *mut BoxNode)})
184//!         }
185//!     }
186//!
187//!     /// # Safety
188//!     /// the address into_raw cannot be defer directly
189//!     fn into_raw(self) -> *const MixedAddr {
190//!         let addr: usize = match self {
191//!             MixedPointer::Multi(item)=>{Arc::into_raw(item) as usize | IS_ARC},
192//!             MixedPointer::One(item)=>{Box::into_raw(item) as usize},
193//!         };
194//!         addr as *const MixedAddr
195//!     }
196//! }
197//!
198//! unsafe impl DListItem<()> for MixedAddr {
199//!     
200//!     fn get_node(&self) -> &mut DListNode<()> {
201//!         unreachable!();
202//!     }
203//!
204//!     unsafe fn get_node_from_ptr<'a>(p: *mut u8) -> &'a mut DListNode<()>
205//!     where
206//!         Self: 'a,
207//!     {
208//!         let real_p = (p as usize) & (!TYPE_MASK);
209//!         debug_assert!(real_p != 0);
210//!         let type_flag = (p as usize) & TYPE_MASK;
211//!         if type_flag == IS_ARC {
212//!             unsafe{&mut *(*(real_p as *const ArcNode))._node.get()}
213//!         } else {
214//!             unsafe{&mut *(*(real_p as *const BoxNode))._node.get()}
215//!         }
216//!     }
217//! }
218//!
219//! // list operation
220//! let mut l = DLinkedList::<MixedPointer, ()>::new();
221//! l.push_back(MixedPointer::Multi(ArcNode::new(1)));
222//! l.push_back(MixedPointer::One(BoxNode::new("box1".to_string())));
223//! l.push_back(MixedPointer::One(BoxNode::new("box2".to_string())));
224//! l.push_back(MixedPointer::Multi(ArcNode::new(2)));
225//!
226//! let mut iter = l.iter();
227//! assert_eq!(iter.next().unwrap().as_multi().v, 1);
228//! assert_eq!(iter.next().unwrap().as_one().v.as_str(), "box1");
229//! assert_eq!(iter.next().unwrap().as_one().v.as_str(), "box2");
230//! assert_eq!(iter.next().unwrap().as_multi().v, 2);
231//! assert!(iter.next().is_none());
232//!
233//! let mut iter = l.drain();
234//! assert_eq!(iter.next().unwrap().as_multi().v, 1);
235//! assert_eq!(iter.next().unwrap().as_one().v.as_str(), "box1");
236//! assert_eq!(iter.next().unwrap().as_one().v.as_str(), "box2");
237//! assert_eq!(iter.next().unwrap().as_multi().v, 2);
238//! assert!(iter.next().is_none());
239//! ```
240
241extern crate alloc;
242#[cfg(any(feature = "std", test))]
243extern crate std;
244
245use core::marker::PhantomData;
246use core::{
247    borrow::BorrowMut,
248    fmt,
249    mem::{self, MaybeUninit},
250    ptr::{self, null_mut},
251};
252use pointers::Pointer;
253
254/// A trait to return internal mutable DListNode for specified list.
255///
256/// The tag is used to distinguish different DListNodes within the same item,
257/// allowing an item to belong to multiple lists simultaneously.
258/// For only one ownership, you can use `()`.
259///
260/// # Safety
261///
262/// Implementors must ensure `get_node` returns a valid reference to the `DListNode`
263/// embedded within `Self`. Users must use `UnsafeCell` to hold `DListNode` to support
264/// interior mutability required by list operations.
265pub unsafe trait DListItem<Tag>: Sized {
266    fn get_node(&self) -> &mut DListNode<Tag>;
267
268    /// # Safety
269    ///
270    /// This is just map from raw pointer to `&mut DListNode`.
271    ///
272    /// You only have to implement this when using custom pointer type with abnormal address.
273    /// Refer to [Mixed Type Example](index.html#mixed-types)
274    #[allow(unsafe_op_in_unsafe_fn)]
275    #[inline(always)]
276    unsafe fn get_node_from_ptr<'a>(p: *mut u8) -> &'a mut DListNode<Tag>
277    where
278        Self: 'a,
279    {
280        debug_assert!(!p.is_null());
281        (*(p as *const Self)).get_node()
282    }
283}
284
285/// The node structure that must be embedded in items to be stored in a `DLinkedList`.
286#[repr(C)]
287pub struct DListNode<Tag> {
288    prev: *mut u8,
289    next: *mut u8,
290    _phan: PhantomData<fn(&Tag)>,
291}
292
293unsafe impl<Tag> Send for DListNode<Tag> {}
294
295impl<Tag> Default for DListNode<Tag> {
296    #[inline(always)]
297    fn default() -> Self {
298        Self { prev: null_mut(), next: null_mut(), _phan: Default::default() }
299    }
300}
301
302impl<Tag> fmt::Debug for DListNode<Tag> {
303    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
304        write!(f, "(")?;
305        if !self.prev.is_null() {
306            write!(f, "prev: {:p} ", self.prev)?;
307        } else {
308            write!(f, "prev: none ")?;
309        }
310        if !self.next.is_null() {
311            write!(f, "next: {:p} ", self.next)?;
312        } else {
313            write!(f, "next: none ")?;
314        }
315        write!(f, ")")
316    }
317}
318
319/// An intrusive doubly linked list.
320///
321/// Supports O(1) insertion and removal at both ends.
322#[repr(C)]
323pub struct DLinkedList<P, Tag>
324where
325    P: Pointer,
326    P::Target: DListItem<Tag>,
327{
328    length: usize,
329    head: *mut u8,
330    tail: *mut u8,
331    _phan: PhantomData<fn(&P, &Tag)>,
332}
333
334unsafe impl<P, Tag> Send for DLinkedList<P, Tag>
335where
336    P: Pointer,
337    P::Target: DListItem<Tag>,
338{
339}
340
341impl<P: fmt::Debug, Tag> fmt::Debug for DLinkedList<P, Tag>
342where
343    P: Pointer,
344    P::Target: DListItem<Tag>,
345{
346    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
347        write!(f, "{{ length: {} ", self.length)?;
348        if !self.head.is_null() {
349            write!(f, "head: {:?} ", self.head)?;
350        } else {
351            write!(f, "head: none ")?;
352        }
353        if !self.tail.is_null() {
354            write!(f, "tail: {:?} ", self.tail)?;
355        } else {
356            write!(f, "tail: none ")?;
357        }
358        write!(f, "}}")
359    }
360}
361
362impl<P, Tag> DLinkedList<P, Tag>
363where
364    P: Pointer,
365    P::Target: DListItem<Tag>,
366{
367    /// Creates a new, empty doubly linked list.
368    #[inline(always)]
369    pub fn new() -> Self {
370        DLinkedList { length: 0, head: null_mut(), tail: null_mut(), _phan: Default::default() }
371    }
372
373    /// Clears the list, dropping all of its elements if the pointer type `P` owns them.
374    #[inline]
375    pub fn clear(&mut self) {
376        // By repeatedly popping from the front, we drop each element.
377        // If P is an owned pointer (like Box), the element is dropped.
378        // If P is a raw pointer, it's a no-op, but the list is still emptied.
379        while self.pop_front().is_some() {}
380    }
381
382    /// Returns the length of the list as `usize`.
383    #[inline(always)]
384    pub fn len(&self) -> usize {
385        self.length
386    }
387
388    /// Returns `true` if the list contains no elements.
389    #[inline(always)]
390    pub fn is_empty(&self) -> bool {
391        self.length == 0
392    }
393
394    #[inline(always)]
395    fn _remove_node(&mut self, item: *mut u8) -> bool {
396        let mut removed = false;
397        unsafe {
398            let node = <P::Target as DListItem<Tag>>::get_node_from_ptr(item);
399            if !node.prev.is_null() {
400                <P::Target as DListItem<Tag>>::get_node_from_ptr(node.prev).next = node.next;
401                removed = true;
402            } else if self.head == item {
403                self.head = node.next;
404                removed = true;
405            }
406            if !node.next.is_null() {
407                <P::Target as DListItem<Tag>>::get_node_from_ptr(node.next).prev = node.prev;
408                removed = true;
409            } else if self.tail == item {
410                self.tail = node.prev;
411                removed = true;
412            }
413            if removed {
414                node.next = null_mut();
415                node.prev = null_mut();
416                self.length -= 1;
417            }
418        }
419        removed
420    }
421
422    /// Remove a node by raw pointer from the middle of the list, and recover P from `item`
423    ///
424    /// - Return Some if the item is in the list.
425    /// - Return None if the item is not in any list.
426    ///
427    /// NOTE: Due to avoid miri stack borrow rule error, `item` is a raw pointer.
428    ///
429    /// # Safety
430    ///
431    /// `item` should point the a valid item. Do not remove item from other list, otherwise will lead to UB.
432    ///
433    /// # Example
434    ///
435    /// ```
436    ///
437    /// use embed_dlist::{DLinkedList, DListItem, DListNode};
438    /// use core::cell::UnsafeCell;
439    /// extern crate alloc;
440    /// use alloc::boxed::Box;
441    ///
442    /// #[derive(Debug)]
443    /// pub struct TestNode {
444    ///     pub value: i64,
445    ///     pub node: UnsafeCell<DListNode<()>>,
446    /// }
447    ///
448    /// unsafe impl Send for TestNode {}
449    ///
450    /// unsafe impl DListItem<()> for TestNode {
451    ///     fn get_node(&self) -> &mut DListNode<()> {
452    ///         unsafe { &mut *self.node.get() }
453    ///     }
454    /// }
455    ///
456    /// fn new_node(v: i64) -> TestNode {
457    ///     TestNode { value: v, node: UnsafeCell::new(DListNode::default()) }
458    /// }
459    ///
460    /// let mut l = DLinkedList::<Box<TestNode>, ()>::new();
461    ///
462    /// let node1 = Box::new(new_node(1));
463    /// l.push_back(node1);
464    /// let node2 = Box::new(new_node(2));
465    ///
466    /// // NOTE: use `node_p = node2.as_ptr()`  will trigger miri stack borrow rule.
467    /// // we use into_raw and then from_raw
468    /// let node2_p = Box::into_raw(node2);
469    /// l.push_back(unsafe{Box::from_raw(node2_p)});
470    ///
471    /// let node3 = Box::new(new_node(3));
472    /// l.push_back(node3);
473    /// assert_eq!(l.len(), 3);
474    ///
475    /// let node2 = unsafe { l.remove_node(node2_p).unwrap() };
476    /// assert_eq!(l.len(), 2);
477    /// assert_eq!(node2.value, 2);
478    /// ```
479    #[inline(always)]
480    pub unsafe fn remove_node(&mut self, item: *const P::Target) -> Option<P> {
481        unsafe { if self._remove_node(item as *mut u8) { Some(P::from_raw(item)) } else { None } }
482    }
483
484    /// Moves a node to the front of the list (e.g., for LRU updates).
485    ///
486    /// NOTE: Due to avoid miri stack borrow rule error, `item` is a raw pointer.
487    ///
488    /// # Safety
489    ///
490    /// The item must be in the list, otherwise will lead to UB.
491    #[inline(always)]
492    pub unsafe fn peak(&mut self, item: *const P::Target) {
493        assert!(!self.head.is_null());
494        if !ptr::eq(self.head, item as *mut u8) {
495            assert!(self._remove_node(item as *mut u8), "item is not in the list");
496            self.push_front_ptr(item);
497        }
498    }
499
500    /// Pushes an element to the front of the list.
501    #[inline]
502    pub fn push_front(&mut self, item: P) {
503        let ptr = item.into_raw();
504        self.push_front_ptr(ptr);
505    }
506
507    #[inline]
508    fn push_front_ptr(&mut self, ptr: *const P::Target) {
509        let node = unsafe { <P::Target as DListItem<Tag>>::get_node_from_ptr(ptr as *mut u8) };
510        let head = self.head;
511        node.next = head;
512        node.prev = null_mut();
513
514        if head.is_null() {
515            self.tail = ptr as *mut u8;
516        } else {
517            unsafe {
518                <P::Target as DListItem<Tag>>::get_node_from_ptr(head).prev = ptr as *mut u8;
519            }
520        }
521        self.head = ptr as *mut u8;
522        self.length += 1;
523    }
524
525    /// Pushes an element to the back of the list.
526    #[inline]
527    pub fn push_back(&mut self, item: P) {
528        let tail = self.tail;
529        let ptr = item.into_raw() as *mut u8;
530        unsafe {
531            let node = <P::Target as DListItem<Tag>>::get_node_from_ptr(ptr);
532            node.prev = tail;
533            node.next = null_mut();
534            if tail.is_null() {
535                self.head = ptr;
536            } else {
537                <P::Target as DListItem<Tag>>::get_node_from_ptr(tail).next = ptr;
538            }
539        }
540        self.tail = ptr;
541        self.length += 1;
542    }
543
544    /// Removes and returns the element at the front of the list.
545    pub fn pop_front(&mut self) -> Option<P> {
546        if !self.head.is_null() {
547            let head_ptr = self.head;
548            unsafe {
549                self._remove_node(head_ptr);
550                Some(P::from_raw(head_ptr as *const P::Target))
551            }
552        } else {
553            None
554        }
555    }
556
557    /// Removes and returns the element at the back of the list.
558    #[inline]
559    pub fn pop_back(&mut self) -> Option<P> {
560        if !self.tail.is_null() {
561            let tail_ptr = self.tail;
562            unsafe {
563                self._remove_node(tail_ptr);
564                Some(P::from_raw(tail_ptr as *const P::Target))
565            }
566        } else {
567            None
568        }
569    }
570
571    #[inline]
572    pub fn get_front_ptr(&self) -> *const P::Target {
573        self.head as *const P::Target
574    }
575
576    /// Returns a reference to the front element.
577    #[inline]
578    pub fn get_front(&self) -> Option<&P::Target> {
579        unsafe {
580            if !self.head.is_null() { Some(&(*(self.head as *const P::Target))) } else { None }
581        }
582    }
583
584    #[inline]
585    pub fn get_back_ptr(&self) -> *const P::Target {
586        self.tail as *const P::Target
587    }
588
589    /// Returns a reference to the back element.
590    #[inline]
591    pub fn get_back(&self) -> Option<&P::Target> {
592        unsafe {
593            if !self.tail.is_null() { Some(&(*(self.tail as *const P::Target))) } else { None }
594        }
595    }
596
597    /// Checks if the given node is the head of the list.
598    #[inline(always)]
599    pub fn is_front(&self, node: &P::Target) -> bool {
600        if self.head.is_null() {
601            false
602        } else {
603            // This comparison is tricky because self.head is *mut HrcWrapper<T>
604            // and node is &mut DListNode<T>.
605            // We need to compare the node address or the wrapper address.
606            // Converting head -> node and comparing addresses of DListNode is safer.
607            ptr::eq(self.head, node as *const P::Target as *mut u8)
608        }
609    }
610
611    /// Returns an iterator over the list (borrowed).
612    ///
613    /// # NOTE
614    ///
615    /// If you plan on turn the raw pointer to owned, use drain instead
616    ///
617    /// # Safety
618    ///
619    /// The caller must ensure that the list is not modified in a way that can
620    /// invalidate internal pointers (such as removing elements or dropping
621    /// items) for the duration of the iterator's use.
622    #[inline(always)]
623    pub fn iter<'a>(&'a self) -> DLinkedListIter<'a, P, Tag> {
624        DLinkedListIter {
625            next_p: self.head,
626            len: self.len(),
627            _phan: Default::default(),
628            cur: MaybeUninit::uninit(),
629        }
630    }
631
632    /// Returns a draining iterator that removes items from the list.
633    /// Crucial for cleaning up lists containing owned pointers (like `Box`).
634    ///
635    /// # Note
636    ///
637    /// The iterator removes elements from the **front** of the list (FIFO order),
638    #[inline(always)]
639    pub fn drain<'a>(&'a mut self) -> DLinkedListDrainer<'a, P, Tag> {
640        DLinkedListDrainer { list: self, _phan: Default::default() }
641    }
642}
643
644impl<P, Tag> Drop for DLinkedList<P, Tag>
645where
646    P: Pointer,
647    P::Target: DListItem<Tag>,
648{
649    fn drop(&mut self) {
650        // Calling drain will remove all elements from the list and drop them.
651        // The DLinkedListDrainer iterator returns P, which will be dropped
652        // when the iterator is consumed.
653        if mem::needs_drop::<P>() {
654            self.drain().for_each(drop);
655        }
656    }
657}
658
659pub struct DLinkedListIter<'a, P, Tag>
660where
661    P: Pointer,
662    P::Target: DListItem<Tag>,
663{
664    next_p: *mut u8,
665    cur: MaybeUninit<P>,
666    len: usize,
667    _phan: PhantomData<&'a DLinkedList<P, Tag>>,
668}
669
670unsafe impl<'a, P, Tag> Send for DLinkedListIter<'a, P, Tag>
671where
672    P: Pointer,
673    P::Target: DListItem<Tag>,
674{
675}
676
677impl<'a, P, Tag> Iterator for DLinkedListIter<'a, P, Tag>
678where
679    P: Pointer,
680    P::Target: DListItem<Tag>,
681{
682    type Item = &'a P;
683
684    #[inline]
685    fn next(&mut self) -> Option<&'a P> {
686        if !self.next_p.is_null() {
687            self.len -= 1;
688            let cur = self.next_p;
689            unsafe {
690                self.next_p = <P::Target as DListItem<Tag>>::get_node_from_ptr(cur).next;
691                self.cur.write(P::from_raw(cur as *const P::Target));
692                // use transmute to convert lifetime from '_ to 'a
693                return Some(mem::transmute::<&P, &P>(self.cur.assume_init_ref()));
694            }
695        }
696        None
697    }
698
699    #[inline]
700    fn size_hint(&self) -> (usize, Option<usize>) {
701        (self.len, Some(self.len))
702    }
703}
704
705impl<'a, P, Tag> ExactSizeIterator for DLinkedListIter<'a, P, Tag>
706where
707    P: Pointer,
708    P::Target: DListItem<Tag>,
709{
710}
711
712pub type DLinkedListDrainer<'a, P, Tag> = Drainer<&'a mut DLinkedList<P, Tag>, P, Tag>;
713pub type DLinkedListIntoIter<P, Tag> = Drainer<DLinkedList<P, Tag>, P, Tag>;
714
715pub struct Drainer<L, P, Tag>
716where
717    L: BorrowMut<DLinkedList<P, Tag>>,
718    P: Pointer,
719    P::Target: DListItem<Tag>,
720{
721    list: L,
722    _phan: PhantomData<(P, Tag)>,
723}
724
725impl<L, P, Tag> Iterator for Drainer<L, P, Tag>
726where
727    L: BorrowMut<DLinkedList<P, Tag>>,
728    P: Pointer,
729    P::Target: DListItem<Tag>,
730{
731    type Item = P;
732
733    #[inline]
734    fn next(&mut self) -> Option<P> {
735        self.list.borrow_mut().pop_front()
736    }
737
738    #[inline]
739    fn size_hint(&self) -> (usize, Option<usize>) {
740        let l = self.list.borrow().len();
741        (l, Some(l))
742    }
743}
744
745impl<L, P, Tag> ExactSizeIterator for Drainer<L, P, Tag>
746where
747    L: BorrowMut<DLinkedList<P, Tag>>,
748    P: Pointer,
749    P::Target: DListItem<Tag>,
750{
751}
752
753impl<'a, P, Tag> IntoIterator for &'a DLinkedList<P, Tag>
754where
755    P: Pointer,
756    P::Target: DListItem<Tag>,
757{
758    type Item = &'a P;
759    type IntoIter = DLinkedListIter<'a, P, Tag>;
760
761    #[inline]
762    fn into_iter(self) -> Self::IntoIter {
763        self.iter()
764    }
765}
766
767impl<P, Tag> IntoIterator for DLinkedList<P, Tag>
768where
769    P: Pointer,
770    P::Target: DListItem<Tag>,
771{
772    type Item = P;
773    type IntoIter = DLinkedListIntoIter<P, Tag>;
774
775    #[inline]
776    fn into_iter(self) -> Self::IntoIter {
777        Drainer { list: self, _phan: Default::default() }
778    }
779}
780
781#[cfg(test)]
782mod tests {
783    use super::*;
784    use std::boxed::Box;
785    use std::cell::UnsafeCell;
786    use std::println;
787    use std::ptr::NonNull;
788    use std::sync::Arc;
789    use std::sync::atomic::{AtomicUsize, Ordering};
790
791    pub struct TestTag;
792
793    #[derive(Debug)]
794    pub struct TestNode {
795        pub value: i64,
796        pub node: UnsafeCell<DListNode<TestTag>>,
797    }
798
799    static ACTIVE_NODE_COUNT: AtomicUsize = AtomicUsize::new(0);
800
801    impl Drop for TestNode {
802        fn drop(&mut self) {
803            ACTIVE_NODE_COUNT.fetch_sub(1, Ordering::SeqCst);
804        }
805    }
806
807    unsafe impl Send for TestNode {}
808
809    unsafe impl DListItem<TestTag> for TestNode {
810        fn get_node(&self) -> &mut DListNode<TestTag> {
811            unsafe { &mut *self.node.get() }
812        }
813    }
814
815    fn new_node(v: i64) -> TestNode {
816        ACTIVE_NODE_COUNT.fetch_add(1, Ordering::SeqCst);
817        TestNode { value: v, node: UnsafeCell::new(DListNode::default()) }
818    }
819
820    #[test]
821    fn test_push_back_box() {
822        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
823
824        let node1 = Box::new(new_node(1));
825        l.push_back(node1);
826
827        let node2 = Box::new(new_node(2));
828        l.push_back(node2);
829
830        let node3 = Box::new(new_node(3));
831        l.push_back(node3);
832
833        assert_eq!(3, l.len());
834
835        let mut iter = l.iter();
836        assert_eq!(iter.next().unwrap().value, 1);
837        assert_eq!(iter.next().unwrap().value, 2);
838        assert_eq!(iter.next().unwrap().value, 3);
839        assert!(iter.next().is_none());
840
841        {
842            let mut drain = l.drain();
843            assert_eq!(drain.next().unwrap().value, 1);
844            assert_eq!(drain.next().unwrap().value, 2);
845            assert_eq!(drain.next().unwrap().value, 3);
846            assert!(drain.next().is_none());
847        }
848        assert_eq!(l.len(), 0);
849    }
850
851    #[test]
852    fn test_push_back_arc() {
853        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
854
855        let node1 = Arc::new(new_node(1));
856        l.push_back(node1);
857
858        let node2 = Arc::new(new_node(2));
859        l.push_back(node2);
860
861        let node3 = Arc::new(new_node(3));
862        l.push_back(node3);
863
864        assert_eq!(3, l.len());
865
866        let mut iter = l.iter();
867        assert_eq!(iter.next().unwrap().value, 1);
868        assert_eq!(iter.next().unwrap().value, 2);
869        assert_eq!(iter.next().unwrap().value, 3);
870        assert!(iter.next().is_none());
871
872        {
873            let mut drain = l.drain();
874            assert_eq!(drain.next().unwrap().value, 1);
875            assert_eq!(drain.next().unwrap().value, 2);
876            assert_eq!(drain.next().unwrap().value, 3);
877            assert!(drain.next().is_none());
878        }
879        assert_eq!(l.len(), 0);
880    }
881
882    #[test]
883    fn test_push_front_box() {
884        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
885
886        let node3 = Box::new(new_node(3));
887        l.push_front(node3);
888
889        let node2 = Box::new(new_node(2));
890        l.push_front(node2);
891
892        let node1 = Box::new(new_node(1));
893        l.push_front(node1);
894
895        assert_eq!(3, l.len());
896
897        let mut iter = l.iter();
898        assert_eq!(iter.next().unwrap().value, 1);
899        assert_eq!(iter.next().unwrap().value, 2);
900        assert_eq!(iter.next().unwrap().value, 3);
901        assert!(iter.next().is_none());
902
903        {
904            let mut drain = l.drain();
905            assert_eq!(drain.next().unwrap().value, 1);
906            assert_eq!(drain.next().unwrap().value, 2);
907            assert_eq!(drain.next().unwrap().value, 3);
908            assert!(drain.next().is_none());
909        }
910        assert_eq!(l.len(), 0);
911    }
912
913    #[test]
914    fn test_push_front_arc() {
915        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
916
917        let node3 = Arc::new(new_node(3));
918        l.push_front(node3);
919
920        let node2 = Arc::new(new_node(2));
921        l.push_front(node2);
922
923        let node1 = Arc::new(new_node(1));
924        l.push_front(node1);
925
926        assert_eq!(3, l.len());
927
928        let mut iter = l.iter();
929        assert_eq!(iter.next().unwrap().value, 1);
930        assert_eq!(iter.next().unwrap().value, 2);
931        assert_eq!(iter.next().unwrap().value, 3);
932        assert!(iter.next().is_none());
933
934        {
935            let mut drain = l.drain();
936            assert_eq!(drain.next().unwrap().value, 1);
937            assert_eq!(drain.next().unwrap().value, 2);
938            assert_eq!(drain.next().unwrap().value, 3);
939            assert!(drain.next().is_none());
940        }
941        assert_eq!(l.len(), 0);
942    }
943
944    #[test]
945    fn test_pop_back_box() {
946        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
947
948        let node1 = Box::new(new_node(1));
949        l.push_back(node1);
950
951        let node2 = Box::new(new_node(2));
952        l.push_back(node2);
953
954        let node3 = Box::new(new_node(3));
955        l.push_back(node3);
956
957        let mut iter = l.iter();
958        assert_eq!(iter.next().unwrap().value, 1);
959        assert_eq!(iter.next().unwrap().value, 2);
960        assert_eq!(iter.next().unwrap().value, 3);
961        assert!(iter.next().is_none());
962
963        let del_node = l.pop_back();
964        assert_eq!(2, l.len());
965        assert!(del_node.is_some());
966        assert_eq!(del_node.unwrap().value, 3);
967
968        let mut iter_remaining = l.iter();
969        assert_eq!(iter_remaining.next().unwrap().value, 1);
970        assert_eq!(iter_remaining.next().unwrap().value, 2);
971        assert!(iter_remaining.next().is_none());
972
973        {
974            let mut drain = l.drain();
975            assert_eq!(drain.next().unwrap().value, 1);
976            assert_eq!(drain.next().unwrap().value, 2);
977            assert!(drain.next().is_none());
978        }
979        assert_eq!(l.len(), 0);
980    }
981
982    #[test]
983    fn test_pop_back_arc() {
984        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
985
986        let node1 = Arc::new(new_node(1));
987        l.push_back(node1);
988
989        let node2 = Arc::new(new_node(2));
990        l.push_back(node2);
991
992        let node3 = Arc::new(new_node(3));
993        l.push_back(node3);
994
995        let mut iter = l.iter();
996        assert_eq!(iter.next().unwrap().value, 1);
997        assert_eq!(iter.next().unwrap().value, 2);
998        assert_eq!(iter.next().unwrap().value, 3);
999        assert!(iter.next().is_none());
1000
1001        let del_node = l.pop_back();
1002        assert_eq!(2, l.len());
1003        assert!(del_node.is_some());
1004        // Note: The value returned by Arc::from_raw must still be used.
1005        assert!(del_node.is_some());
1006
1007        // Check the order of remaining elements
1008        let mut iter = l.iter();
1009        assert_eq!(iter.next().unwrap().value, 1);
1010        assert_eq!(iter.next().unwrap().value, 2);
1011        assert!(iter.next().is_none());
1012
1013        {
1014            let mut drain = l.drain();
1015            assert_eq!(drain.next().unwrap().value, 1);
1016            assert_eq!(drain.next().unwrap().value, 2);
1017            assert!(drain.next().is_none());
1018        }
1019        assert_eq!(l.len(), 0);
1020    }
1021
1022    #[test]
1023    fn test_pop_front_arc() {
1024        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
1025
1026        let node1 = Arc::new(new_node(1));
1027        l.push_front(node1);
1028
1029        let node2 = Arc::new(new_node(2));
1030        l.push_front(node2);
1031
1032        let node3 = Arc::new(new_node(3));
1033        l.push_front(node3);
1034
1035        let mut iter = l.iter();
1036        assert_eq!(iter.next().unwrap().value, 3);
1037        assert_eq!(iter.next().unwrap().value, 2);
1038        assert_eq!(iter.next().unwrap().value, 1);
1039        assert!(iter.next().is_none());
1040
1041        let del_node = l.pop_front();
1042        assert_eq!(2, l.len());
1043        assert!(del_node.is_some());
1044        // Note: The value returned by Arc::from_raw must still be used.
1045        assert!(del_node.is_some());
1046
1047        // Check the order of remaining elements
1048        let mut iter = l.iter();
1049        assert_eq!(iter.next().unwrap().value, 2);
1050        assert_eq!(iter.next().unwrap().value, 1);
1051        assert!(iter.next().is_none());
1052
1053        {
1054            assert_eq!(l.pop_front().unwrap().value, 2);
1055            assert_eq!(l.pop_front().unwrap().value, 1);
1056            assert!(l.pop_front().is_none());
1057            assert!(l.pop_back().is_none());
1058        }
1059        assert_eq!(l.len(), 0);
1060    }
1061
1062    #[test]
1063    fn test_iter_box() {
1064        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
1065
1066        let mut count = 0;
1067        for _item in l.iter() {
1068            count += 1;
1069        }
1070        assert_eq!(count, 0);
1071
1072        let node1 = Box::new(new_node(1));
1073        l.push_back(node1);
1074
1075        let node2 = Box::new(new_node(2));
1076        l.push_back(node2);
1077
1078        let node3 = Box::new(new_node(3));
1079        l.push_back(node3);
1080
1081        count = 0;
1082        for item in l.iter() {
1083            count += 1;
1084            println!("{}", item.value);
1085        }
1086        assert_eq!(count, 3);
1087
1088        {
1089            let mut drain = l.drain();
1090            assert_eq!(drain.next().unwrap().value, 1);
1091            assert_eq!(drain.next().unwrap().value, 2);
1092            assert_eq!(drain.next().unwrap().value, 3);
1093            assert!(drain.next().is_none());
1094        }
1095        assert_eq!(l.len(), 0);
1096    }
1097
1098    #[test]
1099    fn test_iter_arc() {
1100        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
1101
1102        let mut count = 0;
1103        for _item in l.iter() {
1104            count += 1;
1105        }
1106        assert_eq!(count, 0);
1107
1108        let node1 = Arc::new(new_node(1));
1109        l.push_back(node1);
1110
1111        let node2 = Arc::new(new_node(2));
1112        l.push_back(node2);
1113
1114        let node3 = Arc::new(new_node(3));
1115        l.push_back(node3);
1116
1117        // Check order
1118        let mut iter = l.iter();
1119        assert_eq!(iter.next().unwrap().value, 1);
1120        assert_eq!(iter.next().unwrap().value, 2);
1121        assert_eq!(iter.next().unwrap().value, 3);
1122        assert!(iter.next().is_none());
1123
1124        {
1125            let mut drain = l.drain();
1126            assert_eq!(drain.next().unwrap().value, 1);
1127            assert_eq!(drain.next().unwrap().value, 2);
1128            assert_eq!(drain.next().unwrap().value, 3);
1129            assert!(drain.next().is_none());
1130        }
1131        assert_eq!(l.len(), 0);
1132    }
1133
1134    #[test]
1135    fn test_single_element_box() {
1136        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
1137        let node1 = Box::new(new_node(1));
1138        l.push_front(node1);
1139        let del_node = l.pop_back();
1140        assert!(del_node.is_some());
1141        assert_eq!(del_node.unwrap().value, 1);
1142        assert_eq!(0, l.len());
1143        assert!(l.pop_back().is_none());
1144
1145        let mut l2 = DLinkedList::<Box<TestNode>, TestTag>::new();
1146        let node2 = Box::new(new_node(2));
1147        l2.push_back(node2);
1148        let del_node2 = l2.pop_back();
1149        assert!(del_node2.is_some());
1150        assert_eq!(del_node2.unwrap().value, 2);
1151        assert_eq!(0, l2.len());
1152        assert!(l2.pop_back().is_none());
1153
1154        {
1155            let mut drain = l.drain();
1156            assert!(drain.next().is_none());
1157        }
1158        assert_eq!(l.len(), 0);
1159
1160        {
1161            let mut drain = l2.drain();
1162            assert!(drain.next().is_none());
1163        }
1164        assert_eq!(l2.len(), 0);
1165    }
1166
1167    #[test]
1168    fn test_single_element_arc() {
1169        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
1170        let node1 = Arc::new(new_node(1));
1171        l.push_front(node1);
1172        let del_node = l.pop_back();
1173        assert!(del_node.is_some());
1174        assert_eq!(0, l.len());
1175        assert!(l.pop_back().is_none());
1176
1177        let mut l2 = DLinkedList::<Arc<TestNode>, TestTag>::new();
1178        let node2 = Arc::new(new_node(2));
1179        l2.push_back(node2);
1180        let del_node2 = l2.pop_back();
1181        assert!(del_node2.is_some());
1182        assert_eq!(0, l2.len());
1183        assert!(l2.pop_back().is_none());
1184
1185        {
1186            let mut drain = l.drain();
1187            assert!(drain.next().is_none());
1188        }
1189        assert_eq!(l.len(), 0);
1190
1191        {
1192            let mut drain = l2.drain();
1193            assert!(drain.next().is_none());
1194        }
1195        assert_eq!(l2.len(), 0);
1196    }
1197
1198    #[test]
1199    fn test_drop_box_implementation() {
1200        // Reset the counter before the test
1201        ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
1202
1203        {
1204            let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
1205
1206            let node1 = Box::new(new_node(1));
1207            l.push_back(node1);
1208
1209            let node2 = Box::new(new_node(2));
1210            l.push_back(node2);
1211
1212            let node3 = Box::new(new_node(3));
1213            l.push_back(node3);
1214
1215            assert_eq!(l.len(), 3);
1216            assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 3);
1217        } // `l` goes out of scope here, triggering DLinkedList's Drop, which drains and drops nodes.
1218
1219        // All nodes should have been dropped
1220        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
1221    }
1222
1223    #[test]
1224    fn test_raw_pointer_list() {
1225        // Reset the counter before the test
1226        ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
1227
1228        // Manually create nodes as raw pointers
1229        let node1 = Box::into_raw(Box::new(new_node(10)));
1230        let node2 = Box::into_raw(Box::new(new_node(20)));
1231
1232        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
1233
1234        unsafe {
1235            let mut l = DLinkedList::<*const TestNode, TestTag>::new();
1236            l.push_back(node1);
1237            l.push_back(node2);
1238
1239            let mut iter = l.iter();
1240            let item = iter.next().unwrap();
1241            assert_eq!((**item).value, 10);
1242            let item = iter.next().unwrap();
1243            assert_eq!((**item).value, 20);
1244            assert!(iter.next().is_none());
1245        } // l dropped here. Because P is *const TestNode, needs_drop is false, so drain is NOT called.
1246
1247        // Nodes should still exist
1248        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
1249
1250        unsafe {
1251            // Check values
1252            assert_eq!((*node1).value, 10);
1253            assert_eq!((*node2).value, 20);
1254
1255            // Clean up
1256            drop(Box::from_raw(node1));
1257            drop(Box::from_raw(node2));
1258        }
1259        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
1260    }
1261
1262    #[test]
1263    fn test_non_null_list() {
1264        // Reset the counter before the test
1265        ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
1266
1267        // Manually create nodes
1268        // Box::leak returns &mut T, which helps creating NonNull
1269        let node1 = Box::leak(Box::new(new_node(100)));
1270        let node2 = Box::leak(Box::new(new_node(200)));
1271
1272        let ptr1 = NonNull::from(node1);
1273        let ptr2 = NonNull::from(node2);
1274
1275        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
1276
1277        unsafe {
1278            let mut l = DLinkedList::<NonNull<TestNode>, TestTag>::new();
1279            l.push_back(ptr1);
1280            l.push_back(ptr2);
1281
1282            let mut iter = l.iter();
1283            assert_eq!(iter.next().unwrap().as_ref().value, 100);
1284            assert_eq!(iter.next().unwrap().as_ref().value, 200);
1285            assert!(iter.next().is_none());
1286        } // l dropped here. NonNull doesn't need drop, so no drain.
1287
1288        // Nodes should still exist
1289        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
1290
1291        unsafe {
1292            // Clean up
1293            drop(Box::from_raw(ptr1.as_ptr()));
1294            drop(Box::from_raw(ptr2.as_ptr()));
1295        }
1296
1297        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
1298    }
1299
1300    #[test]
1301    fn test_clear() {
1302        ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
1303        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
1304
1305        l.push_back(Box::new(new_node(1)));
1306        l.push_back(Box::new(new_node(2)));
1307        assert_eq!(l.len(), 2);
1308        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
1309
1310        l.clear();
1311
1312        assert!(l.is_empty());
1313        assert_eq!(l.len(), 0);
1314        assert!(l.get_front().is_none());
1315        assert!(l.get_back().is_none());
1316        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
1317
1318        // Can still push to the list
1319        l.push_back(Box::new(new_node(3)));
1320        assert_eq!(l.len(), 1);
1321        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 1);
1322    }
1323
1324    #[test]
1325    fn test_remove_middle() {
1326        // Reset the counter before the test
1327        ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
1328        {
1329            let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
1330
1331            let node1 = Box::new(new_node(1));
1332            l.push_back(node1);
1333
1334            let node2 = Box::new(new_node(2));
1335
1336            // NOTE: use `node_p = node2.as_ptr()`  will trigger miri stack borrow rule.
1337            // we use into_raw and then from_raw
1338            let node2_p = Box::into_raw(node2);
1339            l.push_back(unsafe { Box::from_raw(node2_p) });
1340
1341            let node3 = Box::new(new_node(3));
1342            l.push_back(node3);
1343
1344            assert_eq!(l.len(), 3);
1345            assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 3);
1346
1347            let node2 = unsafe { l.remove_node(node2_p).unwrap() };
1348            assert_eq!(l.len(), 2);
1349            assert_eq!(node2.value, 2);
1350
1351            let node4 = Box::new(new_node(4));
1352
1353            let node4_p = Box::into_raw(node4);
1354            assert!(unsafe { l.remove_node(node4_p) }.is_none());
1355            unsafe {
1356                let _ = Box::from_raw(node4_p);
1357            }
1358        } // `l` goes out of scope here, triggering DLinkedList's Drop, which drains and drops nodes.
1359
1360        // All nodes should have been dropped
1361        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
1362    }
1363
1364    #[test]
1365    fn test_peak_arc() {
1366        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
1367
1368        let node1 = Arc::new(new_node(1));
1369        l.push_back(node1);
1370
1371        let node2 = Arc::new(new_node(2));
1372        l.push_back(node2);
1373
1374        let node3 = Arc::new(new_node(3));
1375        l.push_back(node3.clone());
1376
1377        let mut iter = l.iter();
1378        assert_eq!(iter.next().unwrap().value, 1);
1379        assert_eq!(iter.next().unwrap().value, 2);
1380        assert_eq!(iter.next().unwrap().value, 3);
1381        assert!(iter.next().is_none());
1382
1383        let node3_p = Arc::as_ptr(&node3);
1384
1385        unsafe { l.peak(node3_p) };
1386
1387        // Check the order of remaining elements
1388        let mut iter = l.iter();
1389        assert_eq!(iter.next().unwrap().value, 3);
1390        assert_eq!(iter.next().unwrap().value, 1);
1391        assert_eq!(iter.next().unwrap().value, 2);
1392        assert!(iter.next().is_none());
1393
1394        {
1395            let mut drain = l.drain();
1396            assert_eq!(drain.next().unwrap().value, 3);
1397            assert_eq!(drain.next().unwrap().value, 1);
1398            assert_eq!(drain.next().unwrap().value, 2);
1399            assert!(drain.next().is_none());
1400        }
1401        assert_eq!(l.len(), 0);
1402    }
1403}