1use super::chain::{
9 FatalSlot, Filter, FlatMap, Inspect, Map, OpMeter, OpMeterSlot, StageLifecycle, TryMap,
10 TypedChain,
11};
12use super::handoff::{ChunkConfig, SinkHandoff};
13use super::split::{ErasedBranch, Sink, SinkCtx, SplitEmitter, SplitTerminal, new_branch};
14use super::{Collector, Emitter, RunnableChain};
15use crate::backpressure::InflightBudget;
16use crate::deser::{Deserializer, Owned, RecFamily};
17use crate::error::ErrorPolicy;
18use crate::metrics::{ComponentLabels, DeserMetrics, OperatorMetrics};
19use crate::sink::{RecordRouter, RowEncoder, ShardQueues};
20use std::marker::PhantomData;
21use std::sync::Arc;
22
23pub trait MapFn<In, Out>: FnMut(In) -> Out {}
60impl<G, In, Out> MapFn<In, Out> for G where G: FnMut(In) -> Out {}
61
62pub trait TryMapFn<In, Out, Err>: FnMut(In) -> Result<Out, Err> {}
94impl<G, In, Out, Err> TryMapFn<In, Out, Err> for G where G: FnMut(In) -> Result<Out, Err> {}
95
96pub trait Assemble<Term> {
101 type Out;
103 fn assemble(&self, term: Term) -> Self::Out;
105}
106
107#[derive(Clone, Copy, Debug, Default)]
109pub struct Root;
110
111impl<T> Assemble<T> for Root {
112 type Out = T;
113 fn assemble(&self, term: T) -> T {
114 term
115 }
116}
117
118#[derive(Clone, Debug)]
120pub struct MapPart<Prev, G> {
121 prev: Prev,
122 f: G,
123 meter: OpMeterSlot,
124}
125
126impl<Prev, G: Clone, Term> Assemble<Term> for MapPart<Prev, G>
127where
128 Prev: Assemble<Map<G, Term>>,
129{
130 type Out = Prev::Out;
131 fn assemble(&self, term: Term) -> Self::Out {
132 self.prev.assemble(Map {
133 f: self.f.clone(),
134 next: term,
135 meter: self.meter.clone(),
136 })
137 }
138}
139
140#[derive(Clone, Debug)]
142pub struct FilterPart<Prev, P> {
143 prev: Prev,
144 p: P,
145 meter: OpMeterSlot,
146}
147
148impl<Prev, P: Clone, Term> Assemble<Term> for FilterPart<Prev, P>
149where
150 Prev: Assemble<Filter<P, Term>>,
151{
152 type Out = Prev::Out;
153 fn assemble(&self, term: Term) -> Self::Out {
154 self.prev.assemble(Filter {
155 p: self.p.clone(),
156 next: term,
157 meter: self.meter.clone(),
158 })
159 }
160}
161
162#[derive(Clone, Debug)]
164pub struct InspectPart<Prev, G> {
165 prev: Prev,
166 f: G,
167}
168
169impl<Prev, G: Clone, Term> Assemble<Term> for InspectPart<Prev, G>
170where
171 Prev: Assemble<Inspect<G, Term>>,
172{
173 type Out = Prev::Out;
174 fn assemble(&self, term: Term) -> Self::Out {
175 self.prev.assemble(Inspect {
176 f: self.f.clone(),
177 next: term,
178 })
179 }
180}
181
182#[derive(Clone, Debug)]
184pub struct TryMapPart<Prev, G> {
185 prev: Prev,
186 f: G,
187 policy: ErrorPolicy,
188 component: Arc<str>,
189 meter: OpMeterSlot,
190}
191
192impl<Prev, G: Clone, Term> Assemble<Term> for TryMapPart<Prev, G>
193where
194 Prev: Assemble<TryMap<G, Term>>,
195{
196 type Out = Prev::Out;
197 fn assemble(&self, term: Term) -> Self::Out {
198 self.prev.assemble(TryMap {
199 f: self.f.clone(),
200 next: term,
201 policy: self.policy,
202 component: Arc::clone(&self.component),
203 meter: self.meter.clone(),
204 fatal: FatalSlot(None),
205 })
206 }
207}
208
209#[derive(Clone, Debug)]
211pub struct FlatMapPart<OutF: RecFamily, Prev, G> {
212 prev: Prev,
213 g: G,
214 meter: OpMeterSlot,
215 _out: PhantomData<fn() -> OutF>,
216}
217
218impl<OutF: RecFamily, Prev, G: Clone, Term> Assemble<Term> for FlatMapPart<OutF, Prev, G>
219where
220 Prev: Assemble<FlatMap<OutF, G, Term>>,
221{
222 type Out = Prev::Out;
223 fn assemble(&self, term: Term) -> Self::Out {
224 self.prev.assemble(FlatMap {
225 g: self.g.clone(),
226 next: term,
227 meter: self.meter.clone(),
228 _out: PhantomData,
229 })
230 }
231}
232
233#[derive(Clone, Debug)]
234struct MetricsSpec {
235 pipeline: String,
236 component: String,
237 deser: Arc<DeserMetrics>,
238}
239
240impl MetricsSpec {
241 fn op_handle(&self, idx: usize, kind: &'static str) -> Arc<OperatorMetrics> {
242 let labels = ComponentLabels::new(
243 self.pipeline.clone(),
244 format!("{}.{idx}_{kind}", self.component),
245 kind,
246 );
247 Arc::new(OperatorMetrics::new(&labels))
248 }
249}
250
251fn meter_for(metrics: &Option<MetricsSpec>, idx: usize, kind: &'static str) -> OpMeterSlot {
252 OpMeterSlot(OpMeter::new(
253 metrics.as_ref().map(|m| m.op_handle(idx, kind)),
254 ))
255}
256
257#[derive(Clone, Debug)]
262pub struct ChainBuilder<DF: RecFamily, CurF: RecFamily, D, P> {
263 deser: D,
264 parts: P,
265 deser_policy: ErrorPolicy,
266 metrics: Option<MetricsSpec>,
267 stage_idx: usize,
268 _fam: PhantomData<fn() -> (DF, CurF)>,
269}
270
271pub fn chain<F: RecFamily, D: Deserializer<F>>(deser: D) -> ChainBuilder<F, F, D, Root> {
273 ChainBuilder {
274 deser,
275 parts: Root,
276 deser_policy: ErrorPolicy::Skip,
277 metrics: None,
278 stage_idx: 0,
279 _fam: PhantomData,
280 }
281}
282
283pub fn chain_owned<T, D>(deser: D) -> ChainBuilder<Owned<T>, Owned<T>, D, Root>
285where
286 T: Send + 'static,
287 D: Deserializer<Owned<T>>,
288{
289 chain(deser)
290}
291
292impl<DF: RecFamily, CurF: RecFamily, D, P> ChainBuilder<DF, CurF, D, P> {
293 #[must_use]
300 pub fn with_metrics(
301 mut self,
302 pipeline: impl Into<String>,
303 component: impl Into<String>,
304 ) -> Self {
305 assert_eq!(
306 self.stage_idx, 0,
307 "with_metrics must be called before stages are added"
308 );
309 let pipeline = pipeline.into();
310 let component = component.into();
311 let deser_labels = ComponentLabels::new(
312 pipeline.clone(),
313 format!("{component}.deserializer"),
314 "deserializer",
315 );
316 self.metrics = Some(MetricsSpec {
317 pipeline,
318 component,
319 deser: Arc::new(DeserMetrics::new(&deser_labels)),
320 });
321 self
322 }
323
324 #[must_use]
326 pub fn deser_error_policy(mut self, policy: ErrorPolicy) -> Self {
327 self.deser_policy = policy;
328 self
329 }
330
331 #[must_use]
335 pub fn map_rec<NF, G>(self, f: G) -> ChainBuilder<DF, NF, D, MapPart<P, G>>
336 where
337 NF: RecFamily,
338 G: for<'buf> MapFn<CurF::Rec<'buf>, NF::Rec<'buf>>,
339 {
340 let Self {
341 deser,
342 parts,
343 deser_policy,
344 metrics,
345 stage_idx,
346 _fam,
347 } = self;
348 let meter = meter_for(&metrics, stage_idx, "map");
349 ChainBuilder {
350 deser,
351 parts: MapPart {
352 prev: parts,
353 f,
354 meter,
355 },
356 deser_policy,
357 metrics,
358 stage_idx: stage_idx + 1,
359 _fam: PhantomData,
360 }
361 }
362
363 #[must_use]
366 pub fn try_map_rec<NF, G, E>(
367 self,
368 f: G,
369 policy: ErrorPolicy,
370 ) -> ChainBuilder<DF, NF, D, TryMapPart<P, G>>
371 where
372 NF: RecFamily,
373 G: for<'buf> TryMapFn<CurF::Rec<'buf>, NF::Rec<'buf>, E>,
374 E: std::fmt::Display,
375 {
376 let Self {
377 deser,
378 parts,
379 deser_policy,
380 metrics,
381 stage_idx,
382 _fam,
383 } = self;
384 let meter = meter_for(&metrics, stage_idx, "try_map");
385 ChainBuilder {
386 deser,
387 parts: TryMapPart {
388 prev: parts,
389 f,
390 policy,
391 component: Arc::from(format!("try_map_{stage_idx}")),
392 meter,
393 },
394 deser_policy,
395 metrics,
396 stage_idx: stage_idx + 1,
397 _fam: PhantomData,
398 }
399 }
400
401 #[must_use]
403 pub fn filter<Pr>(self, p: Pr) -> ChainBuilder<DF, CurF, D, FilterPart<P, Pr>>
404 where
405 Pr: for<'buf> FnMut(&CurF::Rec<'buf>) -> bool,
406 {
407 let Self {
408 deser,
409 parts,
410 deser_policy,
411 metrics,
412 stage_idx,
413 _fam,
414 } = self;
415 let meter = meter_for(&metrics, stage_idx, "filter");
416 ChainBuilder {
417 deser,
418 parts: FilterPart {
419 prev: parts,
420 p,
421 meter,
422 },
423 deser_policy,
424 metrics,
425 stage_idx: stage_idx + 1,
426 _fam: PhantomData,
427 }
428 }
429
430 #[must_use]
432 pub fn inspect<G>(self, f: G) -> ChainBuilder<DF, CurF, D, InspectPart<P, G>>
433 where
434 G: for<'buf> FnMut(&CurF::Rec<'buf>),
435 {
436 let Self {
437 deser,
438 parts,
439 deser_policy,
440 metrics,
441 stage_idx,
442 _fam,
443 } = self;
444 ChainBuilder {
445 deser,
446 parts: InspectPart { prev: parts, f },
447 deser_policy,
448 metrics,
449 stage_idx: stage_idx + 1,
450 _fam: PhantomData,
451 }
452 }
453
454 #[must_use]
457 pub fn flat_map<OutF, G>(self, g: G) -> ChainBuilder<DF, OutF, D, FlatMapPart<OutF, P, G>>
458 where
459 OutF: RecFamily,
460 G: for<'buf> FnMut(CurF::Rec<'buf>, &mut Emitter<'_, OutF>),
461 {
462 let Self {
463 deser,
464 parts,
465 deser_policy,
466 metrics,
467 stage_idx,
468 _fam,
469 } = self;
470 let meter = meter_for(&metrics, stage_idx, "flat_map");
471 ChainBuilder {
472 deser,
473 parts: FlatMapPart {
474 prev: parts,
475 g,
476 meter,
477 _out: PhantomData,
478 },
479 deser_policy,
480 metrics,
481 stage_idx: stage_idx + 1,
482 _fam: PhantomData,
483 }
484 }
485
486 #[must_use]
494 pub fn sink<E, R>(
495 self,
496 encoder: E,
497 router: R,
498 cfg: ChunkConfig,
499 queues: ShardQueues,
500 budget: Arc<InflightBudget>,
501 ) -> SinkedChain<DF, CurF, D, P, E, R> {
502 let handoff_meter = meter_for(&self.metrics, self.stage_idx, "sink_handoff");
503 SinkedChain {
504 builder: self,
505 encoder,
506 router,
507 cfg,
508 queues,
509 budget,
510 handoff_meter,
511 }
512 }
513
514 #[must_use]
526 pub fn split(self, unmatched: ErrorPolicy) -> SplitBuilder<DF, CurF, D, P> {
527 SplitBuilder {
528 builder: self,
529 unmatched,
530 branches: Vec::new(),
531 next_idx: 0,
532 }
533 }
534}
535
536impl<DF: RecFamily, T: Send + 'static, D, P> ChainBuilder<DF, Owned<T>, D, P> {
538 #[must_use]
541 pub fn map<U, G>(self, f: G) -> ChainBuilder<DF, Owned<U>, D, MapPart<P, G>>
542 where
543 U: Send + 'static,
544 G: FnMut(T) -> U,
545 {
546 let Self {
547 deser,
548 parts,
549 deser_policy,
550 metrics,
551 stage_idx,
552 _fam,
553 } = self;
554 let meter = meter_for(&metrics, stage_idx, "map");
555 ChainBuilder {
556 deser,
557 parts: MapPart {
558 prev: parts,
559 f,
560 meter,
561 },
562 deser_policy,
563 metrics,
564 stage_idx: stage_idx + 1,
565 _fam: PhantomData,
566 }
567 }
568
569 #[must_use]
572 pub fn try_map<U, G, E>(
573 self,
574 f: G,
575 policy: ErrorPolicy,
576 ) -> ChainBuilder<DF, Owned<U>, D, TryMapPart<P, G>>
577 where
578 U: Send + 'static,
579 G: FnMut(T) -> Result<U, E>,
580 E: std::fmt::Display,
581 {
582 let Self {
583 deser,
584 parts,
585 deser_policy,
586 metrics,
587 stage_idx,
588 _fam,
589 } = self;
590 let meter = meter_for(&metrics, stage_idx, "try_map");
591 ChainBuilder {
592 deser,
593 parts: TryMapPart {
594 prev: parts,
595 f,
596 policy,
597 component: Arc::from(format!("try_map_{stage_idx}")),
598 meter,
599 },
600 deser_policy,
601 metrics,
602 stage_idx: stage_idx + 1,
603 _fam: PhantomData,
604 }
605 }
606}
607
608#[derive(Clone, Debug)]
611pub struct SinkedChain<DF: RecFamily, CurF: RecFamily, D, P, E, R> {
612 builder: ChainBuilder<DF, CurF, D, P>,
613 encoder: E,
614 router: R,
615 cfg: ChunkConfig,
616 queues: ShardQueues,
617 budget: Arc<InflightBudget>,
618 handoff_meter: OpMeterSlot,
619}
620
621impl<DF, CurF, D, P, E, R> SinkedChain<DF, CurF, D, P, E, R>
622where
623 DF: RecFamily,
624 CurF: RecFamily,
625 D: Deserializer<DF> + 'static,
626 P: Assemble<SinkHandoff<CurF, E, R>>,
627 P::Out: for<'buf> Collector<<DF as RecFamily>::Rec<'buf>> + StageLifecycle + Send + 'static,
628 E: RowEncoder<CurF> + Clone + 'static,
629 R: RecordRouter<CurF> + Send + 'static,
630{
631 #[must_use]
636 pub fn build(self) -> Box<dyn RunnableChain> {
637 let SinkedChain {
638 builder,
639 encoder,
640 router,
641 cfg,
642 queues,
643 budget,
644 handoff_meter,
645 } = self;
646 let term = SinkHandoff::new(
647 encoder,
648 router,
649 queues,
650 budget,
651 cfg,
652 handoff_meter,
653 Arc::from("sink_handoff"),
654 );
655 let ops = builder.parts.assemble(term);
656 Box::new(TypedChain::<DF, D, _>::new(
657 builder.deser,
658 ops,
659 builder.deser_policy,
660 builder.metrics.as_ref().map(|m| Arc::clone(&m.deser)),
661 ))
662 }
663
664 #[must_use]
667 pub fn build_factory(self) -> ChainFactory<DF, CurF, D, P, E, R>
668 where
669 D: Clone,
670 E: Clone,
671 R: Clone,
672 {
673 ChainFactory { spec: self }
674 }
675}
676
677#[derive(Clone, Debug)]
680pub struct ChainFactory<DF: RecFamily, CurF: RecFamily, D, P, E, R> {
681 spec: SinkedChain<DF, CurF, D, P, E, R>,
682}
683
684impl<DF, CurF, D, P, E, R> ChainFactory<DF, CurF, D, P, E, R>
685where
686 DF: RecFamily,
687 CurF: RecFamily,
688 D: Deserializer<DF> + Clone + 'static,
689 P: Assemble<SinkHandoff<CurF, E, R>>,
690 P::Out: for<'buf> Collector<<DF as RecFamily>::Rec<'buf>> + StageLifecycle + Send + 'static,
691 E: RowEncoder<CurF> + Clone + 'static,
692 R: RecordRouter<CurF> + Clone + Send + 'static,
693{
694 #[must_use]
696 pub fn make(&self) -> Box<dyn RunnableChain> {
697 let spec = &self.spec;
698 let term = SinkHandoff::new(
699 spec.encoder.clone(),
700 spec.router.clone(),
701 spec.queues.clone(),
702 Arc::clone(&spec.budget),
703 spec.cfg,
704 spec.handoff_meter.clone(),
705 Arc::from("sink_handoff"),
706 );
707 let ops = spec.builder.parts.assemble(term);
708 Box::new(TypedChain::<DF, D, _>::new(
709 spec.builder.deser.clone(),
710 ops,
711 spec.builder.deser_policy,
712 spec.builder.metrics.as_ref().map(|m| Arc::clone(&m.deser)),
713 ))
714 }
715}
716
717pub struct SplitBuilder<DF: RecFamily, CurF: RecFamily, D, P> {
722 builder: ChainBuilder<DF, CurF, D, P>,
723 unmatched: ErrorPolicy,
724 branches: Vec<Box<dyn ErasedBranch>>,
725 next_idx: usize,
726}
727
728impl<DF: RecFamily, CurF: RecFamily, D, P> std::fmt::Debug for SplitBuilder<DF, CurF, D, P> {
729 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
730 f.debug_struct("SplitBuilder")
731 .field("branches", &self.branches.len())
732 .field("unmatched", &self.unmatched)
733 .finish_non_exhaustive()
734 }
735}
736
737impl<DF: RecFamily, CurF: RecFamily, D, P> SplitBuilder<DF, CurF, D, P> {
738 #[must_use = "a dropped Sink<F> handle leaves its branch permanently unreachable"]
745 pub fn add<F, E, R>(&mut self, encoder: E, router: R, sink: SinkCtx) -> Sink<F>
746 where
747 F: RecFamily + 'static,
748 E: RowEncoder<F> + Clone + Send + 'static,
749 R: RecordRouter<F> + 'static,
750 {
751 let idx = self.next_idx;
752 self.next_idx += 1;
753 let meter = OpMeterSlot(OpMeter::new(self.builder.metrics.as_ref().map(|m| {
756 let labels = ComponentLabels::new(
757 m.pipeline.clone(),
758 format!("{}.sink.{}", m.component, sink.name),
759 "sink_handoff",
760 );
761 Arc::new(OperatorMetrics::new(&labels))
762 })));
763 let component: Arc<str> = Arc::from(format!("sink.{}", sink.name));
764 let branch = new_branch::<F, E, R>(
765 encoder,
766 router,
767 sink.queues,
768 sink.budget,
769 sink.chunk,
770 meter,
771 component,
772 );
773 self.branches.push(branch);
774 Sink::new(idx)
775 }
776
777 #[must_use]
782 pub fn route<G>(self, route: G) -> RoutedSplit<DF, CurF, D, P, G>
783 where
784 G: for<'buf> FnMut(CurF::Rec<'buf>, &mut SplitEmitter<'_>) + Send + 'static,
785 {
786 let handoff_meter = meter_for(&self.builder.metrics, self.builder.stage_idx, "split");
787 RoutedSplit {
788 builder: self.builder,
789 unmatched: self.unmatched,
790 branches: self.branches,
791 route,
792 handoff_meter,
793 }
794 }
795}
796
797pub struct RoutedSplit<DF: RecFamily, CurF: RecFamily, D, P, G> {
801 builder: ChainBuilder<DF, CurF, D, P>,
802 unmatched: ErrorPolicy,
803 branches: Vec<Box<dyn ErasedBranch>>,
804 route: G,
805 handoff_meter: OpMeterSlot,
806}
807
808impl<DF: RecFamily, CurF: RecFamily, D, P, G> std::fmt::Debug for RoutedSplit<DF, CurF, D, P, G> {
809 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
810 f.debug_struct("RoutedSplit")
811 .field("branches", &self.branches.len())
812 .field("unmatched", &self.unmatched)
813 .finish_non_exhaustive()
814 }
815}
816
817impl<DF, CurF, D, P, G> RoutedSplit<DF, CurF, D, P, G>
818where
819 DF: RecFamily,
820 CurF: RecFamily,
821 D: Deserializer<DF> + 'static,
822 G: for<'buf> FnMut(CurF::Rec<'buf>, &mut SplitEmitter<'_>) + Send + 'static,
823 P: Assemble<SplitTerminal<CurF, G>>,
824 P::Out: for<'buf> Collector<<DF as RecFamily>::Rec<'buf>> + StageLifecycle + Send + 'static,
825{
826 #[must_use]
828 pub fn build(self) -> Box<dyn RunnableChain> {
829 let RoutedSplit {
830 builder,
831 unmatched,
832 branches,
833 route,
834 handoff_meter,
835 } = self;
836 let term = SplitTerminal::new(
837 route,
838 branches,
839 unmatched,
840 handoff_meter,
841 Arc::from("split"),
842 );
843 let ops = builder.parts.assemble(term);
844 Box::new(TypedChain::<DF, D, _>::new(
845 builder.deser,
846 ops,
847 builder.deser_policy,
848 builder.metrics.as_ref().map(|m| Arc::clone(&m.deser)),
849 ))
850 }
851}