-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generate schemas in ROS 2 msg format (#69)
* Create demangle files Signed-off-by: Irene Bandera <[email protected]> * Add demangle test Signed-off-by: Irene Bandera <[email protected]> * Remap demangle -> ros2_mangling & add comments Signed-off-by: Irene Bandera <[email protected]> * Add mangling functions Signed-off-by: Irene Bandera <[email protected]> * Update versions.md Signed-off-by: Irene Bandera <[email protected]> * Move ROS 2 Mangling methods to cpp_utils package Signed-off-by: Irene Bandera <[email protected]> * Store schemas in ROS 2 msg format Signed-off-by: Irene Bandera <[email protected]> * Update versions.md Signed-off-by: Irene Bandera <[email protected]> * Apply changes Signed-off-by: Irene Bandera <[email protected]> * Uncrustify Signed-off-by: Irene Bandera <[email protected]> --------- Signed-off-by: Irene Bandera <[email protected]>
- Loading branch information
Showing
16 changed files
with
547 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
331 changes: 331 additions & 0 deletions
331
ddspipe_core/src/cpp/types/dynamic_types/schema_msg.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,331 @@ | ||
// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
/** | ||
* @file schema_msg.cpp | ||
*/ | ||
|
||
#include <ostream> | ||
#include <map> | ||
|
||
#include <fastrtps/types/DynamicType.h> | ||
#include <fastrtps/types/DynamicTypeMember.h> | ||
#include <fastrtps/types/DynamicTypePtr.h> | ||
#include <fastrtps/types/TypeDescriptor.h> | ||
|
||
#include <cpp_utils/exception/InconsistencyException.hpp> | ||
#include <cpp_utils/exception/UnsupportedException.hpp> | ||
#include <cpp_utils/types/Tree.hpp> | ||
#include <cpp_utils/utils.hpp> | ||
#include <cpp_utils/ros2_mangling.hpp> | ||
|
||
#include <ddspipe_core/types/dynamic_types/schema.hpp> | ||
|
||
namespace eprosima { | ||
namespace ddspipe { | ||
namespace core { | ||
namespace types { | ||
namespace msg { | ||
|
||
constexpr const char* TYPE_SEPARATOR = | ||
"================================================================================\n"; | ||
|
||
struct TreeNodeType | ||
{ | ||
TreeNodeType( | ||
std::string member_name, | ||
std::string type_kind_name, | ||
bool is_struct = false) | ||
: member_name(member_name) | ||
, type_kind_name(type_kind_name) | ||
, is_struct(is_struct) | ||
{ | ||
} | ||
|
||
std::string member_name; | ||
std::string type_kind_name; | ||
bool is_struct; | ||
}; | ||
|
||
// Forward declaration | ||
std::string type_kind_to_str( | ||
const fastrtps::types::DynamicType_ptr& type); | ||
|
||
fastrtps::types::DynamicType_ptr container_internal_type( | ||
const fastrtps::types::DynamicType_ptr& dyn_type) | ||
{ | ||
return dyn_type->get_descriptor()->get_element_type(); | ||
} | ||
|
||
std::vector<uint32_t> array_size( | ||
const fastrtps::types::DynamicType_ptr& dyn_type, | ||
bool unidimensional = true) | ||
{ | ||
if (unidimensional) | ||
{ | ||
return {dyn_type->get_descriptor()->get_total_bounds()}; | ||
} | ||
else | ||
{ | ||
std::vector<uint32_t> result; | ||
for (unsigned int i = 0; i < dyn_type->get_descriptor()->get_bounds_size(); i++) | ||
{ | ||
result.push_back(dyn_type->get_descriptor()->get_bounds(i)); | ||
} | ||
return result; | ||
} | ||
} | ||
|
||
std::vector<std::pair<std::string, fastrtps::types::DynamicType_ptr>> get_members_sorted( | ||
const fastrtps::types::DynamicType_ptr& dyn_type) | ||
{ | ||
std::vector<std::pair<std::string, fastrtps::types::DynamicType_ptr>> result; | ||
|
||
std::map<fastrtps::types::MemberId, fastrtps::types::DynamicTypeMember*> members; | ||
dyn_type->get_all_members(members); | ||
|
||
for (const auto& member : members) | ||
{ | ||
result.emplace_back( | ||
std::make_pair<std::string, fastrtps::types::DynamicType_ptr>( | ||
utils::demangle_if_ros_type(member.second->get_name()), | ||
member.second->get_descriptor()->get_type())); | ||
} | ||
return result; | ||
} | ||
|
||
std::string container_kind_to_str( | ||
const fastrtps::types::DynamicType_ptr& dyn_type, | ||
bool allow_bounded = false) | ||
{ | ||
auto internal_type = container_internal_type(dyn_type); | ||
auto this_array_size = array_size(dyn_type); | ||
|
||
std::stringstream ss; | ||
ss << type_kind_to_str(internal_type); | ||
|
||
for (const auto& bound : this_array_size) | ||
{ | ||
if (bound != fastrtps::types::BOUND_UNLIMITED) | ||
{ | ||
if (allow_bounded) | ||
{ | ||
ss << "[<=" << bound << "]"; | ||
} | ||
else | ||
{ | ||
ss << "[" << bound << "]"; | ||
} | ||
} | ||
else | ||
{ | ||
ss << "[]"; | ||
} | ||
} | ||
|
||
return ss.str(); | ||
} | ||
|
||
std::string type_kind_to_str( | ||
const fastrtps::types::DynamicType_ptr& dyn_type) | ||
{ | ||
switch (dyn_type->get_kind()) | ||
{ | ||
case fastrtps::types::TK_BOOLEAN: | ||
return "bool"; | ||
|
||
case fastrtps::types::TK_BYTE: | ||
return "uint8"; | ||
|
||
case fastrtps::types::TK_INT16: | ||
return "int16"; | ||
|
||
case fastrtps::types::TK_INT32: | ||
return "int32"; | ||
|
||
case fastrtps::types::TK_INT64: | ||
return "int64"; | ||
|
||
case fastrtps::types::TK_UINT16: | ||
return "uint16"; | ||
|
||
case fastrtps::types::TK_UINT32: | ||
return "uint32"; | ||
|
||
case fastrtps::types::TK_UINT64: | ||
return "uint64"; | ||
|
||
case fastrtps::types::TK_FLOAT32: | ||
return "float32"; | ||
|
||
case fastrtps::types::TK_FLOAT64: | ||
return "float64"; | ||
|
||
case fastrtps::types::TK_CHAR8: | ||
return "int8"; | ||
|
||
case fastrtps::types::TK_STRING8: | ||
return "string"; | ||
|
||
case fastrtps::types::TK_ARRAY: | ||
return container_kind_to_str(dyn_type); | ||
|
||
case fastrtps::types::TK_SEQUENCE: | ||
return container_kind_to_str(dyn_type, true); | ||
|
||
case fastrtps::types::TK_STRUCTURE: | ||
return utils::demangle_if_ros_type(dyn_type->get_name()); | ||
|
||
case fastrtps::types::TK_FLOAT128: | ||
case fastrtps::types::TK_CHAR16: | ||
case fastrtps::types::TK_STRING16: | ||
case fastrtps::types::TK_ENUM: | ||
case fastrtps::types::TK_BITSET: | ||
case fastrtps::types::TK_MAP: | ||
case fastrtps::types::TK_UNION: | ||
case fastrtps::types::TK_NONE: | ||
throw utils::UnsupportedException( | ||
STR_ENTRY << "Type " << utils::demangle_if_ros_type( | ||
dyn_type->get_name()) << " is not supported in ROS2 msg."); | ||
|
||
default: | ||
throw utils::InconsistencyException( | ||
STR_ENTRY << "Type " << utils::demangle_if_ros_type( | ||
dyn_type->get_name()) << " has not correct kind."); | ||
} | ||
} | ||
|
||
utils::TreeNode<TreeNodeType> generate_dyn_type_tree( | ||
const fastrtps::types::DynamicType_ptr& type, | ||
const std::string& member_name = "PARENT") | ||
{ | ||
// Get kind | ||
fastrtps::types::TypeKind kind = type->get_kind(); | ||
|
||
switch (kind) | ||
{ | ||
case fastrtps::types::TK_STRUCTURE: | ||
{ | ||
// If is struct, the call is recursive. | ||
// Create new tree node | ||
utils::TreeNode<TreeNodeType> parent(member_name, utils::demangle_if_ros_type(type->get_name()), true); | ||
|
||
// Get all members of this struct | ||
std::vector<std::pair<std::string, | ||
fastrtps::types::DynamicType_ptr>> members_by_name = get_members_sorted(type); | ||
|
||
for (const auto& member : members_by_name) | ||
{ | ||
// Add each member with its name as a new node in a branch (recursion) | ||
parent.add_branch( | ||
generate_dyn_type_tree(member.second, member.first)); | ||
} | ||
return parent; | ||
} | ||
break; | ||
|
||
case fastrtps::types::TK_ARRAY: | ||
case fastrtps::types::TK_SEQUENCE: | ||
{ | ||
// If container (array or struct) has exactly one branch | ||
// Calculate child branch | ||
auto internal_type = container_internal_type(type); | ||
|
||
// Create this node | ||
utils::TreeNode<TreeNodeType> container(member_name, type_kind_to_str(type)); | ||
// Add branch | ||
container.add_branch(generate_dyn_type_tree(internal_type, "CONTAINER_MEMBER")); | ||
|
||
return container; | ||
} | ||
break; | ||
|
||
default: | ||
return utils::TreeNode<TreeNodeType>(member_name, type_kind_to_str(type)); | ||
break; | ||
} | ||
} | ||
|
||
std::ostream& node_to_str( | ||
std::ostream& os, | ||
const TreeNodeType& node) | ||
{ | ||
os << node.type_kind_name << " " << node.member_name; | ||
|
||
return os; | ||
} | ||
|
||
std::ostream& generate_schema_from_node( | ||
std::ostream& os, | ||
const utils::TreeNode<TreeNodeType>& node) | ||
{ | ||
// We know for sure this is called from structs | ||
|
||
for (auto const& child : node.branches()) | ||
{ | ||
node_to_str(os, child.info); | ||
os << "\n"; | ||
} | ||
|
||
return os; | ||
} | ||
|
||
std::string generate_dyn_type_schema_from_tree( | ||
const utils::TreeNode<TreeNodeType>& parent_node) | ||
{ | ||
std::set<std::string> types_written; | ||
|
||
std::stringstream ss; | ||
|
||
// Write down main node | ||
generate_schema_from_node(ss, parent_node); | ||
types_written.insert(parent_node.info.type_kind_name); | ||
|
||
// For every Node, check if it is a struct. | ||
// If it is, check if it is not yet written | ||
// If it is not, write it down | ||
for (const auto& node : parent_node.all_nodes()) | ||
{ | ||
if (node.info.is_struct && types_written.find(node.info.type_kind_name) == types_written.end()) | ||
{ | ||
// Add types separator | ||
ss << TYPE_SEPARATOR; | ||
|
||
// Add types name | ||
ss << "MSG: fastdds/" << node.info.type_kind_name << "\n"; | ||
|
||
// Add next type | ||
generate_schema_from_node(ss, node); | ||
types_written.insert(node.info.type_kind_name); | ||
} | ||
} | ||
|
||
return ss.str(); | ||
} | ||
|
||
std::string generate_ros2_schema( | ||
const fastrtps::types::DynamicType_ptr& dynamic_type) | ||
{ | ||
// Generate type tree | ||
utils::TreeNode<TreeNodeType> parent_type = generate_dyn_type_tree(dynamic_type); | ||
|
||
// From tree, generate string | ||
return generate_dyn_type_schema_from_tree(parent_type); | ||
} | ||
|
||
} /* namespace msg */ | ||
} /* namespace types */ | ||
} /* namespace core */ | ||
} /* namespace ddspipe */ | ||
} /* namespace eprosima */ |
Oops, something went wrong.