File type_object.hpp
File List > astutedds > xtypes > type_object.hpp
Go to the documentation of this file
//
// Copyright (c) 2026, Astute Systems PTY LTD
//
// This file is part of the Astute DDS developed by Astute Systems.
//
// See the commercial LICENSE file in the project root for full license details.
//
// @file type_object.hpp
// @brief DDS X-Types TypeObject and TypeIdentifier
//
// Implements the type system from DDS-XTypes 1.3 specification.
// Reference: https://www.omg.org/spec/DDS-XTypes/1.3/PDF
//
#ifndef ASTUTEDDS_XTYPES_TYPE_OBJECT_HPP
#define ASTUTEDDS_XTYPES_TYPE_OBJECT_HPP
#include <astutedds/cdr/cdr_types.hpp>
#include <array>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <variant>
#include <vector>
namespace astutedds::xtypes
{
// Type Kind (7.2.2.1)
enum class TypeKind : uint8_t
{
TK_NONE = 0x00,
TK_BOOLEAN = 0x01,
TK_BYTE = 0x02,
TK_INT16 = 0x03,
TK_INT32 = 0x04,
TK_INT64 = 0x05,
TK_UINT16 = 0x06,
TK_UINT32 = 0x07,
TK_UINT64 = 0x08,
TK_FLOAT32 = 0x09,
TK_FLOAT64 = 0x0a,
TK_FLOAT128 = 0x0b,
TK_INT8 = 0x0c,
TK_UINT8 = 0x0d,
TK_CHAR8 = 0x10,
TK_CHAR16 = 0x11,
TK_STRING8 = 0x20,
TK_STRING16 = 0x21,
TK_ALIAS = 0x30,
TK_ENUM = 0x31,
TK_BITMASK = 0x32,
TK_ANNOTATION = 0x33,
TK_STRUCTURE = 0x34,
TK_UNION = 0x35,
TK_BITSET = 0x36,
TK_SEQUENCE = 0x40,
TK_ARRAY = 0x41,
TK_MAP = 0x42
};
// Equivalence Hash (7.3.4.9)
using EquivalenceHash = std::array<uint8_t, 14>;
// Type Identifier discriminator (7.3.4.5.1)
enum class TypeIdKind : uint8_t
{
TI_STRING8_SMALL = 0x70,
TI_STRING8_LARGE = 0x71,
TI_STRING16_SMALL = 0x72,
TI_STRING16_LARGE = 0x73,
TI_PLAIN_SEQUENCE_SMALL = 0x74,
TI_PLAIN_SEQUENCE_LARGE = 0x75,
TI_PLAIN_ARRAY_SMALL = 0x76,
TI_PLAIN_ARRAY_LARGE = 0x77,
TI_PLAIN_MAP_SMALL = 0x78,
TI_PLAIN_MAP_LARGE = 0x79,
TI_STRONGLY_CONNECTED_COMPONENT = 0x7a,
EK_COMPLETE = 0x7b,
EK_MINIMAL = 0x7c
};
// Forward declarations
struct TypeIdentifier;
// String Type Identifier (7.3.4.5.2)
struct StringSTypeDefn
{
uint8_t bound{0}; // 0 = unbounded
};
struct StringLTypeDefn
{
uint32_t bound{0}; // 0 = unbounded
};
// Sequence Type Identifier (7.3.4.5.3)
//
// element_identifier is a shared_ptr (rather than an owning raw pointer) so
// that the compiler-generated copy/move/destructor for this struct (and for
// the std::variant in TypeIdentifier that holds it) correctly manage the
// lifetime of the heap-allocated element type. A raw owning pointer here
// previously leaked on every copy/destruction since nothing ever called
// delete on it (see create_sequence_type_identifier()/create_array_type_identifier()).
struct PlainSequenceSElemDefn
{
uint8_t bound{0};
std::shared_ptr<TypeIdentifier> element_identifier;
};
struct PlainSequenceLElemDefn
{
uint32_t bound{0};
std::shared_ptr<TypeIdentifier> element_identifier;
};
// Array Type Identifier (7.3.4.5.4)
struct PlainArraySElemDefn
{
std::vector<uint8_t> array_bound_seq;
std::shared_ptr<TypeIdentifier> element_identifier;
};
struct PlainArrayLElemDefn
{
std::vector<uint32_t> array_bound_seq;
std::shared_ptr<TypeIdentifier> element_identifier;
};
// Map Type Identifier (7.3.4.5.5)
struct PlainMapSTypeDefn
{
uint8_t bound{0};
std::shared_ptr<TypeIdentifier> key_identifier;
std::shared_ptr<TypeIdentifier> element_identifier;
};
struct PlainMapLTypeDefn
{
uint32_t bound{0};
std::shared_ptr<TypeIdentifier> key_identifier;
std::shared_ptr<TypeIdentifier> element_identifier;
};
// Strongly-Connected Component identifier (7.3.4.9.3) — identifies the set of
// mutually-dependent types (a "SCC") that a recursive/cyclic TypeIdentifier
// belongs to. `sc_component_id` is the EquivalenceHash of the serialized
// TypeObjectSeq for the whole component (discriminator is always EK_MINIMAL or
// EK_COMPLETE); `scc_length` is the number of types in the component.
struct StronglyConnectedComponentId
{
TypeIdKind discriminator{TypeIdKind::EK_MINIMAL};
EquivalenceHash sc_component_id{};
uint32_t scc_length{0};
};
// Strongly-Connected Component TypeIdentifier payload (7.3.4.6.4) — identifies
// one specific type (`scc_index`, 1-based) within a strongly-connected
// component. An `scc_index` of 0 denotes the abstract SCCIdentifier itself
// (a reference to the whole component rather than one member type).
struct SCCTypeIdentifierDefn
{
StronglyConnectedComponentId component_id;
uint32_t scc_index{0};
};
// Type Identifier (7.3.4.5)
struct TypeIdentifier
{
using VariantType =
std::variant<std::monostate, // TK_NONE or primitive types
StringSTypeDefn, StringLTypeDefn, PlainSequenceSElemDefn, PlainSequenceLElemDefn,
PlainArraySElemDefn, PlainArrayLElemDefn, PlainMapSTypeDefn, PlainMapLTypeDefn, EquivalenceHash,
SCCTypeIdentifierDefn>;
TypeIdKind discriminator{TypeIdKind::EK_MINIMAL};
VariantType value;
};
// Member Flags (7.3.1.2.1.4)
struct MemberFlag
{
static constexpr uint16_t TRY_CONSTRUCT_DISCARD = 0x0001;
static constexpr uint16_t TRY_CONSTRUCT_USE_DEFAULT = 0x0002;
static constexpr uint16_t IS_EXTERNAL = 0x0004;
static constexpr uint16_t IS_OPTIONAL = 0x0008;
static constexpr uint16_t IS_MUST_UNDERSTAND = 0x0010;
static constexpr uint16_t IS_KEY = 0x0020;
static constexpr uint16_t IS_DEFAULT = 0x0040;
};
// Common Structure Member (7.3.1.2.1)
struct CommonStructMember
{
uint32_t member_id{0};
uint16_t member_flags{0};
TypeIdentifier member_type_id;
};
// Complete Structure Member (7.3.1.2.2)
struct CompleteStructMember
{
CommonStructMember common;
std::string name;
std::vector<std::string> annotations; // Simplified
};
// Minimal Structure Member (7.3.1.2.3)
struct MinimalStructMember
{
CommonStructMember common;
uint32_t name_hash{0}; // Hash of the member name
};
// Structure Type (7.3.1.2.4)
//
// `base_type` records single-inheritance aggregate types (§7.2.2.4.5, "struct
// Derived : Base { ... }"). Unset (std::nullopt) means the struct has no base
// type, matching the spec's "+base_type 0..1" optional association.
struct CompleteStructType
{
cdr::ExtensibilityKind extensibility{cdr::ExtensibilityKind::FINAL};
std::vector<CompleteStructMember> members;
std::string name;
std::optional<TypeIdentifier> base_type;
};
struct MinimalStructType
{
cdr::ExtensibilityKind extensibility{cdr::ExtensibilityKind::FINAL};
std::vector<MinimalStructMember> members;
std::optional<TypeIdentifier> base_type;
};
// Union Case Label Sequence (7.3.1.2.1) — discriminator values selecting a member.
// An empty sequence combined with MemberFlag::IS_DEFAULT denotes the default case.
using UnionCaseLabelSeq = std::vector<int32_t>;
// Common Union Member (7.3.1.2.1)
struct CommonUnionMember
{
uint32_t member_id{0};
uint16_t member_flags{0};
TypeIdentifier member_type_id;
UnionCaseLabelSeq label_seq;
};
// Complete Union Member (7.3.1.2.2)
struct CompleteUnionMember
{
CommonUnionMember common;
std::string name;
std::vector<std::string> annotations; // Simplified
};
// Minimal Union Member (7.3.1.2.3)
struct MinimalUnionMember
{
CommonUnionMember common;
uint32_t name_hash{0}; // Hash of the member name
};
// Common Discriminator Member (7.3.1.2.1) — the union's `switch` type and its flags.
// IS_MUST_UNDERSTAND is implicit for discriminators per the spec; IS_KEY and the
// TRY_CONSTRUCT_* bits are the only flags that apply here.
struct CommonDiscriminatorMember
{
uint16_t member_flags{0};
TypeIdentifier type_id;
};
// Union Type (7.3.1.2.4)
struct CompleteUnionType
{
cdr::ExtensibilityKind extensibility{cdr::ExtensibilityKind::FINAL};
CommonDiscriminatorMember discriminator;
std::vector<CompleteUnionMember> members;
std::string name;
};
struct MinimalUnionType
{
cdr::ExtensibilityKind extensibility{cdr::ExtensibilityKind::FINAL};
CommonDiscriminatorMember discriminator;
std::vector<MinimalUnionMember> members;
};
// Enum Literal (7.3.1.3.1)
struct CommonEnumeratedLiteral
{
int32_t value{0};
uint16_t flags{0};
};
struct CompleteEnumeratedLiteral
{
CommonEnumeratedLiteral common;
std::string name;
};
struct MinimalEnumeratedLiteral
{
CommonEnumeratedLiteral common;
uint32_t name_hash{0};
};
// Enum Type (7.3.1.3.2)
struct CompleteEnumeratedType
{
uint16_t bit_bound{32}; // Number of bits used
std::vector<CompleteEnumeratedLiteral> literals;
std::string name;
};
struct MinimalEnumeratedType
{
uint16_t bit_bound{32};
std::vector<MinimalEnumeratedLiteral> literals;
};
// Common Bitflag (7.3.1.4.1) — a single named bit position within a bitmask.
struct CommonBitflag
{
uint16_t position{0};
uint16_t flags{0};
};
// Complete Bitflag (7.3.1.4.2)
struct CompleteBitflag
{
CommonBitflag common;
std::string name;
std::vector<std::string> annotations; // Simplified
};
// Minimal Bitflag (7.3.1.4.3)
struct MinimalBitflag
{
CommonBitflag common;
uint32_t name_hash{0}; // Hash of the flag name
};
// Bitmask Type (7.3.1.4.4) — ordered by CommonBitflag::position per spec.
// `bit_bound` selects the underlying storage width (8/16/32/64), driven by the
// IDL `@bit_bound(N)` annotation (defaults to 32 when unspecified, matching the
// enum convention above).
struct CompleteBitmaskType
{
uint16_t bit_bound{32};
std::vector<CompleteBitflag> flags;
std::string name;
};
struct MinimalBitmaskType
{
uint16_t bit_bound{32};
std::vector<MinimalBitflag> flags;
};
// Alias Type (7.2.2.4.2, TK_ALIAS) — represents an IDL `typedef` as a distinct
// TypeObject rather than collapsing it into the underlying type at parse time,
// so that typedef-heavy IDL keeps a stable TypeIdentifier hash and can be
// checked for assignability against the aliased type (§7.2.4.4.3).
struct CompleteAliasType
{
TypeIdentifier related_type;
std::string name;
};
struct MinimalAliasType
{
TypeIdentifier related_type;
};
// Type Object (7.3.4.2)
struct CompleteTypeObject
{
using VariantType = std::variant<std::monostate, CompleteStructType, CompleteEnumeratedType, CompleteUnionType,
CompleteBitmaskType, CompleteAliasType
// Add other types as needed
>;
VariantType value;
};
struct MinimalTypeObject
{
using VariantType = std::variant<std::monostate, MinimalStructType, MinimalEnumeratedType, MinimalUnionType,
MinimalBitmaskType, MinimalAliasType
// Add other types as needed
>;
VariantType value;
};
struct TypeObject
{
using VariantType = std::variant<CompleteTypeObject, MinimalTypeObject>;
VariantType value;
};
// Factory functions for creating TypeObjects
CompleteTypeObject create_complete_struct_type_object(
const std::string& name, const std::vector<CompleteStructMember>& members,
cdr::ExtensibilityKind extensibility = cdr::ExtensibilityKind::FINAL,
const std::optional<TypeIdentifier>& base_type = std::nullopt);
MinimalTypeObject create_minimal_struct_type_object(
const std::vector<MinimalStructMember>& members,
cdr::ExtensibilityKind extensibility = cdr::ExtensibilityKind::FINAL,
const std::optional<TypeIdentifier>& base_type = std::nullopt);
CompleteTypeObject create_complete_enum_type_object(const std::string& name,
const std::vector<CompleteEnumeratedLiteral>& literals,
uint16_t bit_bound = 32);
MinimalTypeObject create_minimal_enum_type_object(const std::vector<MinimalEnumeratedLiteral>& literals,
uint16_t bit_bound = 32);
CompleteTypeObject create_complete_union_type_object(
const std::string& name, const TypeIdentifier& discriminator_type,
const std::vector<CompleteUnionMember>& members,
cdr::ExtensibilityKind extensibility = cdr::ExtensibilityKind::FINAL, uint16_t discriminator_flags = 0);
MinimalTypeObject create_minimal_union_type_object(const TypeIdentifier& discriminator_type,
const std::vector<MinimalUnionMember>& members,
cdr::ExtensibilityKind extensibility = cdr::ExtensibilityKind::FINAL,
uint16_t discriminator_flags = 0);
CompleteTypeObject create_complete_bitmask_type_object(const std::string& name,
const std::vector<CompleteBitflag>& flags,
uint16_t bit_bound = 32);
MinimalTypeObject create_minimal_bitmask_type_object(const std::vector<MinimalBitflag>& flags,
uint16_t bit_bound = 32);
CompleteTypeObject create_complete_alias_type_object(const std::string& name, const TypeIdentifier& related_type);
MinimalTypeObject create_minimal_alias_type_object(const TypeIdentifier& related_type);
// TypeIdentifier creation functions
TypeIdentifier create_primitive_type_identifier(TypeKind kind);
TypeIdentifier create_string_type_identifier(uint32_t bound = 0);
TypeIdentifier create_sequence_type_identifier(const TypeIdentifier& element_type, uint32_t bound = 0);
TypeIdentifier create_array_type_identifier(const TypeIdentifier& element_type, const std::vector<uint32_t>& bounds);
TypeIdentifier create_map_type_identifier(const TypeIdentifier& key_type, const TypeIdentifier& element_type,
uint32_t bound = 0);
TypeIdentifier create_scc_type_identifier(const StronglyConnectedComponentId& component_id, uint32_t scc_index);
std::vector<uint8_t> serialize_type_object(const TypeObject& type_obj);
EquivalenceHash generate_equivalence_hash(const TypeObject& type_obj);
TypeIdentifier create_type_identifier_from_hash(const EquivalenceHash& hash, bool use_minimal = true);
MinimalStructMember to_minimal_struct_member(const CompleteStructMember& complete);
MinimalEnumeratedLiteral to_minimal_enum_literal(const CompleteEnumeratedLiteral& complete);
MinimalUnionMember to_minimal_union_member(const CompleteUnionMember& complete);
MinimalBitflag to_minimal_bitflag(const CompleteBitflag& complete);
// Assignability functions (DDS-XTypes 1.3 Section 7.6.3)
struct TypeConsistencyOptions
{
bool allow_type_widening{false};
bool ignore_sequence_bounds{false};
bool ignore_string_bounds{false};
};
bool is_primitive_assignable(TypeKind source, TypeKind target);
bool is_primitive_assignable(TypeKind source, TypeKind target, const TypeConsistencyOptions& options);
bool is_string_assignable(const TypeIdentifier& source, const TypeIdentifier& target);
bool is_string_assignable(const TypeIdentifier& source, const TypeIdentifier& target,
const TypeConsistencyOptions& options);
bool is_sequence_assignable(const TypeIdentifier& source, const TypeIdentifier& target);
bool is_sequence_assignable(const TypeIdentifier& source, const TypeIdentifier& target,
const TypeConsistencyOptions& options);
bool is_array_assignable(const TypeIdentifier& source, const TypeIdentifier& target);
bool is_array_assignable(const TypeIdentifier& source, const TypeIdentifier& target,
const TypeConsistencyOptions& options);
bool is_map_assignable(const TypeIdentifier& source, const TypeIdentifier& target);
bool is_map_assignable(const TypeIdentifier& source, const TypeIdentifier& target,
const TypeConsistencyOptions& options);
bool is_type_identifier_assignable(const TypeIdentifier& source, const TypeIdentifier& target);
bool is_type_identifier_assignable(const TypeIdentifier& source, const TypeIdentifier& target,
const TypeConsistencyOptions& options);
bool are_struct_members_assignable(const CommonStructMember& source, const CommonStructMember& target);
bool is_struct_assignable(const CompleteStructType& source, const CompleteStructType& target);
bool is_enum_assignable(const CompleteEnumeratedType& source, const CompleteEnumeratedType& target);
bool is_union_assignable(const CompleteUnionType& source, const CompleteUnionType& target);
bool is_union_assignable(const CompleteUnionType& source, const CompleteUnionType& target,
const TypeConsistencyOptions& options);
bool is_bitmask_assignable(const CompleteBitmaskType& source, const CompleteBitmaskType& target);
bool is_alias_assignable(const CompleteAliasType& source, const CompleteAliasType& target);
bool is_alias_assignable(const CompleteAliasType& source, const CompleteAliasType& target,
const TypeConsistencyOptions& options);
bool is_scc_type_identifier_assignable(const SCCTypeIdentifierDefn& source, const SCCTypeIdentifierDefn& target);
bool is_assignable(const TypeObject& source, const TypeObject& target);
bool is_assignable(const TypeObject& source, const TypeObject& target, const TypeConsistencyOptions& options);
// TypeIdentifier helper functions
bool operator==(const TypeIdentifier& lhs, const TypeIdentifier& rhs);
bool operator!=(const TypeIdentifier& lhs, const TypeIdentifier& rhs);
std::string to_string(const TypeIdentifier& ti);
TypeIdentifier clone_type_identifier(const TypeIdentifier& source);
bool is_primitive_type_identifier(const TypeIdentifier& ti);
bool is_string_type_identifier(const TypeIdentifier& ti);
bool is_collection_type_identifier(const TypeIdentifier& ti);
} // namespace astutedds::xtypes
#endif // ASTUTEDDS_XTYPES_TYPE_OBJECT_HPP