Skip to main content

aimdb_core/transform/
mod.rs

1//! Reactive transform primitives for derived records.
2//!
3//! # Transform Archetypes
4//!
5//! - **Map** (1:1, stateless): Transform each input value to zero-or-one output value
6//! - **Accumulate** (N:1, stateful): Aggregate a stream of values with persistent state
7//! - **Join** (M×N:1, stateful, multi-input): Combine values from multiple input records
8//!
9//! All three are handled by a unified API surface:
10//! - Single-input: `.transform()` with `TransformBuilder`
11//! - Multi-input: `.transform_join()` with `JoinBuilder`
12
13use core::fmt::Debug;
14
15use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
16
17use crate::typed_record::BoxFuture;
18
19pub mod join;
20pub mod single;
21
22// Public re-exports
23pub use single::{StatefulTransformBuilder, TransformBuilder, TransformPipeline};
24
25#[cfg(feature = "observability")]
26use crate::{profiling::Clock, StageMetrics};
27pub use join::{JoinBuilder, JoinEventRx, JoinPipeline, JoinTrigger};
28
29// ============================================================================
30// TransformDescriptor — stored per output record in TypedRecord
31// ============================================================================
32
33/// Futures contributed by a transform at build-time collection.
34///
35/// `task_future` is the transform's main event loop; `fanin_futures` is any
36/// per-input forwarder needed for multi-input joins (empty for single-input).
37pub(crate) struct CollectedTransform {
38    pub task_future: BoxFuture<'static, ()>,
39    pub fanin_futures: Vec<BoxFuture<'static, ()>>,
40}
41
42#[cfg(feature = "observability")]
43pub(crate) type TransformProfiling = Option<(Arc<StageMetrics>, Clock)>;
44
45#[cfg(not(feature = "observability"))]
46pub(crate) type TransformProfiling = ();
47
48pub(crate) struct TransformDescriptor<T>
49where
50    T: Send + 'static + Debug + Clone,
51{
52    pub input_keys: Vec<String>,
53
54    /// Build the transform's futures.
55    ///
56    /// Receives:
57    /// - `Producer<T>` — the pre-resolved write handle for the output record.
58    /// - `Arc<AimDb>` — used by input forwarders to resolve their input
59    ///   consumers at startup time.
60    /// - `&str` — the output record's key, threaded through so the transform
61    ///   task can include it in tracing messages even though `Producer<T>` no
62    ///   longer carries a `.key()` accessor. Important when
63    ///   multiple records share type `T` under different keys.
64    #[allow(clippy::type_complexity)]
65    pub build_fn: Box<
66        dyn FnOnce(
67                crate::Producer<T>,
68                Arc<crate::AimDb>,
69                &str,
70                TransformProfiling,
71            ) -> CollectedTransform
72            + Send,
73    >,
74}