mcap2arrow_ros2msg/
parser.rs1use mcap2arrow_ros2_common::{ConstDef, FieldDef, PrimitiveType, Ros2Error, StructDef, TypeExpr};
8use re_ros_msg::{
9 MessageSchema,
10 message_spec::{
11 ArraySize, BuiltInType, ComplexType, Constant, Field, MessageSpecification, Type,
12 },
13};
14pub fn parse_msg(schema_name: &str, msg_text: &str) -> Result<StructDef, Ros2Error> {
16 let schema = MessageSchema::parse(schema_name, msg_text)
18 .map_err(|e| Ros2Error(format!("failed to parse msg schema '{schema_name}': {e}")))?;
19
20 let full_name = parse_schema_name(schema_name)?;
22
23 convert_to_struct_def(full_name, schema.spec)
25}
26
27fn parse_schema_name(name: &str) -> Result<Vec<String>, Ros2Error> {
28 let parts: Vec<&str> = name.split('/').collect();
31
32 match parts.len() {
33 3 => Ok(parts.iter().map(|s| s.to_string()).collect()),
34 2 => Ok(vec![
35 parts[0].to_string(),
36 "msg".to_string(),
37 parts[1].to_string(),
38 ]),
39 _ => Err(format!("invalid schema name format: {name}").into()),
40 }
41}
42
43fn convert_to_struct_def(
44 full_name: Vec<String>,
45 spec: MessageSpecification,
46) -> Result<StructDef, Ros2Error> {
47 let fields = spec
48 .fields
49 .into_iter()
50 .map(convert_field)
51 .collect::<Result<Vec<_>, _>>()?;
52
53 let consts = spec
54 .constants
55 .into_iter()
56 .map(convert_constant)
57 .collect::<Result<Vec<_>, _>>()?;
58
59 Ok(StructDef {
60 full_name,
61 fields,
62 consts,
63 })
64}
65
66fn convert_field(field: Field) -> Result<FieldDef, Ros2Error> {
67 let (ty, fixed_len) = convert_type(&field.ty)?;
68
69 Ok(FieldDef {
70 name: field.name,
71 ty,
72 fixed_len,
73 })
74}
75
76fn convert_type(ty: &Type) -> Result<(TypeExpr, Option<usize>), Ros2Error> {
77 match ty {
78 Type::BuiltIn(builtin) => Ok((convert_builtin_type(builtin), None)),
79 Type::Complex(complex) => {
80 let scoped = convert_complex_type(complex);
81 Ok((TypeExpr::Scoped(scoped), None))
82 }
83 Type::Array { ty: elem_ty, size } => {
84 let (elem, elem_fixed) = convert_type(elem_ty)?;
85
86 if elem_fixed.is_some() {
88 return Err("nested fixed arrays are not supported in ROS2".into());
89 }
90
91 match size {
92 ArraySize::Fixed(n) => {
93 Ok((elem, Some(*n)))
95 }
96 ArraySize::Unbounded => {
97 Ok((
99 TypeExpr::Sequence {
100 elem: Box::new(elem),
101 max_len: None,
102 },
103 None,
104 ))
105 }
106 ArraySize::Bounded(n) => {
107 Ok((
109 TypeExpr::Sequence {
110 elem: Box::new(elem),
111 max_len: Some(*n),
112 },
113 None,
114 ))
115 }
116 }
117 }
118 }
119}
120
121fn convert_builtin_type(ty: &BuiltInType) -> TypeExpr {
122 let prim = match ty {
123 BuiltInType::Bool => PrimitiveType::Bool,
124 BuiltInType::Byte => PrimitiveType::U8,
125 BuiltInType::Char => PrimitiveType::U8,
126 BuiltInType::Int8 => PrimitiveType::I8,
127 BuiltInType::UInt8 => PrimitiveType::U8,
128 BuiltInType::Int16 => PrimitiveType::I16,
129 BuiltInType::UInt16 => PrimitiveType::U16,
130 BuiltInType::Int32 => PrimitiveType::I32,
131 BuiltInType::UInt32 => PrimitiveType::U32,
132 BuiltInType::Int64 => PrimitiveType::I64,
133 BuiltInType::UInt64 => PrimitiveType::U64,
134 BuiltInType::Float32 => PrimitiveType::F32,
135 BuiltInType::Float64 => PrimitiveType::F64,
136 BuiltInType::String(None) => PrimitiveType::String,
137 BuiltInType::String(Some(n)) => {
138 return TypeExpr::BoundedString(*n);
139 }
140 BuiltInType::WString(None) => PrimitiveType::WString,
141 BuiltInType::WString(Some(n)) => {
142 return TypeExpr::BoundedWString(*n);
143 }
144 };
145
146 TypeExpr::Primitive(prim)
147}
148
149fn convert_complex_type(ty: &ComplexType) -> Vec<String> {
150 match ty {
151 ComplexType::Absolute { package, name } => {
152 vec![package.clone(), "msg".to_string(), name.clone()]
154 }
155 ComplexType::Relative { name } => {
156 vec![name.clone()]
158 }
159 }
160}
161
162fn convert_constant(constant: Constant) -> Result<ConstDef, Ros2Error> {
163 let ty = match &constant.ty {
164 Type::BuiltIn(builtin) => convert_builtin_type(builtin),
165 Type::Array { .. } => {
166 return Err("constants cannot be arrays".into());
167 }
168 Type::Complex(_) => {
169 return Err("constants must be primitive types".into());
170 }
171 };
172
173 Ok(ConstDef {
174 ty,
175 name: constant.name,
176 value: format!("{:?}", constant.value),
177 })
178}