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