Skip to main content

rx_rust/utils/
pending_events.rs

1use crate::observer::{Event, Termination};
2use educe::Educe;
3use std::collections::VecDeque;
4
5/// One atomic batch of events to queue.
6#[derive(Educe)]
7#[educe(Debug, Clone, PartialEq, Eq)]
8pub enum EventBatch<T, E> {
9    Next(T),
10    Termination(Termination<E>),
11    NextAndTermination(T, Termination<E>),
12    NextBatch(Vec<T>),
13    NextBatchAndTermination(Vec<T>, Termination<E>),
14}
15
16impl<T, E> EventBatch<T, E> {
17    /// Returns whether the batch carries a termination, after which nothing can be queued.
18    pub fn ends_stream(&self) -> bool {
19        matches!(
20            self,
21            Self::Termination(_) | Self::NextAndTermination(..) | Self::NextBatchAndTermination(..)
22        )
23    }
24}
25
26/// The events waiting to be delivered to an observer.
27///
28/// A termination is the last event of a stream, so it is queued last and nothing is queued after
29/// it. Queuing anything after it gives the event back instead of accepting it: the caller drops it
30/// outside of the lock that guards this queue, because dropping a value can run arbitrary code
31/// that re-enters that lock.
32#[derive(Educe)]
33#[educe(Debug)]
34pub struct PendingEvents<T, E> {
35    values: VecDeque<T>,
36    termination: Option<Termination<E>>,
37}
38
39impl<T, E> PendingEvents<T, E> {
40    pub fn new() -> Self {
41        Self {
42            values: VecDeque::new(),
43            termination: None,
44        }
45    }
46
47    pub fn with_capacity(capacity: usize) -> Self {
48        Self {
49            values: VecDeque::with_capacity(capacity),
50            termination: None,
51        }
52    }
53
54    /// Splits `events` into the value to deliver first and the queue holding what follows it.
55    ///
56    /// The queue is built here, so it is never already terminated and nothing can be given back.
57    /// The first value is handed to the caller instead of being queued, so a batch carrying a
58    /// single value leaves the queue empty and never allocates it.
59    pub fn from_batch(events: EventBatch<T, E>) -> (Option<T>, Self) {
60        let empty_queue = |termination| Self {
61            values: VecDeque::new(),
62            termination,
63        };
64        // A batch of many values is turned into the queue directly, which reuses its allocation,
65        // and the first value is then taken off the front.
66        let queue_batch = |values: Vec<T>, termination| {
67            let mut values = VecDeque::from(values);
68            let first_next = values.pop_front();
69            (
70                first_next,
71                Self {
72                    values,
73                    termination,
74                },
75            )
76        };
77        match events {
78            EventBatch::Next(value) => (Some(value), empty_queue(None)),
79            EventBatch::Termination(termination) => (None, empty_queue(Some(termination))),
80            EventBatch::NextAndTermination(value, termination) => {
81                (Some(value), empty_queue(Some(termination)))
82            }
83            EventBatch::NextBatch(values) => queue_batch(values, None),
84            EventBatch::NextBatchAndTermination(values, termination) => {
85                queue_batch(values, Some(termination))
86            }
87        }
88    }
89
90    /// Returns whether the last event has been queued, after which nothing can be queued anymore.
91    pub fn is_terminated(&self) -> bool {
92        self.termination.is_some()
93    }
94
95    /// Returns whether there is nothing left to deliver.
96    pub fn is_empty(&self) -> bool {
97        self.values.is_empty() && self.termination.is_none()
98    }
99
100    /// Queues `event`, or gives it back when the last event has already been queued.
101    #[must_use = "a rejected event must be dropped outside the lock that guards these events"]
102    pub fn push(&mut self, event: Event<T, E>) -> Option<Event<T, E>> {
103        if self.is_terminated() {
104            return Some(event);
105        }
106        match event {
107            Event::Next(value) => self.values.push_back(value),
108            Event::Termination(termination) => self.termination = Some(termination),
109        }
110        None
111    }
112
113    /// Queues `events`, or gives them back when the last event has already been queued.
114    ///
115    /// A batch is queued as a whole: it holds at most one termination and queues it last, so no
116    /// event of a batch can be rejected on its own.
117    #[must_use = "rejected events must be dropped outside the lock that guards these events"]
118    pub fn push_batch(&mut self, events: EventBatch<T, E>) -> Option<EventBatch<T, E>> {
119        if self.is_terminated() {
120            return Some(events);
121        }
122        match events {
123            EventBatch::Next(value) => self.values.push_back(value),
124            EventBatch::Termination(termination) => self.termination = Some(termination),
125            EventBatch::NextAndTermination(value, termination) => {
126                self.values.push_back(value);
127                self.termination = Some(termination);
128            }
129            EventBatch::NextBatch(values) => self.values.extend(values),
130            EventBatch::NextBatchAndTermination(values, termination) => {
131                self.values.extend(values);
132                self.termination = Some(termination);
133            }
134        }
135        None
136    }
137
138    /// Takes the next event to deliver, which is the termination once no value is left.
139    pub fn pop(&mut self) -> Option<Event<T, E>> {
140        match self.pop_next() {
141            Some(value) => Some(Event::Next(value)),
142            None => self.take_termination().map(Event::Termination),
143        }
144    }
145
146    /// Takes the next value to deliver, leaving the termination in place.
147    pub fn pop_next(&mut self) -> Option<T> {
148        self.values.pop_front()
149    }
150
151    /// Takes the last event, whether or not values are still queued before it.
152    pub fn take_termination(&mut self) -> Option<Termination<E>> {
153        self.termination.take()
154    }
155}
156
157impl<T, E> Default for PendingEvents<T, E> {
158    fn default() -> Self {
159        Self::new()
160    }
161}