use std::borrow::Cow;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};
const ROS1_GEOMETRY_MSGS: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/ros1_common_interfaces/common_msgs/geometry_msgs"
);
const ROS1_STD_MSGS: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/ros1_common_interfaces/std_msgs"
);
const ROS2_GEOMETRY_MSGS: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/ros2_common_interfaces/geometry_msgs"
);
const ROS2_STD_MSGS: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/ros2_common_interfaces/std_msgs"
);
const ROS2_BUILTIN_INTERFACES: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/ros2_required_msgs/rcl_interfaces/builtin_interfaces"
);
fn format_rust_source(source: &str) -> Cow<'_, str> {
if let Ok(mut process) = Command::new("rustfmt")
.arg("--emit=stdout")
.arg("--edition=2021")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()
{
{
let stdin = process.stdin.as_mut().unwrap();
stdin.write_all(source.as_bytes()).unwrap()
}
if let Ok(output) = process.wait_with_output() {
if output.status.success() {
return std::str::from_utf8(&output.stdout[..])
.unwrap()
.to_owned()
.into();
}
}
}
Cow::Borrowed(source)
}
fn generate_messages() -> String {
let ros1_paths: Vec<PathBuf> = vec![ROS1_GEOMETRY_MSGS.into(), ROS1_STD_MSGS.into()];
let ros2_paths: Vec<PathBuf> = vec![
ROS2_GEOMETRY_MSGS.into(),
ROS2_STD_MSGS.into(),
ROS2_BUILTIN_INTERFACES.into(),
];
let (ros1_source, _) =
roslibrust::codegen::find_and_generate_ros_messages_without_ros_package_path(ros1_paths)
.expect("Failed to generate ROS1 messages");
let ros1_source = format_rust_source(&ros1_source.to_string()).to_string();
let (ros2_source, _) =
roslibrust::codegen::find_and_generate_ros_messages_without_ros_package_path(ros2_paths)
.expect("Failed to generate ROS2 messages");
let ros2_source = format_rust_source(&ros2_source.to_string()).to_string();
format!(
r#"//! Message type definitions for tf2_msgs.
//!
//! This module contains pre-generated message types for tf2_msgs/TFMessage.
//! The code is generated by running: `cargo test -p roslibrust_transforms message_gen`
//!
//! Both ROS1 and ROS2 message formats are provided:
//! - `ros1` - ROS1 message format (Header has `seq` field, uses `secs`/`nsecs`)
//! - `ros2` - ROS2 message format (Header has no `seq` field, uses `sec`/`nanosec`)
/// ROS1 message types for tf2 functionality.
/// Header uses `seq` field and `stamp` has `secs`/`nsecs` fields.
pub mod ros1 {{
{ros1_source}
/// TFMessage is the message type published on /tf and /tf_static topics.
/// It contains an array of geometry_msgs/TransformStamped messages.
#[allow(non_snake_case)]
#[derive(
::serde::Deserialize,
::serde::Serialize,
::roslibrust::codegen::SmartDefault,
Debug,
Clone,
PartialEq,
)]
pub struct TFMessage {{
pub transforms: Vec<geometry_msgs::TransformStamped>,
}}
impl ::roslibrust_common::RosMessageType for TFMessage {{
const DESCRIPTION: ::roslibrust_common::MessageDescriptor =
::roslibrust_common::MessageDescriptor::new::<Self>(
"tf2_msgs/TFMessage",
"94810edda583a504dfda3829e70d7eec",
"geometry_msgs/TransformStamped[] transforms",
"tf2_msgs::msg::dds_::TFMessage_",
&[
0x84, 0x64, 0x1e, 0xf6, 0x1a, 0x5a, 0xa7, 0xf4, 0x9e, 0x8f, 0xc3, 0xca,
0x2f, 0x3c, 0xf7, 0x3e, 0x24, 0x3a, 0x50, 0x7c, 0xc6, 0x5a, 0x6b, 0x93,
0xe4, 0x1a, 0xa3, 0x57, 0x83, 0xd1, 0x94, 0x71,
],
);
}}
}}
/// ROS2 message types for tf2 functionality.
/// Header has no `seq` field and `stamp` has `sec`/`nanosec` fields.
pub mod ros2 {{
{ros2_source}
/// TFMessage is the message type published on /tf and /tf_static topics.
/// It contains an array of geometry_msgs/TransformStamped messages.
#[allow(non_snake_case)]
#[derive(
::serde::Deserialize,
::serde::Serialize,
::roslibrust::codegen::SmartDefault,
Debug,
Clone,
PartialEq,
)]
pub struct TFMessage {{
pub transforms: Vec<geometry_msgs::TransformStamped>,
}}
impl ::roslibrust_common::RosMessageType for TFMessage {{
const DESCRIPTION: ::roslibrust_common::MessageDescriptor =
::roslibrust_common::MessageDescriptor::new::<Self>(
"tf2_msgs/TFMessage",
"94810edda583a504dfda3829e70d7eec",
"geometry_msgs/TransformStamped[] transforms",
"tf2_msgs::msg::dds_::TFMessage_",
&[
0x84, 0x64, 0x1e, 0xf6, 0x1a, 0x5a, 0xa7, 0xf4, 0x9e, 0x8f, 0xc3, 0xca,
0x2f, 0x3c, 0xf7, 0x3e, 0x24, 0x3a, 0x50, 0x7c, 0xc6, 0x5a, 0x6b, 0x93,
0xe4, 0x1a, 0xa3, 0x57, 0x83, 0xd1, 0x94, 0x71,
],
);
}}
}}
"#
)
}
#[test]
fn messages_rs_is_up_to_date() {
let generated = generate_messages();
let generated = format_rust_source(&generated).to_string();
let messages_path = concat!(env!("CARGO_MANIFEST_DIR"), "/src/messages.rs");
let current_contents =
std::fs::read_to_string(messages_path).expect("Failed to read current messages.rs");
if generated.trim() != current_contents.trim() {
std::fs::write(messages_path, &generated).expect("Failed to write messages.rs");
let diff = diffy::create_patch(¤t_contents, &generated);
println!("messages.rs was out of date and has been updated.");
println!("Diff:\n{}", diff);
panic!(
"messages.rs was out of date and has been regenerated. \
Please commit the updated file and re-run the tests."
);
}
}