1pub mod props {
2 include!("lightspeed.props.rs");
3}
4
5pub mod devices {
6 include!("lightspeed.devices.rs");
7 pub mod actions {
8 include!("lightspeed.devices.actions.rs");
9 }
10}
11
12pub mod request {
13 include!("lightspeed.request.rs");
14}
15
16pub mod response {
17 include!("lightspeed.response.rs");
18}
19
20pub mod service {
21 include!("lightspeed.service.rs");
22}
23
24pub mod proto {
25 pub const FD_DESCRIPTOR_SET: &[u8] = include_bytes!("lightspeed.bin");
26}
27
28pub mod properties {
29 use serde::{Deserialize, Serialize};
30
31 #[derive(Debug)]
32 pub enum PermissionError {
33 CannotUpdateReadOnlyProp,
34 }
35
36 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
37 pub enum Permission {
38 ReadOnly = 0,
39 ReadWrite,
40 }
41
42 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
43 struct Range<T> {
44 min: T,
45 max: T,
46 }
47
48 impl<T> Range<T> {
49 fn new(min: T, max: T) -> Self {
50 Self { min, max }
51 }
52
53 fn max(&self) -> &T {
54 &self.max
55 }
56
57 fn min(&self) -> &T {
58 &self.min
59 }
60 }
61
62 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
63 #[serde(deny_unknown_fields)]
64 pub struct Property<T> {
65 #[serde(rename = "value")]
66 val: T,
67 permission: Permission,
68 range: Option<Range<T>>,
69 }
70
71 impl<T> Property<T> {
72 pub fn new(value: T, permission: Permission, range: Option<(T, T)>) -> Self {
73 if let Some(r) = range {
74 return Self {
75 val: value,
76 permission,
77 range: Some(Range::new(r.0, r.1)),
78 };
79 } else {
80 return Self {
81 val: value,
82 permission,
83 range: None,
84 };
85 }
86 }
87
88 pub fn value(&self) -> &T {
89 &self.val
90 }
91
92 fn update_allowed(&self) -> Result<(), PermissionError> {
93 if self.permission == Permission::ReadOnly {
94 Err(PermissionError::CannotUpdateReadOnlyProp)
95 } else {
96 Ok(())
97 }
98 }
99
100 pub fn update(&mut self, value: T) -> Result<(), PermissionError> {
103 self.update_allowed()?;
104 self.val = value;
105 Ok(())
106 }
107
108 pub fn set_val(&mut self, value: T) {
111 self.val = value;
112 }
113 }
114
115 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
116 pub struct BoolProperty {
117 value: bool,
118 permission: Permission,
119 }
120
121 impl BoolProperty {
122 pub fn new(value: bool, permission: Permission) -> Self {
123 Self { value, permission }
124 }
125
126 fn update_allowed(&self) -> Result<(), PermissionError> {
127 if self.permission == Permission::ReadOnly {
128 Err(PermissionError::CannotUpdateReadOnlyProp)
129 } else {
130 Ok(())
131 }
132 }
133
134 pub fn update(&mut self) -> Result<(), PermissionError> {
135 self.update_allowed()?;
136 self.value = !self.value;
137 Ok(())
138 }
139 }
140
141 #[cfg(test)]
142 mod unit_tests {
143 use super::{BoolProperty, Permission, Property};
144 use std::borrow::Cow;
145
146 #[test]
147 fn test_bool_prop_initialization() {
148 let p = BoolProperty::new(false, Permission::ReadOnly);
149 assert_eq!(p.value, false);
150 }
151
152 #[test]
153 fn test_bool_prop_readonly_cannot_be_updated() -> Result<(), String> {
154 let mut p = BoolProperty::new(false, Permission::ReadOnly);
155 match p.update() {
156 Ok(()) => Err(String::from(
157 "It should not be possible to update a ReadOnly property",
158 )),
159 Err(_) => {
160 assert_eq!(p.value, false);
161 Ok(())
162 }
163 }
164 }
165
166 #[test]
167 fn test_bool_prop_readwrite_can_be_written() -> Result<(), String> {
168 let mut p = BoolProperty::new(false, Permission::ReadWrite);
169 match p.update() {
170 Ok(()) => {
171 assert_eq!(p.value, true);
172 Ok(())
173 }
174 Err(_) => Err(String::from(
175 "It MUST be possible to update a WriteOnly property",
176 )),
177 }
178 }
179
180 #[test]
181 fn test_numeric_prop_readonly_cannot_be_updated() -> Result<(), String> {
182 let mut p: Property<u64> = Property::new(78, Permission::ReadOnly, None);
183 match p.update(55) {
184 Ok(()) => Err(String::from(
185 "It should not be possible to update a ReadOnly property",
186 )),
187 Err(_) => {
188 assert_eq!(p.value(), &78_u64);
189 Ok(())
190 }
191 }
192 }
193
194 #[test]
195 fn test_numeric_prop_readwrite_can_be_written() -> Result<(), String> {
196 let mut p = Property::<u64>::new(78, Permission::ReadWrite, None);
197 match p.update(55) {
198 Ok(()) => {
199 assert_eq!(p.value(), &55_u64);
200 Ok(())
201 }
202 Err(_) => Err(String::from(
203 "It MUST be possible to update a WriteOnly property",
204 )),
205 }
206 }
207
208 #[test]
209 fn test_cow_borrow_prop_readwrite_can_be_written() -> Result<(), String> {
210 let mut p = Property::<Cow<'static, str>>::new(
211 Cow::Borrowed("test"),
212 Permission::ReadWrite,
213 None,
214 );
215 match p.update(Cow::Borrowed("done")) {
216 Ok(()) => {
217 assert_eq!(p.value(), "done");
218 Ok(())
219 }
220 Err(_) => Err(String::from(
221 "It MUST be possible to update a WriteOnly property",
222 )),
223 }
224 }
225
226 #[test]
227 fn test_cow_owned_prop_readwrite_can_be_written() -> Result<(), String> {
228 let mut p = Property::<Cow<'static, str>>::new(
229 Cow::Owned(String::from("test")),
230 Permission::ReadWrite,
231 None,
232 );
233 match p.update(Cow::Owned(String::from("done"))) {
234 Ok(()) => {
235 assert_eq!(p.value(), "done");
236 Ok(())
237 }
238 Err(_) => Err(String::from(
239 "It MUST be possible to update a WriteOnly property",
240 )),
241 }
242 }
243
244 #[test]
245 fn test_str_prop_initialization_no_range() {
246 let test_str = String::from("test");
247 let p = Property::new(test_str.clone(), Permission::ReadOnly, None);
248 assert_eq!(p.value(), &test_str);
249 }
250
251 #[test]
252 fn test_num_prop_initialization_no_range() {
253 let test_val = 5;
254 let p = Property::new(test_val.clone(), Permission::ReadOnly, None);
255 assert_eq!(p.value(), &test_val);
256 }
257
258 #[test]
259 fn test_float_prop_initialization_no_range() {
260 let test_val = 5.32_f64;
261 let p = Property::new(test_val.clone(), Permission::ReadOnly, None);
262 assert_eq!(p.value(), &test_val);
263 }
264
265 #[test]
266 fn test_float_prop_initialization_range() {
267 let test_val = 5.32_f64;
268 let min_range = 10.0_f64;
269 let max_range = 100.0_f64;
270 let p = Property::new(
271 test_val.clone(),
272 Permission::ReadOnly,
273 Some((min_range.clone(), max_range.clone())),
274 );
275 assert_eq!(p.range.unwrap().min(), &min_range);
276 assert_eq!(p.range.unwrap().max(), &max_range);
277 }
278 }
279
280 #[cfg(test)]
281 mod serialization_tests {
282 use super::{BoolProperty, Permission, Property};
283
284 #[test]
285 fn test_serialize_num_prop_no_range() {
286 let p = Property::new(5, Permission::ReadOnly, None);
287 let serialized = serde_json::to_string(&p).unwrap();
288 assert_eq!(
289 serialized,
290 r#"{"value":5,"permission":"ReadOnly","range":null}"#
291 );
292 }
293
294 #[test]
295 fn test_serialize_num_prop_with_range() {
296 let p = Property::new(5, Permission::ReadOnly, Some((1, 100)));
297 let serialized = serde_json::to_string(&p).unwrap();
298 assert_eq!(
299 serialized,
300 r#"{"value":5,"permission":"ReadOnly","range":{"min":1,"max":100}}"#
301 );
302 }
303
304 #[test]
305 fn test_serialize_bool_prop() {
306 let p = BoolProperty::new(true, Permission::ReadOnly);
307 let serialized = serde_json::to_string(&p).unwrap();
308 assert_eq!(serialized, r#"{"value":true,"permission":"ReadOnly"}"#);
309 }
310 }
311}