Skip to main content

oxidros_msg/
primitives.rs

1//! Definition of ROS2 primitive types
2//!
3
4use std::fmt::Display;
5
6// ============================================================================
7// rcl feature - FFI implementations
8// ============================================================================
9#[cfg(feature = "rcl")]
10mod rcl_impl {
11    use crate::rcl::*;
12
13    macro_rules! def_sequence {
14        ($ty: ident, $ty_orig:ty, $ty_seq:ty, $init:ident, $fini:ident, $eq:ident, $copy:ident) => {
15            /// A sequence of elements.
16            /// `N` represents the maximum number of elements.
17            /// If `N` is `0`, the sequence is unlimited.
18            #[repr(C)]
19            #[derive(Debug)]
20            pub struct $ty<const N: usize>($ty_seq);
21
22            impl<const N: usize> $ty<N> {
23                pub fn new(size: usize) -> Option<Self> {
24                    if N != 0 && size > N {
25                        // the size exceeds in the maximum number
26                        return None;
27                    }
28
29                    let mut msg: $ty_seq = unsafe { std::mem::zeroed() };
30                    if unsafe { $init(&mut msg, size as _) } {
31                        Some($ty(msg))
32                    } else {
33                        None
34                    }
35                }
36
37                pub fn null() -> Self {
38                    let msg: $ty_seq = unsafe { std::mem::zeroed() };
39                    $ty(msg)
40                }
41
42                pub fn as_slice(&self) -> &[$ty_orig] {
43                    if self.0.data.is_null() {
44                        &[]
45                    } else {
46                        let s = unsafe {
47                            std::slice::from_raw_parts(self.0.data, self.0.size as usize)
48                        };
49                        s
50                    }
51                }
52
53                pub fn as_mut_slice(&mut self) -> &mut [$ty_orig] {
54                    if self.0.data.is_null() {
55                        &mut []
56                    } else {
57                        let s = unsafe {
58                            std::slice::from_raw_parts_mut(self.0.data, self.0.size as usize)
59                        };
60                        s
61                    }
62                }
63
64                pub fn iter(&self) -> std::slice::Iter<'_, $ty_orig> {
65                    self.as_slice().iter()
66                }
67
68                pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, $ty_orig> {
69                    self.as_mut_slice().iter_mut()
70                }
71
72                pub fn len(&self) -> usize {
73                    self.as_slice().len()
74                }
75
76                pub fn is_empty(&self) -> bool {
77                    self.len() == 0
78                }
79            }
80
81            impl<const N: usize> Drop for $ty<N> {
82                fn drop(&mut self) {
83                    unsafe { $fini(&mut self.0 as *mut _) };
84                }
85            }
86
87            impl<const N: usize> PartialEq for $ty<N> {
88                fn eq(&self, other: &Self) -> bool {
89                    unsafe { $eq(&self.0, &other.0) }
90                }
91            }
92
93            impl<const N: usize> ::oxidros_core::msg::TryClone for $ty<N> {
94                fn try_clone(&self) -> Option<Self> {
95                    let mut result = Self::new(self.0.size)?;
96                    if unsafe { $copy(&self.0, &mut result.0) } {
97                        Some(result)
98                    } else {
99                        None
100                    }
101                }
102            }
103
104            impl<const N: usize> Clone for $ty<N> {
105                fn clone(&self) -> Self {
106                    ::oxidros_core::msg::TryClone::try_clone(self).unwrap()
107                }
108            }
109
110            impl<const N: usize> Default for $ty<N> {
111                fn default() -> Self {
112                    Self::null()
113                }
114            }
115
116            unsafe impl<const N: usize> Sync for $ty<N> {}
117            unsafe impl<const N: usize> Send for $ty<N> {}
118        };
119    }
120
121    def_sequence!(
122        BoolSeq,
123        bool,
124        rosidl_runtime_c__boolean__Sequence,
125        rosidl_runtime_c__boolean__Sequence__init,
126        rosidl_runtime_c__boolean__Sequence__fini,
127        rosidl_runtime_c__boolean__Sequence__are_equal,
128        rosidl_runtime_c__boolean__Sequence__copy
129    );
130
131    def_sequence!(
132        F32Seq,
133        f32,
134        rosidl_runtime_c__float__Sequence,
135        rosidl_runtime_c__float__Sequence__init,
136        rosidl_runtime_c__float__Sequence__fini,
137        rosidl_runtime_c__float__Sequence__are_equal,
138        rosidl_runtime_c__float__Sequence__copy
139    );
140
141    def_sequence!(
142        F64Seq,
143        f64,
144        rosidl_runtime_c__double__Sequence,
145        rosidl_runtime_c__double__Sequence__init,
146        rosidl_runtime_c__double__Sequence__fini,
147        rosidl_runtime_c__double__Sequence__are_equal,
148        rosidl_runtime_c__double__Sequence__copy
149    );
150
151    def_sequence!(
152        U8Seq,
153        u8,
154        rosidl_runtime_c__uint8__Sequence,
155        rosidl_runtime_c__uint8__Sequence__init,
156        rosidl_runtime_c__uint8__Sequence__fini,
157        rosidl_runtime_c__uint8__Sequence__are_equal,
158        rosidl_runtime_c__uint8__Sequence__copy
159    );
160
161    // ByteSeq uses ROS2 byte/octet FFI - distinct from U8Seq for type hash purposes
162    // ROS2 byte (type_id 16) vs uint8 (type_id 7) have different type hashes
163    def_sequence!(
164        ByteSeq,
165        u8,
166        rosidl_runtime_c__octet__Sequence,
167        rosidl_runtime_c__octet__Sequence__init,
168        rosidl_runtime_c__octet__Sequence__fini,
169        rosidl_runtime_c__octet__Sequence__are_equal,
170        rosidl_runtime_c__octet__Sequence__copy
171    );
172
173    def_sequence!(
174        I8Seq,
175        i8,
176        rosidl_runtime_c__int8__Sequence,
177        rosidl_runtime_c__int8__Sequence__init,
178        rosidl_runtime_c__int8__Sequence__fini,
179        rosidl_runtime_c__int8__Sequence__are_equal,
180        rosidl_runtime_c__int8__Sequence__copy
181    );
182    def_sequence!(
183        U16Seq,
184        u16,
185        rosidl_runtime_c__uint16__Sequence,
186        rosidl_runtime_c__uint16__Sequence__init,
187        rosidl_runtime_c__uint16__Sequence__fini,
188        rosidl_runtime_c__uint16__Sequence__are_equal,
189        rosidl_runtime_c__uint16__Sequence__copy
190    );
191
192    def_sequence!(
193        I16Seq,
194        i16,
195        rosidl_runtime_c__int16__Sequence,
196        rosidl_runtime_c__int16__Sequence__init,
197        rosidl_runtime_c__int16__Sequence__fini,
198        rosidl_runtime_c__int16__Sequence__are_equal,
199        rosidl_runtime_c__int16__Sequence__copy
200    );
201
202    def_sequence!(
203        U32Seq,
204        u32,
205        rosidl_runtime_c__uint32__Sequence,
206        rosidl_runtime_c__uint32__Sequence__init,
207        rosidl_runtime_c__uint32__Sequence__fini,
208        rosidl_runtime_c__uint32__Sequence__are_equal,
209        rosidl_runtime_c__uint32__Sequence__copy
210    );
211
212    def_sequence!(
213        I32Seq,
214        i32,
215        rosidl_runtime_c__int32__Sequence,
216        rosidl_runtime_c__int32__Sequence__init,
217        rosidl_runtime_c__int32__Sequence__fini,
218        rosidl_runtime_c__int32__Sequence__are_equal,
219        rosidl_runtime_c__int32__Sequence__copy
220    );
221
222    def_sequence!(
223        U64Seq,
224        u64,
225        rosidl_runtime_c__uint64__Sequence,
226        rosidl_runtime_c__uint64__Sequence__init,
227        rosidl_runtime_c__uint64__Sequence__fini,
228        rosidl_runtime_c__uint64__Sequence__are_equal,
229        rosidl_runtime_c__uint64__Sequence__copy
230    );
231
232    def_sequence!(
233        I64Seq,
234        i64,
235        rosidl_runtime_c__int64__Sequence,
236        rosidl_runtime_c__int64__Sequence__init,
237        rosidl_runtime_c__int64__Sequence__fini,
238        rosidl_runtime_c__int64__Sequence__are_equal,
239        rosidl_runtime_c__int64__Sequence__copy
240    );
241}
242
243// ============================================================================
244// non-rcl feature - Pure Rust implementations
245// ============================================================================
246#[cfg(not(feature = "rcl"))]
247mod non_rcl_impl {
248    use ros2_types::serde::{Deserialize, Deserializer, Serialize, Serializer};
249
250    macro_rules! def_sequence {
251        ($ty: ident, $ty_orig:ty) => {
252            /// A sequence of elements.
253            /// `N` represents the maximum number of elements.
254            /// If `N` is `0`, the sequence is unlimited.
255            #[derive(Debug)]
256            pub struct $ty<const N: usize>(Vec<$ty_orig>);
257
258            impl<const N: usize> $ty<N> {
259                pub fn new(size: usize) -> Option<Self> {
260                    if N != 0 && size > N {
261                        // the size exceeds the maximum number
262                        return None;
263                    }
264                    Some($ty(vec![Default::default(); size]))
265                }
266
267                pub fn null() -> Self {
268                    $ty(Vec::new())
269                }
270
271                pub fn as_slice(&self) -> &[$ty_orig] {
272                    &self.0
273                }
274
275                pub fn as_mut_slice(&mut self) -> &mut [$ty_orig] {
276                    &mut self.0
277                }
278
279                pub fn iter(&self) -> std::slice::Iter<'_, $ty_orig> {
280                    self.0.iter()
281                }
282
283                pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, $ty_orig> {
284                    self.0.iter_mut()
285                }
286
287                pub fn len(&self) -> usize {
288                    self.0.len()
289                }
290
291                pub fn is_empty(&self) -> bool {
292                    self.0.is_empty()
293                }
294            }
295
296            impl<const N: usize> PartialEq for $ty<N> {
297                fn eq(&self, other: &Self) -> bool {
298                    self.0 == other.0
299                }
300            }
301
302            impl<const N: usize> ::oxidros_core::msg::TryClone for $ty<N> {
303                fn try_clone(&self) -> Option<Self> {
304                    Some($ty(self.0.clone()))
305                }
306            }
307
308            impl<const N: usize> Clone for $ty<N> {
309                fn clone(&self) -> Self {
310                    $ty(self.0.clone())
311                }
312            }
313
314            impl<const N: usize> Default for $ty<N> {
315                fn default() -> Self {
316                    Self::null()
317                }
318            }
319
320            impl<const N: usize> Serialize for $ty<N> {
321                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
322                where
323                    S: Serializer,
324                {
325                    self.0.serialize(serializer)
326                }
327            }
328
329            impl<'de, const N: usize> Deserialize<'de> for $ty<N> {
330                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
331                where
332                    D: Deserializer<'de>,
333                {
334                    let vec = Vec::<$ty_orig>::deserialize(deserializer)?;
335                    if N != 0 && vec.len() > N {
336                        return Err(ros2_types::serde::de::Error::custom(format!(
337                            "sequence length {} exceeds maximum {}",
338                            vec.len(),
339                            N
340                        )));
341                    }
342                    Ok($ty(vec))
343                }
344            }
345
346            unsafe impl<const N: usize> Sync for $ty<N> {}
347            unsafe impl<const N: usize> Send for $ty<N> {}
348        };
349    }
350
351    def_sequence!(BoolSeq, bool);
352    def_sequence!(F32Seq, f32);
353    def_sequence!(F64Seq, f64);
354    def_sequence!(U8Seq, u8);
355    def_sequence!(ByteSeq, u8); // Distinct from U8Seq for ROS2 type hash (byte vs uint8)
356    def_sequence!(I8Seq, i8);
357    def_sequence!(U16Seq, u16);
358    def_sequence!(I16Seq, i16);
359    def_sequence!(U32Seq, u32);
360    def_sequence!(I32Seq, i32);
361    def_sequence!(U64Seq, u64);
362    def_sequence!(I64Seq, i64);
363}
364
365// ============================================================================
366// Re-exports
367// ============================================================================
368#[cfg(feature = "rcl")]
369pub use rcl_impl::*;
370
371#[cfg(not(feature = "rcl"))]
372pub use non_rcl_impl::*;
373
374// ============================================================================
375// Common utilities
376// ============================================================================
377
378/// The error type returned when a conversion from a slice to an array fails.
379#[derive(Debug, Copy, Clone)]
380pub struct TryFromSliceError(());
381
382impl std::fmt::Display for TryFromSliceError {
383    #[inline]
384    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
385        "could not convert slice to array".fmt(f)
386    }
387}
388
389impl std::error::Error for TryFromSliceError {}
390
391macro_rules! def_try_from {
392    ($from:ty, $to:ty) => {
393        impl TryFrom<&[$from]> for $to {
394            type Error = TryFromSliceError;
395            fn try_from(value: &[$from]) -> Result<Self, Self::Error> {
396                let mut seq = Self::new(value.len()).ok_or(TryFromSliceError(()))?;
397                seq.iter_mut().zip(value).for_each(|(dst, &src)| *dst = src);
398                Ok(seq)
399            }
400        }
401    };
402}
403
404def_try_from!(bool, BoolSeq<0>);
405def_try_from!(i8, I8Seq<0>);
406def_try_from!(i16, I16Seq<0>);
407def_try_from!(i32, I32Seq<0>);
408def_try_from!(i64, I64Seq<0>);
409def_try_from!(u8, U8Seq<0>);
410def_try_from!(u16, U16Seq<0>);
411def_try_from!(u32, U32Seq<0>);
412def_try_from!(u64, U64Seq<0>);
413def_try_from!(f32, F32Seq<0>);
414def_try_from!(f64, F64Seq<0>);
415
416#[cfg(test)]
417mod tests {
418    use oxidros_core::msg::TryClone;
419
420    use super::*;
421
422    #[test]
423    fn test_clone() {
424        let v1: BoolSeq<0> = [true; 10].as_slice().try_into().unwrap();
425        let v2 = v1.try_clone().unwrap();
426        assert_eq!(v1, v2);
427        let v1: U32Seq<0> = [2; 10].as_slice().try_into().unwrap();
428        let v2 = v1.try_clone().unwrap();
429        assert_eq!(v1, v2);
430    }
431}
432
433// ============================================================================
434// RosFieldType implementations for primitive sequences
435// ============================================================================
436
437use ros2_types::RosFieldType;
438use ros2_types::types::FieldType;
439
440macro_rules! impl_ros_field_type_seq {
441    ($ty:ident, $type_id:ident) => {
442        impl<const N: usize> RosFieldType for $ty<N> {
443            fn ros_field_type() -> FieldType {
444                if N == 0 {
445                    FieldType::sequence(ros2_types::$type_id)
446                } else {
447                    FieldType::bounded_sequence(ros2_types::$type_id, N as u64)
448                }
449            }
450        }
451    };
452}
453
454impl_ros_field_type_seq!(BoolSeq, FIELD_TYPE_BOOLEAN);
455impl_ros_field_type_seq!(I8Seq, FIELD_TYPE_INT8);
456impl_ros_field_type_seq!(U8Seq, FIELD_TYPE_UINT8);
457impl_ros_field_type_seq!(ByteSeq, FIELD_TYPE_BYTE);
458impl_ros_field_type_seq!(I16Seq, FIELD_TYPE_INT16);
459impl_ros_field_type_seq!(U16Seq, FIELD_TYPE_UINT16);
460impl_ros_field_type_seq!(I32Seq, FIELD_TYPE_INT32);
461impl_ros_field_type_seq!(U32Seq, FIELD_TYPE_UINT32);
462impl_ros_field_type_seq!(I64Seq, FIELD_TYPE_INT64);
463impl_ros_field_type_seq!(U64Seq, FIELD_TYPE_UINT64);
464impl_ros_field_type_seq!(F32Seq, FIELD_TYPE_FLOAT);
465impl_ros_field_type_seq!(F64Seq, FIELD_TYPE_DOUBLE);