10.10. Dynamic Types profiles

Fast DDS supports the implementation of DynamicType by defining them through XML files. Thus the Dynamic Types can be modified without the need to modify the source code of the DDS application.

10.10.1. XML Structure

The definition of type profiles in the XML file is done with the <types> tag. Each <types> element can contain one or more Type definitions. Defining several types within a <types> element or a single type for each <types> element has the same result. Below, an example of a stand-alone types definition via XML is shown.

<types xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <type>
        <!-- Type definition -->
    </type>
    <type>
        <!-- Type definition -->
        <!-- Type definition -->
    </type>
</types>

Note

For more information on the difference between stand-alone and rooted definitions please refer to section Rooted vs Standalone profiles definition.

10.10.2. Type definition

Below, the types supported by Fast DDS are presented . For further information about the supported DynamicType, please, refer to Supported Types. For each of the types detailed below, an example of how to build the type’s XML profile is provided.

10.10.2.1. Member types

Member types are defined as any type that can belong to a Struct or a Union, or be aliased by a Typedef. These can be defined by the <member> XML tag.

10.10.2.1.1. Primitive types

The identifiers of the available basic types are listed in the table below. Please, refer to Primitive Types for more information on the primitive types.

boolean

char8

char16

byte

octet

uint8

int8

int16

int32

uint16

uint32

int64

uint64

float32

float64

float128

string

wstring

All of them are defined as follows:

<struct name="primitive_types_example">
    <!-- Primitive type definitions inside a struct -->
    <member name="my_bool" type="boolean"/>
    <member name="my_char" type="char8"/>
    <member name="my_wchar" type="char16"/>
    <member name="my_byte" type="byte"/>
    <member name="my_octet" type="octet"/>
    <member name="my_uint8" type="uint8"/>
    <member name="my_short" type="int16"/>
    <member name="my_long" type="int32"/>
    <member name="my_unsignedshort" type="uint16"/>
    <member name="my_unsignedlong" type="uint32"/>
    <member name="my_longlong" type="int64"/>
    <member name="my_unsignedlonglong" type="uint64"/>
    <member name="my_float" type="float32"/>
    <member name="my_double" type="float64"/>
    <member name="my_longdouble" type="float128"/>
    <member name="my_string" type="string"/>
    <member name="my_wstring" type="wstring"/>
</struct>

10.10.2.1.2. Bounded strings

Bounded strings are defined as any other string or wstring but adding the attribute stringMaxLength with the maximum length available for that specific string. Please, refer to String and WString for more information on string type.

<member name="my_large_string" type="string" stringMaxLength="41925"/>
<member name="my_large_wstring" type="wstring" stringMaxLength="20925"/>

10.10.2.1.3. Sequences

The sequence type is implemented by setting three attributes: name, type, and the sequenceMaxLength. The type of its content should be defined by the type attribute. Please, refer to Sequence section for more information on sequence type.

<member name="short_sequence" sequenceMaxLength="5" type="int16"/>

10.10.2.1.4. Arrays

Arrays are defined in the same way as any other member type but they add the attribute arrayDimensions. The format of the arrayDimensions attribute value is the size of each dimension separated by commas. Please, refer to Array explanation for more information on array type.

<member name="long_array" type="int32" arrayDimensions="2,3,4"/>

10.10.2.1.5. Maps

Maps are similar to sequences, but they need to define two content types. The key_type defines the type of the map key, while the type defines the map value type. See section Map for more information on map type.

<member name="long_long_map" type="int32" key_type="int32" mapMaxLength="2"/>

10.10.2.2. Complex types

The complex types are a combination of the aforementioned types. Complex types can be defined using the <member> element in the same way a basic or an array type would be. The type in this case is nonBasic (not a Primitive types) and the name of the previously defined type is given in the nonBasicTypeName attribute. Please, refer to Complex Types section for more information on complex types.

The following example shows a new structure with the primitive_types_example struct defined in Primitive types example.

<struct name="ComplexTypeStruct">
    <member name="my_complex_struct" type="nonBasic" nonBasicTypeName="primitive_types_example" arrayDimensions="5"/>
</struct>

10.10.2.2.1. Complex types attributes

The attributes of a complex type element can be highly varied depending on the type being defined. Since the attributes that can be defined for each of the types have already been listed, these attributes are then defined in the following table.

Name

Description

type

Data type. This can be a Primitive types or a nonBasic type.
The latter is used to denote that a complex type is defined.

nonBasicTypeName

Name of the complex type. Only applies if the type attribute is set to nonBasic.

stringMaxLength

Maximum length of a string.

sequenceMaxLength

Maximum length of a Sequences.

arrayDimensions

Dimensions of an array.

key_type

Data type of a map key.

mapMaxLength

Maximum length of a Maps.

10.10.2.3. Typedef

The <typedef> XML element is defined by a name and a type mandatory attributes, and any of the optional attributes presented in Complex types attributes section. This element allows for defining complex types without the need to define them previously as members. Maps, arrays and sequences can be elements within another container using <typedef>. The <typedef> element corresponds to Alias in Supported Types section.

<typedef name="MyAliasEnum" type="nonBasic" nonBasicTypeName="MyEnum"/>
<typedef name="MyAliasArray" type="int32" arrayDimensions="2,2"/>
<!--Complex map-->
<typedef name="my_map_inner" type="int32" key_type="int32"/>
<struct name="StructComplexMap">
    <member name="my_complex_map" type="nonBasic" nonBasicTypeName="my_map_inner" key_type="int32" mapMaxLength="2"/>
