6
6
use crate :: notify:: { GenericNotify , Internal , Notification } ;
7
7
use crate :: sync:: atomic:: Ordering ;
8
8
use crate :: sync:: cell:: { Cell , UnsafeCell } ;
9
- use crate :: { RegisterResult , State , TaskRef } ;
9
+ use crate :: { QueueStrategy , RegisterResult , State , TaskRef } ;
10
10
11
11
#[ cfg( feature = "critical-section" ) ]
12
12
use core:: cell:: RefCell ;
@@ -42,17 +42,21 @@ struct Inner<T> {
42
42
43
43
/// The number of notified listeners.
44
44
notified : usize ,
45
+
46
+ /// Strategy by which the list is organized.
47
+ strategy : QueueStrategy ,
45
48
}
46
49
47
50
impl < T > List < T > {
48
51
/// Create a new, empty event listener list.
49
- pub ( super ) fn new ( ) -> Self {
52
+ pub ( super ) fn new ( strategy : QueueStrategy ) -> Self {
50
53
let inner = Inner {
51
54
head : None ,
52
55
tail : None ,
53
56
next : None ,
54
57
len : 0 ,
55
58
notified : 0 ,
59
+ strategy,
56
60
} ;
57
61
58
62
#[ cfg( feature = "critical-section" ) ]
@@ -149,39 +153,9 @@ impl<T> crate::Inner<T> {
149
153
} )
150
154
}
151
155
152
- /// Add a new listener to the list.
153
- pub ( crate ) fn insert ( & self , mut listener : Pin < & mut Option < Listener < T > > > ) {
154
- self . with_inner ( |inner| {
155
- listener. as_mut ( ) . set ( Some ( Listener {
156
- link : UnsafeCell :: new ( Link {
157
- state : Cell :: new ( State :: Created ) ,
158
- prev : Cell :: new ( inner. tail ) ,
159
- next : Cell :: new ( None ) ,
160
- } ) ,
161
- _pin : PhantomPinned ,
162
- } ) ) ;
163
- let listener = listener. as_pin_mut ( ) . unwrap ( ) ;
164
-
165
- {
166
- let entry_guard = listener. link . get ( ) ;
167
- // SAFETY: We are locked, so we can access the inner `link`.
168
- let entry = unsafe { entry_guard. deref ( ) } ;
169
-
170
- // Replace the tail with the new entry.
171
- match mem:: replace ( & mut inner. tail , Some ( entry. into ( ) ) ) {
172
- None => inner. head = Some ( entry. into ( ) ) ,
173
- Some ( t) => unsafe { t. as_ref ( ) . next . set ( Some ( entry. into ( ) ) ) } ,
174
- } ;
175
- }
176
-
177
- // If there are no unnotified entries, this is the first one.
178
- if inner. next . is_none ( ) {
179
- inner. next = inner. tail ;
180
- }
181
-
182
- // Bump the entry count.
183
- inner. len += 1 ;
184
- } ) ;
156
+ /// Adds a listener to the list.
157
+ pub ( crate ) fn insert ( & self , listener : Pin < & mut Option < Listener < T > > > ) {
158
+ self . with_inner ( |inner| inner. insert ( listener) )
185
159
}
186
160
187
161
/// Remove a listener from the list.
@@ -248,6 +222,53 @@ impl<T> crate::Inner<T> {
248
222
}
249
223
250
224
impl < T > Inner < T > {
225
+ fn insert ( & mut self , mut listener : Pin < & mut Option < Listener < T > > > ) {
226
+ use QueueStrategy :: { Fifo , Lifo } ;
227
+
228
+ listener. as_mut ( ) . set ( Some ( Listener {
229
+ link : UnsafeCell :: new ( Link {
230
+ state : Cell :: new ( State :: Created ) ,
231
+ prev : Cell :: new ( self . tail . filter ( |_| self . strategy == Fifo ) ) ,
232
+ next : Cell :: new ( self . head . filter ( |_| self . strategy == Lifo ) ) ,
233
+ } ) ,
234
+ _pin : PhantomPinned ,
235
+ } ) ) ;
236
+ let listener = listener. as_pin_mut ( ) . unwrap ( ) ;
237
+
238
+ {
239
+ let entry_guard = listener. link . get ( ) ;
240
+ // SAFETY: We are locked, so we can access the inner `link`.
241
+ let entry = unsafe { entry_guard. deref ( ) } ;
242
+
243
+ // Replace the head or tail with the new entry.
244
+ let replacing = match self . strategy {
245
+ Lifo => & mut self . head ,
246
+ Fifo => & mut self . tail ,
247
+ } ;
248
+
249
+ match replacing. replace ( entry. into ( ) ) {
250
+ None => * replacing = Some ( entry. into ( ) ) ,
251
+ Some ( t) if self . strategy == Lifo => unsafe {
252
+ t. as_ref ( ) . prev . set ( Some ( entry. into ( ) ) )
253
+ } ,
254
+ Some ( t) if self . strategy == Fifo => unsafe {
255
+ t. as_ref ( ) . next . set ( Some ( entry. into ( ) ) )
256
+ } ,
257
+ Some ( _) => unimplemented ! ( "unimplemented queue strategy" ) ,
258
+ } ;
259
+ }
260
+
261
+ // If there are no unnotified entries, or if using LIFO strategy, this is the first one.
262
+ if self . strategy == Lifo {
263
+ self . next = self . head ;
264
+ } else if self . next . is_none ( ) {
265
+ self . next = self . tail ;
266
+ }
267
+
268
+ // Bump the entry count.
269
+ self . len += 1 ;
270
+ }
271
+
251
272
fn remove (
252
273
& mut self ,
253
274
mut listener : Pin < & mut Option < Listener < T > > > ,
@@ -413,7 +434,7 @@ mod tests {
413
434
414
435
#[ test]
415
436
fn insert ( ) {
416
- let inner = crate :: Inner :: new ( ) ;
437
+ let inner = crate :: Inner :: new ( QueueStrategy :: Fifo ) ;
417
438
make_listeners ! ( listen1, listen2, listen3) ;
418
439
419
440
// Register the listeners.
@@ -434,7 +455,7 @@ mod tests {
434
455
435
456
#[ test]
436
457
fn drop_non_notified ( ) {
437
- let inner = crate :: Inner :: new ( ) ;
458
+ let inner = crate :: Inner :: new ( QueueStrategy :: Fifo ) ;
438
459
make_listeners ! ( listen1, listen2, listen3) ;
439
460
440
461
// Register the listeners.
0 commit comments