open62541pp 0.17.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>
15#include <string_view>
16#include <type_traits> // is_same_v
17#include <utility> // move
18#include <variant>
19#include <vector>
20
21#include "open62541pp/common.hpp" // NamespaceIndex
22#include "open62541pp/detail/iterator.hpp" // TransformIterator
24#include "open62541pp/detail/string_utils.hpp" // allocNativeString
28#include "open62541pp/span.hpp"
33
34namespace opcua {
35
36/* ----------------------------------------- StatusCode ----------------------------------------- */
37
38/**
39 * UA_StatusCode wrapper class.
40 * StatusCode can be used interchangeably with @ref UA_StatusCode due to implicit conversions
41 * (without any overhead) but provides some methods to simplify the handling with status codes.
42 * @see statuscodes.h
43 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.39
44 * @ingroup Wrapper
45 */
46class StatusCode : public Wrapper<UA_StatusCode> {
47public:
48 /// Create a StatusCode with the default status code `UA_STATUSCODE_GOOD`.
49 constexpr StatusCode() noexcept = default;
50
51 constexpr StatusCode(UA_StatusCode code) noexcept // NOLINT(hicpp-explicit-conversions)
52 : Wrapper(code) {}
53
54 /// Explicitly get underlying UA_StatusCode.
55 constexpr UA_StatusCode get() const noexcept {
56 return native();
57 }
58
59 /// Get human-readable name of the StatusCode.
60 /// This feature might be disabled to create a smaller binary with the
61 /// `UA_ENABLE_STATUSCODE_DESCRIPTIONS` build-flag. Then the function returns an empty string
62 /// for every StatusCode.
63 std::string_view name() const noexcept {
64 return {UA_StatusCode_name(native())};
65 }
66
67 /// Check if the status code is good.
68 constexpr bool isGood() const noexcept {
69 return detail::isGood(native());
70 }
71
72 /// Check if the status code is uncertain.
73 constexpr bool isUncertain() const noexcept {
74 return detail::isUncertain(native());
75 }
76
77 /// Check if the status code is bad.
78 constexpr bool isBad() const noexcept {
79 return detail::isBad(native());
80 }
81
82 /// Throw a BadStatus exception if the status code is bad.
83 /// @exception BadStatus
84 constexpr void throwIfBad() const {
86 }
87};
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 TypeWrapper<UA_String, UA_TYPES_STRING>,
256 public detail::StringLikeMixin<String, char> {
257public:
259
260 explicit String(std::string_view str)
261 : TypeWrapper(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 /// @deprecated Use conversion with `static_cast` instead
292 [[deprecated("use conversion with static_cast instead")]]
293 std::string_view get() const noexcept {
294 return {data(), size()};
295 }
296};
297
298/// @relates String
299inline bool operator==(const UA_String& lhs, const UA_String& rhs) noexcept {
300 return UA_String_equal(&lhs, &rhs);
301}
302
303/// @relates String
304inline bool operator!=(const UA_String& lhs, const UA_String& rhs) noexcept {
305 return !(lhs == rhs);
306}
307
308/// @relates String
309inline bool operator==(const String& lhs, std::string_view rhs) noexcept {
310 return static_cast<std::string_view>(lhs) == rhs;
311}
312
313/// @relates String
314inline bool operator!=(const String& lhs, std::string_view rhs) noexcept {
315 return static_cast<std::string_view>(lhs) != rhs;
316}
317
318/// @relates String
319inline bool operator==(std::string_view lhs, const String& rhs) noexcept {
320 return lhs == static_cast<std::string_view>(rhs);
321}
322
323/// @relates String
324inline bool operator!=(std::string_view lhs, const String& rhs) noexcept {
325 return lhs != static_cast<std::string_view>(rhs);
326}
327
328/// @relates String
329std::ostream& operator<<(std::ostream& os, const String& str);
330
331template <typename Traits>
332struct TypeConverter<std::basic_string_view<char, Traits>> {
333 using Type = std::basic_string_view<char, Traits>;
335
336 static void fromNative(const NativeType& src, Type& dst) {
337 dst = Type{src.data(), src.size()};
338 }
339
340 static void toNative(Type src, NativeType& dst) {
341 dst = NativeType{src};
342 }
343};
344
345template <typename Traits, typename Allocator>
346struct TypeConverter<std::basic_string<char, Traits, Allocator>> {
347 using Type = std::basic_string<char, Traits, Allocator>;
349
350 static void fromNative(const NativeType& src, Type& dst) {
351 dst = Type{src.data(), src.size()};
352 }
353
354 static void toNative(const Type& src, NativeType& dst) {
355 dst = NativeType{src};
356 }
357};
358
359template <>
360struct TypeConverter<const char*> {
361 using Type = const char*;
363
364 static void toNative(Type src, NativeType& dst) {
365 dst = NativeType{src};
366 }
367};
368
369template <size_t N>
370struct TypeConverter<char[N]> { // NOLINT
371 using Type = char[N]; // NOLINT
373
374 static void toNative(const Type& src, NativeType& dst) {
375 dst = NativeType{std::string_view{static_cast<const char*>(src), N}};
376 }
377};
378
379/* ------------------------------------------ DateTime ------------------------------------------ */
380
381/**
382 * UA_DateTime wrapper class.
383 *
384 * An instance in time. A DateTime value is encoded as a 64-bit signed integer which represents the
385 * number of 100 nanosecond intervals since January 1, 1601 (UTC).
386 *
387 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.2.2.5
388 * @ingroup Wrapper
389 */
390class DateTime : public TypeWrapper<UA_DateTime, UA_TYPES_DATETIME> {
391public:
392 using DefaultClock = std::chrono::system_clock;
393 using UaDuration = std::chrono::duration<int64_t, std::ratio<1, 10'000'000>>;
394
396
397 template <typename Clock, typename Duration>
398 DateTime(std::chrono::time_point<Clock, Duration> timePoint) // NOLINT(*-explicit-conversions)
399 : DateTime(fromTimePoint(timePoint)) {}
400
401 /// Get current DateTime.
402 static DateTime now() noexcept {
403 return DateTime(UA_DateTime_now()); // NOLINT
404 }
405
406 /// Get DateTime from std::chrono::time_point.
407 template <typename Clock, typename Duration>
408 static DateTime fromTimePoint(std::chrono::time_point<Clock, Duration> timePoint) {
409 return DateTime(
410 int64_t{UA_DATETIME_UNIX_EPOCH} +
411 std::chrono::duration_cast<UaDuration>(timePoint.time_since_epoch()).count()
412 );
413 }
414
415 /// Get DateTime from Unix time.
416 static DateTime fromUnixTime(int64_t unixTime) noexcept {
417 return DateTime(UA_DateTime_fromUnixTime(unixTime)); // NOLINT
418 }
419
420 /// Offset of local time to UTC.
421 static int64_t localTimeUtcOffset() noexcept {
423 }
424
425 /// Convert to std::chrono::time_point.
426 template <typename Clock = DefaultClock, typename Duration = UaDuration>
427 std::chrono::time_point<Clock, Duration> toTimePoint() const {
428 const std::chrono::time_point<Clock, Duration> unixEpoch{};
429 if (get() < UA_DATETIME_UNIX_EPOCH) {
430 return unixEpoch;
431 }
432 const auto sinceEpoch = UaDuration(get() - UA_DATETIME_UNIX_EPOCH);
433 return unixEpoch + std::chrono::duration_cast<Duration>(sinceEpoch);
434 }
435
436 /// Convert to Unix time (number of seconds since January 1, 1970 UTC).
437 int64_t toUnixTime() const noexcept {
438 if (get() < UA_DATETIME_UNIX_EPOCH) {
439 return 0;
440 }
441 return UA_DateTime_toUnixTime(get());
442 }
443
444 /// Convert to UA_DateTimeStruct.
445 UA_DateTimeStruct toStruct() const noexcept {
446 return UA_DateTime_toStruct(get());
447 }
448
449 /// Get DateTime value as 100 nanosecond intervals since January 1, 1601 (UTC).
450 int64_t get() const noexcept {
451 return *handle();
452 }
453
454 /// Convert to string with given format (same format codes as strftime).
455 /// @see https://en.cppreference.com/w/cpp/chrono/c/strftime
456 std::string format(std::string_view format, bool localtime = false) const;
457};
458
459template <typename Clock, typename Duration>
460struct TypeConverter<std::chrono::time_point<Clock, Duration>> {
461 using Type = std::chrono::time_point<Clock, Duration>;
463
464 static void fromNative(const NativeType& src, Type& dst) {
465 dst = src.toTimePoint<Clock, Duration>();
466 }
467
468 static void toNative(const Type& src, NativeType& dst) {
469 dst = DateTime::fromTimePoint(src);
470 }
471};
472
473/* -------------------------------------------- Guid -------------------------------------------- */
474
475/**
476 * UA_Guid wrapper class.
477 * @ingroup Wrapper
478 */
479class Guid : public TypeWrapper<UA_Guid, UA_TYPES_GUID> {
480public:
482
483 explicit Guid(std::array<uint8_t, 16> data) noexcept
484 : Guid(UA_Guid{
485 // NOLINTBEGIN(hicpp-signed-bitwise)
486 static_cast<uint32_t>(
487 (data[0] << 24U) | (data[1] << 16U) | (data[2] << 8U) | data[3]
488 ),
489 static_cast<uint16_t>((data[4] << 8U) | data[5]),
490 static_cast<uint16_t>((data[6] << 8U) | data[7]),
491 // NOLINTEND(hicpp-signed-bitwise)
492 {data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]},
493 }) {}
494
495 Guid(uint32_t data1, uint16_t data2, uint16_t data3, std::array<uint8_t, 8> data4) noexcept
496 : Guid(UA_Guid{
497 data1,
498 data2,
499 data3,
500 {data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], data4[7]},
501 }) {}
502
503 static Guid random() noexcept {
504 return Guid(UA_Guid_random()); // NOLINT
505 }
506
507 std::string toString() const;
508};
509
510/// @relates Guid
511inline bool operator==(const UA_Guid& lhs, const UA_Guid& rhs) noexcept {
512 return UA_Guid_equal(&lhs, &rhs);
513}
514
515/// @relates Guid
516inline bool operator!=(const UA_Guid& lhs, const UA_Guid& rhs) noexcept {
517 return !(lhs == rhs);
518}
519
520/// @relates Guid
521std::ostream& operator<<(std::ostream& os, const Guid& guid);
522
523/* ----------------------------------------- ByteString ----------------------------------------- */
524
525/**
526 * UA_ByteString wrapper class.
527 * @ingroup Wrapper
528 */
530 : public TypeWrapper<UA_ByteString, UA_TYPES_BYTESTRING>,
531 public detail::StringLikeMixin<ByteString, uint8_t> {
532public:
534
535 explicit ByteString(std::string_view str)
536 : TypeWrapper(detail::allocNativeString(str)) {}
537
538 explicit ByteString(const char* str) // required to avoid ambiguity
539 : ByteString(std::string_view(str)) {}
540
542 init(bytes.begin(), bytes.end());
543 }
544
545 template <typename InputIt>
546 ByteString(InputIt first, InputIt last) {
547 init(first, last);
548 }
549
550 /// Parse ByteString from Base64 encoded string.
551 /// @note Supported since open62541 v1.1
552 static ByteString fromBase64(std::string_view encoded);
553
554 /// Explicit conversion to std::string_view.
555 template <typename Traits>
556 explicit operator std::basic_string_view<char, Traits>() const noexcept {
557 return {reinterpret_cast<const char*>(data()), size()}; // NOLINT
558 }
559
560 /// Convert to Base64 encoded string.
561 /// @note Supported since open62541 v1.1
562 std::string toBase64() const;
563
564 /// @deprecated Use conversion with `static_cast` instead
565 [[deprecated("use conversion with static_cast instead")]]
566 std::string_view get() const noexcept {
567 return {reinterpret_cast<const char*>(data()), size()}; // NOLINT
568 }
569};
570
571/// @relates ByteString
572inline bool operator==(const ByteString& lhs, std::string_view rhs) noexcept {
573 return (static_cast<std::string_view>(lhs) == rhs);
574}
575
576/// @relates ByteString
577inline bool operator!=(const ByteString& lhs, std::string_view rhs) noexcept {
578 return (static_cast<std::string_view>(lhs) != rhs);
579}
580
581/// @relates ByteString
582inline bool operator==(std::string_view lhs, const ByteString& rhs) noexcept {
583 return (lhs == static_cast<std::string_view>(rhs));
584}
585
586/// @relates ByteString
587inline bool operator!=(std::string_view lhs, const ByteString& rhs) noexcept {
588 return (lhs != static_cast<std::string_view>(rhs));
589}
590
591/* ----------------------------------------- XmlElement ----------------------------------------- */
592
593/**
594 * UA_XmlElement wrapper class.
595 * @ingroup Wrapper
596 */
598 : public TypeWrapper<UA_XmlElement, UA_TYPES_XMLELEMENT>,
599 public detail::StringLikeMixin<XmlElement, char> {
600public:
602
603 explicit XmlElement(std::string_view str)
604 : TypeWrapper(detail::allocNativeString(str)) {}
605
606 template <typename InputIt>
607 XmlElement(InputIt first, InputIt last) {
608 init(first, last);
609 }
610
611 /// Assign null-termined character string.
612 XmlElement& operator=(const char* str) {
613 *this = XmlElement(str);
614 return *this;
615 }
616
617 /// Assign std::string_view.
618 template <typename Traits>
619 XmlElement& operator=(std::basic_string_view<char, Traits> str) {
620 *this = XmlElement(str);
621 return *this;
622 }
623
624 /// Implicit conversion to std::string_view.
625 template <typename Traits>
626 operator std::basic_string_view<char, Traits>() const noexcept { // NOLINT(*-conversions)
627 return {data(), size()};
628 }
629
630 /// @deprecated Use conversion with `static_cast` instead
631 [[deprecated("use conversion with static_cast instead")]]
632 std::string_view get() const noexcept {
633 return {data(), size()};
634 }
635};
636
637/// @relates XmlElement
638std::ostream& operator<<(std::ostream& os, const XmlElement& xmlElement);
639
640/* ------------------------------------------- NodeId ------------------------------------------- */
641
642namespace detail {
643template <typename T, typename = void>
644struct IsNodeIdEnum : std::false_type {};
645
646template <typename T>
647struct IsNodeIdEnum<T, std::void_t<decltype(namespaceOf(std::declval<T>()))>> : std::is_enum<T> {};
648} // namespace detail
649
650/**
651 * NodeId types.
652 * @see UA_NodeIdType
653 */
660
661/**
662 * UA_NodeId wrapper class.
663 * @see https://reference.opcfoundation.org/Core/Part3/v105/docs/8.2
664 * @ingroup Wrapper
665 */
666class NodeId : public TypeWrapper<UA_NodeId, UA_TYPES_NODEID> {
667public:
669
670 /// Create NodeId with numeric identifier.
676
677 /// Create NodeId with String identifier.
681 handle()->identifier.string = detail::allocNativeString(identifier); // NOLINT
682 }
683
684 /// Create NodeId with Guid identifier.
690
691 /// Create NodeId with ByteString identifier.
695 // force zero-initialization, only first member of identifier union is zero-initialized
696 handle()->identifier.byteString = {}; // NOLINT
698 }
699
700 /// Create NodeId from enum class with numeric identifiers like `opcua::ObjectId`.
701 /// The namespace is retrieved by calling e.g. `namespaceOf(opcua::ObjectId)`.
702 /// Make sure to provide an overload for custom enum types.
703 template <typename T, typename = std::enable_if_t<detail::IsNodeIdEnum<T>::value>>
704 NodeId(T identifier) noexcept // NOLINT(hicpp-explicit-conversions)
705 : NodeId(namespaceOf(identifier).index, static_cast<uint32_t>(identifier)) {}
706
707 bool isNull() const noexcept {
708 return UA_NodeId_isNull(handle());
709 }
710
711 uint32_t hash() const noexcept {
712 return UA_NodeId_hash(handle());
713 }
714
716 return handle()->namespaceIndex;
717 }
718
719 /// @deprecated Use namespaceIndex() instead
720 [[deprecated("use namespaceIndex() instead")]]
722 return namespaceIndex();
723 }
724
725 NodeIdType identifierType() const noexcept {
726 return static_cast<NodeIdType>(handle()->identifierType);
727 }
728
729 /// @deprecated Use identifierType() instead
730 [[deprecated("use identifierType() instead")]]
731 NodeIdType getIdentifierType() const noexcept {
732 return identifierType();
733 }
734
735 /**
736 * Get identifier pointer or `nullptr` on error.
737 * @tparam T Requested identifier type, should be either:
738 * - `uint32_t` for NodeIdType::Numeric
739 * - `String` for NodeIdType::String
740 * - `Guid` for NodeIdType::Guid
741 * - `ByteString` for NodeIdType::ByteString
742 * @return Pointer to the stored identifier
743 * or a `nullptr` if `T` doesn't match the stored identifier type
744 */
745 template <typename T>
746 T* identifierIf() noexcept {
747 return const_cast<T*>(std::as_const(*this).identifierIf<T>()); // NOLINT
748 }
749
750 /// @copydoc identifierIf
751 template <typename T>
752 const T* identifierIf() const noexcept {
753 static_assert(
754 detail::IsOneOf<T, uint32_t, String, Guid, ByteString>::value,
755 "Invalid type for NodeId identifier"
756 );
757 // NOLINTBEGIN(cppcoreguidelines-pro-type-union-access)
758 if constexpr (std::is_same_v<T, uint32_t>) {
761 : nullptr;
762 }
763 if constexpr (std::is_same_v<T, String>) {
766 : nullptr;
767 }
768 if constexpr (std::is_same_v<T, Guid>) {
771 : nullptr;
772 }
773 if constexpr (std::is_same_v<T, ByteString>) {
776 : nullptr;
777 }
778 // NOLINTEND(cppcoreguidelines-pro-type-union-access)
779 return nullptr;
780 }
781
782 /**
783 * Get identifier reference.
784 * @tparam T Requested identifier type, should be either:
785 * - `uint32_t` for NodeIdType::Numeric
786 * - `String` for NodeIdType::String
787 * - `Guid` for NodeIdType::Guid
788 * - `ByteString` for NodeIdType::ByteString
789 * @return Reference to the stored identifier
790 * @throws TypeError If the requested type `T` doesn't match the stored identifier type
791 */
792 template <typename T>
794 return const_cast<T&>(std::as_const(*this).identifier<T>()); // NOLINT
795 }
796
797 /// @copydoc identifier
798 template <typename T>
799 const T& identifier() const {
800 if (auto* ptr = identifierIf<T>()) {
801 return *ptr;
802 }
803 throw TypeError("NodeId identifier type doesn't match the requested type");
804 }
805
806 /// Get identifier variant.
807 /// @deprecated Use identifier<T>() or identifierIf<T>() instead
808 [[deprecated("use identifier<T>() or identifierIf<T>() instead")]]
809 std::variant<uint32_t, String, Guid, ByteString> getIdentifier() const {
810 return getIdentifierImpl();
811 }
812
813 /// Get identifier by template type.
814 /// @deprecated Use identifier<T>() or identifierIf<T>() instead
815 template <typename T>
816 [[deprecated("use identifier<T>() or identifierIf<T>() instead")]]
817 auto getIdentifierAs() const {
818 return getIdentifierAsImpl<T>();
819 }
820
821 /// Get identifier by NodeIdType enum.
822 /// @deprecated Use identifier<T>() or identifierIf<T>() instead
823 template <NodeIdType E>
824 [[deprecated("use identifier<T>() or identifierIf<T>() instead")]]
825 auto getIdentifierAs() const {
826 return getIdentifierAsImpl<E>();
827 }
828
829 /// Encode NodeId as a string like `ns=1;s=SomeNode`.
830 /// @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.3.1.10
831 std::string toString() const;
832
833private:
834 std::variant<uint32_t, String, Guid, ByteString> getIdentifierImpl() const {
835 switch (handle()->identifierType) {
837 return handle()->identifier.numeric; // NOLINT
839 return String(handle()->identifier.string); // NOLINT
841 return Guid(handle()->identifier.guid); // NOLINT
843 return ByteString(handle()->identifier.byteString); // NOLINT
844 default:
845 return {};
846 }
847 }
848
849 template <typename T>
850 auto getIdentifierAsImpl() const {
851 return std::get<T>(getIdentifierImpl());
852 }
853
854 template <NodeIdType E>
855 auto getIdentifierAsImpl() const {
856 if constexpr (E == NodeIdType::Numeric) {
857 return getIdentifierAsImpl<uint32_t>();
858 }
859 if constexpr (E == NodeIdType::String) {
860 return getIdentifierAsImpl<String>();
861 }
862 if constexpr (E == NodeIdType::Guid) {
863 return getIdentifierAsImpl<Guid>();
864 }
865 if constexpr (E == NodeIdType::ByteString) {
866 return getIdentifierAsImpl<ByteString>();
867 }
868 }
869};
870
871/// @relates NodeId
872inline bool operator==(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
873 return UA_NodeId_equal(&lhs, &rhs);
874}
875
876/// @relates NodeId
877inline bool operator!=(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
878 return !(lhs == rhs);
879}
880
881/// @relates NodeId
882inline bool operator<(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
883 return UA_NodeId_order(&lhs, &rhs) == UA_ORDER_LESS;
884}
885
886/// @relates NodeId
887inline bool operator>(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
888 return UA_NodeId_order(&lhs, &rhs) == UA_ORDER_MORE;
889}
890
891/// @relates NodeId
892inline bool operator<=(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
893 return (lhs < rhs) || (lhs == rhs);
894}
895
896/// @relates NodeId
897inline bool operator>=(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
898 return (lhs > rhs) || (lhs == rhs);
899}
900
901/* --------------------------------------- ExpandedNodeId --------------------------------------- */
902
903/**
904 * UA_ExpandedNodeId wrapper class.
905 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.16
906 * @ingroup Wrapper
907 */
908class ExpandedNodeId : public TypeWrapper<UA_ExpandedNodeId, UA_TYPES_EXPANDEDNODEID> {
909public:
911
912 explicit ExpandedNodeId(NodeId id) noexcept {
913 asWrapper<NodeId>(handle()->nodeId) = std::move(id);
914 }
915
916 ExpandedNodeId(NodeId id, std::string_view namespaceUri, uint32_t serverIndex) {
917 asWrapper<NodeId>(handle()->nodeId) = std::move(id);
918 handle()->namespaceUri = detail::allocNativeString(namespaceUri);
920 }
921
922 bool isLocal() const noexcept {
923 return handle()->serverIndex == 0;
924 }
925
926 uint32_t hash() const noexcept {
928 }
929
930 NodeId& nodeId() noexcept {
932 }
933
934 const NodeId& nodeId() const noexcept {
936 }
937
938 /// @deprecated Use nodeId() instead
939 [[deprecated("use nodeId() instead")]]
940 NodeId& getNodeId() noexcept {
941 return nodeId();
942 }
943
944 /// @deprecated Use nodeId() instead
945 [[deprecated("use nodeId() instead")]]
946 const NodeId& getNodeId() const noexcept {
947 return nodeId();
948 }
949
950 std::string_view namespaceUri() const {
951 return detail::toStringView(handle()->namespaceUri);
952 }
953
954 /// @deprecated Use namespaceUri() instead
955 [[deprecated("use namespaceUri() instead")]]
956 std::string_view getNamespaceUri() const {
957 return namespaceUri();
958 }
959
960 uint32_t serverIndex() const noexcept {
961 return handle()->serverIndex;
962 }
963
964 /// @deprecated Use serverIndex() instead
965 [[deprecated("use serverIndex() instead")]]
966 uint32_t getServerIndex() const noexcept {
967 return serverIndex();
968 }
969
970 /// Encode ExpandedNodeId as a string like `svr=1;nsu=http://test.org/UA/Data/;ns=2;i=10157`.
971 /// @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.3.1.11
972 std::string toString() const;
973};
974
975/// @relates ExpandedNodeId
976inline bool operator==(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
977 return UA_ExpandedNodeId_equal(&lhs, &rhs);
978}
979
980/// @relates ExpandedNodeId
981inline bool operator!=(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
982 return !(lhs == rhs);
983}
984
985/// @relates ExpandedNodeId
986inline bool operator<(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
987 return UA_ExpandedNodeId_order(&lhs, &rhs) == UA_ORDER_LESS;
988}
989
990/// @relates ExpandedNodeId
991inline bool operator>(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
992 return UA_ExpandedNodeId_order(&lhs, &rhs) == UA_ORDER_MORE;
993}
994
995/// @relates ExpandedNodeId
996inline bool operator<=(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
997 return (lhs < rhs) || (lhs == rhs);
998}
999
1000/// @relates ExpandedNodeId
1001inline bool operator>=(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
1002 return (lhs > rhs) || (lhs == rhs);
1003}
1004
1005/* ---------------------------------------- QualifiedName --------------------------------------- */
1006
1007/**
1008 * UA_QualifiedName wrapper class.
1009 * @ingroup Wrapper
1010 */
1011class QualifiedName : public TypeWrapper<UA_QualifiedName, UA_TYPES_QUALIFIEDNAME> {
1012public:
1014
1017 handle()->name = detail::allocNativeString(name);
1018 }
1019
1021 return handle()->namespaceIndex;
1022 }
1023
1024 /// @deprecated Use namespaceIndex() instead
1025 [[deprecated("use namespaceIndex() instead")]]
1027 return namespaceIndex();
1028 }
1029
1030 std::string_view name() const noexcept {
1031 return detail::toStringView(handle()->name);
1032 }
1033
1034 /// @deprecated Use name() instead
1035 [[deprecated("use name() instead")]]
1036 std::string_view getName() const noexcept {
1037 return name();
1038 }
1039};
1040
1041/// @relates QualifiedName
1042inline bool operator==(const UA_QualifiedName& lhs, const UA_QualifiedName& rhs) noexcept {
1043 return (lhs.namespaceIndex == rhs.namespaceIndex) && (lhs.name == rhs.name);
1044}
1045
1046/// @relates QualifiedName
1047inline bool operator!=(const UA_QualifiedName& lhs, const UA_QualifiedName& rhs) noexcept {
1048 return !(lhs == rhs);
1049}
1050
1051/* ---------------------------------------- LocalizedText --------------------------------------- */
1052
1053/**
1054 * UA_LocalizedText wrapper class.
1055 * The format of locale is `<language>[-<country/region>]`:
1056 * - `<language>` is the two letter ISO 639 code for a language
1057 * - `<country/region>` is the two letter ISO 3166 code for the country/region
1058 * @see https://reference.opcfoundation.org/Core/Part3/v105/docs/8.5/
1059 * @see https://reference.opcfoundation.org/Core/Part3/v105/docs/8.4/
1060 * @ingroup Wrapper
1061 */
1062class LocalizedText : public TypeWrapper<UA_LocalizedText, UA_TYPES_LOCALIZEDTEXT> {
1063public:
1065
1066 LocalizedText(std::string_view locale, std::string_view text) {
1067 handle()->locale = detail::allocNativeString(locale);
1068 handle()->text = detail::allocNativeString(text);
1069 }
1070
1071 std::string_view locale() const noexcept {
1072 return detail::toStringView(handle()->locale);
1073 }
1074
1075 /// @deprecated Use locale() instead
1076 [[deprecated("use locale() instead")]]
1077 std::string_view getLocale() const noexcept {
1078 return locale();
1079 }
1080
1081 std::string_view text() const noexcept {
1082 return detail::toStringView(handle()->text);
1083 }
1084
1085 /// @deprecated Use text() instead
1086 [[deprecated("use text() instead")]]
1087 std::string_view getText() const noexcept {
1088 return text();
1089 }
1090};
1091
1092/// @relates LocalizedText
1093inline bool operator==(const UA_LocalizedText& lhs, const UA_LocalizedText& rhs) noexcept {
1094 return (lhs.locale == rhs.locale) && (lhs.text == rhs.text);
1095}
1096
1097/// @relates LocalizedText
1098inline bool operator!=(const UA_LocalizedText& lhs, const UA_LocalizedText& rhs) noexcept {
1099 return !(lhs == rhs);
1100}
1101
1102/* ------------------------------------------- Variant ------------------------------------------ */
1103
1104/**
1105 * Policies for variant factory methods Variant::fromScalar, Variant::fromArray.
1106 */
1107enum class VariantPolicy {
1108 // clang-format off
1109 Copy, ///< Store copy of scalar/array inside the variant.
1110 Reference, ///< Store reference to scalar/array inside the variant.
1111 ///< Both scalars and arrays must be mutable native/wrapper types.
1112 ///< Arrays must store the elements contiguously in memory.
1113 // clang-format on
1114};
1115
1117public:
1118 using TypeError::TypeError;
1119};
1120
1121/**
1122 * UA_Variant wrapper class.
1123 *
1124 * Variants may contain scalar values or arrays of any type together with a type definition.
1125 * The standard mandates that variants contain built-in data types only.
1126 * open62541 transparently handles this wrapping in the encoding layer. If the type is unknown to
1127 * the receiver, the variant stores the original ExtensionObject in binary or XML encoding.
1128 *
1129 * open62541pp enhances variant handling with the following features:
1130 *
1131 * 1. **Type category detection**: Identifies whether `T` is scalar or array:
1132 * - **Scalar**, if `T` is:
1133 * - A registered type (TypeRegistry spezialization). This applies to native types and
1134 * @ref Wrapper "wrapper types".
1135 * - A convertible type (TypeConverter spezialization).
1136 * - **Array**, if `T` is a container type (e.g. `std::vector` or `std::list`) and does not
1137 * satisfy the criterias of a scalar type.
1138 *
1139 * Applied in @ref Variant::Variant "constructors", @ref assign, and @ref to functions:
1140 *
1141 * @code
1142 * opcua::Variant var(5); // set scalar (via constructor)
1143 * auto value = var.to<int>(); // convert scalar
1144 *
1145 * std::array<int> array{1, 2, 3};
1146 * var.assign(array); // set array (via assign)
1147 * auto vec = var.to<std::vector<int>>(); // convert array
1148 * @endcode
1149 *
1150 * 2. **Type definition retrieval**: Automatically retrieves UA_DataType via TypeRegistry.
1151 * For every registered type `T`, the type definition parameter can be omitted:
1152 *
1153 * @code
1154 * opcua::Variant var(5, UA_TYPES[UA_TYPES_INT]); // explicit type definition
1155 * opcua::Variant var(5); // auto-detected type definition
1156 * @endcode
1157 *
1158 * 3. **Type conversion**: Convert non-native types using TypeConverter.
1159 * Native `UA_*` types can be assigned and retrieved to/from variants without any conversion,
1160 * because their binary layout is described by the type definition (UA_DataType). The same is
1161 * true for wrapper types, that share the exact memory layout as their wrapped native type.
1162 * Non-native types, like `std::string` from the STL, may not be describeable by UA_DataType
1163 * because their memory layout is an implementation detail.
1164 * Instead, the conversion between non-native and native types can be defined with template
1165 * specializations of TypeConverter. If a type is convertible (TypeConverter specialization),
1166 * the Variant automatically manages the conversion, requiring a copy:
1167 *
1168 * @code
1169 * opcua::Variant var(std::string("test")); // convert to native type (copy)
1170 * auto& native = var.scalar<opcua::String>(); // reference to native type (no copy)
1171 * auto str = var.to<std::string>(); // conversion (copy required)
1172 * @endcode
1173 *
1174 * @ingroup Wrapper
1175 */
1176class Variant : public TypeWrapper<UA_Variant, UA_TYPES_VARIANT> {
1177private:
1178 template <typename T>
1179 static constexpr bool isVariant =
1180 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, Variant> ||
1181 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, UA_Variant>;
1182
1183public:
1185
1186 /// Create Variant from a pointer to a scalar/array (no copy).
1187 /// @see assign(T*)
1188 template <typename T, typename = std::enable_if_t<!std::is_const_v<T>>>
1189 explicit Variant(T* ptr) noexcept {
1190 assign(ptr);
1191 }
1192
1193 /// Create Variant from a pointer to a scalar/array with a custom data type (no copy).
1194 /// @see assign(T*, const UA_DataType&)
1195 template <typename T, typename = std::enable_if_t<!std::is_const_v<T>>>
1196 Variant(T* ptr, const UA_DataType& type) noexcept {
1197 assign(ptr, type);
1198 }
1199
1200 /// Create Variant from a scalar/array (copy).
1201 /// @see assign(const T&)
1202 template <typename T, typename = std::enable_if_t<!isVariant<T>>>
1203 explicit Variant(const T& value) {
1204 assign(value);
1205 }
1206
1207 /// Create Variant from a scalar/array with a custom data type (copy).
1208 /// @see assign(const T&, const UA_DataType&)
1209 template <typename T>
1210 Variant(const T& value, const UA_DataType& type) {
1211 assign(value, type);
1212 }
1213
1214 /// Create Variant from a range of elements (copy).
1215 /// @see assign(InputIt, InputIt)
1216 template <typename InputIt>
1217 Variant(InputIt first, InputIt last) {
1218 assign(first, last);
1219 }
1220
1221 /// Create Variant from a range of elements with a custom data type (copy).
1222 /// @see assign(InputIt, InputIt, const UA_DataType&)
1223 template <typename InputIt>
1224 Variant(InputIt first, InputIt last, const UA_DataType& type) {
1225 assign(first, last, type);
1226 }
1227
1228 /// @deprecated Use new universal Variant constructor instead
1229 template <VariantPolicy Policy = VariantPolicy::Copy, typename T, typename... Args>
1230 [[deprecated("use new universal Variant constructor instead")]] [[nodiscard]]
1231 static Variant fromScalar(T&& value, Args&&... args) {
1232 if constexpr (Policy == VariantPolicy::Copy) {
1233 return Variant{std::forward<T>(value), std::forward<Args>(args)...};
1234 } else {
1235 return Variant{&value, std::forward<Args>(args)...};
1236 }
1237 }
1238
1239 /// @deprecated Use new universal Variant constructor instead
1240 template <VariantPolicy Policy = VariantPolicy::Copy, typename T, typename... Args>
1241 [[deprecated("use new universal Variant constructor instead")]] [[nodiscard]]
1242 static Variant fromArray(T&& array, Args&&... args) {
1243 if constexpr (Policy == VariantPolicy::Copy) {
1244 return Variant{std::forward<T>(array), std::forward<Args>(args)...};
1245 } else {
1246 return Variant{&array, std::forward<Args>(args)...};
1247 }
1248 }
1249
1250 /// @deprecated Use new universal Variant constructor instead
1251 template <VariantPolicy Policy = VariantPolicy::Copy, typename InputIt, typename... Args>
1252 [[deprecated("use new universal Variant constructor instead")]] [[nodiscard]]
1253 static Variant fromArray(InputIt first, InputIt last, Args&&... args) {
1254 return Variant{first, last, std::forward<Args>(args)...};
1255 }
1256
1257 /**
1258 * @name Modifiers
1259 * Modify internal scalar/array value.
1260 * @{
1261 */
1262
1263 void assign(std::nullptr_t ptr) noexcept = delete;
1264 void assign(std::nullptr_t ptr, const UA_DataType& type) noexcept = delete;
1265
1266 /**
1267 * Assign pointer to scalar/array to variant (no copy).
1268 * The object will *not* be deleted when the Variant is destructed.
1269 * @param ptr Non-const pointer to a value to assign to the variant. This can be:
1270 * - A pointer to a scalar native or wrapper value.
1271 * - A pointer to a contiguous container such as `std::array` or `std::vector`
1272 * holding native or wrapper elements.
1273 * The underlying array must be accessible with `std::data` and `std::size`.
1274 * - A `nullptr`, in which case the variant will be cleared.
1275 */
1276 template <typename T, typename = std::enable_if_t<!std::is_const_v<T>>>
1277 void assign(T* ptr) noexcept {
1278 if constexpr (isArrayType<T>()) {
1279 using ValueType = typename T::value_type;
1280 assertIsRegistered<ValueType>();
1282 } else {
1283 assertIsRegistered<T>();
1285 }
1286 }
1287
1288 /**
1289 * Assign pointer to scalar/array to variant with custom data type (no copy).
1290 * @copydetails assign(T*)
1291 * @param type Custom data type.
1292 */
1293 template <typename T, typename = std::enable_if_t<!std::is_const_v<T>>>
1294 void assign(T* ptr, const UA_DataType& type) noexcept {
1295 if (ptr == nullptr) {
1296 clear();
1297 } else if constexpr (isArrayType<T>()) {
1298 setArrayImpl(std::data(*ptr), std::size(*ptr), type, UA_VARIANT_DATA_NODELETE);
1299 } else {
1300 setScalarImpl(ptr, type, UA_VARIANT_DATA_NODELETE);
1301 }
1302 }
1303
1304 /**
1305 * Assign scalar/array to variant (copy and convert if required).
1306 * @param value Value to copy to the variant. It can be:
1307 * - A scalar native, wrapper or convertible value.
1308 * - A container with native, wrapper or convertible elements.
1309 * The container must implement `begin()` and `end()`.
1310 */
1311 template <typename T>
1312 void assign(const T& value) {
1313 if constexpr (isArrayType<T>()) {
1314 assign(value.begin(), value.end());
1315 } else {
1316 assertIsRegisteredOrConvertible<T>();
1317 if constexpr (detail::isRegisteredType<T>) {
1318 setScalarCopyImpl(value, opcua::getDataType<T>());
1319 } else {
1320 setScalarCopyConvertImpl(value);
1321 }
1322 }
1323 }
1324
1325 /**
1326 * Assign scalar/array to variant with custom data type (copy).
1327 * @param value Value to copy to the variant. It can be:
1328 * - A scalar native or wrapper value.
1329 * - A container with native or wrapper elements.
1330 * The container must implement `begin()` and `end()`.
1331 * @param type Custom data type.
1332 */
1333 template <typename T>
1334 void assign(const T& value, const UA_DataType& type) {
1335 if constexpr (isArrayType<T>()) {
1336 setArrayCopyImpl(value.begin(), value.end(), type);
1337 } else {
1338 setScalarCopyImpl(value, type);
1339 }
1340 }
1341
1342 /**
1343 * Assign range to variant (copy and convert if required).
1344 * @param first Iterator to the beginning of the range.
1345 * @param last Iterator to the end of the range.
1346 * @tparam InputIt Iterator of a container with native, wrapper or convertible elements.
1347 */
1348 template <typename InputIt>
1349 void assign(InputIt first, InputIt last) {
1350 using ValueType = typename std::iterator_traits<InputIt>::value_type;
1351 assertIsRegisteredOrConvertible<ValueType>();
1352 if constexpr (detail::isRegisteredType<ValueType>) {
1353 setArrayCopyImpl(first, last, opcua::getDataType<ValueType>());
1354 } else {
1355 setArrayCopyConvertImpl(first, last);
1356 }
1357 }
1358
1359 /**
1360 * Assign range to variant with custom data type (copy).
1361 * @param first Iterator to the beginning of the range.
1362 * @param last Iterator to the end of the range.
1363 * @param type Custom data type.
1364 * @tparam InputIt Iterator of a container with native or wrapper elements.
1365 */
1366 template <typename InputIt>
1367 void assign(InputIt first, InputIt last, const UA_DataType& type) {
1368 setArrayCopyImpl(first, last, type);
1369 }
1370
1371 /// Assign pointer to scalar/array to variant (no copy).
1372 /// @see assign(T*)
1373 template <typename T, typename = std::enable_if_t<!isVariant<T>>>
1374 Variant& operator=(T* value) noexcept {
1375 assign(value);
1376 return *this;
1377 }
1378
1379 /// Assign scalar/array to variant (copy and convert if required).
1380 /// @see assign(const T&)
1381 template <typename T, typename = std::enable_if_t<!isVariant<T>>>
1382 Variant& operator=(const T& value) {
1383 assign(value);
1384 return *this;
1385 }
1386
1387 /// @deprecated Use assign overload with pointer instead
1388 template <typename T, typename... Args>
1389 [[deprecated("use assign overload with pointer instead")]]
1390 void setScalar(T& value, Args&&... args) noexcept {
1391 assign(&value, std::forward<Args>(args)...);
1392 }
1393
1394 /// @deprecated Use assign overload instead
1395 template <typename T, typename... Args>
1396 [[deprecated("use assign overload instead")]]
1397 void setScalarCopy(const T& value, Args&&... args) {
1398 assign(value, std::forward<Args>(args)...);
1399 }
1400
1401 /// @deprecated Use assign overload with pointer instead
1402 template <typename T, typename... Args>
1403 [[deprecated("use assign overload with pointer instead")]]
1404 void setArray(T& array, Args&&... args) noexcept {
1405 assign(&array, std::forward<Args>(args)...);
1406 }
1407
1408 /// @deprecated Use assign overload instead
1409 template <typename T, typename... Args>
1410 [[deprecated("use assign overload instead")]]
1411 void setArrayCopy(const T& array, Args&&... args) {
1412 assign(array, std::forward<Args>(args)...);
1413 }
1414
1415 /// @deprecated Use assign overload instead
1416 template <typename InputIt, typename... Args>
1417 [[deprecated("use assign overload instead")]]
1418 void setArrayCopy(InputIt first, InputIt last, Args&&... args) {
1419 assign(first, last, std::forward<Args>(args)...);
1420 }
1421
1422 /**
1423 * @name Observers
1424 * Check the type category, type definition and array structure of the internal value.
1425 */
1426
1427 /// Check if the variant is empty.
1428 bool empty() const noexcept {
1429 return handle()->type == nullptr;
1430 }
1431
1432 /// @deprecated Use empty() instead
1433 [[deprecated("use empty() instead")]]
1434 bool isEmpty() const noexcept {
1435 return empty();
1436 }
1437
1438 /// Check if the variant is a scalar.
1439 bool isScalar() const noexcept {
1440 return (
1441 !empty() && handle()->arrayLength == 0 &&
1442 handle()->data > UA_EMPTY_ARRAY_SENTINEL // NOLINT
1443 );
1444 }
1445
1446 /// Check if the variant is an array.
1447 bool isArray() const noexcept {
1448 return !empty() && !isScalar();
1449 }
1450
1451 /// Check if the variant type is equal to the provided data type.
1452 bool isType(const UA_DataType* type) const noexcept {
1453 return (
1454 handle()->type != nullptr && type != nullptr && handle()->type->typeId == type->typeId
1455 );
1456 }
1457
1458 /// Check if the variant type is equal to the provided data type.
1459 bool isType(const UA_DataType& type) const noexcept {
1460 return isType(&type);
1461 }
1462
1463 /// Check if the variant type is equal to the provided data type node id.
1464 bool isType(const NodeId& id) const noexcept {
1465 return (handle()->type != nullptr) && (handle()->type->typeId == id);
1466 }
1467
1468 /// Check if the variant type is equal to the provided template type.
1469 template <typename T>
1470 bool isType() const noexcept {
1471 return isType(opcua::getDataType<T>());
1472 }
1473
1474 /// Get data type.
1475 const UA_DataType* type() const noexcept {
1476 return handle()->type;
1477 }
1478
1479 /// @deprecated Use type() instead
1480 [[deprecated("use type() instead")]]
1481 const UA_DataType* getDataType() const noexcept {
1482 return type();
1483 }
1484
1485 /// Get array length or 0 if variant is not an array.
1486 size_t arrayLength() const noexcept {
1487 return handle()->arrayLength;
1488 }
1489
1490 /// @deprecated Use arrayLength() instead
1491 [[deprecated("use arrayLength() instead")]]
1492 size_t getArrayLength() const noexcept {
1493 return arrayLength();
1494 }
1495
1496 /// Get array dimensions.
1500
1501 /// @deprecated Use arrayDimensions() instead
1502 [[deprecated("use arrayDimensions() instead")]]
1504 return arrayDimensions();
1505 }
1506
1507 /**
1508 * @name Accessors
1509 * Access and convert internal scalar/array value.
1510 * @{
1511 */
1512
1513 /// Get pointer to the underlying data.
1514 /// Check the properties and data type before casting it to the actual type.
1515 /// Use the methods @ref isScalar, @ref isArray, @ref isType / @ref type.
1516 void* data() noexcept {
1517 return handle()->data;
1518 }
1519
1520 /// @copydoc data
1521 const void* data() const noexcept {
1522 return handle()->data;
1523 }
1524
1525 /// Get reference to scalar value with given template type (only native or wrapper types).
1526 /// @exception BadVariantAccess If the variant is not a scalar or not of type `T`.
1527 template <typename T>
1528 T& scalar() & {
1529 assertIsRegistered<T>();
1530 checkIsScalar();
1531 checkIsType<T>();
1532 return *static_cast<T*>(handle()->data);
1533 }
1534
1535 /// @copydoc scalar()&
1536 template <typename T>
1537 const T& scalar() const& {
1538 assertIsRegistered<T>();
1539 checkIsScalar();
1540 checkIsType<T>();
1541 return *static_cast<const T*>(handle()->data);
1542 }
1543
1544 /// @copydoc scalar()&
1545 template <typename T>
1546 T&& scalar() && {
1547 return std::move(scalar<T>());
1548 }
1549
1550 /// @copydoc scalar()&
1551 template <typename T>
1552 const T&& scalar() const&& {
1553 return std::move(scalar<T>());
1554 }
1555
1556 /// @deprecated Use scalar() instead
1557 template <typename T>
1558 [[deprecated("use scalar() instead")]]
1560 return scalar<T>();
1561 }
1562
1563 /// @deprecated Use scalar() instead
1564 template <typename T>
1565 [[deprecated("use scalar() instead")]]
1566 const T& getScalar() const {
1567 return scalar<T>();
1568 }
1569
1570 /// @deprecated Use to<T>() instead
1571 template <typename T>
1572 [[deprecated("use to<T>() instead")]]
1573 T getScalarCopy() const {
1574 return to<T>();
1575 }
1576
1577 /// Get reference to array with given template type (only native or wrapper types).
1578 /// @exception BadVariantAccess If the variant is not an array or not of type `T`.
1579 template <typename T>
1581 assertIsRegistered<T>();
1582 checkIsArray();
1583 checkIsType<T>();
1584 return Span<T>(static_cast<T*>(handle()->data), handle()->arrayLength);
1585 }
1586
1587 /// Get reference to array with given template type (only native or wrapper types).
1588 /// @exception BadVariantAccess If the variant is not an array or not of type `T`.
1589 template <typename T>
1591 assertIsRegistered<T>();
1592 checkIsArray();
1593 checkIsType<T>();
1594 return Span<const T>(static_cast<const T*>(handle()->data), handle()->arrayLength);
1595 }
1596
1597 /// @deprecated Use array() instead
1598 template <typename T>
1599 [[deprecated("use array() instead")]]
1601 return array<T>();
1602 }
1603
1604 /// @deprecated Use array() instead
1605 template <typename T>
1606 [[deprecated("use array() instead")]]
1608 return array<T>();
1609 }
1610
1611 /// @deprecated Use to<std::vector<T>>() instead
1612 template <typename T>
1613 [[deprecated("use to<std::vector<T>>() instead")]]
1614 std::vector<T> getArrayCopy() const {
1615 return to<std::vector<T>>();
1616 }
1617
1618 /**
1619 * Converts the variant to the specified type `T` with automatic conversion if required.
1620 *
1621 * Determines the type category (scalar or array) based on the characteristics of `T` using
1622 * @ref Variant "type category detection".
1623 * If `T` is a container, it must be constructible from an iterator pair.
1624 *
1625 * @code
1626 * // Scalar
1627 * opcua::Variant var(11);
1628 * const auto value = var.to<int>();
1629 * @endcode
1630 *
1631 * @code
1632 * // Array
1633 * std::array<std::string, 3> array{"One", "Two", "Three"};
1634 * opcua::Variant var(array);
1635 * const auto vec = var.to<std::vector<std::string>>();
1636 * const auto lst = var.to<std::list<opcua::String>>();
1637 * @endcode
1638 *
1639 * @exception BadVariantAccess If the variant is not convertible to `T`.
1640 */
1641 template <typename T>
1642 [[nodiscard]] T to() const {
1643 if constexpr (isArrayType<T>()) {
1644 return toArrayImpl<T>();
1645 } else {
1646 return toScalarImpl<T>();
1647 }
1648 }
1649
1650 /**
1651 * @}
1652 */
1653
1654private:
1655 template <typename T>
1656 static constexpr bool isScalarType() noexcept {
1657 return detail::isRegisteredType<T> || detail::isConvertibleType<T>;
1658 }
1659
1660 template <typename T>
1661 static constexpr bool isArrayType() noexcept {
1662 return detail::isContainer<T> && !isScalarType<T>();
1663 }
1664
1665 template <typename T>
1666 static constexpr void assertIsRegistered() {
1667 static_assert(
1668 detail::isRegisteredType<T>,
1669 "Template type must be a native/wrapper type to assign or get scalar/array without copy"
1670 );
1671 }
1672
1673 template <typename T>
1674 static constexpr void assertIsRegisteredOrConvertible() {
1675 static_assert(
1676 detail::isRegisteredType<T> || detail::isConvertibleType<T>,
1677 "Template type must be either a native/wrapper type or a convertible type. "
1678 "If the type is a native type: Provide the type definition (UA_DataType) manually or "
1679 "register the type with a TypeRegistry template specialization. "
1680 "If the type should be converted: Add a template specialization for TypeConverter."
1681 );
1682 }
1683
1684 template <typename T>
1685 static constexpr void assertNoVariant() {
1686 static_assert(!isVariant<T>, "Variants cannot directly contain another variant");
1687 }
1688
1689 void checkIsScalar() const {
1690 if (!isScalar()) {
1691 throw BadVariantAccess("Variant is not a scalar");
1692 }
1693 }
1694
1695 void checkIsArray() const {
1696 if (!isArray()) {
1697 throw BadVariantAccess("Variant is not an array");
1698 }
1699 }
1700
1701 template <typename T>
1702 void checkIsType() const {
1703 const auto* dt = type();
1704 if (dt == nullptr || dt->typeId != opcua::getDataType<T>().typeId) {
1705 throw BadVariantAccess("Variant does not contain a value convertible to template type");
1706 }
1707 }
1708
1709 template <typename T>
1710 T toScalarImpl() const;
1711 template <typename T>
1712 T toArrayImpl() const;
1713
1714 template <typename T>
1715 inline void setScalarImpl(
1716 T* data, const UA_DataType& type, UA_VariantStorageType storageType
1717 ) noexcept;
1718 template <typename T>
1719 inline void setArrayImpl(
1720 T* data, size_t arrayLength, const UA_DataType& type, UA_VariantStorageType storageType
1721 ) noexcept;
1722 template <typename T>
1723 inline void setScalarCopyImpl(const T& value, const UA_DataType& type);
1724 template <typename T>
1725 inline void setScalarCopyConvertImpl(const T& value);
1726 template <typename InputIt>
1727 inline void setArrayCopyImpl(InputIt first, InputIt last, const UA_DataType& type);
1728 template <typename InputIt>
1729 inline void setArrayCopyConvertImpl(InputIt first, InputIt last);
1730};
1731
1732template <typename T>
1733T Variant::toScalarImpl() const {
1734 assertIsRegisteredOrConvertible<T>();
1735 if constexpr (detail::isRegisteredType<T>) {
1736 return scalar<T>();
1737 } else {
1738 using Native = typename TypeConverter<T>::NativeType;
1739 return detail::fromNative<T>(scalar<Native>());
1740 }
1741}
1742
1743template <typename T>
1744T Variant::toArrayImpl() const {
1745 using ValueType = typename T::value_type;
1746 assertIsRegisteredOrConvertible<ValueType>();
1747 if constexpr (detail::isRegisteredType<ValueType>) {
1748 auto native = array<ValueType>();
1749 return T(native.begin(), native.end());
1750 } else {
1751 using Native = typename TypeConverter<ValueType>::NativeType;
1752 auto native = array<Native>();
1753 return T(
1754 detail::TransformIterator(native.begin(), detail::fromNative<ValueType>),
1755 detail::TransformIterator(native.end(), detail::fromNative<ValueType>)
1756 );
1757 }
1758}
1759
1760template <typename T>
1761void Variant::setScalarImpl(
1762 T* data, const UA_DataType& type, UA_VariantStorageType storageType
1763) noexcept {
1764 assertNoVariant<T>();
1765 assert(sizeof(T) == type.memSize);
1766 clear();
1767 handle()->type = &type;
1768 handle()->storageType = storageType;
1769 handle()->data = data;
1770}
1771
1772template <typename T>
1773void Variant::setArrayImpl(
1774 T* data, size_t arrayLength, const UA_DataType& type, UA_VariantStorageType storageType
1775) noexcept {
1776 assertNoVariant<T>();
1777 assert(sizeof(T) == type.memSize);
1778 clear();
1779 handle()->type = &type;
1780 handle()->storageType = storageType;
1781 handle()->data = data;
1782 handle()->arrayLength = arrayLength;
1783}
1784
1785template <typename T>
1786void Variant::setScalarCopyImpl(const T& value, const UA_DataType& type) {
1787 auto native = detail::allocateUniquePtr<T>(type);
1788 *native = detail::copy(value, type);
1789 setScalarImpl(native.release(), type, UA_VARIANT_DATA); // move ownership
1790}
1791
1792template <typename T>
1793void Variant::setScalarCopyConvertImpl(const T& value) {
1794 using Native = typename TypeConverter<T>::NativeType;
1795 const auto& type = opcua::getDataType<Native>();
1796 auto native = detail::allocateUniquePtr<Native>(type);
1797 *native = detail::toNative(value);
1798 setScalarImpl(native.release(), type, UA_VARIANT_DATA); // move ownership
1799}
1800
1801template <typename InputIt>
1802void Variant::setArrayCopyImpl(InputIt first, InputIt last, const UA_DataType& type) {
1803 using ValueType = typename std::iterator_traits<InputIt>::value_type;
1804 const size_t size = std::distance(first, last);
1805 auto native = detail::allocateArrayUniquePtr<ValueType>(size, type);
1806 std::transform(first, last, native.get(), [&](const ValueType& value) {
1807 return detail::copy(value, type);
1808 });
1809 setArrayImpl(native.release(), size, type, UA_VARIANT_DATA); // move ownership
1810}
1811
1812template <typename InputIt>
1813void Variant::setArrayCopyConvertImpl(InputIt first, InputIt last) {
1814 using ValueType = typename std::iterator_traits<InputIt>::value_type;
1815 using Native = typename TypeConverter<ValueType>::NativeType;
1816 const auto& type = opcua::getDataType<Native>();
1817 const size_t size = std::distance(first, last);
1818 auto native = detail::allocateArrayUniquePtr<Native>(size, type);
1819 std::transform(first, last, native.get(), [&](const ValueType& value) {
1820 return detail::toNative(value);
1821 });
1822 setArrayImpl(native.release(), size, type, UA_VARIANT_DATA); // move ownership
1823}
1824
1825/* ------------------------------------------ DataValue ----------------------------------------- */
1826
1827/**
1828 * UA_DataValue wrapper class.
1829 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.11
1830 * @ingroup Wrapper
1831 */
1832class DataValue : public TypeWrapper<UA_DataValue, UA_TYPES_DATAVALUE> {
1833public:
1835
1836 explicit DataValue(Variant value) noexcept {
1837 setValue(std::move(value));
1838 }
1839
1841 Variant value,
1842 std::optional<DateTime> sourceTimestamp, // NOLINT
1843 std::optional<DateTime> serverTimestamp, // NOLINT
1844 std::optional<uint16_t> sourcePicoseconds,
1845 std::optional<uint16_t> serverPicoseconds,
1846 std::optional<StatusCode> status
1847 ) noexcept
1849 UA_Variant{},
1850 sourceTimestamp.value_or(UA_DateTime{}),
1851 serverTimestamp.value_or(UA_DateTime{}),
1852 sourcePicoseconds.value_or(uint16_t{}),
1853 serverPicoseconds.value_or(uint16_t{}),
1854 status.value_or(UA_StatusCode{}),
1855 false,
1856 sourceTimestamp.has_value(),
1857 serverTimestamp.has_value(),
1858 sourcePicoseconds.has_value(),
1859 serverPicoseconds.has_value(),
1860 status.has_value(),
1861 }) {
1862 setValue(std::move(value));
1863 }
1864
1865 /// Create DataValue from scalar value.
1866 /// @deprecated Use constructor with new universal Variant constructor instead:
1867 /// `opcua::DataValue dv(opcua::Variant(value))`
1868 template <VariantPolicy Policy = VariantPolicy::Copy, typename... Args>
1869 [[deprecated("use constructor with new universal Variant constructor instead")]] [[nodiscard]]
1870 static DataValue fromScalar(Args&&... args) {
1871 return DataValue(Variant::fromScalar<Policy>(std::forward<Args>(args)...));
1872 }
1873
1874 /// Create DataValue from array.
1875 /// @see Variant::fromArray
1876 /// @deprecated Use constructor with new universal Variant constructor instead:
1877 /// `opcua::DataValue dv(opcua::Variant(array))`
1878 template <VariantPolicy Policy = VariantPolicy::Copy, typename... Args>
1879 [[deprecated("use constructor with new universal Variant constructor instead")]] [[nodiscard]]
1880 static DataValue fromArray(Args&&... args) {
1881 return DataValue(Variant::fromArray<Policy>(std::forward<Args>(args)...));
1882 }
1883
1884 /// Set value (copy).
1885 void setValue(const Variant& value) {
1887 handle()->hasValue = true;
1888 }
1889
1890 /// Set value (move).
1891 void setValue(Variant&& value) noexcept {
1892 asWrapper<Variant>(handle()->value) = std::move(value);
1893 handle()->hasValue = true;
1894 }
1895
1896 /// Set source timestamp for the value.
1899 handle()->hasSourceTimestamp = true;
1900 }
1901
1902 /// Set server timestamp for the value.
1905 handle()->hasServerTimestamp = true;
1906 }
1907
1908 /// Set picoseconds interval added to the source timestamp.
1913
1914 /// Set picoseconds interval added to the server timestamp.
1919
1920 /// Set status.
1921 void setStatus(StatusCode status) noexcept {
1922 handle()->status = status;
1923 handle()->hasStatus = true;
1924 }
1925
1926 bool hasValue() const noexcept {
1927 return handle()->hasValue;
1928 }
1929
1930 bool hasSourceTimestamp() const noexcept {
1931 return handle()->hasSourceTimestamp;
1932 }
1933
1934 bool hasServerTimestamp() const noexcept {
1935 return handle()->hasServerTimestamp;
1936 }
1937
1938 bool hasSourcePicoseconds() const noexcept {
1939 return handle()->hasSourcePicoseconds;
1940 }
1941
1942 bool hasServerPicoseconds() const noexcept {
1943 return handle()->hasServerPicoseconds;
1944 }
1945
1946 bool hasStatus() const noexcept {
1947 return handle()->hasStatus;
1948 }
1949
1950 /// Get value.
1951 Variant& value() & noexcept {
1952 return asWrapper<Variant>(handle()->value);
1953 }
1954
1955 /// Get value.
1956 const Variant& value() const& noexcept {
1957 return asWrapper<Variant>(handle()->value);
1958 }
1959
1960 /// Get value (rvalue).
1961 Variant&& value() && noexcept {
1962 return std::move(value());
1963 }
1964
1965 /// Get value (rvalue).
1966 const Variant&& value() const&& noexcept {
1967 return std::move(value()); // NOLINT(*move-const-arg)
1968 }
1969
1970 /// @deprecated Use value() instead
1971 [[deprecated("use value() instead")]]
1972 Variant& getValue() & noexcept {
1973 return value();
1974 }
1975
1976 /// @deprecated Use value() instead
1977 [[deprecated("use value() instead")]]
1978 const Variant& getValue() const& noexcept {
1979 return value();
1980 }
1981
1982 /// @deprecated Use value() instead
1983 [[deprecated("use value() instead")]]
1984 Variant&& getValue() && noexcept {
1985 return std::move(value());
1986 }
1987
1988 /// @deprecated Use value() instead
1989 [[deprecated("use value() instead")]]
1990 const Variant&& getValue() const&& noexcept {
1991 return std::move(value()); // NOLINT(*move-const-arg)
1992 }
1993
1994 /// Get source timestamp for the value.
1995 DateTime sourceTimestamp() const noexcept {
1996 return DateTime(handle()->sourceTimestamp); // NOLINT
1997 }
1998
1999 /// @deprecated Use sourceTimestamp() instead
2000 [[deprecated("use sourceTimestamp() instead")]]
2001 DateTime getSourceTimestamp() const noexcept {
2002 return sourceTimestamp();
2003 }
2004
2005 /// Get server timestamp for the value.
2006 DateTime serverTimestamp() const noexcept {
2007 return DateTime(handle()->serverTimestamp); // NOLINT
2008 }
2009
2010 /// @deprecated Use serverTimestamp() instead
2011 [[deprecated("use serverTimestamp() instead")]]
2012 DateTime getServerTimestamp() const noexcept {
2013 return serverTimestamp();
2014 }
2015
2016 /// Get picoseconds interval added to the source timestamp.
2017 uint16_t sourcePicoseconds() const noexcept {
2018 return handle()->sourcePicoseconds;
2019 }
2020
2021 /// @deprecated Use sourcePicoseconds() instead
2022 [[deprecated("use sourcePicoseconds() instead")]]
2023 uint16_t getSourcePicoseconds() const noexcept {
2024 return sourcePicoseconds();
2025 }
2026
2027 /// Get picoseconds interval added to the server timestamp.
2028 uint16_t serverPicoseconds() const noexcept {
2029 return handle()->serverPicoseconds;
2030 }
2031
2032 /// @deprecated Use serverPicoseconds() instead
2033 [[deprecated("use serverPicoseconds() instead")]]
2034 uint16_t getServerPicoseconds() const noexcept {
2035 return serverPicoseconds();
2036 }
2037
2038 /// Get status.
2039 StatusCode status() const noexcept {
2040 return handle()->status;
2041 }
2042
2043 /// @deprecated Use status() instead
2044 [[deprecated("use status() instead")]]
2045 StatusCode getStatus() const noexcept {
2046 return status();
2047 }
2048};
2049
2050/* --------------------------------------- ExtensionObject -------------------------------------- */
2051
2052/**
2053 * Extension object encoding.
2054 * @see UA_ExtensionObjectEncoding
2055 */
2065
2066/**
2067 * UA_ExtensionObject wrapper class.
2068 *
2069 * ExtensionObjects may contain scalars of any data type. Even those that are unknown to the
2070 * receiver. If the received data type is unknown, the encoded string and target NodeId is stored
2071 * instead of the decoded data.
2072 *
2073 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.1.6
2074 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.2.2.15
2075 * @ingroup Wrapper
2076 */
2077class ExtensionObject : public TypeWrapper<UA_ExtensionObject, UA_TYPES_EXTENSIONOBJECT> {
2078private:
2079 template <typename T>
2080 static constexpr bool isExtensionObject =
2081 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ExtensionObject> ||
2082 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, UA_ExtensionObject>;
2083
2084public:
2086
2087 /**
2088 * Create ExtensionObject from a pointer to a decoded object (no copy).
2089 * The object will *not* be deleted when the ExtensionObject is destructed.
2090 * @param ptr Pointer to decoded object (native or wrapper).
2091 */
2092 template <typename T>
2093 explicit ExtensionObject(T* ptr) noexcept
2094 : ExtensionObject(ptr, getDataType<T>()) {}
2095
2096 /**
2097 * Create ExtensionObject from a pointer to a decoded object with a custom data type (no copy).
2098 * The object will *not* be deleted when the ExtensionObject is destructed.
2099 * @param ptr Pointer to decoded object (native or wrapper).
2100 * @param type Data type of the decoded object.
2101 */
2102 template <typename T>
2103 ExtensionObject(T* ptr, const UA_DataType& type) noexcept {
2104 if (ptr == nullptr) {
2105 return;
2106 }
2107 assert(sizeof(T) == type.memSize);
2109 handle()->content.decoded.type = &type; // NOLINT
2110 handle()->content.decoded.data = ptr; // NOLINT
2111 }
2112
2113 /**
2114 * Create ExtensionObject from a decoded object (copy).
2115 * @param decoded Decoded object (native or wrapper).
2116 */
2117 template <typename T, typename = std::enable_if_t<!isExtensionObject<T>>>
2118 explicit ExtensionObject(const T& decoded)
2119 : ExtensionObject(decoded, getDataType<T>()) {}
2120
2121 /**
2122 * Create ExtensionObject from a decoded object with a custom data type (copy).
2123 * @param decoded Decoded object (native or wrapper).
2124 * @param type Data type of the decoded object.
2125 */
2126 template <typename T, typename = std::enable_if_t<!isExtensionObject<T>>>
2127 explicit ExtensionObject(const T& decoded, const UA_DataType& type) {
2128 auto ptr = detail::allocateUniquePtr<T>(type);
2129 *ptr = detail::copy(decoded, type);
2131 handle()->content.decoded.type = &type; // NOLINT
2132 handle()->content.decoded.data = ptr.release(); // NOLINT
2133 }
2134
2135 /// @deprecated Use new universal ExtensionObject constructor instead
2136 template <typename T, typename... Args>
2137 [[deprecated("use new universal ExtensionObject constructor instead")]] [[nodiscard]]
2138 static ExtensionObject fromDecoded(T& data, Args&&... args) noexcept {
2139 return ExtensionObject(&data, std::forward<Args>(args)...);
2140 }
2141
2142 /// @deprecated Use new universal ExtensionObject constructor instead
2143 template <typename T, typename... Args>
2144 [[deprecated("use new universal ExtensionObject constructor instead")]] [[nodiscard]]
2145 static ExtensionObject fromDecodedCopy(const T& data, Args&&... args) {
2146 return ExtensionObject(data, std::forward<Args>(args)...);
2147 }
2148
2149 /// Check if the ExtensionObject is empty
2150 bool empty() const noexcept {
2152 }
2153
2154 /// @deprecated Use empty() instead
2155 [[deprecated("use empty() instead")]]
2156 bool isEmpty() const noexcept {
2157 return empty();
2158 }
2159
2160 /// Check if the ExtensionObject is encoded (usually if the data type is unknown).
2161 bool isEncoded() const noexcept {
2164 }
2165
2166 /// Check if the ExtensionObject is decoded.
2167 bool isDecoded() const noexcept {
2170 }
2171
2172 /// Get the encoding.
2174 return static_cast<ExtensionObjectEncoding>(handle()->encoding);
2175 }
2176
2177 /// @deprecated Use encoding() instead
2178 [[deprecated("use encoding() instead")]]
2180 return encoding();
2181 }
2182
2183 /// Get the encoded type id.
2184 /// Returns `nullptr` if ExtensionObject is not encoded.
2185 const NodeId* encodedTypeId() const noexcept {
2186 return isEncoded()
2187 ? asWrapper<NodeId>(&handle()->content.encoded.typeId) // NOLINT
2188 : nullptr;
2189 }
2190
2191 /// @deprecated Use encodedTypeId() instead
2192 [[deprecated("use encodedTypeId() instead")]]
2193 const NodeId* getEncodedTypeId() const noexcept {
2194 return encodedTypeId();
2195 }
2196
2197 /// Get the encoded body in binary format.
2198 /// Returns `nullptr` if ExtensionObject is not encoded in binary format.
2199 const ByteString* encodedBinary() const noexcept {
2201 ? asWrapper<ByteString>(&handle()->content.encoded.body) // NOLINT
2202 : nullptr;
2203 }
2204
2205 /// Get the encoded body in XML format.
2206 /// Returns `nullptr` if ExtensionObject is not encoded in XML format.
2207 const XmlElement* encodedXml() const noexcept {
2209 ? asWrapper<XmlElement>(&handle()->content.encoded.body) // NOLINT
2210 : nullptr;
2211 }
2212
2213 /// @deprecated Use encodedBinary() or encodedXml() instead
2214 [[deprecated("use encodedBinary() or encodedXml() instead")]]
2215 const ByteString* getEncodedBody() const noexcept {
2216 return isEncoded()
2217 ? asWrapper<ByteString>(&handle()->content.encoded.body) // NOLINT
2218 : nullptr;
2219 }
2220
2221 /// Get the decoded data type.
2222 /// Returns `nullptr` if ExtensionObject is not decoded.
2223 const UA_DataType* decodedType() const noexcept {
2224 return isDecoded()
2225 ? handle()->content.decoded.type // NOLINT
2226 : nullptr;
2227 }
2228
2229 /// @deprecated Use decodedType() instead
2230 [[deprecated("use decodedType() instead")]]
2231 const UA_DataType* getDecodedDataType() const noexcept {
2232 return decodedType();
2233 }
2234
2235 /// Get pointer to the decoded data with given template type.
2236 /// Returns `nullptr` if the ExtensionObject is either not decoded or the decoded data is not of
2237 /// type `T`.
2238 template <typename T>
2239 T* decodedData() noexcept {
2240 return isDecodedType<T>() ? static_cast<T*>(decodedData()) : nullptr;
2241 }
2242
2243 /// Get const pointer to the decoded data with given template type.
2244 /// Returns `nullptr` if the ExtensionObject is either not decoded or the decoded data is not of
2245 /// type `T`.
2246 template <typename T>
2247 const T* decodedData() const noexcept {
2248 return isDecodedType<T>() ? static_cast<const T*>(decodedData()) : nullptr;
2249 }
2250
2251 /// @deprecated Use decodedData<T>() instead
2252 template <typename T>
2253 [[deprecated("use decodedData<T>() instead")]]
2254 T* getDecodedData() noexcept {
2255 return decodedData<T>();
2256 }
2257
2258 /// @deprecated Use decodedData<T>() instead
2259 template <typename T>
2260 [[deprecated("use decodedData<T>() instead")]]
2261 const T* getDecodedData() const noexcept {
2262 return decodedData<T>();
2263 }
2264
2265 /// Get pointer to the decoded data.
2266 /// Returns `nullptr` if the ExtensionObject is not decoded.
2267 /// @warning Type erased version, use with caution.
2268 void* decodedData() noexcept {
2269 return isDecoded()
2270 ? handle()->content.decoded.data // NOLINT
2271 : nullptr;
2272 }
2273
2274 /// Get pointer to the decoded data.
2275 /// Returns `nullptr` if the ExtensionObject is not decoded.
2276 /// @warning Type erased version, use with caution.
2277 const void* decodedData() const noexcept {
2278 return isDecoded()
2279 ? handle()->content.decoded.data // NOLINT
2280 : nullptr;
2281 }
2282
2283 /// @deprecated Use decodedData() instead
2284 [[deprecated("use decodedData() instead")]]
2285 void* getDecodedData() noexcept {
2286 return decodedData();
2287 }
2288
2289 /// @deprecated Use decodedData() instead
2290 [[deprecated("use decodedData() instead")]]
2291 const void* getDecodedData() const noexcept {
2292 return decodedData();
2293 }
2294
2295private:
2296 template <typename T>
2297 bool isDecodedType() const noexcept {
2298 const auto* type = decodedType();
2299 return (type != nullptr) && (type->typeId == getDataType<T>().typeId);
2300 }
2301};
2302
2303/* --------------------------------------- DiagnosticInfo --------------------------------------- */
2304
2305/**
2306 * UA_DiagnosticInfo wrapper class.
2307 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.12
2308 * @ingroup Wrapper
2309 */
2310class DiagnosticInfo : public TypeWrapper<UA_DiagnosticInfo, UA_TYPES_DIAGNOSTICINFO> {
2311public:
2313
2314 bool hasSymbolicId() const noexcept {
2315 return handle()->hasSymbolicId;
2316 }
2317
2318 bool hasNamespaceUri() const noexcept {
2319 return handle()->hasNamespaceUri;
2320 }
2321
2322 bool hasLocalizedText() const noexcept {
2323 return handle()->hasLocalizedText;
2324 }
2325
2326 bool hasLocale() const noexcept {
2327 return handle()->hasLocale;
2328 }
2329
2330 bool hasAdditionalInfo() const noexcept {
2331 return handle()->hasAdditionalInfo;
2332 }
2333
2334 bool hasInnerStatusCode() const noexcept {
2335 return handle()->hasInnerStatusCode;
2336 }
2337
2338 bool hasInnerDiagnosticInfo() const noexcept {
2340 }
2341
2342 int32_t symbolicId() const noexcept {
2343 return handle()->symbolicId;
2344 }
2345
2346 /// @deprecated Use symbolicId() instead
2347 [[deprecated("use symbolicId() instead")]]
2348 int32_t getSymbolicId() const noexcept {
2349 return symbolicId();
2350 }
2351
2352 int32_t namespaceUri() const noexcept {
2353 return handle()->namespaceUri;
2354 }
2355
2356 /// @deprecated Use namespaceUri() instead
2357 [[deprecated("use namespaceUri() instead")]]
2358 int32_t getNamespaceUri() const noexcept {
2359 return namespaceUri();
2360 }
2361
2362 int32_t localizedText() const noexcept {
2363 return handle()->localizedText;
2364 }
2365
2366 /// @deprecated Use localizedText() instead
2367 [[deprecated("use localizedText() instead")]]
2368 int32_t getLocalizedText() const noexcept {
2369 return localizedText();
2370 }
2371
2372 int32_t locale() const noexcept {
2373 return handle()->locale;
2374 }
2375
2376 /// @deprecated Use locale() instead
2377 [[deprecated("use locale() instead")]]
2378 int32_t getLocale() const noexcept {
2379 return locale();
2380 }
2381
2382 const String& additionalInfo() const noexcept {
2384 }
2385
2386 /// @deprecated Use additionalInfo() instead
2387 [[deprecated("use additionalInfo() instead")]]
2388 const String& getAdditionalInfo() const noexcept {
2389 return additionalInfo();
2390 }
2391
2392 StatusCode innerStatusCode() const noexcept {
2393 return handle()->innerStatusCode;
2394 }
2395
2396 /// @deprecated Use innerStatusCode() instead
2397 [[deprecated("use innerStatusCode() instead")]]
2399 return innerStatusCode();
2400 }
2401
2405
2406 /// @deprecated Use innerDiagnosticInfo() instead
2407 [[deprecated("use innerDiagnosticInfo() instead")]]
2408 const DiagnosticInfo* getInnerDiagnosticInfo() const noexcept {
2409 return innerDiagnosticInfo();
2410 }
2411};
2412
2413/* ---------------------------------------- NumericRange ---------------------------------------- */
2414
2416
2417/// @relates NumericRange
2418inline bool operator==(
2419 const NumericRangeDimension& lhs, const NumericRangeDimension& rhs
2420) noexcept {
2421 return (lhs.min == rhs.min) && (lhs.max == rhs.max);
2422}
2423
2424/// @relates NumericRange
2425inline bool operator!=(
2426 const NumericRangeDimension& lhs, const NumericRangeDimension& rhs
2427) noexcept {
2428 return !(lhs == rhs);
2429}
2430
2431/**
2432 * UA_NumericRange wrapper class.
2433 *
2434 * Numeric ranges indicate subsets of (multidimensional) arrays.
2435 * They are no official data type in the OPC UA standard and are transmitted only with a string
2436 * encoding, such as "1:2,0:3,5". The colon separates min/max index and the comma separates
2437 * dimensions. A single value indicates a range with a single element (min==max).
2438 *
2439 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.27
2440 * @ingroup Wrapper
2441 */
2442class NumericRange : public Wrapper<UA_NumericRange> {
2443public:
2444 NumericRange() = default;
2445
2446 /// Create a NumericRange from the encoded representation, e.g. `1:2,0:3,5`.
2447 explicit NumericRange(std::string_view encodedRange);
2448
2449 /// @overload
2450 explicit NumericRange(const char* encodedRange) // required to avoid ambiguity
2451 : NumericRange(std::string_view(encodedRange)) {}
2452
2453 /// Create a NumericRange from dimensions.
2456
2457 /// Create a NumericRange from native object (copy).
2459 : Wrapper(copy(native)) {}
2460
2461 /// Create a NumericRange from native object (move).
2463 : Wrapper(std::exchange(native, {})) {}
2464
2466 clear();
2467 }
2468
2470 : Wrapper(copy(other.native())) {}
2471
2472 NumericRange(NumericRange&& other) noexcept
2473 : Wrapper(std::exchange(other.native(), {})) {}
2474
2476 if (this != &other) {
2477 clear();
2478 native() = copy(other.native());
2479 }
2480 return *this;
2481 }
2482
2484 if (this != &other) {
2485 clear();
2486 native() = std::exchange(other.native(), {});
2487 }
2488 return *this;
2489 }
2490
2491 bool empty() const noexcept {
2492 return native().dimensionsSize == 0;
2493 }
2494
2498
2499 std::string toString() const;
2500
2501private:
2502 void clear() noexcept {
2503 detail::deallocateArray(native().dimensions);
2504 native() = {};
2505 }
2506
2507 [[nodiscard]] static UA_NumericRange copy(const UA_NumericRangeDimension* array, size_t size) {
2508 UA_NumericRange result{};
2509 result.dimensions = detail::copyArray(array, size);
2510 result.dimensionsSize = size;
2511 return result;
2512 }
2513
2514 [[nodiscard]] static UA_NumericRange copy(const UA_NumericRange& other) {
2515 return copy(other.dimensions, other.dimensionsSize);
2516 }
2517};
2518
2519} // namespace opcua
2520
2521/* ---------------------------------- std::hash specializations --------------------------------- */
2522
2523template <>
2524struct std::hash<opcua::NodeId> {
2525 std::size_t operator()(const opcua::NodeId& id) const noexcept {
2526 return id.hash();
2527 }
2528};
2529
2530template <>
2531struct std::hash<opcua::ExpandedNodeId> {
2532 std::size_t operator()(const opcua::ExpandedNodeId& id) const noexcept {
2533 return id.hash();
2534 }
2535};
UA_ByteString wrapper class.
Definition types.hpp:531
bool operator==(const ByteString &lhs, std::string_view rhs) noexcept
Definition types.hpp:572
std::string_view get() const noexcept
Definition types.hpp:566
std::string toBase64() const
Convert to Base64 encoded string.
bool operator!=(const ByteString &lhs, std::string_view rhs) noexcept
Definition types.hpp:577
ByteString(InputIt first, InputIt last)
Definition types.hpp:546
ByteString(std::string_view str)
Definition types.hpp:535
bool operator!=(std::string_view lhs, const ByteString &rhs) noexcept
Definition types.hpp:587
ByteString(Span< const uint8_t > bytes)
Definition types.hpp:541
static ByteString fromBase64(std::string_view encoded)
Parse ByteString from Base64 encoded string.
bool operator==(std::string_view lhs, const ByteString &rhs) noexcept
Definition types.hpp:582
ByteString(const char *str)
Definition types.hpp:538
Client * asWrapper(UA_Client *client) noexcept
Convert native UA_Client pointer to its wrapper instance.
UA_DataValue wrapper class.
Definition types.hpp:1832
bool hasServerPicoseconds() const noexcept
Definition types.hpp:1942
void setSourceTimestamp(DateTime sourceTimestamp) noexcept
Set source timestamp for the value.
Definition types.hpp:1897
uint16_t serverPicoseconds() const noexcept
Get picoseconds interval added to the server timestamp.
Definition types.hpp:2028
bool hasValue() const noexcept
Definition types.hpp:1926
DateTime getServerTimestamp() const noexcept
Definition types.hpp:2012
DataValue(Variant value) noexcept
Definition types.hpp:1836
const Variant && getValue() const &&noexcept
Definition types.hpp:1990
uint16_t getServerPicoseconds() const noexcept
Definition types.hpp:2034
StatusCode status() const noexcept
Get status.
Definition types.hpp:2039
const Variant && value() const &&noexcept
Get value (rvalue).
Definition types.hpp:1966
DateTime serverTimestamp() const noexcept
Get server timestamp for the value.
Definition types.hpp:2006
bool hasSourceTimestamp() const noexcept
Definition types.hpp:1930
void setServerPicoseconds(uint16_t serverPicoseconds) noexcept
Set picoseconds interval added to the server timestamp.
Definition types.hpp:1915
uint16_t sourcePicoseconds() const noexcept
Get picoseconds interval added to the source timestamp.
Definition types.hpp:2017
const Variant & getValue() const &noexcept
Definition types.hpp:1978
Variant && value() &&noexcept
Get value (rvalue).
Definition types.hpp:1961
bool hasStatus() const noexcept
Definition types.hpp:1946
static DataValue fromScalar(Args &&... args)
Create DataValue from scalar value.
Definition types.hpp:1870
void setValue(Variant &&value) noexcept
Set value (move).
Definition types.hpp:1891
void setServerTimestamp(DateTime serverTimestamp) noexcept
Set server timestamp for the value.
Definition types.hpp:1903
Variant & getValue() &noexcept
Definition types.hpp:1972
static DataValue fromArray(Args &&... args)
Create DataValue from array.
Definition types.hpp:1880
StatusCode getStatus() const noexcept
Definition types.hpp:2045
void setStatus(StatusCode status) noexcept
Set status.
Definition types.hpp:1921
Variant & value() &noexcept
Get value.
Definition types.hpp:1951
void setSourcePicoseconds(uint16_t sourcePicoseconds) noexcept
Set picoseconds interval added to the source timestamp.
Definition types.hpp:1909
bool hasSourcePicoseconds() const noexcept
Definition types.hpp:1938
DateTime sourceTimestamp() const noexcept
Get source timestamp for the value.
Definition types.hpp:1995
uint16_t getSourcePicoseconds() const noexcept
Definition types.hpp:2023
bool hasServerTimestamp() const noexcept
Definition types.hpp:1934
void setValue(const Variant &value)
Set value (copy).
Definition types.hpp:1885
Variant && getValue() &&noexcept
Definition types.hpp:1984
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:1840
const Variant & value() const &noexcept
Get value.
Definition types.hpp:1956
DateTime getSourceTimestamp() const noexcept
Definition types.hpp:2001
UA_DateTime wrapper class.
Definition types.hpp:390
int64_t get() const noexcept
Get DateTime value as 100 nanosecond intervals since January 1, 1601 (UTC).
Definition types.hpp:450
UA_DateTimeStruct toStruct() const noexcept
Convert to UA_DateTimeStruct.
Definition types.hpp:445
static DateTime fromUnixTime(int64_t unixTime) noexcept
Get DateTime from Unix time.
Definition types.hpp:416
static DateTime now() noexcept
Get current DateTime.
Definition types.hpp:402
std::chrono::duration< int64_t, std::ratio< 1, 10 '000 '000 > > UaDuration
Definition types.hpp:393
static DateTime fromTimePoint(std::chrono::time_point< Clock, Duration > timePoint)
Get DateTime from std::chrono::time_point.
Definition types.hpp:408
int64_t toUnixTime() const noexcept
Convert to Unix time (number of seconds since January 1, 1970 UTC).
Definition types.hpp:437
static int64_t localTimeUtcOffset() noexcept
Offset of local time to UTC.
Definition types.hpp:421
DateTime(std::chrono::time_point< Clock, Duration > timePoint)
Definition types.hpp:398
std::string format(std::string_view format, bool localtime=false) const
Convert to string with given format (same format codes as strftime).
std::chrono::time_point< Clock, Duration > toTimePoint() const
Convert to std::chrono::time_point.
Definition types.hpp:427
std::chrono::system_clock DefaultClock
Definition types.hpp:392
UA_DiagnosticInfo wrapper class.
Definition types.hpp:2310
bool hasInnerStatusCode() const noexcept
Definition types.hpp:2334
bool hasLocalizedText() const noexcept
Definition types.hpp:2322
int32_t getSymbolicId() const noexcept
Definition types.hpp:2348
int32_t symbolicId() const noexcept
Definition types.hpp:2342
int32_t getNamespaceUri() const noexcept
Definition types.hpp:2358
bool hasSymbolicId() const noexcept
Definition types.hpp:2314
int32_t locale() const noexcept
Definition types.hpp:2372
StatusCode innerStatusCode() const noexcept
Definition types.hpp:2392
const String & additionalInfo() const noexcept
Definition types.hpp:2382
bool hasLocale() const noexcept
Definition types.hpp:2326
bool hasInnerDiagnosticInfo() const noexcept
Definition types.hpp:2338
int32_t getLocalizedText() const noexcept
Definition types.hpp:2368
int32_t getLocale() const noexcept
Definition types.hpp:2378
const DiagnosticInfo * innerDiagnosticInfo() const noexcept
Definition types.hpp:2402
const String & getAdditionalInfo() const noexcept
Definition types.hpp:2388
int32_t namespaceUri() const noexcept
Definition types.hpp:2352
const DiagnosticInfo * getInnerDiagnosticInfo() const noexcept
Definition types.hpp:2408
StatusCode getInnerStatusCode() const noexcept
Definition types.hpp:2398
bool hasNamespaceUri() const noexcept
Definition types.hpp:2318
int32_t localizedText() const noexcept
Definition types.hpp:2362
bool hasAdditionalInfo() const noexcept
Definition types.hpp:2330
UA_ExpandedNodeId wrapper class.
Definition types.hpp:908
bool operator<=(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:996
uint32_t hash() const noexcept
Definition types.hpp:926
ExpandedNodeId(NodeId id) noexcept
Definition types.hpp:912
const NodeId & getNodeId() const noexcept
Definition types.hpp:946
ExpandedNodeId(NodeId id, std::string_view namespaceUri, uint32_t serverIndex)
Definition types.hpp:916
bool operator>=(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:1001
bool isLocal() const noexcept
Definition types.hpp:922
bool operator!=(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:981
uint32_t serverIndex() const noexcept
Definition types.hpp:960
std::string toString() const
Encode ExpandedNodeId as a string like svr=1;nsu=http://test.org/UA/Data/;ns=2;i=10157.
bool operator<(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:986
std::string_view namespaceUri() const
Definition types.hpp:950
uint32_t getServerIndex() const noexcept
Definition types.hpp:966
const NodeId & nodeId() const noexcept
Definition types.hpp:934
NodeId & nodeId() noexcept
Definition types.hpp:930
NodeId & getNodeId() noexcept
Definition types.hpp:940
bool operator>(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:991
std::string_view getNamespaceUri() const
Definition types.hpp:956
bool operator==(const UA_ExpandedNodeId &lhs, const UA_ExpandedNodeId &rhs) noexcept
Definition types.hpp:976
UA_ExtensionObject wrapper class.
Definition types.hpp:2077
bool isDecoded() const noexcept
Check if the ExtensionObject is decoded.
Definition types.hpp:2167
bool isEmpty() const noexcept
Definition types.hpp:2156
const UA_DataType * getDecodedDataType() const noexcept
Definition types.hpp:2231
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:2103
const UA_DataType * decodedType() const noexcept
Get the decoded data type.
Definition types.hpp:2223
const XmlElement * encodedXml() const noexcept
Get the encoded body in XML format.
Definition types.hpp:2207
static ExtensionObject fromDecoded(T &data, Args &&... args) noexcept
Definition types.hpp:2138
T * decodedData() noexcept
Get pointer to the decoded data with given template type.
Definition types.hpp:2239
ExtensionObject(T *ptr) noexcept
Create ExtensionObject from a pointer to a decoded object (no copy).
Definition types.hpp:2093
T * getDecodedData() noexcept
Definition types.hpp:2254
bool empty() const noexcept
Check if the ExtensionObject is empty.
Definition types.hpp:2150
const ByteString * getEncodedBody() const noexcept
Definition types.hpp:2215
ExtensionObject(const T &decoded)
Create ExtensionObject from a decoded object (copy).
Definition types.hpp:2118
const NodeId * encodedTypeId() const noexcept
Get the encoded type id.
Definition types.hpp:2185
const T * getDecodedData() const noexcept
Definition types.hpp:2261
const NodeId * getEncodedTypeId() const noexcept
Definition types.hpp:2193
void * decodedData() noexcept
Get pointer to the decoded data.
Definition types.hpp:2268
const T * decodedData() const noexcept
Get const pointer to the decoded data with given template type.
Definition types.hpp:2247
ExtensionObjectEncoding getEncoding() const noexcept
Definition types.hpp:2179
void * getDecodedData() noexcept
Definition types.hpp:2285
bool isEncoded() const noexcept
Check if the ExtensionObject is encoded (usually if the data type is unknown).
Definition types.hpp:2161
ExtensionObject(const T &decoded, const UA_DataType &type)
Create ExtensionObject from a decoded object with a custom data type (copy).
Definition types.hpp:2127
const ByteString * encodedBinary() const noexcept
Get the encoded body in binary format.
Definition types.hpp:2199
ExtensionObjectEncoding encoding() const noexcept
Get the encoding.
Definition types.hpp:2173
const void * getDecodedData() const noexcept
Definition types.hpp:2291
const void * decodedData() const noexcept
Get pointer to the decoded data.
Definition types.hpp:2277
static ExtensionObject fromDecodedCopy(const T &data, Args &&... args)
Definition types.hpp:2145
UA_Guid wrapper class.
Definition types.hpp:479
std::ostream & operator<<(std::ostream &os, const Guid &guid)
Guid(uint32_t data1, uint16_t data2, uint16_t data3, std::array< uint8_t, 8 > data4) noexcept
Definition types.hpp:495
Guid(std::array< uint8_t, 16 > data) noexcept
Definition types.hpp:483
bool operator==(const UA_Guid &lhs, const UA_Guid &rhs) noexcept
Definition types.hpp:511
bool operator!=(const UA_Guid &lhs, const UA_Guid &rhs) noexcept
Definition types.hpp:516
std::string toString() const
static Guid random() noexcept
Definition types.hpp:503
UA_LocalizedText wrapper class.
Definition types.hpp:1062
bool operator==(const UA_LocalizedText &lhs, const UA_LocalizedText &rhs) noexcept
Definition types.hpp:1093
std::string_view text() const noexcept
Definition types.hpp:1081
std::string_view locale() const noexcept
Definition types.hpp:1071
std::string_view getLocale() const noexcept
Definition types.hpp:1077
std::string_view getText() const noexcept
Definition types.hpp:1087
bool operator!=(const UA_LocalizedText &lhs, const UA_LocalizedText &rhs) noexcept
Definition types.hpp:1098
LocalizedText(std::string_view locale, std::string_view text)
Definition types.hpp:1066
UA_NodeId wrapper class.
Definition types.hpp:666
const T & identifier() const
Get identifier reference.
Definition types.hpp:799
std::string toString() const
Encode NodeId as a string like ns=1;s=SomeNode.
NodeId(T identifier) noexcept
Create NodeId from enum class with numeric identifiers like opcua::ObjectId.
Definition types.hpp:704
NodeIdType identifierType() const noexcept
Definition types.hpp:725
NamespaceIndex namespaceIndex() const noexcept
Definition types.hpp:715
NodeId(NamespaceIndex namespaceIndex, uint32_t identifier) noexcept
Create NodeId with numeric identifier.
Definition types.hpp:671
NodeId(NamespaceIndex namespaceIndex, ByteString identifier) noexcept
Create NodeId with ByteString identifier.
Definition types.hpp:692
bool operator!=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:877
std::variant< uint32_t, String, Guid, ByteString > getIdentifier() const
Get identifier variant.
Definition types.hpp:809
bool operator<(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:882
bool operator>(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:887
NodeId(NamespaceIndex namespaceIndex, Guid identifier) noexcept
Create NodeId with Guid identifier.
Definition types.hpp:685
const T * identifierIf() const noexcept
Get identifier pointer or nullptr on error.
Definition types.hpp:752
auto getIdentifierAs() const
Get identifier by template type.
Definition types.hpp:817
bool operator==(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:872
bool isNull() const noexcept
Definition types.hpp:707
bool operator>=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:897
bool operator<=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:892
T * identifierIf() noexcept
Get identifier pointer or nullptr on error.
Definition types.hpp:746
NamespaceIndex getNamespaceIndex() const noexcept
Definition types.hpp:721
NodeIdType getIdentifierType() const noexcept
Definition types.hpp:731
T & identifier()
Get identifier reference.
Definition types.hpp:793
uint32_t hash() const noexcept
Definition types.hpp:711
NodeId(NamespaceIndex namespaceIndex, std::string_view identifier)
Create NodeId with String identifier.
Definition types.hpp:678
UA_NumericRange wrapper class.
Definition types.hpp:2442
bool empty() const noexcept
Definition types.hpp:2491
NumericRange(UA_NumericRange &&native) noexcept
Create a NumericRange from native object (move).
Definition types.hpp:2462
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:2425
NumericRange(const char *encodedRange)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition types.hpp:2450
NumericRange(Span< const NumericRangeDimension > dimensions)
Create a NumericRange from dimensions.
Definition types.hpp:2454
Span< const NumericRangeDimension > dimensions() const noexcept
Definition types.hpp:2495
NumericRange(const NumericRange &other)
Definition types.hpp:2469
bool operator==(const NumericRangeDimension &lhs, const NumericRangeDimension &rhs) noexcept
Definition types.hpp:2418
NumericRange()=default
NumericRange(NumericRange &&other) noexcept
Definition types.hpp:2472
NumericRange(const UA_NumericRange &native)
Create a NumericRange from native object (copy).
Definition types.hpp:2458
std::string toString() const
NumericRange & operator=(const NumericRange &other)
Definition types.hpp:2475
NumericRange & operator=(NumericRange &&other) noexcept
Definition types.hpp:2483
UA_QualifiedName wrapper class.
Definition types.hpp:1011
bool operator!=(const UA_QualifiedName &lhs, const UA_QualifiedName &rhs) noexcept
Definition types.hpp:1047
NamespaceIndex getNamespaceIndex() const noexcept
Definition types.hpp:1026
bool operator==(const UA_QualifiedName &lhs, const UA_QualifiedName &rhs) noexcept
Definition types.hpp:1042
NamespaceIndex namespaceIndex() const noexcept
Definition types.hpp:1020
QualifiedName(NamespaceIndex namespaceIndex, std::string_view name)
Definition types.hpp:1015
std::string_view name() const noexcept
Definition types.hpp:1030
std::string_view getName() const noexcept
Definition types.hpp:1036
View to a contiguous sequence of objects, similar to std::span in C++20.
Definition span.hpp:28
constexpr iterator begin() const noexcept
Definition span.hpp:143
Span(Container &) -> Span< typename Container::value_type >
constexpr iterator end() const noexcept
Definition span.hpp:147
UA_StatusCode wrapper class.
Definition types.hpp:46
constexpr void throwIfBad() const
Throw a BadStatus exception if the status code is bad.
Definition types.hpp:84
constexpr bool isUncertain() const noexcept
Check if the status code is uncertain.
Definition types.hpp:73
constexpr bool isBad() const noexcept
Check if the status code is bad.
Definition types.hpp:78
std::string_view name() const noexcept
Get human-readable name of the StatusCode.
Definition types.hpp:63
constexpr bool isGood() const noexcept
Check if the status code is good.
Definition types.hpp:68
constexpr UA_StatusCode get() const noexcept
Explicitly get underlying UA_StatusCode.
Definition types.hpp:55
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==(std::string_view lhs, const String &rhs) noexcept
Definition types.hpp:319
std::string_view get() const noexcept
Definition types.hpp:293
bool operator==(const String &lhs, std::string_view rhs) noexcept
Definition types.hpp:309
String(InputIt first, InputIt last)
Definition types.hpp:264
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:314
bool operator!=(std::string_view lhs, const String &rhs) noexcept
Definition types.hpp:324
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:304
bool operator==(const UA_String &lhs, const UA_String &rhs) noexcept
Definition types.hpp:299
Exception for type-related errors.
Definition exception.hpp:45
Template base class to wrap UA_* type objects that require manual memory management.
constexpr TypeWrapper() noexcept=default
UA_Variant wrapper class.
Definition types.hpp:1176
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:1224
T getScalarCopy() const
Definition types.hpp:1573
Span< T > getArray()
Definition types.hpp:1600
bool isType(const UA_DataType &type) const noexcept
Check if the variant type is equal to the provided data type.
Definition types.hpp:1459
const void * data() const noexcept
Get pointer to the underlying data.
Definition types.hpp:1521
void assign(InputIt first, InputIt last)
Assign range to variant (copy and convert if required).
Definition types.hpp:1349
Variant(InputIt first, InputIt last)
Create Variant from a range of elements (copy).
Definition types.hpp:1217
void assign(InputIt first, InputIt last, const UA_DataType &type)
Assign range to variant with custom data type (copy).
Definition types.hpp:1367
T && scalar() &&
Get reference to scalar value with given template type (only native or wrapper types).
Definition types.hpp:1546
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:1196
const UA_DataType * getDataType() const noexcept
Definition types.hpp:1481
const T & scalar() const &
Get reference to scalar value with given template type (only native or wrapper types).
Definition types.hpp:1537
Variant & operator=(T *value) noexcept
Assign pointer to scalar/array to variant (no copy).
Definition types.hpp:1374
const T && scalar() const &&
Get reference to scalar value with given template type (only native or wrapper types).
Definition types.hpp:1552
void setScalar(T &value, Args &&... args) noexcept
Definition types.hpp:1390
Span< const uint32_t > getArrayDimensions() const noexcept
Definition types.hpp:1503
size_t getArrayLength() const noexcept
Definition types.hpp:1492
Span< T > array()
Get reference to array with given template type (only native or wrapper types).
Definition types.hpp:1580
static Variant fromArray(T &&array, Args &&... args)
Definition types.hpp:1242
void assign(const T &value)
Assign scalar/array to variant (copy and convert if required).
Definition types.hpp:1312
static Variant fromArray(InputIt first, InputIt last, Args &&... args)
Definition types.hpp:1253
T & scalar() &
Get reference to scalar value with given template type (only native or wrapper types).
Definition types.hpp:1528
std::vector< T > getArrayCopy() const
Definition types.hpp:1614
void setArrayCopy(InputIt first, InputIt last, Args &&... args)
Definition types.hpp:1418
bool isType(const UA_DataType *type) const noexcept
Check if the variant type is equal to the provided data type.
Definition types.hpp:1452
T to() const
Converts the variant to the specified type T with automatic conversion if required.
Definition types.hpp:1642
void assign(T *ptr) noexcept
Assign pointer to scalar/array to variant (no copy).
Definition types.hpp:1277
bool isType(const NodeId &id) const noexcept
Check if the variant type is equal to the provided data type node id.
Definition types.hpp:1464
Span< const T > getArray() const
Definition types.hpp:1607
bool empty() const noexcept
Check if the variant is empty.
Definition types.hpp:1428
static Variant fromScalar(T &&value, Args &&... args)
Definition types.hpp:1231
Variant & operator=(const T &value)
Assign scalar/array to variant (copy and convert if required).
Definition types.hpp:1382
void setScalarCopy(const T &value, Args &&... args)
Definition types.hpp:1397
void setArray(T &array, Args &&... args) noexcept
Definition types.hpp:1404
size_t arrayLength() const noexcept
Get array length or 0 if variant is not an array.
Definition types.hpp:1486
const UA_DataType * type() const noexcept
Get data type.
Definition types.hpp:1475
bool isEmpty() const noexcept
Definition types.hpp:1434
Variant(T *ptr) noexcept
Create Variant from a pointer to a scalar/array (no copy).
Definition types.hpp:1189
Variant(const T &value)
Create Variant from a scalar/array (copy).
Definition types.hpp:1203
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:1497
bool isArray() const noexcept
Check if the variant is an array.
Definition types.hpp:1447
void setArrayCopy(const T &array, Args &&... args)
Definition types.hpp:1411
Variant(const T &value, const UA_DataType &type)
Create Variant from a scalar/array with a custom data type (copy).
Definition types.hpp:1210
Span< const T > array() const
Get reference to array with given template type (only native or wrapper types).
Definition types.hpp:1590
T & getScalar()
Definition types.hpp:1559
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:1294
bool isScalar() const noexcept
Check if the variant is a scalar.
Definition types.hpp:1439
void assign(const T &value, const UA_DataType &type)
Assign scalar/array to variant with custom data type (copy).
Definition types.hpp:1334
bool isType() const noexcept
Check if the variant type is equal to the provided template type.
Definition types.hpp:1470
void * data() noexcept
Get pointer to the underlying data.
Definition types.hpp:1516
const T & getScalar() const
Definition types.hpp:1566
Template base class to wrap native objects.
Definition wrapper.hpp:33
constexpr const UA_StatusCode & native() const noexcept
Definition wrapper.hpp:102
constexpr UA_DateTime * handle() noexcept
Definition wrapper.hpp:82
constexpr Wrapper() noexcept=default
UA_XmlElement wrapper class.
Definition types.hpp:599
std::string_view get() const noexcept
Definition types.hpp:632
std::ostream & operator<<(std::ostream &os, const XmlElement &xmlElement)
XmlElement(std::string_view str)
Definition types.hpp:603
XmlElement & operator=(std::basic_string_view< char, Traits > str)
Assign std::string_view.
Definition types.hpp:619
XmlElement(InputIt first, InputIt last)
Definition types.hpp:607
XmlElement & operator=(const char *str)
Assign null-termined character string.
Definition types.hpp:612
UA_ORDER_LESS
UA_ORDER_MORE
constexpr Namespace namespaceOf(DataTypeId) noexcept
Get namespace of DataTypeId.
Definition nodeids.hpp:448
constexpr NativeType * asNative(WrapperType *wrapper) noexcept
Cast Wrapper object pointers to native object pointers.
Definition wrapper.hpp:223
static UA_LogCategory const char va_list args
NodeIdType
NodeId types.
Definition types.hpp:654
ExtensionObjectEncoding
Extension object encoding.
Definition types.hpp:2056
VariantPolicy
Policies for variant factory methods Variant::fromScalar, Variant::fromArray.
Definition types.hpp:1107
@ Copy
Store copy of scalar/array inside the variant.
@ Reference
Store reference to scalar/array inside the variant.
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
uint16_t NamespaceIndex
Namespace index.
Definition common.hpp:12
@ NodeId
Unambiguous identifier of a node.
const UA_DataType & getDataType() noexcept
UA_NodeId typeId
UA_Boolean hasSourcePicoseconds
UA_Boolean hasServerTimestamp
UA_UInt16 serverPicoseconds
UA_DateTime serverTimestamp
UA_UInt16 sourcePicoseconds
UA_StatusCode status
UA_DateTime sourceTimestamp
UA_Boolean hasStatus
UA_Boolean hasSourceTimestamp
UA_Boolean hasServerPicoseconds
UA_Boolean hasValue
UA_Boolean hasNamespaceUri
UA_Boolean hasInnerDiagnosticInfo
UA_Boolean hasSymbolicId
UA_Int32 namespaceUri
UA_Boolean hasLocale
UA_Int32 localizedText
UA_Boolean hasLocalizedText
UA_Boolean hasInnerStatusCode
UA_StatusCode innerStatusCode
UA_Boolean hasAdditionalInfo
UA_UInt32 serverIndex
UA_String namespaceUri
UA_ExtensionObjectEncoding encoding
struct UA_ExtensionObject::@26::@27 encoded
union UA_ExtensionObject::@26 content
const UA_DataType * type
UA_ByteString body
struct UA_ExtensionObject::@26::@28 decoded
UA_String locale
enum UA_NodeIdType identifierType
UA_Guid guid
UA_String string
UA_UInt16 namespaceIndex
union UA_NodeId::@25 identifier
UA_ByteString byteString
UA_UInt32 numeric
UA_NumericRangeDimension * dimensions
size_t dimensionsSize
UA_UInt16 namespaceIndex
const UA_DataType * type
size_t arrayLength
void * data
UA_UInt32 * arrayDimensions
size_t arrayDimensionsSize
static void toNative(const Type &src, NativeType &dst)
Definition types.hpp:374
static void toNative(Type src, NativeType &dst)
Definition types.hpp:364
std::basic_string< char, Traits, Allocator > Type
Definition types.hpp:347
static void fromNative(const NativeType &src, Type &dst)
Definition types.hpp:350
static void toNative(const Type &src, NativeType &dst)
Definition types.hpp:354
std::basic_string_view< char, Traits > Type
Definition types.hpp:333
static void toNative(Type src, NativeType &dst)
Definition types.hpp:340
static void fromNative(const NativeType &src, Type &dst)
Definition types.hpp:336
std::chrono::time_point< Clock, Duration > Type
Definition types.hpp:461
static void fromNative(const NativeType &src, Type &dst)
Definition types.hpp:464
static void toNative(const Type &src, NativeType &dst)
Definition types.hpp:468
Type conversion from and to native types.
std::size_t operator()(const opcua::ExpandedNodeId &id) const noexcept
Definition types.hpp:2532
std::size_t operator()(const opcua::NodeId &id) const noexcept
Definition types.hpp:2525
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)
#define UA_EMPTY_ARRAY_SENTINEL
UA_Guid UA_Guid_random(void)
UA_UInt32 UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n)
UA_Order UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2)
#define UA_DATETIME_UNIX_EPOCH
UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t)
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