sim_lib_stream_combinators/
ops.rs1mod nodes;
2
3use std::sync::{Arc, Mutex};
4
5use sim_kernel::{Cx, Diagnostic, Error, Event, Expr, Ref, Result, Symbol, Tick};
6use sim_lib_stream_core::{ClockTickIndex, StreamDiagnostic, StreamItem, StreamPacket};
7
8use crate::stream::Stream;
9
10pub type StreamStage = Box<dyn Fn(Stream) -> Stream + Send + Sync>;
16
17type MapFn = Arc<dyn Fn(StreamItem) -> Result<StreamItem> + Send + Sync>;
18type DataMapFn = Arc<dyn Fn(Expr) -> Result<Expr> + Send + Sync>;
19type PredicateFn = Arc<dyn Fn(&StreamItem) -> Result<bool> + Send + Sync>;
20type ShapePredicateFn = Arc<dyn Fn(&Expr) -> Result<bool> + Send + Sync>;
21type TapFn = Arc<dyn Fn(&StreamItem) -> Result<()> + Send + Sync>;
22type DiagnosticTapFn = Arc<dyn Fn(&StreamDiagnostic) -> Result<()> + Send + Sync>;
23type MergeKeyFn = Arc<dyn Fn(&StreamItem) -> Result<Option<ClockTickIndex>> + Send + Sync>;
24type ClockConvertFn =
25 Arc<dyn Fn(&StreamItem) -> Result<(Vec<Tick>, Vec<Diagnostic>)> + Send + Sync>;
26
27pub fn pipe(source: Stream, stages: Vec<StreamStage>) -> Stream {
56 stages
57 .into_iter()
58 .fold(source, |stream, stage| stage(stream))
59}
60
61pub fn identity() -> StreamStage {
63 Box::new(|stream| stream)
64}
65
66pub fn map<F>(source: Stream, f: F) -> Stream
68where
69 F: Fn(StreamItem) -> Result<StreamItem> + Send + Sync + 'static,
70{
71 nodes::map_with(source, Arc::new(f))
72}
73
74pub fn map_stage<F>(f: F) -> StreamStage
76where
77 F: Fn(StreamItem) -> Result<StreamItem> + Send + Sync + 'static,
78{
79 let f: MapFn = Arc::new(f);
80 Box::new(move |source| nodes::map_with(source, Arc::clone(&f)))
81}
82
83pub fn map_data_expr<F>(source: Stream, f: F) -> Stream
87where
88 F: Fn(Expr) -> Result<Expr> + Send + Sync + 'static,
89{
90 nodes::map_data_expr_with(source, Arc::new(f))
91}
92
93pub fn map_data_expr_stage<F>(f: F) -> StreamStage
95where
96 F: Fn(Expr) -> Result<Expr> + Send + Sync + 'static,
97{
98 let f: DataMapFn = Arc::new(f);
99 Box::new(move |source| nodes::map_data_expr_with(source, Arc::clone(&f)))
100}
101
102pub fn filter<F>(source: Stream, pred: F) -> Stream
104where
105 F: Fn(&StreamItem) -> Result<bool> + Send + Sync + 'static,
106{
107 nodes::filter_with(source, Arc::new(pred))
108}
109
110pub fn filter_stage<F>(pred: F) -> StreamStage
112where
113 F: Fn(&StreamItem) -> Result<bool> + Send + Sync + 'static,
114{
115 let pred: PredicateFn = Arc::new(pred);
116 Box::new(move |source| nodes::filter_with(source, Arc::clone(&pred)))
117}
118
119pub fn filter_data_kind(source: Stream, kind: Symbol) -> Stream {
121 nodes::filter_with(
122 source,
123 Arc::new(move |item| match item.packet() {
124 StreamPacket::Data(packet) => Ok(packet.kind == kind),
125 _ => Ok(false),
126 }),
127 )
128}
129
130pub fn filter_data_kind_stage(kind: Symbol) -> StreamStage {
132 Box::new(move |source| filter_data_kind(source, kind.clone()))
133}
134
135pub fn filter_data_shape<F>(source: Stream, matches: F) -> Stream
139where
140 F: Fn(&Expr) -> Result<bool> + Send + Sync + 'static,
141{
142 nodes::filter_data_shape_with(source, Arc::new(matches))
143}
144
145pub fn filter_data_shape_stage<F>(matches: F) -> StreamStage
147where
148 F: Fn(&Expr) -> Result<bool> + Send + Sync + 'static,
149{
150 let matches: ShapePredicateFn = Arc::new(matches);
151 Box::new(move |source| nodes::filter_data_shape_with(source, Arc::clone(&matches)))
152}
153
154pub fn tap<F>(source: Stream, f: F) -> Stream
156where
157 F: Fn(&StreamItem) -> Result<()> + Send + Sync + 'static,
158{
159 nodes::tap_with(source, Arc::new(f))
160}
161
162pub fn tap_stage<F>(f: F) -> StreamStage
164where
165 F: Fn(&StreamItem) -> Result<()> + Send + Sync + 'static,
166{
167 let f: TapFn = Arc::new(f);
168 Box::new(move |source| nodes::tap_with(source, Arc::clone(&f)))
169}
170
171pub fn tap_diagnostics<F>(source: Stream, f: F) -> Stream
175where
176 F: Fn(&StreamDiagnostic) -> Result<()> + Send + Sync + 'static,
177{
178 nodes::tap_diagnostics_with(source, Arc::new(f))
179}
180
181pub fn tap_diagnostics_stage<F>(f: F) -> StreamStage
183where
184 F: Fn(&StreamDiagnostic) -> Result<()> + Send + Sync + 'static,
185{
186 let f: DiagnosticTapFn = Arc::new(f);
187 Box::new(move |source| nodes::tap_diagnostics_with(source, Arc::clone(&f)))
188}
189
190pub fn take(source: Stream, limit: usize) -> Stream {
192 nodes::take_with_limit(source, limit)
193}
194
195pub fn take_stage(limit: usize) -> StreamStage {
197 Box::new(move |source| take(source, limit))
198}
199
200pub fn window_by_count(source: Stream, count: usize) -> Stream {
207 nodes::window_by_count(source, count)
208}
209
210pub fn window_by_count_stage(count: usize) -> StreamStage {
212 Box::new(move |source| window_by_count(source, count))
213}
214
215pub fn stream_window_data_kind() -> Symbol {
217 Symbol::qualified("stream/data", "window")
218}
219
220pub fn merge(left: Stream, right: Stream) -> Stream {
224 nodes::merge_with_key(left, right, Arc::new(|_| Ok(None)))
225}
226
227pub fn merge_by_clock(left: Stream, right: Stream, clock: Symbol) -> Stream {
232 nodes::merge_with_key(
233 left,
234 right,
235 Arc::new(move |item| {
236 item.ticks().iter().try_fold(None, |found, tick| {
237 sim_lib_stream_core::tick_clock_index(tick, &clock).map(|parsed| found.or(parsed))
238 })
239 }),
240 )
241}
242
243pub struct Fanout {
245 pub left: Stream,
247 pub right: Stream,
249}
250
251pub fn fan(source: Stream) -> Fanout {
256 let (left, right) = nodes::fan_readers(source);
257 Fanout { left, right }
258}
259
260pub struct ClockConvertedStream {
266 stream: Stream,
267 diagnostics: Arc<Mutex<Vec<Diagnostic>>>,
268}
269
270impl ClockConvertedStream {
271 pub fn stream(&self) -> &Stream {
273 &self.stream
274 }
275
276 pub fn into_stream(self) -> Stream {
278 self.stream
279 }
280
281 pub fn next_packet(&self) -> Result<Option<StreamItem>> {
283 self.stream.next_packet()
284 }
285
286 pub fn diagnostics(&self) -> Result<Vec<Diagnostic>> {
288 self.diagnostics
289 .lock()
290 .map_err(|_| Error::PoisonedLock("clock-convert diagnostics"))
291 .map(|diagnostics| diagnostics.clone())
292 }
293}
294
295pub fn clock_convert<F>(source: Stream, convert: F) -> ClockConvertedStream
301where
302 F: Fn(&StreamItem) -> Result<(Vec<Tick>, Vec<Diagnostic>)> + Send + Sync + 'static,
303{
304 let diagnostics = Arc::new(Mutex::new(Vec::new()));
305 ClockConvertedStream {
306 stream: nodes::clock_convert_stream(source, Arc::new(convert), Arc::clone(&diagnostics)),
307 diagnostics,
308 }
309}
310
311pub fn run_bang(stream: &Stream, cx: &mut Cx, run: Ref, start_seq: u64) -> Result<Vec<Event>> {
316 stream.run_events(cx, run, start_seq)
317}