</struct>
<!--Complex sequence-->
<typedef name="long_sequence" sequenceMaxLength="10" type="int32"/>
<struct name="StructComplexSequence">
    <member name="my_sequence_sequence" type="nonBasic" nonBasicTypeName="long_sequence" sequenceMaxLength="3"/>
</struct>

10.10.2.4. Enumerations

The <enum> type is defined by its attribute name and a set of <enumerator> child elements. Each <enumerator> is defined by two attributes: a mandatory name and an optional unsigned integer value. Please, refer to Enumeration for more information on the <enum> type.

<enum name="MyEnum">
    <enumerator name="A" value="0"/>
    <enumerator name="B" value="1"/>
    <enumerator name="C"/>
</enum>

10.10.2.5. Struct

The <struct> element is defined by its name attribute and its <member> child elements. Please, refer to Structure for more information on the <struct> type.

<struct name="MyStruct">
    <member name="first" type="int32"/>
    <member name="second" type="int64"/>
</struct>

Structs can inherit from another struct. This is implemented by defining the value of the baseType attribute, on the child <struct> element to be the value of the name attribute of the parent <struct> element. This is exemplified by the code snippet below.

<struct name="ParentStruct">
    <member name="first" type="int32"/>
    <member name="second" type="int64"/>
</struct>
<struct name="ChildStruct" baseType="ParentStruct">
    <member name="third" type="int32"/>
    <member name="fourth" type="int64"/>
</struct>

10.10.2.6. Union

The <union> type is defined by a name attribute, a <discriminator> child element and a set of <case> child elements. The <discriminator> must define its type Each <case> element has one or more <caseDiscriminator> elements, which type must be consistent with the <discriminator> type, and a unique <member> element. Please, refer to Union for more information on the <union> type.

<union name="MyUnion">
    <discriminator type="byte"/>
    <case>
        <caseDiscriminator value="0"/>
        <caseDiscriminator value="1"/>
        <member name="first" type="int32"/>
    </case>
    <case>
        <caseDiscriminator value="2"/>
        <member name="second" type="nonBasic" nonBasicTypeName="MyStruct"/>
    </case>
    <case>
        <caseDiscriminator value="default"/>
        <member name="third" type="nonBasic" nonBasicTypeName="int64"/>
    </case>
</union>

10.10.2.7. Bitset

The <bitset> element defines the Bitset type. It is comprised by a name attribute and a set of <bitfield> child elements. In turn, the <bitfield> element has the mandatory bit_bound attribute, which cannot be higher than 64, and two optional attributes: name and type. A <bitfield> without name attribute is an inaccessible set of bits. Its management type can ease the <bitfield> modification and access. Please, refer to Bitset for more information about the <bitset> type.

<bitset name="MyBitSet">
    <bitfield name="a" bit_bound="3"/>
    <bitfield name="b" bit_bound="1"/>
    <bitfield bit_bound="4"/>
    <bitfield name="c" bit_bound="10"/>
    <bitfield name="d" bit_bound="12" type="int16"/>
</bitset>

Moreover, bitsets can inherit from another bitsets:

<bitset name="ParentBitSet">
    <bitfield name="a" bit_bound="10"/>
    <bitfield name="b" bit_bound="15"/>
</bitset>

<bitset name="ChildBitSet" baseType="ParentBitSet">
    <bitfield bit_bound="1"/>
    <bitfield bit_bound="5" type="uint16"/>
</bitset>

10.10.2.8. Bitmask

The <bitmask> element, which corresponds to the Bitmask type, is defined by a mandatory name attribute, an optional bit_bound attribute, and several <bit_value> child elements. The bit_bound attribute specifies the number of bits that the bitmask type will manage. The maximum value allowed for the bit_bound is 64. The <bit_value> element must define the name attribute and it might define its position in the bitmask setting the positition attribute. Please, refer to Bitmask for more information on the <bitmask> type.

<bitmask name="MyBitMask" bit_bound="8">
    <bit_value name="flag0" position="0"/>
    <bit_value name="flag1"/>
    <bit_value name="flag2" position="2"/>
    <bit_value name="flag5" position="5"/>
</bitmask>

10.10.3. Loading dynamic types in a Fast DDS application

In the Fast DDS application that will make use of the XML Types, the XML files that define the types must be loaded before trying to instantiate DynamicPubSubType objects of these types.

// Create a DomainParticipant
DomainParticipant* participant =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == participant)
{
    // Error
    return;
}

// Load the XML File
if (ReturnCode_t::RETCODE_OK ==
        DomainParticipantFactory::get_instance()->load_XML_profiles_file("my_profiles.xml"))
{
    // Retrieve the an instance of MyStruct type
    eprosima::fastrtps::types::DynamicType_ptr my_struct_type =
            eprosima::fastrtps::xmlparser::XMLProfileManager::getDynamicTypeByName("MyStruct")->build();
    // Register MyStruct type
    TypeSupport my_struct_type_support(new eprosima::fastrtps::types::DynamicPubSubType(my_struct_type));
    my_struct_type_support.register_type(participant, nullptr);
}
else
{
    std::cout << "Cannot open XML file \"types.xml\". "
              << "Please, set the correct path to the XML file"
              << std::endl;
}