Skip to content

Commit

Permalink
Generate schemas in ROS 2 msg format (#69)
Browse files Browse the repository at this point in the history
* 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
irenebm authored Nov 3, 2023
1 parent 19d4dc1 commit 1c37ea5
Show file tree
Hide file tree
Showing 16 changed files with 547 additions and 7 deletions.
12 changes: 12 additions & 0 deletions ddspipe_core/include/ddspipe_core/types/dynamic_types/schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,22 @@ namespace ddspipe {
namespace core {
namespace types {

namespace idl {

DDSPIPE_CORE_DllAPI
std::string generate_idl_schema(
const fastrtps::types::DynamicType_ptr& dynamic_type);

} /* namespace idl */

namespace msg {

DDSPIPE_CORE_DllAPI
std::string generate_ros2_schema(
const fastrtps::types::DynamicType_ptr& dynamic_type);

} /* namespace msg */

} /* namespace types */
} /* namespace core */
} /* namespace ddspipe */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

/**
* @file schema.cpp
* @file schema_idl.cpp
*/

#include <ostream>
Expand All @@ -35,6 +35,7 @@ namespace eprosima {
namespace ddspipe {
namespace core {
namespace types {
namespace idl {

constexpr const char* TYPE_OPENING =
"\n{\n";
Expand Down Expand Up @@ -232,6 +233,7 @@ std::string type_kind_to_str(
default:
throw utils::InconsistencyException(
STR_ENTRY << "Type " << dyn_type->get_name() << " has not correct kind.");

}
}

Expand Down Expand Up @@ -381,8 +383,11 @@ std::ostream& union_to_str(

os << "case " << std::to_string(label) << ":";
}

os << "\n" << TAB_SEPARATOR << TAB_SEPARATOR << type_kind_to_str(member.second->get_descriptor()->get_type()) <<
" " << member.second->get_name() << ";\n";


}

// Close definition
Expand Down Expand Up @@ -445,6 +450,7 @@ std::string generate_idl_schema(
return generate_dyn_type_schema_from_tree(parent_type);
}

} /* namespace idl */
} /* namespace types */
} /* namespace core */
} /* namespace ddspipe */
Expand Down
331 changes: 331 additions & 0 deletions ddspipe_core/src/cpp/types/dynamic_types/schema_msg.cpp
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 */
Loading

0 comments on commit 1c37ea5

Please sign in to comment.