ftui_runtime/tick_strategy/
uniform.rs1use super::{TickDecision, TickStrategy};
4
5#[derive(Debug, Clone, Copy)]
14pub struct Uniform {
15 divisor: u64,
16}
17
18impl Uniform {
19 #[must_use]
23 pub const fn new(divisor: u64) -> Self {
24 Self {
25 divisor: if divisor == 0 { 1 } else { divisor },
26 }
27 }
28
29 #[must_use]
31 pub const fn divisor(&self) -> u64 {
32 self.divisor
33 }
34}
35
36impl Default for Uniform {
37 fn default() -> Self {
38 Self::new(5)
39 }
40}
41
42impl TickStrategy for Uniform {
43 fn should_tick(
44 &mut self,
45 _screen_id: &str,
46 tick_count: u64,
47 _active_screen: &str,
48 ) -> TickDecision {
49 if tick_count.is_multiple_of(self.divisor) {
50 TickDecision::Tick
51 } else {
52 TickDecision::Skip
53 }
54 }
55
56 fn name(&self) -> &str {
57 "Uniform"
58 }
59
60 fn debug_stats(&self) -> Vec<(String, String)> {
61 vec![
62 ("strategy".into(), "Uniform".into()),
63 ("divisor".into(), self.divisor.to_string()),
64 ]
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn divisor_1_always_ticks() {
74 let mut s = Uniform::new(1);
75 for tick in 0..20 {
76 assert_eq!(
77 s.should_tick("x", tick, "active"),
78 TickDecision::Tick,
79 "divisor=1 should always Tick, failed at tick={tick}"
80 );
81 }
82 }
83
84 #[test]
85 fn divisor_5_pattern() {
86 let mut s = Uniform::new(5);
87 for tick in 0..20 {
88 let expected = if tick % 5 == 0 {
89 TickDecision::Tick
90 } else {
91 TickDecision::Skip
92 };
93 assert_eq!(
94 s.should_tick("x", tick, "active"),
95 expected,
96 "divisor=5, tick={tick}"
97 );
98 }
99 }
100
101 #[test]
102 fn divisor_0_clamped_to_1() {
103 let s = Uniform::new(0);
104 assert_eq!(s.divisor(), 1);
105 }
106
107 #[test]
108 fn consistent_across_screen_ids() {
109 let mut s = Uniform::new(3);
110 let d1 = s.should_tick("alpha", 6, "active");
111 let d2 = s.should_tick("beta", 6, "active");
112 assert_eq!(d1, d2);
113 }
114
115 #[test]
116 fn name_is_stable() {
117 assert_eq!(Uniform::new(5).name(), "Uniform");
118 }
119
120 #[test]
121 fn debug_stats_reports_divisor() {
122 let stats = Uniform::new(7).debug_stats();
123 assert!(stats.iter().any(|(k, v)| k == "divisor" && v == "7"));
124 }
125
126 #[test]
127 fn default_is_divisor_5() {
128 assert_eq!(Uniform::default().divisor(), 5);
129 }
130}