open62541pp 0.16.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
23#include "open62541pp/detail/string_utils.hpp" // allocNativeString
26#include "open62541pp/span.hpp"
31
32namespace opcua {
33
34/* ----------------------------------------- StatusCode ----------------------------------------- */
35
36/**
37 * UA_StatusCode wrapper class.
38 * StatusCode can be used interchangeably with @ref UA_StatusCode due to implicit conversions
39 * (without any overhead) but provides some methods to simplify the handling with status codes.
40 * @see statuscodes.h
41 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.39
42 * @ingroup Wrapper
43 */
44class StatusCode : public Wrapper<UA_StatusCode> {
45public:
46 /// Create a StatusCode with the default status code `UA_STATUSCODE_GOOD`.
47 constexpr StatusCode() noexcept = default;
48
49 constexpr StatusCode(UA_StatusCode code) noexcept // NOLINT(hicpp-explicit-conversions)
50 : Wrapper(code) {}
51
52 /// Explicitly get underlying UA_StatusCode.
53 constexpr UA_StatusCode get() const noexcept {
54 return native();
55 }
56
57 /// Get human-readable name of the StatusCode.
58 /// This feature might be disabled to create a smaller binary with the
59 /// `UA_ENABLE_STATUSCODE_DESCRIPTIONS` build-flag. Then the function returns an empty string
60 /// for every StatusCode.
61 std::string_view name() const noexcept {
62 return {UA_StatusCode_name(native())};
63 }
64
65 /// Check if the status code is good.
66 constexpr bool isGood() const noexcept {
67 return detail::isGood(native());
68 }
69
70 /// Check if the status code is uncertain.
71 constexpr bool isUncertain() const noexcept {
73 }
74
75 /// Check if the status code is bad.
76 constexpr bool isBad() const noexcept {
77 return detail::isBad(native());
78 }
79
80 /// Throw a BadStatus exception if the status code is bad.
81 /// @exception BadStatus
82 constexpr void throwIfBad() const {
84 }
85};
86
87/* ---------------------------------------- StringWrapper --------------------------------------- */
88
89namespace detail {
90
91template <typename T, TypeIndex typeIndex, typename CharT>
92class StringWrapper : public TypeWrapper<T, typeIndex> {
93public:
94 static_assert(std::is_same_v<T, UA_String>);
95
96 // clang-format off
97 using value_type = CharT;
98 using size_type = size_t;
99 using difference_type = std::ptrdiff_t;
101 using const_pointer = const value_type*;
106 using reverse_iterator = std::reverse_iterator<iterator>;
107 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
108 // clang-format on
109
110 using TypeWrapper<T, typeIndex>::TypeWrapper; // inherit constructors
111
112 template <typename InputIt>
113 StringWrapper(InputIt first, InputIt last)
114 : StringWrapper(first, last, typename std::iterator_traits<InputIt>::iterator_category{}) {}
115
116 StringWrapper(std::initializer_list<CharT> init)
117 : StringWrapper(init.begin(), init.end()) {}
118
119 size_t size() const noexcept {
120 return this->native().length;
121 }
122
123 size_t length() const noexcept {
124 return size();
125 }
126
127 bool empty() const noexcept {
128 return size() == 0;
129 }
130
131 pointer data() noexcept {
132 return reinterpret_cast<pointer>(this->native().data); // NOLINT
133 }
134
135 const_pointer data() const noexcept {
136 return reinterpret_cast<const_pointer>(this->native().data); // NOLINT
137 }
138
139 reference operator[](size_t index) noexcept {
140 assert(index < size());
141 return data()[index];
142 }
143
144 const_reference operator[](size_t index) const noexcept {
145 assert(index < size());
146 return data()[index];
147 }
148
149 reference front() noexcept {
150 assert(!empty());
151 return *data();
152 }
153
154 const_reference front() const noexcept {
155 assert(!empty());
156 return *data();
157 }
158
159 reference back() noexcept {
160 assert(!empty());
161 return *(data() + size() - 1);
162 }
163
164 const_reference back() const noexcept {
165 assert(!empty());
166 return *(data() + size() - 1);
167 }
168
169 iterator begin() noexcept {
170 return {data()};
171 }
172
173 const_iterator begin() const noexcept {
174 return {data()};
175 }
176
177 const_iterator cbegin() const noexcept {
178 return {data()};
179 }
180
181 iterator end() noexcept {
182 return {data() + size()};
183 }
184
185 const_iterator end() const noexcept {
186 return {data() + size()};
187 }
188
189 const_iterator cend() const noexcept {
190 return {data() + size()};
191 }
192
194 return reverse_iterator(end());
195 }
196
198 return const_reverse_iterator(end());
199 }
200
203 }
204
206 return reverse_iterator(begin());
207 }
208
209 const_reverse_iterator rend() const noexcept {
211 }
212
213 const_reverse_iterator crend() const noexcept {
215 }
216
217protected:
218 void init(size_t length) {
219 this->native().length = length;
220 if (length > 0) {
221 this->native().data = static_cast<uint8_t*>(UA_malloc(length)); // NOLINT
222 if (data() == nullptr) {
224 }
225 }
226 }
227
228 template <typename InputIt, typename Tag>
229 StringWrapper(InputIt first, InputIt last, Tag /* unused */) {
230 init(std::distance(first, last));
231 std::copy(first, last, data());
232 }
233
234 template <typename InputIt>
235 StringWrapper(InputIt first, InputIt last, std::input_iterator_tag /* unused */) {
236 // input iterator can only be read once -> buffer data in vector
237 std::vector<uint8_t> buffer(first, last);
238 init(buffer.size());
239 std::copy(buffer.begin(), buffer.end(), data());
240 }
241};
242
243} // namespace detail
244
245/* ------------------------------------------- String ------------------------------------------- */
246
247/**
248 * UA_String wrapper class.
249 * @ingroup Wrapper
250 */
251class String : public detail::StringWrapper<UA_String, UA_TYPES_STRING, char> {
252public:
253 using StringWrapper::StringWrapper; // inherit constructors
254
255 explicit String(std::string_view str)
256 : StringWrapper(detail::allocNativeString(str)) {}
257
258 /// Implicit conversion to std::string_view.
259 operator std::string_view() const noexcept { // NOLINT(hicpp-explicit-conversions)
260 return {data(), size()};
261 }
262
263 [[deprecated("use conversion function with static_cast instead")]]
264 std::string_view get() const noexcept {
265 return {data(), size()};
266 }
267};
268
269inline bool operator==(const UA_String& lhs, const UA_String& rhs) noexcept {
270 return UA_String_equal(&lhs, &rhs);
271}
272
273inline bool operator!=(const UA_String& lhs, const UA_String& rhs) noexcept {
274 return !(lhs == rhs);
275}
276
277inline bool operator==(const String& lhs, std::string_view rhs) noexcept {
278 return (static_cast<std::string_view>(lhs) == rhs);
279}
280
281inline bool operator!=(const String& lhs, std::string_view rhs) noexcept {
282 return (static_cast<std::string_view>(lhs) != rhs);
283}
284
285inline bool operator==(std::string_view lhs, const String& rhs) noexcept {
286 return (lhs == static_cast<std::string_view>(rhs));
287}
288
289inline bool operator!=(std::string_view lhs, const String& rhs) noexcept {
290 return (lhs != static_cast<std::string_view>(rhs));
291}
292
293std::ostream& operator<<(std::ostream& os, const String& str);
294
295template <>
296struct TypeConverter<std::string_view> {
297 using ValueType = std::string_view;
299
300 static void fromNative(const NativeType& src, std::string_view& dst) {
301 dst = static_cast<std::string_view>(src);
302 }
303
304 static void toNative(std::string_view src, NativeType& dst) {
305 dst = String(src);
306 }
307};
308
309template <>
310struct TypeConverter<std::string> {
311 using ValueType = std::string;
313
314 static void fromNative(const NativeType& src, ValueType& dst) {
315 dst = std::string(src);
316 }
317
318 static void toNative(const ValueType& src, NativeType& dst) {
319 dst = String(src);
320 }
321};
322
323template <>
324struct TypeConverter<const char*> {
325 using ValueType = const char*;
327
328 static void toNative(const char* src, NativeType& dst) {
329 dst = String(src);
330 }
331};
332
333template <size_t N>
334struct TypeConverter<char[N]> { // NOLINT
335 using ValueType = char[N]; // NOLINT
337
338 static void toNative(const ValueType& src, NativeType& dst) {
339 dst = String({static_cast<const char*>(src), N});
340 }
341};
342
343/* ------------------------------------------ DateTime ------------------------------------------ */
344
345/**
346 * UA_DateTime wrapper class.
347 *
348 * An instance in time. A DateTime value is encoded as a 64-bit signed integer which represents the
349 * number of 100 nanosecond intervals since January 1, 1601 (UTC).
350 *
351 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.2.2.5
352 * @ingroup Wrapper
353 */
354class DateTime : public TypeWrapper<UA_DateTime, UA_TYPES_DATETIME> {
355public:
356 using DefaultClock = std::chrono::system_clock;
357 using UaDuration = std::chrono::duration<int64_t, std::ratio<1, 10'000'000>>;
358
359 using TypeWrapper::TypeWrapper; // inherit constructors
360
361 template <typename Clock, typename Duration>
362 DateTime(std::chrono::time_point<Clock, Duration> timePoint) // NOLINT(*-explicit-conversions)
363 : DateTime(fromTimePoint(timePoint)) {}
364
365 /// Get current DateTime.
366 static DateTime now() noexcept {
367 return DateTime(UA_DateTime_now()); // NOLINT
368 }
369
370 /// Get DateTime from std::chrono::time_point.
371 template <typename Clock, typename Duration>
372 static DateTime fromTimePoint(std::chrono::time_point<Clock, Duration> timePoint) {
373 return DateTime(
374 int64_t{UA_DATETIME_UNIX_EPOCH} +
375 std::chrono::duration_cast<UaDuration>(timePoint.time_since_epoch()).count()
376 );
377 }
378
379 /// Get DateTime from Unix time.
380 static DateTime fromUnixTime(int64_t unixTime) noexcept {
381 return DateTime(UA_DateTime_fromUnixTime(unixTime)); // NOLINT
382 }
383
384 /// Offset of local time to UTC.
385 static int64_t localTimeUtcOffset() noexcept {
387 }
388
389 /// Convert to std::chrono::time_point.
390 template <typename Clock = DefaultClock, typename Duration = UaDuration>
391 std::chrono::time_point<Clock, Duration> toTimePoint() const {
392 const std::chrono::time_point<Clock, Duration> unixEpoch{};
393 if (get() < UA_DATETIME_UNIX_EPOCH) {
394 return unixEpoch;
395 }
396 const auto sinceEpoch = UaDuration(get() - UA_DATETIME_UNIX_EPOCH);
397 return unixEpoch + std::chrono::duration_cast<Duration>(sinceEpoch);
398 }
399
400 /// Convert to Unix time (number of seconds since January 1, 1970 UTC).
401 int64_t toUnixTime() const noexcept {
402 if (get() < UA_DATETIME_UNIX_EPOCH) {
403 return 0;
404 }
405 return UA_DateTime_toUnixTime(get());
406 }
407
408 /// Convert to UA_DateTimeStruct.
409 UA_DateTimeStruct toStruct() const noexcept {
410 return UA_DateTime_toStruct(get());
411 }
412
413 /// Get DateTime value as 100 nanosecond intervals since January 1, 1601 (UTC).
414 int64_t get() const noexcept {
415 return *handle();
416 }
417
418 /// Convert to string with given format (same format codes as strftime).
419 /// @see https://en.cppreference.com/w/cpp/chrono/c/strftime
420 std::string format(std::string_view format, bool localtime = false) const;
421};
422
423template <typename Clock, typename Duration>
424struct TypeConverter<std::chrono::time_point<Clock, Duration>> {
425 using ValueType = std::chrono::time_point<Clock, Duration>;
427
428 static void fromNative(const NativeType& src, ValueType& dst) {
429 dst = src.toTimePoint<Clock, Duration>();
430 }
431
432 static void toNative(const ValueType& src, NativeType& dst) {
433 dst = DateTime::fromTimePoint(src);
434 }
435};
436
437/* -------------------------------------------- Guid -------------------------------------------- */
438
439/**
440 * UA_Guid wrapper class.
441 * @ingroup Wrapper
442 */
443class Guid : public TypeWrapper<UA_Guid, UA_TYPES_GUID> {
444public:
445 using TypeWrapper::TypeWrapper; // inherit constructors
446
447 explicit Guid(std::array<uint8_t, 16> data) noexcept
448 : Guid(UA_Guid{
449 // NOLINTBEGIN(hicpp-signed-bitwise)
450 static_cast<uint32_t>(
451 (data[0] << 24U) | (data[1] << 16U) | (data[2] << 8U) | data[3]
452 ),
453 static_cast<uint16_t>((data[4] << 8U) | data[5]),
454 static_cast<uint16_t>((data[6] << 8U) | data[7]),
455 // NOLINTEND(hicpp-signed-bitwise)
456 {data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]},
457 }) {}
458
459 Guid(uint32_t data1, uint16_t data2, uint16_t data3, std::array<uint8_t, 8> data4) noexcept
460 : Guid(UA_Guid{
461 data1,
462 data2,
463 data3,
464 {data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], data4[7]},
465 }) {}
466
467 static Guid random() noexcept {
468 return Guid(UA_Guid_random()); // NOLINT
469 }
470
471 std::string toString() const;
472};
473
474inline bool operator==(const UA_Guid& lhs, const UA_Guid& rhs) noexcept {
475 return UA_Guid_equal(&lhs, &rhs);
476}
477
478inline bool operator!=(const UA_Guid& lhs, const UA_Guid& rhs) noexcept {
479 return !(lhs == rhs);
480}
481
482std::ostream& operator<<(std::ostream& os, const Guid& guid);
483
484/* ----------------------------------------- ByteString ----------------------------------------- */
485
486/**
487 * UA_ByteString wrapper class.
488 * @ingroup Wrapper
489 */
490class ByteString : public detail::StringWrapper<UA_ByteString, UA_TYPES_BYTESTRING, uint8_t> {
491public:
492 using StringWrapper::StringWrapper; // inherit constructors
493
494 explicit ByteString(std::string_view str)
495 : StringWrapper(detail::allocNativeString(str)) {}
496
497 explicit ByteString(const char* str) // required to avoid ambiguity
498 : ByteString(std::string_view(str)) {}
499
501 : StringWrapper(bytes.begin(), bytes.end()) {}
502
503 /// Parse ByteString from Base64 encoded string.
504 /// @note Supported since open62541 v1.1
505 static ByteString fromBase64(std::string_view encoded);
506
507 /// Explicit conversion to std::string_view.
508 explicit operator std::string_view() const noexcept {
509 return {reinterpret_cast<const char*>(data()), size()}; // NOLINT
510 }
511
512 /// Convert to Base64 encoded string.
513 /// @note Supported since open62541 v1.1
514 std::string toBase64() const;
515
516 [[deprecated("use conversion function with static_cast instead")]]
517 std::string_view get() const noexcept {
518 return {reinterpret_cast<const char*>(data()), size()}; // NOLINT
519 }
520};
521
522inline bool operator==(const ByteString& lhs, std::string_view rhs) noexcept {
523 return (static_cast<std::string_view>(lhs) == rhs);
524}
525
526inline bool operator!=(const ByteString& lhs, std::string_view rhs) noexcept {
527 return (static_cast<std::string_view>(lhs) != rhs);
528}
529
530inline bool operator==(std::string_view lhs, const ByteString& rhs) noexcept {
531 return (lhs == static_cast<std::string_view>(rhs));
532}
533
534inline bool operator!=(std::string_view lhs, const ByteString& rhs) noexcept {
535 return (lhs != static_cast<std::string_view>(rhs));
536}
537
538/* ----------------------------------------- XmlElement ----------------------------------------- */
539
540/**
541 * UA_XmlElement wrapper class.
542 * @ingroup Wrapper
543 */
544class XmlElement : public detail::StringWrapper<UA_XmlElement, UA_TYPES_XMLELEMENT, char> {
545public:
546 using StringWrapper::StringWrapper; // inherit constructors
547
548 explicit XmlElement(std::string_view str)
549 : StringWrapper(detail::allocNativeString(str)) {}
550
551 /// Implicit conversion to std::string_view.
552 operator std::string_view() const noexcept { // NOLINT(hicpp-explicit-conversions)
553 return {data(), size()};
554 }
555
556 [[deprecated("use conversion function with static_cast instead")]]
557 std::string_view get() const noexcept {
558 return {data(), size()};
559 }
560};
561
562std::ostream& operator<<(std::ostream& os, const XmlElement& xmlElement);
563
564/* ------------------------------------------- NodeId ------------------------------------------- */
565
566namespace detail {
567template <typename T, typename = void>
568struct IsNodeIdEnum : std::false_type {};
569
570template <typename T>
571struct IsNodeIdEnum<T, std::void_t<decltype(getNamespace(std::declval<T>()))>> : std::true_type {};
572} // namespace detail
573
574/**
575 * NodeId types.
576 * @see UA_NodeIdType
577 */
584
585/**
586 * UA_NodeId wrapper class.
587 * @see https://reference.opcfoundation.org/Core/Part3/v105/docs/8.2
588 * @ingroup Wrapper
589 */
590class NodeId : public TypeWrapper<UA_NodeId, UA_TYPES_NODEID> {
591public:
592 using TypeWrapper::TypeWrapper; // inherit constructors
593
594 /// Create NodeId with numeric identifier.
595 NodeId(NamespaceIndex namespaceIndex, uint32_t identifier) noexcept {
596 handle()->namespaceIndex = namespaceIndex;
598 handle()->identifier.numeric = identifier; // NOLINT
599 }
600
601 /// Create NodeId with String identifier from standard strings.
602 NodeId(NamespaceIndex namespaceIndex, std::string_view identifier) {
603 handle()->namespaceIndex = namespaceIndex;
605 handle()->identifier.string = detail::allocNativeString(identifier); // NOLINT
606 }
607
608 /// Create NodeId with String identifier from String wrapper class.
609 NodeId(NamespaceIndex namespaceIndex, String identifier) noexcept {
610 handle()->namespaceIndex = namespaceIndex;
612 handle()->identifier.string = std::exchange(asNative(identifier), {}); // NOLINT
613 }
614
615 /// Create NodeId with Guid identifier.
616 NodeId(NamespaceIndex namespaceIndex, Guid identifier) noexcept {
617 handle()->namespaceIndex = namespaceIndex;
619 handle()->identifier.guid = identifier; // NOLINT
620 }
621
622 /// Create NodeId with ByteString identifier.
623 NodeId(NamespaceIndex namespaceIndex, ByteString identifier) noexcept {
624 handle()->namespaceIndex = namespaceIndex;
626 handle()->identifier.byteString = std::exchange(asNative(identifier), {}); // NOLINT
627 }
628
629 /// Create NodeId from enum class with numeric identifiers like `opcua::ObjectId`.
630 /// The namespace is retrieved by calling e.g. `getNamespace(opcua::ObjectId)`.
631 /// Make sure to provide an overload for custom enum types.
632 template <typename T, typename = std::enable_if_t<detail::IsNodeIdEnum<T>::value>>
633 NodeId(T identifier) noexcept // NOLINT(hicpp-explicit-conversions)
634 : NodeId(getNamespace(identifier).index, static_cast<uint32_t>(identifier)) {}
635
636 bool isNull() const noexcept {
637 return UA_NodeId_isNull(handle());
638 }
639
640 uint32_t hash() const noexcept {
641 return UA_NodeId_hash(handle());
642 }
643
645 return handle()->namespaceIndex;
646 }
647
648 NodeIdType getIdentifierType() const noexcept {
649 return static_cast<NodeIdType>(handle()->identifierType);
650 }
651
652 /// Get identifier variant.
653 std::variant<uint32_t, String, Guid, ByteString> getIdentifier() const {
654 switch (handle()->identifierType) {
656 return handle()->identifier.numeric; // NOLINT
658 return String(handle()->identifier.string); // NOLINT
660 return Guid(handle()->identifier.guid); // NOLINT
662 return ByteString(handle()->identifier.byteString); // NOLINT
663 default:
664 return {};
665 }
666 }
667
668 /// Get identifier by template type.
669 template <typename T>
670 auto getIdentifierAs() const {
671 return std::get<T>(getIdentifier());
672 }
673
674 /// Get identifier by NodeIdType enum.
675 template <NodeIdType E>
676 auto getIdentifierAs() const {
677 if constexpr (E == NodeIdType::Numeric) {
679 }
680 if constexpr (E == NodeIdType::String) {
682 }
683 if constexpr (E == NodeIdType::Guid) {
684 return getIdentifierAs<Guid>();
685 }
686 if constexpr (E == NodeIdType::ByteString) {
688 }
689 }
690
691 /// Encode NodeId as a string like `ns=1;s=SomeNode`.
692 /// @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.3.1.10
693 std::string toString() const;
694};
695
696inline bool operator==(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
697 return UA_NodeId_equal(&lhs, &rhs);
698}
699
700inline bool operator!=(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
701 return !(lhs == rhs);
702}
703
704inline bool operator<(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
705 return UA_NodeId_order(&lhs, &rhs) == UA_ORDER_LESS;
706}
707
708inline bool operator>(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
709 return UA_NodeId_order(&lhs, &rhs) == UA_ORDER_MORE;
710}
711
712inline bool operator<=(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
713 return (lhs < rhs) || (lhs == rhs);
714}
715
716inline bool operator>=(const UA_NodeId& lhs, const UA_NodeId& rhs) noexcept {
717 return (lhs > rhs) || (lhs == rhs);
718}
719
720/* --------------------------------------- ExpandedNodeId --------------------------------------- */
721
722/**
723 * UA_ExpandedNodeId wrapper class.
724 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.16
725 * @ingroup Wrapper
726 */
727class ExpandedNodeId : public TypeWrapper<UA_ExpandedNodeId, UA_TYPES_EXPANDEDNODEID> {
728public:
729 using TypeWrapper::TypeWrapper; // inherit constructors
730
731 explicit ExpandedNodeId(NodeId id) noexcept {
732 asWrapper<NodeId>(handle()->nodeId) = std::move(id);
733 }
734
735 ExpandedNodeId(NodeId id, std::string_view namespaceUri, uint32_t serverIndex) {
736 asWrapper<NodeId>(handle()->nodeId) = std::move(id);
738 handle()->serverIndex = serverIndex;
739 }
740
741 bool isLocal() const noexcept {
742 return handle()->serverIndex == 0;
743 }
744
745 uint32_t hash() const noexcept {
747 }
748
749 NodeId& getNodeId() noexcept {
750 return asWrapper<NodeId>(handle()->nodeId);
751 }
752
753 const NodeId& getNodeId() const noexcept {
754 return asWrapper<NodeId>(handle()->nodeId);
755 }
756
757 std::string_view getNamespaceUri() const {
758 return detail::toStringView(handle()->namespaceUri);
759 }
760
761 uint32_t getServerIndex() const noexcept {
762 return handle()->serverIndex;
763 }
764
765 /// Encode ExpandedNodeId as a string like `svr=1;nsu=http://test.org/UA/Data/;ns=2;i=10157`.
766 /// @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.3.1.11
767 std::string toString() const;
768};
769
770inline bool operator==(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
771 return UA_ExpandedNodeId_equal(&lhs, &rhs);
772}
773
774inline bool operator!=(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
775 return !(lhs == rhs);
776}
777
778inline bool operator<(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
779 return UA_ExpandedNodeId_order(&lhs, &rhs) == UA_ORDER_LESS;
780}
781
782inline bool operator>(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
783 return UA_ExpandedNodeId_order(&lhs, &rhs) == UA_ORDER_MORE;
784}
785
786inline bool operator<=(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
787 return (lhs < rhs) || (lhs == rhs);
788}
789
790inline bool operator>=(const UA_ExpandedNodeId& lhs, const UA_ExpandedNodeId& rhs) noexcept {
791 return (lhs > rhs) || (lhs == rhs);
792}
793
794/* ---------------------------------------- QualifiedName --------------------------------------- */
795
796/**
797 * UA_QualifiedName wrapper class.
798 * @ingroup Wrapper
799 */
800class QualifiedName : public TypeWrapper<UA_QualifiedName, UA_TYPES_QUALIFIEDNAME> {
801public:
802 using TypeWrapper::TypeWrapper; // inherit constructors
803
804 QualifiedName(NamespaceIndex namespaceIndex, std::string_view name) {
805 handle()->namespaceIndex = namespaceIndex;
807 }
808
810 return handle()->namespaceIndex;
811 }
812
813 std::string_view getName() const noexcept {
814 return detail::toStringView(handle()->name);
815 }
816};
817
818inline bool operator==(const UA_QualifiedName& lhs, const UA_QualifiedName& rhs) noexcept {
819 return (lhs.namespaceIndex == rhs.namespaceIndex) && (lhs.name == rhs.name);
820}
821
822inline bool operator!=(const UA_QualifiedName& lhs, const UA_QualifiedName& rhs) noexcept {
823 return !(lhs == rhs);
824}
825
826/* ---------------------------------------- LocalizedText --------------------------------------- */
827
828/**
829 * UA_LocalizedText wrapper class.
830 * The format of locale is `<language>[-<country/region>]`:
831 * - `<language>` is the two letter ISO 639 code for a language
832 * - `<country/region>` is the two letter ISO 3166 code for the country/region
833 * @see https://reference.opcfoundation.org/Core/Part3/v105/docs/8.5/
834 * @see https://reference.opcfoundation.org/Core/Part3/v105/docs/8.4/
835 * @ingroup Wrapper
836 */
837class LocalizedText : public TypeWrapper<UA_LocalizedText, UA_TYPES_LOCALIZEDTEXT> {
838public:
839 using TypeWrapper::TypeWrapper; // inherit constructors
840
841 LocalizedText(std::string_view locale, std::string_view text) {
844 }
845
846 std::string_view getLocale() const noexcept {
847 return detail::toStringView(handle()->locale);
848 }
849
850 std::string_view getText() const noexcept {
851 return detail::toStringView(handle()->text);
852 }
853};
854
855inline bool operator==(const UA_LocalizedText& lhs, const UA_LocalizedText& rhs) noexcept {
856 return (lhs.locale == rhs.locale) && (lhs.text == rhs.text);
857}
858
859inline bool operator!=(const UA_LocalizedText& lhs, const UA_LocalizedText& rhs) noexcept {
860 return !(lhs == rhs);
861}
862
863/* ------------------------------------------- Variant ------------------------------------------ */
864
865/**
866 * Policies for variant factory methods Variant::fromScalar, Variant::fromArray.
867 */
868enum class VariantPolicy {
869 // clang-format off
870 Copy, ///< Store copy of scalar/array inside the variant.
871 Reference, ///< Store reference to scalar/array inside the variant.
872 ///< Both scalars and arrays must be mutable native/wrapper types.
873 ///< Arrays must store the elements contiguously in memory.
874 ReferenceIfPossible, ///< Favor referencing but fall back to copying if necessary.
875 // clang-format on
876};
877
878namespace detail {
879template <VariantPolicy>
881} // namespace detail
882
883/**
884 * UA_Variant wrapper class.
885 * @ingroup Wrapper
886 */
887class Variant : public TypeWrapper<UA_Variant, UA_TYPES_VARIANT> {
888public:
889 using TypeWrapper::TypeWrapper; // inherit constructors
890
891 /// Create Variant from scalar value.
892 /// @tparam Policy Policy (@ref VariantPolicy) how to store the scalar inside the variant
893 template <VariantPolicy Policy = VariantPolicy::Copy, typename T>
894 [[nodiscard]] static Variant fromScalar(T&& value) {
895 Variant var;
896 detail::VariantHandler<Policy>::setScalar(var, std::forward<T>(value));
897 return var;
898 }
899
900 /// Create Variant from scalar value with custom data type.
901 /// @tparam Policy Policy (@ref VariantPolicy) how to store the scalar inside the variant
902 template <VariantPolicy Policy = VariantPolicy::Copy, typename T>
903 [[nodiscard]] static Variant fromScalar(T&& value, const UA_DataType& dataType) {
904 Variant var;
905 detail::VariantHandler<Policy>::setScalar(var, std::forward<T>(value), dataType);
906 return var;
907 }
908
909 /// Create Variant from array.
910 /// @tparam Policy Policy (@ref VariantPolicy) how to store the array inside the variant
911 template <VariantPolicy Policy = VariantPolicy::Copy, typename ArrayLike>
912 [[nodiscard]] static Variant fromArray(ArrayLike&& array) {
913 using Handler = detail::VariantHandler<Policy>;
914 Variant var;
916 Handler::setArray(var, Span{std::forward<ArrayLike>(array)});
917 } else {
918 Handler::setArray(var, array.begin(), array.end());
919 }
920 return var;
921 }
922
923 /// Create Variant from array with custom data type.
924 /// @tparam Policy Policy (@ref VariantPolicy) how to store the array inside the variant
925 template <VariantPolicy Policy = VariantPolicy::Copy, typename ArrayLike>
926 [[nodiscard]] static Variant fromArray(ArrayLike&& array, const UA_DataType& dataType) {
927 using Handler = detail::VariantHandler<Policy>;
928 Variant var;
930 Handler::setArray(var, Span{std::forward<ArrayLike>(array)}, dataType);
931 } else {
932 Handler::setArray(var, array.begin(), array.end(), dataType);
933 }
934 return var;
935 }
936
937 /// Create Variant from range of elements (copy required).
938 /// @tparam Policy Policy (@ref VariantPolicy) how to store the array inside the variant
939 template <VariantPolicy Policy = VariantPolicy::Copy, typename InputIt>
940 [[nodiscard]] static Variant fromArray(InputIt first, InputIt last) {
941 Variant var;
943 return var;
944 }
945
946 /// Create Variant from range of elements with custom data type (copy required).
947 /// @tparam Policy Policy (@ref VariantPolicy) how to store the array inside the variant
948 template <VariantPolicy Policy = VariantPolicy::Copy, typename InputIt>
949 [[nodiscard]] static Variant fromArray(
950 InputIt first, InputIt last, const UA_DataType& dataType
951 ) {
952 Variant var;
953 detail::VariantHandler<Policy>::setArray(var, first, last, dataType);
954 return var;
955 }
956
957 /// Check if the variant is empty.
958 bool isEmpty() const noexcept {
959 return handle()->type == nullptr;
960 }
961
962 /// Check if the variant is a scalar.
963 bool isScalar() const noexcept {
964 return (
965 !isEmpty() && handle()->arrayLength == 0 &&
966 handle()->data > UA_EMPTY_ARRAY_SENTINEL // NOLINT
967 );
968 }
969
970 /// Check if the variant is an array.
971 bool isArray() const noexcept {
972 return !isEmpty() && !isScalar();
973 }
974
975 /// Check if the variant type is equal to the provided data type.
976 bool isType(const UA_DataType* dataType) const noexcept {
977 return (
978 handle()->type != nullptr && dataType != nullptr &&
979 handle()->type->typeId == dataType->typeId
980 );
981 }
982
983 /// Check if the variant type is equal to the provided data type.
984 bool isType(const UA_DataType& dataType) const noexcept {
985 return isType(&dataType);
986 }
987
988 /// Check if the variant type is equal to the provided data type node id.
989 bool isType(const NodeId& id) const noexcept {
990 return (handle()->type != nullptr) && (handle()->type->typeId == id);
991 }
992
993 /// Check if the variant type is equal to the provided template type.
994 template <typename T>
995 bool isType() const noexcept {
997 }
998
999 /// Get data type.
1000 const UA_DataType* getDataType() const noexcept {
1001 return handle()->type;
1002 }
1003
1004 /// Get pointer to the underlying data.
1005 /// Check the properties and data type before casting it to the actual type.
1006 /// Use the methods @ref isScalar, @ref isArray, @ref isType / @ref getDataType.
1007 void* data() noexcept {
1008 return handle()->data;
1009 }
1010
1011 /// @copydoc data
1012 const void* data() const noexcept {
1013 return handle()->data;
1014 }
1015
1016 /// Get reference to scalar value with given template type (only native or wrapper types).
1017 /// @exception BadVariantAccess If the variant is not a scalar or not of type `T`.
1018 template <typename T>
1019 T& getScalar() & {
1020 assertIsNative<T>();
1021 checkIsScalar();
1022 checkIsDataType<T>();
1023 return *static_cast<T*>(handle()->data);
1024 }
1025
1026 /// @copydoc getScalar()&
1027 template <typename T>
1028 const T& getScalar() const& {
1029 assertIsNative<T>();
1030 checkIsScalar();
1031 checkIsDataType<T>();
1032 return *static_cast<const T*>(handle()->data);
1033 }
1034
1035 /// @copydoc getScalar()&
1036 template <typename T>
1037 T&& getScalar() && {
1038 return std::move(getScalar<T>());
1039 }
1040
1041 /// @copydoc getScalar()&
1042 template <typename T>
1043 const T&& getScalar() const&& {
1044 return std::move(getScalar<T>());
1045 }
1046
1047 /// Get copy of scalar value with given template type.
1048 /// @exception BadVariantAccess If the variant is not a scalar or not convertible to `T`.
1049 template <typename T>
1050 T getScalarCopy() const {
1051 assertIsCopyableOrConvertible<T>();
1052 return getScalarCopyImpl<T>();
1053 }
1054
1055 /// Get array length or 0 if variant is not an array.
1056 size_t getArrayLength() const noexcept {
1057 return handle()->arrayLength;
1058 }
1059
1060 /// Get array dimensions.
1064
1065 /// Get array with given template type (only native or wrapper types).
1066 /// @exception BadVariantAccess If the variant is not an array or not of type `T`.
1067 template <typename T>
1069 assertIsNative<T>();
1070 checkIsArray();
1071 checkIsDataType<T>();
1072 return Span<T>(static_cast<T*>(handle()->data), handle()->arrayLength);
1073 }
1074
1075 /// Get array with given template type (only native or wrapper types).
1076 /// @exception BadVariantAccess If the variant is not an array or not of type `T`.
1077 template <typename T>
1079 assertIsNative<T>();
1080 checkIsArray();
1081 checkIsDataType<T>();
1082 return Span<const T>(static_cast<const T*>(handle()->data), handle()->arrayLength);
1083 }
1084
1085 /// Get copy of array with given template type and return it as a std::vector.
1086 /// @exception BadVariantAccess If the variant is not an array or not convertible to `T`.
1087 template <typename T>
1088 std::vector<T> getArrayCopy() const {
1089 assertIsCopyableOrConvertible<T>();
1090 return getArrayCopyImpl<T>();
1091 }
1092
1093 /// Assign scalar value to variant (no copy).
1094 template <typename T>
1095 void setScalar(T& value) noexcept {
1096 assertIsNative<T>();
1098 }
1099
1100 /// Assign scalar value to variant with custom data type (no copy).
1101 template <typename T>
1102 void setScalar(T& value, const UA_DataType& dataType) noexcept {
1103 setScalarImpl(&value, dataType, UA_VARIANT_DATA_NODELETE);
1104 }
1105
1106 /// Copy scalar value to variant.
1107 template <typename T>
1108 void setScalarCopy(const T& value) {
1109 assertIsCopyableOrConvertible<T>();
1110 if constexpr (detail::isRegisteredType<T>) {
1111 setScalarCopyImpl(value, opcua::getDataType<T>());
1112 } else {
1113 setScalarCopyConvertImpl(value);
1114 }
1115 }
1116
1117 /// Copy scalar value to variant with custom data type.
1118 template <typename T>
1119 void setScalarCopy(const T& value, const UA_DataType& dataType) {
1120 setScalarCopyImpl(value, dataType);
1121 }
1122
1123 /**
1124 * Assign array to variant (no copy).
1125 * @param array Container with a contiguous sequence of elements.
1126 * For example `std::array`, `std::vector` or `Span`.
1127 * The underlying array must be accessible with `std::data` and `std::size`.
1128 */
1129 template <typename ArrayLike>
1130 void setArray(ArrayLike&& array) noexcept {
1131 using ValueType = typename std::remove_reference_t<ArrayLike>::value_type;
1132 assertIsNative<ValueType>();
1133 setArray(std::forward<ArrayLike>(array), opcua::getDataType<ValueType>());
1134 }
1135
1136 /**
1137 * Assign array to variant with custom data type (no copy).
1138 * @copydetails setArray
1139 * @param dataType Custom data type.
1140 */
1141 template <typename ArrayLike>
1142 void setArray(ArrayLike&& array, const UA_DataType& dataType) noexcept {
1143 static_assert(!isTemporaryArray<decltype(array)>());
1144 setArrayImpl(
1145 std::data(std::forward<ArrayLike>(array)),
1146 std::size(std::forward<ArrayLike>(array)),
1147 dataType,
1149 );
1150 }
1151
1152 /**
1153 * Copy array to variant.
1154 * @param array Iterable container, for example `std::vector`, `std::list` or `Span`.
1155 * The container must implement `begin()` and `end()`.
1156 */
1157 template <typename ArrayLike>
1158 void setArrayCopy(const ArrayLike& array) {
1159 setArrayCopy(array.begin(), array.end());
1160 }
1161
1162 /**
1163 * Copy array to variant with custom data type.
1164 * @copydetails setArrayCopy
1165 * @param dataType Custom data type.
1166 */
1167 template <typename ArrayLike>
1168 void setArrayCopy(const ArrayLike& array, const UA_DataType& dataType) {
1169 setArrayCopy(array.begin(), array.end(), dataType);
1170 }
1171
1172 /**
1173 * Copy range of elements as array to variant.
1174 */
1175 template <typename InputIt>
1176 void setArrayCopy(InputIt first, InputIt last) {
1177 using ValueType = typename std::iterator_traits<InputIt>::value_type;
1178 assertIsCopyableOrConvertible<ValueType>();
1180 setArrayCopyImpl(first, last, opcua::getDataType<ValueType>());
1181 } else {
1182 setArrayCopyConvertImpl(first, last);
1183 }
1184 }
1185
1186 /**
1187 * Copy range of elements as array to variant with custom data type.
1188 */
1189 template <typename InputIt>
1190 void setArrayCopy(InputIt first, InputIt last, const UA_DataType& dataType) {
1191 setArrayCopyImpl(first, last, dataType);
1192 }
1193
1194private:
1195 template <typename ArrayLike>
1196 static constexpr bool isTemporaryArray() {
1197 constexpr bool isTemporary = std::is_rvalue_reference_v<ArrayLike>;
1198 constexpr bool isView = detail::IsSpan<std::remove_reference_t<ArrayLike>>::value;
1199 return isTemporary && !isView;
1200 }
1201
1202 template <typename T>
1203 static constexpr void assertIsNative() {
1204 static_assert(
1206 "Template type must be a native/wrapper type to assign or get scalar/array without copy"
1207 );
1208 }
1209
1210 template <typename T>
1211 static constexpr void assertIsCopyableOrConvertible() {
1212 static_assert(
1214 "Template type must be either a native/wrapper type (copyable) or a convertible type. "
1215 "If the type is a native type: Provide the data type (UA_DataType) manually "
1216 "or register the type with a TypeRegistry template specialization. "
1217 "If the type should be converted: Add a template specialization for TypeConverter."
1218 );
1219 }
1220
1221 template <typename T>
1222 static constexpr void assertNoVariant() {
1223 static_assert(
1224 !std::is_same_v<T, Variant> && !std::is_same_v<T, UA_Variant>,
1225 "Variants cannot directly contain another variant"
1226 );
1227 }
1228
1229 void checkIsScalar() const {
1230 if (!isScalar()) {
1231 throw BadVariantAccess("Variant is not a scalar");
1232 }
1233 }
1234
1235 void checkIsArray() const {
1236 if (!isArray()) {
1237 throw BadVariantAccess("Variant is not an array");
1238 }
1239 }
1240
1241 template <typename T>
1242 void checkIsDataType() const {
1243 const auto* dt = getDataType();
1244 if (dt == nullptr || dt->typeId != opcua::getDataType<T>().typeId) {
1245 throw BadVariantAccess("Variant does not contain a value convertible to template type");
1246 }
1247 }
1248
1249 template <typename T>
1250 inline T getScalarCopyImpl() const;
1251 template <typename T>
1252 inline std::vector<T> getArrayCopyImpl() const;
1253
1254 template <typename T>
1255 inline void setScalarImpl(
1256 T* data, const UA_DataType& dataType, UA_VariantStorageType storageType
1257 ) noexcept;
1258 template <typename T>
1259 inline void setArrayImpl(
1260 T* data, size_t arrayLength, const UA_DataType& dataType, UA_VariantStorageType storageType
1261 ) noexcept;
1262 template <typename T>
1263 inline void setScalarCopyImpl(const T& value, const UA_DataType& dataType);
1264 template <typename T>
1265 inline void setScalarCopyConvertImpl(const T& value);
1266 template <typename InputIt>
1267 inline void setArrayCopyImpl(InputIt first, InputIt last, const UA_DataType& dataType);
1268 template <typename InputIt>
1269 inline void setArrayCopyConvertImpl(InputIt first, InputIt last);
1270};
1271
1272template <typename T>
1273T Variant::getScalarCopyImpl() const {
1274 if constexpr (detail::isRegisteredType<T>) {
1276 } else {
1277 using Native = typename TypeConverter<T>::NativeType;
1278 T result{};
1279 TypeConverter<T>::fromNative(getScalar<Native>(), result);
1280 return result;
1281 }
1282}
1283
1284template <typename T>
1285std::vector<T> Variant::getArrayCopyImpl() const {
1286 std::vector<T> result(handle()->arrayLength);
1287 if constexpr (detail::isRegisteredType<T>) {
1288 auto native = getArray<T>();
1289 std::transform(native.begin(), native.end(), result.begin(), [](auto&& value) {
1290 return detail::copy(value, opcua::getDataType<T>());
1291 });
1292 } else {
1293 using Native = typename TypeConverter<T>::NativeType;
1294 auto native = getArray<Native>();
1295 for (size_t i = 0; i < native.size(); ++i) {
1296 TypeConverter<T>::fromNative(native[i], result[i]);
1297 }
1298 }
1299 return result;
1300}
1301
1302template <typename T>
1303void Variant::setScalarImpl(
1304 T* data, const UA_DataType& dataType, UA_VariantStorageType storageType
1305) noexcept {
1306 assertNoVariant<T>();
1307 assert(sizeof(T) == dataType.memSize);
1308 clear();
1309 handle()->type = &dataType;
1310 handle()->storageType = storageType;
1311 handle()->data = data;
1312}
1313
1314template <typename T>
1315void Variant::setArrayImpl(
1316 T* data, size_t arrayLength, const UA_DataType& dataType, UA_VariantStorageType storageType
1317) noexcept {
1318 assertNoVariant<T>();
1319 assert(sizeof(T) == dataType.memSize);
1320 clear();
1321 handle()->type = &dataType;
1322 handle()->storageType = storageType;
1323 handle()->data = data;
1324 handle()->arrayLength = arrayLength;
1325}
1326
1327template <typename T>
1328void Variant::setScalarCopyImpl(const T& value, const UA_DataType& dataType) {
1329 auto native = detail::allocateUniquePtr<T>(dataType);
1330 *native = detail::copy(value, dataType);
1331 setScalarImpl(native.release(), dataType, UA_VARIANT_DATA); // move ownership
1332}
1333
1334template <typename T>
1335void Variant::setScalarCopyConvertImpl(const T& value) {
1336 using Native = typename TypeConverter<T>::NativeType;
1337 const auto& dataType = opcua::getDataType<Native>();
1339 TypeConverter<T>::toNative(value, *native);
1340 setScalarImpl(native.release(), dataType, UA_VARIANT_DATA); // move ownership
1341}
1342
1343template <typename InputIt>
1344void Variant::setArrayCopyImpl(InputIt first, InputIt last, const UA_DataType& dataType) {
1345 using ValueType = typename std::iterator_traits<InputIt>::value_type;
1346 const size_t size = std::distance(first, last);
1348 std::transform(first, last, native.get(), [&](const ValueType& value) {
1349 return detail::copy(value, dataType);
1350 });
1351 setArrayImpl(native.release(), size, dataType, UA_VARIANT_DATA); // move ownership
1352}
1353
1354template <typename InputIt>
1355void Variant::setArrayCopyConvertImpl(InputIt first, InputIt last) {
1356 using ValueType = typename std::iterator_traits<InputIt>::value_type;
1357 using Native = typename TypeConverter<ValueType>::NativeType;
1358 const auto& dataType = opcua::getDataType<Native>();
1359 const size_t size = std::distance(first, last);
1360 auto native = detail::allocateArrayUniquePtr<Native>(size, dataType);
1361 for (size_t i = 0; i < size; ++i) {
1362 TypeConverter<ValueType>::toNative(*first++, native.get()[i]); // NOLINT
1363 }
1364 setArrayImpl(native.release(), size, dataType, UA_VARIANT_DATA); // move ownership
1365}
1366
1367namespace detail {
1368
1369template <>
1371 template <typename T>
1372 static void setScalar(Variant& var, const T& value) {
1373 var.setScalarCopy(value);
1374 }
1375
1376 template <typename T>
1377 static void setScalar(Variant& var, const T& value, const UA_DataType& dtype) {
1378 var.setScalarCopy(value, dtype);
1379 }
1380
1381 template <typename T>
1382 static void setArray(Variant& var, Span<T> array) {
1383 var.setArrayCopy(array.begin(), array.end());
1384 }
1385
1386 template <typename T>
1387 static void setArray(Variant& var, Span<T> array, const UA_DataType& dtype) {
1388 var.setArrayCopy(array.begin(), array.end(), dtype);
1389 }
1390
1391 template <typename InputIt>
1392 static void setArray(Variant& var, InputIt first, InputIt last) {
1393 var.setArrayCopy(first, last);
1394 }
1395
1396 template <typename InputIt>
1397 static void setArray(Variant& var, InputIt first, InputIt last, const UA_DataType& dtype) {
1398 var.setArrayCopy(first, last, dtype);
1399 }
1400};
1401
1402template <>
1404 template <typename T>
1405 static void setScalar(Variant& var, T& value) noexcept {
1406 var.setScalar(value);
1407 }
1408
1409 template <typename T>
1410 static void setScalar(Variant& var, T& value, const UA_DataType& dtype) noexcept {
1411 var.setScalar(value, dtype);
1412 }
1413
1414 template <typename T>
1415 static void setArray(Variant& var, Span<T> array) noexcept {
1416 var.setArray(array);
1417 }
1418
1419 template <typename T>
1420 static void setArray(Variant& var, Span<T> array, const UA_DataType& dtype) noexcept {
1421 var.setArray(array, dtype);
1422 }
1423};
1424
1425template <>
1427 using VariantHandler<VariantPolicy::Copy>::setScalar;
1428 using VariantHandler<VariantPolicy::Copy>::setArray;
1429
1430 template <typename T>
1431 static void setScalar(Variant& var, T& value) noexcept(detail::isRegisteredType<T>) {
1432 if constexpr (detail::isRegisteredType<T>) {
1433 var.setScalar(value);
1434 } else {
1435 var.setScalarCopy(value);
1436 }
1437 }
1438
1439 template <typename T>
1440 static void setScalar(Variant& var, T& value, const UA_DataType& dtype) noexcept {
1441 var.setScalar(value, dtype);
1442 }
1443
1444 template <typename T>
1445 static void setArray(Variant& var, Span<T> array) noexcept(detail::isRegisteredType<T>) {
1446 if constexpr (detail::isRegisteredType<T>) {
1447 var.setArray(array);
1448 } else {
1449 var.setArrayCopy(array);
1450 }
1451 }
1452
1453 template <typename T>
1454 static void setArray(Variant& var, Span<T> array, const UA_DataType& dtype) noexcept {
1455 var.setArray(array, dtype);
1456 }
1457
1458 template <typename T>
1459 static void setArray(Variant& var, Span<const T> array) {
1460 var.setArrayCopy(array.begin(), array.end());
1461 }
1462
1463 template <typename T>
1464 static void setArray(Variant& var, Span<const T> array, const UA_DataType& dtype) {
1465 var.setArrayCopy(array.begin(), array.end(), dtype);
1466 }
1467};
1468
1469} // namespace detail
1470
1471/* ------------------------------------------ DataValue ----------------------------------------- */
1472
1473/**
1474 * UA_DataValue wrapper class.
1475 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.11
1476 * @ingroup Wrapper
1477 */
1478class DataValue : public TypeWrapper<UA_DataValue, UA_TYPES_DATAVALUE> {
1479public:
1480 using TypeWrapper::TypeWrapper; // inherit constructors
1481
1482 explicit DataValue(Variant value) noexcept {
1483 setValue(std::move(value));
1484 }
1485
1487 Variant value,
1488 std::optional<DateTime> sourceTimestamp, // NOLINT
1489 std::optional<DateTime> serverTimestamp, // NOLINT
1490 std::optional<uint16_t> sourcePicoseconds,
1491 std::optional<uint16_t> serverPicoseconds,
1492 std::optional<StatusCode> status
1493 ) noexcept
1495 UA_Variant{},
1496 sourceTimestamp.value_or(UA_DateTime{}),
1497 serverTimestamp.value_or(UA_DateTime{}),
1498 sourcePicoseconds.value_or(uint16_t{}),
1499 serverPicoseconds.value_or(uint16_t{}),
1500 status.value_or(UA_StatusCode{}),
1501 false,
1502 sourceTimestamp.has_value(),
1503 serverTimestamp.has_value(),
1504 sourcePicoseconds.has_value(),
1505 serverPicoseconds.has_value(),
1506 status.has_value(),
1507 }) {
1508 setValue(std::move(value));
1509 }
1510
1511 /// Create DataValue from scalar value.
1512 /// @see Variant::fromScalar
1513 template <VariantPolicy Policy = VariantPolicy::Copy, typename... Args>
1514 [[nodiscard]] static DataValue fromScalar(Args&&... args) {
1515 return DataValue(Variant::fromScalar<Policy>(std::forward<Args>(args)...));
1516 }
1517
1518 /// Create DataValue from array.
1519 /// @see Variant::fromArray
1520 template <VariantPolicy Policy = VariantPolicy::Copy, typename... Args>
1521 [[nodiscard]] static DataValue fromArray(Args&&... args) {
1522 return DataValue(Variant::fromArray<Policy>(std::forward<Args>(args)...));
1523 }
1524
1525 bool hasValue() const noexcept {
1526 return handle()->hasValue;
1527 }
1528
1529 bool hasSourceTimestamp() const noexcept {
1530 return handle()->hasSourceTimestamp;
1531 }
1532
1533 bool hasServerTimestamp() const noexcept {
1534 return handle()->hasServerTimestamp;
1535 }
1536
1537 bool hasSourcePicoseconds() const noexcept {
1538 return handle()->hasSourcePicoseconds;
1539 }
1540
1541 bool hasServerPicoseconds() const noexcept {
1542 return handle()->hasServerPicoseconds;
1543 }
1544
1545 bool hasStatus() const noexcept {
1546 return handle()->hasStatus;
1547 }
1548
1549 /// Get value.
1550 Variant& getValue() & noexcept {
1551 return asWrapper<Variant>(handle()->value);
1552 }
1553
1554 /// Get value.
1555 const Variant& getValue() const& noexcept {
1556 return asWrapper<Variant>(handle()->value);
1557 }
1558
1559 /// Get value (rvalue).
1560 Variant&& getValue() && noexcept {
1561 return std::move(asWrapper<Variant>(handle()->value));
1562 }
1563
1564 /// Get value (rvalue).
1565 const Variant&& getValue() const&& noexcept {
1566 return std::move(asWrapper<Variant>(handle()->value)); // NOLINT
1567 }
1568
1569 /// Get source timestamp for the value.
1570 DateTime getSourceTimestamp() const noexcept {
1571 return DateTime(handle()->sourceTimestamp); // NOLINT
1572 }
1573
1574 /// Get server timestamp for the value.
1575 DateTime getServerTimestamp() const noexcept {
1576 return DateTime(handle()->serverTimestamp); // NOLINT
1577 }
1578
1579 /// Get picoseconds interval added to the source timestamp.
1580 uint16_t getSourcePicoseconds() const noexcept {
1581 return handle()->sourcePicoseconds;
1582 }
1583
1584 /// Get picoseconds interval added to the server timestamp.
1585 uint16_t getServerPicoseconds() const noexcept {
1586 return handle()->serverPicoseconds;
1587 }
1588
1589 /// Get status.
1590 StatusCode getStatus() const noexcept {
1591 return handle()->status;
1592 }
1593
1594 /// Set value (copy).
1595 void setValue(const Variant& value) {
1596 asWrapper<Variant>(handle()->value) = value;
1597 handle()->hasValue = true;
1598 }
1599
1600 /// Set value (move).
1601 void setValue(Variant&& value) noexcept {
1602 asWrapper<Variant>(handle()->value) = std::move(value);
1603 handle()->hasValue = true;
1604 }
1605
1606 /// Set source timestamp for the value.
1607 void setSourceTimestamp(DateTime sourceTimestamp) noexcept { // NOLINT
1608 handle()->sourceTimestamp = sourceTimestamp.get();
1609 handle()->hasSourceTimestamp = true;
1610 }
1611
1612 /// Set server timestamp for the value.
1613 void setServerTimestamp(DateTime serverTimestamp) noexcept { // NOLINT
1614 handle()->serverTimestamp = serverTimestamp.get();
1615 handle()->hasServerTimestamp = true;
1616 }
1617
1618 /// Set picoseconds interval added to the source timestamp.
1619 void setSourcePicoseconds(uint16_t sourcePicoseconds) noexcept {
1620 handle()->sourcePicoseconds = sourcePicoseconds;
1621 handle()->hasSourcePicoseconds = true;
1622 }
1623
1624 /// Set picoseconds interval added to the server timestamp.
1625 void setServerPicoseconds(uint16_t serverPicoseconds) noexcept {
1626 handle()->serverPicoseconds = serverPicoseconds;
1627 handle()->hasServerPicoseconds = true;
1628 }
1629
1630 /// Set status.
1631 void setStatus(StatusCode status) noexcept {
1632 handle()->status = status;
1633 handle()->hasStatus = true;
1634 }
1635};
1636
1637/* --------------------------------------- ExtensionObject -------------------------------------- */
1638
1639/**
1640 * Extension object encoding.
1641 * @see UA_ExtensionObjectEncoding
1642 */
1652
1653/**
1654 * UA_ExtensionObject wrapper class.
1655 *
1656 * ExtensionObjects may contain scalars of any data type. Even those that are unknown to the
1657 * receiver. If the received data type is unknown, the encoded string and target NodeId is stored
1658 * instead of the decoded data.
1659 *
1660 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.1.6
1661 * @see https://reference.opcfoundation.org/Core/Part6/v105/docs/5.2.2.15
1662 * @ingroup Wrapper
1663 */
1664class ExtensionObject : public TypeWrapper<UA_ExtensionObject, UA_TYPES_EXTENSIONOBJECT> {
1665public:
1666 using TypeWrapper::TypeWrapper; // inherit constructors
1667
1668 /// Create an ExtensionObject from a decoded object (reference).
1669 /// The data will *not* be deleted when the ExtensionObject is destructed.
1670 /// @param data Decoded data
1671 template <typename T>
1672 [[nodiscard]] static ExtensionObject fromDecoded(T& data) noexcept {
1673 return fromDecoded(&data, getDataType<T>());
1674 }
1675
1676 /// Create an ExtensionObject from a decoded object (reference).
1677 /// The data will *not* be deleted when the ExtensionObject is destructed.
1678 /// @param data Decoded data
1679 /// @param type Data type of the decoded data
1680 /// @warning Type erased version, use with caution.
1681 [[nodiscard]] static ExtensionObject fromDecoded(void* data, const UA_DataType& type) noexcept {
1682 ExtensionObject obj;
1684 obj->content.decoded.type = &type; // NOLINT
1685 obj->content.decoded.data = data; // NOLINT
1686 return obj;
1687 }
1688
1689 /// Create an ExtensionObject from a decoded object (copy).
1690 /// Set the "decoded" data to a copy of the given object.
1691 /// @param data Decoded data
1692 template <typename T>
1693 [[nodiscard]] static ExtensionObject fromDecodedCopy(const T& data) {
1694 return fromDecodedCopy(&data, getDataType<T>());
1695 }
1696
1697 /// Create an ExtensionObject from a decoded object (copy).
1698 /// @param data Decoded data
1699 /// @param type Data type of the decoded data
1700 /// @warning Type erased version, use with caution.
1701 [[nodiscard]] static ExtensionObject fromDecodedCopy(
1702 const void* data, const UA_DataType& type
1703 ) {
1704 // manual implementation instead of UA_ExtensionObject_setValueCopy to support open62541
1705 // v1.0 https://github.com/open62541/open62541/blob/v1.3.5/src/ua_types.c#L503-L524
1706 ExtensionObject obj;
1707 obj->encoding = UA_EXTENSIONOBJECT_DECODED;
1708 obj->content.decoded.data = detail::allocate<void>(type); // NOLINT
1709 obj->content.decoded.type = &type; // NOLINT
1710 throwIfBad(UA_copy(data, obj->content.decoded.data, &type)); // NOLINT
1711 return obj;
1712 }
1713
1714 /// Check if the ExtensionObject is empty
1715 bool isEmpty() const noexcept {
1716 return (handle()->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY);
1717 }
1718
1719 /// Check if the ExtensionObject is encoded (usually if the data type is unknown).
1720 bool isEncoded() const noexcept {
1721 return (handle()->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) ||
1723 }
1724
1725 /// Check if the ExtensionObject is decoded.
1726 bool isDecoded() const noexcept {
1727 return (handle()->encoding == UA_EXTENSIONOBJECT_DECODED) ||
1729 }
1730
1731 /// Get the encoding.
1733 return static_cast<ExtensionObjectEncoding>(handle()->encoding);
1734 }
1735
1736 /// Get the encoded type id.
1737 /// Returns `nullptr` if ExtensionObject is not encoded.
1738 const NodeId* getEncodedTypeId() const noexcept {
1739 return isEncoded()
1740 ? asWrapper<NodeId>(&handle()->content.encoded.typeId) // NOLINT
1741 : nullptr;
1742 }
1743
1744 /// Get the encoded body.
1745 /// Returns `nullptr` if ExtensionObject is not encoded.
1746 const ByteString* getEncodedBody() const noexcept {
1747 return isEncoded()
1748 ? asWrapper<ByteString>(&handle()->content.encoded.body) // NOLINT
1749 : nullptr;
1750 }
1751
1752 /// Get the decoded data type.
1753 /// Returns `nullptr` if ExtensionObject is not decoded.
1754 const UA_DataType* getDecodedDataType() const noexcept {
1755 return isDecoded()
1756 ? handle()->content.decoded.type // NOLINT
1757 : nullptr;
1758 }
1759
1760 /// Get pointer to the decoded data with given template type.
1761 /// Returns `nullptr` if the ExtensionObject is either not decoded or the decoded data is not of
1762 /// type `T`.
1763 template <typename T>
1764 T* getDecodedData() noexcept {
1765 return isDecodedDataType<T>() ? static_cast<T*>(getDecodedData()) : nullptr;
1766 }
1767
1768 /// Get const pointer to the decoded data with given template type.
1769 /// Returns `nullptr` if the ExtensionObject is either not decoded or the decoded data is not of
1770 /// type `T`.
1771 template <typename T>
1772 const T* getDecodedData() const noexcept {
1773 return isDecodedDataType<T>() ? static_cast<const T*>(getDecodedData()) : nullptr;
1774 }
1775
1776 /// Get pointer to the decoded data.
1777 /// Returns `nullptr` if the ExtensionObject is not decoded.
1778 /// @warning Type erased version, use with caution.
1779 void* getDecodedData() noexcept {
1780 return isDecoded()
1781 ? handle()->content.decoded.data // NOLINT
1782 : nullptr;
1783 }
1784
1785 /// Get pointer to the decoded data.
1786 /// Returns `nullptr` if the ExtensionObject is not decoded.
1787 /// @warning Type erased version, use with caution.
1788 const void* getDecodedData() const noexcept {
1789 return isDecoded()
1790 ? handle()->content.decoded.data // NOLINT
1791 : nullptr;
1792 }
1793
1794private:
1795 template <typename T>
1796 bool isDecodedDataType() const noexcept {
1797 const auto* type = getDecodedDataType();
1798 return (type != nullptr) && (type->typeId == getDataType<T>().typeId);
1799 }
1800};
1801
1802/* --------------------------------------- DiagnosticInfo --------------------------------------- */
1803
1804/**
1805 * UA_DiagnosticInfo wrapper class.
1806 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.12
1807 * @ingroup Wrapper
1808 */
1809class DiagnosticInfo : public TypeWrapper<UA_DiagnosticInfo, UA_TYPES_DIAGNOSTICINFO> {
1810public:
1811 using TypeWrapper::TypeWrapper; // inherit constructors
1812
1813 bool hasSymbolicId() const noexcept {
1814 return handle()->hasSymbolicId;
1815 }
1816
1817 bool hasNamespaceUri() const noexcept {
1818 return handle()->hasNamespaceUri;
1819 }
1820
1821 bool hasLocalizedText() const noexcept {
1822 return handle()->hasLocalizedText;
1823 }
1824
1825 bool hasLocale() const noexcept {
1826 return handle()->hasLocale;
1827 }
1828
1829 bool hasAdditionalInfo() const noexcept {
1830 return handle()->hasAdditionalInfo;
1831 }
1832
1833 bool hasInnerStatusCode() const noexcept {
1834 return handle()->hasInnerStatusCode;
1835 }
1836
1837 bool hasInnerDiagnosticInfo() const noexcept {
1839 }
1840
1841 int32_t getSymbolicId() const noexcept {
1842 return handle()->symbolicId;
1843 }
1844
1845 int32_t getNamespaceUri() const noexcept {
1846 return handle()->namespaceUri;
1847 }
1848
1849 int32_t getLocalizedText() const noexcept {
1850 return handle()->localizedText;
1851 }
1852
1853 int32_t getLocale() const noexcept {
1854 return handle()->locale;
1855 }
1856
1857 const String& getAdditionalInfo() const noexcept {
1858 return asWrapper<String>(handle()->additionalInfo);
1859 }
1860
1862 return handle()->innerStatusCode;
1863 }
1864
1865 const DiagnosticInfo* getInnerDiagnosticInfo() const noexcept {
1866 return asWrapper<DiagnosticInfo>(handle()->innerDiagnosticInfo);
1867 }
1868};
1869
1870/* ---------------------------------------- NumericRange ---------------------------------------- */
1871
1873
1874inline bool operator==(
1875 const NumericRangeDimension& lhs, const NumericRangeDimension& rhs
1876) noexcept {
1877 return (lhs.min == rhs.min) && (lhs.max == rhs.max);
1878}
1879
1880inline bool operator!=(
1881 const NumericRangeDimension& lhs, const NumericRangeDimension& rhs
1882) noexcept {
1883 return !(lhs == rhs);
1884}
1885
1886/**
1887 * Numeric range to indicate subsets of (multidimensional) arrays.
1888 * They are no official data type in the OPC UA standard and are transmitted only with a string
1889 * encoding, such as "1:2,0:3,5". The colon separates min/max index and the comma separates
1890 * dimensions. A single value indicates a range with a single element (min==max).
1891 * @see https://reference.opcfoundation.org/Core/Part4/v105/docs/7.27
1892 */
1894public:
1895 NumericRange() = default;
1896
1897 explicit NumericRange(std::string_view encodedRange);
1898
1899 explicit NumericRange(const char* encodedRange) // required to avoid ambiguity
1900 : NumericRange(std::string_view(encodedRange)) {}
1901
1903 : dimensions_(dimensions.begin(), dimensions.end()) {}
1904
1905 explicit NumericRange(const UA_NumericRange& native)
1906 : NumericRange({native.dimensions, native.dimensionsSize}) {}
1907
1908 bool empty() const noexcept {
1909 return dimensions_.empty();
1910 }
1911
1913 return dimensions_;
1914 }
1915
1916 std::string toString() const;
1917
1918private:
1919 std::vector<NumericRangeDimension> dimensions_;
1920};
1921
1922} // namespace opcua
1923
1924/* ---------------------------------- std::hash specializations --------------------------------- */
1925
1926template <>
1927struct std::hash<opcua::NodeId> {
1928 std::size_t operator()(const opcua::NodeId& id) const noexcept {
1929 return id.hash();
1930 }
1931};
1932
1933template <>
1934struct std::hash<opcua::ExpandedNodeId> {
1935 std::size_t operator()(const opcua::ExpandedNodeId& id) const noexcept {
1936 return id.hash();
1937 }
1938};
Exception for bad status codes from open62541 UA_STATUSCODE_*.
Definition exception.hpp:15
UA_ByteString wrapper class.
Definition types.hpp:490
std::string_view get() const noexcept
Definition types.hpp:517
std::string toBase64() const
Convert to Base64 encoded string.
operator std::string_view() const noexcept
Explicit conversion to std::string_view.
Definition types.hpp:508
ByteString(std::string_view str)
Definition types.hpp:494
ByteString(Span< const uint8_t > bytes)
Definition types.hpp:500
static ByteString fromBase64(std::string_view encoded)
Parse ByteString from Base64 encoded string.
ByteString(const char *str)
Definition types.hpp:497
UA_DataValue wrapper class.
Definition types.hpp:1478
bool hasServerPicoseconds() const noexcept
Definition types.hpp:1541
void setSourceTimestamp(DateTime sourceTimestamp) noexcept
Set source timestamp for the value.
Definition types.hpp:1607
bool hasValue() const noexcept
Definition types.hpp:1525
DateTime getServerTimestamp() const noexcept
Get server timestamp for the value.
Definition types.hpp:1575
DataValue(Variant value) noexcept
Definition types.hpp:1482
const Variant && getValue() const &&noexcept
Get value (rvalue).
Definition types.hpp:1565
uint16_t getServerPicoseconds() const noexcept
Get picoseconds interval added to the server timestamp.
Definition types.hpp:1585
bool hasSourceTimestamp() const noexcept
Definition types.hpp:1529
void setServerPicoseconds(uint16_t serverPicoseconds) noexcept
Set picoseconds interval added to the server timestamp.
Definition types.hpp:1625
const Variant & getValue() const &noexcept
Get value.
Definition types.hpp:1555
bool hasStatus() const noexcept
Definition types.hpp:1545
static DataValue fromScalar(Args &&... args)
Create DataValue from scalar value.
Definition types.hpp:1514
void setValue(Variant &&value) noexcept
Set value (move).
Definition types.hpp:1601
void setServerTimestamp(DateTime serverTimestamp) noexcept
Set server timestamp for the value.
Definition types.hpp:1613
Variant & getValue() &noexcept
Get value.
Definition types.hpp:1550
static DataValue fromArray(Args &&... args)
Create DataValue from array.
Definition types.hpp:1521
StatusCode getStatus() const noexcept
Get status.
Definition types.hpp:1590
void setStatus(StatusCode status) noexcept
Set status.
Definition types.hpp:1631
void setSourcePicoseconds(uint16_t sourcePicoseconds) noexcept
Set picoseconds interval added to the source timestamp.
Definition types.hpp:1619
bool hasSourcePicoseconds() const noexcept
Definition types.hpp:1537
uint16_t getSourcePicoseconds() const noexcept
Get picoseconds interval added to the source timestamp.
Definition types.hpp:1580
bool hasServerTimestamp() const noexcept
Definition types.hpp:1533
void setValue(const Variant &value)
Set value (copy).
Definition types.hpp:1595
Variant && getValue() &&noexcept
Get value (rvalue).
Definition types.hpp:1560
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:1486
DateTime getSourceTimestamp() const noexcept
Get source timestamp for the value.
Definition types.hpp:1570
UA_DateTime wrapper class.
Definition types.hpp:354
int64_t get() const noexcept
Get DateTime value as 100 nanosecond intervals since January 1, 1601 (UTC).
Definition types.hpp:414
UA_DateTimeStruct toStruct() const noexcept
Convert to UA_DateTimeStruct.
Definition types.hpp:409
static DateTime fromUnixTime(int64_t unixTime) noexcept
Get DateTime from Unix time.
Definition types.hpp:380
static DateTime now() noexcept
Get current DateTime.
Definition types.hpp:366
std::chrono::duration< int64_t, std::ratio< 1, 10 '000 '000 > > UaDuration
Definition types.hpp:357
static DateTime fromTimePoint(std::chrono::time_point< Clock, Duration > timePoint)
Get DateTime from std::chrono::time_point.
Definition types.hpp:372
int64_t toUnixTime() const noexcept
Convert to Unix time (number of seconds since January 1, 1970 UTC).
Definition types.hpp:401
static int64_t localTimeUtcOffset() noexcept
Offset of local time to UTC.
Definition types.hpp:385
DateTime(std::chrono::time_point< Clock, Duration > timePoint)
Definition types.hpp:362
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:391
std::chrono::system_clock DefaultClock
Definition types.hpp:356
UA_DiagnosticInfo wrapper class.
Definition types.hpp:1809
bool hasInnerStatusCode() const noexcept
Definition types.hpp:1833
bool hasLocalizedText() const noexcept
Definition types.hpp:1821
int32_t getSymbolicId() const noexcept
Definition types.hpp:1841
int32_t getNamespaceUri() const noexcept
Definition types.hpp:1845
bool hasSymbolicId() const noexcept
Definition types.hpp:1813
bool hasLocale() const noexcept
Definition types.hpp:1825
bool hasInnerDiagnosticInfo() const noexcept
Definition types.hpp:1837
int32_t getLocalizedText() const noexcept
Definition types.hpp:1849
int32_t getLocale() const noexcept
Definition types.hpp:1853
const String & getAdditionalInfo() const noexcept
Definition types.hpp:1857
const DiagnosticInfo * getInnerDiagnosticInfo() const noexcept
Definition types.hpp:1865
StatusCode getInnerStatusCode() const noexcept
Definition types.hpp:1861
bool hasNamespaceUri() const noexcept
Definition types.hpp:1817
bool hasAdditionalInfo() const noexcept
Definition types.hpp:1829
UA_ExpandedNodeId wrapper class.
Definition types.hpp:727
uint32_t hash() const noexcept
Definition types.hpp:745
ExpandedNodeId(NodeId id) noexcept
Definition types.hpp:731
const NodeId & getNodeId() const noexcept
Definition types.hpp:753
ExpandedNodeId(NodeId id, std::string_view namespaceUri, uint32_t serverIndex)
Definition types.hpp:735
bool isLocal() const noexcept
Definition types.hpp:741
std::string toString() const
Encode ExpandedNodeId as a string like svr=1;nsu=http://test.org/UA/Data/;ns=2;i=10157.
uint32_t getServerIndex() const noexcept
Definition types.hpp:761
NodeId & getNodeId() noexcept
Definition types.hpp:749
std::string_view getNamespaceUri() const
Definition types.hpp:757
UA_ExtensionObject wrapper class.
Definition types.hpp:1664
bool isDecoded() const noexcept
Check if the ExtensionObject is decoded.
Definition types.hpp:1726
static ExtensionObject fromDecoded(void *data, const UA_DataType &type) noexcept
Create an ExtensionObject from a decoded object (reference).
Definition types.hpp:1681
static ExtensionObject fromDecodedCopy(const void *data, const UA_DataType &type)
Create an ExtensionObject from a decoded object (copy).
Definition types.hpp:1701
bool isEmpty() const noexcept
Check if the ExtensionObject is empty.
Definition types.hpp:1715
const UA_DataType * getDecodedDataType() const noexcept
Get the decoded data type.
Definition types.hpp:1754
T * getDecodedData() noexcept
Get pointer to the decoded data with given template type.
Definition types.hpp:1764
const ByteString * getEncodedBody() const noexcept
Get the encoded body.
Definition types.hpp:1746
static ExtensionObject fromDecodedCopy(const T &data)
Create an ExtensionObject from a decoded object (copy).
Definition types.hpp:1693
static ExtensionObject fromDecoded(T &data) noexcept
Create an ExtensionObject from a decoded object (reference).
Definition types.hpp:1672
const T * getDecodedData() const noexcept
Get const pointer to the decoded data with given template type.
Definition types.hpp:1772
const NodeId * getEncodedTypeId() const noexcept
Get the encoded type id.
Definition types.hpp:1738
ExtensionObjectEncoding getEncoding() const noexcept
Get the encoding.
Definition types.hpp:1732
void * getDecodedData() noexcept
Get pointer to the decoded data.
Definition types.hpp:1779
bool isEncoded() const noexcept
Check if the ExtensionObject is encoded (usually if the data type is unknown).
Definition types.hpp:1720
const void * getDecodedData() const noexcept
Get pointer to the decoded data.
Definition types.hpp:1788
UA_Guid wrapper class.
Definition types.hpp:443
Guid(uint32_t data1, uint16_t data2, uint16_t data3, std::array< uint8_t, 8 > data4) noexcept
Definition types.hpp:459
Guid(std::array< uint8_t, 16 > data) noexcept
Definition types.hpp:447
std::string toString() const
static Guid random() noexcept
Definition types.hpp:467
UA_LocalizedText wrapper class.
Definition types.hpp:837
std::string_view getLocale() const noexcept
Definition types.hpp:846
std::string_view getText() const noexcept
Definition types.hpp:850
LocalizedText(std::string_view locale, std::string_view text)
Definition types.hpp:841
UA_NodeId wrapper class.
Definition types.hpp:590
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:633
NodeId(NamespaceIndex namespaceIndex, uint32_t identifier) noexcept
Create NodeId with numeric identifier.
Definition types.hpp:595
NodeId(NamespaceIndex namespaceIndex, ByteString identifier) noexcept
Create NodeId with ByteString identifier.
Definition types.hpp:623
std::variant< uint32_t, String, Guid, ByteString > getIdentifier() const
Get identifier variant.
Definition types.hpp:653
NodeId(NamespaceIndex namespaceIndex, Guid identifier) noexcept
Create NodeId with Guid identifier.
Definition types.hpp:616
auto getIdentifierAs() const
Get identifier by template type.
Definition types.hpp:670
bool isNull() const noexcept
Definition types.hpp:636
NamespaceIndex getNamespaceIndex() const noexcept
Definition types.hpp:644
NodeIdType getIdentifierType() const noexcept
Definition types.hpp:648
NodeId(NamespaceIndex namespaceIndex, String identifier) noexcept
Create NodeId with String identifier from String wrapper class.
Definition types.hpp:609
uint32_t hash() const noexcept
Definition types.hpp:640
NodeId(NamespaceIndex namespaceIndex, std::string_view identifier)
Create NodeId with String identifier from standard strings.
Definition types.hpp:602
Numeric range to indicate subsets of (multidimensional) arrays.
Definition types.hpp:1893
bool empty() const noexcept
Definition types.hpp:1908
NumericRange(std::string_view encodedRange)
NumericRange(const char *encodedRange)
Definition types.hpp:1899
NumericRange(Span< const NumericRangeDimension > dimensions)
Definition types.hpp:1902
Span< const NumericRangeDimension > dimensions() const noexcept
Definition types.hpp:1912
NumericRange()=default
NumericRange(const UA_NumericRange &native)
Definition types.hpp:1905
std::string toString() const
UA_QualifiedName wrapper class.
Definition types.hpp:800
NamespaceIndex getNamespaceIndex() const noexcept
Definition types.hpp:809
QualifiedName(NamespaceIndex namespaceIndex, std::string_view name)
Definition types.hpp:804
std::string_view getName() const noexcept
Definition types.hpp:813
View to a contiguous sequence of objects, similar to std::span in C++20.
Definition span.hpp:26
constexpr iterator begin() const noexcept
Definition span.hpp:128
constexpr iterator end() const noexcept
Definition span.hpp:132
UA_StatusCode wrapper class.
Definition types.hpp:44
constexpr void throwIfBad() const
Throw a BadStatus exception if the status code is bad.
Definition types.hpp:82
constexpr bool isUncertain() const noexcept
Check if the status code is uncertain.
Definition types.hpp:71
constexpr bool isBad() const noexcept
Check if the status code is bad.
Definition types.hpp:76
std::string_view name() const noexcept
Get human-readable name of the StatusCode.
Definition types.hpp:61
constexpr bool isGood() const noexcept
Check if the status code is good.
Definition types.hpp:66
constexpr UA_StatusCode get() const noexcept
Explicitly get underlying UA_StatusCode.
Definition types.hpp:53
constexpr StatusCode() noexcept=default
Create a StatusCode with the default status code UA_STATUSCODE_GOOD.
UA_String wrapper class.
Definition types.hpp:251
std::string_view get() const noexcept
Definition types.hpp:264
String(std::string_view str)
Definition types.hpp:255
Template base class to wrap UA_* type objects.
constexpr TypeWrapper()=default
UA_Variant wrapper class.
Definition types.hpp:887
void setArrayCopy(const ArrayLike &array, const UA_DataType &dataType)
Copy array to variant with custom data type.
Definition types.hpp:1168
bool isType(const UA_DataType *dataType) const noexcept
Check if the variant type is equal to the provided data type.
Definition types.hpp:976
T getScalarCopy() const
Get copy of scalar value with given template type.
Definition types.hpp:1050
Span< T > getArray()
Get array with given template type (only native or wrapper types).
Definition types.hpp:1068
const T && getScalar() const &&
Get reference to scalar value with given template type (only native or wrapper types).
Definition types.hpp:1043
void setArray(ArrayLike &&array) noexcept
Assign array to variant (no copy).
Definition types.hpp:1130
const void * data() const noexcept
Get pointer to the underlying data.
Definition types.hpp:1012
void setArray(ArrayLike &&array, const UA_DataType &dataType) noexcept
Assign array to variant with custom data type (no copy).
Definition types.hpp:1142
void setArrayCopy(const ArrayLike &array)
Copy array to variant.
Definition types.hpp:1158
T && getScalar() &&
Get reference to scalar value with given template type (only native or wrapper types).
Definition types.hpp:1037
const UA_DataType * getDataType() const noexcept
Get data type.
Definition types.hpp:1000
Span< const uint32_t > getArrayDimensions() const noexcept
Get array dimensions.
Definition types.hpp:1061
size_t getArrayLength() const noexcept
Get array length or 0 if variant is not an array.
Definition types.hpp:1056
void setArrayCopy(InputIt first, InputIt last)
Copy range of elements as array to variant.
Definition types.hpp:1176
static Variant fromScalar(T &&value)
Create Variant from scalar value.
Definition types.hpp:894
bool isType(const UA_DataType &dataType) const noexcept
Check if the variant type is equal to the provided data type.
Definition types.hpp:984
std::vector< T > getArrayCopy() const
Get copy of array with given template type and return it as a std::vector.
Definition types.hpp:1088
static Variant fromScalar(T &&value, const UA_DataType &dataType)
Create Variant from scalar value with custom data type.
Definition types.hpp:903
void setScalarCopy(const T &value)
Copy scalar value to variant.
Definition types.hpp:1108
static Variant fromArray(InputIt first, InputIt last, const UA_DataType &dataType)
Create Variant from range of elements with custom data type (copy required).
Definition types.hpp:949
void setScalar(T &value) noexcept
Assign scalar value to variant (no copy).
Definition types.hpp:1095
bool isType(const NodeId &id) const noexcept
Check if the variant type is equal to the provided data type node id.
Definition types.hpp:989
Span< const T > getArray() const
Get array with given template type (only native or wrapper types).
Definition types.hpp:1078
bool isEmpty() const noexcept
Check if the variant is empty.
Definition types.hpp:958
void setScalar(T &value, const UA_DataType &dataType) noexcept
Assign scalar value to variant with custom data type (no copy).
Definition types.hpp:1102
static Variant fromArray(ArrayLike &&array, const UA_DataType &dataType)
Create Variant from array with custom data type.
Definition types.hpp:926
void setScalarCopy(const T &value, const UA_DataType &dataType)
Copy scalar value to variant with custom data type.
Definition types.hpp:1119
static Variant fromArray(InputIt first, InputIt last)
Create Variant from range of elements (copy required).
Definition types.hpp:940
bool isArray() const noexcept
Check if the variant is an array.
Definition types.hpp:971
void setArrayCopy(InputIt first, InputIt last, const UA_DataType &dataType)
Copy range of elements as array to variant with custom data type.
Definition types.hpp:1190
const T & getScalar() const &
Get reference to scalar value with given template type (only native or wrapper types).
Definition types.hpp:1028
T & getScalar() &
Get reference to scalar value with given template type (only native or wrapper types).
Definition types.hpp:1019
bool isScalar() const noexcept
Check if the variant is a scalar.
Definition types.hpp:963
bool isType() const noexcept
Check if the variant type is equal to the provided template type.
Definition types.hpp:995
static Variant fromArray(ArrayLike &&array)
Create Variant from array.
Definition types.hpp:912
void * data() noexcept
Get pointer to the underlying data.
Definition types.hpp:1007
Template base class to wrap native objects.
Definition wrapper.hpp:32
constexpr const UA_StatusCode & native() const noexcept
Definition wrapper.hpp:75
constexpr UA_DateTime * handle() noexcept
Definition wrapper.hpp:65
UA_XmlElement wrapper class.
Definition types.hpp:544
std::string_view get() const noexcept
Definition types.hpp:557
XmlElement(std::string_view str)
Definition types.hpp:548
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition types.hpp:107
const_reference operator[](size_t index) const noexcept
Definition types.hpp:144
StringWrapper(InputIt first, InputIt last, std::input_iterator_tag)
Definition types.hpp:235
reverse_iterator rbegin() noexcept
Definition types.hpp:193
const value_type & const_reference
Definition types.hpp:103
reverse_iterator rend() noexcept
Definition types.hpp:205
reference back() noexcept
Definition types.hpp:159
const_reverse_iterator rbegin() const noexcept
Definition types.hpp:197
pointer data() noexcept
Definition types.hpp:131
size_t length() const noexcept
Definition types.hpp:123
iterator begin() noexcept
Definition types.hpp:169
std::reverse_iterator< iterator > reverse_iterator
Definition types.hpp:106
const_iterator begin() const noexcept
Definition types.hpp:173
StringWrapper(std::initializer_list< CharT > init)
Definition types.hpp:116
const_reverse_iterator crbegin() const noexcept
Definition types.hpp:201
const_reverse_iterator crend() const noexcept
Definition types.hpp:213
const_reference front() const noexcept
Definition types.hpp:154
void init(size_t length)
Definition types.hpp:218
StringWrapper(InputIt first, InputIt last)
Definition types.hpp:113
bool empty() const noexcept
Definition types.hpp:127
iterator end() noexcept
Definition types.hpp:181
size_t size() const noexcept
Definition types.hpp:119
const_iterator cbegin() const noexcept
Definition types.hpp:177
const value_type * const_pointer
Definition types.hpp:101
const_pointer const_iterator
Definition types.hpp:105
reference operator[](size_t index) noexcept
Definition types.hpp:139
const_iterator cend() const noexcept
Definition types.hpp:189
const_reference back() const noexcept
Definition types.hpp:164
const_pointer data() const noexcept
Definition types.hpp:135
const_reverse_iterator rend() const noexcept
Definition types.hpp:209
reference front() noexcept
Definition types.hpp:149
StringWrapper(InputIt first, InputIt last, Tag)
Definition types.hpp:229
std::ptrdiff_t difference_type
Definition types.hpp:99
const_iterator end() const noexcept
Definition types.hpp:185
UA_ORDER_LESS
UA_ORDER_MORE
constexpr Namespace getNamespace(DataTypeId) noexcept
Get namespace of DataTypeId.
Definition nodeids.hpp:447
constexpr NativeType * asNative(WrapperType *wrapper) noexcept
Cast Wrapper object pointers to native object pointers.
Definition wrapper.hpp:191
static UA_LogCategory const char va_list args
UA_String allocNativeString(std::string_view src)
Allocate UA_String from std::string_view.
constexpr T copy(const T &src, const UA_DataType &type) noexcept(isPointerFree< T >)
auto allocateUniquePtr(const UA_DataType &type)
std::string_view toStringView(const UA_String &src) noexcept
Convert UA_String to std::string_view Can be marked noexcept: https://stackoverflow....
constexpr bool isGood(UA_StatusCode code) noexcept
Definition exception.hpp:54
constexpr bool isRegisteredType
constexpr void clear(T &native, const UA_DataType &type) noexcept
constexpr bool isUncertain(UA_StatusCode code) noexcept
Definition exception.hpp:58
T * allocate(const UA_DataType &type)
auto allocateArrayUniquePtr(size_t size, const UA_DataType &type)
constexpr bool isConvertibleType
constexpr bool isBad(UA_StatusCode code) noexcept
Definition exception.hpp:62
NodeIdType
NodeId types.
Definition types.hpp:578
ExtensionObjectEncoding
Extension object encoding.
Definition types.hpp:1643
bool operator>=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:716
VariantPolicy
Policies for variant factory methods Variant::fromScalar, Variant::fromArray.
Definition types.hpp:868
@ ReferenceIfPossible
Favor referencing but fall back to copying if necessary.
@ Copy
Store copy of scalar/array inside the variant.
@ Reference
Store reference to scalar/array inside the variant.
bool operator<=(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:712
std::ostream & operator<<(std::ostream &os, const String &str)
constexpr void throwIfBad(UA_StatusCode code)
Check the status code and throw a BadStatus exception if the status code is bad.
Definition exception.hpp:87
Client * asWrapper(UA_Client *client) noexcept
Convert native UA_Client pointer to its wrapper instance.
Span(Container &) -> Span< typename Container::value_type >
uint16_t NamespaceIndex
Namespace index.
Definition common.hpp:12
bool operator!=(const Client &lhs, const Client &rhs) noexcept
Definition client.hpp:295
@ NodeId
Unambiguous identifier of a node.
const UA_DataType & getDataType() noexcept
bool operator<(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:704
bool operator>(const UA_NodeId &lhs, const UA_NodeId &rhs) noexcept
Definition types.hpp:708
bool operator==(const Client &lhs, const Client &rhs) noexcept
Definition client.hpp:291
#define UA_STATUSCODE_BADOUTOFMEMORY
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 ValueType &src, NativeType &dst)
Definition types.hpp:338
static void toNative(const char *src, NativeType &dst)
Definition types.hpp:328
static void fromNative(const NativeType &src, ValueType &dst)
Definition types.hpp:428
static void toNative(const ValueType &src, NativeType &dst)
Definition types.hpp:432
std::chrono::time_point< Clock, Duration > ValueType
Definition types.hpp:425
static void fromNative(const NativeType &src, ValueType &dst)
Definition types.hpp:314
static void toNative(const ValueType &src, NativeType &dst)
Definition types.hpp:318
static void toNative(std::string_view src, NativeType &dst)
Definition types.hpp:304
static void fromNative(const NativeType &src, std::string_view &dst)
Definition types.hpp:300
Type conversion from and to native types.
static void setArray(Variant &var, Span< T > array)
Definition types.hpp:1382
static void setArray(Variant &var, Span< T > array, const UA_DataType &dtype)
Definition types.hpp:1387
static void setScalar(Variant &var, const T &value, const UA_DataType &dtype)
Definition types.hpp:1377
static void setArray(Variant &var, InputIt first, InputIt last, const UA_DataType &dtype)
Definition types.hpp:1397
static void setArray(Variant &var, InputIt first, InputIt last)
Definition types.hpp:1392
static void setScalar(Variant &var, const T &value)
Definition types.hpp:1372
static void setScalar(Variant &var, T &value, const UA_DataType &dtype) noexcept
Definition types.hpp:1440
static void setArray(Variant &var, Span< const T > array)
Definition types.hpp:1459
static void setScalar(Variant &var, T &value) noexcept(detail::isRegisteredType< T >)
Definition types.hpp:1431
static void setArray(Variant &var, Span< const T > array, const UA_DataType &dtype)
Definition types.hpp:1464
static void setArray(Variant &var, Span< T > array) noexcept(detail::isRegisteredType< T >)
Definition types.hpp:1445
static void setArray(Variant &var, Span< T > array, const UA_DataType &dtype) noexcept
Definition types.hpp:1454
static void setScalar(Variant &var, T &value) noexcept
Definition types.hpp:1405
static void setArray(Variant &var, Span< T > array, const UA_DataType &dtype) noexcept
Definition types.hpp:1420
static void setArray(Variant &var, Span< T > array) noexcept
Definition types.hpp:1415
static void setScalar(Variant &var, T &value, const UA_DataType &dtype) noexcept
Definition types.hpp:1410
std::size_t operator()(const opcua::ExpandedNodeId &id) const noexcept
Definition types.hpp:1935
std::size_t operator()(const opcua::NodeId &id) const noexcept
Definition types.hpp:1928
UA_NODEIDTYPE_STRING
UA_NODEIDTYPE_GUID
UA_NODEIDTYPE_BYTESTRING
UA_NODEIDTYPE_NUMERIC
UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *type)
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