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 dds::TypeSupport, that allows registering 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 application code to support type handling when using Safe DDS from data types defined in an IDL (Interface Definition Language) file. It does so by generating code which leverages Safe DDS APIs. 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 dds::TypedTypeSupport<HelloWorld>
{
public:

    // Definition of internal data type
    using DataType = HelloWorld;

    // Implementation of dds::TypedTypeSupport
    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;
    }

    uint32_t max_serialized_size() const noexcept override
    {
        return
            sizeof(serialization::RepresentationHeader) +
            sizeof(HelloWorld::index) +
            sizeof(HelloWorld::message_size) +
            sizeof(HelloWorld::message);
    }

    uint32_t serialized_size(
            const DataType& sample,
            serialization::cdr::XCDRVersion /* xcdr_version */) 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,
            serialization::cdr::XCDRVersion xcdr_version) const noexcept override
    {
        // Do not serialize if size is bigger than buffer capacity
        if (buffer.size() < serialized_size(sample, xcdr_version))
        {
            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, portable::MACHINE_ENDIANNESS,
                serialization::cdr::XCDRVersion::XCDRV1);

        // Serialize a RepresentationHeader
        serialization::RepresentationHeader representation_header{};
        representation_header.init_as_cdr();
        ser.serialize_array(
            representation_header.encapsulation_kind.data(),
            serialization::RepresentationHeader::ENCAPSULATION_KIND_SIZE);
        ser.serialize_array(
            representation_header.encapsulation_options.data(),
            serialization::RepresentationHeader::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, portable::MACHINE_ENDIANNESS,
                serialization::cdr::XCDRVersion::XCDRV1);

        // Deserialize RepresentationHeader
        serialization::RepresentationHeader representation_header{};
        protocol::rtps::RTPSTypeSupport::deserialize(
            representation_header_deser,
            representation_header);

        // Retrieve the payload buffer
        memory::byte_array::ByteArrayView payload_view = {nullptr, 0U};
        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.get_endianness(),
            serialization::cdr::XCDRVersion::XCDRV1);

        // 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;
    }

    dds::ReturnCode get_key(
            const DataType& /* data */,
            dds::KeyHash& key_hash) const noexcept override
    {
        key_hash = dds::KeyHash{};

        return dds::ReturnCode::ILLEGAL_OPERATION;
    }

    dds::ReturnCode get_key_from_payload(
            const memory::IConstByteArrayView& /* view */,
            const protocol::PayloadKind& /* kind */,
            dds::KeyHash& key_hash) const noexcept override
    {
        key_hash = dds::KeyHash{};

        return dds::ReturnCode::ILLEGAL_OPERATION;
    }

};