Skip to content

Commit 1ee6c1f

Browse files
committed
Add type_description struct conversion utils
Signed-off-by: methylDragon <[email protected]>
1 parent a0a2a06 commit 1ee6c1f

File tree

3 files changed

+340
-0
lines changed

3 files changed

+340
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Copyright 2025 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_
16+
#define RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_
17+
18+
#include "rosidl_runtime_cpp/type_description/individual_type_description__struct.hpp"
19+
#include "rosidl_runtime_cpp/type_description/type_description__struct.hpp"
20+
#include "rosidl_runtime_cpp/type_description/type_source__struct.hpp"
21+
#include "type_description_interfaces/msg/individual_type_description.hpp"
22+
#include "type_description_interfaces/msg/type_description.hpp"
23+
#include "type_description_interfaces/msg/type_source.hpp"
24+
25+
namespace rclcpp
26+
{
27+
namespace dynamic_typesupport
28+
{
29+
30+
// IndividualTypeDescription =======================================================================
31+
32+
/// Convert a runtime individual type description struct to its corresponding message.
33+
/**
34+
* This function converts a rosidl_runtime_cpp::type_description::IndividualTypeDescription
35+
* struct to the corresponding type_description_interfaces/msg/IndividualTypeDescription
36+
* msg.
37+
*
38+
* \param[in] runtime_individual_description the runtime struct to convert
39+
* \return the converted individual type description msg
40+
*/
41+
template<
42+
typename ToAllocatorT = std::allocator<void>,
43+
typename FromAllocatorT
44+
>
45+
type_description_interfaces::msg::IndividualTypeDescription_<ToAllocatorT>
46+
convert_individual_type_description_runtime_to_msg(
47+
const rosidl_runtime_cpp::type_description::IndividualTypeDescription_<FromAllocatorT> &
48+
runtime_individual_description, const ToAllocatorT & alloc = ToAllocatorT())
49+
{
50+
type_description_interfaces::msg::IndividualTypeDescription_<ToAllocatorT> out(alloc);
51+
out.type_name = runtime_individual_description.type_name;
52+
53+
for (const auto & field : runtime_individual_description.fields) {
54+
out.fields.emplace_back();
55+
out.fields.back().name = field.name;
56+
out.fields.back().default_value = field.default_value;
57+
58+
out.fields.back().type.type_id = field.type.type_id;
59+
out.fields.back().type.capacity = field.type.capacity;
60+
out.fields.back().type.string_capacity = field.type.string_capacity;
61+
out.fields.back().type.nested_type_name = field.type.nested_type_name;
62+
}
63+
return out;
64+
}
65+
66+
/// Convert a individual type description message to its corresponding runtime struct.
67+
/**
68+
* This function converts a type_description_interfaces/msg/IndividualTypeDescription msg
69+
* to the corresponding rosidl_runtime_cpp::type_description::IndividualTypeDescription
70+
* struct.
71+
*
72+
* \param[in] description_msg the message to convert
73+
* \return the converted runtime struct
74+
*/
75+
template<
76+
typename ToAllocatorT = std::allocator<void>,
77+
typename FromAllocatorT
78+
>
79+
rosidl_runtime_cpp::type_description::IndividualTypeDescription_<ToAllocatorT>
80+
convert_individual_type_description_msg_to_runtime(
81+
const type_description_interfaces::msg::IndividualTypeDescription_<FromAllocatorT> &
82+
individual_description_msg, const ToAllocatorT & alloc = ToAllocatorT())
83+
{
84+
rosidl_runtime_cpp::type_description::IndividualTypeDescription_<ToAllocatorT> out(alloc);
85+
out.type_name = individual_description_msg.type_name;
86+
87+
for (const auto & field : individual_description_msg.fields) {
88+
out.fields.emplace_back();
89+
out.fields.back().name = field.name;
90+
out.fields.back().default_value = field.default_value;
91+
92+
out.fields.back().type.type_id = field.type.type_id;
93+
out.fields.back().type.capacity = field.type.capacity;
94+
out.fields.back().type.string_capacity = field.type.string_capacity;
95+
out.fields.back().type.nested_type_name = field.type.nested_type_name;
96+
}
97+
return out;
98+
}
99+
100+
// TypeDescription =================================================================================
101+
102+
/// Convert a runtime type description struct to its corresponding message.
103+
/**
104+
* This function converts a rosidl_runtime_cpp::type_description::TypeDescription
105+
* struct to the corresponding type_description_interfaces/msg/TypeDescription
106+
* msg.
107+
*
108+
* \param[in] runtime_description the runtime struct to convert
109+
* \return the converted message
110+
*/
111+
template<
112+
typename ToAllocatorT = std::allocator<void>,
113+
typename FromAllocatorT
114+
>
115+
type_description_interfaces::msg::TypeDescription_<ToAllocatorT>
116+
convert_type_description_runtime_to_msg(
117+
const rosidl_runtime_cpp::type_description::TypeDescription_<FromAllocatorT> & runtime_description,
118+
const ToAllocatorT & alloc = ToAllocatorT())
119+
{
120+
type_description_interfaces::msg::TypeDescription_<ToAllocatorT> out(alloc);
121+
out.type_description =
122+
convert_individual_type_description_runtime_to_msg(runtime_description.type_description, alloc);
123+
124+
for (const auto & referenced_type_description :
125+
runtime_description.referenced_type_descriptions)
126+
{
127+
out.referenced_type_descriptions.push_back(convert_individual_type_description_runtime_to_msg(
128+
referenced_type_description, alloc));
129+
}
130+
return out;
131+
}
132+
133+
/// Convert a type description message to its corresponding runtime struct.
134+
/**
135+
* This function converts a type_description_interfaces/msg/TypeDescription msg
136+
* to the corresponding rosidl_runtime_cpp::type_description::TypeDescription
137+
* struct.
138+
*
139+
* \param[in] description_msg the message to convert
140+
* \return the converted runtime struct
141+
*/
142+
template<
143+
typename ToAllocatorT = std::allocator<void>,
144+
typename FromAllocatorT
145+
>
146+
rosidl_runtime_cpp::type_description::TypeDescription_<ToAllocatorT>
147+
convert_type_description_msg_to_runtime(
148+
const type_description_interfaces::msg::TypeDescription_<FromAllocatorT> & description_msg,
149+
const ToAllocatorT & alloc = ToAllocatorT())
150+
{
151+
rosidl_runtime_cpp::type_description::TypeDescription_<ToAllocatorT> out(alloc);
152+
out.type_description =
153+
convert_individual_type_description_msg_to_runtime(description_msg.type_description, alloc);
154+
155+
for (const auto & referenced_type_description : description_msg.referenced_type_descriptions) {
156+
out.referenced_type_descriptions.push_back(convert_individual_type_description_msg_to_runtime(
157+
referenced_type_description, alloc));
158+
}
159+
return out;
160+
}
161+
162+
// TypeSource ======================================================================================
163+
164+
/// Convert a runtime type source struct to its corresponding message.
165+
/**
166+
* This function converts a rosidl_runtime_cpp::type_description::TypeSource
167+
* struct to the corresponding type_description_interfaces/msg/TypeSource msg.
168+
*
169+
* \param[in] runtime_type_source the runtime struct to convert
170+
* \return the converted message
171+
*/
172+
template<
173+
typename ToAllocatorT = std::allocator<void>,
174+
typename FromAllocatorT
175+
>
176+
type_description_interfaces::msg::TypeSource_<ToAllocatorT>
177+
convert_type_source_sequence_runtime_to_msg(
178+
const rosidl_runtime_cpp::type_description::TypeSource_<FromAllocatorT> & runtime_type_source,
179+
const ToAllocatorT & alloc = ToAllocatorT())
180+
{
181+
type_description_interfaces::msg::TypeSource_<ToAllocatorT> out(alloc);
182+
out.type_name = runtime_type_source.type_name;
183+
out.encoding = runtime_type_source.encoding;
184+
out.raw_file_contents = runtime_type_source.raw_file_contents;
185+
return out;
186+
}
187+
188+
/// Convert a type source message to its corresponding runtime struct.
189+
/**
190+
* This function converts a type_description_interfaces/msg/TypeSource msg to
191+
* the corresponding rosidl_runtime_cpp::type_description::TypeSource struct.
192+
*
193+
* \param[in] type_source_msg the message to convert
194+
* \return the converted runtime struct
195+
*/
196+
template<
197+
typename ToAllocatorT = std::allocator<void>,
198+
typename FromAllocatorT
199+
>
200+
rosidl_runtime_cpp::type_description::TypeSource_<ToAllocatorT>
201+
convert_type_source_sequence_msg_to_runtime(
202+
const type_description_interfaces::msg::TypeSource_<FromAllocatorT> & type_source_msg,
203+
const ToAllocatorT & alloc = ToAllocatorT())
204+
{
205+
rosidl_runtime_cpp::type_description::TypeSource_<ToAllocatorT> out(alloc);
206+
out.type_name = type_source_msg.type_name;
207+
out.encoding = type_source_msg.encoding;
208+
out.raw_file_contents = type_source_msg.raw_file_contents;
209+
return out;
210+
}
211+
212+
} // namespace dynamic_typesupport
213+
} // namespace rclcpp
214+
215+
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_

