1#[cfg(test)]
7use crate::ParameterStorage;
8use crate::{
9 ParameterDescriptor, ParameterRange, ParameterServer, ParameterType, SetParameterResult,
10};
11use heapless::String;
12
13pub use crate::ParameterVariant;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum ParameterError {
19 TypeMismatch,
21 OutOfRange,
23 ReadOnly,
25 NotFound,
27 StorageFull,
29 StringConversion,
31 InvalidRange,
33}
34
35impl From<SetParameterResult> for ParameterError {
36 fn from(result: SetParameterResult) -> Self {
37 match result {
38 SetParameterResult::TypeMismatch => ParameterError::TypeMismatch,
39 SetParameterResult::OutOfRange => ParameterError::OutOfRange,
40 SetParameterResult::ReadOnly => ParameterError::ReadOnly,
41 SetParameterResult::NotFound => ParameterError::NotFound,
42 SetParameterResult::StorageFull => ParameterError::StorageFull,
43 _ => panic!("Unexpected SetParameterResult"), }
45 }
46}
47
48pub trait RangeConvertible: ParameterVariant + Clone {
50 fn to_parameter_range(
52 range: core::ops::RangeInclusive<Self>,
53 ) -> Result<ParameterRange, ParameterError>;
54}
55
56impl RangeConvertible for i64 {
57 fn to_parameter_range(
58 range: core::ops::RangeInclusive<Self>,
59 ) -> Result<ParameterRange, ParameterError> {
60 Ok(ParameterRange::Integer(crate::IntegerRange::new(
61 *range.start(),
62 *range.end(),
63 1, )))
65 }
66}
67
68impl RangeConvertible for f64 {
69 fn to_parameter_range(
70 range: core::ops::RangeInclusive<Self>,
71 ) -> Result<ParameterRange, ParameterError> {
72 Ok(ParameterRange::FloatingPoint(
73 crate::FloatingPointRange::new(
74 *range.start(),
75 *range.end(),
76 0.0, ),
78 ))
79 }
80}
81
82pub struct ParameterBuilder<'a, 's, T: ParameterVariant> {
84 server: &'a mut ParameterServer<'s>,
88 name: &'a str,
90 default: Option<T>,
92 description: Option<&'a str>,
94 range: Option<ParameterRange>,
96 read_only: bool,
98 _phantom: core::marker::PhantomData<T>,
100}
101
102impl<'a, 's, T: ParameterVariant> ParameterBuilder<'a, 's, T> {
103 pub fn new(server: &'a mut ParameterServer<'s>, name: &'a str) -> Self {
105 Self {
106 server,
107 name,
108 default: None,
109 description: None,
110 range: None,
111 read_only: false,
112 _phantom: core::marker::PhantomData,
113 }
114 }
115
116 pub fn default(mut self, value: T) -> Self {
118 self.default = Some(value);
119 self
120 }
121
122 pub fn description(mut self, desc: &'a str) -> Self {
124 self.description = Some(desc);
125 self
126 }
127
128 pub fn integer_range(mut self, min: i64, max: i64, step: i64) -> Result<Self, ParameterError> {
130 if T::parameter_type() != ParameterType::Integer {
131 return Err(ParameterError::InvalidRange);
132 }
133 self.range = Some(ParameterRange::Integer(crate::IntegerRange::new(
134 min, max, step,
135 )));
136 Ok(self)
137 }
138
139 pub fn float_range(mut self, min: f64, max: f64, step: f64) -> Result<Self, ParameterError> {
141 if T::parameter_type() != ParameterType::Double {
142 return Err(ParameterError::InvalidRange);
143 }
144 self.range = Some(ParameterRange::FloatingPoint(
145 crate::FloatingPointRange::new(min, max, step),
146 ));
147 Ok(self)
148 }
149
150 pub fn range(mut self, range: core::ops::RangeInclusive<T>) -> Result<Self, ParameterError>
158 where
159 T: RangeConvertible,
160 {
161 self.range = Some(T::to_parameter_range(range)?);
162 Ok(self)
163 }
164
165 pub fn read_only(self) -> Result<ReadOnlyParameter<'a, 's, T>, ParameterError> {
170 let default_value = self
172 .default
173 .as_ref()
174 .ok_or(ParameterError::NotFound)?
175 .clone();
176
177 let mut descriptor = ParameterDescriptor::new(self.name, T::parameter_type())
178 .ok_or(ParameterError::StorageFull)?;
179 descriptor.description.clear();
180 if let Some(desc) = self.description {
181 descriptor
182 .description
183 .push_str(desc)
184 .map_err(|_| ParameterError::StringConversion)?;
185 }
186 descriptor.read_only = true;
187 descriptor.range = self.range.unwrap_or_default();
188
189 let param_value = default_value.to_parameter_value();
190
191 self.server
192 .declare_parameter(descriptor, Some(¶m_value))?;
193
194 Ok(ReadOnlyParameter::new(self.server, self.name))
195 }
196
197 pub fn mandatory(self) -> Result<MandatoryParameter<'a, 's, T>, ParameterError> {
201 let mut descriptor = ParameterDescriptor::new(self.name, T::parameter_type())
202 .ok_or(ParameterError::StorageFull)?;
203 descriptor.description.clear();
204 if let Some(desc) = self.description {
205 descriptor
206 .description
207 .push_str(desc)
208 .map_err(|_| ParameterError::StringConversion)?;
209 }
210 descriptor.read_only = self.read_only;
211 descriptor.range = self.range.unwrap_or_default();
212
213 let default_value = self.default.map(|v| v.to_parameter_value());
214
215 self.server
216 .declare_parameter(descriptor, default_value.as_ref())?;
217
218 Ok(MandatoryParameter::new(self.server, self.name))
219 }
220
221 pub fn optional(self) -> Result<OptionalParameter<'a, 's, T>, ParameterError> {
223 let mut descriptor = ParameterDescriptor::new(self.name, T::parameter_type())
224 .ok_or(ParameterError::StorageFull)?;
225 descriptor.description.clear();
226 if let Some(desc) = self.description {
227 descriptor
228 .description
229 .push_str(desc)
230 .map_err(|_| ParameterError::StringConversion)?;
231 }
232 descriptor.read_only = self.read_only;
233 descriptor.range = self.range.unwrap_or_default();
234
235 let default_value = self.default.map(|v| v.to_parameter_value());
236
237 self.server
238 .declare_parameter(descriptor, default_value.as_ref())?;
239
240 Ok(OptionalParameter::new(self.server, self.name))
241 }
242}
243
244pub struct MandatoryParameter<'a, 's, T: ParameterVariant> {
246 server: &'a mut ParameterServer<'s>,
247 name: String<{ crate::MAX_PARAM_NAME_LEN }>,
248 _phantom: core::marker::PhantomData<T>,
249}
250
251impl<'a, 's, T: ParameterVariant> MandatoryParameter<'a, 's, T> {
252 pub(crate) fn new(server: &'a mut ParameterServer<'s>, name: &'a str) -> Self {
253 let mut n = String::new();
254 n.push_str(name).unwrap();
255 Self {
256 server,
257 name: n,
258 _phantom: core::marker::PhantomData,
259 }
260 }
261
262 pub fn get(&self) -> T {
264 self.server
265 .get_parameter_value(self.name.as_str())
266 .and_then(|val| T::from_parameter_value(&val))
267 .expect("Mandatory parameter must have a value")
268 }
269
270 pub fn set(&mut self, value: T) -> Result<(), ParameterError> {
272 let converted = value
276 .try_to_parameter_value()
277 .map_err(|_| ParameterError::StringConversion)?;
278 let result = self
279 .server
280 .set_parameter_value(self.name.as_str(), converted);
281 if result == SetParameterResult::Success {
282 Ok(())
283 } else {
284 Err(ParameterError::from(result))
285 }
286 }
287}
288
289pub struct OptionalParameter<'a, 's, T: ParameterVariant> {
291 server: &'a mut ParameterServer<'s>,
292 name: String<{ crate::MAX_PARAM_NAME_LEN }>,
293 _phantom: core::marker::PhantomData<T>,
294}
295
296impl<'a, 's, T: ParameterVariant> OptionalParameter<'a, 's, T> {
297 pub(crate) fn new(server: &'a mut ParameterServer<'s>, name: &'a str) -> Self {
298 let mut n = String::new();
299 n.push_str(name).unwrap();
300 Self {
301 server,
302 name: n,
303 _phantom: core::marker::PhantomData,
304 }
305 }
306
307 pub fn get(&self) -> Option<T> {
309 self.server
310 .get_parameter_value(self.name.as_str())
311 .and_then(|val| T::from_parameter_value(&val))
312 }
313
314 pub fn set(&mut self, value: Option<T>) -> Result<(), ParameterError> {
316 let param_value = value.map(|v| v.to_parameter_value());
317 let result = self
318 .server
319 .set_parameter_value(self.name.as_str(), param_value.unwrap_or_default());
320 if result == SetParameterResult::Success {
321 Ok(())
322 } else {
323 Err(ParameterError::from(result))
324 }
325 }
326}
327
328pub struct ReadOnlyParameter<'a, 's, T: ParameterVariant> {
330 server: &'a mut ParameterServer<'s>,
331 name: String<{ crate::MAX_PARAM_NAME_LEN }>,
332 _phantom: core::marker::PhantomData<T>,
333}
334
335impl<'a, 's, T: ParameterVariant> ReadOnlyParameter<'a, 's, T> {
336 pub(crate) fn new(server: &'a mut ParameterServer<'s>, name: &'a str) -> Self {
337 let mut n = String::new();
338 n.push_str(name).unwrap();
339 Self {
340 server,
341 name: n,
342 _phantom: core::marker::PhantomData,
343 }
344 }
345
346 pub fn get(&self) -> T {
348 self.server
349 .get_parameter_value(self.name.as_str())
350 .and_then(|val| T::from_parameter_value(&val))
351 .expect("Read-only parameter must have a value")
352 }
353}
354
355pub struct UndeclaredParameters<'a, 's> {
360 server: &'a mut ParameterServer<'s>,
361}
362
363impl<'a, 's> UndeclaredParameters<'a, 's> {
364 pub fn new(server: &'a mut ParameterServer<'s>) -> Self {
365 Self { server }
366 }
367
368 pub fn get_bool(&self, name: &str) -> Option<bool> {
370 self.server.get_bool(name)
371 }
372
373 pub fn get_integer(&self, name: &str) -> Option<i64> {
375 self.server.get_integer(name)
376 }
377
378 pub fn get_double(&self, name: &str) -> Option<f64> {
380 self.server.get_double(name)
381 }
382
383 pub fn get_string(&self, name: &str) -> Option<&str> {
385 self.server.get_string(name)
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392
393 #[test]
394 fn test_mandatory_parameter_with_default() {
395 let mut storage: ParameterStorage = ParameterStorage::new();
396 let mut server = ParameterServer::new_in(storage.as_table());
397 let param = ParameterBuilder::<i64>::new(&mut server, "test_param")
398 .default(42)
399 .description("A test parameter")
400 .mandatory()
401 .expect("Failed to declare parameter");
402
403 assert_eq!(param.get(), 42);
404 }
405
406 #[test]
407 fn test_mandatory_parameter_set() {
408 let mut storage: ParameterStorage = ParameterStorage::new();
409 let mut server = ParameterServer::new_in(storage.as_table());
410 let mut param = ParameterBuilder::<i64>::new(&mut server, "test_param")
411 .default(0)
412 .mandatory()
413 .expect("Failed to declare parameter");
414
415 param.set(100).expect("Failed to set parameter");
416 assert_eq!(param.get(), 100);
417 }
418
419 #[test]
420 fn test_optional_parameter_none() {
421 let mut storage: ParameterStorage = ParameterStorage::new();
422 let mut server = ParameterServer::new_in(storage.as_table());
423 let param = ParameterBuilder::<i64>::new(&mut server, "test_param")
424 .optional()
425 .expect("Failed to declare parameter");
426
427 assert_eq!(param.get(), None);
428 }
429
430 #[test]
431 fn test_optional_parameter_with_default() {
432 let mut storage: ParameterStorage = ParameterStorage::new();
433 let mut server = ParameterServer::new_in(storage.as_table());
434 let param = ParameterBuilder::<i64>::new(&mut server, "test_param")
435 .default(42)
436 .optional()
437 .expect("Failed to declare parameter");
438
439 assert_eq!(param.get(), Some(42));
440 }
441
442 #[test]
443 fn test_optional_parameter_set() {
444 let mut storage: ParameterStorage = ParameterStorage::new();
445 let mut server = ParameterServer::new_in(storage.as_table());
446 let mut param = ParameterBuilder::<i64>::new(&mut server, "test_param")
447 .optional()
448 .expect("Failed to declare parameter");
449
450 param.set(Some(100)).expect("Failed to set parameter");
451 assert_eq!(param.get(), Some(100));
452 }
453
454 #[test]
455 fn test_read_only_parameter() {
456 let mut storage: ParameterStorage = ParameterStorage::new();
457 let mut server = ParameterServer::new_in(storage.as_table());
458 let param = ParameterBuilder::<i64>::new(&mut server, "readonly_param")
459 .default(42)
460 .description("A read-only parameter")
461 .read_only()
462 .expect("Failed to declare parameter");
463
464 assert_eq!(param.get(), 42);
465 }
466
467 #[test]
468 fn test_read_only_parameter_requires_default() {
469 let mut storage: ParameterStorage = ParameterStorage::new();
470 let mut server = ParameterServer::new_in(storage.as_table());
471 let result = ParameterBuilder::<i64>::new(&mut server, "readonly_param").read_only();
472
473 assert_eq!(result.err(), Some(ParameterError::NotFound));
474 }
475
476 #[test]
477 fn test_integer_range_constraint() {
478 let mut storage: ParameterStorage = ParameterStorage::new();
479 let mut server = ParameterServer::new_in(storage.as_table());
480 let mut param = ParameterBuilder::<i64>::new(&mut server, "ranged_param")
481 .default(50)
482 .integer_range(0, 100, 1)
483 .expect("Failed to set range")
484 .mandatory()
485 .expect("Failed to declare parameter");
486
487 param.set(75).expect("Failed to set valid value");
489 assert_eq!(param.get(), 75);
490 }
491
492 #[test]
493 fn test_float_range_constraint() {
494 let mut storage: ParameterStorage = ParameterStorage::new();
495 let mut server = ParameterServer::new_in(storage.as_table());
496 let mut param = ParameterBuilder::<f64>::new(&mut server, "float_param")
497 .default(0.5)
498 .float_range(0.0, 1.0, 0.0)
499 .expect("Failed to set range")
500 .mandatory()
501 .expect("Failed to declare parameter");
502
503 param.set(0.75).expect("Failed to set valid value");
505 assert_eq!(param.get(), 0.75);
506 }
507
508 #[test]
509 fn test_range_convenience_integer() {
510 let mut storage: ParameterStorage = ParameterStorage::new();
511 let mut server = ParameterServer::new_in(storage.as_table());
512 let param = ParameterBuilder::<i64>::new(&mut server, "ranged_param")
513 .default(50)
514 .range(0..=100)
515 .expect("Failed to set range")
516 .mandatory()
517 .expect("Failed to declare parameter");
518
519 assert_eq!(param.get(), 50);
520 }
521
522 #[test]
523 fn test_range_convenience_float() {
524 let mut storage: ParameterStorage = ParameterStorage::new();
525 let mut server = ParameterServer::new_in(storage.as_table());
526 let param = ParameterBuilder::<f64>::new(&mut server, "float_param")
527 .default(0.5)
528 .range(0.0..=1.0)
529 .expect("Failed to set range")
530 .mandatory()
531 .expect("Failed to declare parameter");
532
533 assert_eq!(param.get(), 0.5);
534 }
535
536 #[test]
537 fn test_parameter_description() {
538 let mut storage: ParameterStorage = ParameterStorage::new();
539 let mut server = ParameterServer::new_in(storage.as_table());
540 let _param = ParameterBuilder::<i64>::new(&mut server, "described_param")
541 .default(42)
542 .description("This is a test description")
543 .mandatory()
544 .expect("Failed to declare parameter");
545
546 let desc = server.get_descriptor("described_param");
548 assert!(desc.is_some());
549 assert_eq!(
550 desc.unwrap().description.as_str(),
551 "This is a test description"
552 );
553 }
554
555 #[test]
556 fn test_bool_parameter() {
557 let mut storage: ParameterStorage = ParameterStorage::new();
558 let mut server = ParameterServer::new_in(storage.as_table());
559 let mut param = ParameterBuilder::<bool>::new(&mut server, "bool_param")
560 .default(false)
561 .mandatory()
562 .expect("Failed to declare parameter");
563
564 assert!(!param.get());
565 param.set(true).expect("Failed to set parameter");
566 assert!(param.get());
567 }
568
569 #[test]
570 fn test_undeclared_parameters() {
571 use crate::ParameterValue;
572
573 let mut storage: ParameterStorage = ParameterStorage::new();
574 let mut server = ParameterServer::new_in(storage.as_table());
575
576 server.set_or_declare("flag", ParameterValue::Bool(true));
578 server.set_or_declare("count", ParameterValue::Integer(42));
579 server.set_or_declare("ratio", ParameterValue::Double(0.5));
580
581 let undeclared = UndeclaredParameters::new(&mut server);
582
583 assert_eq!(undeclared.get_bool("flag"), Some(true));
584 assert_eq!(undeclared.get_integer("count"), Some(42));
585 assert_eq!(undeclared.get_double("ratio"), Some(0.5));
586 assert_eq!(undeclared.get_string("nonexistent"), None);
587 }
588}