Skip to main content

ros2_types/
types.rs

1//! Type description data structures
2//!
3//! These structures match the ROS2 type_description_interfaces
4
5use serde::{Deserialize, Serialize};
6
7/// Complete type description message including referenced types
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct TypeDescriptionMsg {
10    /// The main type being described
11    pub type_description: IndividualTypeDescription,
12    /// All types referenced by the main type
13    pub referenced_type_descriptions: Vec<IndividualTypeDescription>,
14}
15
16/// Description of a single type
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct IndividualTypeDescription {
19    /// Fully qualified type name (e.g., "std_msgs/msg/Header")
20    pub type_name: String,
21    /// Fields in this type
22    pub fields: Vec<Field>,
23}
24
25/// Description of a field in a type
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct Field {
28    /// Field name
29    pub name: String,
30    /// Field type information
31    #[serde(rename = "type")]
32    pub field_type: FieldType,
33    /// Default value (empty string if none)
34    pub default_value: String,
35}
36
37/// Type information for a field
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct FieldType {
40    /// Type ID from FieldType.msg constants
41    pub type_id: u8,
42    /// Array/sequence capacity (0 if not applicable)
43    pub capacity: u64,
44    /// String capacity (0 if not applicable)
45    pub string_capacity: u64,
46    /// Nested type name (empty if not a nested type)
47    pub nested_type_name: String,
48}
49
50// Field type constants matching type_description_interfaces/msg/FieldType.msg
51pub const FIELD_TYPE_NOT_SET: u8 = 0;
52pub const FIELD_TYPE_NESTED_TYPE: u8 = 1;
53pub const FIELD_TYPE_INT8: u8 = 2;
54pub const FIELD_TYPE_UINT8: u8 = 3;
55pub const FIELD_TYPE_INT16: u8 = 4;
56pub const FIELD_TYPE_UINT16: u8 = 5;
57pub const FIELD_TYPE_INT32: u8 = 6;
58pub const FIELD_TYPE_UINT32: u8 = 7;
59pub const FIELD_TYPE_INT64: u8 = 8;
60pub const FIELD_TYPE_UINT64: u8 = 9;
61pub const FIELD_TYPE_FLOAT: u8 = 10;
62pub const FIELD_TYPE_DOUBLE: u8 = 11;
63pub const FIELD_TYPE_LONG_DOUBLE: u8 = 12;
64pub const FIELD_TYPE_CHAR: u8 = 13;
65pub const FIELD_TYPE_WCHAR: u8 = 14;
66pub const FIELD_TYPE_BOOLEAN: u8 = 15;
67pub const FIELD_TYPE_BYTE: u8 = 16;
68pub const FIELD_TYPE_STRING: u8 = 17;
69pub const FIELD_TYPE_WSTRING: u8 = 18;
70pub const FIELD_TYPE_FIXED_STRING: u8 = 19;
71pub const FIELD_TYPE_FIXED_WSTRING: u8 = 20;
72pub const FIELD_TYPE_BOUNDED_STRING: u8 = 21;
73pub const FIELD_TYPE_BOUNDED_WSTRING: u8 = 22;
74
75// Fixed-size arrays (49-96)
76pub const FIELD_TYPE_NESTED_TYPE_ARRAY: u8 = 49;
77pub const FIELD_TYPE_INT8_ARRAY: u8 = 50;
78pub const FIELD_TYPE_UINT8_ARRAY: u8 = 51;
79pub const FIELD_TYPE_INT16_ARRAY: u8 = 52;
80pub const FIELD_TYPE_UINT16_ARRAY: u8 = 53;
81pub const FIELD_TYPE_INT32_ARRAY: u8 = 54;
82pub const FIELD_TYPE_UINT32_ARRAY: u8 = 55;
83pub const FIELD_TYPE_INT64_ARRAY: u8 = 56;
84pub const FIELD_TYPE_UINT64_ARRAY: u8 = 57;
85pub const FIELD_TYPE_FLOAT_ARRAY: u8 = 58;
86pub const FIELD_TYPE_DOUBLE_ARRAY: u8 = 59;
87pub const FIELD_TYPE_LONG_DOUBLE_ARRAY: u8 = 60;
88pub const FIELD_TYPE_CHAR_ARRAY: u8 = 61;
89pub const FIELD_TYPE_WCHAR_ARRAY: u8 = 62;
90pub const FIELD_TYPE_BOOLEAN_ARRAY: u8 = 63;
91pub const FIELD_TYPE_BYTE_ARRAY: u8 = 64;
92pub const FIELD_TYPE_STRING_ARRAY: u8 = 65;
93pub const FIELD_TYPE_WSTRING_ARRAY: u8 = 66;
94
95// Bounded sequences (97-144)
96pub const FIELD_TYPE_NESTED_TYPE_BOUNDED_SEQUENCE: u8 = 97;
97pub const FIELD_TYPE_INT8_BOUNDED_SEQUENCE: u8 = 98;
98pub const FIELD_TYPE_UINT8_BOUNDED_SEQUENCE: u8 = 99;
99pub const FIELD_TYPE_INT16_BOUNDED_SEQUENCE: u8 = 100;
100pub const FIELD_TYPE_UINT16_BOUNDED_SEQUENCE: u8 = 101;
101pub const FIELD_TYPE_INT32_BOUNDED_SEQUENCE: u8 = 102;
102pub const FIELD_TYPE_UINT32_BOUNDED_SEQUENCE: u8 = 103;
103pub const FIELD_TYPE_INT64_BOUNDED_SEQUENCE: u8 = 104;
104pub const FIELD_TYPE_UINT64_BOUNDED_SEQUENCE: u8 = 105;
105pub const FIELD_TYPE_FLOAT_BOUNDED_SEQUENCE: u8 = 106;
106pub const FIELD_TYPE_DOUBLE_BOUNDED_SEQUENCE: u8 = 107;
107pub const FIELD_TYPE_LONG_DOUBLE_BOUNDED_SEQUENCE: u8 = 108;
108pub const FIELD_TYPE_CHAR_BOUNDED_SEQUENCE: u8 = 109;
109pub const FIELD_TYPE_WCHAR_BOUNDED_SEQUENCE: u8 = 110;
110pub const FIELD_TYPE_BOOLEAN_BOUNDED_SEQUENCE: u8 = 111;
111pub const FIELD_TYPE_BYTE_BOUNDED_SEQUENCE: u8 = 112;
112pub const FIELD_TYPE_STRING_BOUNDED_SEQUENCE: u8 = 113;
113pub const FIELD_TYPE_WSTRING_BOUNDED_SEQUENCE: u8 = 114;
114
115// Unbounded sequences (145-192)
116pub const FIELD_TYPE_NESTED_TYPE_UNBOUNDED_SEQUENCE: u8 = 145;
117pub const FIELD_TYPE_INT8_UNBOUNDED_SEQUENCE: u8 = 146;
118pub const FIELD_TYPE_UINT8_UNBOUNDED_SEQUENCE: u8 = 147;
119pub const FIELD_TYPE_INT16_UNBOUNDED_SEQUENCE: u8 = 148;
120pub const FIELD_TYPE_UINT16_UNBOUNDED_SEQUENCE: u8 = 149;
121pub const FIELD_TYPE_INT32_UNBOUNDED_SEQUENCE: u8 = 150;
122pub const FIELD_TYPE_UINT32_UNBOUNDED_SEQUENCE: u8 = 151;
123pub const FIELD_TYPE_INT64_UNBOUNDED_SEQUENCE: u8 = 152;
124pub const FIELD_TYPE_UINT64_UNBOUNDED_SEQUENCE: u8 = 153;
125pub const FIELD_TYPE_FLOAT_UNBOUNDED_SEQUENCE: u8 = 154;
126pub const FIELD_TYPE_DOUBLE_UNBOUNDED_SEQUENCE: u8 = 155;
127pub const FIELD_TYPE_LONG_DOUBLE_UNBOUNDED_SEQUENCE: u8 = 156;
128pub const FIELD_TYPE_CHAR_UNBOUNDED_SEQUENCE: u8 = 157;
129pub const FIELD_TYPE_WCHAR_UNBOUNDED_SEQUENCE: u8 = 158;
130pub const FIELD_TYPE_BOOLEAN_UNBOUNDED_SEQUENCE: u8 = 159;
131pub const FIELD_TYPE_BYTE_UNBOUNDED_SEQUENCE: u8 = 160;
132pub const FIELD_TYPE_STRING_UNBOUNDED_SEQUENCE: u8 = 161;
133pub const FIELD_TYPE_WSTRING_UNBOUNDED_SEQUENCE: u8 = 162;
134
135impl FieldType {
136    /// Create a primitive field type
137    pub fn primitive(type_id: u8) -> Self {
138        Self {
139            type_id,
140            capacity: 0,
141            string_capacity: 0,
142            nested_type_name: String::new(),
143        }
144    }
145
146    /// Create a nested type field
147    pub fn nested(type_name: impl Into<String>) -> Self {
148        Self {
149            type_id: FIELD_TYPE_NESTED_TYPE,
150            capacity: 0,
151            string_capacity: 0,
152            nested_type_name: type_name.into(),
153        }
154    }
155
156    /// Create an unbounded sequence of nested types (Vec<NestedType>)
157    pub fn nested_sequence(type_name: impl Into<String>) -> Self {
158        Self {
159            type_id: FIELD_TYPE_NESTED_TYPE_UNBOUNDED_SEQUENCE,
160            capacity: 0,
161            string_capacity: 0,
162            nested_type_name: type_name.into(),
163        }
164    }
165
166    /// Create a fixed-size array field type (e.g., [T; N])
167    /// For nested types: [NestedType; N]
168    /// For primitives: [primitive; N]
169    pub fn array(base_type_id: u8, capacity: u64) -> Self {
170        let array_type_id = match base_type_id {
171            FIELD_TYPE_INT8 => FIELD_TYPE_INT8_ARRAY,
172            FIELD_TYPE_UINT8 => FIELD_TYPE_UINT8_ARRAY,
173            FIELD_TYPE_INT16 => FIELD_TYPE_INT16_ARRAY,
174            FIELD_TYPE_UINT16 => FIELD_TYPE_UINT16_ARRAY,
175            FIELD_TYPE_INT32 => FIELD_TYPE_INT32_ARRAY,
176            FIELD_TYPE_UINT32 => FIELD_TYPE_UINT32_ARRAY,
177            FIELD_TYPE_INT64 => FIELD_TYPE_INT64_ARRAY,
178            FIELD_TYPE_UINT64 => FIELD_TYPE_UINT64_ARRAY,
179            FIELD_TYPE_FLOAT => FIELD_TYPE_FLOAT_ARRAY,
180            FIELD_TYPE_DOUBLE => FIELD_TYPE_DOUBLE_ARRAY,
181            FIELD_TYPE_LONG_DOUBLE => FIELD_TYPE_LONG_DOUBLE_ARRAY,
182            FIELD_TYPE_CHAR => FIELD_TYPE_CHAR_ARRAY,
183            FIELD_TYPE_WCHAR => FIELD_TYPE_WCHAR_ARRAY,
184            FIELD_TYPE_BOOLEAN => FIELD_TYPE_BOOLEAN_ARRAY,
185            FIELD_TYPE_BYTE => FIELD_TYPE_BYTE_ARRAY,
186            FIELD_TYPE_STRING => FIELD_TYPE_STRING_ARRAY,
187            FIELD_TYPE_WSTRING => FIELD_TYPE_WSTRING_ARRAY,
188            _ => base_type_id, // Fallback
189        };
190        Self {
191            type_id: array_type_id,
192            capacity,
193            string_capacity: 0,
194            nested_type_name: String::new(),
195        }
196    }
197
198    /// Create a fixed-size array of nested types
199    pub fn nested_array(type_name: impl Into<String>, capacity: u64) -> Self {
200        Self {
201            type_id: FIELD_TYPE_NESTED_TYPE_ARRAY,
202            capacity,
203            string_capacity: 0,
204            nested_type_name: type_name.into(),
205        }
206    }
207
208    /// Create an unbounded sequence (Vec) of primitives
209    pub fn sequence(base_type_id: u8) -> Self {
210        let sequence_type_id = match base_type_id {
211            FIELD_TYPE_INT8 => FIELD_TYPE_INT8_UNBOUNDED_SEQUENCE,
212            FIELD_TYPE_UINT8 => FIELD_TYPE_UINT8_UNBOUNDED_SEQUENCE,
213            FIELD_TYPE_INT16 => FIELD_TYPE_INT16_UNBOUNDED_SEQUENCE,
214            FIELD_TYPE_UINT16 => FIELD_TYPE_UINT16_UNBOUNDED_SEQUENCE,
215            FIELD_TYPE_INT32 => FIELD_TYPE_INT32_UNBOUNDED_SEQUENCE,
216            FIELD_TYPE_UINT32 => FIELD_TYPE_UINT32_UNBOUNDED_SEQUENCE,
217            FIELD_TYPE_INT64 => FIELD_TYPE_INT64_UNBOUNDED_SEQUENCE,
218            FIELD_TYPE_UINT64 => FIELD_TYPE_UINT64_UNBOUNDED_SEQUENCE,
219            FIELD_TYPE_FLOAT => FIELD_TYPE_FLOAT_UNBOUNDED_SEQUENCE,
220            FIELD_TYPE_DOUBLE => FIELD_TYPE_DOUBLE_UNBOUNDED_SEQUENCE,
221            FIELD_TYPE_LONG_DOUBLE => FIELD_TYPE_LONG_DOUBLE_UNBOUNDED_SEQUENCE,
222            FIELD_TYPE_CHAR => FIELD_TYPE_CHAR_UNBOUNDED_SEQUENCE,
223            FIELD_TYPE_WCHAR => FIELD_TYPE_WCHAR_UNBOUNDED_SEQUENCE,
224            FIELD_TYPE_BOOLEAN => FIELD_TYPE_BOOLEAN_UNBOUNDED_SEQUENCE,
225            FIELD_TYPE_BYTE => FIELD_TYPE_BYTE_UNBOUNDED_SEQUENCE,
226            FIELD_TYPE_STRING => FIELD_TYPE_STRING_UNBOUNDED_SEQUENCE,
227            FIELD_TYPE_WSTRING => FIELD_TYPE_WSTRING_UNBOUNDED_SEQUENCE,
228            _ => base_type_id, // Fallback
229        };
230        Self {
231            type_id: sequence_type_id,
232            capacity: 0,
233            string_capacity: 0,
234            nested_type_name: String::new(),
235        }
236    }
237
238    /// Create a string field type with capacity
239    pub fn string_with_capacity(type_id: u8, string_capacity: u64) -> Self {
240        Self {
241            type_id,
242            capacity: 0,
243            string_capacity,
244            nested_type_name: String::new(),
245        }
246    }
247
248    /// Create a bounded string (string with maximum size)
249    pub fn bounded_string(string_capacity: u64) -> Self {
250        Self {
251            type_id: FIELD_TYPE_BOUNDED_STRING,
252            capacity: 0,
253            string_capacity,
254            nested_type_name: String::new(),
255        }
256    }
257
258    /// Create a bounded wstring (wide string with maximum size)
259    pub fn bounded_wstring(string_capacity: u64) -> Self {
260        Self {
261            type_id: FIELD_TYPE_BOUNDED_WSTRING,
262            capacity: 0,
263            string_capacity,
264            nested_type_name: String::new(),
265        }
266    }
267
268    /// Create a bounded sequence of primitives
269    pub fn bounded_sequence(base_type_id: u8, capacity: u64) -> Self {
270        let sequence_type_id = match base_type_id {
271            FIELD_TYPE_INT8 => FIELD_TYPE_INT8_BOUNDED_SEQUENCE,
272            FIELD_TYPE_UINT8 => FIELD_TYPE_UINT8_BOUNDED_SEQUENCE,
273            FIELD_TYPE_INT16 => FIELD_TYPE_INT16_BOUNDED_SEQUENCE,
274            FIELD_TYPE_UINT16 => FIELD_TYPE_UINT16_BOUNDED_SEQUENCE,
275            FIELD_TYPE_INT32 => FIELD_TYPE_INT32_BOUNDED_SEQUENCE,
276            FIELD_TYPE_UINT32 => FIELD_TYPE_UINT32_BOUNDED_SEQUENCE,
277            FIELD_TYPE_INT64 => FIELD_TYPE_INT64_BOUNDED_SEQUENCE,
278            FIELD_TYPE_UINT64 => FIELD_TYPE_UINT64_BOUNDED_SEQUENCE,
279            FIELD_TYPE_FLOAT => FIELD_TYPE_FLOAT_BOUNDED_SEQUENCE,
280            FIELD_TYPE_DOUBLE => FIELD_TYPE_DOUBLE_BOUNDED_SEQUENCE,
281            FIELD_TYPE_LONG_DOUBLE => FIELD_TYPE_LONG_DOUBLE_BOUNDED_SEQUENCE,
282            FIELD_TYPE_CHAR => FIELD_TYPE_CHAR_BOUNDED_SEQUENCE,
283            FIELD_TYPE_WCHAR => FIELD_TYPE_WCHAR_BOUNDED_SEQUENCE,
284            FIELD_TYPE_BOOLEAN => FIELD_TYPE_BOOLEAN_BOUNDED_SEQUENCE,
285            FIELD_TYPE_BYTE => FIELD_TYPE_BYTE_BOUNDED_SEQUENCE,
286            FIELD_TYPE_STRING => FIELD_TYPE_STRING_BOUNDED_SEQUENCE,
287            FIELD_TYPE_WSTRING => FIELD_TYPE_WSTRING_BOUNDED_SEQUENCE,
288            _ => base_type_id, // Fallback
289        };
290        Self {
291            type_id: sequence_type_id,
292            capacity,
293            string_capacity: 0,
294            nested_type_name: String::new(),
295        }
296    }
297
298    /// Create a bounded sequence with string_capacity for bounded string elements
299    /// Used for sequence<string<M>, N> where M is string_capacity and N is capacity
300    pub fn bounded_sequence_with_string_capacity(
301        base_type_id: u8,
302        capacity: u64,
303        string_capacity: u64,
304    ) -> Self {
305        let mut ft = Self::bounded_sequence(base_type_id, capacity);
306        ft.string_capacity = string_capacity;
307        ft
308    }
309
310    /// Create an unbounded sequence with string_capacity for bounded string elements
311    /// Used for sequence<string<M>> where M is string_capacity
312    pub fn sequence_with_string_capacity(base_type_id: u8, string_capacity: u64) -> Self {
313        let mut ft = Self::sequence(base_type_id);
314        ft.string_capacity = string_capacity;
315        ft
316    }
317
318    /// Create a bounded sequence of nested types
319    pub fn nested_bounded_sequence(type_name: impl Into<String>, capacity: u64) -> Self {
320        Self {
321            type_id: FIELD_TYPE_NESTED_TYPE_BOUNDED_SEQUENCE,
322            capacity,
323            string_capacity: 0,
324            nested_type_name: type_name.into(),
325        }
326    }
327}
328
329impl Field {
330    /// Create a new field
331    pub fn new(name: impl Into<String>, field_type: FieldType) -> Self {
332        Self {
333            name: name.into(),
334            field_type,
335            default_value: String::new(),
336        }
337    }
338
339    /// Create a new field with a default value
340    pub fn with_default(
341        name: impl Into<String>,
342        field_type: FieldType,
343        default_value: impl Into<String>,
344    ) -> Self {
345        Self {
346            name: name.into(),
347            field_type,
348            default_value: default_value.into(),
349        }
350    }
351}
352
353impl IndividualTypeDescription {
354    /// Create a new type description
355    pub fn new(type_name: impl Into<String>, fields: Vec<Field>) -> Self {
356        Self {
357            type_name: type_name.into(),
358            fields,
359        }
360    }
361}
362
363impl TypeDescriptionMsg {
364    /// Create a new type description message
365    pub fn new(
366        type_description: IndividualTypeDescription,
367        referenced_type_descriptions: Vec<IndividualTypeDescription>,
368    ) -> Self {
369        Self {
370            type_description,
371            referenced_type_descriptions,
372        }
373    }
374}