9#include <initializer_list>
22#include "open62541pp/config.hpp"
64 std::string_view
name() const noexcept {
69 constexpr bool isGood() const noexcept {
70 return detail::isGood(
native());
75 return detail::isUncertain(
native());
79 constexpr bool isBad() const noexcept {
80 return detail::isBad(
native());
97template <
typename WrapperType,
typename CharT>
98class StringLikeMixin {
101 using value_type = CharT;
102 using size_type = size_t;
103 using difference_type = std::ptrdiff_t;
104 using pointer = value_type*;
105 using const_pointer =
const value_type*;
106 using reference = value_type&;
107 using const_reference =
const value_type&;
108 using iterator = pointer;
109 using const_iterator = const_pointer;
110 using reverse_iterator = std::reverse_iterator<iterator>;
111 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
114 size_t size() const noexcept {
115 const auto& native = asNative(
static_cast<const WrapperType&
>(*
this));
116 return native.length;
119 size_t length() const noexcept {
123 bool empty() const noexcept {
127 pointer data() noexcept {
128 auto& native = asNative(
static_cast<WrapperType&
>(*
this));
129 return reinterpret_cast<pointer
>(native.data);
132 const_pointer data() const noexcept {
133 const auto& native = asNative(
static_cast<const WrapperType&
>(*
this));
134 return reinterpret_cast<const_pointer
>(native.data);
137 reference operator[](
size_t index)
noexcept {
138 assert(index < size());
139 return data()[index];
142 const_reference operator[](
size_t index)
const noexcept {
143 assert(index < size());
144 return data()[index];
147 reference front() noexcept {
152 const_reference front() const noexcept {
157 reference back() noexcept {
159 return *(data() + size() - 1);
162 const_reference back() const noexcept {
164 return *(data() + size() - 1);
167 iterator begin() noexcept {
171 const_iterator begin() const noexcept {
175 const_iterator cbegin() const noexcept {
179 iterator end() noexcept {
180 return {data() + size()};
183 const_iterator end() const noexcept {
184 return {data() + size()};
187 const_iterator cend() const noexcept {
188 return {data() + size()};
191 reverse_iterator rbegin() noexcept {
192 return reverse_iterator(end());
195 const_reverse_iterator rbegin() const noexcept {
196 return const_reverse_iterator(end());
199 const_reverse_iterator crbegin() const noexcept {
200 return const_reverse_iterator(cend());
203 reverse_iterator rend() noexcept {
204 return reverse_iterator(begin());
207 const_reverse_iterator rend() const noexcept {
208 return const_reverse_iterator(begin());
211 const_reverse_iterator crend() const noexcept {
212 return const_reverse_iterator(cbegin());
216 void init(
size_t length) {
217 auto& native = asNative(
static_cast<WrapperType&
>(*
this));
218 native.length = length;
220 native.data =
static_cast<uint8_t*
>(
UA_malloc(length));
221 if (data() ==
nullptr) {
222 throw BadStatus(UA_STATUSCODE_BADOUTOFMEMORY);
227 template <
typename InputIt>
228 void init(InputIt first, InputIt last) {
229 init(first, last,
typename std::iterator_traits<InputIt>::iterator_category{});
232 template <
typename InputIt,
typename Tag>
233 void init(InputIt first, InputIt last, Tag ) {
234 init(std::distance(first, last));
235 std::copy(first, last, data());
238 template <
typename InputIt>
239 void init(InputIt first, InputIt last, std::input_iterator_tag ) {
241 std::vector<uint8_t> buffer(first, last);
243 std::copy(buffer.begin(), buffer.end(), data());
257 public detail::StringLikeMixin<String, char> {
264 template <
typename InputIt>
269 String(std::initializer_list<char> values) {
270 init(values.begin(), values.end());
280 template <
typename Traits>
287 template <
typename Traits>
288 operator std::basic_string_view<char, Traits>() const noexcept {
289 return {data(), size()};
293 [[deprecated(
"use conversion with static_cast instead")]]
294 std::string_view
get() const noexcept {
295 return {data(), size()};
306 return !(lhs == rhs);
311 return asNative(lhs) == asNative(rhs);
316 return !(lhs == rhs);
321 return static_cast<std::string_view
>(lhs) == rhs;
326 return static_cast<std::string_view
>(lhs) != rhs;
331 return lhs ==
static_cast<std::string_view
>(rhs);
336 return lhs !=
static_cast<std::string_view
>(rhs);
342template <
typename Traits>
344 using Type = std::basic_string_view<char, Traits>;
348 dst =
Type{src.data(), src.size()};
356template <
typename Traits,
typename Allocator>
358 using Type = std::basic_string<char, Traits, Allocator>;
362 dst =
Type{src.data(), src.size()};
386 dst =
NativeType{std::string_view{
static_cast<const char*
>(src), N}};
404 using UaDuration = std::chrono::duration<int64_t, std::ratio<1, 10'000'000>>;
408 template <
typename Clock,
typename Duration>
409 DateTime(std::chrono::time_point<Clock, Duration> timePoint)
418 template <
typename Clock,
typename Duration>
422 std::chrono::duration_cast<UaDuration>(timePoint.time_since_epoch()).count()
428 return DateTime(UA_DateTime_fromUnixTime(unixTime));
437 template <
typename Clock = DefaultClock,
typename Duration = UaDuration>
439 const std::chrono::time_point<Clock, Duration> unixEpoch{};
444 return unixEpoch + std::chrono::duration_cast<Duration>(sinceEpoch);
452 return UA_DateTime_toUnixTime(
get());
461 int64_t
get() const noexcept {
467 std::string
format(std::string_view
format,
bool localtime =
false)
const;
470template <
typename Clock,
typename Duration>
472 using Type = std::chrono::time_point<Clock, Duration>;
495 explicit Guid(std::array<uint8_t, 16> data) noexcept
498 static_cast<uint32_t
>(
499 (data[0] << 24U) | (data[1] << 16U) | (data[2] << 8U) | data[3]
501 static_cast<uint16_t
>((data[4] << 8U) | data[5]),
502 static_cast<uint16_t
>((data[6] << 8U) | data[7]),
504 {data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]},
507 Guid(uint32_t data1, uint16_t data2, uint16_t data3, std::array<uint8_t, 8> data4) noexcept
512 {data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], data4[7]},
531 [[deprecated(
"use free function toString instead")]]
542 return !(lhs == rhs);
552 :
public TypeWrapper<UA_ByteString, UA_TYPES_BYTESTRING>,
553 public detail::StringLikeMixin<ByteString, uint8_t> {
567 template <
typename InputIt>
577 template <
typename Traits>
578 explicit operator std::basic_string_view<char, Traits>() const noexcept {
579 return {
reinterpret_cast<const char*
>(data()), size()};
587 [[deprecated(
"use conversion with static_cast instead")]]
588 std::string_view
get() const noexcept {
589 return {
reinterpret_cast<const char*
>(data()), size()};
600 :
public TypeWrapper<UA_XmlElement, UA_TYPES_XMLELEMENT>,
601 public detail::StringLikeMixin<XmlElement, char> {
608 template <
typename InputIt>
620 template <
typename Traits>
627 template <
typename Traits>
628 operator std::basic_string_view<char, Traits>() const noexcept {
629 return {data(), size()};
633 [[deprecated(
"use conversion with static_cast instead")]]
634 std::string_view
get() const noexcept {
635 return {data(), size()};
642template <
typename T,
typename =
void>
643struct IsNodeIdEnum : std::false_type {};
646struct IsNodeIdEnum<T, std::void_t<decltype(namespaceOf(std::declval<T>()))>> : std::is_enum<T> {};
695 handle()->identifier.byteString = {};
702 template <typename T, typename = std::enable_if_t<detail::IsNodeIdEnum<T>::value>>
721 uint32_t
hash() const noexcept {
726 return handle()->namespaceIndex;
730 [[deprecated(
"use namespaceIndex() instead")]]
740 [[deprecated(
"use identifierType() instead")]]
755 template <
typename T>
757 return const_cast<T*
>(std::as_const(*this).identifierIf<T>());
761 template <
typename T>
764 detail::IsOneOf<T, uint32_t, String, Guid, ByteString>::value,
765 "Invalid type for NodeId identifier"
768 if constexpr (std::is_same_v<T, uint32_t>) {
770 ? &
handle()->identifier.numeric
772 }
else if constexpr (std::is_same_v<T, String>) {
776 }
else if constexpr (std::is_same_v<T, Guid>) {
780 }
else if constexpr (std::is_same_v<T, ByteString>) {
800 template <
typename T>
802 return const_cast<T&
>(std::as_const(*this).identifier<T>());
806 template <
typename T>
808 if (
auto* ptr = identifierIf<T>()) {
811 throw TypeError(
"NodeId identifier type doesn't match the requested type");
816 [[deprecated(
"use identifier<T>() or identifierIf<T>() instead")]]
818 return getIdentifierImpl();
823 template <
typename T>
824 [[deprecated(
"use identifier<T>() or identifierIf<T>() instead")]]
826 return getIdentifierAsImpl<T>();
831 template <NodeIdType E>
832 [[deprecated(
"use identifier<T>() or identifierIf<T>() instead")]]
834 return getIdentifierAsImpl<E>();
838 [[deprecated(
"use free function toString instead")]]
842 std::variant<uint32_t, String, Guid, ByteString> getIdentifierImpl()
const {
845 return handle()->identifier.numeric;
857 template <
typename T>
858 auto getIdentifierAsImpl()
const {
859 return std::get<T>(getIdentifierImpl());
862 template <NodeIdType E>
863 auto getIdentifierAsImpl()
const {
865 return getIdentifierAsImpl<uint32_t>();
867 return getIdentifierAsImpl<String>();
869 return getIdentifierAsImpl<Guid>();
871 return getIdentifierAsImpl<ByteString>();
878 return UA_NodeId_equal(&lhs, &rhs);
883 return !(lhs == rhs);
898 return (lhs < rhs) || (lhs == rhs);
903 return (lhs > rhs) || (lhs == rhs);
934 throwIfBad(UA_ExpandedNodeId_parse(
id.
handle(), detail::toNativeString(str)));
940 return handle()->serverIndex == 0;
943 uint32_t
hash() const noexcept {
956 [[deprecated(
"use nodeId() instead")]]
962 [[deprecated(
"use nodeId() instead")]]
972 [[deprecated(
"use namespaceUri() instead")]]
978 return handle()->serverIndex;
982 [[deprecated(
"use serverIndex() instead")]]
988 [[deprecated(
"use free function toString instead")]]
994 return UA_ExpandedNodeId_equal(&lhs, &rhs);
999 return !(lhs == rhs);
1014 return (lhs < rhs) || (lhs == rhs);
1019 return (lhs > rhs) || (lhs == rhs);
1034 handle()->name = detail::allocNativeString(
name);
1038 return handle()->namespaceIndex;
1042 [[deprecated(
"use namespaceIndex() instead")]]
1047 std::string_view
name() const noexcept {
1052 [[deprecated(
"use name() instead")]]
1060 return (lhs.namespaceIndex == rhs.namespaceIndex) && (lhs.name == rhs.name);
1065 return !(lhs == rhs);
1085 handle()->text = detail::allocNativeString(
text);
1093 [[deprecated(
"use locale() instead")]]
1098 std::string_view
text() const noexcept {
1103 [[deprecated(
"use text() instead")]]
1111 return (lhs.locale == rhs.locale) && (lhs.text == rhs.text);
1116 return !(lhs == rhs);
1135 using TypeError::TypeError;
1195 template <
typename T>
1196 static constexpr bool isVariant =
1197 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
Variant> ||
1198 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
UA_Variant>;
1205 template <
typename T,
typename = std::enable_if_t<!std::is_const_v<T>>>
1212 template <
typename T,
typename = std::enable_if_t<!std::is_const_v<T>>>
1219 template <
typename T,
typename = std::enable_if_t<!isVariant<T>>>
1226 template <
typename T>
1233 template <
typename InputIt>
1240 template <
typename InputIt>
1247 [[deprecated(
"use new universal Variant constructor instead")]] [[nodiscard]]
1250 return Variant{std::forward<T>(value), std::forward<Args>(
args)...};
1252 return Variant{&value, std::forward<Args>(
args)...};
1258 [[deprecated(
"use new universal Variant constructor instead")]] [[nodiscard]]
1269 [[deprecated(
"use new universal Variant constructor instead")]] [[nodiscard]]
1271 return Variant{first, last, std::forward<Args>(
args)...};
1280 void assign(std::nullptr_t ptr)
noexcept =
delete;
1293 template <
typename T,
typename = std::enable_if_t<!std::is_const_v<T>>>
1295 if constexpr (isArrayType<T>()) {
1296 using ValueType = detail::RangeValueT<T>;
1297 assertIsRegistered<ValueType>();
1298 assign(ptr, opcua::getDataType<ValueType>());
1300 assertIsRegistered<T>();
1301 assign(ptr, opcua::getDataType<T>());
1310 template <
typename T,
typename = std::enable_if_t<!std::is_const_v<T>>>
1312 if (ptr ==
nullptr) {
1314 }
else if constexpr (isArrayType<T>()) {
1328 template <
typename T>
1330 if constexpr (isArrayType<T>()) {
1331 assign(std::begin(value), std::end(value));
1333 assertIsRegisteredOrConvertible<T>();
1334 if constexpr (detail::IsRegistered<T>::value) {
1335 setScalarCopyImpl(value, opcua::getDataType<T>());
1337 setScalarCopyConvertImpl(value);
1350 template <
typename T>
1352 if constexpr (isArrayType<T>()) {
1353 setArrayCopyImpl(std::begin(value), std::end(value),
type);
1355 setScalarCopyImpl(value,
type);
1365 template <
typename InputIt>
1367 using ValueType =
typename std::iterator_traits<InputIt>::value_type;
1368 assertIsRegisteredOrConvertible<ValueType>();
1369 if constexpr (detail::IsRegistered<ValueType>::value) {
1370 setArrayCopyImpl(first, last, opcua::getDataType<ValueType>());
1372 setArrayCopyConvertImpl(first, last);
1383 template <
typename InputIt>
1385 setArrayCopyImpl(first, last,
type);
1390 template <
typename T,
typename = std::enable_if_t<!isVariant<T>>>
1398 template <
typename T,
typename = std::enable_if_t<!isVariant<T>>>
1405 template <
typename T,
typename... Args>
1406 [[deprecated(
"use assign overload with pointer instead")]]
1412 template <
typename T,
typename... Args>
1413 [[deprecated(
"use assign overload instead")]]
1419 template <
typename T,
typename... Args>
1420 [[deprecated(
"use assign overload with pointer instead")]]
1426 template <
typename T,
typename... Args>
1427 [[deprecated(
"use assign overload instead")]]
1433 template <
typename InputIt,
typename... Args>
1434 [[deprecated(
"use assign overload instead")]]
1436 assign(first, last, std::forward<Args>(
args)...);
1446 return handle()->type ==
nullptr;
1450 [[deprecated(
"use empty() instead")]]
1486 template <
typename T>
1488 return isType(opcua::getDataType<T>());
1497 [[deprecated(
"use type() instead")]]
1504 return handle()->arrayLength;
1508 [[deprecated(
"use arrayLength() instead")]]
1515 return {
handle()->arrayDimensions,
handle()->arrayDimensionsSize};
1519 [[deprecated(
"use arrayDimensions() instead")]]
1538 const void*
data() const noexcept {
1544 template <
typename T>
1546 assertIsRegistered<T>();
1549 return *
static_cast<T*
>(
handle()->data);
1553 template <
typename T>
1555 assertIsRegistered<T>();
1558 return *
static_cast<const T*
>(
handle()->data);
1562 template <
typename T>
1564 return std::move(scalar<T>());
1568 template <
typename T>
1570 return std::move(scalar<T>());
1574 template <
typename T>
1575 [[deprecated(
"use scalar() instead")]]
1581 template <
typename T>
1582 [[deprecated(
"use scalar() instead")]]
1588 template <
typename T>
1589 [[deprecated(
"use to<T>() instead")]]
1596 template <
typename T>
1598 assertIsRegistered<T>();
1606 template <
typename T>
1608 assertIsRegistered<T>();
1615 template <
typename T>
1616 [[deprecated(
"use array() instead")]]
1622 template <
typename T>
1623 [[deprecated(
"use array() instead")]]
1629 template <
typename T>
1630 [[deprecated(
"use to<std::vector<T>>() instead")]]
1632 return to<std::vector<T>>();
1658 template <
typename T>
1659 [[nodiscard]] T
to()
const {
1660 if constexpr (isArrayType<T>()) {
1661 return toArrayImpl<T>();
1663 return toScalarImpl<T>();
1672 template <
typename T>
1673 static constexpr bool isScalarType() noexcept {
1674 return detail::IsRegistered<T>::value || detail::IsConvertible<T>::value;
1677 template <
typename T>
1678 static constexpr bool isArrayType() noexcept {
1679 return detail::IsRange<T>::value && !isScalarType<T>();
1682 template <
typename T>
1683 static constexpr void assertIsRegistered() {
1685 detail::IsRegistered<T>::value,
1686 "Template type must be a native/wrapper type to assign or get scalar/array without copy"
1690 template <
typename T>
1691 static constexpr void assertIsRegisteredOrConvertible() {
1693 detail::IsRegistered<T>::value || detail::IsConvertible<T>::value,
1694 "Template type must be either a native/wrapper type or a convertible type. "
1695 "If the type is a native type: Provide the type definition (UA_DataType) manually or "
1696 "register the type with a TypeRegistry template specialization. "
1697 "If the type should be converted: Add a template specialization for TypeConverter."
1701 template <
typename T>
1702 static constexpr void assertNoVariant() {
1703 static_assert(!isVariant<T>,
"Variants cannot directly contain another variant");
1706 void checkIsScalar()
const {
1708 throw BadVariantAccess(
"Variant is not a scalar");
1712 void checkIsArray()
const {
1714 throw BadVariantAccess(
"Variant is not an array");
1718 template <
typename T>
1719 void checkIsType()
const {
1720 const auto* dt =
type();
1721 if (dt ==
nullptr || dt->typeId != opcua::getDataType<T>().typeId) {
1722 throw BadVariantAccess(
"Variant does not contain a value convertible to template type");
1726 template <
typename T>
1727 T toScalarImpl()
const;
1728 template <
typename T>
1729 T toArrayImpl()
const;
1731 template <
typename T>
1732 inline void setScalarImpl(
1735 template <
typename T>
1736 inline void setArrayImpl(
1739 template <
typename T>
1740 inline void setScalarCopyImpl(
const T& value,
const UA_DataType&
type);
1741 template <
typename T>
1742 inline void setScalarCopyConvertImpl(
const T& value);
1743 template <
typename InputIt>
1744 inline void setArrayCopyImpl(InputIt first, InputIt last,
const UA_DataType&
type);
1745 template <
typename InputIt>
1746 inline void setArrayCopyConvertImpl(InputIt first, InputIt last);
1749template <
typename T>
1750T Variant::toScalarImpl()
const {
1751 assertIsRegisteredOrConvertible<T>();
1752 if constexpr (detail::IsRegistered<T>::value) {
1755 using Native =
typename TypeConverter<T>::NativeType;
1756 return detail::fromNative<T>(scalar<Native>());
1760template <
typename T>
1761T Variant::toArrayImpl()
const {
1762 using ValueType =
typename T::value_type;
1763 assertIsRegisteredOrConvertible<ValueType>();
1764 if constexpr (detail::IsRegistered<ValueType>::value) {
1765 auto native = array<ValueType>();
1768 using Native =
typename TypeConverter<ValueType>::NativeType;
1769 auto native = array<Native>();
1771 detail::TransformIterator(
native.begin(), detail::fromNative<ValueType>),
1772 detail::TransformIterator(
native.end(), detail::fromNative<ValueType>)
1777template <
typename T>
1778void Variant::setScalarImpl(
1781 assertNoVariant<T>();
1782 assert(
sizeof(T) == type.memSize);
1784 handle()->type = &type;
1785 handle()->storageType = storageType;
1786 handle()->data = data;
1789template <
typename T>
1790void Variant::setArrayImpl(
1793 assertNoVariant<T>();
1794 assert(
sizeof(T) == type.memSize);
1796 handle()->type = &type;
1797 handle()->storageType = storageType;
1798 handle()->data = data;
1799 handle()->arrayLength = arrayLength;
1802template <
typename T>
1803void Variant::setScalarCopyImpl(
const T& value,
const UA_DataType& type) {
1804 auto native = detail::allocateUniquePtr<T>(
type);
1806 setScalarImpl(
native.release(),
type, UA_VARIANT_DATA);
1809template <
typename T>
1810void Variant::setScalarCopyConvertImpl(
const T& value) {
1811 using Native =
typename TypeConverter<T>::NativeType;
1812 const auto&
type = opcua::getDataType<Native>();
1813 auto native = detail::allocateUniquePtr<Native>(
type);
1814 *
native = detail::toNative(value);
1815 setScalarImpl(
native.release(),
type, UA_VARIANT_DATA);
1818template <
typename InputIt>
1819void Variant::setArrayCopyImpl(InputIt first, InputIt last,
const UA_DataType& type) {
1820 using ValueType =
typename std::iterator_traits<InputIt>::value_type;
1821 const size_t size = std::distance(first, last);
1822 auto native = detail::allocateArrayUniquePtr<ValueType>(size,
type);
1823 std::transform(first, last,
native.get(), [&](
const ValueType& value) {
1824 return detail::copy(value, type);
1826 setArrayImpl(
native.release(), size,
type, UA_VARIANT_DATA);
1829template <
typename InputIt>
1830void Variant::setArrayCopyConvertImpl(InputIt first, InputIt last) {
1831 using ValueType =
typename std::iterator_traits<InputIt>::value_type;
1832 using Native =
typename TypeConverter<ValueType>::NativeType;
1833 const auto&
type = opcua::getDataType<Native>();
1834 const size_t size = std::distance(first, last);
1835 auto native = detail::allocateArrayUniquePtr<Native>(size,
type);
1836 std::transform(first, last,
native.get(), [&](
const ValueType& value) {
1837 return detail::toNative(value);
1839 setArrayImpl(
native.release(), size,
type, UA_VARIANT_DATA);
1863 std::optional<StatusCode>
status
1886 [[deprecated(
"use constructor with new universal Variant constructor instead")]] [[nodiscard]]
1888 return DataValue(Variant::fromScalar<Policy>(std::forward<Args>(
args)...));
1896 [[deprecated(
"use constructor with new universal Variant constructor instead")]] [[nodiscard]]
1898 return DataValue(Variant::fromArray<Policy>(std::forward<Args>(
args)...));
1904 handle()->hasValue =
true;
1910 handle()->hasValue =
true;
1916 handle()->hasSourceTimestamp =
true;
1922 handle()->hasServerTimestamp =
true;
1928 handle()->hasSourcePicoseconds =
true;
1934 handle()->hasServerPicoseconds =
true;
1940 handle()->hasStatus =
true;
1944 return handle()->hasValue;
1948 return handle()->hasSourceTimestamp;
1952 return handle()->hasServerTimestamp;
1956 return handle()->hasSourcePicoseconds;
1960 return handle()->hasServerPicoseconds;
1964 return handle()->hasStatus;
1979 return std::move(
value());
1984 return std::move(
value());
1988 [[deprecated(
"use value() instead")]]
1994 [[deprecated(
"use value() instead")]]
2000 [[deprecated(
"use value() instead")]]
2002 return std::move(
value());
2006 [[deprecated(
"use value() instead")]]
2008 return std::move(
value());
2017 [[deprecated(
"use sourceTimestamp() instead")]]
2028 [[deprecated(
"use serverTimestamp() instead")]]
2035 return handle()->sourcePicoseconds;
2039 [[deprecated(
"use sourcePicoseconds() instead")]]
2046 return handle()->serverPicoseconds;
2050 [[deprecated(
"use serverPicoseconds() instead")]]
2061 [[deprecated(
"use status() instead")]]
2096 template <
typename T>
2097 static constexpr bool isExtensionObject =
2098 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
ExtensionObject> ||
2109 template <
typename T>
2119 template <
typename T>
2121 if (ptr ==
nullptr) {
2124 assert(
sizeof(T) == type.memSize);
2126 handle()->content.decoded.type = &type;
2127 handle()->content.decoded.data = ptr;
2134 template <
typename T,
typename = std::enable_if_t<!isExtensionObject<T>>>
2143 template <
typename T,
typename = std::enable_if_t<!isExtensionObject<T>>>
2145 auto ptr = detail::allocateUniquePtr<T>(type);
2146 *ptr = detail::copy(decoded, type);
2148 handle()->content.decoded.type = &type;
2149 handle()->content.decoded.data = ptr.release();
2153 template <
typename T,
typename... Args>
2154 [[deprecated(
"use new universal ExtensionObject constructor instead")]] [[nodiscard]]
2160 template <
typename T,
typename... Args>
2161 [[deprecated(
"use new universal ExtensionObject constructor instead")]] [[nodiscard]]
2172 [[deprecated(
"use empty() instead")]]
2195 [[deprecated(
"use encoding() instead")]]
2204 ? asWrapper<NodeId>(&
handle()->content.encoded.typeId)
2209 [[deprecated(
"use encodedTypeId() instead")]]
2218 ? asWrapper<ByteString>(&
handle()->content.encoded.body)
2226 ? asWrapper<XmlElement>(&
handle()->content.encoded.body)
2231 [[deprecated(
"use encodedBinary() or encodedXml() instead")]]
2234 ? asWrapper<ByteString>(&
handle()->content.encoded.body)
2242 ?
handle()->content.decoded.type
2247 [[deprecated(
"use decodedType() instead")]]
2255 template <
typename T>
2257 return isDecodedType<T>() ?
static_cast<T*
>(
decodedData()) :
nullptr;
2263 template <
typename T>
2265 return isDecodedType<T>() ?
static_cast<const T*
>(
decodedData()) :
nullptr;
2269 template <
typename T>
2270 [[deprecated(
"use decodedData<T>() instead")]]
2272 return decodedData<T>();
2276 template <
typename T>
2277 [[deprecated(
"use decodedData<T>() instead")]]
2279 return decodedData<T>();
2287 ?
handle()->content.decoded.data
2296 ?
handle()->content.decoded.data
2301 [[deprecated(
"use decodedData() instead")]]
2307 [[deprecated(
"use decodedData() instead")]]
2313 template <
typename T>
2314 bool isDecodedType() const noexcept {
2316 return (type !=
nullptr) && (type->typeId == getDataType<T>().typeId);
2332 return handle()->hasSymbolicId;
2336 return handle()->hasNamespaceUri;
2340 return handle()->hasLocalizedText;
2344 return handle()->hasLocale;
2348 return handle()->hasAdditionalInfo;
2352 return handle()->hasInnerStatusCode;
2356 return handle()->hasInnerDiagnosticInfo;
2360 return handle()->symbolicId;
2364 [[deprecated(
"use symbolicId() instead")]]
2370 return handle()->namespaceUri;
2374 [[deprecated(
"use namespaceUri() instead")]]
2380 return handle()->localizedText;
2384 [[deprecated(
"use localizedText() instead")]]
2394 [[deprecated(
"use locale() instead")]]
2404 [[deprecated(
"use additionalInfo() instead")]]
2410 return handle()->innerStatusCode;
2414 [[deprecated(
"use innerStatusCode() instead")]]
2424 [[deprecated(
"use innerDiagnosticInfo() instead")]]
2438 return (lhs.min == rhs.min) && (lhs.max == rhs.max);
2445 return !(lhs == rhs);
2490 :
Wrapper(std::exchange(other.native(), {})) {}
2493 if (
this != &other) {
2501 if (
this != &other) {
2503 native() = std::exchange(other.native(), {});
2517 [[deprecated(
"use free function toString instead")]]
2521 void clear() noexcept {
2528 result.
dimensions = detail::copyArray(array, size);
2529 result.dimensionsSize = size;
2559template <
typename T>
2562 if constexpr (UAPP_HAS_TOSTRING) {
2573template <typename T, typename = std::enable_if_t<detail::IsRegistered<T>::value>>
2575 return toString(
object, getDataType<T>());
2590struct std::hash<
opcua::ExpandedNodeId> {
UA_ByteString wrapper class.
std::string_view get() const noexcept
ByteString(InputIt first, InputIt last)
ByteString(std::string_view str)
String toBase64() const
Convert to Base64 encoded string.
ByteString(Span< const uint8_t > bytes)
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
DateTime getServerTimestamp() const noexcept
DataValue(Variant value) noexcept
const Variant && getValue() const &&noexcept
uint16_t getServerPicoseconds() const 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.
const Variant & getValue() const &noexcept
Variant && value() &&noexcept
Get value (rvalue).
bool hasStatus() const noexcept
static DataValue fromScalar(Args &&... args)
Create DataValue from scalar value.
void setValue(Variant &&value) noexcept
Set value (move).
void setServerTimestamp(DateTime serverTimestamp) noexcept
Set server timestamp for the value.
Variant & getValue() &noexcept
static DataValue fromArray(Args &&... args)
Create DataValue from array.
StatusCode getStatus() const noexcept
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.
uint16_t getSourcePicoseconds() const noexcept
bool hasServerTimestamp() const noexcept
void setValue(const Variant &value)
Set value (copy).
Variant && getValue() &&noexcept
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.
DateTime getSourceTimestamp() const noexcept
UA_DateTime wrapper class.
int64_t get() const noexcept
Get DateTime value as 100 nanosecond intervals since January 1, 1601 (UTC).
UA_DateTimeStruct toStruct() const noexcept
Convert to UA_DateTimeStruct.
static DateTime fromUnixTime(int64_t unixTime) noexcept
Get DateTime from Unix time.
static DateTime now() noexcept
Get current DateTime.
static DateTime fromTimePoint(std::chrono::time_point< Clock, Duration > timePoint)
Get DateTime from std::chrono::time_point.
int64_t toUnixTime() const noexcept
Convert to Unix time (number of seconds since January 1, 1970 UTC).
static int64_t localTimeUtcOffset() noexcept
Offset of local time to UTC.
DateTime(std::chrono::time_point< Clock, Duration > timePoint)
std::chrono::duration< int64_t, std::ratio< 1, 10 '000 '000 > > UaDuration
std::string format(std::string_view format, bool localtime=false) const
Convert to string with given format (same format codes as strftime).
std::chrono::time_point< Clock, Duration > toTimePoint() const
Convert to std::chrono::time_point.
std::chrono::system_clock DefaultClock
UA_DiagnosticInfo wrapper class.
bool hasInnerStatusCode() const noexcept
bool hasLocalizedText() const noexcept
int32_t getSymbolicId() const noexcept
int32_t symbolicId() const noexcept
int32_t getNamespaceUri() 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
int32_t getLocalizedText() const noexcept
int32_t getLocale() const noexcept
const DiagnosticInfo * innerDiagnosticInfo() const noexcept
const String & getAdditionalInfo() const noexcept
int32_t namespaceUri() const noexcept
const DiagnosticInfo * getInnerDiagnosticInfo() const noexcept
StatusCode getInnerStatusCode() 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
const NodeId & getNodeId() const 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
std::string toString() const
bool operator<(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
std::string_view namespaceUri() const
uint32_t getServerIndex() const noexcept
const NodeId & nodeId() const noexcept
NodeId & nodeId() noexcept
NodeId & getNodeId() noexcept
bool operator>(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
std::string_view getNamespaceUri() const
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.
bool isEmpty() const noexcept
const UA_DataType * getDecodedDataType() const noexcept
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.
static ExtensionObject fromDecoded(T &data, Args &&... args) noexcept
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).
T * getDecodedData() noexcept
bool empty() const noexcept
Check if the ExtensionObject is empty.
const ByteString * getEncodedBody() const noexcept
ExtensionObject(const T &decoded)
Create ExtensionObject from a decoded object (copy).
const NodeId * encodedTypeId() const noexcept
Get the encoded type id.
const T * getDecodedData() const noexcept
const NodeId * getEncodedTypeId() const noexcept
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.
ExtensionObjectEncoding getEncoding() const noexcept
void * getDecodedData() noexcept
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 * getDecodedData() const noexcept
const void * decodedData() const noexcept
Get pointer to the decoded data.
static ExtensionObject fromDecodedCopy(const T &data, Args &&... args)
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
std::string toString() const
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
std::string_view getLocale() const noexcept
std::string_view getText() 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.
std::string toString() const
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
std::variant< uint32_t, String, Guid, ByteString > getIdentifier() const
Get identifier variant.
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.
auto getIdentifierAs() const
Get identifier by template type.
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.
NamespaceIndex getNamespaceIndex() const noexcept
NodeIdType getIdentifierType() const noexcept
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)
bool operator==(const NumericRangeDimension &lhs, const NumericRangeDimension &rhs) noexcept
NumericRange(NumericRange &&other) noexcept
NumericRange(const UA_NumericRange &native)
Create a NumericRange from native object (copy).
std::string toString() const
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
NamespaceIndex getNamespaceIndex() const 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
std::string_view getName() 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 a StatusCode with the default status code UA_STATUSCODE_GOOD.
String & operator=(std::basic_string_view< char, Traits > str)
Assign std::string_view.
String(std::initializer_list< char > values)
bool operator!=(const String &lhs, const String &rhs) noexcept
bool operator==(std::string_view lhs, const String &rhs) noexcept
std::string_view get() const 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.
Template base class to wrap UA_* type objects that require manual memory management.
constexpr TypeWrapper() noexcept=default
constexpr void clear() noexcept
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).
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).
T && scalar() &&
Get reference to scalar value with given template type (only native or wrapper types).
Variant(T *ptr, const UA_DataType &type) noexcept
Create Variant from a pointer to a scalar/array with a custom data type (no copy).
const UA_DataType * getDataType() const noexcept
const T & scalar() const &
Get reference to 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).
const T && scalar() const &&
Get reference to scalar value with given template type (only native or wrapper types).
void setScalar(T &value, Args &&... args) noexcept
Span< const uint32_t > getArrayDimensions() const noexcept
size_t getArrayLength() const noexcept
Span< T > array()
Get reference to array with given template type (only native or wrapper types).
static Variant fromArray(T &&array, Args &&... args)
void assign(const T &value)
Assign scalar/array to variant (copy and convert if required).
static Variant fromArray(InputIt first, InputIt last, Args &&... args)
T & scalar() &
Get reference to scalar value with given template type (only native or wrapper types).
std::vector< T > getArrayCopy() const
void setArrayCopy(InputIt first, InputIt last, Args &&... args)
bool isType(const UA_DataType *type) const noexcept
Check if the variant type is equal to the provided data type.
T to() const
Converts the variant to the specified type T with automatic conversion if required.
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 node id.
Span< const T > getArray() const
bool empty() const noexcept
Check if the variant is empty.
static Variant fromScalar(T &&value, Args &&... args)
Variant & operator=(const T &value)
Assign scalar/array to variant (copy and convert if required).
void setScalarCopy(const T &value, Args &&... args)
void setArray(T &array, Args &&... args) noexcept
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.
bool isEmpty() const noexcept
Variant(T *ptr) noexcept
Create Variant from a pointer to a scalar/array (no copy).
Variant(const T &value)
Create Variant from a scalar/array (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.
void setArrayCopy(const T &array, Args &&... args)
Variant(const T &value, const UA_DataType &type)
Create Variant from a scalar/array with a custom data type (copy).
Span< const T > array() const
Get reference to 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).
bool isScalar() const noexcept
Check if the variant is a scalar.
void assign(const T &value, const UA_DataType &type)
Assign scalar/array to variant with custom data type (copy).
bool isType() const noexcept
Check if the variant type is equal to the provided template type.
void * data() noexcept
Get pointer to the underlying data.
const T & getScalar() const
Template base class to wrap native objects.
constexpr const UA_StatusCode & native() const noexcept
constexpr T * handle() noexcept
Return pointer to native object.
constexpr Wrapper() noexcept=default
UA_XmlElement wrapper class.
std::string_view get() const noexcept
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...
String toString(const T &object, const UA_DataType &type)
Converts an object to its string representation.
static UA_LogCategory const char va_list args
uint16_t NamespaceIndex
Namespace index.
ExtensionObjectEncoding
Extension object encoding.
VariantPolicy
Policies for variant factory methods Variant::fromScalar, Variant::fromArray.
@ Copy
Store copy of scalar/array inside the variant.
@ Reference
Store reference to scalar/array inside the variant.
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 void toNative(const Type &src, NativeType &dst)
static void toNative(Type src, NativeType &dst)
std::basic_string< char, Traits, Allocator > Type
static void fromNative(const NativeType &src, Type &dst)
static void toNative(const Type &src, NativeType &dst)
std::basic_string_view< char, Traits > Type
static void toNative(Type src, NativeType &dst)
static void fromNative(const NativeType &src, Type &dst)
std::chrono::time_point< Clock, Duration > Type
static void fromNative(const NativeType &src, Type &dst)
static void toNative(const Type &src, NativeType &dst)
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
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_Boolean UA_String_equal(const UA_String *s1, const UA_String *s2)
#define UA_EMPTY_ARRAY_SENTINEL
UA_Guid UA_Guid_random(void)
UA_UInt32 UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n)
UA_Order UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2)
UA_StatusCode UA_print(const void *p, const UA_DataType *type, UA_String *output)
#define UA_DATETIME_UNIX_EPOCH
UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t)
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_Boolean UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2)
UA_Int64 UA_DateTime_localTimeUtcOffset(void)