open62541pp 0.19.0
C++ wrapper of open62541
Loading...
Searching...
No Matches
types.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm> // copy
4#include <array>
5#include <cassert>
6#include <chrono>
7#include <cstdint>
8#include <functional> // hash
9#include <initializer_list>
10#include <iosfwd> // forward declare ostream
11#include <iterator> // reverse_iterator
12#include <optional>
13#include <ratio>
14#include <string_view>
15#include <type_traits> // is_same_v
16#include <utility> // move
17#include <vector>
18
19#include "open62541pp/common.hpp" // NamespaceIndex
20#include "open62541pp/config.hpp"
21#include "open62541pp/detail/iterator.hpp" // TransformIterator
23#include "open62541pp/detail/string_utils.hpp" // allocNativeString
27#include "open62541pp/span.hpp"
31
32namespace opcua {
33
34/* ----------------------------------------- StatusCode ----------------------------------------- */
35
36/**
37 * UA_StatusCode wrapper class.
38 * StatusCode can be used interchangeably with @ref UA_StatusCode due to implicit conversions
39 * (without any overhead) but provides some methods to simplify the handling with status codes.
40 * @see statuscodes.h
41 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.39
42 * @ingroup Wrapper
43 */
44class StatusCode : public Wrapper<UA_StatusCode> {
45public:
46 /// Create a StatusCode with the default status code `UA_STATUSCODE_GOOD`.
47 constexpr StatusCode() noexcept = default;
48
49 constexpr StatusCode(UA_StatusCode code) noexcept // NOLINT(hicpp-explicit-conversions)
50 : Wrapper{code} {}
51
52 /// Explicitly get underlying UA_StatusCode.
53 constexpr UA_StatusCode get() const noexcept {
54 return native();
55 }
56
57 /// Get human-readable name of the StatusCode.
58 /// This feature might be disabled to create a smaller binary with the
59 /// `UA_ENABLE_STATUSCODE_DESCRIPTIONS` build-flag. Then the function returns an empty string
60 /// for every StatusCode.
61 std::string_view name() const noexcept {
62 return {UA_StatusCode_name(native())};
63 }
64
65 /// Check if the status code is good.
66 constexpr bool isGood() const noexcept {
67 return detail::isGood(native());
68 }
69
70 /// Check if the status code is uncertain.
71 constexpr bool isUncertain() const noexcept {
72 return detail::isUncertain(native());
73 }
74
75 /// Check if the status code is bad.
76 constexpr bool isBad() const noexcept {
77 return detail::isBad(native());
78 }
79
80 /// Throw a BadStatus exception if the status code is bad.
81 /// @exception BadStatus
82 constexpr void throwIfBad() const {
84 }
85};
86
87UAPP_TYPEREGISTRY_NATIVE(StatusCode, UA_TYPES_STATUSCODE)
88
89/* --------------------------------------- StringLikeMixin -------------------------------------- */
90
91namespace detail {
92
93/**
94 * CRTP mixin class to provide a STL-compatible string interface.
95 */
96template <typename WrapperType, typename CharT>
97class StringLikeMixin {
98public:
99 // clang-format off
100 using value_type = CharT;
101 using size_type = size_t;
102 using difference_type = std::ptrdiff_t;
103 using pointer = value_type*;
104 using const_pointer = const value_type*;
105 using reference = value_type&;
106 using const_reference = const value_type&;
107 using iterator = pointer;
108 using const_iterator = const_pointer;
109 using reverse_iterator = std::reverse_iterator<iterator>;
110 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
111 // clang-format on
112
113 size_t size() const noexcept {
114 const auto& native = asNative(static_cast<const WrapperType&>(*this));
115 return native.length;
116 }
117
118 size_t length() const noexcept {
119 return size();
120 }
121
122 bool empty() const noexcept {
123 return size() == 0;
124 }
125
126 pointer data() noexcept {
127 auto& native = asNative(static_cast<WrapperType&>(*this));
128 return reinterpret_cast<pointer>(native.data); // NOLINT
129 }
130
131 const_pointer data() const noexcept {
132 const auto& native = asNative(static_cast<const WrapperType&>(*this));
133 return reinterpret_cast<const_pointer>(native.data); // NOLINT
134 }
135
136 reference operator[](size_t index) noexcept {
137 assert(index < size());
138 return data()[index];
139 }
140
141 const_reference operator[](size_t index) const noexcept {
142 assert(index < size());
143 return data()[index];
144 }
145
146 reference front() noexcept {
147 assert(!empty());
148 return *data();
149 }
150
151 const_reference front() const noexcept {
152 assert(!empty());
153 return *data();
154 }
155
156 reference back() noexcept {
157 assert(!empty());
158 return *(data() + size() - 1);
159 }
160
161 const_reference back() const noexcept {
162 assert(!empty());
163 return *(data() + size() - 1);
164 }
165
166 iterator begin() noexcept {
167 return {data()};
168 }
169
170 const_iterator begin() const noexcept {
171 return {data()};
172 }
173
174 const_iterator cbegin() const noexcept {
175 return {data()};
176 }
177
178 iterator end() noexcept {
179 return {data() + size()};
180 }
181
182 const_iterator end() const noexcept {
183 return {data() + size()};
184 }
185
186 const_iterator cend() const noexcept {
187 return {data() + size()};
188 }
189
190 reverse_iterator rbegin() noexcept {
191 return reverse_iterator(end());
192 }
193
194 const_reverse_iterator rbegin() const noexcept {
195 return const_reverse_iterator(end());
196 }
197
198 const_reverse_iterator crbegin() const noexcept {
199 return const_reverse_iterator(cend());
200 }
201
202 reverse_iterator rend() noexcept {
203 return reverse_iterator(begin());
204 }
205
206 const_reverse_iterator rend() const noexcept {
207 return const_reverse_iterator(begin());
208 }
209
210 const_reverse_iterator crend() const noexcept {
211 return const_reverse_iterator(cbegin());
212 }
213
214protected:
215 void init(size_t length) {
216 auto& native = asNative(static_cast<WrapperType&>(*this));
217 native.length = length;
218 if (length > 0) {
219 native.data = static_cast<uint8_t*>(UA_malloc(length)); // NOLINT
220 if (data() == nullptr) {
221 throw BadStatus{UA_STATUSCODE_BADOUTOFMEMORY};
222 }
223 }
224 }
225
226 template <typename InputIt>
227 void init(InputIt first, InputIt last) {
228 init(first, last, typename std::iterator_traits<InputIt>::iterator_category{});
229 }
230
231 template <typename InputIt, typename Tag>
232 void init(InputIt first, InputIt last, Tag /* unused */) {
233 init(std::distance(first, last));
234 std::copy(first, last, data());
235 }
236
237 template <typename InputIt>
238 void init(InputIt first, InputIt last, std::input_iterator_tag /* unused */) {
239 // input iterator can only be read once -> buffer data in vector
240 std::vector<uint8_t> buffer(first, last);
241 init(buffer.size());
242 std::copy(buffer.begin(), buffer.end(), data());
243 }
244};
245
246} // namespace detail
247
248/* ------------------------------------------- String ------------------------------------------- */
249
250/**
251 * UA_String wrapper class.
252 * @ingroup Wrapper
253 */
255 : public WrapperNative<UA_String, UA_TYPES_STRING>,
256 public detail::StringLikeMixin<String, char> {
257public:
258 using Wrapper::Wrapper;
259
260 explicit String(std::string_view str)
261 : String{detail::allocNativeString(str)} {}
262
263 template <typename InputIt>
264 String(InputIt first, InputIt last) {
265 init(first, last);
266 }
267
268 String(std::initializer_list<char> values) {
269 init(values.begin(), values.end());
270 }
271
272 /// Assign null-termined character string.
273 String& operator=(const char* str) {
274 *this = String(str);
275 return *this;
276 }
277
278 /// Assign std::string_view.
279 template <typename Traits>
280 String& operator=(std::basic_string_view<char, Traits> str) {
281 *this = String(str);
282 return *this;
283 }
284
285 /// Implicit conversion to std::string_view.
286 template <typename Traits>
287 operator std::basic_string_view<char, Traits>() const noexcept { // NOLINT(*-conversions)
288 return {data(), size()};
289 }
290};
291
292/// @relates String
293inline bool operator==(const UA_String& lhs, const UA_String& rhs) noexcept {
294 return UA_String_equal(&lhs, &rhs);
295}
296
297/// @relates String
298inline bool operator!=(const UA_String& lhs, const UA_String& rhs) noexcept {
299 return !(lhs == rhs);
300}
301
302/// @relates String
303inline bool operator==(const String& lhs, const String& rhs) noexcept {
304 return asNative(lhs) == asNative(rhs);
305}
306
307/// @relates String
308inline bool operator!=(const String& lhs, const String& rhs) noexcept {
309 return !(lhs == rhs);
310}
311
312/// @relates String
313inline bool operator==(const String& lhs, std::string_view rhs) noexcept {
314 return static_cast<std::string_view>(lhs) == rhs;
315}
316
317/// @relates String
318inline bool operator!=(const String& lhs, std::string_view rhs) noexcept {
319 return static_cast<std::string_view>(lhs) != rhs;
320}
321
322/// @relates String
323inline bool operator==(std::string_view lhs, const String& rhs) noexcept {
324 return lhs == static_cast<std::string_view>(rhs);
325}
326
327/// @relates String
328inline bool operator!=(std::string_view lhs, const String& rhs) noexcept {
329 return lhs != static_cast<std::string_view>(rhs);
330}
331
332/// @relates String
333std::ostream& operator<<(std::ostream& os, const String& str);
334
335template <typename T>
336struct TypeConverter<T, std::enable_if_t<detail::IsStringLike<T>::value>> {
338
339 [[nodiscard]] static T fromNative(const String& src) {
340 return T{src.data(), src.size()};
341 }
342
343 [[nodiscard]] static String toNative(const T& src) {
344 return String{src.begin(), src.end()};
345 }
346};
347
348template <>
349struct TypeConverter<const char*> {
351
352 [[nodiscard]] static String toNative(const char* src) {
353 return String{src};
354 }
355};
356
357template <size_t N>
358struct TypeConverter<char[N]> { // NOLINT(*c-arrays)
360
361 [[nodiscard]] static String toNative(const char (&src)[N]) { // NOLINT(*c-arrays)
362 // string literals are null-terminated, trim null terminator if present
363 const auto length = N > 0 && src[N - 1] == '\0' ? N - 1 : N;
364 return String{std::string_view{static_cast<const char*>(src), length}};
365 }
366};
367
368UAPP_TYPEREGISTRY_NATIVE(String, UA_TYPES_STRING)
369
370/* ------------------------------------------ DateTime ------------------------------------------ */
371
372/**
373 * UA_DateTime wrapper class.
374 *
375 * An instance in time. A DateTime value is encoded as a 64-bit signed integer which represents the
376 * number of 100 nanosecond intervals since January 1, 1601 (UTC).
377 *
378 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.2.2.5
379 * @ingroup Wrapper
380 */
381class DateTime : public Wrapper<UA_DateTime> {
382public:
383 using DefaultClock = std::chrono::system_clock;
384 using UaDuration = std::chrono::duration<int64_t, std::ratio<1, 10'000'000>>;
385
386 using Wrapper::Wrapper;
387
388 template <typename Clock, typename Duration>
389 DateTime(std::chrono::time_point<Clock, Duration> timePoint) // NOLINT(*-explicit-conversions)
390 : DateTime{fromTimePoint(timePoint)} {}
391
392 /// Get current DateTime.
393 static DateTime now() noexcept {
394 return DateTime{UA_DateTime_now()}; // NOLINT
395 }
396
397 /// Get DateTime from std::chrono::time_point.
398 template <typename Clock, typename Duration>
399 static DateTime fromTimePoint(std::chrono::time_point<Clock, Duration> timePoint) {
400 return DateTime{
401 int64_t{UA_DATETIME_UNIX_EPOCH} +
402 std::chrono::duration_cast<UaDuration>(timePoint.time_since_epoch()).count()
403 };
404 }
405
406 /// Get DateTime from Unix time.
407 static DateTime fromUnixTime(int64_t unixTime) noexcept {
408 return DateTime{UA_DateTime_fromUnixTime(unixTime)}; // NOLINT
409 }
410
411 /// Offset of local time to UTC.
412 static int64_t localTimeUtcOffset() noexcept {
414 }
415
416 /// Convert to std::chrono::time_point.
417 template <typename Clock = DefaultClock, typename Duration = UaDuration>
418 std::chrono::time_point<Clock, Duration> toTimePoint() const {
419 const std::chrono::time_point<Clock, Duration> unixEpoch{};
420 if (get() < UA_DATETIME_UNIX_EPOCH) {
421 return unixEpoch;
422 }
423 const auto sinceEpoch = UaDuration(get() - UA_DATETIME_UNIX_EPOCH);
424 return unixEpoch + std::chrono::duration_cast<Duration>(sinceEpoch);
425 }
426
427 /// Convert to Unix time (number of seconds since January 1, 1970 UTC).
428 int64_t toUnixTime() const noexcept {
429 if (get() < UA_DATETIME_UNIX_EPOCH) {
430 return 0;
431 }
432 return UA_DateTime_toUnixTime(get());
433 }
434
435 /// Convert to UA_DateTimeStruct.
436 UA_DateTimeStruct toStruct() const noexcept {
437 return UA_DateTime_toStruct(get());
438 }
439
440 /// Get DateTime value as 100 nanosecond intervals since January 1, 1601 (UTC).
441 int64_t get() const noexcept {
442 return *handle();
443 }
444
445 /// Convert to string with given format (same format codes as strftime).
446 /// @see https://en.cppreference.com/w/cpp/chrono/c/strftime
447 String format(std::string_view format, bool localtime = false) const;
448};
449
450template <typename Clock, typename Duration>
451struct TypeConverter<std::chrono::time_point<Clock, Duration>> {
452 using TimePoint = std::chrono::time_point<Clock, Duration>;
454
455 [[nodiscard]] static TimePoint fromNative(const DateTime& src) {
456 return src.toTimePoint<Clock, Duration>();
457 }
458
459 [[nodiscard]] static DateTime toNative(const TimePoint& src) {
460 return DateTime::fromTimePoint(src);
461 }
462};
463
464UAPP_TYPEREGISTRY_NATIVE(DateTime, UA_TYPES_DATETIME)
465
466/* -------------------------------------------- Guid -------------------------------------------- */
467
468/**
469 * UA_Guid wrapper class.
470 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.1.3
471 * @ingroup Wrapper
472 */
473class Guid : public Wrapper<UA_Guid> {
474public:
475 using Wrapper::Wrapper;
476
477 explicit Guid(std::array<uint8_t, 16> data) noexcept
478 : Guid{UA_Guid{
479 // NOLINTBEGIN(hicpp-signed-bitwise)
480 static_cast<uint32_t>(
481 (data[0] << 24U) | (data[1] << 16U) | (data[2] << 8U) | data[3]
482 ),
483 static_cast<uint16_t>((data[4] << 8U) | data[5]),
484 static_cast<uint16_t>((data[6] << 8U) | data[7]),
485 // NOLINTEND(hicpp-signed-bitwise)
486 {data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]},
487 }} {}
488
489 Guid(uint32_t data1, uint16_t data2, uint16_t data3, std::array<uint8_t, 8> data4) noexcept
490 : Guid{UA_Guid{
491 data1,
492 data2,
493 data3,
494 {data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], data4[7]},
495 }} {}
496
497 /// Generate random Guid.
498 static Guid random() noexcept {
499 return Guid(UA_Guid_random()); // NOLINT
500 }
501
502#if UAPP_HAS_PARSING
503 /// Parse Guid from its string representation.
504 /// Format: `C496578A-0DFE-4B8F-870A-745238C6AEAE`.
505 static Guid parse(std::string_view str) {
506 Guid guid;
507 throwIfBad(UA_Guid_parse(guid.handle(), detail::toNativeString(str)));
508 return guid;
509 }
510#endif
511
512 /// @deprecated Use free function opcua::toString(const T&) instead
513 [[deprecated("use free function toString instead")]]
515};
516
517/// @relates Guid
518inline bool operator==(const UA_Guid& lhs, const UA_Guid& rhs) noexcept {
519 return UA_Guid_equal(&lhs, &rhs);
520}
521
522/// @relates Guid
523inline bool operator!=(const UA_Guid& lhs, const UA_Guid& rhs) noexcept {
524 return !(lhs == rhs);
525}
526
527UAPP_TYPEREGISTRY_NATIVE(Guid, UA_TYPES_GUID)
528
529/* ----------------------------------------- ByteString ----------------------------------------- */
530
531/**
532 * UA_ByteString wrapper class.
533 * @ingroup Wrapper
534 */
536 : public WrapperNative<UA_ByteString, UA_TYPES_BYTESTRING>,
537 public detail::StringLikeMixin<ByteString, uint8_t> {
538public:
539 using Wrapper::Wrapper;
540
541 explicit ByteString(std::string_view str)
542 : ByteString{detail::allocNativeString(str)} {}
543
544 explicit ByteString(const char* str) // required to avoid ambiguity
545 : ByteString{std::string_view{str}} {}
546
548 init(bytes.begin(), bytes.end());
549 }
550
551 template <typename InputIt>
552 ByteString(InputIt first, InputIt last) {
553 init(first, last);
554 }
555
556 /// Parse ByteString from Base64 encoded string.
557 /// @note Supported since open62541 v1.1
558 static ByteString fromBase64(std::string_view encoded);
559
560 /// Explicit conversion to std::string_view.
561 template <typename Traits>
562 explicit operator std::basic_string_view<char, Traits>() const noexcept {
563 return {reinterpret_cast<const char*>(data()), size()}; // NOLINT
564 }
565
566 /// Convert to Base64 encoded string.
567 /// @note Supported since open62541 v1.1
569};
570
571UAPP_TYPEREGISTRY_NATIVE(ByteString, UA_TYPES_BYTESTRING)
572
573/* ----------------------------------------- XmlElement ----------------------------------------- */
574
575/**
576 * UA_XmlElement wrapper class.
577 * @ingroup Wrapper
578 */
580 : public WrapperNative<UA_XmlElement, UA_TYPES_XMLELEMENT>,
581 public detail::StringLikeMixin<XmlElement, char> {
582public:
583 using Wrapper::Wrapper;
584
585 explicit XmlElement(std::string_view str)
586 : XmlElement{detail::allocNativeString(str)} {}
587
588 template <typename InputIt>
589 XmlElement(InputIt first, InputIt last) {
590 init(first, last);
591 }
592
593 /// Assign null-termined character string.
594 XmlElement& operator=(const char* str) {
595 *this = XmlElement(str);
596 return *this;
597 }
598
599 /// Assign std::string_view.
600 template <typename Traits>
601 XmlElement& operator=(std::basic_string_view<char, Traits> str) {
602 *this = XmlElement(str);
603 return *this;
604 }
605
606 /// Implicit conversion to std::string_view.
607 template <typename Traits>
608 operator std::basic_string_view<char, Traits>() const noexcept { // NOLINT(*-conversions)
609 return {data(), size()};
610 }
611};
612
613UAPP_TYPEREGISTRY_NATIVE(XmlElement, UA_TYPES_XMLELEMENT)
614
615/* ------------------------------------------- NodeId ------------------------------------------- */
616
617namespace detail {
618template <typename T, typename = void>
619struct IsNodeIdEnum : std::false_type {};
620
621template <typename T>
622struct IsNodeIdEnum<T, std::void_t<decltype(namespaceOf(std::declval<T>()))>> : std::is_enum<T> {};
623} // namespace detail
624
625/**
626 * NodeId types.
627 * @see UA_NodeIdType
628 */
635
636/**
637 * UA_NodeId wrapper class.
638 * @see https://reference.opcfoundation.org/Core/Part3/v105/docs/8.2
639 * @ingroup Wrapper
640 */
641class NodeId : public WrapperNative<UA_NodeId, UA_TYPES_NODEID> {
642public:
643 using Wrapper::Wrapper;
644
645 /// Create NodeId with numeric identifier.
647 handle()->namespaceIndex = namespaceIndex;
648 handle()->identifierType = UA_NODEIDTYPE_NUMERIC;
649 handle()->identifier.numeric = identifier; // NOLINT
650 }
651
652 /// Create NodeId with String identifier.
654 handle()->namespaceIndex = namespaceIndex;
655 handle()->identifierType = UA_NODEIDTYPE_STRING;
656 handle()->identifier.string = detail::allocNativeString(identifier); // NOLINT
657 }
658
659 /// Create NodeId with Guid identifier.
661 handle()->namespaceIndex = namespaceIndex;
662 handle()->identifierType = UA_NODEIDTYPE_GUID;
663 handle()->identifier.guid = identifier; // NOLINT
664 }
665
666 /// Create NodeId with ByteString identifier.
668 handle()->namespaceIndex = namespaceIndex;
669 handle()->identifierType = UA_NODEIDTYPE_BYTESTRING;
670 // force zero-initialization, only first member of identifier union is zero-initialized
671 handle()->identifier.byteString = {}; // NOLINT
672 asWrapper<ByteString>(handle()->identifier.byteString) = std::move(identifier); // NOLINT
673 }
674
675 /// Create NodeId from enum class with numeric identifiers like `opcua::ObjectId`.
676 /// The namespace is retrieved by calling e.g. `namespaceOf(opcua::ObjectId)`.
677 /// Make sure to provide an overload for custom enum types.
678 template <typename T, typename = std::enable_if_t<detail::IsNodeIdEnum<T>::value>>
679 NodeId(T identifier) noexcept // NOLINT(hicpp-explicit-conversions)
680 : NodeId(namespaceOf(identifier).index, static_cast<uint32_t>(identifier)) {}
681
682#if UAPP_HAS_PARSING
683 /// Parse NodeId from its string representation.
684 /// Format: `ns=<namespaceindex>;<type>=<value>`, e.g. `i=13` or `ns=10;s=HelloWorld`
685 /// @see https://reference.opcfoundation.org/Core/Part6/v104/docs/5.3.1.10
686 static NodeId parse(std::string_view str) {
687 NodeId id;
688 throwIfBad(UA_NodeId_parse(id.handle(), detail::toNativeString(str)));
689 return id;
690 }
691#endif
692
693 bool isNull() const noexcept {
694 return UA_NodeId_isNull(handle());
695 }
696
697 uint32_t hash() const noexcept {
698 return UA_NodeId_hash(handle());
699 }
700
702 return handle()->namespaceIndex;
703 }
704
705 NodeIdType identifierType() const noexcept {
706 return static_cast<NodeIdType>(handle()->identifierType);
707 }
708
709 /**
710 * Get identifier pointer or `nullptr` on error.
711 * @tparam T Requested identifier type, should be either:
712 * - `uint32_t` for NodeIdType::Numeric
713 * - `String` for NodeIdType::String
714 * - `Guid` for NodeIdType::Guid
715 * - `ByteString` for NodeIdType::ByteString
716 * @return Pointer to the stored identifier
717 * or a `nullptr` if `T` doesn't match the stored identifier type
718 */
719 template <typename T>
720 T* identifierIf() noexcept {
721 return const_cast<T*>(std::as_const(*this).identifierIf<T>()); // NOLINT
722 }
723
724 /// @copydoc identifierIf
725 template <typename T>
726 const T* identifierIf() const noexcept {
727 static_assert(
728 detail::IsOneOf<T, uint32_t, String, Guid, ByteString>::value,
729 "Invalid type for NodeId identifier"
730 );
731 // NOLINTBEGIN(cppcoreguidelines-pro-type-union-access)
732 if constexpr (std::is_same_v<T, uint32_t>) {
734 ? &handle()->identifier.numeric
735 : nullptr;
736 } else if constexpr (std::is_same_v<T, String>) {
738 ? asWrapper<String>(&handle()->identifier.string)
739 : nullptr;
740 } else if constexpr (std::is_same_v<T, Guid>) {
742 ? asWrapper<Guid>(&handle()->identifier.guid)
743 : nullptr;
744 } else if constexpr (std::is_same_v<T, ByteString>) {
746 ? asWrapper<ByteString>(&handle()->identifier.byteString)
747 : nullptr;
748 } else {
749 return nullptr;
750 }
751 // NOLINTEND(cppcoreguidelines-pro-type-union-access)
752 }
753
754 /**
755 * Get identifier reference.
756 * @tparam T Requested identifier type, should be either:
757 * - `uint32_t` for NodeIdType::Numeric
758 * - `String` for NodeIdType::String
759 * - `Guid` for NodeIdType::Guid
760 * - `ByteString` for NodeIdType::ByteString
761 * @return Reference to the stored identifier
762 * @throws TypeError If the requested type `T` doesn't match the stored identifier type
763 */
764 template <typename T>
766 return const_cast<T&>(std::as_const(*this).identifier<T>()); // NOLINT
767 }
768
769 /// @copydoc identifier
770 template <typename T>
771 const T& identifier() const {
772 if (auto* ptr = identifierIf<T>()) {
773 return *ptr;
774 }
775 throw TypeError("NodeId identifier type doesn't match the requested type");
776 }
777
778 /// @deprecated Use free function opcua::toString(const T&) instead
779 [[deprecated("use free function toString instead")]]
781};
782
783/// @relates NodeId
784inline bool operator==(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
785 return UA_NodeId_equal(&lhs, &rhs);
786}
787
788/// @relates NodeId
789inline bool operator!=(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
790 return !(lhs == rhs);
791}
792
793/// @relates NodeId
794inline bool operator<(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
795 return UA_NodeId_order(&lhs, &rhs) == UA_ORDER_LESS;
796}
797
798/// @relates NodeId
799inline bool operator>(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
800 return UA_NodeId_order(&lhs, &rhs) == UA_ORDER_MORE;
801}
802
803/// @relates NodeId
804inline bool operator<=(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
805 return (lhs < rhs) || (lhs == rhs);
806}
807
808/// @relates NodeId
809inline bool operator>=(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
810 return (lhs > rhs) || (lhs == rhs);
811}
812
813UAPP_TYPEREGISTRY_NATIVE(NodeId, UA_TYPES_NODEID)
814
815/* --------------------------------------- ExpandedNodeId --------------------------------------- */
816
817/**
818 * UA_ExpandedNodeId wrapper class.
819 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.16
820 * @ingroup Wrapper
821 */
822class ExpandedNodeId : public WrapperNative<UA_ExpandedNodeId, UA_TYPES_EXPANDEDNODEID> {
823public:
824 using Wrapper::Wrapper;
825
826 explicit ExpandedNodeId(NodeId id) noexcept {
827 asWrapper<NodeId>(handle()->nodeId) = std::move(id);
828 }
829
830 ExpandedNodeId(NodeId id, std::string_view namespaceUri, uint32_t serverIndex) {
831 asWrapper<NodeId>(handle()->nodeId) = std::move(id);
832 handle()->namespaceUri = detail::allocNativeString(namespaceUri);
833 handle()->serverIndex = serverIndex;
834 }
835
836#if UAPP_HAS_PARSING
837 /// Parse ExpandedNodeId from its string representation.
838 /// Format: `svr=<serverindex>;ns=<namespaceindex>;<type>=<value>` or
839 /// `svr=<serverindex>;nsu=<uri>;<type>=<value>`
840 /// @see https://reference.opcfoundation.org/Core/Part6/v104/docs/5.3.1.11
841 static ExpandedNodeId parse(std::string_view str) {
843 throwIfBad(UA_ExpandedNodeId_parse(id.handle(), detail::toNativeString(str)));
844 return id;
845 }
846#endif
847
848 bool isLocal() const noexcept {
849 return handle()->serverIndex == 0;
850 }
851
852 uint32_t hash() const noexcept {
853 return UA_ExpandedNodeId_hash(handle());
854 }
855
856 NodeId& nodeId() noexcept {
857 return asWrapper<NodeId>(handle()->nodeId);
858 }
859
860 const NodeId& nodeId() const noexcept {
861 return asWrapper<NodeId>(handle()->nodeId);
862 }
863
864 std::string_view namespaceUri() const {
865 return detail::toStringView(handle()->namespaceUri);
866 }
867
868 uint32_t serverIndex() const noexcept {
869 return handle()->serverIndex;
870 }
871
872 /// @deprecated Use free function opcua::toString(const T&) instead
873 [[deprecated("use free function toString instead")]]
875};
876
877/// @relates ExpandedNodeId
878inline bool operator==(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
879 return UA_ExpandedNodeId_equal(&lhs, &rhs);
880}
881
882/// @relates ExpandedNodeId
883inline bool operator!=(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
884 return !(lhs == rhs);
885}
886
887/// @relates ExpandedNodeId
888inline bool operator<(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
889 return UA_ExpandedNodeId_order(&lhs, &rhs) == UA_ORDER_LESS;
890}
891
892/// @relates ExpandedNodeId
893inline bool operator>(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
894 return UA_ExpandedNodeId_order(&lhs, &rhs) == UA_ORDER_MORE;
895}
896
897/// @relates ExpandedNodeId
898inline bool operator<=(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
899 return (lhs < rhs) || (lhs == rhs);
900}
901
902/// @relates ExpandedNodeId
903inline bool operator>=(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
904 return (lhs > rhs) || (lhs == rhs);
905}
906
907UAPP_TYPEREGISTRY_NATIVE(ExpandedNodeId, UA_TYPES_EXPANDEDNODEID)
908
909/* ---------------------------------------- QualifiedName --------------------------------------- */
910
911/**
912 * UA_QualifiedName wrapper class.
913 * @ingroup Wrapper
914 */
915class QualifiedName : public WrapperNative<UA_QualifiedName, UA_TYPES_QUALIFIEDNAME> {
916public:
917 using Wrapper::Wrapper;
918
919 QualifiedName(NamespaceIndex namespaceIndex, std::string_view name) {
920 handle()->namespaceIndex = namespaceIndex;
921 handle()->name = detail::allocNativeString(name);
922 }
923
925 return handle()->namespaceIndex;
926 }
927
928 std::string_view name() const noexcept {
929 return detail::toStringView(handle()->name);
930 }
931};
932
933/// @relates QualifiedName
934inline bool operator==(const UA_QualifiedName& lhs, const UA_QualifiedName& rhs) noexcept {
935 return (lhs.namespaceIndex == rhs.namespaceIndex) && (lhs.name == rhs.name);
936}
937
938/// @relates QualifiedName
939inline bool operator!=(const UA_QualifiedName& lhs, const UA_QualifiedName& rhs) noexcept {
940 return !(lhs == rhs);
941}
942
943UAPP_TYPEREGISTRY_NATIVE(QualifiedName, UA_TYPES_QUALIFIEDNAME)
944
945/* ---------------------------------------- LocalizedText --------------------------------------- */
946
947/**
948 * UA_LocalizedText wrapper class.
949 * The format of locale is `<language>[-<country/region>]`:
950 * - `<language>` is the two letter ISO 639 code for a language
951 * - `<country/region>` is the two letter ISO 3166 code for the country/region
952 * @see https://reference.opcfoundation.org/Core/Part3/v105/docs/8.5/
953 * @see https://reference.opcfoundation.org/Core/Part3/v105/docs/8.4/
954 * @ingroup Wrapper
955 */
956class LocalizedText : public WrapperNative<UA_LocalizedText, UA_TYPES_LOCALIZEDTEXT> {
957public:
958 using Wrapper::Wrapper;
959
960 LocalizedText(std::string_view locale, std::string_view text) {
961 handle()->locale = detail::allocNativeString(locale);
962 handle()->text = detail::allocNativeString(text);
963 }
964
965 std::string_view locale() const noexcept {
966 return detail::toStringView(handle()->locale);
967 }
968
969 std::string_view text() const noexcept {
970 return detail::toStringView(handle()->text);
971 }
972};
973
974/// @relates LocalizedText
975inline bool operator==(const UA_LocalizedText& lhs, const UA_LocalizedText& rhs) noexcept {
976 return (lhs.locale == rhs.locale) && (lhs.text == rhs.text);
977}
978
979/// @relates LocalizedText
980inline bool operator!=(const UA_LocalizedText& lhs, const UA_LocalizedText& rhs) noexcept {
981 return !(lhs == rhs);
982}
983
984UAPP_TYPEREGISTRY_NATIVE(LocalizedText, UA_TYPES_LOCALIZEDTEXT)
985
986/* ------------------------------------------- Variant ------------------------------------------ */
987
989public:
990 using TypeError::TypeError;
991};
992
993/**
994 * UA_Variant wrapper class.
995 *
996 * Variants may contain scalar values or arrays of any type together with a type definition.
997 * The standard mandates that variants contain built-in data types only.
998 * open62541 transparently handles this wrapping in the encoding layer. If the type is unknown to
999 * the receiver, the variant stores the original ExtensionObject in binary or XML encoding.
1000 *
1001 * open62541pp enhances variant handling with the following features:
1002 *
1003 * 1. **Type category detection**: Identifies whether `T` is scalar or array:
1004 * - **Scalar**, if `T` is:
1005 * - A registered type (TypeRegistry spezialization). This applies to native types and
1006 * @ref Wrapper "wrapper types".
1007 * - A convertible type (TypeConverter spezialization).
1008 * - **Array**, if `T` is a container type (e.g. `std::vector` or `std::list`) and does not
1009 * satisfy the criterias of a scalar type.
1010 *
1011 * Applied in @ref Variant::Variant "constructors", @ref assign, and @ref to functions:
1012 *
1013 * @code
1014 * opcua::Variant var{5}; // set scalar (via constructor)
1015 * auto value = var.to<int>(); // convert scalar
1016 *
1017 * std::array<int> array{1, 2, 3};
1018 * var.assign(array); // set array (via assign)
1019 * auto vec = var.to<std::vector<int>>(); // convert array
1020 * @endcode
1021 *
1022 * 2. **Type definition retrieval**: Automatically retrieves UA_DataType via TypeRegistry.
1023 * For every registered type `T`, the type definition parameter can be omitted:
1024 *
1025 * @code
1026 * opcua::Variant var{5, UA_TYPES[UA_TYPES_INT]}; // explicit type definition
1027 * opcua::Variant var{5}; // auto-detected type definition
1028 * @endcode
1029 *
1030 * 3. **Type conversion**: Convert non-native types using TypeConverter.
1031 * Native `UA_*` types can be assigned and retrieved to/from variants without any conversion,
1032 * because their binary layout is described by the type definition (UA_DataType). The same is
1033 * true for wrapper types, that share the exact memory layout as their wrapped native type.
1034 * Non-native types, like `std::string` from the STL, may not be describeable by UA_DataType
1035 * because their memory layout is an implementation detail.
1036 * Instead, the conversion between non-native and native types can be defined with template
1037 * specializations of TypeConverter. If a type is convertible (TypeConverter specialization),
1038 * the Variant automatically manages the conversion, requiring a copy:
1039 *
1040 * @code
1041 * opcua::Variant var{std::string{"test"}}; // convert to native type (copy)
1042 * auto& native = var.scalar<opcua::String>(); // reference to native type (no copy)
1043 * auto str = var.to<std::string>(); // conversion (copy required)
1044 * @endcode
1045 *
1046 * @ingroup Wrapper
1047 */
1048class Variant : public WrapperNative<UA_Variant, UA_TYPES_VARIANT> {
1049private:
1050 template <typename T>
1051 static constexpr bool isVariant =
1052 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, Variant> ||
1053 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, UA_Variant>;
1054
1055public:
1056 using Wrapper::Wrapper;
1057
1058 /// Create Variant from a pointer to a scalar/array (no copy).
1059 /// @see assign(T*)
1060 template <typename T, typename = std::enable_if_t<!std::is_const_v<T>>>
1061 explicit Variant(T* ptr) noexcept {
1062 assign(ptr);
1063 }
1064
1065 /// Create Variant from a pointer to a scalar/array with a custom data type (no copy).
1066 /// @see assign(T*, const UA_DataType&)
1067 template <typename T, typename = std::enable_if_t<!std::is_const_v<T>>>
1068 Variant(T* ptr, const UA_DataType& type) noexcept {
1069 assign(ptr, type);
1070 }
1071
1072 /// Create Variant from a scalar/array (copy/move).
1073 /// @see assign(T&&)
1074 template <typename T, typename = std::enable_if_t<!isVariant<T>>>
1075 explicit Variant(T&& value) {
1076 assign(std::forward<T>(value));
1077 }
1078
1079 /// Create Variant from a scalar/array with a custom data type (copy/move).
1080 /// @see assign(T&&, const UA_DataType&)
1081 template <typename T>
1082 Variant(T&& value, const UA_DataType& type) {
1083 assign(std::forward<T>(value), type);
1084 }
1085
1086 /// Create Variant from a range of elements (copy).
1087 /// @see assign(InputIt, InputIt)
1088 template <typename InputIt>
1089 Variant(InputIt first, InputIt last) {
1090 assign(first, last);
1091 }
1092
1093 /// Create Variant from a range of elements with a custom data type (copy).
1094 /// @see assign(InputIt, InputIt, const UA_DataType&)
1095 template <typename InputIt>
1096 Variant(InputIt first, InputIt last, const UA_DataType& type) {
1097 assign(first, last, type);
1098 }
1099
1100 /**
1101 * @name Modifiers
1102 * Modify internal scalar/array value.
1103 * @{
1104 */
1105
1106 void assign(std::nullptr_t ptr) noexcept = delete;
1107 void assign(std::nullptr_t ptr, const UA_DataType& type) noexcept = delete;
1108
1109 /**
1110 * Assign pointer to scalar/array to variant (no copy).
1111 * The object will *not* be deleted when the Variant is destructed.
1112 * @param ptr Non-const pointer to a value to assign to the variant. This can be:
1113 * - A pointer to a scalar native or wrapper value.
1114 * - A pointer to a contiguous container such as `std::array` or `std::vector`
1115 * holding native or wrapper elements.
1116 * The underlying array must be accessible with `std::data` and `std::size`.
1117 * - A `nullptr`, in which case the variant will be cleared.
1118 */
1119 template <typename T, typename = std::enable_if_t<!std::is_const_v<T>>>
1120 void assign(T* ptr) noexcept {
1121 if constexpr (isArrayType<T>()) {
1122 using ValueType = detail::RangeValueT<T>;
1123 assertIsRegistered<ValueType>();
1124 assign(ptr, opcua::getDataType<ValueType>());
1125 } else {
1126 assertIsRegistered<T>();
1127 assign(ptr, opcua::getDataType<T>());
1128 }
1129 }
1130
1131 /**
1132 * Assign pointer to scalar/array to variant with custom data type (no copy).
1133 * @copydetails assign(T*)
1134 * @param type Custom data type.
1135 */
1136 template <typename T, typename = std::enable_if_t<!std::is_const_v<T>>>
1137 void assign(T* ptr, const UA_DataType& type) noexcept {
1138 if (ptr == nullptr) {
1139 clear();
1140 } else if constexpr (isArrayType<T>()) {
1141 setArrayImpl(std::data(*ptr), std::size(*ptr), type, UA_VARIANT_DATA_NODELETE);
1142 } else {
1143 setScalarImpl(ptr, type, UA_VARIANT_DATA_NODELETE);
1144 }
1145 }
1146
1147 /**
1148 * Assign scalar/array to variant (copy/move and convert if required).
1149 * @param value Value to copy to the variant. It can be:
1150 * - A scalar native, wrapper or convertible value.
1151 * - A container with native, wrapper or convertible elements.
1152 * The container must implement `begin()` and `end()`.
1153 */
1154 template <typename T>
1155 void assign(T&& value) {
1156 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
1157 if constexpr (isArrayType<ValueType>()) {
1158 assign(std::begin(value), std::end(value));
1159 } else {
1160 assertIsRegisteredOrConvertible<ValueType>();
1161 if constexpr (IsRegistered<ValueType>::value) {
1162 setScalarCopyImpl(std::forward<T>(value), opcua::getDataType<ValueType>());
1163 } else {
1164 setScalarCopyConvertImpl(std::forward<T>(value));
1165 }
1166 }
1167 }
1168
1169 /**
1170 * Assign scalar/array to variant with custom data type (copy/move).
1171 * @param value Value to copy to the variant. It can be:
1172 * - A scalar native or wrapper value.
1173 * - A container with native or wrapper elements.
1174 * The container must implement `begin()` and `end()`.
1175 * @param type Custom data type.
1176 */
1177 template <typename T>
1178 void assign(T&& value, const UA_DataType& type) {
1179 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
1180 if constexpr (isArrayType<ValueType>()) {
1181 setArrayCopyImpl(std::begin(value), std::end(value), type);
1182 } else {
1183 setScalarCopyImpl(std::forward<T>(value), type);
1184 }
1185 }
1186
1187 /**
1188 * Assign range to variant (copy and convert if required).
1189 * @param first Iterator to the beginning of the range.
1190 * @param last Iterator to the end of the range.
1191 * @tparam InputIt Iterator of a container with native, wrapper or convertible elements.
1192 */
1193 template <typename InputIt>
1194 void assign(InputIt first, InputIt last) {
1195 using ValueType = typename std::iterator_traits<InputIt>::value_type;
1196 assertIsRegisteredOrConvertible<ValueType>();
1197 if constexpr (IsRegistered<ValueType>::value) {
1198 setArrayCopyImpl(first, last, opcua::getDataType<ValueType>());
1199 } else {
1200 setArrayCopyConvertImpl(first, last);
1201 }
1202 }
1203
1204 /**
1205 * Assign range to variant with custom data type (copy).
1206 * @param first Iterator to the beginning of the range.
1207 * @param last Iterator to the end of the range.
1208 * @param type Custom data type.
1209 * @tparam InputIt Iterator of a container with native or wrapper elements.
1210 */
1211 template <typename InputIt>
1212 void assign(InputIt first, InputIt last, const UA_DataType& type) {
1213 setArrayCopyImpl(first, last, type);
1214 }
1215
1216 /// Assign pointer to scalar/array to variant (no copy).
1217 /// @see assign(T*)
1218 template <typename T, typename = std::enable_if_t<!isVariant<T>>>
1219 Variant& operator=(T* value) noexcept {
1220 assign(value);
1221 return *this;
1222 }
1223
1224 /// Assign scalar/array to variant (copy and convert if required).
1225 /// @see assign(T&&)
1226 template <typename T, typename = std::enable_if_t<!isVariant<T>>>
1227 Variant& operator=(T&& value) {
1228 assign(std::forward<T>(value));
1229 return *this;
1230 }
1231
1232 /**
1233 * @name Observers
1234 * Check the type category, type definition and array structure of the internal value.
1235 */
1236
1237 /// Check if the variant is empty.
1238 bool empty() const noexcept {
1239 return UA_Variant_isEmpty(handle());
1240 }
1241
1242 /// Check if the variant is a scalar.
1243 bool isScalar() const noexcept {
1244 return UA_Variant_isScalar(handle());
1245 }
1246
1247 /// Check if the variant is an array.
1248 bool isArray() const noexcept {
1249 return !empty() && !isScalar();
1250 }
1251
1252 /// Check if the variant type is equal to the provided data type.
1253 bool isType(const UA_DataType* type) const noexcept {
1254 return type != nullptr && isType(asWrapper<NodeId>(type->typeId));
1255 }
1256
1257 /// Check if the variant type is equal to the provided data type.
1258 bool isType(const UA_DataType& type) const noexcept {
1259 return isType(&type);
1260 }
1261
1262 /// Check if the variant type is equal to the provided data type id.
1263 bool isType(const NodeId& id) const noexcept {
1264 return type() != nullptr && type()->typeId == id;
1265 }
1266
1267 /// Check if the variant type is equal to the provided template type.
1268 template <typename T>
1269 bool isType() const noexcept {
1270 return isType(opcua::getDataType<T>());
1271 }
1272
1273 /// Get data type.
1274 const UA_DataType* type() const noexcept {
1275 return handle()->type;
1276 }
1277
1278 /// Get array length or 0 if variant is not an array.
1279 size_t arrayLength() const noexcept {
1280 return handle()->arrayLength;
1281 }
1282
1283 /// Get array dimensions.
1285 return {handle()->arrayDimensions, handle()->arrayDimensionsSize};
1286 }
1287
1288 /**
1289 * @name Accessors
1290 * Access and convert internal scalar/array value.
1291 * @{
1292 */
1293
1294 /// Get pointer to the underlying data.
1295 /// Check the properties and data type before casting it to the actual type.
1296 /// Use the methods @ref isScalar, @ref isArray, @ref isType / @ref type.
1297 /// @note The @ref UA_EMPTY_ARRAY_SENTINEL sentinel, used to indicate an empty array, is
1298 /// stripped from the returned pointer.
1299 void* data() noexcept {
1300 return detail::stripEmptyArraySentinel(handle()->data);
1301 }
1302
1303 /// @copydoc data
1304 const void* data() const noexcept {
1305 return detail::stripEmptyArraySentinel(handle()->data);
1306 }
1307
1308 /// Get scalar value with given template type (only native or wrapper types).
1309 /// @exception BadVariantAccess If the variant is not a scalar or not of type `T`.
1310 template <typename T>
1311 T& scalar() & {
1312 checkIsScalarType<T>();
1313 return *static_cast<T*>(data());
1314 }
1315
1316 /// @copydoc scalar()&
1317 template <typename T>
1318 const T& scalar() const& {
1319 checkIsScalarType<T>();
1320 return *static_cast<const T*>(data());
1321 }
1322
1323 /// @copydoc scalar()&
1324 template <typename T>
1325 [[nodiscard]] T scalar() && {
1326 return isBorrowed() ? scalar<T>() : std::move(scalar<T>());
1327 }
1328
1329 /// @copydoc scalar()&
1330 template <typename T>
1331 [[nodiscard]] T scalar() const&& {
1332 return isBorrowed() ? scalar<T>() : std::move(scalar<T>());
1333 }
1334
1335 /// Get array with given template type (only native or wrapper types).
1336 /// @exception BadVariantAccess If the variant is not an array or not of type `T`.
1337 template <typename T>
1339 checkIsArrayType<T>();
1340 return Span<T>(static_cast<T*>(data()), arrayLength());
1341 }
1342
1343 /// @copydoc array()
1344 template <typename T>
1346 checkIsArrayType<T>();
1347 return Span<const T>(static_cast<const T*>(data()), arrayLength());
1348 }
1349
1350 /**
1351 * Converts the variant to the specified type `T` with automatic conversion if required.
1352 *
1353 * Determines the type category (scalar or array) based on the characteristics of `T` using
1354 * @ref Variant "type category detection".
1355 * If `T` is a container, it must be constructible from an iterator pair.
1356 *
1357 * @code
1358 * // Scalar
1359 * opcua::Variant var{11};
1360 * const auto value = var.to<int>();
1361 * @endcode
1362 *
1363 * @code
1364 * // Array
1365 * std::array<std::string, 3> array{"One", "Two", "Three"};
1366 * opcua::Variant var{array};
1367 * const auto vec = var.to<std::vector<std::string>>();
1368 * const auto lst = var.to<std::list<opcua::String>>();
1369 * @endcode
1370 *
1371 * @exception BadVariantAccess If the variant is not convertible to `T`.
1372 */
1373 template <typename T>
1374 [[nodiscard]] T to() const& {
1375 return toImpl<T>(*this);
1376 }
1377
1378 /// @copydoc to()const&
1379 template <typename T>
1380 [[nodiscard]] T to() && {
1381 return toImpl<T>(std::move(*this));
1382 }
1383
1384 /**
1385 * @}
1386 */
1387
1388private:
1389 template <typename T>
1390 static constexpr bool isScalarType() noexcept {
1392 }
1393
1394 template <typename T>
1395 static constexpr bool isArrayType() noexcept {
1396 return detail::IsRange<T>::value && !isScalarType<T>();
1397 }
1398
1399 template <typename T>
1400 static constexpr void assertIsRegistered() {
1401 static_assert(
1402 IsRegistered<T>::value,
1403 "Template type must be a native/wrapper type to assign or get scalar/array without copy"
1404 );
1405 }
1406
1407 template <typename T>
1408 static constexpr void assertIsRegisteredOrConvertible() {
1409 static_assert(
1410 IsRegistered<T>::value || IsConvertible<T>::value,
1411 "Template type must be either a native/wrapper type or a convertible type. "
1412 "If the type is a native type: Provide the type definition (UA_DataType) manually or "
1413 "register the type with a TypeRegistry template specialization. "
1414 "If the type should be converted: Add a template specialization for TypeConverter."
1415 );
1416 }
1417
1418 template <typename T>
1419 static constexpr void assertNoVariant() {
1420 static_assert(!isVariant<T>, "Variants cannot directly contain another variant");
1421 }
1422
1423 void checkIsScalar() const {
1424 if (!isScalar()) {
1425 throw BadVariantAccess("Variant is not a scalar");
1426 }
1427 }
1428
1429 void checkIsArray() const {
1430 if (!isArray()) {
1431 throw BadVariantAccess("Variant is not an array");
1432 }
1433 }
1434
1435 template <typename T>
1436 void checkIsType() const {
1437 const auto* dt = type();
1438 if (dt == nullptr || dt->typeId != opcua::getDataType<T>().typeId) {
1439 throw BadVariantAccess("Variant does not contain a value convertible to template type");
1440 }
1441 }
1442
1443 template <typename T>
1444 void checkIsScalarType() const {
1445 assertIsRegistered<T>();
1446 checkIsScalar();
1447 checkIsType<T>();
1448 }
1449
1450 template <typename T>
1451 void checkIsArrayType() const {
1452 assertIsRegistered<T>();
1453 checkIsArray();
1454 checkIsType<T>();
1455 }
1456
1457 bool isBorrowed() const noexcept {
1458 return handle()->storageType == UA_VARIANT_DATA_NODELETE;
1459 }
1460
1461 template <typename T>
1462 void setScalarImpl(
1463 T* data, const UA_DataType& type, UA_VariantStorageType storageType
1464 ) noexcept {
1465 setArrayImpl(data, 0, type, storageType);
1466 }
1467
1468 template <typename T>
1469 void setArrayImpl(
1470 T* data, size_t arrayLength, const UA_DataType& type, UA_VariantStorageType storageType
1471 ) noexcept {
1472 assertNoVariant<T>();
1473 assert(sizeof(T) == type.memSize);
1474 clear();
1475 handle()->type = &type;
1476 handle()->storageType = storageType;
1477 handle()->data = data;
1478 handle()->arrayLength = arrayLength;
1479 }
1480
1481 template <typename T>
1482 void setScalarCopyImpl(T&& value, const UA_DataType& type) {
1483 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
1484 auto native = detail::allocateUniquePtr<ValueType>(type);
1485 *native = detail::copy<ValueType>(std::forward<T>(value), type);
1486 setScalarImpl(native.release(), type, UA_VARIANT_DATA); // move ownership
1487 }
1488
1489 template <typename T>
1490 void setScalarCopyConvertImpl(T&& value) {
1491 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
1492 using Native = typename TypeConverter<ValueType>::NativeType;
1493 const auto& type = opcua::getDataType<Native>();
1494 auto native = detail::allocateUniquePtr<Native>(type);
1495 *native = detail::toNative<ValueType>(std::forward<T>(value));
1496 setScalarImpl(native.release(), type, UA_VARIANT_DATA); // move ownership
1497 }
1498
1499 template <typename InputIt>
1500 void setArrayCopyImpl(InputIt first, InputIt last, const UA_DataType& type) {
1501 using ValueType = typename std::iterator_traits<InputIt>::value_type;
1502 const size_t size = std::distance(first, last);
1503 auto native = detail::allocateArrayUniquePtr<ValueType>(size, type);
1504 std::transform(first, last, native.get(), [&](auto&& value) {
1505 return detail::copy<ValueType>(std::forward<decltype(value)>(value), type);
1506 });
1507 setArrayImpl(native.release(), size, type, UA_VARIANT_DATA); // move ownership
1508 }
1509
1510 template <typename InputIt>
1511 void setArrayCopyConvertImpl(InputIt first, InputIt last) {
1512 using ValueType = typename std::iterator_traits<InputIt>::value_type;
1513 using Native = typename TypeConverter<ValueType>::NativeType;
1514 const auto& type = opcua::getDataType<Native>();
1515 const size_t size = std::distance(first, last);
1516 auto native = detail::allocateArrayUniquePtr<Native>(size, type);
1517 std::transform(first, last, native.get(), detail::toNative<ValueType>);
1518 setArrayImpl(native.release(), size, type, UA_VARIANT_DATA); // move ownership
1519 }
1520
1521 template <typename T, typename Self>
1522 static T toImpl(Self&& self) {
1523 if constexpr (isArrayType<T>()) {
1524 return toArrayImpl<T>(std::forward<Self>(self));
1525 } else {
1526 return toScalarImpl<T>(std::forward<Self>(self));
1527 }
1528 }
1529
1530 template <typename T, typename Self>
1531 static T toScalarImpl(Self&& self) {
1532 assertIsRegisteredOrConvertible<T>();
1533 if constexpr (IsRegistered<T>::value) {
1534 return std::forward<Self>(self).template scalar<T>();
1535 } else {
1536 using Native = typename TypeConverter<T>::NativeType;
1537 return detail::fromNative<T>(std::forward<Self>(self).template scalar<Native>());
1538 }
1539 }
1540
1541 template <typename T, typename Self>
1542 static T toArrayImpl(Self&& self) {
1543 using ValueType = detail::RangeValueT<T>;
1544 assertIsRegisteredOrConvertible<ValueType>();
1545 if constexpr (IsRegistered<ValueType>::value) {
1546 auto native = std::forward<Self>(self).template array<ValueType>();
1547 return T(native.begin(), native.end());
1548 } else {
1549 using Native = typename TypeConverter<ValueType>::NativeType;
1550 auto native = std::forward<Self>(self).template array<Native>();
1551 return T(
1552 detail::TransformIterator(native.begin(), detail::fromNative<ValueType>),
1553 detail::TransformIterator(native.end(), detail::fromNative<ValueType>)
1554 );
1555 }
1556 }
1557};
1558
1559UAPP_TYPEREGISTRY_NATIVE(Variant, UA_TYPES_VARIANT)
1560
1561/* ------------------------------------------ DataValue ----------------------------------------- */
1562
1563/**
1564 * UA_DataValue wrapper class.
1565 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.11
1566 * @ingroup Wrapper
1567 */
1568class DataValue : public WrapperNative<UA_DataValue, UA_TYPES_DATAVALUE> {
1569public:
1570 using Wrapper::Wrapper;
1571
1572 explicit DataValue(Variant value) noexcept {
1573 setValue(std::move(value));
1574 }
1575
1577 Variant value,
1578 std::optional<DateTime> sourceTimestamp, // NOLINT(*value-param)
1579 std::optional<DateTime> serverTimestamp, // NOLINT(*value-param)
1580 std::optional<uint16_t> sourcePicoseconds,
1581 std::optional<uint16_t> serverPicoseconds,
1582 std::optional<StatusCode> status // NOLINT(*value-param)
1583 ) noexcept
1585 UA_Variant{},
1586 sourceTimestamp.value_or(UA_DateTime{}),
1587 serverTimestamp.value_or(UA_DateTime{}),
1588 sourcePicoseconds.value_or(uint16_t{}),
1589 serverPicoseconds.value_or(uint16_t{}),
1590 status.value_or(UA_StatusCode{}),
1591 false,
1592 sourceTimestamp.has_value(),
1593 serverTimestamp.has_value(),
1594 sourcePicoseconds.has_value(),
1595 serverPicoseconds.has_value(),
1596 status.has_value(),
1597 }} {
1598 setValue(std::move(value));
1599 }
1600
1601 /// Set value (copy).
1602 void setValue(const Variant& value) {
1603 asWrapper<Variant>(handle()->value) = value;
1604 handle()->hasValue = true;
1605 }
1606
1607 /// Set value (move).
1608 void setValue(Variant&& value) noexcept {
1609 asWrapper<Variant>(handle()->value) = std::move(value);
1610 handle()->hasValue = true;
1611 }
1612
1613 /// Set source timestamp for the value.
1614 void setSourceTimestamp(DateTime sourceTimestamp) noexcept { // NOLINT
1615 handle()->sourceTimestamp = sourceTimestamp.get();
1616 handle()->hasSourceTimestamp = true;
1617 }
1618
1619 /// Set server timestamp for the value.
1620 void setServerTimestamp(DateTime serverTimestamp) noexcept { // NOLINT
1621 handle()->serverTimestamp = serverTimestamp.get();
1622 handle()->hasServerTimestamp = true;
1623 }
1624
1625 /// Set picoseconds interval added to the source timestamp.
1626 void setSourcePicoseconds(uint16_t sourcePicoseconds) noexcept {
1627 handle()->sourcePicoseconds = sourcePicoseconds;
1628 handle()->hasSourcePicoseconds = true;
1629 }
1630
1631 /// Set picoseconds interval added to the server timestamp.
1632 void setServerPicoseconds(uint16_t serverPicoseconds) noexcept {
1633 handle()->serverPicoseconds = serverPicoseconds;
1634 handle()->hasServerPicoseconds = true;
1635 }
1636
1637 /// Set status.
1638 void setStatus(StatusCode status) noexcept {
1639 handle()->status = status;
1640 handle()->hasStatus = true;
1641 }
1642
1643 bool hasValue() const noexcept {
1644 return handle()->hasValue;
1645 }
1646
1647 bool hasSourceTimestamp() const noexcept {
1648 return handle()->hasSourceTimestamp;
1649 }
1650
1651 bool hasServerTimestamp() const noexcept {
1652 return handle()->hasServerTimestamp;
1653 }
1654
1655 bool hasSourcePicoseconds() const noexcept {
1656 return handle()->hasSourcePicoseconds;
1657 }
1658
1659 bool hasServerPicoseconds() const noexcept {
1660 return handle()->hasServerPicoseconds;
1661 }
1662
1663 bool hasStatus() const noexcept {
1664 return handle()->hasStatus;
1665 }
1666
1667 /// Get value.
1668 Variant& value() & noexcept {
1669 return asWrapper<Variant>(handle()->value);
1670 }
1671
1672 /// Get value.
1673 const Variant& value() const& noexcept {
1674 return asWrapper<Variant>(handle()->value);
1675 }
1676
1677 /// Get value (rvalue).
1678 Variant&& value() && noexcept {
1679 return std::move(value());
1680 }
1681
1682 /// Get value (rvalue).
1683 const Variant&& value() const&& noexcept {
1684 return std::move(value()); // NOLINT(*move-const-arg)
1685 }
1686
1687 /// Get source timestamp for the value.
1688 DateTime sourceTimestamp() const noexcept {
1689 return DateTime{handle()->sourceTimestamp}; // NOLINT
1690 }
1691
1692 /// Get server timestamp for the value.
1693 DateTime serverTimestamp() const noexcept {
1694 return DateTime{handle()->serverTimestamp}; // NOLINT
1695 }
1696
1697 /// Get picoseconds interval added to the source timestamp.
1698 uint16_t sourcePicoseconds() const noexcept {
1699 return handle()->sourcePicoseconds;
1700 }
1701
1702 /// Get picoseconds interval added to the server timestamp.
1703 uint16_t serverPicoseconds() const noexcept {
1704 return handle()->serverPicoseconds;
1705 }
1706
1707 /// Get status.
1708 StatusCode status() const noexcept {
1709 return handle()->status;
1710 }
1711};
1712
1713UAPP_TYPEREGISTRY_NATIVE(DataValue, UA_TYPES_DATAVALUE)
1714
1715/* --------------------------------------- ExtensionObject -------------------------------------- */
1716
1717/**
1718 * Extension object encoding.
1719 * @see UA_ExtensionObjectEncoding
1720 */
1730
1731/**
1732 * UA_ExtensionObject wrapper class.
1733 *
1734 * ExtensionObjects may contain scalars of any data type. Even those that are unknown to the
1735 * receiver. If the received data type is unknown, the encoded string and target NodeId is stored
1736 * instead of the decoded data.
1737 *
1738 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.1.6
1739 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.2.2.15
1740 * @ingroup Wrapper
1741 */
1742class ExtensionObject : public WrapperNative<UA_ExtensionObject, UA_TYPES_EXTENSIONOBJECT> {
1743private:
1744 template <typename T>
1745 static constexpr bool isExtensionObject =
1746 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ExtensionObject> ||
1747 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, UA_ExtensionObject>;
1748
1749public:
1750 using Wrapper::Wrapper;
1751
1752 /**
1753 * Create ExtensionObject from a pointer to a decoded object (no copy).
1754 * The object will *not* be deleted when the ExtensionObject is destructed.
1755 * @param ptr Pointer to decoded object (native or wrapper).
1756 */
1757 template <typename T>
1758 explicit ExtensionObject(T* ptr) noexcept
1759 : ExtensionObject{ptr, getDataType<T>()} {}
1760
1761 /**
1762 * Create ExtensionObject from a pointer to a decoded object with a custom data type (no copy).
1763 * The object will *not* be deleted when the ExtensionObject is destructed.
1764 * @param ptr Pointer to decoded object (native or wrapper).
1765 * @param type Data type of the decoded object.
1766 */
1767 template <typename T>
1768 ExtensionObject(T* ptr, const UA_DataType& type) noexcept {
1769 if (ptr == nullptr) {
1770 return;
1771 }
1772 assert(sizeof(T) == type.memSize);
1774 handle()->content.decoded.type = &type; // NOLINT
1775 handle()->content.decoded.data = ptr; // NOLINT
1776 }
1777
1778 /**
1779 * Create ExtensionObject from a decoded object (copy).
1780 * @param decoded Decoded object (native or wrapper).
1781 */
1782 template <typename T, typename = std::enable_if_t<!isExtensionObject<T>>>
1783 explicit ExtensionObject(const T& decoded)
1784 : ExtensionObject{decoded, getDataType<T>()} {}
1785
1786 /**
1787 * Create ExtensionObject from a decoded object with a custom data type (copy).
1788 * @param decoded Decoded object (native or wrapper).
1789 * @param type Data type of the decoded object.
1790 */
1791 template <typename T, typename = std::enable_if_t<!isExtensionObject<T>>>
1792 explicit ExtensionObject(const T& decoded, const UA_DataType& type) {
1793 auto ptr = detail::allocateUniquePtr<T>(type);
1794 *ptr = detail::copy(decoded, type);
1795 handle()->encoding = UA_EXTENSIONOBJECT_DECODED;
1796 handle()->content.decoded.type = &type; // NOLINT
1797 handle()->content.decoded.data = ptr.release(); // NOLINT
1798 }
1799
1800 /// Check if the ExtensionObject is empty
1801 bool empty() const noexcept {
1803 }
1804
1805 /// Check if the ExtensionObject is encoded (usually if the data type is unknown).
1806 bool isEncoded() const noexcept {
1808 (handle()->encoding == UA_EXTENSIONOBJECT_ENCODED_XML);
1809 }
1810
1811 /// Check if the ExtensionObject is decoded.
1812 bool isDecoded() const noexcept {
1815 }
1816
1817 /// Get the encoding.
1819 return static_cast<ExtensionObjectEncoding>(handle()->encoding);
1820 }
1821
1822 /// Get the encoded type id.
1823 /// Returns `nullptr` if ExtensionObject is not encoded.
1824 const NodeId* encodedTypeId() const noexcept {
1825 return isEncoded()
1826 ? asWrapper<NodeId>(&handle()->content.encoded.typeId) // NOLINT
1827 : nullptr;
1828 }
1829
1830 /// Get the encoded body in binary format.
1831 /// Returns `nullptr` if ExtensionObject is not encoded in binary format.
1832 const ByteString* encodedBinary() const noexcept {
1833 return handle()->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING
1834 ? asWrapper<ByteString>(&handle()->content.encoded.body) // NOLINT
1835 : nullptr;
1836 }
1837
1838 /// Get the encoded body in XML format.
1839 /// Returns `nullptr` if ExtensionObject is not encoded in XML format.
1840 const XmlElement* encodedXml() const noexcept {
1841 return handle()->encoding == UA_EXTENSIONOBJECT_ENCODED_XML
1842 ? asWrapper<XmlElement>(&handle()->content.encoded.body) // NOLINT
1843 : nullptr;
1844 }
1845
1846 /// Get the decoded data type.
1847 /// Returns `nullptr` if ExtensionObject is not decoded.
1848 const UA_DataType* decodedType() const noexcept {
1849 return isDecoded()
1850 ? handle()->content.decoded.type // NOLINT
1851 : nullptr;
1852 }
1853
1854 /// Get pointer to the decoded data with given template type.
1855 /// Returns `nullptr` if the ExtensionObject is either not decoded or the decoded data is not of
1856 /// type `T`.
1857 template <typename T>
1858 T* decodedData() noexcept {
1859 return isDecodedType<T>() ? static_cast<T*>(decodedData()) : nullptr;
1860 }
1861
1862 /// Get const pointer to the decoded data with given template type.
1863 /// Returns `nullptr` if the ExtensionObject is either not decoded or the decoded data is not of
1864 /// type `T`.
1865 template <typename T>
1866 const T* decodedData() const noexcept {
1867 return isDecodedType<T>() ? static_cast<const T*>(decodedData()) : nullptr;
1868 }
1869
1870 /// Get pointer to the decoded data.
1871 /// Returns `nullptr` if the ExtensionObject is not decoded.
1872 /// @warning Type erased version, use with caution.
1873 void* decodedData() noexcept {
1874 return isDecoded()
1875 ? handle()->content.decoded.data // NOLINT
1876 : nullptr;
1877 }
1878
1879 /// Get pointer to the decoded data.
1880 /// Returns `nullptr` if the ExtensionObject is not decoded.
1881 /// @warning Type erased version, use with caution.
1882 const void* decodedData() const noexcept {
1883 return isDecoded()
1884 ? handle()->content.decoded.data // NOLINT
1885 : nullptr;
1886 }
1887
1888private:
1889 template <typename T>
1890 bool isDecodedType() const noexcept {
1891 const auto* type = decodedType();
1892 return (type != nullptr) && (type->typeId == getDataType<T>().typeId);
1893 }
1894};
1895
1896UAPP_TYPEREGISTRY_NATIVE(ExtensionObject, UA_TYPES_EXTENSIONOBJECT)
1897
1898/* --------------------------------------- DiagnosticInfo --------------------------------------- */
1899
1900/**
1901 * UA_DiagnosticInfo wrapper class.
1902 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.12
1903 * @ingroup Wrapper
1904 */
1905class DiagnosticInfo : public WrapperNative<UA_DiagnosticInfo, UA_TYPES_DIAGNOSTICINFO> {
1906public:
1907 using Wrapper::Wrapper;
1908
1909 bool hasSymbolicId() const noexcept {
1910 return handle()->hasSymbolicId;
1911 }
1912
1913 bool hasNamespaceUri() const noexcept {
1914 return handle()->hasNamespaceUri;
1915 }
1916
1917 bool hasLocalizedText() const noexcept {
1918 return handle()->hasLocalizedText;
1919 }
1920
1921 bool hasLocale() const noexcept {
1922 return handle()->hasLocale;
1923 }
1924
1925 bool hasAdditionalInfo() const noexcept {
1926 return handle()->hasAdditionalInfo;
1927 }
1928
1929 bool hasInnerStatusCode() const noexcept {
1930 return handle()->hasInnerStatusCode;
1931 }
1932
1933 bool hasInnerDiagnosticInfo() const noexcept {
1934 return handle()->hasInnerDiagnosticInfo;
1935 }
1936
1937 int32_t symbolicId() const noexcept {
1938 return handle()->symbolicId;
1939 }
1940
1941 int32_t namespaceUri() const noexcept {
1942 return handle()->namespaceUri;
1943 }
1944
1945 int32_t localizedText() const noexcept {
1946 return handle()->localizedText;
1947 }
1948
1949 int32_t locale() const noexcept {
1950 return handle()->locale;
1951 }
1952
1953 const String& additionalInfo() const noexcept {
1954 return asWrapper<String>(handle()->additionalInfo);
1955 }
1956
1957 StatusCode innerStatusCode() const noexcept {
1958 return handle()->innerStatusCode;
1959 }
1960
1961 const DiagnosticInfo* innerDiagnosticInfo() const noexcept {
1962 return asWrapper<DiagnosticInfo>(handle()->innerDiagnosticInfo);
1963 }
1964};
1965
1966UAPP_TYPEREGISTRY_NATIVE(DiagnosticInfo, UA_TYPES_DIAGNOSTICINFO)
1967
1968/* ---------------------------------------- NumericRange ---------------------------------------- */
1969
1971
1972/// @relates NumericRange
1973inline bool operator==(
1974 const NumericRangeDimension& lhs, const NumericRangeDimension& rhs
1975) noexcept {
1976 return (lhs.min == rhs.min) && (lhs.max == rhs.max);
1977}
1978
1979/// @relates NumericRange
1980inline bool operator!=(
1981 const NumericRangeDimension& lhs, const NumericRangeDimension& rhs
1982) noexcept {
1983 return !(lhs == rhs);
1984}
1985
1986/**
1987 * UA_NumericRange wrapper class.
1988 *
1989 * Numeric ranges indicate subsets of (multidimensional) arrays.
1990 * They are no official data type in the OPC UA standard and are transmitted only with a string
1991 * encoding, such as "1:2,0:3,5". The colon separates min/max index and the comma separates
1992 * dimensions. A single value indicates a range with a single element (min==max).
1993 *
1994 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.27
1995 * @ingroup Wrapper
1996 */
1997class NumericRange : public Wrapper<UA_NumericRange> {
1998public:
1999 NumericRange() = default;
2000
2001 /// Create a NumericRange from the encoded representation, e.g. `1:2,0:3,5`.
2002 explicit NumericRange(std::string_view encodedRange);
2003
2004 /// @overload
2005 explicit NumericRange(const char* encodedRange) // required to avoid ambiguity
2006 : NumericRange{std::string_view{encodedRange}} {}
2007
2008 /// Create a NumericRange from dimensions.
2011
2012 /// Create a NumericRange from native object (copy).
2014 : Wrapper{copy(native)} {}
2015
2016 /// Create a NumericRange from native object (move).
2018 : Wrapper{std::exchange(native, {})} {}
2019
2021 clear();
2022 }
2023
2025 : Wrapper{copy(other.native())} {}
2026
2027 NumericRange(NumericRange&& other) noexcept
2028 : Wrapper{std::exchange(other.native(), {})} {}
2029
2031 if (this != &other) {
2032 clear();
2033 native() = copy(other.native());
2034 }
2035 return *this;
2036 }
2037
2039 if (this != &other) {
2040 clear();
2041 native() = std::exchange(other.native(), {});
2042 }
2043 return *this;
2044 }
2045
2046 bool empty() const noexcept {
2047 return native().dimensionsSize == 0;
2048 }
2049
2053
2054 /// @deprecated Use free function opcua::toString(const T&) instead
2055 [[deprecated("use free function toString instead")]]
2057
2058private:
2059 void clear() noexcept {
2060 detail::deallocateArray(native().dimensions);
2061 native() = {};
2062 }
2063
2064 [[nodiscard]] static UA_NumericRange copy(const UA_NumericRangeDimension* array, size_t size) {
2065 UA_NumericRange result{};
2066 result.dimensions = detail::copyArray(array, size);
2067 result.dimensionsSize = size;
2068 return result;
2069 }
2070
2071 [[nodiscard]] static UA_NumericRange copy(const UA_NumericRange& other) {
2072 return copy(other.dimensions, other.dimensionsSize);
2073 }
2074};
2075
2077
2078/* --------------------------------------- Free functions --------------------------------------- */
2079
2080/**
2081 * Converts an object to its string representation.
2082 *
2083 * This function wraps @ref UA_print to generate a string representation of the given object, based
2084 * on its data type description.
2085 *
2086 * @note
2087 * Requires open62541 v1.2 or later.
2088 * The open62541 library must be compiled with the `UA_ENABLE_TYPEDESCRIPTION` option.
2089 * If these conditions are not met, the function returns an empty String.
2090 *
2091 * @param object Native or wrapper object.
2092 * @param type Data type of `object`.
2093 *
2094 * @relates TypeWrapper
2095 * @ingroup Wrapper
2096 */
2097template <typename T>
2098String toString(const T& object, const UA_DataType& type) {
2099 String output;
2100 if constexpr (UAPP_HAS_TOSTRING) {
2101 throwIfBad(UA_print(&object, &type, output.handle()));
2102 }
2103 return output;
2104}
2105
2106/**
2107 * @overload
2108 * @relates TypeWrapper
2109 * @ingroup Wrapper
2110 */
2111template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2112String toString(const T& object) {
2113 return toString(object, getDataType<T>());
2114}
2115
2116/* ------------------------------------ Comparison operators ------------------------------------ */
2117
2118#if UAPP_HAS_ORDER
2119
2120/// @relates TypeWrapper
2121/// @ingroup Wrapper
2122template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2123inline bool operator==(const T& lhs, const T& rhs) noexcept {
2124 return UA_order(&lhs, &rhs, &getDataType<T>()) == UA_ORDER_EQ;
2125}
2126
2127/// @relates TypeWrapper
2128/// @ingroup Wrapper
2129template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2130inline bool operator!=(const T& lhs, const T& rhs) noexcept {
2131 return UA_order(&lhs, &rhs, &getDataType<T>()) != UA_ORDER_EQ;
2132}
2133
2134/// @relates TypeWrapper
2135/// @ingroup Wrapper
2136template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2137inline bool operator<(const T& lhs, const T& rhs) noexcept {
2138 return UA_order(&lhs, &rhs, &getDataType<T>()) == UA_ORDER_LESS;
2139}
2140
2141/// @relates TypeWrapper
2142/// @ingroup Wrapper
2143template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2144inline bool operator<=(const T& lhs, const T& rhs) noexcept {
2145 return UA_order(&lhs, &rhs, &getDataType<T>()) <= UA_ORDER_EQ;
2146}
2147
2148/// @relates TypeWrapper
2149/// @ingroup Wrapper
2150template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2151inline bool operator>(const T& lhs, const T& rhs) noexcept {
2152 return UA_order(&lhs, &rhs, &getDataType<T>()) == UA_ORDER_MORE;
2153}
2154
2155/// @relates TypeWrapper
2156/// @ingroup Wrapper
2157template <typename T, typename = std::enable_if_t<IsRegistered<T>::value>>
2158inline bool operator>=(const T& lhs, const T& rhs) noexcept {
2159 return UA_order(&lhs, &rhs, &getDataType<T>()) >= UA_ORDER_EQ;
2160}
2161
2162#endif
2163
2164} // namespace opcua
2165
2166/* ---------------------------------- std::hash specializations --------------------------------- */
2167
2168template <>
2169struct std::hash<opcua::NodeId> {
2170 std::size_t operator()(const opcua::NodeId& id) const noexcept {
2171 return id.hash();
2172 }
2173};
2174
2175template <>
2176struct std::hash<opcua::ExpandedNodeId> {
2177 std::size_t operator()(const opcua::ExpandedNodeId& id) const noexcept {
2178 return id.hash();
2179 }
2180};
UA_ByteString wrapper class.
Definition types.hpp:537
ByteString(InputIt first, InputIt last)
Definition types.hpp:552
ByteString(std::string_view str)
Definition types.hpp:541
String toBase64() const
Convert to Base64 encoded string.
ByteString(Span< const uint8_t > bytes)
Definition types.hpp:547
static ByteString fromBase64(std::string_view encoded)
Parse ByteString from Base64 encoded string.
ByteString(const char *str)
Definition types.hpp:544
UA_DataValue wrapper class.
Definition types.hpp:1568
bool hasServerPicoseconds() const noexcept
Definition types.hpp:1659
void setSourceTimestamp(DateTime sourceTimestamp) noexcept
Set source timestamp for the value.
Definition types.hpp:1614
uint16_t serverPicoseconds() const noexcept
Get picoseconds interval added to the server timestamp.
Definition types.hpp:1703
bool hasValue() const noexcept
Definition types.hpp:1643
DataValue(Variant value) noexcept
Definition types.hpp:1572
StatusCode status() const noexcept
Get status.
Definition types.hpp:1708
const Variant && value() const &&noexcept
Get value (rvalue).
Definition types.hpp:1683
DateTime serverTimestamp() const noexcept
Get server timestamp for the value.
Definition types.hpp:1693
bool hasSourceTimestamp() const noexcept
Definition types.hpp:1647
void setServerPicoseconds(uint16_t serverPicoseconds) noexcept
Set picoseconds interval added to the server timestamp.
Definition types.hpp:1632
uint16_t sourcePicoseconds() const noexcept
Get picoseconds interval added to the source timestamp.
Definition types.hpp:1698
Variant && value() &&noexcept
Get value (rvalue).
Definition types.hpp:1678
bool hasStatus() const noexcept
Definition types.hpp:1663
void setValue(Variant &&value) noexcept
Set value (move).
Definition types.hpp:1608
void setServerTimestamp(DateTime serverTimestamp) noexcept
Set server timestamp for the value.
Definition types.hpp:1620
void setStatus(StatusCode status) noexcept
Set status.
Definition types.hpp:1638
Variant & value() &noexcept
Get value.
Definition types.hpp:1668
void setSourcePicoseconds(uint16_t sourcePicoseconds) noexcept
Set picoseconds interval added to the source timestamp.
Definition types.hpp:1626
bool hasSourcePicoseconds() const noexcept
Definition types.hpp:1655
DateTime sourceTimestamp() const noexcept
Get source timestamp for the value.
Definition types.hpp:1688
bool hasServerTimestamp() const noexcept
Definition types.hpp:1651
void setValue(const Variant &value)
Set value (copy).
Definition types.hpp:1602
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
Definition types.hpp:1576
const Variant & value() const &noexcept
Get value.
Definition types.hpp:1673
UA_DateTime wrapper class.
Definition types.hpp:381
String format(std::string_view format, bool localtime=false) const
Convert to string with given format (same format codes as strftime).
int64_t get() const noexcept
Get DateTime value as 100 nanosecond intervals since January 1, 1601 (UTC).
Definition types.hpp:441
UA_DateTimeStruct toStruct() const noexcept
Convert to UA_DateTimeStruct.
Definition types.hpp:436
static DateTime fromUnixTime(int64_t unixTime) noexcept
Get DateTime from Unix time.
Definition types.hpp:407
static DateTime now() noexcept
Get current DateTime.
Definition types.hpp:393
static DateTime fromTimePoint(std::chrono::time_point< Clock, Duration > timePoint)
Get DateTime from std::chrono::time_point.
Definition types.hpp:399
int64_t toUnixTime() const noexcept
Convert to Unix time (number of seconds since January 1, 1970 UTC).
Definition types.hpp:428
static int64_t localTimeUtcOffset() noexcept
Offset of local time to UTC.
Definition types.hpp:412
DateTime(std::chrono::time_point< Clock, Duration > timePoint)
Definition types.hpp:389
std::chrono::duration< int64_t, std::ratio< 1, 10 '000 '000 > > UaDuration
Definition types.hpp:384
std::chrono::time_point< Clock, Duration > toTimePoint() const
Convert to std::chrono::time_point.
Definition types.hpp:418
std::chrono::system_clock DefaultClock
Definition types.hpp:383
UA_DiagnosticInfo wrapper class.
Definition types.hpp:1905
bool hasInnerStatusCode() const noexcept
Definition types.hpp:1929
bool hasLocalizedText() const noexcept
Definition types.hpp:1917
int32_t symbolicId() const noexcept
Definition types.hpp:1937
bool hasSymbolicId() const noexcept
Definition types.hpp:1909
int32_t locale() const noexcept
Definition types.hpp:1949
StatusCode innerStatusCode() const noexcept
Definition types.hpp:1957
const String & additionalInfo() const noexcept
Definition types.hpp:1953
bool hasLocale() const noexcept
Definition types.hpp:1921
bool hasInnerDiagnosticInfo() const noexcept
Definition types.hpp:1933
const DiagnosticInfo * innerDiagnosticInfo() const noexcept
Definition types.hpp:1961
int32_t namespaceUri() const noexcept
Definition types.hpp:1941
bool hasNamespaceUri() const noexcept
Definition types.hpp:1913
int32_t localizedText() const noexcept
Definition types.hpp:1945
bool hasAdditionalInfo() const noexcept
Definition types.hpp:1925
UA_ExpandedNodeId wrapper class.
Definition types.hpp:822
static ExpandedNodeId parse(std::string_view str)
Parse ExpandedNodeId from its string representation.
Definition types.hpp:841
bool operator<=(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:898
uint32_t hash() const noexcept
Definition types.hpp:852
ExpandedNodeId(NodeId id) noexcept
Definition types.hpp:826
ExpandedNodeId(NodeId id, std::string_view namespaceUri, uint32_t serverIndex)
Definition types.hpp:830
bool operator>=(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:903
bool isLocal() const noexcept
Definition types.hpp:848
bool operator!=(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:883
uint32_t serverIndex() const noexcept
Definition types.hpp:868
bool operator<(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:888
std::string_view namespaceUri() const
Definition types.hpp:864
String toString() const
const NodeId & nodeId() const noexcept
Definition types.hpp:860
NodeId & nodeId() noexcept
Definition types.hpp:856
bool operator>(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:893
bool operator==(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:878
UA_ExtensionObject wrapper class.
Definition types.hpp:1742
bool isDecoded() const noexcept
Check if the ExtensionObject is decoded.
Definition types.hpp:1812
ExtensionObject(T *ptr, const UA_DataType &type) noexcept
Create ExtensionObject from a pointer to a decoded object with a custom data type (no copy).
Definition types.hpp:1768
const UA_DataType * decodedType() const noexcept
Get the decoded data type.
Definition types.hpp:1848
const XmlElement * encodedXml() const noexcept
Get the encoded body in XML format.
Definition types.hpp:1840
T * decodedData() noexcept
Get pointer to the decoded data with given template type.
Definition types.hpp:1858
ExtensionObject(T *ptr) noexcept
Create ExtensionObject from a pointer to a decoded object (no copy).
Definition types.hpp:1758
bool empty() const noexcept
Check if the ExtensionObject is empty.
Definition types.hpp:1801
ExtensionObject(const T &decoded)
Create ExtensionObject from a decoded object (copy).
Definition types.hpp:1783
const NodeId * encodedTypeId() const noexcept
Get the encoded type id.
Definition types.hpp:1824
void * decodedData() noexcept
Get pointer to the decoded data.
Definition types.hpp:1873
const T * decodedData() const noexcept
Get const pointer to the decoded data with given template type.
Definition types.hpp:1866
bool isEncoded() const noexcept
Check if the ExtensionObject is encoded (usually if the data type is unknown).
Definition types.hpp:1806
ExtensionObject(const T &decoded, const UA_DataType &type)
Create ExtensionObject from a decoded object with a custom data type (copy).
Definition types.hpp:1792
const ByteString * encodedBinary() const noexcept
Get the encoded body in binary format.
Definition types.hpp:1832
ExtensionObjectEncoding encoding() const noexcept
Get the encoding.
Definition types.hpp:1818
const void * decodedData() const noexcept
Get pointer to the decoded data.
Definition types.hpp:1882
UA_Guid wrapper class.
Definition types.hpp:473
String toString() const
Guid(uint32_t data1, uint16_t data2, uint16_t data3, std::array< uint8_t, 8 > data4) noexcept
Definition types.hpp:489
Guid(std::array< uint8_t, 16 > data) noexcept
Definition types.hpp:477
bool operator==(const UA_Guid &lhs, const UA_Guid &rhs) noexcept
Definition types.hpp:518
static Guid parse(std::string_view str)
Parse Guid from its string representation.
Definition types.hpp:505
bool operator!=(const UA_Guid &lhs, const UA_Guid &rhs) noexcept
Definition types.hpp:523
static Guid random() noexcept
Generate random Guid.
Definition types.hpp:498
UA_LocalizedText wrapper class.
Definition types.hpp:956
bool operator==(const UA_LocalizedText &lhs, const UA_LocalizedText &rhs) noexcept
Definition types.hpp:975
std::string_view text() const noexcept
Definition types.hpp:969
std::string_view locale() const noexcept
Definition types.hpp:965
bool operator!=(const UA_LocalizedText &lhs, const UA_LocalizedText &rhs) noexcept
Definition types.hpp:980
LocalizedText(std::string_view locale, std::string_view text)
Definition types.hpp:960
UA_NodeId wrapper class.
Definition types.hpp:641
const T & identifier() const
Get identifier reference.
Definition types.hpp:771
NodeId(T identifier) noexcept
Create NodeId from enum class with numeric identifiers like opcua::ObjectId.
Definition types.hpp:679
NodeIdType identifierType() const noexcept
Definition types.hpp:705
String toString() const
static NodeId parse(std::string_view str)
Parse NodeId from its string representation.
Definition types.hpp:686
NamespaceIndex namespaceIndex() const noexcept
Definition types.hpp:701
NodeId(NamespaceIndex namespaceIndex, uint32_t identifier) noexcept
Create NodeId with numeric identifier.
Definition types.hpp:646
NodeId(NamespaceIndex namespaceIndex, ByteString identifier) noexcept
Create NodeId with ByteString identifier.
Definition types.hpp:667
bool operator!=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:789
bool operator<(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:794
bool operator>(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:799
NodeId(NamespaceIndex namespaceIndex, Guid identifier) noexcept
Create NodeId with Guid identifier.
Definition types.hpp:660
const T * identifierIf() const noexcept
Get identifier pointer or nullptr on error.
Definition types.hpp:726
bool operator==(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:784
bool isNull() const noexcept
Definition types.hpp:693
bool operator>=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:809
bool operator<=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:804
T * identifierIf() noexcept
Get identifier pointer or nullptr on error.
Definition types.hpp:720
T & identifier()
Get identifier reference.
Definition types.hpp:765
uint32_t hash() const noexcept
Definition types.hpp:697
NodeId(NamespaceIndex namespaceIndex, std::string_view identifier)
Create NodeId with String identifier.
Definition types.hpp:653
UA_NumericRange wrapper class.
Definition types.hpp:1997
bool empty() const noexcept
Definition types.hpp:2046
NumericRange(UA_NumericRange &&native) noexcept
Create a NumericRange from native object (move).
Definition types.hpp:2017
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
Definition types.hpp:1980
NumericRange(const char *encodedRange)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition types.hpp:2005
NumericRange(Span< const NumericRangeDimension > dimensions)
Create a NumericRange from dimensions.
Definition types.hpp:2009
Span< const NumericRangeDimension > dimensions() const noexcept
Definition types.hpp:2050
NumericRange(const NumericRange &other)
Definition types.hpp:2024
NumericRange()=default
NumericRange(NumericRange &&other) noexcept
Definition types.hpp:2027
String toString() const
NumericRange(const UA_NumericRange &native)
Create a NumericRange from native object (copy).
Definition types.hpp:2013
NumericRange & operator=(const NumericRange &other)
Definition types.hpp:2030
NumericRange & operator=(NumericRange &&other) noexcept
Definition types.hpp:2038
UA_QualifiedName wrapper class.
Definition types.hpp:915
bool operator!=(const UA_QualifiedName &lhs, const UA_QualifiedName &rhs) noexcept
Definition types.hpp:939
bool operator==(const UA_QualifiedName &lhs, const UA_QualifiedName &rhs) noexcept
Definition types.hpp:934
NamespaceIndex namespaceIndex() const noexcept
Definition types.hpp:924
QualifiedName(NamespaceIndex namespaceIndex, std::string_view name)
Definition types.hpp:919
std::string_view name() const noexcept
Definition types.hpp:928
View to a contiguous sequence of objects, similar to std::span in C++20.
Definition span.hpp:29
constexpr iterator begin() const noexcept
Definition span.hpp:131
constexpr iterator end() const noexcept
Definition span.hpp:135
UA_StatusCode wrapper class.
Definition types.hpp:44
constexpr void throwIfBad() const
Throw a BadStatus exception if the status code is bad.
Definition types.hpp:82
constexpr bool isUncertain() const noexcept
Check if the status code is uncertain.
Definition types.hpp:71
constexpr bool isBad() const noexcept
Check if the status code is bad.
Definition types.hpp:76
std::string_view name() const noexcept
Get human-readable name of the StatusCode.
Definition types.hpp:61
constexpr bool isGood() const noexcept
Check if the status code is good.
Definition types.hpp:66
constexpr UA_StatusCode get() const noexcept
Explicitly get underlying UA_StatusCode.
Definition types.hpp:53
constexpr StatusCode() noexcept=default
Create a StatusCode with the default status code UA_STATUSCODE_GOOD.
UA_String wrapper class.
Definition types.hpp:256
String & operator=(std::basic_string_view< char, Traits > str)
Assign std::string_view.
Definition types.hpp:280
String(std::initializer_list< char > values)
Definition types.hpp:268
bool operator!=(const String &lhs, const String &rhs) noexcept
Definition types.hpp:308
bool operator==(std::string_view lhs, const String &rhs) noexcept
Definition types.hpp:323
bool operator==(const String &lhs, std::string_view rhs) noexcept
Definition types.hpp:313
String(InputIt first, InputIt last)
Definition types.hpp:264
bool operator==(const String &lhs, const String &rhs) noexcept
Definition types.hpp:303
String & operator=(const char *str)
Assign null-termined character string.
Definition types.hpp:273
bool operator!=(const String &lhs, std::string_view rhs) noexcept
Definition types.hpp:318
bool operator!=(std::string_view lhs, const String &rhs) noexcept
Definition types.hpp:328
String(std::string_view str)
Definition types.hpp:260
std::ostream & operator<<(std::ostream &os, const String &str)
bool operator!=(const UA_String &lhs, const UA_String &rhs) noexcept
Definition types.hpp:298
bool operator==(const UA_String &lhs, const UA_String &rhs) noexcept
Definition types.hpp:293
Exception for type-related errors.
Definition exception.hpp:45
UA_Variant wrapper class.
Definition types.hpp:1048
Variant(InputIt first, InputIt last, const UA_DataType &type)
Create Variant from a range of elements with a custom data type (copy).
Definition types.hpp:1096
void assign(T &&value)
Assign scalar/array to variant (copy/move and convert if required).
Definition types.hpp:1155
Variant(T &&value, const UA_DataType &type)
Create Variant from a scalar/array with a custom data type (copy/move).
Definition types.hpp:1082
void assign(T &&value, const UA_DataType &type)
Assign scalar/array to variant with custom data type (copy/move).
Definition types.hpp:1178
bool isType(const UA_DataType &type) const noexcept
Check if the variant type is equal to the provided data type.
Definition types.hpp:1258
const void * data() const noexcept
Get pointer to the underlying data.
Definition types.hpp:1304
void assign(InputIt first, InputIt last)
Assign range to variant (copy and convert if required).
Definition types.hpp:1194
Variant(InputIt first, InputIt last)
Create Variant from a range of elements (copy).
Definition types.hpp:1089
void assign(InputIt first, InputIt last, const UA_DataType &type)
Assign range to variant with custom data type (copy).
Definition types.hpp:1212
Variant(T *ptr, const UA_DataType &type) noexcept
Create Variant from a pointer to a scalar/array with a custom data type (no copy).
Definition types.hpp:1068
T to() const &
Converts the variant to the specified type T with automatic conversion if required.
Definition types.hpp:1374
const T & scalar() const &
Get scalar value with given template type (only native or wrapper types).
Definition types.hpp:1318
Variant & operator=(T *value) noexcept
Assign pointer to scalar/array to variant (no copy).
Definition types.hpp:1219
Span< T > array()
Get array with given template type (only native or wrapper types).
Definition types.hpp:1338
T scalar() &&
Get scalar value with given template type (only native or wrapper types).
Definition types.hpp:1325
Variant(T &&value)
Create Variant from a scalar/array (copy/move).
Definition types.hpp:1075
T scalar() const &&
Get scalar value with given template type (only native or wrapper types).
Definition types.hpp:1331
T & scalar() &
Get scalar value with given template type (only native or wrapper types).
Definition types.hpp:1311
bool isType(const UA_DataType *type) const noexcept
Check if the variant type is equal to the provided data type.
Definition types.hpp:1253
void assign(T *ptr) noexcept
Assign pointer to scalar/array to variant (no copy).
Definition types.hpp:1120
bool isType(const NodeId &id) const noexcept
Check if the variant type is equal to the provided data type id.
Definition types.hpp:1263
bool empty() const noexcept
Check if the variant is empty.
Definition types.hpp:1238
size_t arrayLength() const noexcept
Get array length or 0 if variant is not an array.
Definition types.hpp:1279
const UA_DataType * type() const noexcept
Get data type.
Definition types.hpp:1274
Variant(T *ptr) noexcept
Create Variant from a pointer to a scalar/array (no copy).
Definition types.hpp:1061
void assign(std::nullptr_t ptr, const UA_DataType &type) noexcept=delete
Span< const uint32_t > arrayDimensions() const noexcept
Get array dimensions.
Definition types.hpp:1284
bool isArray() const noexcept
Check if the variant is an array.
Definition types.hpp:1248
Span< const T > array() const
Get array with given template type (only native or wrapper types).
Definition types.hpp:1345
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).
Definition types.hpp:1137
Variant & operator=(T &&value)
Assign scalar/array to variant (copy and convert if required).
Definition types.hpp:1227
bool isScalar() const noexcept
Check if the variant is a scalar.
Definition types.hpp:1243
bool isType() const noexcept
Check if the variant type is equal to the provided template type.
Definition types.hpp:1269
T to() &&
Converts the variant to the specified type T with automatic conversion if required.
Definition types.hpp:1380
void * data() noexcept
Get pointer to the underlying data.
Definition types.hpp:1299
Template base class to wrap (native) objects.
Definition wrapper.hpp:135
constexpr T * handle() noexcept
Return pointer to native object.
Definition wrapper.hpp:221
constexpr const UA_StatusCode & native() const noexcept
Definition wrapper.hpp:243
constexpr Wrapper() noexcept=default
constexpr void clear() noexcept
Definition wrapper.hpp:251
UA_XmlElement wrapper class.
Definition types.hpp:581
XmlElement(std::string_view str)
Definition types.hpp:585
XmlElement & operator=(std::basic_string_view< char, Traits > str)
Assign std::string_view.
Definition types.hpp:601
XmlElement(InputIt first, InputIt last)
Definition types.hpp:589
XmlElement & operator=(const char *str)
Assign null-termined character string.
Definition types.hpp:594
UA_ORDER_LESS
UA_ORDER_MORE
UA_ORDER_EQ
constexpr Namespace namespaceOf(DataTypeId) noexcept
Get namespace of DataTypeId.
Definition nodeids.hpp:448
String toString(const T &object)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition types.hpp:2112
bool operator<=(const T &lhs, const T &rhs) noexcept
Definition types.hpp:2144
constexpr T::NativeType * asNative(T *wrapper) noexcept
Cast Wrapper object pointers to native object pointers.
Definition wrapper.hpp:342
bool operator<(const T &lhs, const T &rhs) noexcept
Definition types.hpp:2137
bool operator==(const T &lhs, const T &rhs) noexcept
Definition types.hpp:2123
bool operator>=(const T &lhs, const T &rhs) noexcept
Definition types.hpp:2158
bool operator!=(const T &lhs, const T &rhs) noexcept
Definition types.hpp:2130
bool operator>(const T &lhs, const T &rhs) noexcept
Definition types.hpp:2151
String toString(const T &object, const UA_DataType &type)
Converts an object to its string representation.
Definition types.hpp:2098
uint16_t NamespaceIndex
Namespace index.
Definition common.hpp:12
NodeIdType
NodeId types.
Definition types.hpp:629
ExtensionObjectEncoding
Extension object encoding.
Definition types.hpp:1721
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.
Definition exception.hpp:85
const UA_DataType & getDataType() noexcept
#define UA_STATUSCODE_BADOUTOFMEMORY
UA_UInt32 memSize
UA_NodeId typeId
UA_NumericRangeDimension * dimensions
size_t dimensionsSize
static String toNative(const char(&src)[N])
Definition types.hpp:361
static String toNative(const char *src)
Definition types.hpp:352
std::chrono::time_point< Clock, Duration > TimePoint
Definition types.hpp:452
Type conversion from and to native types.
std::size_t operator()(const opcua::ExpandedNodeId &id) const noexcept
Definition types.hpp:2177
std::size_t operator()(const opcua::NodeId &id) const noexcept
Definition types.hpp:2170
#define UAPP_TYPEREGISTRY_NATIVE(NativeType, typeIndex)
UA_NODEIDTYPE_STRING
UA_NODEIDTYPE_GUID
UA_NODEIDTYPE_BYTESTRING
UA_NODEIDTYPE_NUMERIC
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)
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_Order UA_order(const void *p1, const void *p2, const UA_DataType *type)
UA_Boolean UA_NodeId_isNull(const UA_NodeId *p)
int64_t UA_DateTime
UA_EXPORT const char * UA_StatusCode_name(UA_StatusCode code)
uint32_t UA_StatusCode
UA_VariantStorageType
UA_VARIANT_DATA_NODELETE
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)
#define UA_malloc
UA_StatusCode status