ros_message.cpp
Go to the documentation of this file.
1 /***** MIT License ****
2  *
3  * Copyright (c) 2016-2022 Davide Faconti
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <string_view>
25 #include <sstream>
26 #include <regex>
28 
29 namespace RosMsgParser
30 {
31 
32 ROSMessage::ROSMessage(const std::string& msg_def)
33 {
34  std::istringstream messageDescriptor(msg_def);
35  std::match_results<std::string::const_iterator> what;
36 
37  for (std::string line; std::getline(messageDescriptor, line, '\n');)
38  {
39  std::string::const_iterator begin = line.begin(), end = line.end();
40 
41  // Skip empty line or one that is a comment
42  if (std::regex_search(begin, end, what, std::regex("(^\\s*$|^\\s*#)")))
43  {
44  continue;
45  }
46 
47  TrimStringLeft(line);
48 
49  if (line.compare(0, 5, "MSG: ") == 0)
50  {
51  line.erase(0, 5);
52  _type = ROSType(line);
53  }
54  else
55  {
56  auto new_field = ROSField(line);
57  _fields.push_back(new_field);
58  }
59  }
60 }
61 
62 std::vector<std::string> SplitMultipleMessageDefinitions(const std::string& multi_def)
63 {
64  std::istringstream ss_msg(multi_def);
65 
66  std::vector<std::string> parts;
67  std::string part;
68 
69  for (std::string line; std::getline(ss_msg, line, '\n');)
70  {
71  if (line.find("========") == 0)
72  {
73  parts.emplace_back(std::move(part));
74  part = {};
75  }
76  else
77  {
78  part.append(line);
79  part.append("\n");
80  }
81  }
82  parts.emplace_back(std::move(part));
83 
84  return parts;
85 }
86 
87 std::vector<ROSMessage::Ptr> ParseMessageDefinitions(const std::string& multi_def,
88  const ROSType& root_type)
89 {
90  auto parts = SplitMultipleMessageDefinitions(multi_def);
91  std::vector<ROSType> known_type;
92  std::vector<ROSMessage::Ptr> parsed_msgs;
93 
94  const ROSType no_type;
95 
96  // iterating in reverse to fill known_type in the right order
97  // i.e. with no missing dependencies
98  for (int i = parts.size() - 1; i >= 0; i--)
99  {
100  auto msg = std::make_shared<ROSMessage>(parts[i]);
101 
102  if (i == 0)
103  {
104  // type NOT found in the definition, but provided as argument
105  if (msg->type() == no_type && root_type != no_type)
106  {
107  msg->setType(root_type);
108  }
109  else if (msg->type() == no_type && root_type == no_type)
110  {
111  std::cout << multi_def << std::endl;
112  throw std::runtime_error("Message type unspecified");
113  }
114  }
115 
116  // add to vector
117  parsed_msgs.push_back(msg);
118  known_type.push_back(msg->type());
119  }
120 
121  // adjust types with undefined package type
122  for (auto& msg : parsed_msgs)
123  {
124  for (ROSField& field : msg->fields())
125  {
126  // if package name is missing, try to find msgName in the list of known_type
127  if (field.type().pkgName().empty())
128  {
129  std::vector<ROSType> guessed_type;
130 
131  for (const ROSType& known_type : known_type)
132  {
133  if (field.type().msgName() == known_type.msgName())
134  {
135  guessed_type.push_back(known_type);
136  }
137  }
138 
139  if (!guessed_type.empty())
140  {
141  bool better_match = false;
142 
143  // attempt to match ambiguous ros msg within package before
144  // using external known type
145  for (const ROSType& guessed_type : guessed_type)
146  {
147  if (guessed_type.pkgName() == root_type.pkgName())
148  {
149  field.changeType(guessed_type);
150  better_match = true;
151  break;
152  }
153  }
154 
155  // if nothing from the same package, take a guess with the first matching msg
156  // name
157  if (!better_match)
158  {
159  field.changeType(guessed_type[0]);
160  }
161  }
162  }
163  }
164  }
165 
166  std::reverse(parsed_msgs.begin(), parsed_msgs.end());
167  return parsed_msgs;
168 }
169 
170 MessageSchema::Ptr BuildMessageSchema(const std::string& topic_name,
171  const std::vector<ROSMessage::Ptr>& parsed_msgs)
172 {
173  auto schema = std::make_shared<MessageSchema>();
174  schema->topic_name = topic_name;
175  schema->root_msg = parsed_msgs.front();
176 
177  for (const auto& msg : parsed_msgs)
178  {
179  schema->msg_library.insert({ msg->type(), msg });
180  }
181 
183  std::function<void(ROSMessage::Ptr, FieldTreeNode*)> recursiveTreeCreator;
184 
185  recursiveTreeCreator = [&](ROSMessage::Ptr msg, FieldTreeNode* field_node) {
186  // note: should use reserve here, NOT resize
187  const size_t NUM_FIELDS = msg->fields().size();
188  field_node->children().reserve(NUM_FIELDS);
189 
190  for (const ROSField& field : msg->fields())
191  {
192  if (field.isConstant())
193  {
194  continue;
195  }
196  // Let's add first a child to string_node
197  field_node->addChild(&field);
198  FieldTreeNode* new_string_node = &(field_node->children().back());
199 
200  // builtin types will not trigger a recursion
201  if (field.type().isBuiltin() == false)
202  {
203  auto new_msg = field.getMessagePtr(schema->msg_library);
204  if (!new_msg)
205  {
206  throw std::runtime_error("Missing ROSType in library");
207  }
208 
209  recursiveTreeCreator(new_msg, new_string_node);
210  }
211  } // end of for fields
212  }; // end of recursiveTreeCreator
213 
214  // build root and start recursion
215  auto root_field = new ROSField(schema->root_msg->type(), topic_name);
216  schema->field_tree.root()->setValue(root_field);
217 
218  recursiveTreeCreator(schema->root_msg, schema->field_tree.root());
219 
220  return schema;
221 }
222 
223 } // namespace RosMsgParser
RosMsgParser::ROSType::pkgName
const std::string_view & pkgName() const
ex.: geometry_msgs/Pose -> "geometry_msgs"
Definition: ros_type.hpp:123
RosMsgParser::ROSMessage::Ptr
std::shared_ptr< ROSMessage > Ptr
Definition: ros_message.hpp:37
RosMsgParser::ROSMessage::_fields
std::vector< ROSField > _fields
Definition: ros_message.hpp:70
RosMsgParser::ROSType
ROSType.
Definition: ros_type.hpp:39
RosMsgParser::MessageSchema::Ptr
std::shared_ptr< MessageSchema > Ptr
Definition: ros_message.hpp:78
RosMsgParser::SplitMultipleMessageDefinitions
std::vector< std::string > SplitMultipleMessageDefinitions(const std::string &multi_def)
Definition: ros_message.cpp:62
RosMsgParser::TrimStringLeft
void TrimStringLeft(std::string &s)
mqtt_test_proto.msg
msg
Definition: mqtt_test_proto.py:43
ros_message.hpp
RosMsgParser
Definition: builtin_types.hpp:34
RosMsgParser::ROSMessage::ROSMessage
ROSMessage(const std::string &msg_def)
Definition: ros_message.cpp:32
backward::details::move
const T & move(const T &v)
Definition: backward.hpp:394
RosMsgParser::ROSMessage::_type
ROSType _type
Definition: ros_message.hpp:69
nlohmann::detail::void
j template void())
Definition: json.hpp:4061
field
static void field(LexState *ls, ConsControl *cc)
Definition: lparser.c:891
RosMsgParser::BuildMessageSchema
MessageSchema::Ptr BuildMessageSchema(const std::string &topic_name, const std::vector< ROSMessage::Ptr > &parsed_msgs)
Definition: ros_message.cpp:170
RosMsgParser::details::TreeNode
Element of the tree. it has a single parent and N >= 0 children.
Definition: tree.hpp:119
RosMsgParser::ROSField
A ROSMessage will contain one or more ROSField(s). Each field is little more than a name / type pair.
Definition: ros_field.hpp:46
RosMsgParser::ParseMessageDefinitions
std::vector< ROSMessage::Ptr > ParseMessageDefinitions(const std::string &multi_def, const ROSType &type)
Definition: ros_message.cpp:87


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Nov 11 2024 03:23:46