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//!
12//! The free function [`forward`] transfers items from any [`Source`] to any
13//! [`Sink`], stopping when the source is empty or the sink rejects a value.
14//!
15//! [`RingBuf`]: crate::RingBuf
16//! [`seq_ring::Producer`]: crate::seq_ring::Producer
17//! [`seq_ring::Consumer`]: crate::seq_ring::Consumer
18//! [`event_buf::Producer`]: crate::event_buf::Producer
19//! [`event_buf::Consumer`]: crate::event_buf::Consumer
20
21/// Accept events.
22///
23/// `Error` is the type returned when the sink cannot accept the value.
24/// Sinks that never reject (e.g. overwrite rings) use
25/// [`core::convert::Infallible`].
26///
27/// # Implementors
28/// - [`crate::RingBuf`] — always succeeds (`Error = Infallible`).
29/// - [`crate::seq_ring::Producer`] — always succeeds (`Error = Infallible`).
30/// - [`crate::event_buf::Producer`] — returns `Err(val)` when full (`Error = T`).
31pub trait Sink<T> {
32    /// The error returned when the sink cannot accept the value.
33    type Error;
34
35    /// Push a value into the sink.
36    ///
37    /// Returns `Ok(())` on success or `Err(Self::Error)` when the sink is
38    /// unable to accept the value.
39    fn try_push(&mut self, val: T) -> Result<(), Self::Error>;
40}
41
42/// Yield events.
43///
44/// # Implementors
45/// - [`crate::seq_ring::Consumer`] — drains the next in-order item.
46/// - [`crate::event_buf::Consumer`] — pops the oldest buffered item.
47pub trait Source<T> {
48    /// Pull the next event, or `None` if nothing is available.
49    fn try_pop(&mut self) -> Option<T>;
50}
51
52/// A bidirectional pass-through: accepts `In` and yields `Out`.
53///
54/// This is automatically implemented for any type that is both
55/// [`Sink<In>`] and [`Source<Out>`].
56pub trait Link<In, Out>: Sink<In> + Source<Out> {}
57
58impl<In, Out, L> Link<In, Out> for L where L: Sink<In> + Source<Out> {}
59
60/// Transfer up to `max` items from a [`Source`] into a [`Sink`].
61///
62/// Stops early if the source is empty or the sink returns an error.
63/// Returns `(transferred, last_error)` — `last_error` is `Some` only if
64/// the sink rejected a value.
65///
66/// # Example
67/// ```
68/// use ph_eventing::{EventBuf, SeqRing};
69/// use ph_eventing::traits::{Sink, Source, forward};
70///
71/// let seq = SeqRing::<u32, 8>::new();
72/// let sp = seq.try_producer().expect("producer");
73/// let mut sc = seq.try_consumer().expect("consumer");
74///
75/// sp.push(1);
76/// sp.push(2);
77///
78/// let eb = EventBuf::<u32, 8>::new();
79/// let mut ep = eb.try_producer().expect("producer");
80///
81/// let (n, err) = forward(&mut sc, &mut ep, 10);
82/// assert_eq!(n, 2);
83/// assert!(err.is_none());
84/// ```
85pub fn forward<T, S, K>(src: &mut S, snk: &mut K, max: usize) -> (usize, Option<K::Error>)
86where
87    S: Source<T>,
88    K: Sink<T>,
89{
90    let mut count = 0;
91    while count < max {
92        let val = match src.try_pop() {
93            Some(v) => v,
94            None => break,
95        };
96        match snk.try_push(val) {
97            Ok(()) => count += 1,
98            Err(e) => return (count, Some(e)),
99        }
100    }
101    (count, None)
102}
103
104#[cfg(test)]
105mod tests {
106    // The deprecated `producer()` / `consumer()` remain public API until 0.3.0,
107    // so these tests are their coverage -- including the two that assert the
108    // panic message. Allowing the lint here rather than at the crate root keeps
109    // the warning live for library code, which is where it should bite.
110    #![allow(deprecated)]
111
112    use super::*;
113    use crate::{EventBuf, RingBuf, SeqRing};
114
115    // ── Sink tests ─────────────────────────────────────────────────
116
117    #[test]
118    fn ringbuf_as_sink() {
119        let mut ring = RingBuf::<u32, 4>::new();
120        assert!(ring.try_push(1).is_ok());
121        assert!(ring.try_push(2).is_ok());
122        assert_eq!(ring.len(), 2);
123    }
124
125    #[test]
126    fn seq_producer_as_sink() {
127        let ring = SeqRing::<u32, 4>::new();
128        let mut p = ring.producer();
129        assert!(p.try_push(10).is_ok());
130        assert!(p.try_push(20).is_ok());
131    }
132
133    #[test]
134    fn event_producer_as_sink() {
135        let buf = EventBuf::<u32, 2>::new();
136        let mut p = buf.producer();
137        assert!(p.try_push(1).is_ok());
138        assert!(p.try_push(2).is_ok());
139        assert_eq!(p.try_push(3), Err(3));
140    }
141
142    // ── Source tests ───────────────────────────────────────────────
143
144    #[test]
145    fn seq_consumer_as_source() {
146        let ring = SeqRing::<u32, 4>::new();
147        let p = ring.producer();
148        let mut c = ring.consumer();
149
150        p.push(10);
151        p.push(20);
152
153        assert_eq!(c.try_pop(), Some(10));
154        assert_eq!(c.try_pop(), Some(20));
155        assert_eq!(c.try_pop(), None);
156    }
157
158    #[test]
159    fn event_consumer_as_source() {
160        let buf = EventBuf::<u32, 4>::new();
161        let p = buf.producer();
162        let mut c = buf.consumer();
163
164        p.push(10).unwrap();
165        p.push(20).unwrap();
166
167        assert_eq!(c.try_pop(), Some(10));
168        assert_eq!(c.try_pop(), Some(20));
169        assert_eq!(c.try_pop(), None);
170    }
171
172    // ── forward tests ──────────────────────────────────────────────
173
174    #[test]
175    fn forward_seq_to_event() {
176        let seq = SeqRing::<u32, 8>::new();
177        let sp = seq.producer();
178        let mut sc = seq.consumer();
179
180        sp.push(1);
181        sp.push(2);
182        sp.push(3);
183
184        let eb = EventBuf::<u32, 8>::new();
185        let mut ep = eb.producer();
186
187        let (n, err) = forward(&mut sc, &mut ep, 10);
188        assert_eq!(n, 3);
189        assert!(err.is_none());
190
191        let ec = eb.consumer();
192        assert_eq!(ec.pop(), Some(1));
193        assert_eq!(ec.pop(), Some(2));
194        assert_eq!(ec.pop(), Some(3));
195    }
196
197    #[test]
198    fn forward_event_to_ringbuf() {
199        let eb = EventBuf::<u32, 8>::new();
200        let ep = eb.producer();
201        let mut ec = eb.consumer();
202
203        ep.push(10).unwrap();
204        ep.push(20).unwrap();
205
206        let mut ring = RingBuf::<u32, 4>::new();
207
208        let (n, err) = forward(&mut ec, &mut ring, 10);
209        assert_eq!(n, 2);
210        assert!(err.is_none());
211        assert_eq!(ring.get(0), Some(10));
212        assert_eq!(ring.get(1), Some(20));
213    }
214
215    #[test]
216    fn forward_stops_when_sink_full() {
217        let src_buf = EventBuf::<u32, 8>::new();
218        let sp = src_buf.producer();
219        let mut sc = src_buf.consumer();
220
221        for i in 0..5 {
222            sp.push(i).unwrap();
223        }
224
225        let dst_buf = EventBuf::<u32, 2>::new();
226        let mut dp = dst_buf.producer();
227
228        let (n, err) = forward(&mut sc, &mut dp, 10);
229        assert_eq!(n, 2);
230        assert_eq!(err, Some(2)); // third item rejected
231    }
232
233    #[test]
234    fn forward_empty_source_transfers_nothing() {
235        let seq = SeqRing::<u32, 4>::new();
236        let _sp = seq.producer();
237        let mut sc = seq.consumer();
238
239        let eb = EventBuf::<u32, 4>::new();
240        let mut ep = eb.producer();
241
242        let (n, err) = forward(&mut sc, &mut ep, 10);
243        assert_eq!(n, 0);
244        assert!(err.is_none());
245    }
246
247    // ── generic helper to prove trait-generic code compiles ────────
248
249    fn drain_all_into_vec<T: Copy, S: Source<T>>(src: &mut S) -> std::vec::Vec<T> {
250        let mut out = std::vec::Vec::new();
251        while let Some(v) = src.try_pop() {
252            out.push(v);
253        }
254        out
255    }
256
257    #[test]
258    fn generic_drain_seq() {
259        let ring = SeqRing::<u32, 4>::new();
260        let p = ring.producer();
261        let mut c = ring.consumer();
262
263        p.push(1);
264        p.push(2);
265        p.push(3);
266
267        let v = drain_all_into_vec(&mut c);
268        assert_eq!(v, [1, 2, 3]);
269    }
270
271    #[test]
272    fn generic_drain_event() {
273        let buf = EventBuf::<u32, 4>::new();
274        let p = buf.producer();
275        let mut c = buf.consumer();
276
277        p.push(1).unwrap();
278        p.push(2).unwrap();
279
280        let v = drain_all_into_vec(&mut c);
281        assert_eq!(v, [1, 2]);
282    }
283}