13#include "open62541pp/config.hpp"
40#if UAPP_HAS_TYPEDESCRIPTION
48#if UAPP_HAS_TYPEDESCRIPTION
55#if UAPP_OPEN62541_VER_GE(1, 3)
63#if UAPP_OPEN62541_VER_GE(1, 3)
90#if UAPP_OPEN62541_VER_GE(1, 1)
98#if UAPP_OPEN62541_VER_GE(1, 1)
125#if UAPP_HAS_TYPEDESCRIPTION
133 [[deprecated(
"use typeName() instead")]]
139#if UAPP_HAS_TYPEDESCRIPTION
150 [[deprecated(
"use typeId() instead")]]
160#if UAPP_OPEN62541_VER_GE(1, 2)
168 [[deprecated(
"use binaryEncodingId() instead")]]
174#if UAPP_OPEN62541_VER_GE(1, 2)
186 [[deprecated(
"use memSize() instead")]]
200 [[deprecated(
"use typeKind() instead")]]
214 [[deprecated(
"use pointerFree() instead")]]
228 [[deprecated(
"use overlayable() instead")]]
242 [[deprecated(
"use members() instead")]]
252 return lhs.typeId == rhs.typeId;
257 return !(lhs == rhs);
262#if UAPP_OPEN62541_VER_GE(1, 3)
263 if (lhs.memberType ==
nullptr || rhs.memberType ==
nullptr) {
266 return (lhs.memberType == rhs.memberType) || (*lhs.memberType == *rhs.memberType);
268 return lhs.memberTypeIndex == rhs.memberTypeIndex;
274 return !(lhs == rhs);
281template <auto memberPtr>
283 using TMember = detail::MemberTypeT<
decltype(memberPtr)>;
284 return getDataType<std::remove_pointer_t<TMember>>();
288template <
typename T,
typename TMember>
289size_t offsetOfMember(TMember T::* member) {
291 return size_t(&(
object.*member)) - size_t(&
object);
294struct TagDataTypeAny;
295struct TagDataTypeEnum;
296struct TagDataTypeStruct;
297struct TagDataTypeUnion;
307template <
typename T,
typename Tag = detail::TagDataTypeAny,
typename U = struct DeferT>
342 template <auto U::* field>
349 template <auto U::* field>
351 return addField<field>(fieldName, detail::getMemberDataType<field>());
363 template <auto U::* fieldSize, auto U::* fieldArray>
370 template <auto U::* fieldSize, auto U::* fieldArray>
372 return addField<fieldSize, fieldArray>(fieldName, detail::getMemberDataType<fieldArray>());
382 template <auto U::* memberUnion,
typename TField>
389 template <auto U::* memberUnion,
typename TField>
391 return addUnionField<memberUnion, TField>(fieldName, getDataType<TField>());
400 template <
typename,
typename,
typename>
404 : dataType_(std::move(dataType)) {}
409 DataTypeMember dataTypeMember;
413 std::vector<Field> fields_;
418template <
typename T,
typename Tag,
typename U>
420 std::string_view typeName,
NodeId typeId,
NodeId binaryEncodingId
422 static_assert(std::is_enum_v<T>,
"T must be an enum");
434template <
typename T,
typename Tag,
typename U>
436 std::string_view typeName,
NodeId typeId,
NodeId binaryEncodingId
438 static_assert(std::is_class_v<T>,
"T must be a struct or class");
450template <
typename T,
typename Tag,
typename U>
452 std::string_view typeName,
NodeId typeId,
NodeId binaryEncodingId
454 static_assert(std::is_class_v<T>,
"T must be a struct or class");
466template <
typename T,
typename Tag,
typename U>
467template <auto U::* field>
469 std::string_view fieldName,
const UA_DataType& fieldType
471 using TMember = detail::MemberTypeT<
decltype(field)>;
473 std::is_same_v<Tag, detail::TagDataTypeStruct>,
474 "Built type must be a struct or class to add members"
476 assert(
sizeof(std::remove_pointer_t<TMember>) == fieldType.
memSize);
477 if (std::is_pointer_v<TMember>) {
480 if (std::is_pointer_v<TMember> || !fieldType.
pointerFree) {
481 dataType_.setPointerFree(
false);
489 fields_.push_back({
sizeof(TMember), detail::offsetOfMember(field), std::move(member)});
493template <
typename T,
typename Tag,
typename U>
494template <auto U::* fieldSize, auto U::* fieldArray>
496 std::string_view fieldName,
const UA_DataType& fieldType
498 using TSize = detail::MemberTypeT<
decltype(fieldSize)>;
499 using TArray = detail::MemberTypeT<
decltype(fieldArray)>;
501 std::is_same_v<Tag, detail::TagDataTypeStruct>,
502 "Built type must be a struct or class to add members"
504 static_assert(std::is_integral_v<TSize>,
"TSize must be an integral type");
505 static_assert(std::is_pointer_v<TArray>,
"TArray must be a pointer");
507 detail::offsetOfMember(fieldArray) == detail::offsetOfMember(fieldSize) +
sizeof(TSize) &&
508 "No padding between members size and array allowed"
510 assert(
sizeof(std::remove_pointer_t<TArray>) == fieldType.
memSize);
511 dataType_.setPointerFree(
false);
519 sizeof(TSize) +
sizeof(TArray),
520 detail::offsetOfMember(fieldSize),
526template <
typename T,
typename Tag,
typename U>
527template <auto U::* memberUnion,
typename TField>
529 std::string_view fieldName,
const UA_DataType& fieldType
531 using TUnion = detail::MemberTypeT<
decltype(memberUnion)>;
533 std::is_same_v<Tag, detail::TagDataTypeUnion>,
534 "Built type must be a union to add union fields"
536 static_assert(std::is_union_v<TUnion>,
"TUnion must be a union");
537 static_assert(
sizeof(TField) <=
sizeof(TUnion),
"TField exceeds size of union");
538 const auto offset = detail::offsetOfMember(memberUnion);
539 assert(offset > 0 &&
"A union type must consist of a switch field and a union");
540 assert(
sizeof(std::remove_pointer_t<TField>) == fieldType.
memSize);
541 if (std::is_pointer_v<TField> || !fieldType.
pointerFree) {
542 dataType_.setPointerFree(
false);
547 member.
setPadding(
static_cast<uint8_t
>(offset));
550 fields_.push_back({
sizeof(TField), offset, std::move(member)});
554template <
typename T,
typename Tag,
typename U>
556 static_assert(!std::is_same_v<Tag, detail::TagDataTypeAny>);
558 std::sort(fields_.begin(), fields_.end(), [](
const auto& lhs,
const auto& rhs) {
559 return lhs.offset < rhs.offset;
562 if constexpr (std::is_same_v<Tag, detail::TagDataTypeStruct>) {
563 for (
auto it = fields_.begin(); it < fields_.end(); ++it) {
564 if (it == fields_.begin()) {
565 it->dataTypeMember->padding =
static_cast<uint8_t
>(it->offset);
567 it->dataTypeMember->padding =
static_cast<uint8_t
>(
568 it->offset - (std::prev(it)->offset + std::prev(it)->memSize)
574 std::vector<UA_DataTypeMember> members(fields_.size());
575 std::transform(fields_.cbegin(), fields_.cend(), members.begin(), [](
const auto& m) {
576 return asNative(m.dataTypeMember);
578 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)
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.
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)
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
constexpr DataTypeMember() noexcept=default
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 getTypeName() const 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
uint16_t getMemSize() const noexcept
void setTypeKind(uint8_t typeKind) noexcept
uint16_t memSize() const noexcept
NodeId typeId() const noexcept
bool getPointerFree() const noexcept
void setTypeId(NodeId typeId)
NodeId getBinaryEncodingId() const noexcept
constexpr DataType() noexcept=default
void setOverlayable(bool overlayable) noexcept
bool getOverlayable() const noexcept
uint8_t getTypeKind() const 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)
NodeId getTypeId() const noexcept
bool operator==(const UA_DataType &lhs, const UA_DataType &rhs) noexcept
bool operator==(const UA_DataTypeMember &lhs, const UA_DataTypeMember &rhs) noexcept
Span< const DataTypeMember > getMembers() const noexcept
NamespaceIndex namespaceIndex() const 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 const UA_DataTypeMember & native() const noexcept
constexpr UA_DataTypeMember * handle() noexcept
Return pointer to native object.
uint16_t TypeIndex
Type index of the UA_TYPES array.
const UA_DataType * memberType
UA_NodeId binaryEncodingId
UA_DATATYPEKIND_OPTSTRUCT
UA_DATATYPEKIND_STRUCTURE