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("es, 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}