PLCnext API Documentation  20.0.0.24462
RscVariant.hxx
1 //
3 // Copyright PHOENIX CONTACT Electronics GmbH
4 //
6 #pragma once
7 #include "Arp/System/Commons/Exceptions/Exceptions.h"
8 #include "Arp/System/Rsc/Services/Rsc.h"
9 #include "Arp/System/Rsc/Services/RscGuid.hpp"
10 #include "Arp/System/Rsc/Services/RscVersion.hpp"
11 #include "Arp/System/Rsc/Services/RscString.hxx"
12 #include "Arp/System/Rsc/Services/SecureString.hxx"
13 #include <cstring>
14 #include <cstddef>
15 
16 namespace Arp { namespace System { namespace Rsc { namespace Services
17 {
18 
19 using namespace Arp::System::Commons;
20 
21 // forwards
22 class RscArrayReader;
23 class RscArrayWriter;
24 class RemotingReader;
25 class RemotingWriter;
26 template<int N> class RscStructReader;
27 template<int N> class RscStructWriter;
28 template<class T, bool IsClass, bool IsSerializable> class RscValueAdapter;
29 
36 template<int MaxStringSize = 0>
38 {
39 public: // typedefs/friends
40  friend class RscArrayReader;
41  friend class RscArrayWriter;
42  template<int N> friend class RscStructReader;
43  template<int N> friend class RscStructWriter;
44  template<class T, bool IsClass, bool IsSerializable> friend class RscValueAdapter;
45  template<int N> friend class SecureString;
46 
47  using ReadElementFunction = std::function<RscType(RscType expectedType, byte* pValue)>;
48  using WriteElementFunction = std::function<void(RscType valueType, const byte* pValue)>;
50 
51 public: // construction/destruction
57 
61  template <class T>
62  RscVariant(const T& value);
63 
68  RscVariant(const String& value);
69 
74  RscVariant(const char* value);
75 
80  template<int N>
81  RscVariant(const RscString<N>& value);
82 
87  template<int N>
88  RscVariant(const SecureString<N>& value);
89 
98  RscVariant(size_t arraySize, RscType arrayElementType, size_t dimensions = 1, size_t fieldCount = 0);
99 
109  RscVariant(size_t arraySize, RscType arrayElementType, ReadElementFunction* pFunction, size_t dimensions = 1, size_t fieldCount = 0);
110 
120  RscVariant(size_t arraySize, RscType arrayElementType, WriteElementFunction* pFunction, size_t dimensions = 1, size_t fieldCount = 0);
121 
122  RscVariant(size_t fieldCount, ReadElementFunction* pFunction);
123 
127  RscVariant(const RscVariant<MaxStringSize>&) = default;
128 
132  RscVariant(RscVariant&&) = default;
133 
134 public: // Static factory operations
140  static RscVariant<MaxStringSize> CreateStructVariant(size_t fieldCount);
141 
150  static RscVariant<MaxStringSize> CreateArrayVariant(size_t arraySize, RscType elementType, size_t dimensions = 1, size_t fieldCount = 0);
151 
152 private: // static factory operations
153  static RscVariant<MaxStringSize> CreateStructVariant(size_t fieldCount, RemotingWriter& writer);
154  static RscVariant<MaxStringSize> CreateArrayVariant(size_t arraySize, RscType elementType, RemotingWriter& writer, size_t dimensions = 1, size_t fieldCount = 0);
155 
156 public: // operators
157  template <class T>
158  RscVariant& operator=(const T& value);
159  RscVariant& operator=(const String& value);
160  RscVariant& operator=(const char* value);
161  template<int N>
162  RscVariant& operator=(const RscString<N>& value);
163  template<int N>
164  RscVariant& operator=(const SecureString<N>& value);
165  RscVariant& operator=(const RscVariant& value) = default;
166  RscVariant& operator=(RscVariant&&) = default;
167  bool operator==(const RscVariant& value)const;
168  bool operator!=(const RscVariant& value)const;
169 
170 public: // getter/setter
175  RscType GetType(void)const;
176 
181  RscType GetValueType(void)const;
182 
188  RscType GetArrayElementType(void)const;
189 
195  size_t GetArrayDimensions(void)const;
196 
202  size_t GetFieldCount(void) const;
203 
208  const char* GetChars(void)const;
209 
215  void SetWriteElementFunction(WriteElementFunction* pFunction) const;
216 
221  const byte* GetDataAddress(void)const;
222 
227  byte* GetDataAddress(void);
228 
233  void SetType(RscType rscType);
234 
235 public: // operations
240  template<class T>
241  T GetValue(void)const;
242 
247  template<class T>
248  void CopyTo(T& value)const;
249 
254  String ToString(void)const;
255 
256 private: // Setter/Getter for internal use and friend classes
257  RscArrayInformation& GetArrayInformation(void);
258  const RscArrayInformation& GetArrayInformation(void) const;
259  RscStructInformation& GetStructInformation(void);
260  const RscStructInformation& GetStructInformation(void) const;
261 
262 private: // methods
263  void Assign(const char*, size_t len, RscType type = RscType::Utf8String);
264  void InitComplexTypeInfo(void);
265  bool ContainsTypeInformation(void) const;
266  size_t GetSize(void)const;
267 
268 private: // nested types
269  struct ComplexTypeInfo
270  {
271  union
272  {
273  RscArrayInformation arrayInformation;
274  RscStructInformation structInformation;
275  };
276  RemotingReader* pReader = nullptr;
277  mutable RemotingWriter* pWriter = nullptr;
278  ReadElementFunction* pReadElementFunction = nullptr;
279  mutable WriteElementFunction* pWriteElementFunction = nullptr;
280  };
281 
282 private: // static fields
283  static const size_t maxPrimitiveSize = 8;
284 #ifdef ARP_SYSTEM_RSC_SUPPORT_VERSION_GUID_AS_OBJECT
285  static const size_t minBufferSize = std::max(maxPrimitiveSize, std::max(sizeof(RscGuid), sizeof(RscVersion)));
286 #else
287  static const size_t minBufferSize = maxPrimitiveSize;
288 #endif // ARP_SYSTEM_RSC_SUPPORT_VERSION_GUID_AS_OBJECT
289 
290  static const size_t bufferSize = minBufferSize < (size_t)MaxStringSize ? (size_t)MaxStringSize : minBufferSize;
291 
292 private: // fields
293  union
294  {
295  ComplexTypeInfo typeInfo;
296  byte buffer[bufferSize];
297  };
298  RscType type = RscType::None;
299 };
300 
301 
303 // inline methods of RscType helper
304 template<int N>
305 inline constexpr RscType GetRscTypeFrom(const RscVariant<N>& /*value*/)
306 {
307  return RscType::Object;
308 }
309 
311 // inline methods of class RscVariant
312 
313 template<int MaxStringSize>
315  : type(typeArg)
316 {
317 }
318 
319 template<int MaxStringSize>
320 template<class T>
322 {
323  this->operator=(value);
324 }
325 
326 template<int MaxStringSize>
328  : type(RscType::Utf8String)
329 {
330  this->operator=(value);
331 }
332 
333 template<int MaxStringSize>
334 inline RscVariant<MaxStringSize>::RscVariant(const char* value)
335 {
336  this->operator=(value);
337 }
338 
339 template<int MaxStringSize>
340 template<int N>
342 {
343  this->operator=(value);
344 }
345 
346 template<int MaxStringSize>
347 template<int N>
349 {
350  this->operator=(value);
351 }
352 
353 template<int MaxStringSize>
354 inline RscVariant<MaxStringSize>::RscVariant(size_t arraySize, RscType arrayElementType, size_t dimensions, size_t fieldCount)
355  : type(RscType::Array)
356 {
357  if(arrayElementType == RscType::Struct && fieldCount == 0)
358  {
359  throw ArgumentException::Create("fieldCount", fieldCount, "fieldCount has to be set for struct element types");
360  }
361  this->GetArrayInformation() = RscArrayInformation(arraySize, arrayElementType, dimensions, fieldCount);
362  this->typeInfo.pReader = nullptr;
363  this->typeInfo.pWriter = nullptr;
364  this->typeInfo.pReadElementFunction = nullptr;
365  this->typeInfo.pWriteElementFunction = nullptr;
366 }
367 
368 template<int MaxStringSize>
369 inline RscVariant<MaxStringSize>::RscVariant(size_t arraySize, RscType arrayElementType, ReadElementFunction* pFunction, size_t dimensions, size_t fieldCount)
370  : type(RscType::Array)
371 {
372  if(arrayElementType == RscType::Struct && fieldCount == 0)
373  {
374  throw ArgumentException::Create("fieldCount", fieldCount, "fieldCount has to be set for struct element types");
375  }
376  this->GetArrayInformation() = RscArrayInformation(arraySize, arrayElementType, dimensions, fieldCount);
377  this->typeInfo.pReader = nullptr;
378  this->typeInfo.pWriter = nullptr;
379  this->typeInfo.pReadElementFunction = pFunction;
380  this->typeInfo.pWriteElementFunction = nullptr;
381 }
382 
383 template<int MaxStringSize>
384 inline RscVariant<MaxStringSize>::RscVariant(size_t arraySize, RscType arrayElementType, WriteElementFunction* pFunction, size_t dimensions, size_t fieldCount)
385  : type(RscType::Array)
386 {
387  if(arrayElementType == RscType::Struct && fieldCount == 0)
388  {
389  throw ArgumentException::Create("fieldCount", fieldCount, "fieldCount has to be set for struct element types");
390  }
391  this->GetArrayInformation() = RscArrayInformation(arraySize, arrayElementType, dimensions, fieldCount);
392  this->typeInfo.pReader = nullptr;
393  this->typeInfo.pWriter = nullptr;
394  this->typeInfo.pReadElementFunction = nullptr;
395  this->typeInfo.pWriteElementFunction = pFunction;
396 }
397 
398 template<int MaxStringSize>
399 inline RscVariant<MaxStringSize>::RscVariant(size_t fieldCount, ReadElementFunction* pFunction)
400  : type(RscType::Struct)
401 {
402  this->InitComplexTypeInfo();
403  this->GetStructInformation() = RscStructInformation(fieldCount);
404  this->typeInfo.pReadElementFunction = pFunction;
405 }
406 
407 template<int MaxStringSize>
409 {
410  return this->type;
411 }
412 
413 template<int MaxStringSize>
415 {
416  switch (this->type)
417  {
418  case RscType::IecTime:
419  return RscType::Int32;
420  case RscType::IecTime64:
421  case RscType::IecDate64:
422  case RscType::IecDateTime64:
423  case RscType::IecTimeOfDay64:
424  return RscType::Int64;
425  default:
426  // no mapping
427  return this->type;
428  }
429 }
430 
431 template<int MaxStringSize>
433 {
434  return this->GetArrayInformation().ElementType;
435 }
436 
437 template<int MaxStringSize>
439 {
440  if(this->GetType() != RscType::Array)
441  {
442  throw InvalidOperationException("RscVariant doesn't contain array information");
443  }
444  return this->typeInfo.arrayInformation;
445 }
446 
447 template<int MaxStringSize>
449 {
450  if(this->GetType() != RscType::Array)
451  {
452  throw InvalidOperationException("RscVariant doesn't contain array information");
453  }
454  return this->typeInfo.arrayInformation;
455 }
456 
457 template<int MaxStringSize>
459 {
460  if(this->GetType() != RscType::Struct)
461  {
462  throw InvalidOperationException("RscVariant doesn't contain struct information");
463  }
464  return this->typeInfo.structInformation;
465 }
466 
467 template<int MaxStringSize>
469 {
470  if(this->GetType() != RscType::Struct)
471  {
472  throw InvalidOperationException("RscVariant doesn't contain struct information");
473  }
474  return this->typeInfo.structInformation;
475 }
476 
477 template<int MaxStringSize>
479 {
480  return this->GetArrayInformation().Dimensions;
481 }
482 
483 template<int MaxStringSize>
485 {
486  return this->GetStructInformation().FieldCount;
487 }
488 
489 template<int MaxStringSize>
491 {
492  return this->buffer;
493 }
494 
495 template<int MaxStringSize>
497 {
498  return this->buffer;
499 }
500 
501 template<int MaxStringSize>
503 {
504  this->type = rscType;
505 }
506 
507 template<int MaxStringSize>
509 {
510  return (this->type == RscType::Struct || this->type == RscType::Array);
511 }
512 
513 template<int MaxStringSize>
514 template<class T>
516 {
517  this->type = GetRscType<T>();
518  if(this->type == RscType::None)
519  {
520  throw NotSupportedException("Cannot assign from argument: Type of argument is not supported");
521  }
522 #ifndef ARP_SYSTEM_RSC_SUPPORT_VERSION_GUID_AS_OBJECT
523  if (this->type == RscType::Version || this->type == RscType::Guid)
524  {
525  throw NotImplementedException("Type RscVersion and RscGuid are currently not supported by RscVariant");
526  }
527 #endif // ARP_SYSTEM_RSC_SUPPORT_VERSION_GUID_AS_OBJECT
528 *reinterpret_cast<T*>(this->buffer) = value;
529 return *this;
530 }
531 
532 template<int MaxStringSize>
534 {
535  RscVariant<MaxStringSize> result(RscType::Struct);
536  result.InitComplexTypeInfo();
537  result.GetStructInformation().FieldCount = fieldCount;
538  return result;
539 }
540 
541 template<int MaxStringSize>
542 inline RscVariant<MaxStringSize> RscVariant<MaxStringSize>::CreateArrayVariant(size_t arraySize, RscType elementType, size_t dimensions, size_t fieldCount)
543 {
544  RscVariant<MaxStringSize> result(arraySize, elementType, dimensions, fieldCount);
545  return result;
546 }
547 
548 template<int MaxStringSize>
549 inline RscVariant<MaxStringSize> RscVariant<MaxStringSize>::CreateStructVariant(size_t fieldCount, RemotingWriter& writer)
550 {
552  result.typeInfo.pWriter = &writer;
553  return result;
554 }
555 
556 template<int MaxStringSize>
557 inline RscVariant<MaxStringSize> RscVariant<MaxStringSize>::CreateArrayVariant(size_t arraySize, RscType elementType, RemotingWriter& writer, size_t dimensions, size_t fieldCount)
558 {
559  RscVariant<MaxStringSize> result(arraySize, elementType, dimensions, fieldCount);
560  result.typeInfo.pWriter = &writer;
561  return result;
562 }
563 
564 template<int MaxStringSize>
566 {
567  size_t len = value.Length();
568  this->Assign(value.CStr(), len);
569  return *this;
570 }
571 
572 template<int MaxStringSize>
574 {
575  size_t len = strlen(value);
576  this->Assign(value, len);
577  return *this;
578 }
579 
580 template<int MaxStringSize>
581 template<int N>
583 {
584  this->Assign(value.CStr(), strlen(value.CStr()), RscType::Utf8String);
585  return *this;
586 }
587 
588 template<int MaxStringSize>
589 template<int N>
591 {
592  this->Assign(value.CStr(), strlen(value.CStr()), RscType::SecureString);
593  return *this;
594 }
595 
596 template<int MaxStringSize>
597 inline void RscVariant<MaxStringSize>::Assign(const char* value, size_t len, RscType typeArg)
598 {
599  if (len >= MaxStringSize)
600  {
601  throw ArgumentException("Cannot copy string: argument string length {0} exceeds MaxStringSize {1}", len, MaxStringSize);
602  }
603  if (typeArg != RscType::Utf8String && typeArg != RscType::SecureString)
604  {
605  throw NotSupportedException("RscType '{0}' not supported", typeArg);
606  }
607  memcpy(this->buffer, value, len);
608  this->buffer[len] = '\0';
609  this->type = typeArg;
610 }
611 
612 template<int MaxStringSize>
613 inline bool RscVariant<MaxStringSize>::operator==(const RscVariant& value)const
614 {
615  if (this->GetType() != value.GetType())
616  {
617  return false;
618  }
619 
620  if (this->GetSize() != value.GetSize())
621  {
622  return false;
623  }
624 
625  if (memcmp(this->buffer, value.buffer, this->GetSize()) != 0)
626  {
627  return false;
628  }
629 
630  if (this->GetType() == RscType::Utf8String)
631  {
632  if (strcmp((char*)this->buffer, (char*)value.buffer) != 0)
633  {
634  return false;
635  }
636  }
637 
638  return true;
639 }
640 
641 template<int MaxStringSize>
642 inline bool RscVariant<MaxStringSize>::operator!=(const RscVariant& value)const
643 {
644  return !(*this == value);
645 }
646 
647 template<int MaxStringSize>
649 {
650  // needed, because elements of union are not initialized
651  this->typeInfo.pReader = nullptr;
652  this->typeInfo.pWriter = nullptr;
653  this->typeInfo.pReadElementFunction = nullptr;
654  this->typeInfo.pWriteElementFunction = nullptr;
655 }
656 
657 template<int MaxStringSize>
658 template<class T>
659 inline void RscVariant<MaxStringSize>::CopyTo(T& value) const
660 {
661  RscType argType = GetRscType<T>();
662  if(this->GetValueType() != argType)
663  {
664  throw InvalidCastException("Cannot copy value to argument: RscVariant contains data type {0} but arg is of type {1}", this->type, argType);
665  }
666  value = *reinterpret_cast<const T*>(this->buffer);
667 }
668 
669 template<int MaxStringSize>
670 inline const char* RscVariant<MaxStringSize>::GetChars() const
671 {
672  if (this->type != RscType::Utf8String && this->type != RscType::SecureString && this->type != RscType::AnsiString)
673  {
674  throw InvalidCastException("Cannot convert to string: RscVariant is of type {0}", this->type);
675  }
676  return reinterpret_cast<const char*>(this->buffer);
677 }
678 
679 template<int MaxStringSize>
680 inline void RscVariant<MaxStringSize>::SetWriteElementFunction(WriteElementFunction * pFunction) const
681 {
682  if(this->type != RscType::Array && this->type != RscType::Struct)
683  {
684  throw InvalidOperationException("Method only allowed for array and struct objects");
685  }
686  this->typeInfo.pWriteElementFunction = pFunction;
687 }
688 
689 template<int MaxStringSize>
690 template<class T>
692 {
693  T result;
694  this->CopyTo(result);
695  return result;
696 }
697 
698 template<int MaxStringSize>
700 {
701  const byte* pValue = this->GetDataAddress();
702 
703  switch (this->type)
704  {
705  case RscType::SecureString:
706  case RscType::AnsiString:
707  case RscType::Utf8String:
708  return reinterpret_cast<const char*>(pValue);
709  case RscType::DateTime:
710  throw NotImplementedException("RscVariant::ToString() not yet implemented for type '{0}'", type);
711  case RscType::Bool:
712  return std::to_string(*reinterpret_cast<const bool*>(pValue));
713  case RscType::Char:
714  return std::to_string(*reinterpret_cast<const char16*>(pValue));
715  case RscType::Int16:
716  return std::to_string(*reinterpret_cast<const int16*>(pValue));
717  case RscType::Int32:
718  case RscType::IecTime:
719  return std::to_string(*reinterpret_cast<const int32*>(pValue));
720  case RscType::Int8:
721  return std::to_string(*reinterpret_cast<const int8*>(pValue));
722  case RscType::Int64:
723  case RscType::IecTime64:
724  case RscType::IecDate64:
725  case RscType::IecDateTime64:
726  case RscType::IecTimeOfDay64:
727  return std::to_string(*reinterpret_cast<const int64*>(pValue));
728  case RscType::None:
729  case RscType::Null:
730  return String::Empty;
731  case RscType::Real32:
732  return std::to_string(*reinterpret_cast<const float*>(pValue));
733  case RscType::Real64:
734  return std::to_string(*reinterpret_cast<const double*>(pValue));
735  case RscType::Uint16:
736  return std::to_string(*reinterpret_cast<const uint16*>(pValue));
737  case RscType::Uint32:
738  return std::to_string(*reinterpret_cast<const uint32*>(pValue));
739  case RscType::Uint64:
740  return std::to_string(*reinterpret_cast<const uint64*>(pValue));
741  case RscType::Uint8:
742  return std::to_string(*reinterpret_cast<const uint8*>(pValue));
743  case RscType::Version:
744  return reinterpret_cast<const RscVersion*>(pValue)->ToString();
745  case RscType::Guid:
746  return reinterpret_cast<const RscGuid*>(pValue)->ToString();
747  case RscType::Void:
748  return String::Empty;
749  default:
750  // case RscType::Array:
751  throw NotSupportedException("RscVariant::ToString() not supported for type '{0}'", type);
752  }
753 }
754 
755 template<int MaxStringSize>
756 inline size_t RscVariant<MaxStringSize>::GetSize(void)const
757 {
758  switch (this->GetValueType())
759  {
760  case RscType::Void:
761  return 0;
762  break;
763  case RscType::Bool:
764  case RscType::Int8:
765  case RscType::Uint8:
766  return 1;
767  break;
768  case RscType::Char:
769  case RscType::Int16:
770  case RscType::Uint16:
771  return 2;
772  break;
773  case RscType::Int32:
774  case RscType::Uint32:
775  case RscType::Real32:
776  case RscType::IecTime:
777  return 4;
778  break;
779  case RscType::Int64:
780  case RscType::Uint64:
781  case RscType::Real64:
782  case RscType::DateTime:
783  case RscType::IecTime64:
784  case RscType::IecDate64:
785  case RscType::IecDateTime64:
786  case RscType::IecTimeOfDay64:
787  return 8;
788  break;
789  case RscType::Utf8String:
790  return strlen((char*)this->buffer);
791  break;
792  case RscType::Array:
793  {
794  return sizeof(RscArrayInformation);
795  break;
796  }
797  case RscType::Struct:
798  {
799  return sizeof(RscStructInformation);
800  break;
801  }
802  case RscType::SecureString:
803  default:
804  throw NotSupportedException("RscType {0} not supported.", this->GetValueType());
805  }
806 }
807 
808 }}}} // end of namespace Arp::System::Rsc::Services
809 
const char * CStr(void) const
Returns pointer to internal buffer.
Definition: RscString.hxx:109
Definition: RscGuid.hpp:17
Helper class to read a struct from an RscVariant. This class uses the struct information stored in Rs...
Definition: RscStructReader.hxx:26
Helper class to read an array of primtive types from an RscVariant. This class uses the array informa...
Definition: RscArrayWriter.hpp:21
This exception is used when a method is not supported.
Definition: NotSupportedException.hpp:14
Arp::BasicVersion Version
The Arp Version class.
Definition: TypeSystem.h:29
This exception is used when a method is not implemented yet.
Definition: NotImplementedException.hpp:14
Helper class to read an array of primtive types from an RscVariant. This class uses the array informa...
Definition: RscArrayReader.hpp:22
This exception is used when an invalid cast occurs.
Definition: InvalidCastException.hpp:14
RscType
Datatypes supported by Rsc. Values are identical with CommonRemoting::RemotingMarshalType. Only supported types of RemotingMarshalType are included.
Definition: RscType.hpp:27
Rsc container class for primitive data type, strings or information about arrays or structs...
Definition: RscVariant.hxx:37
Object type handled by Rsc as RscVariant
Specifies a version with 4 version numbers and is marshalled to .NET type System.Version.
Definition: RscVersion.hpp:20
This exception is used when a method call is invalid for object&#39;s current state.
Definition: InvalidOperationException.hpp:14
This exception is used when an invalid argument occurs.
Definition: ArgumentException.hpp:14
Specialized version of RscString for security context. Not implemented in this version. Wraps only RscString
Definition: RscType.hpp:18
Root namespace for the PLCnext API
RscType GetType(void) const
Gets the RscType of the contained element
Definition: RscVariant.hxx:408
Contains information to marshall an array
Definition: RscType.hpp:120
System components used by the System, Device, Plc or Io domains.
Contains information to marshall an struct
Definition: RscType.hpp:154
Helper class to write a struct from an RscVariant. This class uses the struct information stored in R...
Definition: RscStructWriter.hxx:18
bool operator==(Enum< T > lhs, Enum< T > rhs)
Equality operator for class Enum.
Definition: Enum.hxx:218
Contains a static string with string lentgh up to N characters. The string has to be null terminated...
Definition: RscString.hxx:18
This is a small immutable wrapper around the boost::uuids::uuid class and represents a universal uniq...
Definition: Uuid.hpp:18
Namespace for basic functions of the framework
RscVariant(RscType type=RscType::None)
Creates an empty instance of RscVariant
Definition: RscVariant.hxx:314
unsigned char byte
The Arp character type.
Definition: PrimitiveTypes.hpp:23