@@ -128,6 +128,92 @@ pub mod link {
128128 }
129129}
130130
131+ /// A thread-safe linked-list event pusher and iterator.
132+ pub mod link_sync {
133+
134+ use std:: borrow:: Cow ;
135+ use std:: sync:: { Arc , Mutex } ;
136+
137+ use super :: { Event , EventPusher , EventIterator } ;
138+
139+ /// A linked list of Event<T, C> usable across threads.
140+ pub struct EventLink < T , C > {
141+ /// An event, if one exists.
142+ ///
143+ /// An event might not exist, if either we want to insert a `None` and have the output iterator pause,
144+ /// or in the case of the very first linked list element, which has no event when constructed.
145+ pub event : Option < Event < T , C > > ,
146+ /// The next event, if it exists.
147+ pub next : Mutex < Option < Arc < EventLink < T , C > > > > ,
148+ }
149+
150+ impl < T , C > EventLink < T , C > {
151+ /// Allocates a new `EventLink`.
152+ pub fn new ( ) -> EventLink < T , C > {
153+ EventLink { event : None , next : Mutex :: new ( None ) }
154+ }
155+ }
156+
157+ impl < T , C > EventPusher < T , C > for Arc < EventLink < T , C > > {
158+ fn push ( & mut self , event : Event < T , C > ) {
159+ let mut guard = self . next . lock ( ) . unwrap ( ) ;
160+ * guard = Some ( Arc :: new ( EventLink { event : Some ( event) , next : Mutex :: new ( None ) } ) ) ;
161+ let next = Arc :: clone ( guard. as_ref ( ) . unwrap ( ) ) ;
162+ drop ( guard) ;
163+ * self = next;
164+ }
165+ }
166+
167+ impl < T : Clone , C : Clone > EventIterator < T , C > for Arc < EventLink < T , C > > {
168+ fn next ( & mut self ) -> Option < Cow < ' _ , Event < T , C > > > {
169+ let is_some = self . next . lock ( ) . unwrap ( ) . is_some ( ) ;
170+ if is_some {
171+ let next = Arc :: clone ( self . next . lock ( ) . unwrap ( ) . as_ref ( ) . unwrap ( ) ) ;
172+ * self = next;
173+ if let Some ( this) = Arc :: get_mut ( self ) {
174+ this. event . take ( ) . map ( Cow :: Owned )
175+ }
176+ else {
177+ self . event . as_ref ( ) . map ( Cow :: Borrowed )
178+ }
179+ }
180+ else {
181+ None
182+ }
183+ }
184+ }
185+
186+ // Drop implementation to prevent stack overflow through naive drop impl.
187+ impl < T , C > Drop for EventLink < T , C > {
188+ fn drop ( & mut self ) {
189+ while let Some ( link) = self . next . get_mut ( ) . unwrap ( ) . take ( ) {
190+ if let Ok ( head) = Arc :: try_unwrap ( link) {
191+ * self = head;
192+ }
193+ }
194+ }
195+ }
196+
197+ impl < T , C > Default for EventLink < T , C > {
198+ fn default ( ) -> Self {
199+ Self :: new ( )
200+ }
201+ }
202+
203+ #[ test]
204+ fn avoid_stack_overflow_in_drop ( ) {
205+ #[ cfg( miri) ]
206+ let limit = 1_000 ;
207+ #[ cfg( not( miri) ) ]
208+ let limit = 1_000_000 ;
209+ let mut event1 = Arc :: new ( EventLink :: < ( ) , ( ) > :: new ( ) ) ;
210+ let _event2 = Arc :: clone ( & event1) ;
211+ for _ in 0 .. limit {
212+ event1. push ( Event :: Progress ( vec ! [ ] ) ) ;
213+ }
214+ }
215+ }
216+
131217/// A binary event pusher and iterator.
132218pub mod binary {
133219
0 commit comments