18#include "open62541pp/config.hpp"
59 std::string_view
name() const noexcept {
64 constexpr bool isGood() const noexcept {
65 return detail::isGood(
native());
70 return detail::isUncertain(
native());
74 constexpr bool isBad() const noexcept {
75 return detail::isBad(
native());
94template <
typename WrapperType,
typename CharT>
95class StringLikeMixin {
98 using value_type = CharT;
99 using size_type = size_t;
100 using difference_type = std::ptrdiff_t;
101 using pointer = value_type*;
102 using const_pointer =
const value_type*;
103 using reference = value_type&;
104 using const_reference =
const value_type&;
105 using iterator = pointer;
106 using const_iterator = const_pointer;
107 using reverse_iterator = std::reverse_iterator<iterator>;
108 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
111 size_t size() const noexcept {
112 const auto& native =
asNative(
static_cast<const WrapperType&
>(*
this));
113 return native.length;
116 size_t length() const noexcept {
120 bool empty() const noexcept {
124 pointer data() noexcept {
125 auto& native =
asNative(
static_cast<WrapperType&
>(*
this));
126 return stripEmptyArraySentinel(
reinterpret_cast<pointer
>(native.data));
129 const_pointer data() const noexcept {
130 const auto& native =
asNative(
static_cast<const WrapperType&
>(*
this));
131 return stripEmptyArraySentinel(
reinterpret_cast<const_pointer
>(native.data));
134 reference operator[](
size_t index)
noexcept {
135 assert(index < size());
136 return data()[index];
139 const_reference operator[](
size_t index)
const noexcept {
140 assert(index < size());
141 return data()[index];
144 reference front() noexcept {
149 const_reference front() const noexcept {
154 reference back() noexcept {
156 return *(data() + size() - 1);
159 const_reference back() const noexcept {
161 return *(data() + size() - 1);
164 iterator begin() noexcept {
168 const_iterator begin() const noexcept {
172 const_iterator cbegin() const noexcept {
176 iterator end() noexcept {
177 return {data() + size()};
180 const_iterator end() const noexcept {
181 return {data() + size()};
184 const_iterator cend() const noexcept {
185 return {data() + size()};
188 reverse_iterator rbegin() noexcept {
189 return reverse_iterator(end());
192 const_reverse_iterator rbegin() const noexcept {
193 return const_reverse_iterator(end());
196 const_reverse_iterator crbegin() const noexcept {
197 return const_reverse_iterator(cend());
200 reverse_iterator rend() noexcept {
201 return reverse_iterator(begin());
204 const_reverse_iterator rend() const noexcept {
205 return const_reverse_iterator(begin());
208 const_reverse_iterator crend() const noexcept {
209 return const_reverse_iterator(cbegin());
213 void init(
size_t length) {
214 auto& native =
asNative(
static_cast<WrapperType&
>(*
this));
215 native.data = allocateArray<uint8_t>(length);
216 native.length = length;
219 template <
typename InputIt>
220 void init(InputIt first, InputIt last) {
221 static_assert(
sizeof(detail::IterValueT<InputIt>) ==
sizeof(uint8_t));
222 auto& native =
asNative(
static_cast<WrapperType&
>(*
this));
223 const auto [data, length] = detail::copyArray(first, last, UA_TYPES[UA_TYPES_BYTE]);
224 native.data =
reinterpret_cast<uint8_t*
>(data);
225 native.length = length;
239 public detail::StringLikeMixin<String, char> {
244 :
String{detail::allocNativeString(str)} {}
246 template <
typename InputIt>
258 template <
typename Traits>
265 template <
typename Traits>
266 operator std::basic_string_view<char, Traits>() const noexcept {
267 return {data(), size()};
273 return UA_String_equal(&lhs, &rhs);
278 return !(lhs == rhs);
288 return !(lhs == rhs);
293 return static_cast<std::string_view
>(lhs) == rhs;
298 return static_cast<std::string_view
>(lhs) != rhs;
303 return lhs ==
static_cast<std::string_view
>(rhs);
308 return lhs !=
static_cast<std::string_view
>(rhs);
319 return T{src.data(), src.size()};
323 return String{src.begin(), src.end()};
342 const auto length = N > 0 && src[N - 1] ==
'\0' ? N - 1 : N;
343 return String{std::string_view{
static_cast<const char*
>(src), length}};
362 using Clock = std::chrono::system_clock;
363 using Duration = std::chrono::duration<int64_t, std::ratio<1, 10'000'000>>;
368 template <
typename D>
369 constexpr explicit DateTime(std::chrono::time_point<Clock, D> timePoint) noexcept
371 std::chrono::duration_cast<Duration>(timePoint.time_since_epoch()).count() +
381 template <
typename D>
397 template <
typename D = Duration>
399 return std::chrono::time_point<Clock, D>{
415 template <
typename Rep,
typename Period>
417 native() += std::chrono::duration_cast<Duration>(duration).count();
422 template <
typename Rep,
typename Period>
424 native() -= std::chrono::duration_cast<Duration>(duration).count();
429 constexpr int64_t
get() const noexcept {
440template <
typename Rep,
typename Period>
442 const DateTime& dt, std::chrono::duration<Rep, Period> duration
444 return {dt.
get() + std::chrono::duration_cast<DateTime::Duration>(duration).count()};
449template <
typename Rep,
typename Period>
451 const DateTime& dt, std::chrono::duration<Rep, Period> duration
453 return {dt.
get() - std::chrono::duration_cast<DateTime::Duration>(duration).count()};
462template <
typename Duration>
463struct TypeConverter<std::chrono::time_point<std::chrono::system_clock, Duration>> {
464 using TimePoint = std::chrono::time_point<std::chrono::system_clock, Duration>;
489 explicit Guid(std::array<uint8_t, 16> data) noexcept
492 static_cast<uint32_t
>(
493 (data[0] << 24U) | (data[1] << 16U) | (data[2] << 8U) | data[3]
495 static_cast<uint16_t
>((data[4] << 8U) | data[5]),
496 static_cast<uint16_t
>((data[6] << 8U) | data[7]),
498 {data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]},
501 Guid(uint32_t data1, uint16_t data2, uint16_t data3, std::array<uint8_t, 8> data4) noexcept
506 {data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], data4[7]},
519 throwIfBad(UA_Guid_parse(
guid.handle(), detail::toNativeString(str)));
525 [[deprecated(
"use free function toString instead")]]
531 return UA_Guid_equal(&lhs, &rhs);
536 return !(lhs == rhs);
549 public detail::StringLikeMixin<
ByteString, std::
byte> {
554 :
ByteString{detail::allocNativeString(str)} {}
563 template <
typename InputIt>
573 template <
typename Traits>
574 explicit operator std::basic_string_view<char, Traits>() const noexcept {
575 return {
reinterpret_cast<const char*
>(data()), size()};
593 public detail::StringLikeMixin<
XmlElement,
char> {
598 :
XmlElement{detail::allocNativeString(str)} {}
600 template <
typename InputIt>
612 template <
typename Traits>
619 template <
typename Traits>
620 operator std::basic_string_view<char, Traits>() const noexcept {
621 return {data(), size()};
630template <
typename T,
typename =
void>
631struct IsNodeIdEnum : std::false_type {};
634struct IsNodeIdEnum<T, std::void_t<decltype(namespaceOf(std::declval<T>()))>> : std::is_enum<T> {};
683 handle()->identifier.byteString = {};
690 template <typename T, typename = std::enable_if_t<detail::IsNodeIdEnum<T>::value>>
709 uint32_t
hash() const noexcept {
714 return handle()->namespaceIndex;
731 template <
typename T>
733 return const_cast<T*
>(std::as_const(*this).identifierIf<T>());
737 template <
typename T>
740 detail::IsOneOf<T, uint32_t, String, Guid, ByteString>::value,
741 "Invalid type for NodeId identifier"
744 if constexpr (std::is_same_v<T, uint32_t>) {
746 ? &
handle()->identifier.numeric
748 }
else if constexpr (std::is_same_v<T, String>) {
752 }
else if constexpr (std::is_same_v<T, Guid>) {
756 }
else if constexpr (std::is_same_v<T, ByteString>) {
776 template <
typename T>
778 return const_cast<T&
>(std::as_const(*this).identifier<T>());
782 template <
typename T>
784 if (
auto* ptr = identifierIf<T>()) {
787 throw TypeError(
"NodeId identifier type doesn't match the requested type");
791 [[deprecated(
"use free function toString instead")]]
797 return UA_NodeId_equal(&lhs, &rhs);
802 return !(lhs == rhs);
817 return (lhs < rhs) || (lhs == rhs);
822 return (lhs > rhs) || (lhs == rhs);
839 asWrapper<NodeId>(handle()->
nodeId) = std::move(
id);
843 asWrapper<NodeId>(handle()->
nodeId) = std::move(
id);
844 handle()->namespaceUri = detail::allocNativeString(
namespaceUri);
855 throwIfBad(UA_ExpandedNodeId_parse(
id.handle(), detail::toNativeString(str)));
861 return handle()->serverIndex == 0;
864 uint32_t
hash() const noexcept {
869 return asWrapper<NodeId>(handle()->
nodeId);
873 return asWrapper<NodeId>(handle()->
nodeId);
881 return handle()->serverIndex;
885 [[deprecated(
"use free function toString instead")]]
891 return UA_ExpandedNodeId_equal(&lhs, &rhs);
896 return !(lhs == rhs);
911 return (lhs < rhs) || (lhs == rhs);
916 return (lhs > rhs) || (lhs == rhs);
933 handle()->name = detail::allocNativeString(
name);
937 return handle()->namespaceIndex;
940 std::string_view
name() const noexcept {
941 return detail::toStringView(handle()->
name);
947 return (lhs.namespaceIndex == rhs.namespaceIndex) && (lhs.name == rhs.name);
952 return !(lhs == rhs);
973 handle()->locale = detail::allocNativeString(
locale);
974 handle()->text = detail::allocNativeString(
text);
977 std::string_view
locale() const noexcept {
978 return detail::toStringView(handle()->
locale);
981 std::string_view
text() const noexcept {
982 return detail::toStringView(handle()->
text);
988 return (lhs.locale == rhs.locale) && (lhs.text == rhs.text);
993 return !(lhs == rhs);
1002 using TypeError::TypeError;
1062 template <
typename T>
1063 static constexpr bool isVariant =
1064 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
Variant> ||
1065 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
UA_Variant>;
1072 template <
typename T,
typename = std::enable_if_t<!std::is_const_v<T>>>
1079 template <
typename T,
typename = std::enable_if_t<!std::is_const_v<T>>>
1086 template <
typename T,
typename = std::enable_if_t<!isVariant<T>>>
1088 assign(std::forward<T>(value));
1093 template <
typename T>
1100 template <
typename InputIt>
1107 template <
typename InputIt>
1118 void assign(std::nullptr_t ptr)
noexcept =
delete;
1131 template <
typename T,
typename = std::enable_if_t<!std::is_const_v<T>>>
1133 if constexpr (isArrayType<T>()) {
1134 using ValueType = detail::RangeValueT<T>;
1135 assertIsRegistered<ValueType>();
1136 assign(ptr, opcua::getDataType<ValueType>());
1138 assertIsRegistered<T>();
1139 assign(ptr, opcua::getDataType<T>());
1148 template <
typename T,
typename = std::enable_if_t<!std::is_const_v<T>>>
1150 if (ptr ==
nullptr) {
1152 }
else if constexpr (isArrayType<T>()) {
1166 template <
typename T>
1168 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
1169 if constexpr (isArrayType<ValueType>()) {
1170 assign(std::begin(value), std::end(value));
1172 assertIsRegisteredOrConvertible<ValueType>();
1174 setScalarCopyImpl(std::forward<T>(value), opcua::getDataType<ValueType>());
1176 setScalarCopyConvertImpl(std::forward<T>(value));
1189 template <
typename T>
1191 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
1192 if constexpr (isArrayType<ValueType>()) {
1193 setArrayCopyImpl(std::begin(value), std::end(value),
type);
1195 setScalarCopyImpl(std::forward<T>(value),
type);
1205 template <
typename InputIt>
1207 using ValueType = detail::IterValueT<InputIt>;
1208 assertIsRegisteredOrConvertible<ValueType>();
1210 setArrayCopyImpl(first, last, opcua::getDataType<ValueType>());
1212 setArrayCopyConvertImpl(first, last);
1223 template <
typename InputIt>
1225 setArrayCopyImpl(first, last,
type);
1230 template <
typename T,
typename = std::enable_if_t<!isVariant<T>>>
1238 template <
typename T,
typename = std::enable_if_t<!isVariant<T>>>
1240 assign(std::forward<T>(value));
1251 return UA_Variant_isEmpty(
handle());
1256 return UA_Variant_isScalar(
handle());
1280 template <
typename T>
1282 return isType(opcua::getDataType<T>());
1292 return handle()->arrayLength;
1297 return {
handle()->arrayDimensions,
handle()->arrayDimensionsSize};
1312 return detail::stripEmptyArraySentinel(
handle()->
data);
1316 const void*
data() const noexcept {
1317 return detail::stripEmptyArraySentinel(
handle()->
data);
1322 template <
typename T>
1324 checkIsScalarType<T>();
1325 return *
static_cast<T*
>(
data());
1329 template <
typename T>
1331 checkIsScalarType<T>();
1332 return *
static_cast<const T*
>(
data());
1336 template <
typename T>
1338 return isBorrowed() ? scalar<T>() : std::move(scalar<T>());
1342 template <
typename T>
1344 return isBorrowed() ? scalar<T>() : std::move(scalar<T>());
1349 template <
typename T>
1351 checkIsArrayType<T>();
1356 template <
typename T>
1358 checkIsArrayType<T>();
1385 template <
typename T>
1386 [[nodiscard]] T
to() const& {
1387 return toImpl<T>(*
this);
1391 template <
typename T>
1392 [[nodiscard]] T
to() && {
1393 return toImpl<T>(std::move(*
this));
1401 template <
typename T>
1402 static constexpr bool isScalarType() noexcept {
1406 template <
typename T>
1407 static constexpr bool isArrayType() noexcept {
1408 return detail::IsRange<T>::value && !isScalarType<T>();
1411 template <
typename T>
1412 static constexpr void assertIsRegistered() {
1414 IsRegistered<T>::value,
1415 "Template type must be a native/wrapper type to assign or get scalar/array without copy"
1419 template <
typename T>
1420 static constexpr void assertIsRegisteredOrConvertible() {
1422 IsRegistered<T>::value || IsConvertible<T>::value,
1423 "Template type must be either a native/wrapper type or a convertible type. "
1424 "If the type is a native type: Provide the type definition (UA_DataType) manually or "
1425 "register the type with a TypeRegistry template specialization. "
1426 "If the type should be converted: Add a template specialization for TypeConverter."
1430 template <
typename T>
1431 static constexpr void assertNoVariant() {
1432 static_assert(!isVariant<T>,
"Variants cannot directly contain another variant");
1435 void checkIsScalar()
const {
1437 throw BadVariantAccess(
"Variant is not a scalar");
1441 void checkIsArray()
const {
1443 throw BadVariantAccess(
"Variant is not an array");
1447 template <
typename T>
1448 void checkIsType()
const {
1449 const auto* dt =
type();
1450 if (dt ==
nullptr || dt->typeId != opcua::getDataType<T>().typeId) {
1451 throw BadVariantAccess(
"Variant does not contain a value convertible to template type");
1455 template <
typename T>
1456 void checkIsScalarType()
const {
1457 assertIsRegistered<T>();
1462 template <
typename T>
1463 void checkIsArrayType()
const {
1464 assertIsRegistered<T>();
1469 bool isBorrowed() const noexcept {
1473 template <
typename T>
1477 setArrayImpl(
data, 0,
type, storageType);
1480 template <
typename T>
1484 assertNoVariant<T>();
1488 handle()->storageType = storageType;
1493 template <
typename T>
1495 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
1496 auto native = detail::makeUnique<ValueType>(
type);
1497 *
native = detail::copy<ValueType>(std::forward<T>(value),
type);
1498 setScalarImpl(
native.release(),
type, UA_VARIANT_DATA);
1501 template <
typename T>
1502 void setScalarCopyConvertImpl(T&& value) {
1503 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
1504 using Native =
typename TypeConverter<ValueType>::NativeType;
1505 const auto&
type = opcua::getDataType<Native>();
1506 auto native = detail::makeUnique<Native>(
type);
1507 *
native = detail::toNative<ValueType>(std::forward<T>(value));
1508 setScalarImpl(
native.release(),
type, UA_VARIANT_DATA);
1511 template <
typename InputIt>
1512 void setArrayCopyImpl(InputIt first, InputIt last,
const UA_DataType&
type) {
1513 const auto [ptr, size] = detail::copyArray(first, last,
type);
1514 setArrayImpl(ptr, size,
type, UA_VARIANT_DATA);
1517 template <
typename InputIt>
1518 void setArrayCopyConvertImpl(InputIt first, InputIt last) {
1519 using ValueType = detail::IterValueT<InputIt>;
1520 using Native =
typename TypeConverter<ValueType>::NativeType;
1521 const auto&
type = opcua::getDataType<Native>();
1522 const auto [ptr, size] = detail::copyArray(
1523 detail::TransformIterator(first, detail::toNative<ValueType>),
1524 detail::TransformIterator(last, detail::toNative<ValueType>),
1527 setArrayImpl(ptr, size,
type, UA_VARIANT_DATA);
1530 template <
typename T,
typename Self>
1531 static T toImpl(Self&& self) {
1532 if constexpr (isArrayType<T>()) {
1533 return toArrayImpl<T>(std::forward<Self>(self));
1535 return toScalarImpl<T>(std::forward<Self>(self));
1539 template <
typename T,
typename Self>
1540 static T toScalarImpl(Self&& self) {
1541 assertIsRegisteredOrConvertible<T>();
1542 if constexpr (IsRegistered<T>::value) {
1543 return std::forward<Self>(self).template scalar<T>();
1545 using Native =
typename TypeConverter<T>::NativeType;
1546 return detail::fromNative<T>(std::forward<Self>(self).
template scalar<Native>());
1550 template <
typename T,
typename Self>
1551 static T toArrayImpl(Self&& self) {
1552 using ValueType = detail::RangeValueT<T>;
1553 assertIsRegisteredOrConvertible<ValueType>();
1554 if constexpr (IsRegistered<ValueType>::value) {
1555 auto native = std::forward<Self>(self).template array<ValueType>();
1558 using Native =
typename TypeConverter<ValueType>::NativeType;
1559 auto native = std::forward<Self>(self).template array<Native>();
1561 detail::TransformIterator(
native.begin(), detail::fromNative<ValueType>),
1562 detail::TransformIterator(
native.end(), detail::fromNative<ValueType>)
1582 setValue(std::move(value));
1587 std::optional<DateTime> sourceTimestamp,
1588 std::optional<DateTime> serverTimestamp,
1589 std::optional<uint16_t> sourcePicoseconds,
1590 std::optional<uint16_t> serverPicoseconds,
1591 std::optional<StatusCode> status
1595 sourceTimestamp.value_or(UA_DateTime{}),
1596 serverTimestamp.value_or(UA_DateTime{}),
1597 sourcePicoseconds.value_or(uint16_t{}),
1598 serverPicoseconds.value_or(uint16_t{}),
1601 sourceTimestamp.has_value(),
1602 serverTimestamp.has_value(),
1603 sourcePicoseconds.has_value(),
1604 serverPicoseconds.has_value(),
1607 setValue(std::move(value));
1612 asWrapper<Variant>(handle()->value) = value;
1613 handle()->hasValue =
true;
1618 asWrapper<Variant>(handle()->value) = std::move(value);
1619 handle()->hasValue =
true;
1624 handle()->sourceTimestamp = sourceTimestamp.get();
1625 handle()->hasSourceTimestamp =
true;
1630 handle()->serverTimestamp = serverTimestamp.get();
1631 handle()->hasServerTimestamp =
true;
1636 handle()->sourcePicoseconds = sourcePicoseconds;
1637 handle()->hasSourcePicoseconds =
true;
1642 handle()->serverPicoseconds = serverPicoseconds;
1643 handle()->hasServerPicoseconds =
true;
1648 handle()->status = status;
1649 handle()->hasStatus =
true;
1653 return handle()->hasValue;
1657 return handle()->hasSourceTimestamp;
1661 return handle()->hasServerTimestamp;
1665 return handle()->hasSourcePicoseconds;
1669 return handle()->hasServerPicoseconds;
1673 return handle()->hasStatus;
1678 return asWrapper<Variant>(handle()->value);
1683 return asWrapper<Variant>(handle()->value);
1688 return std::move(value());
1693 return std::move(value());
1698 return DateTime{handle()->sourceTimestamp};
1703 return DateTime{handle()->serverTimestamp};
1708 return handle()->sourcePicoseconds;
1713 return handle()->serverPicoseconds;
1718 return handle()->status;
1753 template <
typename T>
1754 static constexpr bool isExtensionObject =
1755 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
ExtensionObject> ||
1766 template <
typename T>
1776 template <
typename T>
1778 if (ptr ==
nullptr) {
1784 handle()->content.decoded.data = ptr;
1791 template <
typename T,
typename = std::enable_if_t<!isExtensionObject<T>>>
1800 template <
typename T,
typename = std::enable_if_t<!isExtensionObject<T>>>
1802 auto ptr = detail::makeUnique<T>(
type);
1803 *ptr = detail::copy(decoded,
type);
1806 handle()->content.decoded.data = ptr.release();
1835 ? asWrapper<NodeId>(&
handle()->content.encoded.typeId)
1843 ? asWrapper<ByteString>(&
handle()->content.encoded.body)
1851 ? asWrapper<XmlElement>(&
handle()->content.encoded.body)
1859 ?
handle()->content.decoded.type
1866 template <
typename T>
1868 return isDecodedType<T>() ?
static_cast<T*
>(
decodedData()) :
nullptr;
1874 template <
typename T>
1876 return isDecodedType<T>() ?
static_cast<const T*
>(
decodedData()) :
nullptr;
1884 ?
handle()->content.decoded.data
1893 ?
handle()->content.decoded.data
1898 template <
typename T>
1899 bool isDecodedType() const noexcept {
1901 return (type !=
nullptr) && (
type->
typeId == getDataType<T>().typeId);
1919 return handle()->hasSymbolicId;
1923 return handle()->hasNamespaceUri;
1927 return handle()->hasLocalizedText;
1931 return handle()->hasLocale;
1935 return handle()->hasAdditionalInfo;
1939 return handle()->hasInnerStatusCode;
1943 return handle()->hasInnerDiagnosticInfo;
1947 return handle()->symbolicId;
1951 return handle()->namespaceUri;
1955 return handle()->localizedText;
1959 return handle()->locale;
1963 return asWrapper<String>(handle()->additionalInfo);
1967 return handle()->innerStatusCode;
1971 return asWrapper<DiagnosticInfo>(handle()->innerDiagnosticInfo);
1982inline
bool operator==(
1985 return (lhs.min == rhs.min) && (lhs.max == rhs.max);
1992 return !(lhs == rhs);
2037 :
Wrapper{std::exchange(other.native(), {})} {}
2040 if (
this != &other) {
2048 if (
this != &other) {
2050 native() = std::exchange(other.native(), {});
2064 [[deprecated(
"use free function toString instead")]]
2068 void clear() noexcept {
2075 result.
dimensions = detail::copyArray(array, size);
2076 result.dimensionsSize = size;
2087#if UAPP_OPEN62541_VER_GE(1, 1)
2105#if UAPP_OPEN62541_VER_GE(1, 2)
2141template <
typename T>
2144 if constexpr (UAPP_HAS_TOSTRING) {
2155template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2157 return toString(
object, getDataType<T>());
2166template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2173template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2180template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2187template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2194template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2201template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2220struct std::hash<
opcua::ExpandedNodeId> {
UA_ByteString wrapper class.
ByteString(Span< const std::byte > bytes)
ByteString(InputIt first, InputIt last)
ByteString(std::string_view str)
String toBase64() const
Convert to Base64 encoded string.
static ByteString fromBase64(std::string_view encoded)
Parse ByteString from Base64 encoded string.
ByteString(const char *str)
UA_DataValue wrapper class.
bool hasServerPicoseconds() const noexcept
void setSourceTimestamp(DateTime sourceTimestamp) noexcept
Set source timestamp for the value.
uint16_t serverPicoseconds() const noexcept
Get picoseconds interval added to the server timestamp.
bool hasValue() const noexcept
DataValue(Variant value) noexcept
StatusCode status() const noexcept
Get status.
const Variant && value() const &&noexcept
Get value (rvalue).
DateTime serverTimestamp() const noexcept
Get server timestamp for the value.
bool hasSourceTimestamp() const noexcept
void setServerPicoseconds(uint16_t serverPicoseconds) noexcept
Set picoseconds interval added to the server timestamp.
uint16_t sourcePicoseconds() const noexcept
Get picoseconds interval added to the source timestamp.
Variant && value() &&noexcept
Get value (rvalue).
bool hasStatus() const noexcept
void setValue(Variant &&value) noexcept
Set value (move).
void setServerTimestamp(DateTime serverTimestamp) noexcept
Set server timestamp for the value.
void setStatus(StatusCode status) noexcept
Set status.
Variant & value() &noexcept
Get value.
void setSourcePicoseconds(uint16_t sourcePicoseconds) noexcept
Set picoseconds interval added to the source timestamp.
bool hasSourcePicoseconds() const noexcept
DateTime sourceTimestamp() const noexcept
Get source timestamp for the value.
bool hasServerTimestamp() const noexcept
void setValue(const Variant &value)
Set value (copy).
DataValue(Variant value, std::optional< DateTime > sourceTimestamp, std::optional< DateTime > serverTimestamp, std::optional< uint16_t > sourcePicoseconds, std::optional< uint16_t > serverPicoseconds, std::optional< StatusCode > status) noexcept
const Variant & value() const &noexcept
Get value.
UA_DateTime wrapper class.
constexpr int64_t get() const noexcept
Get DateTime value as 100 nanosecond intervals since January 1, 1601 (UTC).
String format(std::string_view format, bool localtime=false) const
Convert to string with given format (same format codes as strftime).
std::chrono::system_clock Clock
constexpr DateTime operator-(const DateTime &dt, std::chrono::duration< Rep, Period > duration) noexcept
Subtract a duration from DateTime.
constexpr DateTime operator+(const DateTime &dt, std::chrono::duration< Rep, Period > duration) noexcept
Add a duration to DateTime.
constexpr DateTime & operator-=(std::chrono::duration< Rep, Period > duration) noexcept
Subtract a duration from the DateTime.
constexpr DateTime & operator+=(std::chrono::duration< Rep, Period > duration) noexcept
Add a duration to the DateTime.
UA_DateTimeStruct toStruct() const noexcept
Convert to UA_DateTimeStruct.
static DateTime now() noexcept
Get current DateTime.
constexpr DateTime(std::chrono::time_point< Clock, D > timePoint) noexcept
Create DateTime from std::chrono::time_point.
std::chrono::duration< int64_t, std::ratio< 1, 10 '000 '000 > > Duration
static int64_t localTimeUtcOffset() noexcept
Offset of local time to UTC.
constexpr DateTime::Duration operator-(const DateTime &lhs, const DateTime &rhs) noexcept
Compute the difference between two DateTimes.
static constexpr DateTime fromUnixTime(int64_t unixTime) noexcept
Get DateTime from Unix time.
constexpr int64_t toUnixTime() const noexcept
Convert to Unix time (number of seconds since January 1, 1970 UTC).
static constexpr DateTime fromTimePoint(std::chrono::time_point< Clock, D > timePoint) noexcept
Get DateTime from std::chrono::time_point.
constexpr std::chrono::time_point< Clock, D > toTimePoint() const
Convert to std::chrono::time_point.
UA_DiagnosticInfo wrapper class.
bool hasInnerStatusCode() const noexcept
bool hasLocalizedText() const noexcept
int32_t symbolicId() const noexcept
bool hasSymbolicId() const noexcept
int32_t locale() const noexcept
StatusCode innerStatusCode() const noexcept
const String & additionalInfo() const noexcept
bool hasLocale() const noexcept
bool hasInnerDiagnosticInfo() const noexcept
const DiagnosticInfo * innerDiagnosticInfo() const noexcept
int32_t namespaceUri() const noexcept
bool hasNamespaceUri() const noexcept
int32_t localizedText() const noexcept
bool hasAdditionalInfo() const noexcept
UA_ExpandedNodeId wrapper class.
static ExpandedNodeId parse(std::string_view str)
Parse ExpandedNodeId from its string representation.
bool operator<=(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
uint32_t hash() const noexcept
ExpandedNodeId(NodeId id) noexcept
ExpandedNodeId(NodeId id, std::string_view namespaceUri, uint32_t serverIndex)
bool operator>=(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
bool isLocal() const noexcept
bool operator!=(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
uint32_t serverIndex() const noexcept
bool operator<(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
std::string_view namespaceUri() const
const NodeId & nodeId() const noexcept
NodeId & nodeId() noexcept
bool operator>(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
bool operator==(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
UA_ExtensionObject wrapper class.
bool isDecoded() const noexcept
Check if the ExtensionObject is decoded.
ExtensionObject(T *ptr, const UA_DataType &type) noexcept
Create ExtensionObject from a pointer to a decoded object with a custom data type (no copy).
const UA_DataType * decodedType() const noexcept
Get the decoded data type.
const XmlElement * encodedXml() const noexcept
Get the encoded body in XML format.
T * decodedData() noexcept
Get pointer to the decoded data with given template type.
ExtensionObject(T *ptr) noexcept
Create ExtensionObject from a pointer to a decoded object (no copy).
bool empty() const noexcept
Check if the ExtensionObject is empty.
ExtensionObject(const T &decoded)
Create ExtensionObject from a decoded object (copy).
const NodeId * encodedTypeId() const noexcept
Get the encoded type id.
void * decodedData() noexcept
Get pointer to the decoded data.
const T * decodedData() const noexcept
Get const pointer to the decoded data with given template type.
bool isEncoded() const noexcept
Check if the ExtensionObject is encoded (usually if the data type is unknown).
ExtensionObject(const T &decoded, const UA_DataType &type)
Create ExtensionObject from a decoded object with a custom data type (copy).
const ByteString * encodedBinary() const noexcept
Get the encoded body in binary format.
ExtensionObjectEncoding encoding() const noexcept
Get the encoding.
const void * decodedData() const noexcept
Get pointer to the decoded data.
Guid(uint32_t data1, uint16_t data2, uint16_t data3, std::array< uint8_t, 8 > data4) noexcept
Guid(std::array< uint8_t, 16 > data) noexcept
bool operator==(const UA_Guid &lhs, const UA_Guid &rhs) noexcept
static Guid parse(std::string_view str)
Parse Guid from its string representation.
bool operator!=(const UA_Guid &lhs, const UA_Guid &rhs) noexcept
static Guid random() noexcept
Generate random Guid.
UA_LocalizedText wrapper class.
bool operator==(const UA_LocalizedText &lhs, const UA_LocalizedText &rhs) noexcept
std::string_view text() const noexcept
std::string_view locale() const noexcept
bool operator!=(const UA_LocalizedText &lhs, const UA_LocalizedText &rhs) noexcept
LocalizedText(std::string_view locale, std::string_view text)
const T & identifier() const
Get identifier reference.
NodeId(T identifier) noexcept
Create NodeId from enum class with numeric identifiers like opcua::ObjectId.
NodeIdType identifierType() const noexcept
static NodeId parse(std::string_view str)
Parse NodeId from its string representation.
NamespaceIndex namespaceIndex() const noexcept
NodeId(NamespaceIndex namespaceIndex, uint32_t identifier) noexcept
Create NodeId with numeric identifier.
NodeId(NamespaceIndex namespaceIndex, ByteString identifier) noexcept
Create NodeId with ByteString identifier.
bool operator!=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
bool operator<(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
bool operator>(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
NodeId(NamespaceIndex namespaceIndex, Guid identifier) noexcept
Create NodeId with Guid identifier.
const T * identifierIf() const noexcept
Get identifier pointer or nullptr on error.
bool operator==(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
bool isNull() const noexcept
bool operator>=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
bool operator<=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
T * identifierIf() noexcept
Get identifier pointer or nullptr on error.
T & identifier()
Get identifier reference.
uint32_t hash() const noexcept
NodeId(NamespaceIndex namespaceIndex, std::string_view identifier)
Create NodeId with String identifier.
UA_NumericRange wrapper class.
bool empty() const noexcept
NumericRange(UA_NumericRange &&native) noexcept
Create a NumericRange from native object (move).
NumericRange(std::string_view encodedRange)
Create a NumericRange from the encoded representation, e.g. 1:2,0:3,5.
bool operator!=(const NumericRangeDimension &lhs, const NumericRangeDimension &rhs) noexcept
NumericRange(const char *encodedRange)
This is an overloaded member function, provided for convenience. It differs from the above function o...
NumericRange(Span< const NumericRangeDimension > dimensions)
Create a NumericRange from dimensions.
Span< const NumericRangeDimension > dimensions() const noexcept
NumericRange(const NumericRange &other)
NumericRange(NumericRange &&other) noexcept
NumericRange(const UA_NumericRange &native)
Create a NumericRange from native object (copy).
NumericRange & operator=(const NumericRange &other)
NumericRange & operator=(NumericRange &&other) noexcept
UA_QualifiedName wrapper class.
bool operator!=(const UA_QualifiedName &lhs, const UA_QualifiedName &rhs) noexcept
bool operator==(const UA_QualifiedName &lhs, const UA_QualifiedName &rhs) noexcept
NamespaceIndex namespaceIndex() const noexcept
QualifiedName(NamespaceIndex namespaceIndex, std::string_view name)
std::string_view name() const noexcept
View to a contiguous sequence of objects, similar to std::span in C++20.
constexpr iterator begin() const noexcept
constexpr iterator end() const noexcept
UA_StatusCode wrapper class.
constexpr void throwIfBad() const
Throw a BadStatus exception if the status code is bad.
constexpr bool isUncertain() const noexcept
Check if the status code is uncertain.
constexpr bool isBad() const noexcept
Check if the status code is bad.
std::string_view name() const noexcept
Get human-readable name of the StatusCode.
constexpr bool isGood() const noexcept
Check if the status code is good.
constexpr UA_StatusCode get() const noexcept
Explicitly get underlying UA_StatusCode.
constexpr StatusCode() noexcept=default
Create StatusCode with the default code UA_STATUSCODE_GOOD.
String & operator=(std::basic_string_view< char, Traits > str)
Assign std::string_view.
bool operator!=(const String &lhs, const String &rhs) noexcept
bool operator==(std::string_view lhs, const String &rhs) noexcept
bool operator==(const String &lhs, std::string_view rhs) noexcept
String(InputIt first, InputIt last)
bool operator==(const String &lhs, const String &rhs) noexcept
String & operator=(const char *str)
Assign null-termined character string.
bool operator!=(const String &lhs, std::string_view rhs) noexcept
bool operator!=(std::string_view lhs, const String &rhs) noexcept
String(std::string_view str)
std::ostream & operator<<(std::ostream &os, const String &str)
bool operator!=(const UA_String &lhs, const UA_String &rhs) noexcept
bool operator==(const UA_String &lhs, const UA_String &rhs) noexcept
Exception for type-related errors.
UA_Variant wrapper class.
Variant(InputIt first, InputIt last, const UA_DataType &type)
Create Variant from a range of elements with a custom data type (copy).
void assign(T &&value)
Assign scalar/array to variant (copy/move and convert if required).
Variant(T &&value, const UA_DataType &type)
Create Variant from a scalar/array with a custom data type (copy/move).
void assign(T &&value, const UA_DataType &type)
Assign scalar/array to variant with custom data type (copy/move).
bool isType(const UA_DataType &type) const noexcept
Check if the variant type is equal to the provided data type.
const void * data() const noexcept
Get pointer to the underlying data.
void assign(InputIt first, InputIt last)
Assign range to variant (copy and convert if required).
Variant(InputIt first, InputIt last)
Create Variant from a range of elements (copy).
void assign(InputIt first, InputIt last, const UA_DataType &type)
Assign range to variant with custom data type (copy).
Variant(T *ptr, const UA_DataType &type) noexcept
Create Variant from a pointer to a scalar/array with a custom data type (no copy).
T to() const &
Converts the variant to the specified type T with automatic conversion if required.
const T & scalar() const &
Get scalar value with given template type (only native or wrapper types).
Variant & operator=(T *value) noexcept
Assign pointer to scalar/array to variant (no copy).
Span< T > array()
Get array with given template type (only native or wrapper types).
T scalar() &&
Get scalar value with given template type (only native or wrapper types).
Variant(T &&value)
Create Variant from a scalar/array (copy/move).
T scalar() const &&
Get scalar value with given template type (only native or wrapper types).
T & scalar() &
Get scalar value with given template type (only native or wrapper types).
bool isType(const UA_DataType *type) const noexcept
Check if the variant type is equal to the provided data type.
void assign(T *ptr) noexcept
Assign pointer to scalar/array to variant (no copy).
bool isType(const NodeId &id) const noexcept
Check if the variant type is equal to the provided data type id.
bool empty() const noexcept
Check if the variant is empty.
size_t arrayLength() const noexcept
Get array length or 0 if variant is not an array.
const UA_DataType * type() const noexcept
Get data type.
Variant(T *ptr) noexcept
Create Variant from a pointer to a scalar/array (no copy).
void assign(std::nullptr_t ptr, const UA_DataType &type) noexcept=delete
Span< const uint32_t > arrayDimensions() const noexcept
Get array dimensions.
bool isArray() const noexcept
Check if the variant is an array.
Span< const T > array() const
Get array with given template type (only native or wrapper types).
void assign(std::nullptr_t ptr) noexcept=delete
void assign(T *ptr, const UA_DataType &type) noexcept
Assign pointer to scalar/array to variant with custom data type (no copy).
Variant & operator=(T &&value)
Assign scalar/array to variant (copy and convert if required).
bool isScalar() const noexcept
Check if the variant is a scalar.
bool isType() const noexcept
Check if the variant type is equal to the provided template type.
T to() &&
Converts the variant to the specified type T with automatic conversion if required.
void * data() noexcept
Get pointer to the underlying data.
Template base class to wrap (native) objects.
constexpr T * handle() noexcept
Return pointer to native object.
constexpr const UA_StatusCode & native() const noexcept
constexpr Wrapper() noexcept=default
constexpr void clear() noexcept
UA_XmlElement wrapper class.
XmlElement(std::string_view str)
XmlElement & operator=(std::basic_string_view< char, Traits > str)
Assign std::string_view.
XmlElement(InputIt first, InputIt last)
XmlElement & operator=(const char *str)
Assign null-termined character string.
constexpr Namespace namespaceOf(DataTypeId) noexcept
Get namespace of DataTypeId.
String toString(const T &object)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool operator<=(const T &lhs, const T &rhs) noexcept
constexpr T::NativeType * asNative(T *wrapper) noexcept
Cast Wrapper object pointers to native object pointers.
bool operator<(const T &lhs, const T &rhs) noexcept
bool operator==(const T &lhs, const T &rhs) noexcept
bool operator>=(const T &lhs, const T &rhs) noexcept
bool operator!=(const T &lhs, const T &rhs) noexcept
bool operator>(const T &lhs, const T &rhs) noexcept
String toString(const T &object, const UA_DataType &type)
Converts an object to its string representation.
uint16_t NamespaceIndex
Namespace index.
ExtensionObjectEncoding
Extension object encoding.
String toString(const NumericRange &range)
constexpr void throwIfBad(UA_StatusCode code)
Check the status code and throw a BadStatus exception if the status code is bad.
const UA_DataType & getDataType() noexcept
UA_NumericRangeDimension * dimensions
static String toNative(const T &src)
static T fromNative(const String &src)
static String toNative(const char(&src)[N])
static String toNative(const char *src)
static TimePoint fromNative(const DateTime &src)
std::chrono::time_point< std::chrono::system_clock, Duration > TimePoint
static DateTime toNative(const TimePoint &src)
Type conversion from and to native types.
std::size_t operator()(const opcua::ExpandedNodeId &id) const noexcept
std::size_t operator()(const opcua::NodeId &id) const noexcept
#define UAPP_TYPEREGISTRY_NATIVE(NativeType, typeIndex)
UA_UInt32 UA_NodeId_hash(const UA_NodeId *n)
UA_EXTENSIONOBJECT_ENCODED_XML
UA_EXTENSIONOBJECT_ENCODED_BYTESTRING
UA_EXTENSIONOBJECT_ENCODED_NOBODY
UA_EXTENSIONOBJECT_DECODED
UA_EXTENSIONOBJECT_DECODED_NODELETE
UA_UInt32 UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n)
UA_Order UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2)
#define UA_DATETIME_UNIX_EPOCH
UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t)
UA_Order UA_order(const void *p1, const void *p2, const UA_DataType *type)
UA_Boolean UA_NodeId_isNull(const UA_NodeId *p)
UA_EXPORT const char * UA_StatusCode_name(UA_StatusCode code)
UA_Order UA_ExpandedNodeId_order(const UA_ExpandedNodeId *n1, const UA_ExpandedNodeId *n2)
UA_DateTime UA_DateTime_now(void)
UA_Int64 UA_DateTime_localTimeUtcOffset(void)
UA_Guid UA_Guid_random(void)