do_not_use_testing_rclrs/parameter/
value.rs1use std::ffi::CStr;
2use std::sync::Arc;
3
4use crate::rcl_bindings::*;
5use crate::{ParameterRange, ParameterRanges, ParameterValueError};
6
7#[derive(Clone, Debug, PartialEq)]
12pub enum ParameterValue {
13 Bool(bool),
17 Integer(i64),
21 Double(f64),
25 String(Arc<str>),
32 ByteArray(Arc<[u8]>),
36 BoolArray(Arc<[bool]>),
40 IntegerArray(Arc<[i64]>),
44 DoubleArray(Arc<[f64]>),
48 StringArray(Arc<[Arc<str>]>),
52}
53
54#[derive(Clone, Debug, PartialEq)]
57pub enum ParameterKind {
58 Bool,
60 Integer,
62 Double,
64 String,
66 ByteArray,
68 BoolArray,
70 IntegerArray,
72 DoubleArray,
74 StringArray,
76 Dynamic,
78}
79
80impl From<bool> for ParameterValue {
81 fn from(value: bool) -> ParameterValue {
82 ParameterValue::Bool(value)
83 }
84}
85
86impl From<i64> for ParameterValue {
87 fn from(value: i64) -> ParameterValue {
88 ParameterValue::Integer(value)
89 }
90}
91
92impl From<f64> for ParameterValue {
93 fn from(value: f64) -> ParameterValue {
94 ParameterValue::Double(value)
95 }
96}
97
98impl From<Arc<str>> for ParameterValue {
99 fn from(value: Arc<str>) -> ParameterValue {
100 ParameterValue::String(value)
101 }
102}
103
104impl From<Arc<[u8]>> for ParameterValue {
105 fn from(value: Arc<[u8]>) -> ParameterValue {
106 ParameterValue::ByteArray(value)
107 }
108}
109
110impl From<Arc<[bool]>> for ParameterValue {
111 fn from(value: Arc<[bool]>) -> ParameterValue {
112 ParameterValue::BoolArray(value)
113 }
114}
115
116impl From<Arc<[i64]>> for ParameterValue {
117 fn from(value: Arc<[i64]>) -> ParameterValue {
118 ParameterValue::IntegerArray(value)
119 }
120}
121
122impl From<Arc<[f64]>> for ParameterValue {
123 fn from(value: Arc<[f64]>) -> ParameterValue {
124 ParameterValue::DoubleArray(value)
125 }
126}
127
128impl From<Arc<[Arc<str>]>> for ParameterValue {
129 fn from(value: Arc<[Arc<str>]>) -> ParameterValue {
130 ParameterValue::StringArray(value)
131 }
132}
133
134pub trait ParameterVariant: Into<ParameterValue> + Clone + TryFrom<ParameterValue> {
136 type Range: Into<ParameterRanges> + Default + Clone;
138
139 fn kind() -> ParameterKind;
141}
142
143impl TryFrom<ParameterValue> for bool {
144 type Error = ParameterValueError;
145
146 fn try_from(value: ParameterValue) -> Result<Self, Self::Error> {
147 match value {
148 ParameterValue::Bool(v) => Ok(v),
149 _ => Err(ParameterValueError::TypeMismatch),
150 }
151 }
152}
153
154impl ParameterVariant for bool {
155 type Range = ();
156
157 fn kind() -> ParameterKind {
158 ParameterKind::Bool
159 }
160}
161
162impl TryFrom<ParameterValue> for i64 {
163 type Error = ParameterValueError;
164
165 fn try_from(value: ParameterValue) -> Result<Self, Self::Error> {
166 match value {
167 ParameterValue::Integer(v) => Ok(v),
168 _ => Err(ParameterValueError::TypeMismatch),
169 }
170 }
171}
172
173impl ParameterVariant for i64 {
174 type Range = ParameterRange<i64>;
175
176 fn kind() -> ParameterKind {
177 ParameterKind::Integer
178 }
179}
180
181impl TryFrom<ParameterValue> for f64 {
182 type Error = ParameterValueError;
183
184 fn try_from(value: ParameterValue) -> Result<Self, Self::Error> {
185 match value {
186 ParameterValue::Double(v) => Ok(v),
187 _ => Err(ParameterValueError::TypeMismatch),
188 }
189 }
190}
191
192impl ParameterVariant for f64 {
193 type Range = ParameterRange<f64>;
194
195 fn kind() -> ParameterKind {
196 ParameterKind::Double
197 }
198}
199
200impl TryFrom<ParameterValue> for Arc<str> {
201 type Error = ParameterValueError;
202
203 fn try_from(value: ParameterValue) -> Result<Self, Self::Error> {
204 match value {
205 ParameterValue::String(v) => Ok(v),
206 _ => Err(ParameterValueError::TypeMismatch),
207 }
208 }
209}
210
211impl ParameterVariant for Arc<str> {
212 type Range = ();
213
214 fn kind() -> ParameterKind {
215 ParameterKind::String
216 }
217}
218
219impl TryFrom<ParameterValue> for Arc<[u8]> {
220 type Error = ParameterValueError;
221
222 fn try_from(value: ParameterValue) -> Result<Self, Self::Error> {
223 match value {
224 ParameterValue::ByteArray(v) => Ok(v),
225 _ => Err(ParameterValueError::TypeMismatch),
226 }
227 }
228}
229
230impl ParameterVariant for Arc<[u8]> {
231 type Range = ();
232
233 fn kind() -> ParameterKind {
234 ParameterKind::ByteArray
235 }
236}
237
238impl TryFrom<ParameterValue> for Arc<[bool]> {
239 type Error = ParameterValueError;
240
241 fn try_from(value: ParameterValue) -> Result<Self, Self::Error> {
242 match value {
243 ParameterValue::BoolArray(v) => Ok(v),
244 _ => Err(ParameterValueError::TypeMismatch),
245 }
246 }
247}
248
249impl ParameterVariant for Arc<[bool]> {
250 type Range = ();
251
252 fn kind() -> ParameterKind {
253 ParameterKind::BoolArray
254 }
255}
256
257impl TryFrom<ParameterValue> for Arc<[i64]> {
258 type Error = ParameterValueError;
259
260 fn try_from(value: ParameterValue) -> Result<Self, Self::Error> {
261 match value {
262 ParameterValue::IntegerArray(v) => Ok(v),
263 _ => Err(ParameterValueError::TypeMismatch),
264 }
265 }
266}
267
268impl ParameterVariant for Arc<[i64]> {
269 type Range = ();
270
271 fn kind() -> ParameterKind {
272 ParameterKind::IntegerArray
273 }
274}
275
276impl TryFrom<ParameterValue> for Arc<[f64]> {
277 type Error = ParameterValueError;
278
279 fn try_from(value: ParameterValue) -> Result<Self, Self::Error> {
280 match value {
281 ParameterValue::DoubleArray(v) => Ok(v),
282 _ => Err(ParameterValueError::TypeMismatch),
283 }
284 }
285}
286
287impl ParameterVariant for Arc<[f64]> {
288 type Range = ();
289
290 fn kind() -> ParameterKind {
291 ParameterKind::DoubleArray
292 }
293}
294
295impl TryFrom<ParameterValue> for Arc<[Arc<str>]> {
296 type Error = ParameterValueError;
297
298 fn try_from(value: ParameterValue) -> Result<Self, Self::Error> {
299 match value {
300 ParameterValue::StringArray(v) => Ok(v),
301 _ => Err(ParameterValueError::TypeMismatch),
302 }
303 }
304}
305
306impl ParameterVariant for Arc<[Arc<str>]> {
307 type Range = ();
308
309 fn kind() -> ParameterKind {
310 ParameterKind::StringArray
311 }
312}
313
314impl ParameterVariant for ParameterValue {
315 type Range = ParameterRanges;
316
317 fn kind() -> ParameterKind {
318 ParameterKind::Dynamic
319 }
320}
321
322impl ParameterValue {
323 pub(crate) unsafe fn from_rcl_variant(var: &rcl_variant_t) -> Self {
328 let num_active: u8 = [
329 !var.bool_value.is_null(),
330 !var.integer_value.is_null(),
331 !var.double_value.is_null(),
332 !var.string_value.is_null(),
333 !var.byte_array_value.is_null(),
334 !var.bool_array_value.is_null(),
335 !var.integer_array_value.is_null(),
336 !var.double_array_value.is_null(),
337 !var.string_array_value.is_null(),
338 ]
339 .into_iter()
340 .map(u8::from)
341 .sum();
342 assert_eq!(num_active, 1);
343 if !var.bool_value.is_null() {
352 ParameterValue::Bool(*var.bool_value)
353 } else if !var.integer_value.is_null() {
354 ParameterValue::Integer(*var.integer_value)
355 } else if !var.double_value.is_null() {
356 ParameterValue::Double(*var.double_value)
357 } else if !var.string_value.is_null() {
358 let cstr = CStr::from_ptr(var.string_value);
359 let s = cstr.to_string_lossy().into_owned();
360 ParameterValue::String(s.into())
361 } else if !var.byte_array_value.is_null() {
362 let rcl_byte_array = &*var.byte_array_value;
363 let slice = std::slice::from_raw_parts(rcl_byte_array.values, rcl_byte_array.size);
364 ParameterValue::ByteArray(slice.into())
365 } else if !var.bool_array_value.is_null() {
366 let rcl_bool_array = &*var.bool_array_value;
367 let slice = std::slice::from_raw_parts(rcl_bool_array.values, rcl_bool_array.size);
368 ParameterValue::BoolArray(slice.into())
369 } else if !var.integer_array_value.is_null() {
370 let rcl_integer_array = &*var.integer_array_value;
371 let slice =
372 std::slice::from_raw_parts(rcl_integer_array.values, rcl_integer_array.size);
373 ParameterValue::IntegerArray(slice.into())
374 } else if !var.double_array_value.is_null() {
375 let rcl_double_array = &*var.double_array_value;
376 let slice = std::slice::from_raw_parts(rcl_double_array.values, rcl_double_array.size);
377 ParameterValue::DoubleArray(slice.into())
378 } else if !var.string_array_value.is_null() {
379 let rcutils_string_array = &*var.string_array_value;
380 let slice =
381 std::slice::from_raw_parts(rcutils_string_array.data, rcutils_string_array.size);
382 let strings = slice
383 .iter()
384 .map(|&ptr| {
385 debug_assert!(!ptr.is_null());
386 let cstr = CStr::from_ptr(ptr);
387 Arc::from(cstr.to_string_lossy())
388 })
389 .collect::<Vec<_>>();
390 ParameterValue::StringArray(strings.into())
391 } else {
392 unreachable!()
393 }
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400 use crate::{Context, RclrsError, ToResult};
401
402 #[test]
405 fn test_parameter_value() -> Result<(), RclrsError> {
406 let input_output_pairs = [
409 ("true", ParameterValue::Bool(true)),
410 ("1", ParameterValue::Integer(1)),
411 ("1.0", ParameterValue::Double(1.0)),
412 ("'1.0'", ParameterValue::String(Arc::from("1.0"))),
413 (
414 "[yes, no]",
415 ParameterValue::BoolArray(Arc::from([true, false])),
416 ),
417 ("[-3, 2]", ParameterValue::IntegerArray(Arc::from([-3, 2]))),
418 (
419 "[-3.0, 2.0]",
420 ParameterValue::DoubleArray(Arc::from([-3.0, 2.0])),
421 ),
422 (
423 "['yes']",
424 ParameterValue::StringArray(Arc::from([Arc::from("yes")])),
425 ),
426 ];
427 for pair in input_output_pairs {
428 let ctx = Context::new([
429 String::from("--ros-args"),
430 String::from("-p"),
431 format!("foo:={}", pair.0),
432 ])?;
433 let mut rcl_params = std::ptr::null_mut();
434 unsafe {
435 rcl_arguments_get_param_overrides(
436 &ctx.rcl_context_mtx.lock().unwrap().global_arguments,
437 &mut rcl_params,
438 )
439 .ok()?;
440 }
441 assert!(!rcl_params.is_null());
442 assert_eq!(unsafe { (*rcl_params).num_nodes }, 1);
443 let rcl_node_params = unsafe { &(*(*rcl_params).params) };
444 assert_eq!(rcl_node_params.num_params, 1);
445 let rcl_variant = unsafe { &(*rcl_node_params.parameter_values) };
446 let param_value = unsafe { ParameterValue::from_rcl_variant(rcl_variant) };
447 assert_eq!(param_value, pair.1);
448 unsafe { rcl_yaml_node_struct_fini(rcl_params) };
449 }
450 Ok(())
451 }
452}