Skip to content

Commit

Permalink
Add type_description struct conversion utils
Browse files Browse the repository at this point in the history
Signed-off-by: methylDragon <[email protected]>
  • Loading branch information
methylDragon committed Dec 31, 2024
1 parent a0a2a06 commit 1ee6c1f
Show file tree
Hide file tree
Showing 3 changed files with 340 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
// Copyright 2025 Open Source Robotics Foundation, Inc.
//
// 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.

#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_

#include "rosidl_runtime_cpp/type_description/individual_type_description__struct.hpp"
#include "rosidl_runtime_cpp/type_description/type_description__struct.hpp"
#include "rosidl_runtime_cpp/type_description/type_source__struct.hpp"
#include "type_description_interfaces/msg/individual_type_description.hpp"
#include "type_description_interfaces/msg/type_description.hpp"
#include "type_description_interfaces/msg/type_source.hpp"

namespace rclcpp
{
namespace dynamic_typesupport
{

// IndividualTypeDescription =======================================================================

/// Convert a runtime individual type description struct to its corresponding message.
/**
* This function converts a rosidl_runtime_cpp::type_description::IndividualTypeDescription
* struct to the corresponding type_description_interfaces/msg/IndividualTypeDescription
* msg.
*
* \param[in] runtime_individual_description the runtime struct to convert
* \return the converted individual type description msg
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
type_description_interfaces::msg::IndividualTypeDescription_<ToAllocatorT>
convert_individual_type_description_runtime_to_msg(
const rosidl_runtime_cpp::type_description::IndividualTypeDescription_<FromAllocatorT> &
runtime_individual_description, const ToAllocatorT & alloc = ToAllocatorT())
{
type_description_interfaces::msg::IndividualTypeDescription_<ToAllocatorT> out(alloc);
out.type_name = runtime_individual_description.type_name;

for (const auto & field : runtime_individual_description.fields) {
out.fields.emplace_back();
out.fields.back().name = field.name;
out.fields.back().default_value = field.default_value;

out.fields.back().type.type_id = field.type.type_id;
out.fields.back().type.capacity = field.type.capacity;
out.fields.back().type.string_capacity = field.type.string_capacity;
out.fields.back().type.nested_type_name = field.type.nested_type_name;
}
return out;
}

/// Convert a individual type description message to its corresponding runtime struct.
/**
* This function converts a type_description_interfaces/msg/IndividualTypeDescription msg
* to the corresponding rosidl_runtime_cpp::type_description::IndividualTypeDescription
* struct.
*
* \param[in] description_msg the message to convert
* \return the converted runtime struct
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
rosidl_runtime_cpp::type_description::IndividualTypeDescription_<ToAllocatorT>
convert_individual_type_description_msg_to_runtime(
const type_description_interfaces::msg::IndividualTypeDescription_<FromAllocatorT> &
individual_description_msg, const ToAllocatorT & alloc = ToAllocatorT())
{
rosidl_runtime_cpp::type_description::IndividualTypeDescription_<ToAllocatorT> out(alloc);
out.type_name = individual_description_msg.type_name;

for (const auto & field : individual_description_msg.fields) {
out.fields.emplace_back();
out.fields.back().name = field.name;
out.fields.back().default_value = field.default_value;

out.fields.back().type.type_id = field.type.type_id;
out.fields.back().type.capacity = field.type.capacity;
out.fields.back().type.string_capacity = field.type.string_capacity;
out.fields.back().type.nested_type_name = field.type.nested_type_name;
}
return out;
}

// TypeDescription =================================================================================

/// Convert a runtime type description struct to its corresponding message.
/**
* This function converts a rosidl_runtime_cpp::type_description::TypeDescription
* struct to the corresponding type_description_interfaces/msg/TypeDescription
* msg.
*
* \param[in] runtime_description the runtime struct to convert
* \return the converted message
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
type_description_interfaces::msg::TypeDescription_<ToAllocatorT>
convert_type_description_runtime_to_msg(
const rosidl_runtime_cpp::type_description::TypeDescription_<FromAllocatorT> & runtime_description,
const ToAllocatorT & alloc = ToAllocatorT())
{
type_description_interfaces::msg::TypeDescription_<ToAllocatorT> out(alloc);
out.type_description =
convert_individual_type_description_runtime_to_msg(runtime_description.type_description, alloc);

for (const auto & referenced_type_description :
runtime_description.referenced_type_descriptions)
{
out.referenced_type_descriptions.push_back(convert_individual_type_description_runtime_to_msg(
referenced_type_description, alloc));
}
return out;
}

/// Convert a type description message to its corresponding runtime struct.
/**
* This function converts a type_description_interfaces/msg/TypeDescription msg
* to the corresponding rosidl_runtime_cpp::type_description::TypeDescription
* struct.
*
* \param[in] description_msg the message to convert
* \return the converted runtime struct
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
rosidl_runtime_cpp::type_description::TypeDescription_<ToAllocatorT>
convert_type_description_msg_to_runtime(
const type_description_interfaces::msg::TypeDescription_<FromAllocatorT> & description_msg,
const ToAllocatorT & alloc = ToAllocatorT())
{
rosidl_runtime_cpp::type_description::TypeDescription_<ToAllocatorT> out(alloc);
out.type_description =
convert_individual_type_description_msg_to_runtime(description_msg.type_description, alloc);

for (const auto & referenced_type_description : description_msg.referenced_type_descriptions) {
out.referenced_type_descriptions.push_back(convert_individual_type_description_msg_to_runtime(
referenced_type_description, alloc));
}
return out;
}

// TypeSource ======================================================================================

/// Convert a runtime type source struct to its corresponding message.
/**
* This function converts a rosidl_runtime_cpp::type_description::TypeSource
* struct to the corresponding type_description_interfaces/msg/TypeSource msg.
*
* \param[in] runtime_type_source the runtime struct to convert
* \return the converted message
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
type_description_interfaces::msg::TypeSource_<ToAllocatorT>
convert_type_source_sequence_runtime_to_msg(
const rosidl_runtime_cpp::type_description::TypeSource_<FromAllocatorT> & runtime_type_source,
const ToAllocatorT & alloc = ToAllocatorT())
{
type_description_interfaces::msg::TypeSource_<ToAllocatorT> out(alloc);
out.type_name = runtime_type_source.type_name;
out.encoding = runtime_type_source.encoding;
out.raw_file_contents = runtime_type_source.raw_file_contents;
return out;
}

/// Convert a type source message to its corresponding runtime struct.
/**
* This function converts a type_description_interfaces/msg/TypeSource msg to
* the corresponding rosidl_runtime_cpp::type_description::TypeSource struct.
*
* \param[in] type_source_msg the message to convert
* \return the converted runtime struct
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
rosidl_runtime_cpp::type_description::TypeSource_<ToAllocatorT>
convert_type_source_sequence_msg_to_runtime(
const type_description_interfaces::msg::TypeSource_<FromAllocatorT> & type_source_msg,
const ToAllocatorT & alloc = ToAllocatorT())
{
rosidl_runtime_cpp::type_description::TypeSource_<ToAllocatorT> out(alloc);
out.type_name = type_source_msg.type_name;
out.encoding = type_source_msg.encoding;
out.raw_file_contents = type_source_msg.raw_file_contents;
return out;
}

} // namespace dynamic_typesupport
} // namespace rclcpp

#endif // RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_
7 changes: 7 additions & 0 deletions rclcpp/test/rclcpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ ament_add_gtest(
if(TARGET test_allocator_deleter)
target_link_libraries(test_allocator_deleter ${PROJECT_NAME})
endif()

ament_add_gtest(test_type_description_conversions
dynamic_typesupport/test_type_description_conversions.cpp)
if(TARGET test_type_description_conversions)
target_link_libraries(test_type_description_conversions ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
endif()

ament_add_gtest(
test_exceptions
exceptions/test_exceptions.cpp)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright 2025 Open Source Robotics Foundation, Inc.
//
// 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.

#include <gtest/gtest.h>

#include "rclcpp/dynamic_typesupport/type_description_conversions.hpp"
#include "rosidl_runtime_cpp/type_description/individual_type_description__struct.hpp"
#include "rosidl_runtime_cpp/type_description/type_description__struct.hpp"
#include "rosidl_runtime_cpp/type_description/type_source__struct.hpp"
#include "type_description_interfaces/msg/individual_type_description.hpp"
#include "type_description_interfaces/msg/type_description.hpp"
#include "type_description_interfaces/msg/type_source.hpp"

using rclcpp::dynamic_typesupport::
convert_individual_type_description_msg_to_runtime;
using rclcpp::dynamic_typesupport::
convert_individual_type_description_runtime_to_msg;
using rclcpp::dynamic_typesupport::convert_type_description_msg_to_runtime;
using rclcpp::dynamic_typesupport::convert_type_description_runtime_to_msg;
using rclcpp::dynamic_typesupport::convert_type_source_sequence_msg_to_runtime;
using rclcpp::dynamic_typesupport::convert_type_source_sequence_runtime_to_msg;

TEST(TestTypeDescriptionConversions, individual_type_description_roundtrip)
{
rosidl_runtime_cpp::type_description::IndividualTypeDescription original;
original.type_name = "test_type_name";

original.fields.emplace_back();
original.fields.back().name = "field1";
original.fields.back().type.type_id = 1;

original.fields.emplace_back();
original.fields.back().name = "field2";
original.fields.back().type.type_id = 2;

type_description_interfaces::msg::IndividualTypeDescription msg =
convert_individual_type_description_runtime_to_msg(original);
rosidl_runtime_cpp::type_description::IndividualTypeDescription converted_back
=
convert_individual_type_description_msg_to_runtime(msg);

EXPECT_EQ(original.type_name, converted_back.type_name);
ASSERT_EQ(original.fields.size(), converted_back.fields.size());
for (size_t i = 0; i < original.fields.size(); ++i) {
EXPECT_EQ(original.fields[i].name, converted_back.fields[i].name);
EXPECT_EQ(original.fields[i].type, converted_back.fields[i].type);
}
}

TEST(TestTypeDescriptionConversions, type_description_roundtrip)
{
rosidl_runtime_cpp::type_description::TypeDescription original;
original.type_description.type_name = "main_type";
original.type_description.fields.emplace_back();
original.type_description.fields.back().name = "field1";
original.type_description.fields.back().type.type_id = 1;
original.type_description.fields.emplace_back();
original.type_description.fields.back().name = "field2";
original.type_description.fields.back().type.type_id = 2;

rosidl_runtime_cpp::type_description::IndividualTypeDescription ref1;
ref1.type_name = "ref_type_1";
ref1.fields.emplace_back();
ref1.fields.back().name = "ref_field1";
ref1.fields.back().type.type_id = 1;

rosidl_runtime_cpp::type_description::IndividualTypeDescription ref2;
ref2.type_name = "ref_type_2";
ref2.fields.emplace_back();
ref2.fields.back().name = "ref_field2";
ref2.fields.back().type.type_id = 2;

original.referenced_type_descriptions.push_back(ref1);
original.referenced_type_descriptions.push_back(ref2);

type_description_interfaces::msg::TypeDescription msg =
convert_type_description_runtime_to_msg(original);
rosidl_runtime_cpp::type_description::TypeDescription converted_back =
convert_type_description_msg_to_runtime(msg);

EXPECT_EQ(original.type_description.type_name,
converted_back.type_description.type_name);
ASSERT_EQ(original.referenced_type_descriptions.size(),
converted_back.referenced_type_descriptions.size());

for (size_t i = 0; i < original.referenced_type_descriptions.size(); ++i) {
EXPECT_EQ(original.referenced_type_descriptions[i].type_name,
converted_back.referenced_type_descriptions[i].type_name);
}
}

TEST(TestTypeSourceConversions, type_source_roundtrip)
{
rosidl_runtime_cpp::type_description::TypeSource original;
original.type_name = "test_type_name";
original.encoding = "test_encoding";
original.raw_file_contents = "test_contents";

type_description_interfaces::msg::TypeSource msg =
convert_type_source_sequence_runtime_to_msg(original);
rosidl_runtime_cpp::type_description::TypeSource converted_back =
convert_type_source_sequence_msg_to_runtime(msg);

EXPECT_EQ(original.type_name, converted_back.type_name);
EXPECT_EQ(original.encoding, converted_back.encoding);
EXPECT_EQ(original.raw_file_contents, converted_back.raw_file_contents);
}

0 comments on commit 1ee6c1f

Please sign in to comment.