Skip to main content

mcap2arrow_ros2msg/
lib.rs

1//! ROS 2 .msg → CDR decoder for `mcap2arrow`.
2//!
3//! Implements [`MessageDecoder`] for the
4//! `(schema_encoding = ros2msg, message_encoding = cdr)` key.
5//!
6//! Unlike the IDL decoder, a .msg schema is a single file, so no
7//! multi-section bundle splitting is needed.  `builtin_interfaces` types
8//! (`Time`, `Duration`) are injected automatically via
9//! [`resolve_single_struct`].
10//!
11//! # Pipeline
12//!
13//! ```text
14//! schema bytes (UTF-8 .msg)
15//!   └─ parse_msg             – re_ros_msg parser → StructDef
16//!       └─ resolve_single_struct  – type resolution → ResolvedSchema
17//!           └─ decode_cdr_to_value – CDR bytes → Value
18//! ```
19
20mod parser;
21
22use mcap2arrow_core::{
23    DecoderError, EncodingKey, MessageDecoder, MessageEncoding, SchemaEncoding, TopicDecoder,
24};
25use mcap2arrow_ros2_common::{ResolvedSchema, Ros2CdrTopicDecoder, resolve_single_struct};
26pub use parser::parse_msg;
27
28/// [`MessageDecoder`] for ROS 2 .msg schemas with CDR-encoded messages.
29pub struct Ros2MsgDecoder;
30
31impl Ros2MsgDecoder {
32    pub fn new() -> Self {
33        Self
34    }
35}
36
37impl Default for Ros2MsgDecoder {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43impl MessageDecoder for Ros2MsgDecoder {
44    fn encoding_key(&self) -> EncodingKey {
45        EncodingKey::new(SchemaEncoding::Ros2Msg, MessageEncoding::Cdr)
46    }
47
48    fn build_topic_decoder(
49        &self,
50        schema_name: &str,
51        schema_data: &[u8],
52    ) -> Result<Box<dyn TopicDecoder>, DecoderError> {
53        let resolved = resolve_for_cdr(schema_name, schema_data)?;
54        Ok(Box::new(Ros2CdrTopicDecoder::new(resolved)))
55    }
56}
57
58/// Parse and resolve a .msg schema into a [`ResolvedSchema`] ready for CDR decoding.
59pub fn resolve_for_cdr(
60    schema_name: &str,
61    schema_data: &[u8],
62) -> Result<ResolvedSchema, DecoderError> {
63    let schema_str = std::str::from_utf8(schema_data).map_err(|e| DecoderError::SchemaParse {
64        schema_name: schema_name.to_string(),
65        source: Box::new(e),
66    })?;
67    let struct_def = parse_msg(schema_name, schema_str).map_err(|e| DecoderError::SchemaParse {
68        schema_name: schema_name.to_string(),
69        source: e.into(),
70    })?;
71    resolve_single_struct(schema_name, struct_def).map_err(|e| DecoderError::SchemaParse {
72        schema_name: schema_name.to_string(),
73        source: e.into(),
74    })
75}