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 DeleteType
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 DeleteType
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 DeleteType
method.
Allows creating a TypeIdentifier
and a (Minimal)``TypeObject`` from a TypeDescriptor
.
CompleteTypeObject
support is planned to be added in the future.
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::GetInstance()->CreateInt32Builder();
DynamicType_ptr created_type = DynamicTypeBuilderFactory::GetInstance()->CreateType(created_builder.get());
DynamicData* data = DynamicDataFactory::GetInstance()->CreateData(created_type);
data->SetInt32Value(1);
// Creating directly the Dynamic Type
DynamicType_ptr pType = DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type();
DynamicData* data2 = DynamicDataFactory::GetInstance()->CreateData(pType);
data2->SetInt32Value(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 CreateStringType
and CreateWstringType
.
By default, its size is set to 255 characters.
// Using Builders
DynamicTypeBuilder_ptr created_builder = DynamicTypeBuilderFactory::GetInstance()->CreateStringBuilder(100);
DynamicType_ptr created_type = DynamicTypeBuilderFactory::GetInstance()->CreateType(created_builder.get());
DynamicData* data = DynamicDataFactory::GetInstance()->CreateData(created_type);
data->SetStringValue("Dynamic String");
// Creating directly the Dynamic Type
DynamicType_ptr pType = DynamicTypeBuilderFactory::GetInstance()->CreateStringType(100);
DynamicData* data2 = DynamicDataFactory::GetInstance()->CreateData(pType);
data2->SetStringValue("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 CreateAliasType
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::GetInstance()->CreateStringBuilder(100);
DynamicType_ptr created_type = DynamicTypeBuilderFactory::GetInstance()->CreateType(base_builder.get());
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateAliasBuilder(created_type.get(), "alias");
DynamicData* data = DynamicDataFactory::GetInstance()->CreateData(builder.get());
data->SetStringValue("Dynamic Alias String");
// Creating directly the Dynamic Type
DynamicType_ptr pType = DynamicTypeBuilderFactory::GetInstance()->CreateStringType(100);
DynamicType_ptr pAliasType = DynamicTypeBuilderFactory::GetInstance()->CreateAliasType(pType, "alias");
DynamicData* data2 = DynamicDataFactory::GetInstance()->CreateData(pAliasType);
data2->SetStringValue("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 CreateEnumType
and after that, they can call to AddMember
given the index and the name of the
different values that the enum is going to support.
The DynamicData class has got methods GetEnumValue
and SetEnumValue
to work
with UINT32
or with strings using the names of the members added to the builder.
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateEnumBuilder();
builder->AddEmptyMember(0, "DEFAULT");
builder->AddEmptyMember(1, "FIRST");
builder->AddEmptyMember(2, "SECOND");
DynamicType_ptr pType = DynamicTypeBuilderFactory::GetInstance()->CreateType(builder.get());
DynamicData* data = DynamicDataFactory::GetInstance()->CreateData(pType);
std::string sValue = "SECOND";
data->SetEnumValue(sValue);
uint32_t uValue = 2;
data->SetEnumValue(uValue);
Bitset¶
Bitset types emulate a list of boolean values but optimized for space allocation
using each bit for a different value.
They work like a boolean
type with the only difference that the GetBoolValue
and
SetBoolValue
need the index of the bit that users want to read or write.
DynamicTypeBuilderFactory
offers the possibility to set the maximum value that the bitset
is going to manage, but it should be less or equal to 64 bits.
uint32_t limit = 5;
// Using Builders
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateBitsetBuilder(limit);
DynamicType_ptr pType = DynamicTypeBuilderFactory::GetInstance()->CreateType(builder.get());
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(pType);
data->SetBoolValue(true, 2);
bool bValue;
data->GetBoolValue(bValue, 0);
// Creating directly the Dynamic Type
DynamicType_ptr pType2 = DynamicTypeBuilderFactory::GetInstance()->CreateBitsetType(limit);
DynamicData_ptr data2 = DynamicDataFactory::GetInstance()->CreateData(pType);
data2->SetBoolValue(true, 2);
bool bValue2;
data2->GetBoolValue(bValue2, 0);
Bitmask¶
Bitmasks are the complex way to work with bitsets because they open the option to
add members and access to each boolean value with the name of the member.
DynamicData
has the special methods GetBitmaskValue
and SetBitmaskValue
using the name of the member, but they can be used like bitsets too.
uint32_t limit = 5;
// Using Builders
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateBitmaskBuilder(limit);
builder->AddEmptyMember(0, "FIRST");
builder->AddEmptyMember(1, "SECOND");
DynamicType_ptr pType = DynamicTypeBuilderFactory::GetInstance()->CreateType(builder.get());
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(pType);
data->SetBoolValue(true, 2);
bool bValue;
data->GetBoolValue(bValue, 0);
bValue = data->GetBitmaskValue("FIRST");
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 LoanValue
to
access to it and ReturnLoanedValue
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 ReturnLoanedValue
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 GetMemberIdByName
.
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateStructBuilder();
builder->AddMember(0, "first", DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type());
builder->AddMember(1, "other", DynamicTypeBuilderFactory::GetInstance()->CreateUint64Type());
DynamicType_ptr struct_type = builder->Build();
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(struct_type);
data->SetInt32Value(5, 0);
data->SetUint64Value(13, 1);
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 CreateUnionType
method.
After the creation of the Dynamic Type, every member that is going to be added
needs at least one UnionCaseIndex
to set how it is going to be selected and
optionally if it is the default value of the union.
DynamicType_ptr discriminator = DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateUnionBuilder(discriminator.get());
builder->AddMember(0, "first", DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type(), "", { 0 }, true);
builder->AddMember(0, "second", DynamicTypeBuilderFactory::GetInstance()->CreateInt64Type(), "", { 1 }, false);
DynamicType_ptr union_type = builder->Build();
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(union_type);
data->SetInt32Value(9, 0);
data->SetInt64Value(13, 1);
uint64_t unionLabel;
data->GetUnionLabel(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:
- InsertSequenceData
: Creates a new element at the end of the list and returns
the id
of the new element.
- RemoveSequenceData
: Removes the element of the given index and refresh the ids
to keep the consistency of the list.
- ClearData
: Removes all the elements of the list.
uint32_t length = 2;
DynamicType_ptr base_type = DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateSequenceBuilder(base_type.get(), length);
DynamicType_ptr sequence_type = builder->Build();
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(sequence_type);
MemberId newId, newId2;
data->InsertInt32Value(10, newId);
data->InsertInt32Value(12, newId2);
data->RemoveSequenceData(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 InsertArrayData
, RemoveArrayData
and ClearData
.
Additionally, there is a special method GetArrayIndex
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::GetInstance()->CreateInt32Type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateArrayBuilder(base_type.get(), lengths);
DynamicType_ptr array_type = builder->Build();
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(array_type);
MemberId pos = data->GetArrayIndex({1, 0});
data->SetInt32Value(11, pos);
data->SetInt32Value(27, pos + 1);
data->ClearArrayData(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 InsertMapData
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 RemoveMapData
that uses the
given id to find the key element and removes the key and the value elements from the map.
The method ClearData
removes all the elements from the map.
uint32_t length = 2;
DynamicType_ptr base = DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateMapBuilder(base.get(), base.get(), length);
DynamicType_ptr map_type = builder->Build();
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(map_type);
DynamicData_ptr key = DynamicDataFactory::GetInstance()->CreateData(base);
MemberId keyId;
MemberId valueId;
data->InsertMapData(key.get(), keyId, valueId);
MemberId keyId2;
MemberId valueId2;
key->SetInt32Value(2);
data->InsertMapData(key.get(), keyId2, valueId2);
data->SetInt32Value(53, valueId2);
data->RemoveMapData(keyId);
data->RemoveMapData(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 LoanValue
to get a pointer to the
data and release it calling ReturnLoanedValue
.
DynamicDatas
manages the counter of loaned values and users can’t loan a value that
has been loaned previously without calling ReturnLoanedValue
before.
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateStructBuilder();
builder->AddMember(0, "first", DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type());
builder->AddMember(1, "other", DynamicTypeBuilderFactory::GetInstance()->CreateUint64Type());
DynamicType_ptr struct_type = builder->Build();
DynamicTypeBuilder_ptr parent_builder = DynamicTypeBuilderFactory::GetInstance()->CreateStructBuilder();
parent_builder->AddMember(0, "child_struct", struct_type);
parent_builder->AddMember(1, "second", DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type());
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(parent_builder.get());
DynamicData* child_data = data->LoanValue(0);
child_data->SetInt32Value(5, 0);
child_data->SetUint64Value(13, 1);
data->ReturnLoanedValue(child_data);
Structures inheritance¶
Structures can inherit from other structures. To do that DynamicTypeBuilderFactory
has the method CreateChildStructType
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::GetInstance()->CreateStructBuilder();
builder->AddMember(0, "first", DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type());
builder->AddMember(1, "other", DynamicTypeBuilderFactory::GetInstance()->CreateUint64Type());
DynamicTypeBuilder_ptr child_builder = DynamicTypeBuilderFactory::GetInstance()->CreateChildStructBuilder(builder.get());
builder->AddMember(2, "third", DynamicTypeBuilderFactory::GetInstance()->CreateUint64Type());
DynamicType_ptr struct_type = child_builder->Build();
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(struct_type);
data->SetInt32Value(5, 0);
data->SetUint64Value(13, 1);
data->SetUint64Value(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 CreateAliasType
method giving the alias as a base type.
// Using Builders
DynamicTypeBuilder_ptr created_builder = DynamicTypeBuilderFactory::GetInstance()->CreateStringBuilder(100);
DynamicType_ptr created_type = DynamicTypeBuilderFactory::GetInstance()->CreateType(created_builder.get());
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateAliasBuilder(created_builder.get(), "alias");
DynamicTypeBuilder_ptr builder2 = DynamicTypeBuilderFactory::GetInstance()->CreateAliasBuilder(builder.get(), "alias2");
DynamicData* data = DynamicDataFactory::GetInstance()->CreateData(builder2.get());
data->SetStringValue("Dynamic Alias 2 String");
// Creating directly the Dynamic Type
DynamicType_ptr pType = DynamicTypeBuilderFactory::GetInstance()->CreateStringType(100);
DynamicType_ptr pAliasType = DynamicTypeBuilderFactory::GetInstance()->CreateAliasType(pType, "alias");
DynamicType_ptr pAliasType2 = DynamicTypeBuilderFactory::GetInstance()->CreateAliasType(pAliasType, "alias2");
DynamicData* data2 = DynamicDataFactory::GetInstance()->CreateData(pAliasType);
data2->SetStringValue("Dynamic Alias 2 String");
Unions with complex types¶
Unions support complex types, the available interface to access to them is calling
LoanValue
to get a pointer to the data and set this field as the active one and
release it calling ReturnLoanedValue
.
DynamicType_ptr discriminator = DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type();
DynamicTypeBuilder_ptr builder = DynamicTypeBuilderFactory::GetInstance()->CreateUnionBuilder(discriminator.get());
builder->AddMember(0, "first", DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type(), "", { 0 }, true);
DynamicTypeBuilder_ptr struct_builder = DynamicTypeBuilderFactory::GetInstance()->CreateStructBuilder();
struct_builder->AddMember(0, "first", DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type());
struct_builder->AddMember(1, "other", DynamicTypeBuilderFactory::GetInstance()->CreateUint64Type());
builder->AddMember(1, "first", struct_builder.get(), "", { 1 }, false);
DynamicType_ptr union_type = builder->Build();
DynamicData_ptr data = DynamicDataFactory::GetInstance()->CreateData(union_type);
DynamicData* child_data = data->LoanValue(1);
child_data->SetInt32Value(9, 0);
child_data->SetInt64Value(13, 1);
data->ReturnLoanedValue(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::GetInstance()->CreateInt32Type();
DynamicPubSubType pubsubType(pType);
// SERIALIZATION EXAMPLE
DynamicData* pData = DynamicDataFactory::GetInstance()->CreateData(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::GetInstance()->CreateData(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::GetInstance()->CreateUint32Builder();
DynamicType_ptr pType = DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type();
DynamicData* pData = DynamicDataFactory::GetInstance()->CreateData(pType);
DynamicTypeBuilderFactory::GetInstance()->DeleteBuilder(pBuilder);
DynamicDataFactory::GetInstance()->DeleteData(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 LoanValue
and ReturnLoanedValue
, 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::GetInstance()->CreateUint32Builder();
DynamicType_ptr pType = DynamicTypeBuilderFactory::GetInstance()->CreateInt32Type();
DynamicData_ptr pData = DynamicDataFactory::GetInstance()->CreateData(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.