sbom_tools/tui/viewmodel/
filter.rs1pub trait CycleFilter: Clone + Copy + Default {
50 #[must_use]
52 fn next(&self) -> Self;
53
54 #[must_use]
56 fn prev(&self) -> Self;
57
58 fn display_name(&self) -> &str;
60}
61
62#[derive(Debug, Clone)]
67pub struct FilterState<F: CycleFilter> {
68 pub current: F,
70}
71
72impl<F: CycleFilter> Default for FilterState<F> {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl<F: CycleFilter> FilterState<F> {
79 #[must_use]
81 pub fn new() -> Self {
82 Self {
83 current: F::default(),
84 }
85 }
86
87 pub const fn with_filter(filter: F) -> Self {
89 Self { current: filter }
90 }
91
92 pub fn next(&mut self) {
94 self.current = self.current.next();
95 }
96
97 pub fn prev(&mut self) {
99 self.current = self.current.prev();
100 }
101
102 pub const fn set(&mut self, filter: F) {
104 self.current = filter;
105 }
106
107 pub fn reset(&mut self) {
109 self.current = F::default();
110 }
111
112 pub fn display_name(&self) -> &str {
114 self.current.display_name()
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
124 enum TestFilter {
125 #[default]
126 All,
127 FilterA,
128 FilterB,
129 }
130
131 impl CycleFilter for TestFilter {
132 fn next(&self) -> Self {
133 match self {
134 Self::All => Self::FilterA,
135 Self::FilterA => Self::FilterB,
136 Self::FilterB => Self::All,
137 }
138 }
139
140 fn prev(&self) -> Self {
141 match self {
142 Self::All => Self::FilterB,
143 Self::FilterA => Self::All,
144 Self::FilterB => Self::FilterA,
145 }
146 }
147
148 fn display_name(&self) -> &str {
149 match self {
150 Self::All => "All Items",
151 Self::FilterA => "Filter A",
152 Self::FilterB => "Filter B",
153 }
154 }
155 }
156
157 #[test]
158 fn test_filter_state_cycling() {
159 let mut state = FilterState::<TestFilter>::new();
160
161 assert_eq!(state.current, TestFilter::All);
162 assert_eq!(state.display_name(), "All Items");
163
164 state.next();
165 assert_eq!(state.current, TestFilter::FilterA);
166 assert_eq!(state.display_name(), "Filter A");
167
168 state.next();
169 assert_eq!(state.current, TestFilter::FilterB);
170
171 state.next();
172 assert_eq!(state.current, TestFilter::All);
173
174 state.prev();
175 assert_eq!(state.current, TestFilter::FilterB);
176 }
177
178 #[test]
179 fn test_filter_state_set_reset() {
180 let mut state = FilterState::<TestFilter>::new();
181
182 state.set(TestFilter::FilterB);
183 assert_eq!(state.current, TestFilter::FilterB);
184
185 state.reset();
186 assert_eq!(state.current, TestFilter::All);
187 }
188
189 #[test]
190 fn test_filter_state_with_initial() {
191 let state = FilterState::with_filter(TestFilter::FilterA);
192 assert_eq!(state.current, TestFilter::FilterA);
193 }
194}