1
+ //! An intrusive linked list implementation using `RawLink`s modified as singly.
2
+ //!
3
+ //! An _intrusive_ list is a list structure wherein the type of element stored
4
+ //! in the list holds references to other nodes. This means that we don't have
5
+ //! to store a separate node data type that holds the stored elements and
6
+ //! pointers to other nodes, reducing the amount of memory allocated. We can
7
+ //! use intrusive lists in code that runs without the kernel memory allocator,
8
+ //! like the allocator implementation itself, since each list element manages
9
+ //! its own memory.
10
+ use super :: { Link , OwningRef } ;
11
+ use core:: marker:: PhantomData ;
12
+ use core:: mem;
13
+ use core:: ops:: DerefMut ;
14
+ #[ cfg( test) ]
15
+ mod tests;
16
+
17
+ //-----------------------------------------------------------------------------
18
+ // Public API types
19
+ //-----------------------------------------------------------------------------
20
+ // List
21
+ /// An intrusive singly-linked list.
22
+ ///
23
+ /// This type is a wrapper around a series of [`Node`]s. It stores [`Link`]s
24
+ /// to the head [`Node`]s and the length of the list.
25
+ ///
26
+ /// # Type parameters
27
+ /// - `T`: the type of the items stored by each `N`
28
+ /// - `N`: the type of nodes in the list
29
+ /// - `R`: the type of [`OwningRef`] that owns each `N`.
30
+ ///
31
+ /// [`Node`]: trait.Node.html
32
+ /// [`Link`]: ../struct.Link.html
33
+ /// [`OwningRef]: ../trait.OwningRef.html
34
+ #[ derive( Default ) ]
35
+ pub struct List < T , N , R > {
36
+ /// Link to the head node of the list.
37
+ head : Link < N > ,
38
+
39
+ /// Length of the list.
40
+ len : usize ,
41
+
42
+ /// Type marker for items stored in the list.
43
+ _elem_ty : PhantomData < T > ,
44
+
45
+ /// Type marker for the `OwningRef` type.
46
+ _ref_ty : PhantomData < R > ,
47
+ }
48
+
49
+ // Linked
50
+ /// Trait that must be implemented in order to be a member of an intrusive
51
+ /// singly linked list.
52
+ pub trait Linked : Sized {
53
+ /// Borrow this element's next [`Link`].
54
+ ///
55
+ /// [`Links`]: struct.Link.html
56
+ fn next ( & self ) -> & Link < Self > ;
57
+
58
+ /// Mutably borrow this element's next [`Link`].
59
+ ///
60
+ /// [`Links`]: struct.Link.html
61
+ fn next_mut ( & mut self ) -> & mut Link < Self > ;
62
+
63
+ /// De-link this node, returning its' next Link.
64
+ fn take_next ( & mut self ) -> Link < Self > {
65
+ mem:: replace ( self . next_mut ( ) , Link :: none ( ) )
66
+ }
67
+ }
68
+
69
+ //-----------------------------------------------------------------------------
70
+ // Implementations
71
+ //-----------------------------------------------------------------------------
72
+
73
+ // ===== impl List =====
74
+
75
+ impl < T , Node , R > List < T , Node , R > {
76
+ /// Create a new `List` with 0 elements.
77
+ pub const fn new ( ) -> Self {
78
+ List {
79
+ head : Link :: none ( ) ,
80
+ len : 0 ,
81
+ _elem_ty : PhantomData ,
82
+ _ref_ty : PhantomData ,
83
+ }
84
+ }
85
+
86
+ /// Returns the length of the list.
87
+ #[ inline]
88
+ pub fn len ( & self ) -> usize {
89
+ self . len
90
+ }
91
+
92
+ /// Returns true if the list is empty, false otherwise.
93
+ #[ inline]
94
+ pub fn is_empty ( & self ) -> bool {
95
+ self . len == 0
96
+ }
97
+
98
+ /// Borrows the first node of the list as an `Option`.
99
+ ///
100
+ /// Note that this is distinct from `front`: this method
101
+ /// borrows the head _node_, not the head _element_.
102
+ ///
103
+ /// # Returns
104
+ /// - `Some(&N)` if the list has elements
105
+ /// - `None` if the list is empty.
106
+ #[ inline]
107
+ pub fn peek ( & self ) -> Option < & Node > {
108
+ self . head . as_ref ( )
109
+ }
110
+
111
+ /// Mutably borrows the head node of the list as an `Option`
112
+ ///
113
+ /// # Returns
114
+ /// - `Some(&mut Node)` if the list has elements
115
+ /// - `None` if the list is empty.
116
+ #[ inline]
117
+ pub fn peek_mut ( & mut self ) -> Option < & mut Node > {
118
+ self . head . as_mut ( )
119
+ }
120
+ }
121
+
122
+ impl < T , Node , Ref > List < T , Node , Ref >
123
+ where
124
+ Node : Linked ,
125
+ Ref : OwningRef < Node > ,
126
+ Ref : DerefMut ,
127
+ {
128
+ /// Push a node to the list.
129
+ pub fn push_node ( & mut self , mut node : Ref ) -> & mut Self {
130
+ unsafe {
131
+ * node. next_mut ( ) = self . head ;
132
+ let node = Link :: from_owning_ref ( node) ;
133
+ self . head = node;
134
+ self . len += 1 ;
135
+ } ;
136
+ self
137
+ }
138
+ }
139
+
140
+ impl < T , Node , Ref > List < T , Node , Ref >
141
+ where
142
+ Node : Linked ,
143
+ Ref : OwningRef < Node > ,
144
+ {
145
+ /// Pop a node from the list.
146
+ pub fn pop_node ( & mut self ) -> Option < Ref > {
147
+ unsafe {
148
+ self . head . as_ptr ( ) . map ( |node| {
149
+ self . head = ( * node) . take_next ( ) ;
150
+ self . len -= 1 ;
151
+ Ref :: from_ptr ( node as * const Node )
152
+ } )
153
+ }
154
+ }
155
+ }
156
+
157
+ impl < T , Node , R > List < T , Node , R >
158
+ where
159
+ Node : AsRef < T > ,
160
+ {
161
+ /// Borrows the head item of the list as an `Option`
162
+ ///
163
+ /// # Returns
164
+ /// - `Some(&T)` if the list has elements
165
+ /// - `None` if the list is empty.
166
+ #[ inline]
167
+ pub fn front ( & self ) -> Option < & T > {
168
+ self . peek ( ) . map ( Node :: as_ref)
169
+ }
170
+ }
171
+
172
+ impl < T , Node , R > List < T , Node , R >
173
+ where
174
+ Node : AsMut < T > ,
175
+ {
176
+ /// Mutably borrows the head element of the list as an `Option`
177
+ ///
178
+ /// # Returns
179
+ /// - `Some(&mut T)` if the list has elements
180
+ /// - `None` if the list is empty.
181
+ #[ inline]
182
+ pub fn head_mut ( & mut self ) -> Option < & mut T > {
183
+ self . peek_mut ( ) . map ( Node :: as_mut)
184
+ }
185
+ }
186
+
187
+ #[ cfg( all(
188
+ feature = "alloc" ,
189
+ not( any( feature = "std" , test) )
190
+ ) ) ]
191
+ use alloc:: boxed:: Box ;
192
+ #[ cfg( any( feature = "std" , test) ) ]
193
+ use std:: boxed:: Box ;
194
+
195
+
196
+ #[ cfg( any( feature = "alloc" , feature = "std" , test) ) ]
197
+ impl < T , Node > List < T , Node , Box < Node > >
198
+ where
199
+ Node : From < T > ,
200
+ Node : Linked ,
201
+ {
202
+ /// Push an item to the list.
203
+ #[ inline]
204
+ pub fn push ( & mut self , item : T ) -> & mut Self {
205
+ self . push_node ( Box :: new ( Node :: from ( item) ) )
206
+ }
207
+ }
208
+
209
+ #[ cfg( any( feature = "alloc" , feature = "std" , test) ) ]
210
+ impl < T , Node > List < T , Node , Box < Node > >
211
+ where
212
+ Node : Linked ,
213
+ Node : Into < T > ,
214
+ {
215
+ /// Pop an item from the list.
216
+ #[ inline]
217
+ pub fn pop ( & mut self ) -> Option < T > {
218
+ self . pop_node ( ) . map ( |b| ( * b) . into ( ) )
219
+ }
220
+ }
0 commit comments