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}