rclcpp/test/rclcpp/CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ ament_add_gtest(
2828
if(TARGET test_allocator_deleter)
2929
target_link_libraries(test_allocator_deleter ${PROJECT_NAME})
3030
endif()
31+
32+
ament_add_gtest(test_type_description_conversions
33+
dynamic_typesupport/test_type_description_conversions.cpp)
34+
if(TARGET test_type_description_conversions)
35+
target_link_libraries(test_type_description_conversions ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
36+
endif()
37+
3138
ament_add_gtest(
3239
test_exceptions
3340
exceptions/test_exceptions.cpp)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright 2025 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <gtest/gtest.h>
16+
17+
#include "rclcpp/dynamic_typesupport/type_description_conversions.hpp"
18+
#include "rosidl_runtime_cpp/type_description/individual_type_description__struct.hpp"
19+
#include "rosidl_runtime_cpp/type_description/type_description__struct.hpp"
20+
#include "rosidl_runtime_cpp/type_description/type_source__struct.hpp"
21+
#include "type_description_interfaces/msg/individual_type_description.hpp"
22+
#include "type_description_interfaces/msg/type_description.hpp"
23+
#include "type_description_interfaces/msg/type_source.hpp"
24+
25+
using rclcpp::dynamic_typesupport::
26+
convert_individual_type_description_msg_to_runtime;
27+
using rclcpp::dynamic_typesupport::
28+
convert_individual_type_description_runtime_to_msg;
29+
using rclcpp::dynamic_typesupport::convert_type_description_msg_to_runtime;
30+
using rclcpp::dynamic_typesupport::convert_type_description_runtime_to_msg;
31+
using rclcpp::dynamic_typesupport::convert_type_source_sequence_msg_to_runtime;
32+
using rclcpp::dynamic_typesupport::convert_type_source_sequence_runtime_to_msg;
33+
34+
TEST(TestTypeDescriptionConversions, individual_type_description_roundtrip)
35+
{
36+
rosidl_runtime_cpp::type_description::IndividualTypeDescription original;
37+
original.type_name = "test_type_name";
38+
39+
original.fields.emplace_back();
40+
original.fields.back().name = "field1";
41+
original.fields.back().type.type_id = 1;
42+
43+
original.fields.emplace_back();
44+
original.fields.back().name = "field2";
45+
original.fields.back().type.type_id = 2;
46+
47+
type_description_interfaces::msg::IndividualTypeDescription msg =
48+
convert_individual_type_description_runtime_to_msg(original);
49+
rosidl_runtime_cpp::type_description::IndividualTypeDescription converted_back
50+
=
51+
convert_individual_type_description_msg_to_runtime(msg);
52+
53+
EXPECT_EQ(original.type_name, converted_back.type_name);
54+
ASSERT_EQ(original.fields.size(), converted_back.fields.size());
55+
for (size_t i = 0; i < original.fields.size(); ++i) {
56+
EXPECT_EQ(original.fields[i].name, converted_back.fields[i].name);
57+
EXPECT_EQ(original.fields[i].type, converted_back.fields[i].type);
58+
}
59+
}
60+
61+
TEST(TestTypeDescriptionConversions, type_description_roundtrip)
62+
{
63+
rosidl_runtime_cpp::type_description::TypeDescription original;
64+
original.type_description.type_name = "main_type";
65+
original.type_description.fields.emplace_back();
66+
original.type_description.fields.back().name = "field1";
67+
original.type_description.fields.back().type.type_id = 1;
68+
original.type_description.fields.emplace_back();
69+
original.type_description.fields.back().name = "field2";
70+
original.type_description.fields.back().type.type_id = 2;
71+
72+
rosidl_runtime_cpp::type_description::IndividualTypeDescription ref1;
73+
ref1.type_name = "ref_type_1";
74+
ref1.fields.emplace_back();
75+
ref1.fields.back().name = "ref_field1";
76+
ref1.fields.back().type.type_id = 1;
77+
78+
rosidl_runtime_cpp::type_description::IndividualTypeDescription ref2;
79+
ref2.type_name = "ref_type_2";
80+
ref2.fields.emplace_back();
81+
ref2.fields.back().name = "ref_field2";
82+
ref2.fields.back().type.type_id = 2;
83+
84+
original.referenced_type_descriptions.push_back(ref1);
85+
original.referenced_type_descriptions.push_back(ref2);
86+
87+
type_description_interfaces::msg::TypeDescription msg =
88+
convert_type_description_runtime_to_msg(original);
89+
rosidl_runtime_cpp::type_description::TypeDescription converted_back =
90+
convert_type_description_msg_to_runtime(msg);
91+
92+
EXPECT_EQ(original.type_description.type_name,
93+
converted_back.type_description.type_name);
94+
ASSERT_EQ(original.referenced_type_descriptions.size(),
95+
converted_back.referenced_type_descriptions.size());
96+
97+
for (size_t i = 0; i < original.referenced_type_descriptions.size(); ++i) {
98+
EXPECT_EQ(original.referenced_type_descriptions[i].type_name,
99+
converted_back.referenced_type_descriptions[i].type_name);
100+
}
101+
}
102+
103+
TEST(TestTypeSourceConversions, type_source_roundtrip)
104+
{
105+
rosidl_runtime_cpp::type_description::TypeSource original;
106+
original.type_name = "test_type_name";
107+
original.encoding = "test_encoding";
108+
original.raw_file_contents = "test_contents";
109+
110+
type_description_interfaces::msg::TypeSource msg =
111+
convert_type_source_sequence_runtime_to_msg(original);
112+
rosidl_runtime_cpp::type_description::TypeSource converted_back =
113+
convert_type_source_sequence_msg_to_runtime(msg);
114+
115+
EXPECT_EQ(original.type_name, converted_back.type_name);
116+
EXPECT_EQ(original.encoding, converted_back.encoding);
117+
EXPECT_EQ(original.raw_file_contents, converted_back.raw_file_contents);
118+
}

0 commit comments

Comments
 (0)