roslibrust_codegen/parse/
action.rs1use crate::parse::ParsedMessageFile;
2use crate::{bail, Error, Package};
3use std::path::{Path, PathBuf};
4
5use super::parse_ros_message_file;
6
7#[derive(Clone, Debug)]
8pub struct ParsedActionFile {
9 pub name: String,
10 pub package: String,
11 pub action_type: ParsedMessageFile,
12 pub goal_type: ParsedMessageFile,
13 pub result_type: ParsedMessageFile,
14 pub feedback_type: ParsedMessageFile,
15 pub action_goal_type: ParsedMessageFile,
16 pub action_result_type: ParsedMessageFile,
17 pub action_feedback_type: ParsedMessageFile,
18 pub source: String,
20 pub path: PathBuf,
22}
23
24pub fn parse_ros_action_file(
25 data: &str,
26 name: &str,
27 package: &Package,
28 path: &Path,
29) -> Result<ParsedActionFile, Error> {
30 let mut dash_line_number_1 = None;
31 let mut dash_line_number_2 = None;
32
33 for (line_num, line) in data.lines().enumerate() {
34 match (line.find("---"), line.find('#')) {
35 (Some(dash_idx), Some(comment_idx)) => {
36 if dash_idx < comment_idx {
37 if dash_line_number_1.is_none() {
38 dash_line_number_1 = Some(line_num);
39 } else {
40 dash_line_number_2 = Some(line_num);
41 break;
42 }
43 }
44 }
45 (Some(_), None) => {
46 if dash_line_number_1.is_none() {
47 dash_line_number_1 = Some(line_num);
48 } else {
49 dash_line_number_2 = Some(line_num);
50 break;
51 }
52 }
53 _ => continue,
54 }
55 }
56 let str_accumulator = |mut acc: String, line: &str| -> String {
57 acc.push_str(line);
58 acc.push('\n');
59 acc
60 };
61
62 if let (Some(first_dash_line), Some(second_dash_line)) =
63 (dash_line_number_1, dash_line_number_2)
64 {
65 let goal_str = data
66 .lines()
67 .take(first_dash_line)
68 .fold(String::new(), str_accumulator);
69 let result_str = data
70 .lines()
71 .skip(first_dash_line + 1)
72 .take(second_dash_line - first_dash_line - 1)
73 .fold(String::new(), str_accumulator);
74 let feedback_str = data
75 .lines()
76 .skip(second_dash_line + 1)
77 .fold(String::new(), str_accumulator);
78
79 Ok(ParsedActionFile {
80 name: name.to_owned(),
81 package: package.name.clone(),
82 action_type: generate_action_msg(name, package, path)?,
83 goal_type: parse_ros_message_file(
84 &goal_str,
85 format!("{name}Goal").as_str(),
86 package,
87 path,
88 )?,
89 result_type: parse_ros_message_file(
90 &result_str,
91 format!("{name}Result").as_str(),
92 package,
93 path,
94 )?,
95 feedback_type: parse_ros_message_file(
96 &feedback_str,
97 format!("{name}Feedback").as_str(),
98 package,
99 path,
100 )?,
101 action_goal_type: generate_action_goal_msg(name, package, path)?,
102 action_result_type: generate_action_result_msg(name, package, path)?,
103 action_feedback_type: generate_action_feedback_msg(name, package, path)?,
104 source: data.to_owned(),
105 path: path.to_owned(),
106 })
107 } else {
108 bail!(
109 "Failed to find both expected delimiter lines '---' in {}/{name}",
110 &package.name
111 )
112 }
113}
114
115fn generate_action_msg(
116 name: &str,
117 package: &Package,
118 path: &Path,
119) -> Result<ParsedMessageFile, Error> {
120 let source = format!(
121 r#"
122{name}ActionGoal action_goal
123{name}ActionResult action_result
124{name}ActionFeedback action_feedback
125 "#
126 );
127
128 parse_ros_message_file(&source, format!("{name}Action").as_str(), package, path)
129}
130
131fn generate_action_goal_msg(
132 name: &str,
133 package: &Package,
134 path: &Path,
135) -> Result<ParsedMessageFile, Error> {
136 let source = format!(
137 r#"
138Header header
139actionlib_msgs/GoalID goal_id
140{name}Goal goal
141 "#
142 );
143
144 parse_ros_message_file(&source, format!("{name}ActionGoal").as_str(), package, path)
145}
146
147fn generate_action_result_msg(
148 name: &str,
149 package: &Package,
150 path: &Path,
151) -> Result<ParsedMessageFile, Error> {
152 let source = format!(
153 r#"
154Header header
155actionlib_msgs/GoalStatus status
156{name}Result result
157 "#
158 );
159
160 parse_ros_message_file(
161 &source,
162 format!("{name}ActionResult").as_str(),
163 package,
164 path,
165 )
166}
167
168fn generate_action_feedback_msg(
169 name: &str,
170 package: &Package,
171 path: &Path,
172) -> Result<ParsedMessageFile, Error> {
173 let source = format!(
174 r#"
175Header header
176actionlib_msgs/GoalStatus status
177{name}Feedback feedback
178 "#
179 );
180
181 parse_ros_message_file(
182 &source,
183 format!("{name}ActionFeedback").as_str(),
184 package,
185 path,
186 )
187}