use crate::parse::{
parse_constant_field, parse_field, split_type_from_line,
strip_comments_respecting_string_constants,
};
use crate::Error;
use crate::{ConstantInfo, FieldInfo, Package, RosVersion};
use std::path::{Path, PathBuf};
#[derive(Clone, PartialEq, Debug)]
pub struct ParsedMessageFile {
pub name: String,
pub package: String,
pub fields: Vec<FieldInfo>,
pub constants: Vec<ConstantInfo>,
pub version: Option<RosVersion>,
pub source: String,
pub path: PathBuf,
}
impl ParsedMessageFile {
pub fn has_header(&self) -> bool {
self.fields.iter().any(|field| {
field.field_type.field_type.as_str() == "Header"
&& (field.field_type.package_name.is_none()
|| field.field_type.package_name == Some(String::from("std_msgs")))
})
}
pub fn get_full_name(&self) -> String {
format!("{}/{}", self.package, self.name)
}
pub fn get_ros2_full_name(&self) -> String {
let parent = self
.path
.parent()
.expect("All ROS messages should have a parent directory")
.file_name()
.expect("All parent directories should have a resolveable file name")
.to_str()
.expect("All parent directory names should be valid unicode");
format!("{}/{}/{}", self.package, parent, self.name)
}
pub fn get_ros2_dds_type_name(&self) -> String {
format!("{}::msg::dds_::{}_", self.package, self.name)
}
}
pub fn parse_ros_message_file(
data: &str,
name: &str,
package: &Package,
path: &Path,
) -> Result<ParsedMessageFile, Error> {
let mut fields = vec![];
let mut constants = vec![];
for line in data.lines() {
let line = strip_comments_respecting_string_constants(line).trim();
if line.is_empty() {
continue;
}
let (_, remainder) = split_type_from_line(line).ok_or(Error::new(format!(
"Found an invalid ros field line, no space delimiting type from name: {line} in {}\n{data}",
path.display()
)))?;
if remainder.contains('=') {
constants.push(parse_constant_field(line, package)?)
} else {
fields.push(parse_field(line, package, name)?);
}
}
Ok(ParsedMessageFile {
fields,
constants,
name: name.to_owned(),
package: package.name.clone(),
version: package.version,
source: data.to_owned(),
path: path.to_owned(),
})
}