Dynamic Topic Types¶
eProsima Fast RTPS provides a dynamic way to define and use topic types and topic data. Our implementation follows the OMG Extensible and Dynamic Topic Types for DDS interface. For more information, you can read the document (DDS-XTypes V1.2) in this link.
The dynamic topic types offer the possibility to work over RTPS without the restrictions related to the IDLs. Using them the users can declare the different types that they need and manage the information directly, avoiding the additional step of updating the IDL file and the generation of C++ classes.
The management of dynamic types is split into two main groups. The first one manages the declaration of the types, building and setting the configuration of every type and the second one is in charge of the data instances and their information.
Concepts¶
Type Descriptor
Stores the information about one type with its relationships and restrictions. It’s the minimum class needed to generate a Dynamic type and in case of the complex ones, it stores information about its children or its parent types.
Member Descriptor
Several complex types need member descriptors to declare the relationship between types. This class stores information about that members like their name, their unique ID, the type that is going to be created and the default value after the creation. Union types have special fields to identify each member by labels.
Dynamic Type Builder Factory
Singleton class that is in charge of the creation and the management of every
DynamicTypes
and DynamicTypeBuilders
.
It declares methods to create each kind of supported types, making easier the
management of the descriptors.
Every object created by the factory must be deleted calling the delete_type
method.
Dynamic Type Builder
Intermediate class used to configure and create DynamicTypes
.
By design Dynamic types can’t be modified, so the previous step to create a new one is to create a builder and apply
the settings that the user needs.
Users can create several types using the same builder, but the changes applied
to the builder don’t affect to the types created previously.
Every object created by a builder must be deleted calling the delete_type
method
of the Dynamic Type builder Factory.
Dynamic Type
Base class in the declaration of Dynamic types, it stores the information about its type and every Member that is related to it. It creates a copy of the descriptor on its creation and cannot be changed to keep the consistency.
Dynamic Type Member
A class that creates the relationship between a member descriptor with its parent type. Dynamic Types have a one Dynamic type member for every child member added to it.
Dynamic Data Factory
Singleton class that is in charge of the creation and the management of every
DynamicData
.
It creates them using the given DynamicType
with its settings.
Every data object created by the factory must be deleted calling the delete_type
method.
Allows creating a TypeIdentifier
and a (Minimal and Complete) TypeObject
from a TypeDescriptor
.
Dynamic Data
A class that manages the data of the Dynamic Types. It stores the information that is
sent and received.
There are two ways to work with DynamicDatas, the first one is the
most secured, activating the macro DYNAMIC_TYPES_CHECKING
, it creates a variable for
each primitive kind to help the debug process.
The second one reduces the size of the DynamicData
class using only the minimum
values and making the code harder to debug.
Dynamic PubSubType
A class that inherits from TopicDataType
and works as an intermediary between RTPS Domain and the Dynamic Types.
It implements the methods needed to create, serialize, deserialize and delete DynamicData
instances when the
participants need to convert the received information from any transport to the registered dynamic type.
Supported Types¶
Primitive Types¶
This section includes every simple kind:
BOOLEAN |
INT64 |
BYTE |
UINT16 |
CHAR8 |
UINT32 |
CHAR16 |
UINT64 |
INT16 |
FLOAT32 |
INT32 |
FLOAT64 |
FLOAT128 |
Primitive types don’t need a specific configuration to create the type. Because of that
DynamicTypeBuilderFactory
has got exposed several methods to allow users to create
the Dynamic Types avoiding the DynamicTypeBuilder
step. The example below shows the two
ways to create dynamic data of a primitive type.
The DynamicData
class has a specific get
and set
Methods for each primitive
type of the list.
// Using Builders
DynamicTypeBuilder_ptr created_builder = DynamicTypeBuilderFactory::get_instance()->create_int32_builder();
DynamicType_ptr created_type = DynamicTypeBuilderFactory::get_instance()->create_type(created_builder.get());
DynamicData* data = DynamicDataFactory::get_instance()->create_data(created_type);
data->set_int32_value(1);
// Creating directly the Dynamic Type
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicData* data2 = DynamicDataFactory::get_instance()->create_data(pType);
data2->set_int32_value(1);
String and WString¶
Strings are pretty similar to primitive types with one exception, they need to set the size
of the buffer
that they can manage.
To do that, DynamicTypeBuilderFactory
exposes the methods create_string_type
and create_wstring_type
.
By default, its size is set to 255 characters.
// Using Builders
DynamicTypeBuilder_ptr created_builder = DynamicTypeBuilderFactory::get_instance()->create_string_builder(100);
DynamicType_ptr created_type = DynamicTypeBuilderFactory::get_instance()->create_type(created_builder.get());
DynamicData* data = DynamicDataFactory::get_instance()->create_data(created_type);
data->set_string_value("Dynamic String");
// Creating directly the Dynamic Type
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_string_type(100);
DynamicData* data2 = DynamicDataFactory::get_instance()->create_data(pType);
data2->set_string_value("Dynamic String");
Alias¶
Alias types have been implemented to rename an existing type, keeping the rest of properties
of the given type.
DynamicTypeBuilderFactory
exposes the method create_alias_type
to create alias types
taking the base type and the new name that the alias is going to set.
After the creation of the DynamicData
, users can access its information like
they were working with the base type.
// Using Builders
DynamicTypeBuilder_ptr base_builder = DynamicTypeBuilderFactory::get_instance()->create_string_builder(100);
DynamicType_ptr created_type = DynamicTypeBuilderFactory::get_instance()->create_type(base_builder.get());
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_alias_builder(created_type.get(), "alias");
DynamicData* data = DynamicDataFactory::get_instance()->create_data(builder.get());
data->set_string_value("Dynamic Alias String");
// Creating directly the Dynamic Type
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_string_type(100);
DynamicType_ptr pAliasType = DynamicTypeBuilderFactory::get_instance()->create_alias_type(pType, "alias");
DynamicData* data2 = DynamicDataFactory::get_instance()->create_data(pAliasType);
data2->set_string_value("Dynamic Alias String");
Enumeration¶
The enum type is managed as complex in Dynamic Types because it allows adding members
to set the different values that the enum is going to manage.
Internally, it works with a UINT32
to store what value is selected.
To use enumerations users must create a Dynamic Type builder calling to create_enum_type
and after that, they can call to add_member
given the index and the name of the
different values that the enum is going to support.
The DynamicData class has got methods get_enum_value
and set_enum_value
to work
with UINT32
or with strings using the names of the members added to the builder.
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_enum_builder();
builder->add_empty_member(0, "DEFAULT");
builder->add_empty_member(1, "FIRST");
builder->add_empty_member(2, "SECOND");
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_type(builder.get());
DynamicData* data = DynamicDataFactory::get_instance()->create_data(pType);
std::string sValue = "SECOND";
data->set_enum_value(sValue);
uint32_t uValue = 2;
data->set_enum_value(uValue);
Bitset¶
Bitset types are similar to structure types but their members are only bitfields, which are stored optimally. In the static version of bitsets, each bit uses just one bit in memory (with platform limitations) without alignment considerations. A bitfield can be anonymous (cannot be addressed) to skip unused bits within a bitset. Each bitfield in a bitset can be modified through their minimal needed primitive representation.
Number of bits | Primitive |
1 |
BOOLEAN |
2-8 |
UINT8 |
9-16 |
UINT16 |
17-32 |
UINT32 |
33-64 |
UINT64 |
Each bitfield (or member) works like its primitive type with the only difference that the internal storage only modifies the involved bits instead of the full primitive value.
Bit_bound and position of the bitfield can be set using annotations (useful when converting between static and dynamic bitsets).
// Create bitfields
DynamicTypeBuilder_ptr base_type_builder = DynamicTypeBuilderFactory::get_instance()->create_byte_builder();
auto base_type = base_type_builder->build();
DynamicTypeBuilder_ptr base_type_builder2 = DynamicTypeBuilderFactory::get_instance()->create_uint32_builder();
auto base_type2 = base_type_builder2->build();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_bitset_builder();
builder->add_member(0, "int2", base_type);
builder->add_member(1, "int20", base_type2);
// Apply members' annotations
builder->apply_annotation_to_member(0, ANNOTATION_BIT_BOUND_ID, "value", "2");
builder->apply_annotation_to_member(0, ANNOTATION_POSITION_ID, "value", "0");
builder->apply_annotation_to_member(1, ANNOTATION_BIT_BOUND_ID, "value", "20");
builder->apply_annotation_to_member(1, ANNOTATION_POSITION_ID, "value", "10"); // 8 bits empty
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_type(builder.get());
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(pType);
data->set_byte_value(234, 0);
data->set_uint32_value(2340, 1);
octet bValue;
uint32_t uValue;
data->get_byte_value(bValue, 0);
data->get_uint32_value(uValue, 1);
Bitsets allows inheritance, exactly with the same OOP meaning. To inherit from another bitset, we must create the
bitset calling the create_child_struct_builder
of the factory. This method is shared with structures and will
deduce our type depending on the parent’s type.
DynamicTypeBuilder_ptr child_builder =
DynamicTypeBuilderFactory::get_instance()->create_child_struct_builder(builder.get());
Bitmask¶
Bitmasks are similar to enumeration types, but their members work as bit flags that can be individually turned on and
off. Bit operations can be applied when testing or setting a bitmask value.
DynamicData
has the special methods get_bitmask_value
and set_bitmask_value
which allow to retrieve or
modify the full value instead of accessing each bit.
Bitmasks can be bound to any number of bits up to 64.
uint32_t limit = 5; // Stores as "octet"
// Using Builders
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_bitmask_builder(limit);
builder->add_empty_member(0, "FIRST");
builder->add_empty_member(1, "SECOND");
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_type(builder.get());
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(pType);
data->set_bool_value(true, 2);
bool bValue;
data->get_bool_value(bValue, 0);
uint64_t fullValue;
data->get_bitmask_value(fullValue);
Structure¶
Structures are the common complex types, they allow to add any kind of members inside them. They don’t have any value, they are only used to contain other types.
To manage the types inside the structure, users can call the get
and set
methods
according to the kind of the type inside the structure using their ids
.
If the structure contains a complex value, it should be used with loan_value
to
access to it and return_loaned_value
to release that pointer.
DynamicData
manages the counter of loaned values and users can’t loan a value that
has been loaned previously without calling return_loaned_value
before.
The Ids
must be consecutive starting by zero, and the DynamicType
will change that
Id if it doesn’t match with the next value.
If two members have the same Id, after adding the second one, the previous
will change its id to the next value.
To get the id of a member by name, DynamicData
exposes the method get_member_id_by_name
.
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_struct_builder();
builder->add_member(0, "first", DynamicTypeBuilderFactory::get_instance()->create_int32_type());
builder->add_member(1, "other", DynamicTypeBuilderFactory::get_instance()->create_uint64_type());
DynamicType_ptr struct_type = builder->build();
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(struct_type);
data->set_int32_value(5, 0);
data->set_uint64_value(13, 1);
Structures allow inheritance, exactly with the same OOP meaning. To inherit from another structure, we must create the
structure calling the create_child_struct_builder
of the factory. This method is shared with bitsets and will
deduce our type depending on the parent’s type.
DynamicTypeBuilder_ptr child_builder =
DynamicTypeBuilderFactory::get_instance()->create_child_struct_builder(builder.get());
Union¶
Unions are a special kind of structures where only one of the members is active
at the same time.
To control these members, users must set the discriminator
type that is going to be used
to select the current member calling the create_union_type
method.
After the creation of the Dynamic Type, every member that is going to be added
needs at least one union_case_index
to set how it is going to be selected and
optionally if it is the default value of the union.
DynamicType_ptr discriminator = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_union_builder(discriminator.get());
builder->add_member(0, "first", DynamicTypeBuilderFactory::get_instance()->create_int32_type(), "", { 0 }, true);
builder->add_member(0, "second", DynamicTypeBuilderFactory::get_instance()->create_int64_type(), "", { 1 }, false);
DynamicType_ptr union_type = builder->build();
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(union_type);
data->set_int32_value(9, 0);
data->set_int64_value(13, 1);
uint64_t unionLabel;
data->get_union_label(unionLabel);
Sequence¶
A complex type that manages its members as a list of items allowing users to
insert, remove or access to a member of the list. To create this type users
need to specify the type that it is going to store and optionally the size
limit of the list.
To ease the memory management of this type, DynamicData
has these methods:
- insert_sequence_data
: Creates a new element at the end of the list and returns
the id
of the new element.
- remove_sequence_data
: Removes the element of the given index and refresh the ids
to keep the consistency of the list.
- clear_data
: Removes all the elements of the list.
uint32_t length = 2;
DynamicType_ptr base_type = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_sequence_builder(base_type.get(), length);
DynamicType_ptr sequence_type = builder->build();
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(sequence_type);
MemberId newId, newId2;
data->insert_int32_value(10, newId);
data->insert_int32_value(12, newId2);
data->remove_sequence_data(newId);
Array¶
Arrays are pretty similar to sequences with two main differences. The first one is
that they can have multiple dimensions and the other one is that they don’t need
that the elements are stored consecutively.
The method to create arrays needs a vector of sizes to set how many dimensions are
going to be managed, if users don’t want to set a limit can set the value as zero
on each dimension and it applies the default value ( 100
).
To ease the management of arrays every set
method in DynamicData
class creates
the item if there isn’t any in the given Id
.
Arrays also have methods to handle the creation and deletion of elements like
sequences, they are insert_array_data
, remove_array_data
and clear_data
.
Additionally, there is a special method get_array_index
that returns the position id
giving a vector of indexes on every dimension that the arrays support, that is
useful in multidimensional arrays.
std::vector<uint32_t> lengths = { 2, 2 };
DynamicType_ptr base_type = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_array_builder(base_type.get(), lengths);
DynamicType_ptr array_type = builder->build();
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(array_type);
MemberId pos = data->get_array_index({1, 0});
data->set_int32_value(11, pos);
data->set_int32_value(27, pos + 1);
data->clear_array_data(pos);
Map¶
Maps contain a list of pairs ‘key-value’ types, allowing users to insert, remove or modify the element types of the map. The main difference with sequences is that the map works with pairs of elements and creates copies of the key element to block the access to these elements.
To create a map, users must set the types of the key and the value elements and
optionally the size limit of the map. To add a new element to the map, DynamicData
has the method insert_map_data
that returns the ids of the key and the value
elements inside the map.
To remove an element of the map there is the method remove_map_data
that uses the
given id to find the key element and removes the key and the value elements from the map.
The method clear_data
removes all the elements from the map.
uint32_t length = 2;
DynamicType_ptr base = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_map_builder(base.get(), base.get(), length);
DynamicType_ptr map_type = builder->build();
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(map_type);
DynamicData_ptr key = DynamicDataFactory::get_instance()->create_data(base);
MemberId keyId;
MemberId valueId;
data->insert_map_data(key.get(), keyId, valueId);
MemberId keyId2;
MemberId valueId2;
key->set_int32_value(2);
data->insert_map_data(key.get(), keyId2, valueId2);
data->set_int32_value(53, valueId2);
data->remove_map_data(keyId);
data->remove_map_data(keyId2);
Complex examples¶
Nested structures¶
Structures allow to add other structures inside them, but users must take care that
to access to these members they need to call loan_value
to get a pointer to the
data and release it calling return_loaned_value
.
DynamicDatas
manages the counter of loaned values and users can’t loan a value that
has been loaned previously without calling return_loaned_value
before.
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_struct_builder();
builder->add_member(0, "first", DynamicTypeBuilderFactory::get_instance()->create_int32_type());
builder->add_member(1, "other", DynamicTypeBuilderFactory::get_instance()->create_uint64_type());
DynamicType_ptr struct_type = builder->build();
DynamicTypeBuilder_ptr parent_builder = DynamicTypeBuilderFactory::get_instance()->create_struct_builder();
parent_builder->add_member(0, "child_struct", struct_type);
parent_builder->add_member(1, "second", DynamicTypeBuilderFactory::get_instance()->create_int32_type());
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(parent_builder.get());
DynamicData* child_data = data->loan_value(0);
child_data->set_int32_value(5, 0);
child_data->set_uint64_value(13, 1);
data->return_loaned_value(child_data);
Structures inheritance¶
Structures can inherit from other structures. To do that DynamicTypeBuilderFactory
has the method create_child_struct_type
that relates the given struct type with
the new one. The resultant type contains the members of the base class and the ones
that users have added to it.
Structures support several levels of inheritance, creating recursively the members of all the types in the hierarchy of the struct.
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_struct_builder();
builder->add_member(0, "first", DynamicTypeBuilderFactory::get_instance()->create_int32_type());
builder->add_member(1, "other", DynamicTypeBuilderFactory::get_instance()->create_uint64_type());
DynamicTypeBuilder_ptr child_builder = DynamicTypeBuilderFactory::get_instance()->create_child_struct_builder(builder.get());
builder->add_member(2, "third", DynamicTypeBuilderFactory::get_instance()->create_uint64_type());
DynamicType_ptr struct_type = child_builder->build();
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(struct_type);
data->set_int32_value(5, 0);
data->set_uint64_value(13, 1);
data->set_uint64_value(47, 2);
Alias of an alias¶
Alias types support recursion, so if users need to create an alias of another alias,
it can be done calling create_alias_type
method giving the alias as a base type.
// Using Builders
DynamicTypeBuilder_ptr created_builder = DynamicTypeBuilderFactory::get_instance()->create_string_builder(100);
DynamicType_ptr created_type = DynamicTypeBuilderFactory::get_instance()->create_type(created_builder.get());
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_alias_builder(created_builder.get(), "alias");
DynamicTypeBuilder_ptr builder2 = DynamicTypeBuilderFactory::get_instance()->create_alias_builder(builder.get(), "alias2");
DynamicData* data = DynamicDataFactory::get_instance()->create_data(builder2.get());
data->set_string_value("Dynamic Alias 2 String");
// Creating directly the Dynamic Type
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_string_type(100);
DynamicType_ptr pAliasType = DynamicTypeBuilderFactory::get_instance()->create_alias_type(pType, "alias");
DynamicType_ptr pAliasType2 = DynamicTypeBuilderFactory::get_instance()->create_alias_type(pAliasType, "alias2");
DynamicData* data2 = DynamicDataFactory::get_instance()->create_data(pAliasType);
data2->set_string_value("Dynamic Alias 2 String");
Unions with complex types¶
Unions support complex types, the available interface to access to them is calling
loan_value
to get a pointer to the data and set this field as the active one and
release it calling return_loaned_value
.
DynamicType_ptr discriminator = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::get_instance()->create_union_builder(discriminator.get());
builder->add_member(0, "first", DynamicTypeBuilderFactory::get_instance()->create_int32_type(), "", { 0 }, true);
DynamicTypeBuilder_ptr struct_builder = DynamicTypeBuilderFactory::get_instance()->create_struct_builder();
struct_builder->add_member(0, "first", DynamicTypeBuilderFactory::get_instance()->create_int32_type());
struct_builder->add_member(1, "other", DynamicTypeBuilderFactory::get_instance()->create_uint64_type());
builder->add_member(1, "first", struct_builder.get(), "", { 1 }, false);
DynamicType_ptr union_type = builder->build();
DynamicData_ptr data = DynamicDataFactory::get_instance()->create_data(union_type);
DynamicData* child_data = data->loan_value(1);
child_data->set_int32_value(9, 0);
child_data->set_int64_value(13, 1);
data->return_loaned_value(child_data);
Serialization¶
Dynamic Types have their own pubsub
type like any class generated with an IDL, and
their management is pretty similar to them.
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicPubSubType pubsubType(pType);
// SERIALIZATION EXAMPLE
DynamicData* pData = DynamicDataFactory::get_instance()->create_data(pType);
uint32_t payloadSize = static_cast<uint32_t>(pubsubType.getSerializedSizeProvider(data)());
SerializedPayload_t payload(payloadSize);
pubsubType.serialize(data, &payload);
// DESERIALIZATION EXAMPLE
types::DynamicData* data2 = DynamicDataFactory::get_instance()->create_data(pType);
pubsubType.deserialize(&payload, data2);
Important Notes¶
The most important part of Dynamic Types is memory management because every dynamic type and dynamic data are managed with pointers. Every object stored inside of other dynamic object is managed by its owner, so users only must take care of the objects that they have created calling to the factories. These two factories in charge to manage these objects, and they must create and delete every object.
DynamicTypeBuilder* pBuilder = DynamicTypeBuilderFactory::get_instance()->create_uint32_builder();
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicData* pData = DynamicDataFactory::get_instance()->create_data(pType);
DynamicTypeBuilderFactory::get_instance()->delete_builder(pBuilder);
DynamicDataFactory::get_instance()->delete_data(pData);
To ease this management, the library incorporates a special kind of shared pointers to call
to the factories to delete the object directly ( DynamicTypeBuilder_ptr
and DynamicData_ptr
).
The only restriction on using this kind of pointers are
the methods loan_value
and return_loaned_value
, because they return a pointer
to an object that is already managed by the library and using a DynamicData_ptr
with them will cause a crash.
DynamicType
will always be returned as DynamicType_ptr
because there is no internal management of its memory.
DynamicTypeBuilder_ptr pBuilder = DynamicTypeBuilderFactory::get_instance()->create_uint32_builder();
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicData_ptr pData = DynamicDataFactory::get_instance()->create_data(pType);
Dynamic Types Discovery and Endpoint Matching¶
When using Dynamic Types support, Fast RTPS make use of an optional TopicDiscoveryKind QoS Policy and TypeIdV1
.
At its current state, the matching will only verify that both endpoints are using the same topic type,
but will not negotiate about it.
This verification is done through MinimalTypeObject
.
TopicDiscoveryKind¶
TopicAttribute
to indicate which kind of Dynamic discovery we are using.
Can take 3 different values:
NO_CHECK
: Default value. Will not perform any check for dynamic types.MINIMAL
: Will check only atTypeInformation
level (andMinimalTypeObject
if needed).COMPLETE
: Will perform a full check withCompleteTypeObject
.
TypeObject (TypeObjectV1)¶
There are two kinds of TypeObject
: MinimalTypeObject
and CompleteTypeObject
.
MinimalTypeObject
is used to check compatibility between types.CompleteTypeObject
fully describes the type.
Both are defined in the annexes of DDS-XTypes V1.2 document so its details will not be covered in this document.
TypeObject
is an IDL union with both representation, Minimal and Complete.
TypeIdentifier (TypeIdV1)¶
TypeIdentifier
is described too in the annexes of DDS-XTypes V1.2 document.
It represents a full description of basic types and has an EquivalenceKind
for complex ones.
An EquivalenceKind
is a hash code of 14 octets, as described by the DDS-XTypes V1.2 document.
TypeObjectFactory¶
Singleton class that manages the creation and access for all registered TypeObjects
and TypeIdentifiers
.
From a basic TypeIdentifier
(in other words, a TypeIdentifier
whose discriminator isn’t
EK_MINIMAL
or EK_COMPLETE
) can generate a full DynamicType
.
Fastrtpsgen¶
FastRTPSGen has been upgraded to generate XXXTypeObject.h
and XXXTypeObject.cxx
files,
taking XXX
as our IDL type. These files provide a small Type Factory for the type XXX
.
Generally, these files are not used directly, as now the type XXX
will register itself through its factory to
TypeObjectFactory
in its constructor, making very easy the use of static types with dynamic types.
XML Dynamic Types¶
XML Dynamic Types allows eProsima Fast RTPS to create Dynamic Types directly defining them through XML.
This allows any application to change TopicDataTypes
without the need to change its source code.