1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct TypeDescriptionMsg {
10 pub type_description: IndividualTypeDescription,
12 pub referenced_type_descriptions: Vec<IndividualTypeDescription>,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct IndividualTypeDescription {
19 pub type_name: String,
21 pub fields: Vec<Field>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct Field {
28 pub name: String,
30 #[serde(rename = "type")]
32 pub field_type: FieldType,
33 pub default_value: String,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct FieldType {
40 pub type_id: u8,
42 pub capacity: u64,
44 pub string_capacity: u64,
46 pub nested_type_name: String,
48}
49
50pub 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
75pub 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
95pub 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
115pub 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 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 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 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 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, };
190 Self {
191 type_id: array_type_id,
192 capacity,
193 string_capacity: 0,
194 nested_type_name: String::new(),
195 }
196 }
197
198 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 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, };
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 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 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 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 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, };
290 Self {
291 type_id: sequence_type_id,
292 capacity,
293 string_capacity: 0,
294 nested_type_name: String::new(),
295 }
296 }
297
298 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 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 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 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 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 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 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}
375
376use std::collections::BTreeSet;
381use std::fmt::Write;
382
383fn decompose_type_id(type_id: u8) -> (u8, char) {
387 match type_id {
388 0..=48 => (type_id, 'p'),
389 49..=96 => (type_id - 48, 'a'),
390 97..=144 => (type_id - 96, 'b'),
391 145..=192 => (type_id - 144, 'u'),
392 _ => (type_id, 'p'),
393 }
394}
395
396fn base_type_to_idl(base_type_id: u8) -> &'static str {
398 match base_type_id {
399 FIELD_TYPE_NESTED_TYPE => "", FIELD_TYPE_INT8 => "int8",
401 FIELD_TYPE_UINT8 => "uint8",
402 FIELD_TYPE_INT16 => "int16",
403 FIELD_TYPE_UINT16 => "uint16",
404 FIELD_TYPE_INT32 => "int32",
405 FIELD_TYPE_UINT32 => "uint32",
406 FIELD_TYPE_INT64 => "int64",
407 FIELD_TYPE_UINT64 => "uint64",
408 FIELD_TYPE_FLOAT => "float",
409 FIELD_TYPE_DOUBLE => "double",
410 FIELD_TYPE_LONG_DOUBLE => "long double",
411 FIELD_TYPE_CHAR => "uint8", FIELD_TYPE_WCHAR => "wchar",
413 FIELD_TYPE_BOOLEAN => "boolean",
414 FIELD_TYPE_BYTE => "octet",
415 FIELD_TYPE_STRING => "string",
416 FIELD_TYPE_WSTRING => "wstring",
417 FIELD_TYPE_FIXED_STRING => "string",
418 FIELD_TYPE_FIXED_WSTRING => "wstring",
419 FIELD_TYPE_BOUNDED_STRING => "string",
420 FIELD_TYPE_BOUNDED_WSTRING => "wstring",
421 _ => "unknown",
422 }
423}
424
425fn base_type_to_msg(base_type_id: u8) -> &'static str {
427 match base_type_id {
428 FIELD_TYPE_NESTED_TYPE => "", FIELD_TYPE_INT8 => "int8",
430 FIELD_TYPE_UINT8 => "uint8",
431 FIELD_TYPE_INT16 => "int16",
432 FIELD_TYPE_UINT16 => "uint16",
433 FIELD_TYPE_INT32 => "int32",
434 FIELD_TYPE_UINT32 => "uint32",
435 FIELD_TYPE_INT64 => "int64",
436 FIELD_TYPE_UINT64 => "uint64",
437 FIELD_TYPE_FLOAT => "float32",
438 FIELD_TYPE_DOUBLE => "float64",
439 FIELD_TYPE_LONG_DOUBLE => "float64",
440 FIELD_TYPE_CHAR => "char",
441 FIELD_TYPE_WCHAR => "char",
442 FIELD_TYPE_BOOLEAN => "bool",
443 FIELD_TYPE_BYTE => "byte",
444 FIELD_TYPE_STRING => "string",
445 FIELD_TYPE_WSTRING => "wstring",
446 FIELD_TYPE_FIXED_STRING => "string",
447 FIELD_TYPE_FIXED_WSTRING => "wstring",
448 FIELD_TYPE_BOUNDED_STRING => "string",
449 FIELD_TYPE_BOUNDED_WSTRING => "wstring",
450 _ => "unknown",
451 }
452}
453
454fn split_type_name(fqn: &str) -> (&str, &str, &str) {
456 let parts: Vec<&str> = fqn.splitn(3, '/').collect();
457 match parts.len() {
458 3 => (parts[0], parts[1], parts[2]),
459 2 => (parts[0], "msg", parts[1]),
460 _ => ("", "msg", fqn),
461 }
462}
463
464fn type_name_to_idl_qualified(fqn: &str) -> String {
466 fqn.replace('/', "::")
467}
468
469impl TypeDescriptionMsg {
470 pub fn to_idl(&self) -> String {
475 let mut output = String::new();
476 let mut typedefs_needed = BTreeSet::new();
477
478 for ref_type in &self.referenced_type_descriptions {
480 Self::emit_idl_struct(&mut output, ref_type, &mut typedefs_needed);
481 output.push('\n');
482 }
483
484 Self::emit_idl_struct(&mut output, &self.type_description, &mut typedefs_needed);
486 output
487 }
488
489 fn emit_idl_struct(
490 output: &mut String,
491 desc: &IndividualTypeDescription,
492 typedefs_needed: &mut BTreeSet<String>,
493 ) {
494 let (pkg, msg_type, name) = split_type_name(&desc.type_name);
495
496 let mut local_typedefs = Vec::new();
498 for field in &desc.fields {
499 let (base_id, kind) = decompose_type_id(field.field_type.type_id);
500 if kind == 'a' {
501 let idl_base = if base_id == FIELD_TYPE_NESTED_TYPE {
502 type_name_to_idl_qualified(&field.field_type.nested_type_name)
503 } else {
504 base_type_to_idl(base_id).to_string()
505 };
506 let cap = field.field_type.capacity;
507 let typedef_name = format!(
508 "{}__{}",
509 idl_base.replace("::", "__").replace(' ', "_"),
510 cap
511 );
512 if typedefs_needed.insert(typedef_name.clone()) {
513 local_typedefs.push((idl_base, typedef_name, cap));
514 }
515 }
516 }
517
518 if !pkg.is_empty() {
520 let _ = writeln!(output, "module {pkg} {{");
521 let _ = writeln!(output, " module {msg_type} {{");
522 }
523
524 let indent = if pkg.is_empty() { "" } else { " " };
525
526 for (base, alias, cap) in &local_typedefs {
528 let _ = writeln!(output, "{indent}typedef {base} {alias}[{cap}];");
529 }
530 if !local_typedefs.is_empty() {
531 output.push('\n');
532 }
533
534 let _ = writeln!(output, "{indent}struct {name} {{");
536 for field in &desc.fields {
537 let idl_type = Self::field_type_to_idl(&field.field_type, typedefs_needed);
538 let _ = writeln!(output, "{indent} {idl_type} {name_};", name_ = field.name);
539 }
540 let _ = writeln!(output, "{indent}}};");
541
542 if !pkg.is_empty() {
544 let _ = writeln!(output, " }};");
545 let _ = writeln!(output, "}};");
546 }
547 }
548
549 fn field_type_to_idl(ft: &FieldType, typedefs_needed: &mut BTreeSet<String>) -> String {
550 let (base_id, kind) = decompose_type_id(ft.type_id);
551
552 let base_name = if base_id == FIELD_TYPE_NESTED_TYPE {
553 type_name_to_idl_qualified(&ft.nested_type_name)
554 } else {
555 let prim = base_type_to_idl(base_id);
556 if ft.string_capacity > 0
558 && matches!(
559 base_id,
560 FIELD_TYPE_STRING
561 | FIELD_TYPE_WSTRING
562 | FIELD_TYPE_BOUNDED_STRING
563 | FIELD_TYPE_BOUNDED_WSTRING
564 | FIELD_TYPE_FIXED_STRING
565 | FIELD_TYPE_FIXED_WSTRING
566 )
567 {
568 format!("{prim}<{}>", ft.string_capacity)
569 } else {
570 prim.to_string()
571 }
572 };
573
574 match kind {
575 'a' => {
576 let typedef_name = format!(
578 "{}__{}",
579 base_name.replace("::", "__").replace(' ', "_"),
580 ft.capacity
581 );
582 typedefs_needed.insert(typedef_name.clone());
583 typedef_name
584 }
585 'b' => {
586 format!("sequence<{base_name}, {}>", ft.capacity)
588 }
589 'u' => {
590 format!("sequence<{base_name}>")
592 }
593 _ => base_name,
594 }
595 }
596
597 pub fn to_msg_definition(&self) -> String {
602 let mut output = String::new();
603
604 Self::emit_msg_struct(&mut output, &self.type_description);
606
607 for ref_type in &self.referenced_type_descriptions {
609 let _ = writeln!(
610 output,
611 "\n================================================================================"
612 );
613 let _ = writeln!(output, "MSG: {}", ref_type.type_name);
614 Self::emit_msg_struct(&mut output, ref_type);
615 }
616
617 output
618 }
619
620 fn emit_msg_struct(output: &mut String, desc: &IndividualTypeDescription) {
621 for field in &desc.fields {
622 let msg_type = Self::field_type_to_msg(&field.field_type);
623 let _ = writeln!(output, "{msg_type} {}", field.name);
624 }
625 }
626
627 fn field_type_to_msg(ft: &FieldType) -> String {
628 let (base_id, kind) = decompose_type_id(ft.type_id);
629
630 let base_name = if base_id == FIELD_TYPE_NESTED_TYPE {
631 let (pkg, _msg_type, name) = split_type_name(&ft.nested_type_name);
634 if pkg.is_empty() {
635 name.to_string()
636 } else {
637 format!("{pkg}/{name}")
638 }
639 } else {
640 let prim = base_type_to_msg(base_id);
641 if ft.string_capacity > 0
643 && matches!(
644 base_id,
645 FIELD_TYPE_BOUNDED_STRING | FIELD_TYPE_BOUNDED_WSTRING
646 )
647 {
648 format!("{prim}<={}>", ft.string_capacity)
649 } else {
650 prim.to_string()
651 }
652 };
653
654 match kind {
655 'a' => {
656 format!("{base_name}[{}]", ft.capacity)
658 }
659 'b' => {
660 format!("{base_name}[<={}]", ft.capacity)
662 }
663 'u' => {
664 format!("{base_name}[]")
666 }
667 _ => base_name,
668 }
669 }
670}