byteor_pipeline_exec/
registry.rs

1//! Stage registry helpers.
2//!
3//! These helpers are intended for ergonomic stage resolution at startup.
4//!
5//! Design goals:
6//! - zero cost in hot loops: stages resolve once, then executors run specialized loops
7//! - small surface: avoid turning stage registration into a DSL
8//! - cold-path linear search is acceptable (resolution is not per-message)
9
10use crate::{ResolvedStage, StageResolver};
11
12/// Factory function for producing a [`ResolvedStage`].
13///
14/// Notes:
15/// - called during role startup (cold path)
16/// - may allocate if returning [`ResolvedStage::Stateful`] or [`ResolvedStage::StatefulTransform`]
17pub type ResolvedStageFactory = fn() -> ResolvedStage;
18
19/// One named stage entry for use with [`SliceStageRegistry`].
20#[derive(Clone, Copy)]
21pub struct StageEntry {
22    /// Stable stage name.
23    pub name: &'static str,
24    /// Factory for the resolved stage callable.
25    pub factory: ResolvedStageFactory,
26}
27
28/// A minimal slice-based stage registry.
29///
30/// This is the intended default for simple runtimes: define a `static` slice of stage entries and
31/// resolve by name.
32///
33/// ```
34/// use byteor_pipeline_exec::{ResolvedStage, SliceStageRegistry, StageEntry, StageResolver};
35///
36/// fn identity() -> ResolvedStage {
37///     ResolvedStage::MapOk(|input, output| {
38///         let n = input.len().min(output.len());
39///         output[..n].copy_from_slice(&input[..n]);
40///         n
41///     })
42/// }
43///
44/// static STAGES: &[StageEntry] = &[StageEntry { name: "identity", factory: identity }];
45///
46/// let reg = SliceStageRegistry::new(STAGES);
47/// assert!(reg.resolve("identity").is_some());
48/// ```
49pub struct SliceStageRegistry {
50    entries: &'static [StageEntry],
51}
52
53impl SliceStageRegistry {
54    /// Create a registry from a slice of stage entries.
55    pub const fn new(entries: &'static [StageEntry]) -> Self {
56        Self { entries }
57    }
58
59    /// Access the underlying entries.
60    pub fn entries(&self) -> &'static [StageEntry] {
61        self.entries
62    }
63}
64
65impl StageResolver for SliceStageRegistry {
66    fn resolve(&self, stage: &str) -> Option<ResolvedStage> {
67        self.entries
68            .iter()
69            .find(|e| e.name == stage)
70            .map(|e| (e.factory)())
71    }
72}