rosidl_dynamic_typesupport
Unified serialization support interface for dynamic typesupport in C.
README
rosidl_dynamic_typesupport
Unified Interface for Dynamic (Runtime) Typesupport and Serialization
This library provides a unified interface for creating and reflecting dynamic types and dynamic data based off those types at runtime, as well as the utilities that support those objects.
It is meant to be used with serialization support libraries that fulfill the interface. Properly implemented, a user should be able to, given a serialized buffer, the serialization library used to serialize it, and the buffer’s message/type description, obtain a way to introspect/reflect its contents.
Example Usage
// Init Serialization Support (in this case, using FastRTPS)
rosidl_dynamic_typesupport_serialization_support_t serialization_support;
rosidl_dynamic_typesupport_serialization_support_init(
rosidl_dynamic_typesupport_fastrtps_init_serialization_support_impl(),
rosidl_dynamic_typesupport_fastrtps_init_serialization_support_interface(),
rcutils_get_default_allocator(),
&serialization_support);
// Configure Dynamic Type Builder
rosidl_dynamic_typesupport_dynamic_type_builder_t * flat_builder =
rosidl_dynamic_typesupport_dynamic_type_builder_init(&serialization_support, "flat");
rosidl_dynamic_typesupport_dynamic_type_builder_add_bool_member(flat_builder, 0, "bool_field");
rosidl_dynamic_typesupport_dynamic_type_builder_add_int32_member(flat_builder, 1, "int32_field");
rosidl_dynamic_typesupport_dynamic_type_builder_add_string_member(flat_builder, 2, "string_field");
// Create Dynamic Type
rosidl_dynamic_typesupport_dynamic_type_t * flat_type =
rosidl_dynamic_typesupport_dynamic_type_builder_build(flat_builder);
rosidl_dynamic_typesupport_dynamic_type_builder_fini(flat_builder);
// Create Dynamic Data
rosidl_dynamic_typesupport_dynamic_data_t * flat_data =
rosidl_dynamic_typesupport_dynamic_data_init_from_dynamic_type(flat_type);
// Dynamic Data Setters
rosidl_dynamic_typesupport_dynamic_data_set_bool_value(flat_data, 0, true);
rosidl_dynamic_typesupport_dynamic_data_set_int32_value(flat_data, 1, 42);
rosidl_dynamic_typesupport_dynamic_data_set_string_value(flat_data, 2, "rar");
// Dynamic Data Getters
bool a;
int32_t b;
char * c;
rosidl_dynamic_typesupport_dynamic_data_get_bool_value(flat_data, 0, &a); // true
rosidl_dynamic_typesupport_dynamic_data_get_int32_value(flat_data, 1, &b); // 42
rosidl_dynamic_typesupport_dynamic_data_get_string_value(flat_data, 2, &c); // "rar"
// Cleanup
free(c);
rosidl_dynamic_typesupport_dynamic_data_fini(flat_data);
Some Terminology
Serialization support: What this library provides; A unified, serialization library agnostic interface
Serialization support library: The implementation of the serialization support interface, which this library calls into
Type description (aka message description): A description of the buffer that fulfills the rosidl spec (this typically takes the form of the
TypeDescription
struct generated from the type_descripion_interfaces package)Dynamic type: The serialization support library’s best-effort internal representation of the type description
Dynamic type builder: The serialization support library’s means of constructing the dynamic type (on a field-by-field basis)
Dynamic data: The serialization support library’s internal representation of the serialized buffer, informed by the dynamic type
Why Dynamic Typesupport?
Dynamic: This library dynamically changes its internal behavior based off its runtime input (e.g. what serialization library is loaded to be used with it)
Typesupport: And it supports the creation of, and access of types
This package differs from the usual ROS 2 notion of “dynamic” typesupport in that it offers runtime functionalities that change based off its input (hence dynamic), rather than compile-time code generation like the “dynamic” rosidl_typesupport_introspection
package does (which generates introspectable typesupports at compile time.)
Furthermore, since this package does not actually generate any code, it is stored separately from the rosidl repository.
The Serialization Support Interface
The serialization support interface is supposed to be an interface that is generic enough to support run-time type reflection (or in other words, dynamic type support), and is written in C
to allow for easy language binding with any downstream libraries that use it.
Its interface is inspired by rosidl, and the DDS XTypes 1.3 language bindings spec (pg. 175), but is still intended to be generic, and so should support non-DDS middlewares.
The Serialization Support includes, for each supported middleware:
Setting type members (dynamic type)
Note the lack of ability to get type members
Getting and setting data members based off that type (dynamic data)
Support for sequences and nested members
Utilities
The interface makes heavy use of void *
casting to abstract away any necessary objects used with each serialization library.
A Note On Proper Usage
The serialization support capabilities of this library are meant to be used alongside a rosidl-compliant description of the message a buffer is meant to represent (the type description).
This is because there is a distinction between the rosidl description of a message, and what a serialization library can describe or express (in its dynamic type.) As such, the rosidl description should be the sole source of determine what specific dynamic data getter functions are called during the unpacking of the message. And the serialization support library is in charge of supporting mapping to and from what types it can support, and the rosidl types.
Consider the following, contrived example, where you have a message layout like so:
int int_field
Suppose you had a serialization library that only provisions support for raw bytes.
In that case, the serialization support library written would probably end up treating the int_field
field as raw bytes when constructing its dynamic type, which means that when the message gets deserialized, something must retain the knowledge that the int_field
was supposed to be an int
type.
This is precisely what the type description is for, which a user should programmatically traverse, and use to determine the appropriate int
dynamic data getter to call.
The serialization support library then should implement its int
dynamic data getter to extract the field from the buffer (as raw bytes, since that is what the serialization library supports), and coerce the extracted type (raw bytes) to output an int
value to return.
Additionally, this means that, in order to support such cases, the serialization library must either:
Use the same member/field indexing as is used in the type description
Have an alternate means to find the field described in the type description (e.g. by matching field names)
Note: There was a consideration to populate the dynamic type/data objects with the type description instead. But as the type description and dynamic type encompasses two subtly different concerns (rosidl compliance, and serialization library specific type support, respectively), it makes sense to keep them separate. And this is especially true given the fact that users are supposed to use the type description to call the appropriate getters.
Type IDs
The type IDs used by this library (in types.h
) are pulling from the type_descripion_interfaces message definitions.