use crate::parse::ParsedMessageFile;
use crate::{bail, Error, Package};
use std::path::{Path, PathBuf};
use super::parse_ros_message_file;
#[derive(Clone, Debug)]
pub struct ParsedActionFile {
pub name: String,
pub package: String,
pub action_type: ParsedMessageFile,
pub goal_type: ParsedMessageFile,
pub result_type: ParsedMessageFile,
pub feedback_type: ParsedMessageFile,
pub action_goal_type: ParsedMessageFile,
pub action_result_type: ParsedMessageFile,
pub action_feedback_type: ParsedMessageFile,
pub source: String,
pub path: PathBuf,
}
pub fn parse_ros_action_file(
data: &str,
name: &str,
package: &Package,
path: &Path,
) -> Result<ParsedActionFile, Error> {
let mut dash_line_number_1 = None;
let mut dash_line_number_2 = None;
for (line_num, line) in data.lines().enumerate() {
match (line.find("---"), line.find('#')) {
(Some(dash_idx), Some(comment_idx)) => {
if dash_idx < comment_idx {
if dash_line_number_1.is_none() {
dash_line_number_1 = Some(line_num);
} else {
dash_line_number_2 = Some(line_num);
break;
}
}
}
(Some(_), None) => {
if dash_line_number_1.is_none() {
dash_line_number_1 = Some(line_num);
} else {
dash_line_number_2 = Some(line_num);
break;
}
}
_ => continue,
}
}
let str_accumulator = |mut acc: String, line: &str| -> String {
acc.push_str(line);
acc.push('\n');
acc
};
if let (Some(first_dash_line), Some(second_dash_line)) =
(dash_line_number_1, dash_line_number_2)
{
let goal_str = data
.lines()
.take(first_dash_line)
.fold(String::new(), str_accumulator);
let result_str = data
.lines()
.skip(first_dash_line + 1)
.take(second_dash_line - first_dash_line - 1)
.fold(String::new(), str_accumulator);
let feedback_str = data
.lines()
.skip(second_dash_line + 1)
.fold(String::new(), str_accumulator);
Ok(ParsedActionFile {
name: name.to_owned(),
package: package.name.clone(),
action_type: generate_action_msg(name, package, path)?,
goal_type: parse_ros_message_file(
&goal_str,
format!("{name}Goal").as_str(),
package,
path,
)?,
result_type: parse_ros_message_file(
&result_str,
format!("{name}Result").as_str(),
package,
path,
)?,
feedback_type: parse_ros_message_file(
&feedback_str,
format!("{name}Feedback").as_str(),
package,
path,
)?,
action_goal_type: generate_action_goal_msg(name, package, path)?,
action_result_type: generate_action_result_msg(name, package, path)?,
action_feedback_type: generate_action_feedback_msg(name, package, path)?,
source: data.to_owned(),
path: path.to_owned(),
})
} else {
bail!(
"Failed to find both expected delimiter lines '---' in {}/{name}",
&package.name
)
}
}
fn generate_action_msg(
name: &str,
package: &Package,
path: &Path,
) -> Result<ParsedMessageFile, Error> {
let source = format!(
r#"
{name}ActionGoal action_goal
{name}ActionResult action_result
{name}ActionFeedback action_feedback
"#
);
parse_ros_message_file(&source, format!("{name}Action").as_str(), package, path)
}
fn generate_action_goal_msg(
name: &str,
package: &Package,
path: &Path,
) -> Result<ParsedMessageFile, Error> {
let source = format!(
r#"
Header header
actionlib_msgs/GoalID goal_id
{name}Goal goal
"#
);
parse_ros_message_file(&source, format!("{name}ActionGoal").as_str(), package, path)
}
fn generate_action_result_msg(
name: &str,
package: &Package,
path: &Path,
) -> Result<ParsedMessageFile, Error> {
let source = format!(
r#"
Header header
actionlib_msgs/GoalStatus status
{name}Result result
"#
);
parse_ros_message_file(
&source,
format!("{name}ActionResult").as_str(),
package,
path,
)
}
fn generate_action_feedback_msg(
name: &str,
package: &Package,
path: &Path,
) -> Result<ParsedMessageFile, Error> {
let source = format!(
r#"
Header header
actionlib_msgs/GoalStatus status
{name}Feedback feedback
"#
);
parse_ros_message_file(
&source,
format!("{name}ActionFeedback").as_str(),
package,
path,
)
}