Skip to main content

dxfeed_graal/
stream.rs

1//! Event streams: the events of a subscription as owned events for async code.
2
3use std::collections::VecDeque;
4use std::fmt;
5use std::future::poll_fn;
6use std::panic::{self, AssertUnwindSafe};
7use std::sync::{Arc, Condvar, Mutex, MutexGuard, PoisonError, Weak};
8use std::task::{Context, Poll, Waker};
9use std::thread;
10use std::time::Duration;
11
12use crate::endpoint::EndpointState;
13use crate::error::{Error, Result};
14use crate::error_manager::{self, ErrorManager};
15use crate::event::{Event, SubscriptionItem};
16use crate::event_queue::{EventQueue, PollResult, SharedEventQueue};
17use crate::feed::DXFeed;
18use crate::observable::ObservableSubscriptionChangeListener;
19use crate::subscription::{DXFeedSubscription, DXFeedTimeSeriesSubscription};
20use crate::symbol::Symbol;
21use crate::terminate::{self, Terminate};
22
23/// How an [`EventStream`] gets the events of its subscription and buffers those that wait to be taken.
24///
25/// There are two ways:
26/// - **A listener** (the default, [`bounded`](Self::bounded), [`unbounded`](Self::unbounded)): a listener on a thread
27///   of the endpoint's executor copies every event into the buffer of the stream as it comes and never waits for the
28///   consumer. The default buffers up to [`DEFAULT_CAPACITY`](Self::DEFAULT_CAPACITY) events and drops the oldest ones
29///   when more come, of whatever symbol, so a slow consumer never blocks the threads of the SDK nor grows the memory
30///   without limit. The subscription can conflate the events before the listener with
31///   [`set_aggregation_period`](DXFeedSubscription::set_aggregation_period).
32/// - **The event queue of the subscription** ([`event_queue`](Self::event_queue)): the events stay in the SDK until
33///   the consumer waits for them. Meanwhile the SDK conflates the lasting events, such as quotes, so that a lagging
34///   consumer gets the last event of each symbol; it keeps the other events, such as trades, in a buffer of the
35///   subscription, and an endpoint of [`Role::StreamFeed`](crate::Role::StreamFeed) stops receiving data instead of
36///   dropping it. See the [`event_queue`](crate::event_queue) module.
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub struct StreamOptions {
39    capacity: Option<usize>,
40    event_queue: bool,
41}
42
43impl StreamOptions {
44    /// The capacity of the default options: 65 536 events.
45    pub const DEFAULT_CAPACITY: usize = 65_536;
46
47    /// Buffers up to `capacity` events; when more come, the oldest are dropped and counted in
48    /// [`EventStream::dropped`]. A capacity of zero is rejected when the stream is made.
49    pub const fn bounded(capacity: usize) -> Self {
50        StreamOptions {
51            capacity: Some(capacity),
52            event_queue: false,
53        }
54    }
55
56    /// Buffers every event until it is taken: nothing is dropped, and the memory grows while the consumer lags.
57    pub const fn unbounded() -> Self {
58        StreamOptions {
59            capacity: None,
60            event_queue: false,
61        }
62    }
63
64    /// Takes the events from an [`EventQueue`] of the subscription, only while the consumer waits for them, so that
65    /// the SDK conflates the lasting events meanwhile.
66    ///
67    /// A thread of the stream polls the queue when the buffer of the stream is empty and a task waits, and moves at
68    /// most about 1 024 events into the buffer at a time; the rest stay in the SDK. [`EventStream::dropped`] counts the
69    /// events that the SDK lost (`getDroppedEvents` of the queue), including those that it held when the stream was
70    /// closed. Each stream has its own thread: prefer one stream for many symbols to a stream per symbol.
71    ///
72    /// The subscription must have no executor and no other queue, as for [`EventQueue::new`].
73    /// [`DXEndpoint::close_and_await_termination`](crate::DXEndpoint::close_and_await_termination) does not wait for
74    /// the consumer: the stream takes the events that the queue holds into its buffer before the endpoint waits for
75    /// them, without conflating them.
76    ///
77    /// ```no_run
78    /// use dxfeed_graal::event::Quote;
79    /// use dxfeed_graal::{DXFeed, StreamOptions};
80    ///
81    /// async fn print_quotes(feed: &DXFeed) -> dxfeed_graal::Result<()> {
82    ///     let subscription = feed.create_subscription::<Quote>()?;
83    ///     let mut quotes = subscription.into_stream_with(StreamOptions::event_queue())?;
84    ///     quotes.subscription().add_symbols(["AAPL", "IBM"])?;
85    ///     while let Some(quote) = quotes.next().await {
86    ///         // While this task is busy, the SDK keeps only the last quote of each symbol.
87    ///         println!("{quote}");
88    ///     }
89    ///     Ok(())
90    /// }
91    /// ```
92    pub const fn event_queue() -> Self {
93        StreamOptions {
94            capacity: None,
95            event_queue: true,
96        }
97    }
98
99    /// The capacity, or `None` for [`unbounded`](Self::unbounded) and [`event_queue`](Self::event_queue).
100    pub const fn capacity(&self) -> Option<usize> {
101        self.capacity
102    }
103}
104
105impl Default for StreamOptions {
106    fn default() -> Self {
107        StreamOptions::bounded(Self::DEFAULT_CAPACITY)
108    }
109}
110
111/// The timeout of a poll that drains the event queue of a stream for an endpoint that awaits its termination.
112const DRAIN_POLL: Duration = Duration::from_millis(10);
113
114/// The limit of a poll of the event queue of a stream.
115const BATCH: usize = 1024;
116
117/// The events of a subscription as owned events, taken with [`next`](Self::next) in async code or, with the cargo
118/// feature `stream`, through the `futures_core::Stream` trait (`StreamExt` of `futures` or `tokio-stream`).
119///
120/// It is made by [`DXFeedSubscription::into_stream`] or [`DXFeedTimeSeriesSubscription::into_stream`] and owns the
121/// subscription, which [`subscription`](Self::subscription) gives for its symbols and settings. It yields `E` for a
122/// subscription to one event type, such as [`Quote`](crate::event::Quote), and [`Event`] for an untyped one, which
123/// skips the events of types that the crate does not map and counts them in [`skipped`](Self::skipped).
124///
125/// By default the events come from a listener on a thread of the endpoint's executor, which copies each batch into
126/// the buffer and wakes the task once; it never waits for the consumer. With [`StreamOptions::event_queue`] they stay
127/// in the SDK, conflated, until the consumer waits for them. See [`StreamOptions`] for both ways and for what happens
128/// when the consumer lags.
129///
130/// The stream ends, yielding `None` after the buffered events, when:
131/// - it is [closed](Self::close), or its subscription is;
132/// - the endpoints of all the feeds that the subscription is attached to are closed, with
133///   [`DXEndpoint::close`](crate::DXEndpoint::close) or
134///   [`close_and_await_termination`](crate::DXEndpoint::close_and_await_termination);
135/// - [`system::shutdown`](crate::system::shutdown) runs.
136///
137/// After [`DXEndpoint::close`](crate::DXEndpoint::close), the events already scheduled are discarded; after
138/// `close_and_await_termination` they are in the buffer. An ended stream stays ended: attaching its subscription to
139/// another feed later brings no events. Dropping the stream drops the subscription, which closes it.
140///
141/// With a [`ManualExecutor`](crate::ManualExecutor), the events of a listener come only while the application
142/// processes the executor, so a task that awaits the stream on the thread that should process it never wakes.
143///
144/// # Example
145///
146/// ```no_run
147/// use dxfeed_graal::DXFeed;
148/// use dxfeed_graal::event::Quote;
149///
150/// async fn print_quotes(feed: &DXFeed) -> dxfeed_graal::Result<()> {
151///     let mut quotes = feed.create_subscription::<Quote>()?.into_stream()?;
152///     quotes.subscription().add_symbols(["AAPL", "IBM"])?;
153///     while let Some(quote) = quotes.next().await {
154///         println!("{quote}");
155///     }
156///     Ok(())
157/// }
158/// ```
159#[must_use = "a stream does nothing unless polled; dropping it closes its subscription"]
160pub struct EventStream<E: SubscriptionItem = Event, S: AsRef<DXFeedSubscription<E>> = DXFeedSubscription<E>> {
161    queue: Arc<Queue<EventQueue<E>>>,
162    subscription: S,
163}
164
165impl<E: SubscriptionItem> DXFeedSubscription<E> {
166    /// Turns the subscription into a stream of owned events with the default [`StreamOptions`].
167    ///
168    /// Make the stream before adding symbols: the SDK refuses a listener of a subscription that has symbols, so this
169    /// returns that [`Error::Java`], and the subscription is dropped.
170    pub fn into_stream(self) -> Result<EventStream<E>> {
171        EventStream::new(self, StreamOptions::default())
172    }
173
174    /// Turns the subscription into a stream of owned events with `options`, as [`into_stream`](Self::into_stream)
175    /// does.
176    ///
177    /// Returns [`Error::InvalidArgument`] for a capacity of zero. With [`StreamOptions::event_queue`], a subscription
178    /// with symbols on a feed, an executor or a queue is [`Error::Java`] of `java.lang.IllegalStateException`, and a
179    /// thread that cannot be started is [`Error::Io`].
180    pub fn into_stream_with(self, options: StreamOptions) -> Result<EventStream<E>> {
181        EventStream::new(self, options)
182    }
183}
184
185impl<E: SubscriptionItem> DXFeedTimeSeriesSubscription<E> {
186    /// Turns the subscription into a stream of owned events with the default [`StreamOptions`], as
187    /// [`DXFeedSubscription::into_stream`] does; [`EventStream::subscription`] keeps
188    /// [`set_from_time`](Self::set_from_time).
189    pub fn into_stream(self) -> Result<EventStream<E, DXFeedTimeSeriesSubscription<E>>> {
190        EventStream::new(self, StreamOptions::default())
191    }
192
193    /// Turns the subscription into a stream of owned events with `options`, as
194    /// [`DXFeedSubscription::into_stream_with`] does.
195    pub fn into_stream_with(self, options: StreamOptions) -> Result<EventStream<E, DXFeedTimeSeriesSubscription<E>>> {
196        EventStream::new(self, options)
197    }
198}
199
200impl<E: SubscriptionItem, S: AsRef<DXFeedSubscription<E>>> EventStream<E, S> {
201    fn new(subscription: S, options: StreamOptions) -> Result<Self> {
202        if options.capacity == Some(0) {
203            return Err(Error::InvalidArgument(
204                "the capacity of an event stream must be positive".into(),
205            ));
206        }
207        let base = subscription.as_ref();
208        let source = if options.event_queue {
209            Some(EventQueue::new(base)?)
210        } else {
211            None
212        };
213        let queue = Arc::new(Queue::new(
214            options.capacity,
215            Feeds::Of(Arc::downgrade(base.shared_feeds())),
216            source,
217            "DXFeedSubscription",
218        ));
219        // Registered first, so that a shutdown that runs meanwhile ends the stream.
220        terminate::register(&queue);
221        if queue.source.is_none() {
222            let listener = queue.clone();
223            base.add_event_listener(move |events| {
224                let mut batch = Vec::with_capacity(events.size_hint().0);
225                let mut skipped = 0;
226                for item in events {
227                    match crate::event::owned::<E>(item) {
228                        Some(event) => batch.push(event),
229                        None => skipped += 1,
230                    }
231                }
232                wake(listener.push(batch, skipped, None));
233            })?;
234        }
235        base.add_change_listener(Closer(queue.clone()))?;
236        // A closed subscription does not call the change listener, and an endpoint may have closed before.
237        if base.is_closed()? {
238            queue.terminate();
239        }
240        queue.check_feeds(None);
241        if queue.source.is_some() {
242            spawn(&queue)?;
243        }
244        Ok(EventStream { queue, subscription })
245    }
246
247    /// The subscription of the stream, to add symbols or change its settings.
248    pub fn subscription(&self) -> &S {
249        &self.subscription
250    }
251
252    /// The next event, or `None` once the stream has ended and its buffer is empty.
253    pub async fn next(&mut self) -> Option<E> {
254        poll_fn(|cx| self.poll_next(cx)).await
255    }
256
257    /// Takes the next event, or `None` once the stream has ended and its buffer is empty; when the buffer is empty
258    /// and the stream goes on, returns [`Poll::Pending`] and wakes the task of `cx` when an event comes or the stream
259    /// ends. After `None`, it returns `None` again.
260    pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<E>> {
261        self.queue.poll_next(cx)
262    }
263
264    /// Ends the stream and closes its subscription. The buffered events are still taken; the events that come later
265    /// are discarded, and those that the event queue of the stream holds are dropped and counted in
266    /// [`dropped`](Self::dropped). Closing again does nothing.
267    pub fn close(&self) -> Result<()> {
268        let closed = if self.queue.source.is_some() {
269            self.queue.close_source()
270        } else {
271            self.queue.terminate();
272            Ok(())
273        };
274        closed.and(self.subscription.as_ref().close())
275    }
276
277    /// The number of the events in the buffer.
278    pub fn buffered(&self) -> usize {
279        self.queue.lock().items.len()
280    }
281
282    /// The number of the events dropped so far: because the buffer was full, or, with
283    /// [`StreamOptions::event_queue`], by the SDK.
284    pub fn dropped(&self) -> u64 {
285        self.queue.lock().dropped
286    }
287
288    /// The number of the events skipped so far because the crate does not map their type
289    /// ([`EventRef::Other`](crate::EventRef::Other)); always zero for a stream of one event type.
290    pub fn skipped(&self) -> u64 {
291        self.queue.lock().skipped
292    }
293}
294
295#[cfg(feature = "stream")]
296impl<E: SubscriptionItem, S: AsRef<DXFeedSubscription<E>> + Unpin> futures_core::Stream for EventStream<E, S> {
297    type Item = E;
298
299    fn poll_next(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<E>> {
300        EventStream::poll_next(self.get_mut(), cx)
301    }
302
303    /// The buffered events, and no upper bound until the stream has ended.
304    fn size_hint(&self) -> (usize, Option<usize>) {
305        self.queue.size_hint()
306    }
307}
308
309impl<E: SubscriptionItem, S: AsRef<DXFeedSubscription<E>>> Drop for EventStream<E, S> {
310    fn drop(&mut self) {
311        // The subscription is dropped after this with no lock held, as that waits for a running call of the listener.
312        self.queue.release();
313    }
314}
315
316impl<E: SubscriptionItem, S: AsRef<DXFeedSubscription<E>>> fmt::Debug for EventStream<E, S> {
317    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318        let state = self.queue.lock();
319        f.debug_struct("EventStream")
320            .field("buffered", &state.items.len())
321            .field("closed", &state.closed)
322            .field("dropped", &state.dropped)
323            .field("skipped", &state.skipped)
324            .field("event_queue", &self.queue.source.is_some())
325            .finish()
326    }
327}
328
329/// The events of the subscriptions attached to a [`SharedEventQueue`], each with the tag of its subscription, as owned
330/// events for async code: taken with [`next`](Self::next) or, with the cargo feature `stream`, through the
331/// `futures_core::Stream` trait.
332///
333/// It is made by [`SharedEventQueue::into_stream`] and owns the queue, which [`queue`](Self::queue) gives to attach
334/// subscriptions and to lend its executor; never poll it then, as the stream does. It does not own the subscriptions:
335/// keep them, as dropping one closes it. It yields the events as [`SharedEventQueue::poll`] returns them,
336/// `(tag, event)`, but skips the events of types that the crate does not map and counts them in
337/// [`skipped`](Self::skipped).
338///
339/// A thread of the stream polls the queue only while a task waits for events and the buffer of the stream is empty,
340/// and moves at most about 1 024 events into the buffer at a time, as with
341/// [`StreamOptions::event_queue`]: meanwhile the SDK conflates the lasting events, such as quotes, and keeps the other
342/// ones in the buffers of the subscriptions; [`dropped`](Self::dropped) counts the events that the SDK lost. The work
343/// of the executor of the queue, such as the listeners of the models built with it, runs in those polls, on the thread
344/// of the stream: it waits while no task waits for events. So the calls that wait for that work, such as
345/// [`DXFeed::detach_subscription_and_clear`] of a subscription with that executor, never return in the task that
346/// consumes the stream, nor anywhere while no task waits for its events. While an endpoint awaits its termination
347/// ([`DXEndpoint::close_and_await_termination`](crate::DXEndpoint::close_and_await_termination)), the thread takes
348/// what the queue holds into the buffer, without conflating it, and runs the work of the executor.
349///
350/// The stream ends, yielding `None` after the buffered events, when it is [closed](Self::close), when its queue is
351/// closed, and when [`system::shutdown`](crate::system::shutdown) runs. Closing an endpoint does not end it, as
352/// subscriptions of any endpoint may be attached to the queue. Dropping the stream closes the queue; the executors
353/// that it lent then run their work at once, on the posting thread, without calling the listeners of the application.
354///
355/// # Example
356///
357/// ```no_run
358/// use dxfeed_graal::DXFeed;
359/// use dxfeed_graal::event::{Quote, Trade};
360/// use dxfeed_graal::event_queue::SharedEventQueue;
361///
362/// async fn print_events(feed: &DXFeed) -> dxfeed_graal::Result<()> {
363///     let mut events = SharedEventQueue::new()?.into_stream()?;
364///     let quotes = feed.create_subscription::<Quote>()?;
365///     let trades = feed.create_subscription::<Trade>()?;
366///     events.queue().attach(&quotes, 1)?;
367///     events.queue().attach(&trades, 2)?;
368///     quotes.add_symbols(["AAPL"])?;
369///     trades.add_symbols(["AAPL"])?;
370///     while let Some((tag, event)) = events.next().await {
371///         println!("{tag}: {event}");
372///     }
373///     Ok(())
374/// }
375/// ```
376#[must_use = "a stream does nothing unless polled; dropping it closes its queue"]
377pub struct TaggedEventStream {
378    queue: Arc<Queue<SharedEventQueue>>,
379}
380
381impl SharedEventQueue {
382    /// Turns the queue into a stream of owned events with their tags. The subscriptions already attached stay
383    /// attached; attach more through [`TaggedEventStream::queue`].
384    ///
385    /// A thread that cannot be started is [`Error::Io`]; the queue is closed then.
386    pub fn into_stream(self) -> Result<TaggedEventStream> {
387        let queue = Arc::new(Queue::new(None, Feeds::Any, Some(self), "EventQueue"));
388        // Registered first, so that a shutdown that runs meanwhile ends the stream.
389        terminate::register(&queue);
390        let stream = TaggedEventStream { queue };
391        spawn(&stream.queue)?;
392        Ok(stream)
393    }
394}
395
396impl TaggedEventStream {
397    /// The queue of the stream, to attach subscriptions, to lend its executor and to read its dropped count. Do not
398    /// poll it: the polls of the stream would take turns with yours. Closing it ends the stream.
399    pub fn queue(&self) -> &SharedEventQueue {
400        self.queue
401            .source
402            .as_ref()
403            .expect("the stream of a shared queue has its queue")
404    }
405
406    /// The next event with its tag, or `None` once the stream has ended and its buffer is empty.
407    pub async fn next(&mut self) -> Option<(i64, Event)> {
408        poll_fn(|cx| self.poll_next(cx)).await
409    }
410
411    /// Takes the next event with its tag, as [`EventStream::poll_next`] does.
412    pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<(i64, Event)>> {
413        self.queue.poll_next(cx)
414    }
415
416    /// Ends the stream and closes its queue. The buffered events are still taken; those that the queue holds are
417    /// dropped and counted in [`dropped`](Self::dropped). Closing again does nothing.
418    pub fn close(&self) -> Result<()> {
419        self.queue.close_source()
420    }
421
422    /// The number of the events in the buffer.
423    pub fn buffered(&self) -> usize {
424        self.queue.lock().items.len()
425    }
426
427    /// The number of the events that the SDK lost so far (`getDroppedEvents` of the queue).
428    pub fn dropped(&self) -> u64 {
429        self.queue.lock().dropped
430    }
431
432    /// The number of the events skipped so far because the crate does not map their type
433    /// ([`EventRef::Other`](crate::EventRef::Other)).
434    pub fn skipped(&self) -> u64 {
435        self.queue.lock().skipped
436    }
437}
438
439#[cfg(feature = "stream")]
440impl futures_core::Stream for TaggedEventStream {
441    type Item = (i64, Event);
442
443    fn poll_next(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<(i64, Event)>> {
444        TaggedEventStream::poll_next(self.get_mut(), cx)
445    }
446
447    /// The buffered events, and no upper bound until the stream has ended.
448    fn size_hint(&self) -> (usize, Option<usize>) {
449        self.queue.size_hint()
450    }
451}
452
453impl Drop for TaggedEventStream {
454    fn drop(&mut self) {
455        self.queue.release();
456    }
457}
458
459impl fmt::Debug for TaggedEventStream {
460    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461        let state = self.queue.lock();
462        f.debug_struct("TaggedEventStream")
463            .field("buffered", &state.items.len())
464            .field("closed", &state.closed)
465            .field("dropped", &state.dropped)
466            .field("skipped", &state.skipped)
467            .finish()
468    }
469}
470
471/// An event queue that the thread of a stream polls.
472pub(crate) trait Source: Send + Sync + 'static {
473    /// What a poll yields for each event.
474    type Item: Send + 'static;
475
476    /// Polls as the public poll of the queue does, but skips and counts the events that the crate does not map; the
477    /// events and the skipped count come as one batch, which may hold no events when all were skipped.
478    fn poll_items(&self, timeout: Option<Duration>, limit: usize) -> Result<PollResult<(Vec<Self::Item>, u64)>>;
479
480    fn wake_up(&self) -> Result<()>;
481
482    fn close(&self) -> Result<()>;
483
484    fn get_dropped_events(&self) -> Result<i64>;
485}
486
487/// Whose endpoints end a stream.
488enum Feeds {
489    /// The feeds of the subscription: the stream ends when the endpoints of all of them are closed.
490    Of(Weak<Mutex<Vec<DXFeed>>>),
491    /// Any endpoint, never ended by their close: a shared queue, attached to subscriptions of any endpoint.
492    Any,
493}
494
495/// The buffer that the listener or the thread of the stream fills and the stream takes from.
496struct Queue<Q: Source> {
497    state: Mutex<State<Q::Item>>,
498    capacity: Option<usize>,
499    feeds: Feeds,
500    /// The event queue that the thread of the stream polls, for [`StreamOptions::event_queue`] and a shared queue.
501    source: Option<Q>,
502    /// Wakes the thread of the stream when the state asks it to poll or to exit.
503    requests: Condvar,
504    /// The component of the errors and panics that go to the error manager.
505    component: &'static str,
506}
507
508struct State<E> {
509    items: VecDeque<E>,
510    closed: bool,
511    waker: Option<Waker>,
512    dropped: u64,
513    skipped: u64,
514    /// A task waits for events: the thread of the stream polls the event queue.
515    demand: bool,
516    /// The endpoints of the subscription that wait for their termination, by address: while there is one, the thread
517    /// polls the event queue with no demand, so that they do not wait for the events that the queue holds.
518    draining: Vec<usize>,
519    /// The stream ends after the thread has taken what the event queue still holds.
520    finishing: bool,
521}
522
523/// Starts the thread of a stream of an event queue.
524fn spawn<Q: Source>(queue: &Arc<Queue<Q>>) -> Result<()> {
525    let helper = queue.clone();
526    thread::Builder::new()
527        .name("dxfeed-event-stream".into())
528        .spawn(move || helper.run())
529        .map(drop)
530        .map_err(|e| Error::Io(Arc::new(e)))
531}
532
533impl<Q: Source> Queue<Q> {
534    fn new(capacity: Option<usize>, feeds: Feeds, source: Option<Q>, component: &'static str) -> Self {
535        Queue {
536            state: Mutex::new(State {
537                items: VecDeque::new(),
538                closed: false,
539                waker: None,
540                dropped: 0,
541                skipped: 0,
542                demand: false,
543                draining: Vec::new(),
544                finishing: false,
545            }),
546            capacity,
547            feeds,
548            source,
549            requests: Condvar::new(),
550            component,
551        }
552    }
553
554    fn lock(&self) -> MutexGuard<'_, State<Q::Item>> {
555        crate::lock(&self.state)
556    }
557
558    /// Takes the next item for the task of `cx`, or stores its waker and, for an event queue, asks the thread to poll.
559    fn poll_next(&self, cx: &mut Context<'_>) -> Poll<Option<Q::Item>> {
560        let (replaced, requested) = {
561            let mut state = self.lock();
562            if let Some(event) = state.items.pop_front() {
563                return Poll::Ready(Some(event));
564            }
565            if state.closed {
566                return Poll::Ready(None);
567            }
568            let requested = self.source.is_some() && !std::mem::replace(&mut state.demand, true);
569            let replaced = match &mut state.waker {
570                Some(waker) if waker.will_wake(cx.waker()) => None,
571                waker => waker.replace(cx.waker().clone()),
572            };
573            (replaced, requested)
574        };
575        if requested {
576            self.requests.notify_one();
577        }
578        // The waker of another task is dropped after the lock, as its drop may run any code.
579        drop(replaced);
580        Poll::Pending
581    }
582
583    /// The buffered items, and no upper bound until the stream has ended.
584    #[cfg(feature = "stream")]
585    fn size_hint(&self) -> (usize, Option<usize>) {
586        let state = self.lock();
587        let buffered = state.items.len();
588        (buffered, state.closed.then_some(buffered))
589    }
590
591    /// Closes the event queue and ends the stream, keeping the buffered items.
592    fn close_source(&self) -> Result<()> {
593        let Some(source) = &self.source else {
594            return Ok(());
595        };
596        let closed = source.close();
597        wake(self.end_with(Some(source.get_dropped_events())));
598        // Lets the thread of the stream exit now rather than when the stream is dropped.
599        self.requests.notify_one();
600        closed
601    }
602
603    /// Ends the stream of a dropped stream, without a wake, as nothing polls it any more, and closes its event queue.
604    fn release(&self) {
605        let waker = {
606            let mut state = self.lock();
607            state.closed = true;
608            state.items.clear();
609            state.waker.take()
610        };
611        drop(waker);
612        if let Some(source) = &self.source {
613            // The thread of the stream exits: at once if it waits for a request, after its poll otherwise, which the
614            // close ends. It is not joined, as this may run on it, in its wake.
615            self.requests.notify_one();
616            let _ = source.close();
617        }
618    }
619
620    /// Adds a batch, dropping the oldest events beyond the capacity, and returns the waker of the task to wake after
621    /// the lock. `lost` is the dropped count of the event queue, if it was read.
622    fn push(&self, batch: Vec<Q::Item>, skipped: u64, lost: Option<Result<i64>>) -> Option<Waker> {
623        let mut state = self.lock();
624        if state.closed {
625            return None;
626        }
627        state.skipped += skipped;
628        Self::update_lost(&mut state, lost);
629        if batch.is_empty() {
630            return None;
631        }
632        state.items.extend(batch);
633        if let Some(capacity) = self.capacity
634            && state.items.len() > capacity
635        {
636            let excess = state.items.len() - capacity;
637            state.items.drain(..excess);
638            state.dropped += excess as u64;
639        }
640        state.demand = false;
641        state.waker.take()
642    }
643
644    /// Ends the stream and returns the waker of the task to wake after the lock. `lost` is the dropped count of the
645    /// event queue, if it was read.
646    fn end_with(&self, lost: Option<Result<i64>>) -> Option<Waker> {
647        let mut state = self.lock();
648        Self::update_lost(&mut state, lost);
649        state.closed = true;
650        state.waker.take()
651    }
652
653    /// Stores the dropped count of the event queue, which never decreases; one that cannot be read, such as after
654    /// shutdown, keeps the last one.
655    fn update_lost(state: &mut State<Q::Item>, lost: Option<Result<i64>>) {
656        if let Some(Ok(lost)) = lost {
657            state.dropped = state.dropped.max(u64::try_from(lost).unwrap_or(0));
658        }
659    }
660
661    /// Ends the stream: at once for a listener; for an event queue, after its thread has taken what the queue still
662    /// holds.
663    fn finish(&self) {
664        let Some(source) = &self.source else {
665            wake(self.end_with(None));
666            return;
667        };
668        {
669            let mut state = self.lock();
670            if state.closed || state.finishing {
671                return;
672            }
673            state.finishing = true;
674        }
675        self.requests.notify_one();
676        // Ends a poll in progress. It fails only when the queue is closed or the SDK is shut down, which end the poll.
677        let _ = source.wake_up();
678    }
679
680    /// Whether the subscription is attached to a feed of `endpoint` (to any feed when it is `None`), and whether the
681    /// endpoints of all its feeds are closed then; a shared queue is attached to every endpoint, never all closed.
682    fn feeds_of(&self, endpoint: Option<&EndpointState>) -> (bool, bool) {
683        match &self.feeds {
684            Feeds::Of(feeds) => feeds_of(feeds, endpoint),
685            Feeds::Any => (true, false),
686        }
687    }
688
689    /// Ends the stream if the endpoints of all the feeds of the subscription are closed and, when `endpoint` is given,
690    /// it is one of them; otherwise a stream of an event queue that drained it for `endpoint` alone takes its events
691    /// on demand again.
692    fn check_feeds(&self, endpoint: Option<&EndpointState>) {
693        let drained = {
694            let mut state = self.lock();
695            if state.closed {
696                return;
697            }
698            let draining = state.draining.len();
699            if let Some(endpoint) = endpoint {
700                let address = address_of(endpoint);
701                state.draining.retain(|&closing| closing != address);
702            }
703            draining > 0 && state.draining.is_empty()
704        };
705        match self.feeds_of(endpoint) {
706            (_, true) => self.finish(),
707            (true, false) => {
708                if drained && let Some(source) = &self.source {
709                    // Ends the poll that drains, so that the thread polls on demand again.
710                    let _ = source.wake_up();
711                }
712            }
713            (false, false) => {}
714        }
715    }
716
717    /// Makes the thread of a stream of an event queue poll it without demand, if the subscription is attached to a
718    /// feed of `endpoint`, which is about to wait for the events that the queue holds.
719    fn drain_for(&self, endpoint: &EndpointState) {
720        if self.source.is_none() || !self.feeds_of(Some(endpoint)).0 {
721            return;
722        }
723        {
724            let mut state = self.lock();
725            if state.closed {
726                return;
727            }
728            state.draining.push(address_of(endpoint));
729        }
730        self.requests.notify_one();
731    }
732
733    /// The thread of a stream of an event queue. It polls the queue while a task waits for events, while an endpoint
734    /// of the subscription waits for its termination, and before the stream ends; it exits once the stream has ended.
735    fn run(self: Arc<Self>) {
736        let ran = panic::catch_unwind(AssertUnwindSafe(|| self.poll_source()));
737        if ran.is_err()
738            && let Some(source) = &self.source
739        {
740            // The queue that no thread polls any more would hold back the termination of its endpoints.
741            let _ = source.close();
742            let waker = self.end_with(Some(source.get_dropped_events()));
743            error_manager::report_panic(
744                self.component,
745                "the waker of an event stream",
746                panic::catch_unwind(AssertUnwindSafe(|| wake(waker))),
747            );
748        }
749        error_manager::report_panic(self.component, "the thread of an event stream", ran);
750    }
751
752    fn poll_source(&self) {
753        let Some(source) = &self.source else {
754            return;
755        };
756        loop {
757            let (finishing, timeout) = {
758                let mut state = self.lock();
759                loop {
760                    if state.closed {
761                        return;
762                    }
763                    if state.finishing {
764                        break (true, Some(Duration::ZERO));
765                    }
766                    if state.demand {
767                        break (false, None);
768                    }
769                    // A wake-up goes to a poll that returns events, so the drain must not rely on one to end: it
770                    // polls with a short timeout and looks at the requests again.
771                    if !state.draining.is_empty() {
772                        break (false, Some(DRAIN_POLL));
773                    }
774                    state = self.requests.wait(state).unwrap_or_else(PoisonError::into_inner);
775                }
776            };
777            match source.poll_items(timeout, BATCH) {
778                Ok(PollResult::Events((batch, skipped))) => {
779                    let waker = self.push(batch, skipped, Some(source.get_dropped_events()));
780                    // A panic of the waker goes to the error manager, as one in a listener does, and the stream goes
781                    // on.
782                    error_manager::report_panic(
783                        self.component,
784                        "the waker of an event stream",
785                        panic::catch_unwind(AssertUnwindSafe(|| wake(waker))),
786                    );
787                }
788                // The queue holds nothing more: the stream ends.
789                Ok(PollResult::NoEvents) if finishing => {
790                    let _ = source.close();
791                    return wake(self.end_with(Some(source.get_dropped_events())));
792                }
793                // A wake-up, or the timeout of a drain: look at the requests again.
794                Ok(PollResult::NoEvents) => {}
795                Ok(PollResult::Closed) | Err(Error::ShutDown) => {
796                    return wake(self.end_with(Some(source.get_dropped_events())));
797                }
798                Err(error) => {
799                    ErrorManager::report_error(self.component, &error);
800                    let _ = source.close();
801                    return wake(self.end_with(Some(source.get_dropped_events())));
802                }
803            }
804        }
805    }
806}
807
808/// Whether `feeds` hold a feed of `endpoint` (any feed when it is `None`), and whether the endpoints of all of them are
809/// closed then; `(false, false)` once the owner of the feeds is gone.
810pub(crate) fn feeds_of(feeds: &Weak<Mutex<Vec<DXFeed>>>, endpoint: Option<&EndpointState>) -> (bool, bool) {
811    let Some(feeds) = feeds.upgrade() else {
812        return (false, false);
813    };
814    let feeds = crate::lock(&feeds);
815    let attached = !feeds.is_empty() && endpoint.is_none_or(|endpoint| feeds.iter().any(|feed| feed.is_of(endpoint)));
816    (attached, attached && feeds.iter().all(DXFeed::is_closed))
817}
818
819/// The address of `endpoint`, which tells it apart from the other endpoints while it is alive.
820fn address_of(endpoint: &EndpointState) -> usize {
821    std::ptr::from_ref(endpoint) as usize
822}
823
824/// Wakes the task of `waker`, if any.
825fn wake(waker: Option<Waker>) {
826    if let Some(waker) = waker {
827        waker.wake();
828    }
829}
830
831impl<Q: Source> Terminate for Queue<Q> {
832    fn terminate(&self) {
833        self.finish();
834    }
835
836    fn endpoint_closed(&self, endpoint: &EndpointState) {
837        self.check_feeds(Some(endpoint));
838    }
839
840    fn endpoint_closing(&self, endpoint: &EndpointState) {
841        self.drain_for(endpoint);
842    }
843}
844
845/// The change listener that ends the stream when the subscription is closed.
846struct Closer<E: SubscriptionItem>(Arc<Queue<EventQueue<E>>>);
847
848impl<E: SubscriptionItem> ObservableSubscriptionChangeListener for Closer<E> {
849    fn symbols_added(&mut self, _symbols: &[Symbol]) {}
850
851    fn subscription_closed(&mut self) {
852        self.0.finish();
853    }
854}
855
856impl<E: SubscriptionItem> AsRef<DXFeedSubscription<E>> for DXFeedSubscription<E> {
857    fn as_ref(&self) -> &DXFeedSubscription<E> {
858        self
859    }
860}
861
862impl<E: SubscriptionItem> AsRef<DXFeedSubscription<E>> for DXFeedTimeSeriesSubscription<E> {
863    fn as_ref(&self) -> &DXFeedSubscription<E> {
864        self
865    }
866}