Skip to main content

camel_api/
loop_eip.rs

1use crate::filter::PredicateSource;
2
3/// How the loop terminates.
4#[derive(Clone)]
5#[non_exhaustive]
6pub enum LoopMode {
7    /// Fixed iteration count.
8    Count(usize),
9    /// While a runtime predicate evaluates to true. Evaluation is fallible:
10    /// a failed predicate ends the loop with that error (never as loop-end
11    /// success).
12    While(PredicateSource),
13}
14
15impl std::fmt::Debug for LoopMode {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        match self {
18            LoopMode::Count(n) => write!(f, "Count({n})"),
19            LoopMode::While(_) => write!(f, "While(<predicate>)"),
20        }
21    }
22}
23
24#[derive(Clone, Debug)]
25pub struct LoopConfig {
26    pub mode: LoopMode,
27    pub max_iterations: usize,
28}
29
30impl LoopConfig {
31    pub fn new(mode: LoopMode) -> Self {
32        Self {
33            mode,
34            max_iterations: MAX_LOOP_ITERATIONS,
35        }
36    }
37
38    pub fn with_max_iterations(mut self, max: usize) -> Self {
39        self.max_iterations = max;
40        self
41    }
42
43    pub fn mode_name(&self) -> &'static str {
44        match &self.mode {
45            LoopMode::Count(_) => "count",
46            LoopMode::While(_) => "while",
47        }
48    }
49}
50
51/// Maximum iterations for while-mode loops. Prevents infinite loops.
52pub const MAX_LOOP_ITERATIONS: usize = 10_000;
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    use crate::filter::{FilterPredicate, PredicateSource};
58
59    fn always_true() -> PredicateSource {
60        PredicateSource::Sync(FilterPredicate::new(|_| true))
61    }
62
63    #[test]
64    fn loop_config_new_count() {
65        let cfg = LoopConfig::new(LoopMode::Count(5));
66        assert_eq!(cfg.mode_name(), "count");
67    }
68
69    #[test]
70    fn loop_config_new_while() {
71        let cfg = LoopConfig::new(LoopMode::While(always_true()));
72        assert_eq!(cfg.mode_name(), "while");
73    }
74
75    #[test]
76    fn loop_mode_debug_count() {
77        let mode = LoopMode::Count(3);
78        assert_eq!(format!("{mode:?}"), "Count(3)");
79    }
80
81    #[test]
82    fn loop_mode_debug_while() {
83        let mode = LoopMode::While(always_true());
84        assert_eq!(format!("{mode:?}"), "While(<predicate>)");
85    }
86
87    #[test]
88    fn loop_mode_clone_count() {
89        let mode = LoopMode::Count(10);
90        let cloned = mode.clone();
91        assert_eq!(format!("{cloned:?}"), "Count(10)");
92    }
93
94    #[test]
95    fn loop_config_clone() {
96        let cfg = LoopConfig::new(LoopMode::Count(2));
97        let cloned = cfg.clone();
98        assert_eq!(cloned.mode_name(), "count");
99    }
100
101    #[test]
102    fn max_loop_iterations_value() {
103        assert_eq!(MAX_LOOP_ITERATIONS, 10_000);
104    }
105
106    #[test]
107    fn loop_config_default_max_iterations() {
108        let cfg = LoopConfig::new(LoopMode::Count(5));
109        assert_eq!(cfg.max_iterations, MAX_LOOP_ITERATIONS);
110    }
111
112    #[test]
113    fn loop_config_with_max_iterations() {
114        let cfg = LoopConfig::new(LoopMode::Count(5)).with_max_iterations(500_000);
115        assert_eq!(cfg.max_iterations, 500_000);
116    }
117}