13#include "open62541pp/config.hpp"
43#if UAPP_HAS_TYPEDESCRIPTION
51#if UAPP_HAS_TYPEDESCRIPTION
58#if UAPP_OPEN62541_VER_GE(1, 3)
66#if UAPP_OPEN62541_VER_GE(1, 3)
93#if UAPP_OPEN62541_VER_GE(1, 1)
101#if UAPP_OPEN62541_VER_GE(1, 1)
116#if UAPP_HAS_TYPEDESCRIPTION
124#if UAPP_HAS_TYPEDESCRIPTION
139#if UAPP_OPEN62541_VER_GE(1, 2)
147#if UAPP_OPEN62541_VER_GE(1, 2)
195 return lhs.typeId == rhs.typeId;
200 return !(lhs == rhs);
205#if UAPP_OPEN62541_VER_GE(1, 3)
206 if (lhs.memberType ==
nullptr || rhs.memberType ==
nullptr) {
209 return (lhs.memberType == rhs.memberType) || (*lhs.memberType == *rhs.memberType);
211 return lhs.memberTypeIndex == rhs.memberTypeIndex;
217 return !(lhs == rhs);
224template <auto memberPtr>
226 using TMember = detail::MemberTypeT<
decltype(memberPtr)>;
227 return getDataType<std::remove_pointer_t<TMember>>();
231template <
typename T,
typename TMember>
232size_t offsetOfMember(TMember T::*member) {
234 return size_t(&(
object.*member)) - size_t(&
object);
237struct TagDataTypeAny;
238struct TagDataTypeEnum;
239struct TagDataTypeStruct;
240struct TagDataTypeUnion;
250template <
typename T,
typename Tag = detail::TagDataTypeAny,
typename U = struct DeferT>
286 template <auto U::*field>
288 using TMember = detail::MemberTypeT<
decltype(field)>;
289 return addField<TMember>(fieldName, detail::offsetOfMember(field), fieldType);
296 template <auto U::*field>
298 return addField<field>(fieldName, detail::getMemberDataType<field>());
308 template <
typename TMember>
315 template <
typename TMember>
316 auto&
addField(std::string_view fieldName,
size_t offset) {
317 return addField<TMember>(fieldName, offset,
getDataType<std::remove_pointer_t<TMember>>());
330 template <
size_t U::*fieldSize, auto U::*fieldArray>
332 using TArray = detail::MemberTypeT<
decltype(fieldArray)>;
333 return addField<TArray>(
335 detail::offsetOfMember(fieldSize),
336 detail::offsetOfMember(fieldArray),
345 template <
size_t U::*fieldSize, auto U::*fieldArray>
347 return addField<fieldSize, fieldArray>(fieldName, detail::getMemberDataType<fieldArray>());
358 template <
typename TArray>
360 std::string_view fieldName,
370 template <
typename TArray>
371 auto&
addField(std::string_view fieldName,
size_t offsetSize,
size_t offsetArray) {
372 return addField<TArray>(
373 fieldName, offsetSize, offsetArray,
getDataType<std::remove_pointer_t<TArray>>()
384 template <auto U::*memberUnion,
typename TField>
391 template <auto U::*memberUnion,
typename TField>
393 return addUnionField<memberUnion, TField>(fieldName, getDataType<TField>());
402 template <
typename,
typename,
typename>
406 : dataType_{std::move(dataType)} {}
411 DataTypeMember dataTypeMember;
415 std::vector<Field> fields_;
420template <
typename T,
typename Tag,
typename U>
422 std::string_view typeName,
NodeId typeId,
NodeId binaryEncodingId
424 static_assert(std::is_enum_v<T>,
"T must be an enum");
436template <
typename T,
typename Tag,
typename U>
438 std::string_view typeName,
NodeId typeId,
NodeId binaryEncodingId
440 static_assert(std::is_class_v<T>,
"T must be a struct or class");
452template <
typename T,
typename Tag,
typename U>
454 std::string_view typeName,
NodeId typeId,
NodeId binaryEncodingId
456 static_assert(std::is_class_v<T>,
"T must be a struct or class");
468template <
typename T,
typename Tag,
typename U>
469template <
typename TMember>
471 std::string_view fieldName,
size_t offset,
const UA_DataType& fieldType
474 std::is_same_v<Tag, detail::TagDataTypeStruct>,
475 "Built type must be a struct or class to add members"
477 assert(
sizeof(std::remove_pointer_t<TMember>) == fieldType.
memSize);
478 if (std::is_pointer_v<TMember>) {
481 if (std::is_pointer_v<TMember> || !fieldType.
pointerFree) {
482 dataType_.setPointerFree(
false);
490 fields_.push_back({
sizeof(TMember), offset, std::move(member)});
494template <
typename T,
typename Tag,
typename U>
495template <
typename TArray>
497 const std::string_view fieldName,
499 [[maybe_unused]]
size_t offsetArray,
503 std::is_same_v<Tag, detail::TagDataTypeStruct>,
504 "Built type must be a struct or class to add members"
506 static_assert(std::is_pointer_v<TArray>,
"TArray must be a pointer");
508 offsetArray == offsetSize +
sizeof(
size_t) &&
509 "No padding between members size and array allowed"
511 assert(
sizeof(std::remove_pointer_t<TArray>) == fieldType.
memSize);
512 dataType_.setPointerFree(
false);
520 sizeof(size_t) +
sizeof(TArray),
527template <
typename T,
typename Tag,
typename U>
528template <auto U::*memberUnion,
typename TField>
530 std::string_view fieldName,
const UA_DataType& fieldType
532 using TUnion = detail::MemberTypeT<
decltype(memberUnion)>;
534 std::is_same_v<Tag, detail::TagDataTypeUnion>,
535 "Built type must be a union to add union fields"
537 static_assert(std::is_union_v<TUnion>,
"TUnion must be a union");
538 static_assert(
sizeof(TField) <=
sizeof(TUnion),
"TField exceeds size of union");
539 const auto offset = detail::offsetOfMember(memberUnion);
540 assert(offset > 0 &&
"A union type must consist of a switch field and a union");
541 assert(
sizeof(std::remove_pointer_t<TField>) == fieldType.
memSize);
542 if (std::is_pointer_v<TField> || !fieldType.
pointerFree) {
543 dataType_.setPointerFree(
false);
548 member.
setPadding(
static_cast<uint8_t
>(offset));
551 fields_.push_back({
sizeof(TField), offset, std::move(member)});
555template <
typename T,
typename Tag,
typename U>
557 static_assert(!std::is_same_v<Tag, detail::TagDataTypeAny>);
559 std::sort(fields_.begin(), fields_.end(), [](
const auto& lhs,
const auto& rhs) {
560 return lhs.offset < rhs.offset;
563 if constexpr (std::is_same_v<Tag, detail::TagDataTypeStruct>) {
564 for (
auto it = fields_.begin(); it < fields_.end(); ++it) {
565 if (it == fields_.begin()) {
566 it->dataTypeMember->padding =
static_cast<uint8_t
>(it->offset);
568 it->dataTypeMember->padding =
static_cast<uint8_t
>(
569 it->offset - (std::prev(it)->offset + std::prev(it)->memSize)
575 std::vector<UA_DataTypeMember> members(fields_.size());
576 std::transform(fields_.cbegin(), fields_.cend(), members.begin(), [](
const auto& m) {
577 return asNative(m.dataTypeMember);
579 dataType_.setMembers({asWrapper<DataTypeMember>(members.data()), members.size()});
Builder to create DataType definitions of custom types.
DataType build()
Create the actual DataType.
auto & addUnionField(std::string_view fieldName, const UA_DataType &fieldType)
Add a union field.
auto & addField(std::string_view fieldName, const UA_DataType &fieldType)
Add a structure array field.
auto & addField(std::string_view fieldName)
Add a structure field (derive DataType from field).
static auto createStructure(std::string_view typeName, NodeId typeId, NodeId binaryEncodingId)
Build a DataType definition for a structure.
auto & addField(std::string_view fieldName, size_t offset)
Add a structure field with a manual offset (derive DataType from TMember).
static auto createUnion(std::string_view typeName, NodeId typeId, NodeId binaryEncodingId)
Build a DataType definition for an union.
auto & addUnionField(std::string_view fieldName)
Add a union field (derive DataType from TField).
auto & addField(std::string_view fieldName, size_t offsetSize, size_t offsetArray)
Add a structure array field with a manual offset (derive DataType from TArray).
auto & addField(std::string_view fieldName)
Add a structure array field (derive DataType from fieldArray).
auto & addField(std::string_view fieldName, const UA_DataType &fieldType)
Add a structure field.
static auto createEnum(std::string_view typeName, NodeId typeId, NodeId binaryEncodingId)
Build a DataType definition for an enum.
friend class DataTypeBuilder
void setIsArray(bool isArray)
bool isOptional() const noexcept
void setPadding(uint8_t padding)
void setMemberType(const UA_DataType *memberType)
uint8_t padding() const noexcept
bool isArray() const noexcept
void setMemberName(std::string_view memberName)
void setIsOptional(bool isOptional)
const UA_DataType * memberType() const noexcept
std::string_view memberName() const noexcept
UA_DataType wrapper class.
bool operator!=(const UA_DataTypeMember &lhs, const UA_DataTypeMember &rhs) noexcept
bool operator!=(const UA_DataType &lhs, const UA_DataType &rhs) noexcept
std::string_view typeName() const noexcept
Span< const DataTypeMember > members() const noexcept
bool pointerFree() const noexcept
NodeId binaryEncodingId() const noexcept
uint8_t typeKind() const noexcept
bool overlayable() const noexcept
void setTypeKind(uint8_t typeKind) noexcept
uint16_t memSize() const noexcept
NodeId typeId() const noexcept
void setTypeId(NodeId typeId)
void setOverlayable(bool overlayable) noexcept
void setMembers(Span< const DataTypeMember > members)
void setMemSize(uint16_t memSize) noexcept
void setPointerFree(bool pointerFree) noexcept
void setTypeName(std::string_view typeName) noexcept
void setBinaryEncodingId(NodeId binaryEncodingId)
bool operator==(const UA_DataType &lhs, const UA_DataType &rhs) noexcept
bool operator==(const UA_DataTypeMember &lhs, const UA_DataTypeMember &rhs) noexcept
T & identifier()
Get identifier reference.
View to a contiguous sequence of objects, similar to std::span in C++20.
Template base class to wrap (native) objects.
constexpr UA_DataTypeMember * handle() noexcept
Return pointer to native object.
constexpr Wrapper() noexcept=default
const UA_DataType & getDataType() noexcept
const UA_DataType * memberType
UA_NodeId binaryEncodingId
static void clear(UA_DataTypeMember &native) noexcept
static UA_DataTypeMember move(UA_DataTypeMember &&native) noexcept
static UA_DataTypeMember copy(const UA_DataTypeMember &native)
static void clear(UA_DataType &native) noexcept
static UA_DataType copy(const UA_DataType &native)
static UA_DataType move(UA_DataType &&native) noexcept
Default type handler providing standard copy and move operations.
UA_DATATYPEKIND_OPTSTRUCT
UA_DATATYPEKIND_STRUCTURE