Skip to main content

ph_eventing/
traits.rs

1//! Common traits for event producers and consumers.
2//!
3//! These traits abstract over the different ring buffer types so that
4//! generic code can work with any combination of producer and consumer.
5//!
6//! | Trait | Role | Implementors |
7//! |-------|------|-------------|
8//! | [`Sink`] | Accept events | [`RingBuf`], [`seq_ring::Producer`], [`event_buf::Producer`] |
9//! | [`Source`] | Yield events | [`seq_ring::Consumer`], [`event_buf::Consumer`] |
10//! | [`Link`] | Both — accept *and* yield | Blanket impl for any `Sink<In> + Source<Out>` |
11//! | [`LatestSink`] | Publish a newest value | [`latest_buf::Producer`](crate::latest_buf::Producer) |
12//! | [`LatestSource`] | Take the newest value with replacement/skipped evidence | [`latest_buf::Consumer`](crate::latest_buf::Consumer) |
13//!
14//! [`forward`] bridges `Source` into `Sink` only — the stream pair.
15//! `LatestBuf`'s handles implement the latest-value pair instead, by decision
16//! D2: `try_pop` cannot report the displacement that is that channel's
17//! designed overload behaviour.
18//!
19//! The free function [`forward`] transfers items from any [`Source`] to any
20//! [`Sink`], stopping when the source is empty or the sink rejects a value.
21//!
22//! [`RingBuf`]: crate::RingBuf
23//! [`seq_ring::Producer`]: crate::seq_ring::Producer
24//! [`seq_ring::Consumer`]: crate::seq_ring::Consumer
25//! [`event_buf::Producer`]: crate::event_buf::Producer
26//! [`event_buf::Consumer`]: crate::event_buf::Consumer
27
28/// Accept events.
29///
30/// `Error` is the type returned when the sink cannot accept the value.
31/// Sinks that never reject (e.g. overwrite rings) use
32/// [`core::convert::Infallible`].
33///
34/// # Implementors
35/// - [`crate::RingBuf`] — always succeeds (`Error = Infallible`).
36/// - [`crate::seq_ring::Producer`] — always succeeds (`Error = Infallible`).
37/// - [`crate::event_buf::Producer`] — returns `Err(val)` when full (`Error = T`).
38pub trait Sink<T> {
39    /// The error returned when the sink cannot accept the value.
40    type Error;
41
42    /// Push a value into the sink.
43    ///
44    /// Returns `Ok(())` on success or `Err(Self::Error)` when the sink is
45    /// unable to accept the value.
46    fn try_push(&mut self, val: T) -> Result<(), Self::Error>;
47}
48
49/// Yield events.
50///
51/// # Implementors
52/// - [`crate::seq_ring::Consumer`] — drains the next in-order item.
53/// - [`crate::event_buf::Consumer`] — pops the oldest buffered item.
54pub trait Source<T> {
55    /// Pull the next event, or `None` if nothing is available.
56    fn try_pop(&mut self) -> Option<T>;
57}
58
59/// Publish complete newest-state values with replacement evidence.
60///
61/// Unlike [`Sink`], this trait exposes whether an unread older value was
62/// displaced by the publication.
63pub trait LatestSink<T> {
64    /// Publish `value` and report its generation and any replacement.
65    fn publish_latest(&mut self, value: T) -> crate::latest_buf::PublishReport;
66}
67
68/// Take the latest complete state together with generation and gap evidence.
69///
70/// This is deliberately distinct from FIFO-oriented [`Source`].
71pub trait LatestSource<T> {
72    /// Claim the newest unread publication, or return `None` when empty.
73    fn try_take_latest(&mut self) -> Option<crate::latest_buf::LatestItem<T>>;
74}
75
76/// A bidirectional pass-through: accepts `In` and yields `Out`.
77///
78/// This is automatically implemented for any type that is both
79/// [`Sink<In>`] and [`Source<Out>`].
80pub trait Link<In, Out>: Sink<In> + Source<Out> {}
81
82impl<In, Out, L> Link<In, Out> for L where L: Sink<In> + Source<Out> {}
83
84/// Transfer up to `max` items from a [`Source`] into a [`Sink`].
85///
86/// Stops early if the source is empty or the sink returns an error.
87/// Returns `(transferred, last_error)` — `last_error` is `Some` only if
88/// the sink rejected a value.
89///
90/// # Example
91/// ```
92/// use ph_eventing::{EventBuf, SeqRing};
93/// use ph_eventing::traits::{Sink, Source, forward};
94///
95/// let seq = SeqRing::<u32, 8>::new();
96/// let sp = seq.try_producer().expect("producer");
97/// let mut sc = seq.try_consumer().expect("consumer");
98///
99/// sp.push(1);
100/// sp.push(2);
101///
102/// let eb = EventBuf::<u32, 8>::new();
103/// let mut ep = eb.try_producer().expect("producer");
104///
105/// let (n, err) = forward(&mut sc, &mut ep, 10);
106/// assert_eq!(n, 2);
107/// assert!(err.is_none());
108/// ```
109pub fn forward<T, S, K>(src: &mut S, snk: &mut K, max: usize) -> (usize, Option<K::Error>)
110where
111    S: Source<T>,
112    K: Sink<T>,
113{
114    let mut count = 0;
115    while count < max {
116        let val = match src.try_pop() {
117            Some(v) => v,
118            None => break,
119        };
120        match snk.try_push(val) {
121            Ok(()) => count += 1,
122            Err(e) => return (count, Some(e)),
123        }
124    }
125    (count, None)
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use crate::{EventBuf, RingBuf, SeqRing};
132
133    // ── Sink tests ─────────────────────────────────────────────────
134
135    #[test]
136    fn ringbuf_as_sink() {
137        let mut ring = RingBuf::<u32, 4>::new();
138        assert!(ring.try_push(1).is_ok());
139        assert!(ring.try_push(2).is_ok());
140        assert_eq!(ring.len(), 2);
141    }
142
143    #[test]
144    fn seq_producer_as_sink() {
145        let ring = SeqRing::<u32, 4>::new();
146        let mut p = ring.try_producer().unwrap();
147        assert!(p.try_push(10).is_ok());
148        assert!(p.try_push(20).is_ok());
149    }
150
151    #[test]
152    fn event_producer_as_sink() {
153        let buf = EventBuf::<u32, 2>::new();
154        let mut p = buf.try_producer().unwrap();
155        assert!(p.try_push(1).is_ok());
156        assert!(p.try_push(2).is_ok());
157        assert_eq!(p.try_push(3), Err(3));
158    }
159
160    // ── Source tests ───────────────────────────────────────────────
161
162    #[test]
163    fn seq_consumer_as_source() {
164        let ring = SeqRing::<u32, 4>::new();
165        let p = ring.try_producer().unwrap();
166        let mut c = ring.try_consumer().unwrap();
167
168        p.push(10);
169        p.push(20);
170
171        assert_eq!(c.try_pop(), Some(10));
172        assert_eq!(c.try_pop(), Some(20));
173        assert_eq!(c.try_pop(), None);
174    }
175
176    #[test]
177    fn event_consumer_as_source() {
178        let buf = EventBuf::<u32, 4>::new();
179        let p = buf.try_producer().unwrap();
180        let mut c = buf.try_consumer().unwrap();
181
182        p.push(10).unwrap();
183        p.push(20).unwrap();
184
185        assert_eq!(c.try_pop(), Some(10));
186        assert_eq!(c.try_pop(), Some(20));
187        assert_eq!(c.try_pop(), None);
188    }
189
190    // ── forward tests ──────────────────────────────────────────────
191
192    #[test]
193    fn forward_seq_to_event() {
194        let seq = SeqRing::<u32, 8>::new();
195        let sp = seq.try_producer().unwrap();
196        let mut sc = seq.try_consumer().unwrap();
197
198        sp.push(1);
199        sp.push(2);
200        sp.push(3);
201
202        let eb = EventBuf::<u32, 8>::new();
203        let mut ep = eb.try_producer().unwrap();
204
205        let (n, err) = forward(&mut sc, &mut ep, 10);
206        assert_eq!(n, 3);
207        assert!(err.is_none());
208
209        let ec = eb.try_consumer().unwrap();
210        assert_eq!(ec.pop(), Some(1));
211        assert_eq!(ec.pop(), Some(2));
212        assert_eq!(ec.pop(), Some(3));
213    }
214
215    #[test]
216    fn forward_event_to_ringbuf() {
217        let eb = EventBuf::<u32, 8>::new();
218        let ep = eb.try_producer().unwrap();
219        let mut ec = eb.try_consumer().unwrap();
220
221        ep.push(10).unwrap();
222        ep.push(20).unwrap();
223
224        let mut ring = RingBuf::<u32, 4>::new();
225
226        let (n, err) = forward(&mut ec, &mut ring, 10);
227        assert_eq!(n, 2);
228        assert!(err.is_none());
229        assert_eq!(ring.get(0), Some(10));
230        assert_eq!(ring.get(1), Some(20));
231    }
232
233    #[test]
234    fn forward_stops_when_sink_full() {
235        let src_buf = EventBuf::<u32, 8>::new();
236        let sp = src_buf.try_producer().unwrap();
237        let mut sc = src_buf.try_consumer().unwrap();
238
239        for i in 0..5 {
240            sp.push(i).unwrap();
241        }
242
243        let dst_buf = EventBuf::<u32, 2>::new();
244        let mut dp = dst_buf.try_producer().unwrap();
245
246        let (n, err) = forward(&mut sc, &mut dp, 10);
247        assert_eq!(n, 2);
248        assert_eq!(err, Some(2)); // third item rejected
249    }
250
251    #[test]
252    fn forward_empty_source_transfers_nothing() {
253        let seq = SeqRing::<u32, 4>::new();
254        let _sp = seq.try_producer().unwrap();
255        let mut sc = seq.try_consumer().unwrap();
256
257        let eb = EventBuf::<u32, 4>::new();
258        let mut ep = eb.try_producer().unwrap();
259
260        let (n, err) = forward(&mut sc, &mut ep, 10);
261        assert_eq!(n, 0);
262        assert!(err.is_none());
263    }
264
265    // ── generic helper to prove trait-generic code compiles ────────
266
267    fn drain_all_into_vec<T: Copy, S: Source<T>>(src: &mut S) -> std::vec::Vec<T> {
268        let mut out = std::vec::Vec::new();
269        while let Some(v) = src.try_pop() {
270            out.push(v);
271        }
272        out
273    }
274
275    #[test]
276    fn generic_drain_seq() {
277        let ring = SeqRing::<u32, 4>::new();
278        let p = ring.try_producer().unwrap();
279        let mut c = ring.try_consumer().unwrap();
280
281        p.push(1);
282        p.push(2);
283        p.push(3);
284
285        let v = drain_all_into_vec(&mut c);
286        assert_eq!(v, [1, 2, 3]);
287    }
288
289    #[test]
290    fn generic_drain_event() {
291        let buf = EventBuf::<u32, 4>::new();
292        let p = buf.try_producer().unwrap();
293        let mut c = buf.try_consumer().unwrap();
294
295        p.push(1).unwrap();
296        p.push(2).unwrap();
297
298        let v = drain_all_into_vec(&mut c);
299        assert_eq!(v, [1, 2]);
300    }
301}