raspberry_web/
validation.rs1use crate::errors::RpWebError;
2use crate::settings::GpioConfig;
3pub fn vec_option_to_vec(option: &Option<Vec<i32>>) -> Vec<i32> {
7 match option {
8 Some(vec) => vec.to_vec(),
9 None => vec![],
10 }
11}
12
13fn elements_in_both_vecs(u: &Vec<i32>, v: &Vec<i32>) -> Option<Vec<i32>> {
15 let mut res = vec![];
16
17 for &idx in u.iter() {
19 if v.contains(&idx) {
20 res.push(idx);
21 }
22 }
23
24 if !res.is_empty() {
26 return Some(res);
27 } else {
28 return None;
29 }
30}
31
32pub fn validate_setup(gpioconfig: &GpioConfig) -> Result<(), RpWebError> {
33 let gpios_in_use = vec_option_to_vec(&gpioconfig.gpios_in_use);
40 let gpios_mode_output = vec_option_to_vec(&gpioconfig.gpios_mode_output);
41 let gpios_mode_input = vec_option_to_vec(&gpioconfig.gpios_mode_input);
42 let gpios_level_low = vec_option_to_vec(&gpioconfig.gpios_level_low);
43 let gpios_level_high = vec_option_to_vec(&gpioconfig.gpios_level_high);
44
45 let mut gpio_all_levels: Vec<i32> = vec![];
47 gpio_all_levels.append(&mut gpios_level_low.to_vec());
48 gpio_all_levels.append(&mut gpios_level_high.to_vec());
49
50 if gpios_in_use.is_empty() {
52 if !gpio_all_levels.is_empty() {
53 return Err(RpWebError::new(
54 "Invalid configuration: gpio_levels_* is set, but gpios_in_use is empty",
55 ));
56 }
57 }
58 if gpios_mode_output.is_empty() {
60 if !gpio_all_levels.is_empty() {
61 return Err(RpWebError::new(
62 "Invalid configuration: gpios_level_* is set, but gpios_mode_output is empty",
63 ));
64 }
65 }
66
67 for idx in gpio_all_levels.iter() {
69 if !gpios_in_use.contains(idx) {
71 let errs = format!(
72 "Invalid configuration: GPIO #{} is not in_use, but a level is set for it",
73 idx
74 );
75 return Err(RpWebError::new(&errs));
76 }
77
78 if !gpios_mode_output.contains(idx) {
80 let errs = format!(
81 "Invalid configuration: GPIO #{} is not configured to OUTPUT, but a level is set for it", idx);
82 return Err(RpWebError::new(&errs));
83 }
84 }
85
86 let both_high_and_low_option = elements_in_both_vecs(&gpios_level_low, &gpios_level_high);
88 if let Some(high_and_low) = both_high_and_low_option {
89 let errs = format!(
90 "Invalid configuration: GPIO(s) {:?} in both gpios_level_low and gpios_level_high",
91 high_and_low
92 );
93 return Err(RpWebError::new(&errs));
94 }
95
96 let both_input_and_output_option = elements_in_both_vecs(&gpios_mode_input, &gpios_mode_output);
98 if let Some(input_and_output) = both_input_and_output_option {
99 let errs = format!(
100 "Invalid configuration: GPIO(s) {:?} in both gpios_mode_input and gpios_mode_output",
101 input_and_output
102 );
103 return Err(RpWebError::new(&errs));
104 }
105
106 Ok(())
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn validation_in_use_none_but_level_set_must_fail() {
115 let gpioconfig = GpioConfig {
116 gpios_in_use: None,
117 gpios_mode_output: Some(vec![1]),
118 gpios_mode_input: None,
119 gpios_level_low: Some(vec![1]),
120 gpios_level_high: None,
121 };
122
123 let res = validate_setup(&gpioconfig);
124 assert!(res.is_err());
125 }
126
127 #[test]
128 fn validation_in_use_not_set_but_level_set_must_fail() {
129 let gpioconfig = GpioConfig {
130 gpios_in_use: Some(vec![2]),
131 gpios_mode_output: Some(vec![2]),
132 gpios_mode_input: None,
133 gpios_level_low: Some(vec![1]),
134 gpios_level_high: None,
135 };
136
137 let res = validate_setup(&gpioconfig);
138 assert!(res.is_err());
139 }
140
141 #[test]
142 fn validation_mode_output_none_but_level_set_must_fail() {
143 let gpioconfig = GpioConfig {
144 gpios_in_use: Some(vec![1]),
145 gpios_mode_output: None,
146 gpios_mode_input: None,
147 gpios_level_low: Some(vec![1]),
148 gpios_level_high: None,
149 };
150
151 let res = validate_setup(&gpioconfig);
152 assert!(res.is_err());
153 }
154
155 #[test]
156 fn validation_mode_output_not_set_but_level_set_must_fail() {
157 let gpioconfig = GpioConfig {
158 gpios_in_use: Some(vec![1]),
159 gpios_mode_output: Some(vec![2]),
160 gpios_mode_input: None,
161 gpios_level_low: Some(vec![1]),
162 gpios_level_high: None,
163 };
164
165 let res = validate_setup(&gpioconfig);
166 assert!(res.is_err());
167 }
168
169 #[test]
170 fn validation_in_use_not_set_for_pin_level_set_must_fail() {
171 let gpioconfig = GpioConfig {
172 gpios_in_use: Some(vec![1, 2]),
173 gpios_mode_output: Some(vec![1, 2, 3]),
174 gpios_mode_input: None,
175 gpios_level_low: Some(vec![3]),
176 gpios_level_high: None,
177 };
178
179 let res = validate_setup(&gpioconfig);
180 assert!(res.is_err());
181 }
182
183 #[test]
184 fn validation_mode_output_not_set_for_pin_level_high_set_must_fail() {
185 let gpioconfig = GpioConfig {
186 gpios_in_use: Some(vec![1, 2, 3]),
187 gpios_mode_output: Some(vec![1, 2]),
188 gpios_mode_input: None,
189 gpios_level_low: Some(vec![3]),
190 gpios_level_high: None,
191 };
192
193 let res = validate_setup(&gpioconfig);
194 assert!(res.is_err());
195 }
196
197 #[test]
198 fn validation_same_pin_high_and_low_must_fail() {
199 let gpioconfig = GpioConfig {
200 gpios_in_use: Some(vec![1, 2]),
201 gpios_mode_output: Some(vec![1, 2]),
202 gpios_mode_input: None,
203 gpios_level_low: Some(vec![1]),
204 gpios_level_high: Some(vec![1]),
205 };
206
207 let res = validate_setup(&gpioconfig);
208 assert!(res.is_err());
209 }
210
211 #[test]
212 fn validation_same_pin_input_and_output_must_fail() {
213 let gpioconfig = GpioConfig {
214 gpios_in_use: Some(vec![1]),
215 gpios_mode_output: Some(vec![1]),
216 gpios_mode_input: Some(vec![1]),
217 gpios_level_low: None,
218 gpios_level_high: None,
219 };
220
221 let res = validate_setup(&gpioconfig);
222 assert!(res.is_err());
223 }
224
225 #[test]
226 fn validation_valid_setup_must_succeed() {
227 let gpioconfig = GpioConfig {
228 gpios_in_use: Some(vec![1, 2, 3]),
229 gpios_mode_output: Some(vec![1, 2, 3]),
230 gpios_mode_input: None,
231 gpios_level_low: Some(vec![1]),
232 gpios_level_high: Some(vec![2, 3]),
233 };
234
235 let res = validate_setup(&gpioconfig);
236
237 assert!(res.is_ok());
238 }
239}