Typesupport
The TypeSupport is a crucial component in DDS which provides an interface for handling data types in a standardized way. It is responsible for managing the serialization, deserialization, and type-specific operations for user-defined data types in a DDS system.
In this sense, the TypeSupport ensures the seamless exchange of data between DataReader and DataWriter by providing a common data representation.
A Safe DDS type support is any class that implements the following interfaces:
datacentric::ITypeSupport<T>: Defines the type support specific type and its serialization and deserialization methods.
dds::TypeSupport: To register the type support within the DDS system and handle the type key identifier.
Data representation
For the purpose of achieving interoperability with other DDS vendors, it is necessary that the implementation of any Safe DDS TypeSupport adheres to a commonly accepted serialization and deserialization format known as CDR (Common Data Representation). To facilitate CDR-compliant serialization and deserialization functionality, the following classes are provided:
To set and decode the type of data representation used, the following structure is provided:
By leveraging these classes, the Safe DDS TypeSupport implementation ensures compatibility with other DDS vendors, promoting effective communication and data exchange across various DDS systems.
Registering a type
For a DDS TypeSupport to be utilized effectively, it is necessary to register it within a the application DomainParticipant. Once this registration process is completed, it is possible to leverage the safety-typed APIs offered by TypedDataReader and TypedDataWriter.
In order to register a dds::TypeSupport
interface into a dds::DomainParticipant
, the TypeSupport::register_type
method shall be used.
// Register the type
CustomTypeSupport type_support{};
type_support.register_type(*participant, type_name);
Safe DDS-Gen
Safe DDS-Gen is a Java application that generates Safe DDS source code using the data types defined in an IDL (Interface Definition Language) file. This generated source code can be used in any Safe DDS application in order to define the data type of a topic, which will later be used to publish or subscribe. Please refer to Typesupport for more information on data types.
To declare the structured data, the IDL format must be used. IDL is a specification language, made by OMG (Object Management Group), which describes an interface in a language independent manner, allowing communication between software components that do not share the same language. The Safe DDS-Gen tool reads the IDL files and parses a subset of the OMG IDL specification to generate source code for data serialization, this subset is detailed in the Supported IDL types section.
Safe DDS-Gen generated source code uses provided CDR serialization implementations detailed on Data representation. Therefore, as stated in the RTPS standard, when the data are sent, the serialization is performed using the corresponding Common Data Representation (CDR).
The main feature of Safe DDS-Gen is to facilitate the implementation of DDS applications without the knowledge of serialization or deserialization mechanisms.
For installing Safe DDS-Gen, please refer to Installation.
HelloWorld TypeSupport
For reference, this documentation provides a simple example of a TypeSupport implementation for the HelloWorld data type used in the getting started section:
// Data Type used by HelloWorldTypeSupport
struct HelloWorld
{
uint32_t index;
uint32_t message_size;
char message[255];
};
// TypeSupport for HelloWorld
class HelloWorldTypeSupport : public datacentric::ITypeSupport<HelloWorld>,
public dds::TypeSupport
{
public:
// Definition of internal data type
using DataType = HelloWorld;
// Implementation of dds::TypeSupport
dds::ReturnCode register_type(
dds::DomainParticipant& participant,
const memory::IStringView& type_name) noexcept override
{
return participant.register_type(*this, type_name);
}
const memory::IStringView& get_type_name() const noexcept override
{
static constexpr char const* default_name = "HelloWorldTypeSupport";
static const memory::container::StaticString256 typesupport_name(default_name);
return typesupport_name;
}
bool has_keys() const noexcept override
{
return false;
}
protocol::KeyHash compute_key_hash(
const memory::IConstByteArrayView& /* view */,
const protocol::PayloadKind& /* kind */) const noexcept override
{
return datacentric::KeyHash{};
}
size_t max_serialized_size() const noexcept override
{
return
sizeof(serialization::RepresentationHeader) +
sizeof(HelloWorld::index) +
sizeof(HelloWorld::message_size) +
sizeof(HelloWorld::message);
}
// Implementation of datacentric::ITypeSupport
size_t serialized_size(
const DataType& sample) const noexcept override
{
return
sizeof(serialization::RepresentationHeader) +
sizeof(HelloWorld::index) +
sizeof(HelloWorld::message_size) +
sample.message_size;
}
safedds::ReturnCode serialize(
const DataType& sample,
memory::IByteArrayView& buffer) const noexcept override
{
// Do not serialize if size is bigger than buffer capacity
if (buffer.size() < serialized_size(sample))
{
return safedds::ReturnCode::SERIALIZATION_INVALID_BUFFER_LENGTH;
}
/***************************************************
* RETURN CODE SAFETY CHECKS ARE OMITTED FOR CLARITY
***************************************************/
// Create a CDR serializer on the provided buffer
serialization::cdr::Serializer ser(buffer);
// Serialize a RepresentationHeader
serialization::RepresentationHeader representation_header{};
representation_header.init_as_cdr();
ser.serialize_array(
representation_header.encapsulation_kind_.data(),
serialization::ENCAPSULATION_KIND_SIZE);
ser.serialize_array(
representation_header.encapsulation_options_.data(),
serialization::ENCAPSULATION_OPTIONS_SIZE);
// Serialize the data type
ser.serialize(sample.index);
ser.serialize(sample.message_size);
ser.serialize_array(sample.message, sample.message_size);
return safedds::ReturnCode::OK;
}
safedds::ReturnCode deserialize(
const memory::IConstByteArrayView& buffer,
DataType& sample) const noexcept override
{
/***************************************************
* RETURN CODE SAFETY CHECKS ARE OMITTED FOR CLARITY
***************************************************/
// Create a CDR deserializer for the representation header on native endianness
serialization::cdr::Deserializer representation_header_deser(buffer, true);
// Deserialize RepresentationHeader
serialization::RepresentationHeader representation_header{};
protocol::rtps::RTPSTypeDeserializer::deserialize(
representation_header_deser,
representation_header);
// Retrieve the payload buffer
memory::byte_array::ByteArrayView payload_view = {nullptr, 0};
representation_header_deser.deserializer_skip(
representation_header_deser.deserializer_remaining_size(),
payload_view);
// Create a deserializer for the payload
serialization::cdr::Deserializer deserializer(
payload_view,
representation_header.check_native_endianness());
// Deserialize the data type
deserializer.deserialize(sample.index);
deserializer.deserialize(sample.message_size);
deserializer.deserialize_array(sample.message, sample.message_size);
return safedds::ReturnCode::OK;
}
protocol::KeyHash get_key(
const DataType& /* data */) const noexcept override
{
return datacentric::KeyHash{};
}
datacentric::KeyHash get_key(
const memory::IConstByteArrayView& /* view */,
const protocol::PayloadKind& /* kind */) const noexcept override
{
return datacentric::KeyHash{};
}
};