do_not_use_testing_rclrs/
parameter.rs

1mod override_map;
2mod value;
3
4pub(crate) use override_map::*;
5pub use value::*;
6
7use crate::rcl_bindings::*;
8use crate::{call_string_getter_with_handle, RclrsError};
9use std::collections::{btree_map::Entry, BTreeMap};
10use std::fmt::Debug;
11use std::marker::PhantomData;
12use std::sync::{
13    atomic::{AtomicBool, Ordering},
14    Arc, Mutex, RwLock, Weak,
15};
16
17// This module implements the core logic of parameters in rclrs.
18// The implementation is fairly different from the existing ROS 2 client libraries. A detailed
19// explanation of the core differences and why they have been implemented is available at:
20// https://github.com/ros2-rust/ros2_rust/pull/332
21// Among the most relevant ones:
22//
23// * Parameter declaration returns an object which will be the main accessor to the parameter,
24// providing getters and, except for read only parameters, setters. Object destruction will
25// undeclare the parameter.
26// * Declaration uses a builder pattern to specify ranges, description, human readable constraints
27// instead of an ParameterDescriptor argument.
28// * Parameters properties of read only and dynamic are embedded in their type rather than being a
29// boolean parameter.
30// * There are no runtime exceptions for common cases such as undeclared parameter, already
31// declared, or uninitialized.
32// * There is no "parameter not set" type, users can instead decide to have a `Mandatory` parameter
33// that must always have a value or `Optional` parameter that can be unset.
34// * Explicit API for access to undeclared parameters by having a
35// `node.use_undeclared_parameters()` API that allows access to all parameters.
36
37#[derive(Clone, Debug)]
38struct ParameterOptionsStorage {
39    _description: Arc<str>,
40    _constraints: Arc<str>,
41    ranges: ParameterRanges,
42}
43
44impl<T: ParameterVariant> From<ParameterOptions<T>> for ParameterOptionsStorage {
45    fn from(opts: ParameterOptions<T>) -> Self {
46        Self {
47            _description: opts.description,
48            _constraints: opts.constraints,
49            ranges: opts.ranges.into(),
50        }
51    }
52}
53
54/// Options that can be attached to a parameter, such as description, ranges.
55/// Some of this data will be used to populate the ParameterDescriptor
56#[derive(Clone, Debug)]
57pub struct ParameterOptions<T: ParameterVariant> {
58    description: Arc<str>,
59    constraints: Arc<str>,
60    ranges: T::Range,
61}
62
63impl<T: ParameterVariant> Default for ParameterOptions<T> {
64    fn default() -> Self {
65        Self {
66            description: Arc::from(""),
67            constraints: Arc::from(""),
68            ranges: Default::default(),
69        }
70    }
71}
72
73impl From<ParameterRange<f64>> for ParameterRanges {
74    fn from(params: ParameterRange<f64>) -> Self {
75        Self {
76            float: Some(params),
77            ..Default::default()
78        }
79    }
80}
81
82impl From<ParameterRange<i64>> for ParameterRanges {
83    fn from(params: ParameterRange<i64>) -> Self {
84        Self {
85            integer: Some(params),
86            ..Default::default()
87        }
88    }
89}
90
91impl From<()> for ParameterRanges {
92    fn from(_empty: ()) -> Self {
93        Self::default()
94    }
95}
96
97/// Contains all the possible type of ranges that can be applied to a value.
98/// Usually only one of these ranges will be applied, but all have to be stored since:
99///
100/// * A dynamic parameter can change its type at runtime, in which case a different range could be
101/// applied.
102/// * Introspection through service calls requires all the ranges to be reported to the user.
103#[derive(Clone, Debug, Default)]
104pub struct ParameterRanges {
105    float: Option<ParameterRange<f64>>,
106    integer: Option<ParameterRange<i64>>,
107}
108
109impl ParameterRanges {
110    fn validate(&self) -> Result<(), DeclarationError> {
111        if let Some(integer) = &self.integer {
112            integer.validate()?;
113        }
114        if let Some(float) = &self.float {
115            float.validate()?;
116        }
117        Ok(())
118    }
119
120    fn in_range(&self, value: &ParameterValue) -> bool {
121        match value {
122            ParameterValue::Integer(v) => {
123                if let Some(range) = &self.integer {
124                    if !range.in_range(*v) {
125                        return false;
126                    }
127                }
128            }
129            ParameterValue::Double(v) => {
130                if let Some(range) = &self.float {
131                    if !range.in_range(*v) {
132                        return false;
133                    }
134                }
135            }
136            _ => {}
137        }
138        true
139    }
140}
141
142/// Describes the range for paramter type T.
143#[derive(Clone, Debug, Default)]
144pub struct ParameterRange<T: ParameterVariant + PartialOrd> {
145    /// Lower limit, if set the parameter must be >= l.
146    pub lower: Option<T>,
147    /// Upper limit, if set the parameter must be <= u.
148    pub upper: Option<T>,
149    /// Step size, if set and `lower` is set the parameter must be within an integer number of
150    /// steps of size `step` from `lower`, or equal to the upper limit if set.
151    /// Example:
152    /// If lower is `Some(0)`, upper is `Some(10)` and step is `Some(3)`, acceptable values are:
153    /// `[0, 3, 6, 9, 10]`.
154    pub step: Option<T>,
155}
156
157impl<T: ParameterVariant + PartialOrd + Default> ParameterRange<T> {
158    fn inside_boundary(&self, value: &T) -> bool {
159        if self.lower.as_ref().is_some_and(|l| value < l) {
160            return false;
161        }
162        if self.upper.as_ref().is_some_and(|u| value > u) {
163            return false;
164        }
165        true
166    }
167
168    fn validate(&self) -> Result<(), DeclarationError> {
169        if self
170            .lower
171            .as_ref()
172            .zip(self.upper.as_ref())
173            .is_some_and(|(l, u)| l > u)
174        {
175            return Err(DeclarationError::InvalidRange);
176        }
177        if self.step.as_ref().is_some_and(|s| s <= &T::default()) {
178            return Err(DeclarationError::InvalidRange);
179        }
180        Ok(())
181    }
182}
183
184impl ParameterRange<i64> {
185    fn in_range(&self, value: i64) -> bool {
186        if !self.inside_boundary(&value) {
187            return false;
188        }
189        if self.upper.is_some_and(|u| u == value) {
190            return true;
191        }
192        if let (Some(l), Some(s)) = (self.lower, self.step) {
193            if (value - l) % s != 0 {
194                return false;
195            }
196        }
197        true
198    }
199}
200
201impl ParameterRange<f64> {
202    // Same comparison function as rclcpp.
203    fn are_close(v1: f64, v2: f64) -> bool {
204        const ULP_TOL: f64 = 100.0;
205        (v1 - v2).abs() <= (f64::EPSILON * (v1 + v2).abs() * ULP_TOL)
206    }
207
208    fn in_range(&self, value: f64) -> bool {
209        if self.upper.is_some_and(|u| Self::are_close(u, value))
210            || self.lower.is_some_and(|l| Self::are_close(l, value))
211        {
212            return true;
213        }
214        if !self.inside_boundary(&value) {
215            return false;
216        }
217        if let (Some(l), Some(s)) = (self.lower, self.step) {
218            if !Self::are_close(((value - l) / s).round() * s + l, value) {
219                return false;
220            }
221        }
222        true
223    }
224}
225
226#[derive(Clone, Debug)]
227enum DeclaredValue {
228    Mandatory(Arc<RwLock<ParameterValue>>),
229    Optional(Arc<RwLock<Option<ParameterValue>>>),
230    ReadOnly(ParameterValue),
231}
232
233/// Builder used to declare a parameter. Obtain this by calling
234/// [`crate::Node::declare_parameter`].
235#[must_use]
236pub struct ParameterBuilder<'a, T: ParameterVariant> {
237    name: Arc<str>,
238    default_value: Option<T>,
239    ignore_override: bool,
240    discard_mismatching_prior_value: bool,
241    discriminator: DiscriminatorFunction<'a, T>,
242    options: ParameterOptions<T>,
243    interface: &'a ParameterInterface,
244}
245
246impl<'a, T: ParameterVariant> ParameterBuilder<'a, T> {
247    /// Sets the default value for the parameter. The parameter value will be
248    /// initialized to this if no command line override was given for this
249    /// parameter and if the parameter also had no value prior to being
250    /// declared.
251    ///
252    /// To customize how the initial value of the parameter is chosen, you can
253    /// provide a custom function with the method [`Self::discriminate()`]. By
254    /// default, the initial value will be chosen as
255    /// `default_value < override_value < prior_value` in order of increasing
256    /// preference.
257    pub fn default(mut self, value: T) -> Self {
258        self.default_value = Some(value);
259        self
260    }
261
262    /// Ignore any override that was given for this parameter.
263    ///
264    /// If you also use [`Self::discriminate()`], the
265    /// [`AvailableValues::override_value`] field given to the discriminator
266    /// will be [`None`] even if the user had provided an override.
267    pub fn ignore_override(mut self) -> Self {
268        self.ignore_override = true;
269        self
270    }
271
272    /// If the parameter was set to a value before being declared with a type
273    /// that does not match this declaration, discard the prior value instead
274    /// of emitting a [`DeclarationError::PriorValueTypeMismatch`].
275    ///
276    /// If the type of the prior value does match the declaration, it will
277    /// still be provided to the discriminator.
278    pub fn discard_mismatching_prior_value(mut self) -> Self {
279        self.discard_mismatching_prior_value = true;
280        self
281    }
282
283    /// Decide what the initial value for the parameter will be based on the
284    /// available `default_value`, `override_value`, or `prior_value`.
285    ///
286    /// The default discriminator is [`default_initial_value_discriminator()`].
287    pub fn discriminate<F>(mut self, f: F) -> Self
288    where
289        F: FnOnce(AvailableValues<T>) -> Option<T> + 'a,
290    {
291        self.discriminator = Box::new(f);
292        self
293    }
294
295    /// Sets the range for the parameter.
296    pub fn range(mut self, range: T::Range) -> Self {
297        self.options.ranges = range;
298        self
299    }
300
301    /// Sets the parameter's human readable description.
302    pub fn description(mut self, description: impl Into<Arc<str>>) -> Self {
303        self.options.description = description.into();
304        self
305    }
306
307    /// Sets the parameter's human readable constraints.
308    /// These are not enforced by the library but are displayed on parameter description requests
309    /// and can be used by integrators to understand complex constraints.
310    pub fn constraints(mut self, constraints: impl Into<Arc<str>>) -> Self {
311        self.options.constraints = constraints.into();
312        self
313    }
314
315    /// Declares the parameter as a Mandatory parameter, that must always have a value.
316    ///
317    /// ## See also
318    /// * [`Self::optional()`]
319    /// * [`Self::read_only()`]
320    pub fn mandatory(self) -> Result<MandatoryParameter<T>, DeclarationError> {
321        self.try_into()
322    }
323
324    /// Declares the parameter as a ReadOnly parameter, that cannot be edited.
325    ///
326    /// # See also
327    /// * [`Self::optional()`]
328    /// * [`Self::mandatory()`]
329    pub fn read_only(self) -> Result<ReadOnlyParameter<T>, DeclarationError> {
330        self.try_into()
331    }
332
333    /// Declares the parameter as an Optional parameter, that can be unset.
334    ///
335    /// This will never return the [`DeclarationError::NoValueAvailable`] variant.
336    ///
337    /// ## See also
338    /// * [`Self::mandatory()`]
339    /// * [`Self::read_only()`]
340    pub fn optional(self) -> Result<OptionalParameter<T>, DeclarationError> {
341        self.try_into()
342    }
343}
344
345impl<'a, T> ParameterBuilder<'a, Arc<[T]>>
346where
347    Arc<[T]>: ParameterVariant,
348{
349    /// Sets the default for an array-like parameter from an iterable.
350    pub fn default_from_iter(mut self, default_value: impl IntoIterator<Item = T>) -> Self {
351        self.default_value = Some(default_value.into_iter().collect());
352        self
353    }
354}
355
356impl<'a> ParameterBuilder<'a, Arc<[Arc<str>]>> {
357    /// Sets the default for the parameter from a string-like array.
358    pub fn default_string_array<U>(mut self, default_value: U) -> Self
359    where
360        U: IntoIterator,
361        U::Item: Into<Arc<str>>,
362    {
363        self.default_value = Some(default_value.into_iter().map(|v| v.into()).collect());
364        self
365    }
366}
367
368/// This struct is given to the discriminator function of the
369/// [`ParameterBuilder`] so it knows what values are available to choose from.
370pub struct AvailableValues<'a, T> {
371    /// The value given to the parameter builder as the default value.
372    pub default_value: Option<T>,
373    /// The value given as an override value, usually as a command line argument.
374    pub override_value: Option<T>,
375    /// A prior value that the parameter was set to before it was declared.
376    pub prior_value: Option<T>,
377    /// The valid ranges for the parameter value.
378    pub ranges: &'a ParameterRanges,
379}
380
381/// The default discriminator that chooses the initial value for a parameter.
382/// The implementation here uses a simple preference of
383/// ```notrust
384/// default_value < override_value < prior_value
385/// ```
386/// in ascending order of preference.
387///
388/// The `prior_value` will automatically be discarded if it is outside the
389/// designated range. The override value will not be discarded if it is out of
390/// range because that is more likely to be an error that needs to be escalated.
391/// You can replace all of this with custom behavior by providing your own
392/// discriminator function to [`ParameterBuilder::discriminate()`].
393pub fn default_initial_value_discriminator<T: ParameterVariant>(
394    available: AvailableValues<T>,
395) -> Option<T> {
396    if let Some(prior) = available.prior_value {
397        if available.ranges.in_range(&prior.clone().into()) {
398            return Some(prior);
399        }
400    }
401    if available.override_value.is_some() {
402        return available.override_value;
403    }
404    available.default_value
405}
406
407type DiscriminatorFunction<'a, T> = Box<dyn FnOnce(AvailableValues<T>) -> Option<T> + 'a>;
408
409impl<T: ParameterVariant> TryFrom<ParameterBuilder<'_, T>> for OptionalParameter<T> {
410    type Error = DeclarationError;
411
412    fn try_from(builder: ParameterBuilder<T>) -> Result<Self, Self::Error> {
413        let ranges = builder.options.ranges.clone().into();
414        let initial_value = builder.interface.get_declaration_initial_value::<T>(
415            &builder.name,
416            builder.default_value,
417            builder.ignore_override,
418            builder.discard_mismatching_prior_value,
419            builder.discriminator,
420            &ranges,
421        )?;
422        let value = Arc::new(RwLock::new(initial_value.map(|v| v.into())));
423        builder.interface.store_parameter(
424            builder.name.clone(),
425            T::kind(),
426            DeclaredValue::Optional(value.clone()),
427            builder.options.into(),
428        );
429        Ok(OptionalParameter {
430            name: builder.name,
431            value,
432            ranges,
433            map: Arc::downgrade(&builder.interface._parameter_map),
434            _marker: Default::default(),
435        })
436    }
437}
438
439/// A parameter that must have a value
440/// This struct has ownership of the declared parameter. Additional parameter declaration will fail
441/// while this struct exists and the parameter will be undeclared when it is dropped.
442pub struct MandatoryParameter<T: ParameterVariant> {
443    name: Arc<str>,
444    value: Arc<RwLock<ParameterValue>>,
445    ranges: ParameterRanges,
446    map: Weak<Mutex<ParameterMap>>,
447    _marker: PhantomData<T>,
448}
449
450impl<T: ParameterVariant + Debug> Debug for MandatoryParameter<T> {
451    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
452        f.debug_struct("MandatoryParameter")
453            .field("name", &self.name)
454            .field("value", &self.get())
455            .field("range", &self.ranges)
456            .finish()
457    }
458}
459
460impl<T: ParameterVariant> Drop for MandatoryParameter<T> {
461    fn drop(&mut self) {
462        // Clear the entry from the parameter map
463        if let Some(map) = self.map.upgrade() {
464            let storage = &mut map.lock().unwrap().storage;
465            storage.remove(&self.name);
466        }
467    }
468}
469
470impl<'a, T: ParameterVariant + 'a> TryFrom<ParameterBuilder<'a, T>> for MandatoryParameter<T> {
471    type Error = DeclarationError;
472
473    fn try_from(builder: ParameterBuilder<T>) -> Result<Self, Self::Error> {
474        let ranges = builder.options.ranges.clone().into();
475        let initial_value = builder.interface.get_declaration_initial_value::<T>(
476            &builder.name,
477            builder.default_value,
478            builder.ignore_override,
479            builder.discard_mismatching_prior_value,
480            builder.discriminator,
481            &ranges,
482        )?;
483        let Some(initial_value) = initial_value else {
484            return Err(DeclarationError::NoValueAvailable);
485        };
486        let value = Arc::new(RwLock::new(initial_value.into()));
487        builder.interface.store_parameter(
488            builder.name.clone(),
489            T::kind(),
490            DeclaredValue::Mandatory(value.clone()),
491            builder.options.into(),
492        );
493        Ok(MandatoryParameter {
494            name: builder.name,
495            value,
496            ranges,
497            map: Arc::downgrade(&builder.interface._parameter_map),
498            _marker: Default::default(),
499        })
500    }
501}
502
503/// A parameter that might not have a value, represented by `Option<T>`.
504/// This struct has ownership of the declared parameter. Additional parameter declaration will fail
505/// while this struct exists and the parameter will be undeclared when it is dropped.
506pub struct OptionalParameter<T: ParameterVariant> {
507    name: Arc<str>,
508    value: Arc<RwLock<Option<ParameterValue>>>,
509    ranges: ParameterRanges,
510    map: Weak<Mutex<ParameterMap>>,
511    _marker: PhantomData<T>,
512}
513
514impl<T: ParameterVariant + Debug> Debug for OptionalParameter<T> {
515    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
516        f.debug_struct("OptionalParameter")
517            .field("name", &self.name)
518            .field("value", &self.get())
519            .field("range", &self.ranges)
520            .finish()
521    }
522}
523
524impl<T: ParameterVariant> Drop for OptionalParameter<T> {
525    fn drop(&mut self) {
526        // Clear the entry from the parameter map
527        if let Some(map) = self.map.upgrade() {
528            let storage = &mut map.lock().unwrap().storage;
529            storage.remove(&self.name);
530        }
531    }
532}
533
534/// A parameter that must have a value and cannot be written to
535/// This struct has ownership of the declared parameter. Additional parameter declaration will fail
536/// while this struct exists and the parameter will be undeclared when it is dropped.
537pub struct ReadOnlyParameter<T: ParameterVariant> {
538    name: Arc<str>,
539    value: ParameterValue,
540    map: Weak<Mutex<ParameterMap>>,
541    _marker: PhantomData<T>,
542}
543
544impl<T: ParameterVariant + Debug> Debug for ReadOnlyParameter<T> {
545    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
546        f.debug_struct("ReadOnlyParameter")
547            .field("name", &self.name)
548            .field("value", &self.value)
549            .finish()
550    }
551}
552
553impl<T: ParameterVariant> Drop for ReadOnlyParameter<T> {
554    fn drop(&mut self) {
555        // Clear the entry from the parameter map
556        if let Some(map) = self.map.upgrade() {
557            let storage = &mut map.lock().unwrap().storage;
558            storage.remove(&self.name);
559        }
560    }
561}
562
563impl<'a, T: ParameterVariant + 'a> TryFrom<ParameterBuilder<'a, T>> for ReadOnlyParameter<T> {
564    type Error = DeclarationError;
565
566    fn try_from(builder: ParameterBuilder<T>) -> Result<Self, Self::Error> {
567        let ranges = builder.options.ranges.clone().into();
568        let initial_value = builder.interface.get_declaration_initial_value::<T>(
569            &builder.name,
570            builder.default_value,
571            builder.ignore_override,
572            builder.discard_mismatching_prior_value,
573            builder.discriminator,
574            &ranges,
575        )?;
576        let Some(initial_value) = initial_value else {
577            return Err(DeclarationError::NoValueAvailable);
578        };
579        let value = initial_value.into();
580        builder.interface.store_parameter(
581            builder.name.clone(),
582            T::kind(),
583            DeclaredValue::ReadOnly(value.clone()),
584            builder.options.into(),
585        );
586        Ok(ReadOnlyParameter {
587            name: builder.name,
588            value,
589            map: Arc::downgrade(&builder.interface._parameter_map),
590            _marker: Default::default(),
591        })
592    }
593}
594
595#[derive(Clone, Debug)]
596struct DeclaredStorage {
597    value: DeclaredValue,
598    kind: ParameterKind,
599    options: ParameterOptionsStorage,
600}
601
602#[derive(Debug)]
603enum ParameterStorage {
604    Declared(DeclaredStorage),
605    Undeclared(ParameterValue),
606}
607
608#[derive(Debug, Default)]
609struct ParameterMap {
610    storage: BTreeMap<Arc<str>, ParameterStorage>,
611}
612
613impl<T: ParameterVariant> MandatoryParameter<T> {
614    /// Returns a clone of the most recent value of the parameter.
615    pub fn get(&self) -> T {
616        self.value.read().unwrap().clone().try_into().ok().unwrap()
617    }
618
619    /// Sets the parameter value.
620    /// Returns [`ParameterValueError::OutOfRange`] if the value is out of the parameter's range.
621    pub fn set<U: Into<T>>(&self, value: U) -> Result<(), ParameterValueError> {
622        let value = value.into().into();
623        if !self.ranges.in_range(&value) {
624            return Err(ParameterValueError::OutOfRange);
625        }
626        *self.value.write().unwrap() = value;
627        Ok(())
628    }
629}
630
631impl<T: ParameterVariant> ReadOnlyParameter<T> {
632    /// Returns a clone of the most recent value of the parameter.
633    pub fn get(&self) -> T {
634        self.value.clone().try_into().ok().unwrap()
635    }
636}
637
638impl<T: ParameterVariant> OptionalParameter<T> {
639    /// Returns a clone of the most recent value of the parameter.
640    pub fn get(&self) -> Option<T> {
641        self.value
642            .read()
643            .unwrap()
644            .clone()
645            .map(|p| p.try_into().ok().unwrap())
646    }
647
648    /// Assigns a value to the optional parameter, setting it to `Some(value)`.
649    /// Returns [`ParameterValueError::OutOfRange`] if the value is out of the parameter's range.
650    pub fn set<U: Into<T>>(&self, value: U) -> Result<(), ParameterValueError> {
651        let value = value.into().into();
652        if !self.ranges.in_range(&value) {
653            return Err(ParameterValueError::OutOfRange);
654        }
655        *self.value.write().unwrap() = Some(value);
656        Ok(())
657    }
658
659    /// Unsets the optional parameter value to `None`.
660    pub fn unset(&self) {
661        *self.value.write().unwrap() = None;
662    }
663}
664
665/// Allows access to all parameters via get / set functions, using their name as a key.
666pub struct Parameters<'a> {
667    pub(crate) interface: &'a ParameterInterface,
668}
669
670/// Describes errors that can be generated when trying to set a parameter's value.
671#[derive(Debug)]
672pub enum ParameterValueError {
673    /// Parameter value was out of the parameter's range.
674    OutOfRange,
675    /// Parameter was stored in a static type and an operation on a different type was attempted.
676    TypeMismatch,
677    /// A write on a read-only parameter was attempted.
678    ReadOnly,
679}
680
681/// Error that can be generated when doing operations on parameters.
682#[derive(Debug)]
683pub enum DeclarationError {
684    /// Parameter was already declared and a new declaration was attempted.
685    AlreadyDeclared,
686    /// Parameter was declared as non optional but no value was available, either through a user
687    /// specified default, a command-line override, or a previously set value.
688    NoValueAvailable,
689    /// The override value that was provided has the wrong type. This error is bypassed
690    /// when using [`ParameterBuilder::ignore_override()`].
691    OverrideValueTypeMismatch,
692    /// The value that the parameter was already set to has the wrong type. This error
693    /// is bypassed when using [`ParameterBuilder::discard_mismatching_prior_value`].
694    PriorValueTypeMismatch,
695    /// The initial value that was selected is out of range.
696    InitialValueOutOfRange,
697    /// An invalid range was provided to a parameter declaration (i.e. lower bound > higher bound).
698    InvalidRange,
699}
700
701impl<'a> Parameters<'a> {
702    /// Tries to read a parameter of the requested type.
703    ///
704    /// Returns `Some(T)` if a parameter of the requested type exists, `None` otherwise.
705    pub fn get<T: ParameterVariant>(&self, name: &str) -> Option<T> {
706        let storage = &self.interface._parameter_map.lock().unwrap().storage;
707        let storage = storage.get(name)?;
708        match storage {
709            ParameterStorage::Declared(storage) => match &storage.value {
710                DeclaredValue::Mandatory(p) => p.read().unwrap().clone().try_into().ok(),
711                DeclaredValue::Optional(p) => {
712                    p.read().unwrap().clone().and_then(|p| p.try_into().ok())
713                }
714                DeclaredValue::ReadOnly(p) => p.clone().try_into().ok(),
715            },
716            ParameterStorage::Undeclared(value) => value.clone().try_into().ok(),
717        }
718    }
719
720    /// Tries to set a parameter with the requested value.
721    ///
722    /// Returns:
723    /// * `Ok(())` if setting was successful.
724    /// * [`Err(DeclarationError::TypeMismatch)`] if the type of the requested value is different
725    /// from the parameter's type.
726    pub fn set<T: ParameterVariant>(
727        &self,
728        name: impl Into<Arc<str>>,
729        value: T,
730    ) -> Result<(), ParameterValueError> {
731        let mut map = self.interface._parameter_map.lock().unwrap();
732        let name: Arc<str> = name.into();
733        match map.storage.entry(name) {
734            Entry::Occupied(mut entry) => {
735                // If it's declared, we can only set if it's the same variant.
736                // Undeclared parameters are dynamic by default
737                match entry.get_mut() {
738                    ParameterStorage::Declared(param) => {
739                        if T::kind() == param.kind {
740                            let value = value.into();
741                            if !param.options.ranges.in_range(&value) {
742                                return Err(ParameterValueError::OutOfRange);
743                            }
744                            match &param.value {
745                                DeclaredValue::Mandatory(p) => *p.write().unwrap() = value,
746                                DeclaredValue::Optional(p) => *p.write().unwrap() = Some(value),
747                                DeclaredValue::ReadOnly(_) => {
748                                    return Err(ParameterValueError::ReadOnly);
749                                }
750                            }
751                        } else {
752                            return Err(ParameterValueError::TypeMismatch);
753                        }
754                    }
755                    ParameterStorage::Undeclared(param) => {
756                        *param = value.into();
757                    }
758                }
759            }
760            Entry::Vacant(entry) => {
761                entry.insert(ParameterStorage::Undeclared(value.into()));
762            }
763        }
764
765        Ok(())
766    }
767}
768
769pub(crate) struct ParameterInterface {
770    _parameter_map: Arc<Mutex<ParameterMap>>,
771    _override_map: ParameterOverrideMap,
772    allow_undeclared: AtomicBool,
773    // NOTE(luca-della-vedova) add a ParameterService field to this struct to add support for
774    // services.
775}
776
777impl ParameterInterface {
778    pub(crate) fn new(
779        rcl_node_mtx: &Arc<Mutex<rcl_node_t>>,
780        node_arguments: &rcl_arguments_t,
781        global_arguments: &rcl_arguments_t,
782    ) -> Result<Self, RclrsError> {
783        let rcl_node = rcl_node_mtx.lock().unwrap();
784        let _override_map = unsafe {
785            let fqn = call_string_getter_with_handle(&rcl_node, rcl_node_get_fully_qualified_name);
786            resolve_parameter_overrides(&fqn, node_arguments, global_arguments)?
787        };
788
789        Ok(ParameterInterface {
790            _parameter_map: Default::default(),
791            _override_map,
792            allow_undeclared: Default::default(),
793        })
794    }
795
796    pub(crate) fn declare<'a, T: ParameterVariant + 'a>(
797        &'a self,
798        name: Arc<str>,
799    ) -> ParameterBuilder<'a, T> {
800        ParameterBuilder {
801            name,
802            default_value: None,
803            ignore_override: false,
804            discard_mismatching_prior_value: false,
805            discriminator: Box::new(default_initial_value_discriminator::<T>),
806            options: Default::default(),
807            interface: self,
808        }
809    }
810
811    fn get_declaration_initial_value<'a, T: ParameterVariant + 'a>(
812        &self,
813        name: &str,
814        default_value: Option<T>,
815        ignore_override: bool,
816        discard_mismatching_prior: bool,
817        discriminator: DiscriminatorFunction<T>,
818        ranges: &ParameterRanges,
819    ) -> Result<Option<T>, DeclarationError> {
820        ranges.validate()?;
821        let override_value: Option<T> = if ignore_override {
822            None
823        } else if let Some(override_value) = self._override_map.get(name).cloned() {
824            Some(
825                override_value
826                    .try_into()
827                    .map_err(|_| DeclarationError::OverrideValueTypeMismatch)?,
828            )
829        } else {
830            None
831        };
832
833        let prior_value =
834            if let Some(prior_value) = self._parameter_map.lock().unwrap().storage.get(name) {
835                match prior_value {
836                    ParameterStorage::Declared(_) => return Err(DeclarationError::AlreadyDeclared),
837                    ParameterStorage::Undeclared(param) => match param.clone().try_into() {
838                        Ok(prior) => Some(prior),
839                        Err(_) => {
840                            if !discard_mismatching_prior {
841                                return Err(DeclarationError::PriorValueTypeMismatch);
842                            }
843                            None
844                        }
845                    },
846                }
847            } else {
848                None
849            };
850
851        let selection = discriminator(AvailableValues {
852            default_value,
853            override_value,
854            prior_value,
855            ranges,
856        });
857        if let Some(initial_value) = &selection {
858            if !ranges.in_range(&initial_value.clone().into()) {
859                return Err(DeclarationError::InitialValueOutOfRange);
860            }
861        }
862        Ok(selection)
863    }
864
865    fn store_parameter(
866        &self,
867        name: Arc<str>,
868        kind: ParameterKind,
869        value: DeclaredValue,
870        options: ParameterOptionsStorage,
871    ) {
872        self._parameter_map.lock().unwrap().storage.insert(
873            name,
874            ParameterStorage::Declared(DeclaredStorage {
875                options,
876                value,
877                kind,
878            }),
879        );
880    }
881
882    pub(crate) fn allow_undeclared(&self) {
883        self.allow_undeclared.store(true, Ordering::Relaxed);
884    }
885}
886
887#[cfg(test)]
888mod tests {
889    use super::*;
890    use crate::{create_node, Context};
891
892    #[test]
893    fn test_parameter_override_errors() {
894        // Create a new node with a few parameter overrides
895        let ctx = Context::new([
896            String::from("--ros-args"),
897            String::from("-p"),
898            String::from("declared_int:=10"),
899        ])
900        .unwrap();
901        let node = create_node(&ctx, "param_test_node").unwrap();
902
903        // Declaring a parameter with a different type than what was overridden should return an
904        // error
905        assert!(matches!(
906            node.declare_parameter("declared_int")
907                .default(1.0)
908                .mandatory(),
909            Err(DeclarationError::OverrideValueTypeMismatch)
910        ));
911
912        // The error should not happen if we ignore overrides
913        assert!(node
914            .declare_parameter("declared_int")
915            .default(1.0)
916            .ignore_override()
917            .mandatory()
918            .is_ok());
919
920        // If the override does not respect the range, we should return an error
921        let range = ParameterRange {
922            upper: Some(5),
923            ..Default::default()
924        };
925        assert!(matches!(
926            node.declare_parameter("declared_int")
927                .default(1)
928                .range(range.clone())
929                .mandatory(),
930            Err(DeclarationError::InitialValueOutOfRange)
931        ));
932
933        // The override being out of range should not matter if we use
934        // ignore_override
935        assert!(node
936            .declare_parameter("declared_int")
937            .default(1)
938            .range(range)
939            .ignore_override()
940            .mandatory()
941            .is_ok());
942    }
943
944    #[test]
945    fn test_parameter_setting_declaring() {
946        // Create a new node with a few parameter overrides
947        let ctx = Context::new([
948            String::from("--ros-args"),
949            String::from("-p"),
950            String::from("declared_int:=10"),
951            String::from("-p"),
952            String::from("double_array:=[1.0, 2.0]"),
953            String::from("-p"),
954            String::from("optional_bool:=true"),
955            String::from("-p"),
956            String::from("non_declared_string:='param'"),
957        ])
958        .unwrap();
959        let node = create_node(&ctx, "param_test_node").unwrap();
960
961        let overridden_int = node
962            .declare_parameter("declared_int")
963            .default(123)
964            .mandatory()
965            .unwrap();
966        assert_eq!(overridden_int.get(), 10);
967
968        let new_param = node
969            .declare_parameter("new_param")
970            .default(2.0)
971            .mandatory()
972            .unwrap();
973        assert_eq!(new_param.get(), 2.0);
974
975        // Getting a parameter that was declared should work
976        assert_eq!(
977            node.use_undeclared_parameters().get::<f64>("new_param"),
978            Some(2.0)
979        );
980
981        // Getting / Setting a parameter with the wrong type should not work
982        assert!(node
983            .use_undeclared_parameters()
984            .get::<i64>("new_param")
985            .is_none());
986        assert!(matches!(
987            node.use_undeclared_parameters().set("new_param", 42),
988            Err(ParameterValueError::TypeMismatch)
989        ));
990
991        // Setting a parameter should update both existing parameter objects and be reflected in
992        // new node.use_undeclared_parameters().get() calls
993        assert!(node
994            .use_undeclared_parameters()
995            .set("new_param", 10.0)
996            .is_ok());
997        assert_eq!(
998            node.use_undeclared_parameters().get("new_param"),
999            Some(10.0)
1000        );
1001        assert_eq!(new_param.get(), 10.0);
1002        new_param.set(5.0).unwrap();
1003        assert_eq!(new_param.get(), 5.0);
1004        assert_eq!(node.use_undeclared_parameters().get("new_param"), Some(5.0));
1005
1006        // Getting a parameter that was not declared should not work
1007        assert_eq!(
1008            node.use_undeclared_parameters()
1009                .get::<f64>("non_existing_param"),
1010            None
1011        );
1012
1013        // Getting a parameter that was not declared should not work, even if a value was provided
1014        // as a parameter override
1015        assert_eq!(
1016            node.use_undeclared_parameters()
1017                .get::<Arc<str>>("non_declared_string"),
1018            None
1019        );
1020
1021        // If a param is set when undeclared, the following declared value should have the
1022        // previously set value.
1023        {
1024            node.use_undeclared_parameters()
1025                .set("new_bool", true)
1026                .unwrap();
1027            let bool_param = node
1028                .declare_parameter("new_bool")
1029                .default(false)
1030                .mandatory()
1031                .unwrap();
1032            assert!(bool_param.get());
1033        }
1034        {
1035            node.use_undeclared_parameters()
1036                .set("new_bool", true)
1037                .unwrap();
1038            let bool_param = node
1039                .declare_parameter("new_bool")
1040                .default(false)
1041                .optional()
1042                .unwrap();
1043            assert_eq!(bool_param.get(), Some(true));
1044        }
1045
1046        let optional_param = node
1047            .declare_parameter("non_existing_bool")
1048            .optional()
1049            .unwrap();
1050        assert_eq!(optional_param.get(), None);
1051        optional_param.set(true).unwrap();
1052        assert_eq!(optional_param.get(), Some(true));
1053        optional_param.unset();
1054        assert_eq!(optional_param.get(), None);
1055
1056        let optional_param2 = node
1057            .declare_parameter("non_existing_bool2")
1058            .default(false)
1059            .optional()
1060            .unwrap();
1061        assert_eq!(optional_param2.get(), Some(false));
1062
1063        // This was provided as a parameter override, hence should be set to true
1064        let optional_param3 = node
1065            .declare_parameter("optional_bool")
1066            .default(false)
1067            .optional()
1068            .unwrap();
1069        assert_eq!(optional_param3.get(), Some(true));
1070
1071        // double_array was overriden to [1.0, 2.0] through command line overrides
1072        let array_param = node
1073            .declare_parameter("double_array")
1074            .default_from_iter(vec![10.0, 20.0])
1075            .mandatory()
1076            .unwrap();
1077        assert_eq!(array_param.get()[0], 1.0);
1078        assert_eq!(array_param.get()[1], 2.0);
1079
1080        let array_param = node
1081            .declare_parameter("string_array")
1082            .default_string_array(vec!["Hello", "World"])
1083            .mandatory()
1084            .unwrap();
1085        assert_eq!(array_param.get()[0], "Hello".into());
1086        assert_eq!(array_param.get()[1], "World".into());
1087
1088        // If a value is set when undeclared, the following declare_parameter should have the
1089        // previously set value.
1090        node.use_undeclared_parameters()
1091            .set("undeclared_int", 42)
1092            .unwrap();
1093        let undeclared_int = node
1094            .declare_parameter("undeclared_int")
1095            .default(10)
1096            .mandatory()
1097            .unwrap();
1098        assert_eq!(undeclared_int.get(), 42);
1099    }
1100
1101    #[test]
1102    fn test_override_undeclared_set_priority() {
1103        let ctx = Context::new([
1104            String::from("--ros-args"),
1105            String::from("-p"),
1106            String::from("declared_int:=10"),
1107        ])
1108        .unwrap();
1109        let node = create_node(&ctx, "param_test_node").unwrap();
1110        // If a parameter was set as an override and as an undeclared parameter, the undeclared
1111        // value should get priority
1112        node.use_undeclared_parameters()
1113            .set("declared_int", 20)
1114            .unwrap();
1115        let param = node
1116            .declare_parameter("declared_int")
1117            .default(30)
1118            .mandatory()
1119            .unwrap();
1120        assert_eq!(param.get(), 20);
1121    }
1122
1123    #[test]
1124    fn test_parameter_scope_redeclaring() {
1125        let ctx = Context::new([
1126            String::from("--ros-args"),
1127            String::from("-p"),
1128            String::from("declared_int:=10"),
1129        ])
1130        .unwrap();
1131        let node = create_node(&ctx, "param_test_node").unwrap();
1132        {
1133            // Setting a parameter with an override
1134            let param = node
1135                .declare_parameter("declared_int")
1136                .default(1)
1137                .mandatory()
1138                .unwrap();
1139            assert_eq!(param.get(), 10);
1140            param.set(2).unwrap();
1141            assert_eq!(param.get(), 2);
1142            // Redeclaring should fail
1143            assert!(matches!(
1144                node.declare_parameter("declared_int")
1145                    .default(1)
1146                    .mandatory(),
1147                Err(DeclarationError::AlreadyDeclared)
1148            ));
1149        }
1150        {
1151            // Parameter went out of scope, redeclaring should be OK and return command line
1152            // override
1153            let param = node
1154                .declare_parameter::<i64>("declared_int")
1155                .mandatory()
1156                .unwrap();
1157            assert_eq!(param.get(), 10);
1158        }
1159        // After a declared parameter went out of scope and was cleared, it should still be
1160        // possible to use it as an undeclared parameter, type can now be changed
1161        assert!(node
1162            .use_undeclared_parameters()
1163            .get::<i64>("declared_int")
1164            .is_none());
1165        node.use_undeclared_parameters()
1166            .set("declared_int", 1.0)
1167            .unwrap();
1168        assert_eq!(
1169            node.use_undeclared_parameters().get::<f64>("declared_int"),
1170            Some(1.0)
1171        );
1172    }
1173
1174    #[test]
1175    fn test_parameter_ranges() {
1176        let ctx = Context::new([]).unwrap();
1177        let node = create_node(&ctx, "param_test_node").unwrap();
1178        // Setting invalid ranges should fail
1179        let range = ParameterRange {
1180            lower: Some(10),
1181            upper: Some(-10),
1182            step: Some(3),
1183        };
1184        assert!(matches!(
1185            node.declare_parameter("int_param")
1186                .default(5)
1187                .range(range)
1188                .mandatory(),
1189            Err(DeclarationError::InvalidRange)
1190        ));
1191        let range = ParameterRange {
1192            lower: Some(-10),
1193            upper: Some(10),
1194            step: Some(-1),
1195        };
1196        assert!(matches!(
1197            node.declare_parameter("int_param")
1198                .default(5)
1199                .range(range)
1200                .mandatory(),
1201            Err(DeclarationError::InvalidRange)
1202        ));
1203        // Setting parameters out of range should fail
1204        let range = ParameterRange {
1205            lower: Some(-10),
1206            upper: Some(10),
1207            step: Some(3),
1208        };
1209        assert!(matches!(
1210            node.declare_parameter("out_of_range_int")
1211                .default(100)
1212                .range(range.clone())
1213                .mandatory(),
1214            Err(DeclarationError::InitialValueOutOfRange)
1215        ));
1216        assert!(matches!(
1217            node.declare_parameter("wrong_step_int")
1218                .default(-9)
1219                .range(range.clone())
1220                .mandatory(),
1221            Err(DeclarationError::InitialValueOutOfRange)
1222        ));
1223        let param = node
1224            .declare_parameter("int_param")
1225            .default(-7)
1226            .range(range)
1227            .mandatory()
1228            .unwrap();
1229        // Out of step but equal to upper, this is OK
1230        assert!(param.set(10).is_ok());
1231        // Trying to set it as undeclared should have the same result
1232        assert!(matches!(
1233            node.use_undeclared_parameters().set("int_param", 100),
1234            Err(ParameterValueError::OutOfRange)
1235        ));
1236        assert!(matches!(
1237            node.use_undeclared_parameters().set("int_param", -9),
1238            Err(ParameterValueError::OutOfRange)
1239        ));
1240        assert!(node
1241            .use_undeclared_parameters()
1242            .set("int_param", -4)
1243            .is_ok());
1244
1245        // Same for a double parameter
1246        let range = ParameterRange {
1247            lower: Some(-10.0),
1248            upper: Some(10.0),
1249            step: Some(3.0),
1250        };
1251        assert!(matches!(
1252            node.declare_parameter("out_of_range_double")
1253                .default(100.0)
1254                .range(range.clone())
1255                .optional(),
1256            Err(DeclarationError::InitialValueOutOfRange)
1257        ));
1258        assert!(matches!(
1259            node.declare_parameter("wrong_step_double")
1260                .default(-9.0)
1261                .range(range.clone())
1262                .read_only(),
1263            Err(DeclarationError::InitialValueOutOfRange)
1264        ));
1265        let param = node
1266            .declare_parameter("double_param")
1267            .default(-7.0)
1268            .range(range.clone())
1269            .mandatory()
1270            .unwrap();
1271        // Out of step but equal to upper, this is OK
1272        assert!(param.set(10.0).is_ok());
1273        // Quite close but out of tolerance, should fail
1274        assert!(matches!(
1275            param.set(-7.001),
1276            Err(ParameterValueError::OutOfRange)
1277        ));
1278        // Close to step within a few EPSILON, should be OK
1279        assert!(param.set(-7.0 - f64::EPSILON * 10.0).is_ok());
1280        assert!(param.set(-7.0 + f64::EPSILON * 10.0).is_ok());
1281        // Close to upper within a few EPSILON, should be OK
1282        assert!(param.set(10.0 - f64::EPSILON * 10.0).is_ok());
1283        assert!(param.set(10.0 + f64::EPSILON * 10.0).is_ok());
1284        // Close to lower within a few EPSILON, should be OK
1285        assert!(param.set(-10.0 - f64::EPSILON * 10.0).is_ok());
1286        assert!(param.set(-10.0 + f64::EPSILON * 10.0).is_ok());
1287        // Trying to set it as undeclared should have the same result
1288        assert!(matches!(
1289            node.use_undeclared_parameters().set("double_param", 100.0),
1290            Err(ParameterValueError::OutOfRange)
1291        ));
1292        assert!(matches!(
1293            node.use_undeclared_parameters().set("double_param", -9.0),
1294            Err(ParameterValueError::OutOfRange)
1295        ));
1296        assert!(node
1297            .use_undeclared_parameters()
1298            .set("double_param", -4.0)
1299            .is_ok());
1300    }
1301
1302    #[test]
1303    fn test_readonly_parameters() {
1304        let ctx = Context::new([]).unwrap();
1305        let node = create_node(&ctx, "param_test_node").unwrap();
1306        let param = node
1307            .declare_parameter("int_param")
1308            .default(100)
1309            .read_only()
1310            .unwrap();
1311        // Multiple copies cannot be declared
1312        assert!(matches!(
1313            node.declare_parameter("int_param").default(100).read_only(),
1314            Err(DeclarationError::AlreadyDeclared)
1315        ));
1316        // A reading should work and return the correct value:w
1317        assert_eq!(param.get(), 100);
1318        assert_eq!(
1319            node.use_undeclared_parameters().get::<i64>("int_param"),
1320            Some(100)
1321        );
1322        // Setting should fail
1323        assert!(matches!(
1324            node.use_undeclared_parameters().set("int_param", 10),
1325            Err(ParameterValueError::ReadOnly)
1326        ));
1327    }
1328
1329    #[test]
1330    fn test_preexisting_value_error() {
1331        let ctx = Context::new([]).unwrap();
1332        let node = create_node(&ctx, "param_test_node").unwrap();
1333        node.use_undeclared_parameters()
1334            .set("int_param", 100)
1335            .unwrap();
1336
1337        assert!(matches!(
1338            node.declare_parameter("int_param").default(1.0).mandatory(),
1339            Err(DeclarationError::PriorValueTypeMismatch)
1340        ));
1341
1342        let range = ParameterRange {
1343            lower: Some(-10),
1344            upper: Some(10),
1345            step: Some(3),
1346        };
1347        assert!(matches!(
1348            node.declare_parameter("int_param")
1349                .default(-1)
1350                .range(range.clone())
1351                .discriminate(|available| { available.prior_value })
1352                .mandatory(),
1353            Err(DeclarationError::InitialValueOutOfRange)
1354        ));
1355
1356        {
1357            // We now ask to discard the mismatching prior value, so we no
1358            // longer get an error.
1359            let param = node
1360                .declare_parameter("int_param")
1361                .default(1.0)
1362                .discard_mismatching_prior_value()
1363                .mandatory()
1364                .unwrap();
1365            assert_eq!(param.get(), 1.0);
1366        }
1367        {
1368            // The out of range prior value will be discarded by default.
1369            node.use_undeclared_parameters()
1370                .set("int_param", 100)
1371                .unwrap();
1372            let param = node
1373                .declare_parameter("int_param")
1374                .default(5)
1375                .range(range)
1376                .mandatory()
1377                .unwrap();
1378            assert_eq!(param.get(), 5);
1379        }
1380    }
1381
1382    #[test]
1383    fn test_optional_parameter_apis() {
1384        let ctx = Context::new([]).unwrap();
1385        let node = create_node(&ctx, "param_test_node").unwrap();
1386        node.declare_parameter::<i64>("int_param")
1387            .optional()
1388            .unwrap();
1389    }
1390}