{ +-------------------------------------------------------------+ }
{ |                                                             | }
{ |   GM-Software                                               | }
{ |   ===========                                               | }
{ |                                                             | }
{ |   Project: All Projects                                     | }
{ |                                                             | }
{ |   Description: Union for multiple types like variant.       | }
{ |                                                             | }
{ |                                                             | }
{ |   Copyright (C) - 2020 - Gerrit Moeller.                    | }
{ |                                                             | }
{ |   Source code dstributed under MIT license.                 | }
{ |                                                             | }
{ |   See: https://www.gm-software.de                           | }
{ |                                                             | }
{ +-------------------------------------------------------------+ }

{$INCLUDE GMCompilerSettings.inc}

unit GMUnionValue;

interface

uses GMStrDef, Variants;

type

  EGMUnionValueType = (uvtUnassigned, uvtNull, uvtString, uvtBoolean, uvtInt16, uvtInt32, uvtInt64, uvtDouble, uvtDateTime, uvtPointer);

  //
  // TStrType is meant to be a string type like: UnicodeString, WideString, AnsiString, RawByteString, Utf8String or AnsiString(CP_XXXX)
  //
  RGMGenericUnionValue<TStrType> = packed record
   private
    StringValue: TStrType;

    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Boolean;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Byte;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): SmallInt;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Word;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): LongInt;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): LongWord;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Int64;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): QWord;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Pointer;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Single;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Double;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): TDateTime;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): UnicodeString;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): WideString;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): AnsiString;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Utf8String;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Variant;
    class operator Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): OleVariant;

    class operator Implicit(AValue: EGMUnionValueType): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: Boolean): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: SmallInt): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: LongInt): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: Int64): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: Double): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: TDateTime): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: Pointer): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: UnicodeString): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: WideString): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: AnsiString): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: Utf8String): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: Variant): RGMGenericUnionValue<TStrType>;
    class operator Implicit(AValue: OleVariant): RGMGenericUnionValue<TStrType>;

   public
    class operator Initialize(var AUnionValue: RGMGenericUnionValue<TStrType>);
    //class operator Finalize(var AUnionValue: RGMGenericUnionValue<TStrType>);
    //class operator Copy(constref ASrc: RGMGenericUnionValue<TStrType>; var ADst: RGMGenericUnionValue<TStrType>);

    class operator Equal(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
    class operator Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: Int64): Boolean;
    class operator Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: LongInt): Boolean;
    class operator Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: Pointer): Boolean;
    class operator Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: Double): Boolean;
    //class operator Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: TDateTime): Boolean;
    class operator Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: UnicodeString): Boolean;
    class operator Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: WideString): Boolean;
    class operator Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: AnsiString): Boolean;
    class operator Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: Utf8String): Boolean;

    class operator NotEqual(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;

    class operator Add(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;
    class operator Multiply(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;
    class operator Divide(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;
    class operator IntDivide(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;
    class operator Modulus(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;

    class operator LessThan(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
    class operator GreaterThan(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
    class operator LessThanOrEqual(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
    class operator GreaterThanOrEqual(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;

    function IsNull: Boolean;
    function IsUnassigned: Boolean;
    function IsNullOrUnassigned: Boolean;

    function AsBoolean: Boolean;
    function AsInt16: SmallInt;
    function AsInt32: LongInt;
    function AsInt64: Int64;
    function AsDouble: Double;
    function AsDateTime: TDateTime;
    function AsString: TGMString;
    //function AsDisplayString: TGMString;
    function AsPointer: Pointer;

    function AsBooleanDflt(const ADefaultValue: Boolean = False): Boolean;
    function AsInt16Dflt(const ADefaultValue: SmallInt = 0): SmallInt;
    function AsInt32Dflt(const ADefaultValue: LongInt = 0): LongInt;
    function AsInt64Dflt(const ADefaultValue: Int64 = 0): Int64;
    function AsDoubleDflt(const ADefaultValue: Double = 0.0): Double;
    function AsDateTimeDflt(const ADefaultValue: TDateTime = 0): TDateTime;
    function AsPointerDflt(const ADefaultValue: Pointer = nil): Pointer;
    function AsStringDflt(const ADefaultValue: TGMString = ''): TGMString;

    function ValueTypeName: TGMSTring;

    case ValueType: EGMUnionValueType of
     //uvtString: (StringValue: Pointer);
     uvtBoolean: (BoolValue: Boolean);
     uvtInt16: (Int16Value: SmallInt);
     uvtInt32: (Int32Value: LongInt);
     uvtInt64: (Int64Value: Int64);
     uvtDouble: (DoubleValue: Double);
     uvtDateTime: (DateTimeValue: TDateTime);
     uvtPointer: (PointerValue: Pointer);
  end;


  RGMUnionValue = RGMGenericUnionValue<TGMString>;
  PGMUnionValue = ^RGMUnionValue;


  IGMGetUnionValue = interface(IUnknown)
    ['{9BB4E638-DB7C-4583-9EE3-410E4FB0F5CB}']
    function GetUnionValue: RGMUnionValue;
    property Value: RGMUnionValue read GetUnionValue;
  end;


  IGMGetSetUnionValue = interface(IGMGetUnionValue)
    ['{3A3129DF-850E-40DA-AEF0-945A0BF2539C}']
    procedure SetUnionValue(const AValue: RGMUnionValue);
    property Value: RGMUnionValue read GetUnionValue write SetUnionValue;
  end;


  TGMUnionValToStrFunc = function (const AValue: RGMUnionValue): TGMString;


//
// To be used with GMNamesAndValuesAsString and GMSeparatedValues
//
function GMUnionValueAsString(const AValue: RGMUnionValue): TGMString;
function GMUnionValueAsQuotedString(const AValue: RGMUnionValue): TGMString;

function GMUnionValueTypeName(const AValueType: EGMUnionValueType): TGMString;

function GMUnionValueAsType(const AValue: RGMUnionValue; const ADestType: EGMUnionValueType): RGMUnionValue;
function GMUnionValueAsTypeDflt(const AValue: RGMUnionValue; const ADestType: EGMUnionValueType): RGMUnionValue;

procedure RaiseExceptionFmt(const AMsg: TGMString = '';
                            const AObj: TObject = nil;
                            const ARoutineName: TGMString = '');


resourcestring

  srValueConvertToErrFmt = 'Cannot convert union value of type %s to type %s';
  srValueConvertFromErrFmt = 'Cannot convert from %s to union value';


implementation

uses SysUtils, TypInfo, GMIntf, GMCommon;

type

  XGMUnionValueConvertError = class(EGMException);


resourcestring

  srValueTypeOutofBounds = 'UnionValue ValueType %d out of bounds, must be in [%d .. %d]';


function GMUnionValueTypeName(const AValueType: EGMUnionValueType): TGMString;
begin
  // AValueType enum value out of bounds may happen if not proper initialized
  if GMIsInRange(Ord(AValueType), Ord(Low(AValueType)), Ord(High(AValueType))) then
    Result := GetEnumName(TypeInfo(EGMUnionValueType), Ord(AValueType))
  else
    Result := GMFormat(srValueTypeOutofBounds, [Ord(AValueType), Low(AValueType), High(AValueType)]);
end;

function GMUnionValueAsString(const AValue: RGMUnionValue): TGMString;
begin
  Result := AValue.AsStringDflt;
end;

function GMUnionValueAsQuotedString(const AValue: RGMUnionValue): TGMString;
begin
  Result := GMQuote(GMUnionValueAsString(AValue), '"', '"');
end;

function GMUnionValueAsType(const AValue: RGMUnionValue; const ADestType: EGMUnionValueType): RGMUnionValue;
begin
  Result := Default(RGMUnionValue);
  case ADestType of
   uvtUnassigned: Result := uvtUnassigned;
   uvtNull: Result := uvtNull;
   uvtString: Result := AValue.AsString;
   uvtBoolean: Result := AValue.AsBoolean;
   uvtInt16: Result := AValue.AsInt16;
   uvtInt32: Result := AValue.AsInt32;
   uvtInt64: Result := AValue.AsInt64;
   uvtDouble: Result := AValue.AsDouble;
   uvtDateTime: Result := AValue.AsDateTime;
   uvtPointer: Result := AValue.AsPointer;
  end;
end;

function GMUnionValueAsTypeDflt(const AValue: RGMUnionValue; const ADestType: EGMUnionValueType): RGMUnionValue;
begin
  Result := Default(RGMUnionValue);
  case ADestType of
   uvtUnassigned: Result := uvtUnassigned;
   uvtNull: Result := uvtNull;
   uvtString: Result := AValue.AsStringDflt;
   uvtBoolean: Result := AValue.AsBooleanDflt;
   uvtInt16: Result := AValue.AsInt16Dflt;
   uvtInt32: Result := AValue.AsInt32Dflt;
   uvtInt64: Result := AValue.AsInt64Dflt;
   uvtDouble: Result := AValue.AsDoubleDflt;
   uvtDateTime: Result := AValue.AsDateTimeDflt;
   uvtPointer: Result := AValue.AsPointerDflt;
  end;
end;

procedure RaiseExceptionFmt(const AMsg: TGMString = cDfltExceptionMsg;
                            const AObj: TObject = nil;
                            const ARoutineName: TGMString = cDfltRoutineName);
                            //const ASeverityLevel: TGMSeverityLevel = svError;
                            //const AHelpCtx: LongInt = cDfltHelpCtx);
begin
  raise XGMUnionValueConvertError.ObjError(AMsg, AObj, ARoutineName);
end;


{ ---------------------------------------- }
{ ---- RGMGenericUnionValue<TStrType> ---- }
{ ---------------------------------------- }

//const
//
//  cBoolInt: array [Boolean] of Int64 = (0, 1);   moved to GMCommon unit
//  cBoolStr: array [Boolean] of TGMString = ('False', 'True');   moved to GMCommon unit


class operator RGMGenericUnionValue<TStrType>.Initialize(var AUnionValue: RGMGenericUnionValue<TStrType>);
begin
  FillByte(AUnionValue, SizeOf(AUnionValue), 0);
  //FillByte(AUnionValue. SizeOf(AUnionValue), 0);
  //AUnionValue := Default(RGMGenericUnionValue<TStrType>);
  //AUnionValue.ValueType := uvtUnassigned;
  //AUnionValue.StringValue := '';
  //AUnionValue.DoubleValue := 0;
end;

//class operator RGMGenericUnionValue<TStrType>.Finalize(var AUnionValue: RGMGenericUnionValue<TStrType>);
//begin
//  case AUnionValue.ValueType of
//   uvtString: if AUnionValue.StringValue <> nil then begin TStrType(AUnionValue.StringValue) := ''; AUnionValue.StringValue := nil; end;
//  end;
//end;

//class operator RGMGenericUnionValue<TStrType>.Copy(constref ASrc: RGMGenericUnionValue<TStrType>; var ADst: RGMGenericUnionValue<TStrType>);
//begin
//  Finalize(ADst);
//  Initialize(ADst);
//
//  case ASrc.ValueType of
//   uvtString: begin
//               ADst.ValueType := ASrc.ValueType;
//               TStrType(ADst.StringValue) := TStrType(ASrc.StringValue);
//              end;
//   else Move(Asrc, ADst, SizeOf(ADst));
//  end;
//end;

function RGMGenericUnionValue<TStrType>.IsNull: Boolean;
begin
  Result := ValueType = uvtNull;
end;

function RGMGenericUnionValue<TStrType>.IsUnassigned: Boolean;
begin
  Result := ValueType = uvtUnassigned;
end;

function RGMGenericUnionValue<TStrType>.IsNullOrUnassigned: Boolean;
begin
  Result := ValueType in [uvtUnassigned, uvtNull];
end;

function RGMGenericUnionValue<TStrType>.ValueTypeName: TGMSTring;
begin
  Result := GMUnionValueTypeName(ValueType);
end;

{$IFDEF FPC}{$push}{$WARN 5059 off : Function result variable does not seem to be initialized}{$ENDIF}
class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Boolean;
begin
  case AUnionValue.ValueType of
   //uvtUnassigned, uvtNull,
   uvtBoolean: Result := AUnionValue.BoolValue;
   uvtString: Result := GMStrToBool(AUnionValue.StringValue); // TStrType()
   uvtInt16: Result := AUnionValue.Int16Value <> 0;
   uvtInt32: Result := AUnionValue.Int32Value <> 0;
   uvtInt64: Result := AUnionValue.Int64Value <> 0;
   uvtDouble: Result := AUnionValue.DoubleValue <> 0.0;
   uvtDateTime: Result := AUnionValue.DateTimeValue <> 0.0;
   uvtPointer: Result := AUnionValue.PointerValue <> nil;
//   else raise XGMUnionValueConvertError.ObjError(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'Boolean']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
   else RaiseExceptionFmt(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'Boolean']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
  end;
end;

{$macro on}
{$define InsertUnionIntCase:=//jvkUnassigned, jvkNull
  uvtBoolean: Result := cBoolInt[AUnionValue.BoolValue];
  uvtString: Result := GMStrToInt(AUnionValue.StringValue); // TStrType()
  uvtInt16: Result := AUnionValue.Int16Value;
  uvtInt32: Result := AUnionValue.Int32Value;
  uvtInt64: Result := AUnionValue.Int64Value;
  uvtDouble: Result := Round(AUnionValue.DoubleValue);
  uvtDateTime: Result := Round(AUnionValue.DateTimeValue);
//  else raise XGMUnionValueConvertError.ObjError(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, cResultTypeName]), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
  else RaiseExceptionFmt(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, cResultTypeName]), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
  end;}


class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Byte;
const cResultTypeName = 'Byte';
begin
  case AUnionValue.ValueType of
  InsertUnionIntCase
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): SmallInt;
const cResultTypeName = 'SmallInt';
begin
  case AUnionValue.ValueType of
  InsertUnionIntCase
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Word;
const cResultTypeName = 'Word';
begin
  case AUnionValue.ValueType of
  InsertUnionIntCase
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): LongInt;
const cResultTypeName = 'LongInt';
begin
  case AUnionValue.ValueType of
  {$IFDEF CPU32}
   uvtPointer: Result := LongInt(AUnionValue.PointerValue);
  {$ENDIF}
  InsertUnionIntCase
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): LongWord;
const cResultTypeName = 'LongWord';
begin
  case AUnionValue.ValueType of
   {$IFDEF CPU32}
    uvtPointer: Result := LongWord(AUnionValue.PointerValue);
   {$ENDIF}
   InsertUnionIntCase
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Int64;
const cResultTypeName = 'Int64';
begin
  case AUnionValue.ValueType of
   {$IFDEF CPU64}
    uvtPointer: Result := Int64(AUnionValue.PointerValue);
   {$ELSE}
    uvtPointer: Result := PtrUInt(AUnionValue.PointerValue);
   {$ENDIF}
   InsertUnionIntCase
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): QWord;
const cResultTypeName = 'QWord';
begin
  case AUnionValue.ValueType of
   {$IFDEF CPU64}
    uvtPointer: Result := QWord(AUnionValue.PointerValue);
   {$ELSE}
    uvtPointer: Result := PtrUInt(AUnionValue.PointerValue);
   {$ENDIF}
   InsertUnionIntCase
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Pointer;
begin
  case AUnionValue.ValueType of
   //jvkUnassigned, jvkNull
   //uvtBoolean: Result := cBoolInt[AUnionValue.BoolValue];
   uvtString: Result := Pointer(AUnionValue.StringValue);
   //uvtInt16: Result := AUnionValue.Int16Value;
   {$IFDEF CPU64}
    uvtInt32: Result := Pointer(Int64(AUnionValue.Int32Value));
    uvtInt64: Result := Pointer(AUnionValue.Int64Value);
   {$ELSE}
    uvtInt32: Result := Pointer(AUnionValue.Int32Value);
    uvtInt64: Result := Pointer(PtrUInt(AUnionValue.Int64Value));
   {$ENDIF}

   //uvtDouble: Result := AUnionValue.DoubleValue;
   //uvtDateTime: Result := AUnionValue.DateTimeValue;
   uvtPointer: Result := AUnionValue.PointerValue;
//   else raise XGMUnionValueConvertError.ObjError(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'Pointer']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
   else RaiseExceptionFmt(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'Pointer']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
  end;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Single;
begin
  case AUnionValue.ValueType of
   //jvkUnassigned, jvkNull
   uvtBoolean:  Result := cBoolInt[AUnionValue.BoolValue];
   uvtString:   Result := GMStrToSingle(AUnionValue.StringValue); // TStrType()
   uvtInt16:    Result := AUnionValue.Int16Value;
   uvtInt32:    Result := AUnionValue.Int32Value;
   uvtInt64:    Result := AUnionValue.Int64Value;
   uvtDouble:   Result := AUnionValue.DoubleValue;
   uvtDateTime: Result := AUnionValue.DateTimeValue;
   uvtPointer:  Result := PtrUInt(AUnionValue.PointerValue);
//   else raise XGMUnionValueConvertError.ObjError(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'Single']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
     else RaiseExceptionFmt(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'Single']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
  end;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Double;
begin
  case AUnionValue.ValueType of
   //jvkUnassigned, jvkNull
   uvtBoolean:  Result := cBoolInt[AUnionValue.BoolValue];
   uvtString:   Result := GMStrToDouble(AUnionValue.StringValue); // TStrType()
   uvtInt16:    Result := AUnionValue.Int16Value;
   uvtInt32:    Result := AUnionValue.Int32Value;
   uvtInt64:    Result := AUnionValue.Int64Value;
   uvtDouble:   Result := AUnionValue.DoubleValue;
   uvtDateTime: Result := AUnionValue.DateTimeValue;
   uvtPointer:  Result := PtrUInt(AUnionValue.PointerValue);
//   else raise XGMUnionValueConvertError.ObjError(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'Double']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
     else RaiseExceptionFmt(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'Double']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
  end;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): TDateTime;
begin
  case AUnionValue.ValueType of
   //jvkUnassigned, jvkNull
   uvtString:   Result := GMFixedDecodeDateTime(AUnionValue.StringValue); // GMStrToDouble(AUnionValue.StringValue); TStrType()
   uvtInt16:    Result := AUnionValue.Int16Value;
   uvtInt32:    Result := AUnionValue.Int32Value;
   uvtInt64:    Result := AUnionValue.Int64Value;
   uvtDouble:   Result := AUnionValue.DoubleValue;
   uvtDateTime: Result := AUnionValue.DateTimeValue;
//   else raise XGMUnionValueConvertError.ObjError(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'TDateTime']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
     else RaiseExceptionFmt(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, 'TDateTime']), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
  end;
end;
{$IFDEF FPC}{$pop}{$ENDIF}

{$macro on}
{$define InsertStringResultCommonPart:=
  case AUnionValue.ValueType of
   //jvkUnassigned, jvkNull
   uvtBoolean: Result := cBoolStr[AUnionValue.BoolValue];
   uvtString: Result := AUnionValue.StringValue; // TStrType()
   uvtInt16: Result := GMIntToStr(AUnionValue.Int16Value);
   uvtInt32: Result := GMIntToStr(AUnionValue.Int32Value);
   uvtInt64: Result := GMIntToStr(AUnionValue.Int64Value);
   uvtDouble: Result := GMDoubleToStr(AUnionValue.DoubleValue);
   uvtDateTime: Result := GMFixedEncodeDateTime(AUnionValue.DateTimeValue); // GMDateTimeToStr(AUnionValue.DateTimeValue);
   uvtPointer: Result := GMIntToHexStr(PtrUInt(AUnionValue.PointerValue));
//   else raise XGMUnionValueConvertError.ObjError(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, cResultTypeName]), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
   else RaiseExceptionFmt(GMFormat(srValueConvertToErrFmt, [AUnionValue.ValueTypeName, cResultTypeName]), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
  end;}

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): UnicodeString;
const cResultTypeName = 'UnicodeString';
begin
  InsertStringResultCommonPart
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): WideString;
const cResultTypeName = 'WideString';
begin
  InsertStringResultCommonPart
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): AnsiString;
const cResultTypeName = 'AnsiString';
begin
  InsertStringResultCommonPart
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Utf8String;
const cResultTypeName = 'Utf8String';
begin
  InsertStringResultCommonPart
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): Variant;
begin
  case AUnionValue.ValueType of
   //uvtUnassigned: Result := Unassigned;
   uvtNull:     Result := Variants.Null;
   uvtString:   Result := AUnionValue.AsString;
   uvtBoolean:  Result := AUnionValue.BoolValue;
   uvtInt16:    Result := AUnionValue.Int16Value;
   uvtInt32:    Result := AUnionValue.Int32Value;
   uvtInt64:    Result := AUnionValue.Int64Value;
   uvtDouble:   Result := AUnionValue.DoubleValue;
   uvtDateTime: Result := AUnionValue.DateTimeValue;
   uvtPointer:  Result := AUnionValue.PointerValue;
   else Result := Variants.Unassigned;
  end;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(const AUnionValue: RGMGenericUnionValue<TStrType>): OleVariant;
begin
  case AUnionValue.ValueType of
   //uvtUnassigned: Result := Unassigned;
   uvtNull:     Result := Variants.Null;
   uvtString:   Result := AUnionValue.AsString;
   uvtBoolean:  Result := AUnionValue.BoolValue;
   uvtInt16:    Result := AUnionValue.Int16Value;
   uvtInt32:    Result := AUnionValue.Int32Value;
   uvtInt64:    Result := AUnionValue.Int64Value;
   uvtDouble:   Result := AUnionValue.DoubleValue;
   uvtDateTime: Result := AUnionValue.DateTimeValue;
   //uvtPointer: Result := AValue.PointerValue;
   else Result := Variants.Unassigned;
  end;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: EGMUnionValueType): RGMGenericUnionValue<TStrType>;
begin
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  Finalize(Result);
  case AValue of
    uvtUnassigned, uvtNull:
     begin
      //TStrType(Result.StringValue) := '';
      //Result.StringValue := '';
      Result.ValueType := AValue;
     end;
//    else raise XGMUnionValueConvertError.ObjError(GMFormat(srValueConvertFromErrFmt, [GMUnionValueTypeName(AValue)]), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
      else RaiseExceptionFmt(GMFormat(srValueConvertFromErrFmt, [GMUnionValueTypeName(AValue)]), nil, 'RGMGenericUnionValue<TStrType>.Implicit');
  end;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: Boolean): RGMGenericUnionValue<TStrType>;
begin
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  Finalize(Result);
  Result.BoolValue := AValue;
  Result.ValueType := uvtBoolean;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: SmallInt): RGMGenericUnionValue<TStrType>;
begin
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  Finalize(Result);
  Result.Int16Value := AValue;
  Result.ValueType := uvtInt16;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: LongInt): RGMGenericUnionValue<TStrType>;
begin
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  Finalize(Result);
  Result.Int32Value := AValue;
  Result.ValueType := uvtInt32;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: Int64): RGMGenericUnionValue<TStrType>;
begin
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  Finalize(Result);
  Result.Int64Value := AValue;
  Result.ValueType := uvtInt64;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: Double): RGMGenericUnionValue<TStrType>;
begin
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  Finalize(Result);
  Result.DoubleValue := AValue;
  Result.ValueType := uvtDouble;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: TDateTime): RGMGenericUnionValue<TStrType>;
begin
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  Finalize(Result);
  Result.DateTimeValue := AValue;
  Result.ValueType := uvtDateTime;
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: Pointer): RGMGenericUnionValue<TStrType>;
begin
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  Finalize(Result);
  Result.PointerValue := AValue;
  Result.ValueType := uvtPointer;
end;

{$define InsertAssignFromStringCommonPart:=
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  Finalize(Result);
  Result.StringValue := AValue; // TStrType()
  Result.ValueType := uvtString;}

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: UnicodeString): RGMGenericUnionValue<TStrType>;
begin
  InsertAssignFromStringCommonPart
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: WideString): RGMGenericUnionValue<TStrType>;
begin
  InsertAssignFromStringCommonPart
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: AnsiString): RGMGenericUnionValue<TStrType>;
begin
  InsertAssignFromStringCommonPart
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: Utf8String): RGMGenericUnionValue<TStrType>;
begin
  InsertAssignFromStringCommonPart
end;

{$define InsertAssignFromVariantCommonPart:=
  //Result := Default(RGMGenericUnionValue<TStrType>); // <- Result may be a re-used instance, assignmet will finalize it before assign
  //Finalize(Result);
  case VarType(AValue) of
   //varEmpty: Result := uvtUnassigned; <- handeled by else case
   varNull: Result := uvtNull;
   varBoolean: Result := Boolean(AValue); // AValue.vBoolean;
   varSmallint: Result := SmallInt(AValue); // AValue.vSmallint;
   varWord: Result := Word(AValue); // AValue.vWord;
   varInteger: Result := LongInt(AValue); // AValue.vInteger;
   varLongword: Result := Longword(AValue); // AValue.vLongword;
   varInt64: Result := Int64(AValue); // AValue.vInt64;
   varQWord: Result := QWord(AValue); // AValue.vQWord;
   varSingle: Result := Single(AValue); // AValue.vSingle;
   varDouble: Result := Double(AValue); // AValue.vDouble;
   varDate: Result := TDateTime(AValue); // AValue.vDate;
   varOleStr, varString: Result := GMVarToStr(AValue);
   varUnknown, varDispatch: Result := Pointer(IUnknown(AValue)); // AValue.vUnknown;
   varError: Result := AValue.vError;
   else Result := uvtUnassigned;
  end;}

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: Variant): RGMGenericUnionValue<TStrType>;
begin
  InsertAssignFromVariantCommonPart
end;

class operator RGMGenericUnionValue<TStrType>.Implicit(AValue: OleVariant): RGMGenericUnionValue<TStrType>;
begin
  InsertAssignFromVariantCommonPart
end;

class operator RGMGenericUnionValue<TStrType>.Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: Int64): Boolean;
begin
  Result := AUnionValue.AsInt64 = AValue;
end;

class operator RGMGenericUnionValue<TStrType>.Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: LongInt): Boolean;
begin
  Result := AUnionValue.AsInt32 = AValue;
end;

class operator RGMGenericUnionValue<TStrType>.Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: Pointer): Boolean;
begin
  Result := AUnionValue.AsPointer = AValue;
end;

class operator RGMGenericUnionValue<TStrType>.Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: Double): Boolean;
begin
  Result := AUnionValue.AsDouble = AValue;
end;

//class operator RGMGenericUnionValue<TStrType>.Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: TDateTime): Boolean;
//begin
//  Result := AUnionValue.AsDateTime = AValue;
//end;

class operator RGMGenericUnionValue<TStrType>.Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: UnicodeString): Boolean;
begin
  Result := AUnionValue.AsString = AValue;
end;

class operator RGMGenericUnionValue<TStrType>.Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: WideString): Boolean;
begin
  Result := AUnionValue.AsString = AValue;
end;

class operator RGMGenericUnionValue<TStrType>.Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: AnsiString): Boolean;
begin
  Result := AUnionValue.AsString = AValue;
end;

class operator RGMGenericUnionValue<TStrType>.Equal(const AUnionValue: RGMGenericUnionValue<TStrType>; AValue: Utf8String): Boolean;
begin
  Result := AUnionValue.AsString = AValue;
end;

//class operator RGMGenericUnionValue<TStrType>.Equal(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
//begin
//  Result := AValue1.ValueType = AValue2.ValueType;
//  if Result then
//   case AValue1.ValueType of
//    //uvtUnassigned, uvtNull, <- Nothing!
//    uvtString:   Result := GMSameText(AValue1.StringValue, AValue2.StringValue);
//    uvtBoolean:  Result := AValue1.BoolValue = AValue2.BoolValue;
//    uvtInt16:    Result := AValue1.Int16Value = AValue2.Int16Value;
//    uvtInt32:    Result := AValue1.Int32Value = AValue2.Int32Value;
//    uvtInt64:    Result := AValue1.Int64Value = AValue2.Int64Value;
//    uvtDouble:   Result := AValue1.DoubleValue = AValue2.DoubleValue;
//    uvtDateTime: Result := AValue1.DateTimeValue = AValue2.DateTimeValue;
//    uvtPointer:  Result := AValue1.PointerValue = AValue2.PointerValue;
//   end;
//end;

class operator RGMGenericUnionValue<TStrType>.Equal(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
begin
  case AValue1.ValueType of
   uvtUnassigned: Result := AValue2.ValueType = uvtUnassigned;
   uvtNull: Result := AValue2.ValueType = uvtNull;
   uvtString:
    case AValue2.ValueType of
     uvtString: Result := GMSameText(AValue1.AsString, AValue2.AsString);
     uvtBoolean, uvtInt16, uvtInt32, uvtInt64, uvtDouble, uvtDateTime: Result := GMSameText(AValue1.AsString, AValue2.AsString);
     else Result := False;
    end;

   uvtBoolean:
    case AValue2.ValueType of
     uvtBoolean: Result := AValue1.BoolValue = AValue2.BoolValue;
     uvtInt16, uvtInt32, uvtInt64: Result := AValue1.BoolValue = (AValue2.AsInt64 <> 0);
     uvtdouble: Result := AValue1.BoolValue = (AVAlue2.DoubleValue <> 0);
     uvtString: Result := AValue1.BoolValue = GMStrToBool(AValue2.StringValue); // TStrType()
     else Result := False;
    end;

   uvtInt16, uvtInt32, uvtInt64:
    case AValue2.ValueType of
     //uvtString: Result := AValue1.AsInt64 =
     //uvtBoolean,
     //uvtString: Result
     uvtInt16, uvtInt32, uvtInt64: Result := AValue1.AsInt64 = AValue2.AsInt64;
     uvtDouble, uvtDateTime: Result := AValue1.AsInt64 = AValue2.DoubleValue;
     else Result := False;
    end;

   uvtDouble, uvtDateTime:
    case AValue2.ValueType of
     //uvtString, uvtBoolean,
     //uvtString,
     uvtInt16, uvtInt32, uvtInt64: Result := AValue1.DoubleValue = AValue2.AsInt64;
     uvtDouble, uvtDateTime: Result := AValue1.DoubleValue = AValue2.DoubleValue;
     else Result := False;
    end;

   uvtPointer:
    case AValue2.ValueType of
     {$IFDEF CPU32}
      uvtInt32: Result := PtrUInt(AValue1.PointerValue) = PtrUInt(AValue2.AsInt32);
     {$ENDIF}
     {$IFDEF CPU64}
      uvtInt64: Result := PtrUInt(AValue1.PointerValue) = PtrUInt(AValue2.AsInt64);
     {$ENDIF}

     uvtPointer: Result := AValue1.PointerValue = AValue2.PointerValue;
     else Result := False;
    end;

   else Result := False;
  end;
end;

class operator RGMGenericUnionValue<TStrType>.NotEqual(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
begin
  Result := not (AValue1 = AValue2);
end;

class operator RGMGenericUnionValue<TStrType>.Add(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;
begin
  case AValue1.ValueType of
   uvtInt16, uvtInt32, uvtInt64:
    case AValue2.ValueType of
     uvtInt16, uvtInt32, uvtInt64: Result := AValue1.AsInt64 + AValue2.AsInt64;
     else Result := AValue1.AsDouble + AValue2.AsDouble;
    end;
   else Result := AValue1.AsDouble + AValue2.AsDouble;
  end;
end;

class operator RGMGenericUnionValue<TStrType>.Multiply(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;
begin
  case AValue1.ValueType of
   uvtInt16, uvtInt32, uvtInt64:
    case AValue2.ValueType of
     uvtInt16, uvtInt32, uvtInt64: Result := AValue1.AsInt64 * AValue2.AsInt64;
     else Result := AValue1.AsDouble * AValue2.AsDouble;
    end;
   else Result := AValue1.AsDouble * AValue2.AsDouble;
  end;
end;

class operator RGMGenericUnionValue<TStrType>.Divide(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;
begin
  case AValue1.ValueType of
   uvtInt16, uvtInt32, uvtInt64:
    case AValue2.ValueType of
     uvtInt16, uvtInt32, uvtInt64: Result := AValue1.AsInt64 / AValue2.AsInt64;
     else Result := AValue1.AsDouble / AValue2.AsDouble;
    end;
   else Result := AValue1.AsDouble / AValue2.AsDouble;
  end;
end;

class operator RGMGenericUnionValue<TStrType>.IntDivide(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;
begin
  Result := AValue1.AsInt64 div AValue2.AsInt64;
end;

class operator RGMGenericUnionValue<TStrType>.Modulus(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): RGMGenericUnionValue<TStrType>;
begin
  Result := AValue1.AsInt64 mod AValue2.AsInt64;
end;

class operator RGMGenericUnionValue<TStrType>.LessThan(const AValue1, AValue2: RGMGenericUnionValue<TStrType> ): Boolean;
begin
  case AValue1.ValueType of
   uvtUnassigned, uvtNull: Result := AValue2.ValueType > uvtNull;
   uvtString:
    case AValue2.ValueType of
     uvtString: Result := GMCompareNames(AValue1.StringValue, AValue2.StringValue) = crALessThanB; // TStrType()
     uvtBoolean, uvtInt16, uvtInt32, uvtInt64, uvtDouble, uvtDateTime: Result := GMCompareNames(AValue1.StringValue, AValue2.AsString) = crALessThanB; // TStrType()
     else Result := False;
    end;

   uvtBoolean:
    case AValue2.ValueType of
     uvtBoolean: Result := AValue1.BoolValue < AValue2.BoolValue;
     uvtInt16, uvtInt32, uvtInt64: Result := AValue1.BoolValue < (AValue2.AsInt64 <> 0);
     uvtdouble: Result := AValue1.BoolValue < (AVAlue2.DoubleValue <> 0);
     uvtString: Result := AValue1.BoolValue < GMStrToBool(AValue2.StringValue); // TStrType()
     else Result := False;
    end;

   uvtInt16, uvtInt32, uvtInt64:
    case AValue2.ValueType of
     //uvtString: Result := AValue1.AsInt64 =
     //uvtBoolean,
     //uvtString: Result
     uvtInt16, uvtInt32, uvtInt64: Result := AValue1.AsInt64 < AValue2.AsInt64;
     uvtDouble, uvtDateTime: Result := AValue1.AsInt64 < AValue2.DoubleValue;
     else Result := False;
    end;

   uvtDouble, uvtDateTime:
    case AValue2.ValueType of
     //uvtString, uvtBoolean,
     //uvtString,
     uvtInt16, uvtInt32, uvtInt64: Result := AValue1.DoubleValue < AValue2.AsInt64;
     uvtDouble, uvtDateTime: Result := AValue1.DoubleValue < AValue2.DoubleValue;
     else Result := False;
    end;

   uvtPointer:
    case AValue2.ValueType of
     {$IFDEF CPU32}
      uvtInt32: Result := PtrUInt(AValue1.PointerValue) < PtrUInt(AValue2.AsInt32);
     {$ENDIF}
     {$IFDEF CPU64}
      uvtInt64: Result := PtrUInt(AValue1.PointerValue) < PtrUInt(AValue2.AsInt64);
     {$ENDIF}

     uvtPointer: Result := AValue1.PointerValue < AValue2.PointerValue;
     else Result := False;
    end;

   else Result := False;
  end;
end;

class operator RGMGenericUnionValue<TStrType>.GreaterThan(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
begin
  Result := not ((AValue1 < AValue2) or (AValue1 = AValue2));
end;

class operator RGMGenericUnionValue<TStrType>.LessThanOrEqual(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
begin
  Result := (AValue1 < AValue2) or (AValue1 = AValue2);
end;

class operator RGMGenericUnionValue<TStrType>.GreaterThanOrEqual(const AValue1, AValue2: RGMGenericUnionValue<TStrType>): Boolean;
begin
  Result := not (AValue1 < AValue2); // (AValue1 > AValue2) or (AValue1 = AValue2);
end;

function RGMGenericUnionValue<TStrType>.AsBoolean: Boolean;
begin
  Result := Self;
end;

function RGMGenericUnionValue<TStrType>.AsInt16: SmallInt;
begin
  Result := Self;
end;

function RGMGenericUnionValue<TStrType>.AsInt32: LongInt;
begin
  Result := Self;
end;

function RGMGenericUnionValue<TStrType>.AsInt64: Int64;
begin
  Result := Self;
end;

function RGMGenericUnionValue<TStrType>.AsDouble: Double;
begin
  Result := Self;
end;

function RGMGenericUnionValue<TStrType>.AsDateTime: TDateTime;
begin
  Result := Self;
end;

function RGMGenericUnionValue<TStrType>.AsString: TGMString;
begin
  Result := Self;
end;

function RGMGenericUnionValue<TStrType>.AsPointer: Pointer;
begin
  Result := Self;
end;

//function RGMGenericUnionValue<TStrType>.AsDisplayString: TGMString;
//begin
//  case ValueType of
//   uvtUnassigned, uvtNull: Result := '';
//   else Result := Self;
//  end;
//end;

function RGMGenericUnionValue<TStrType>.AsBooleanDflt(const ADefaultValue: Boolean): Boolean;
begin
  case ValueType of
   uvtUnassigned, uvtNull: Result := ADefaultValue;
   else Result := Self;
  end;
end;

function RGMGenericUnionValue<TStrType>.AsInt16Dflt(const ADefaultValue: SmallInt): SmallInt;
begin
  case ValueType of
   uvtUnassigned, uvtNull: Result := ADefaultValue;
   else Result := Self;
  end;
end;

function RGMGenericUnionValue<TStrType>.AsInt32Dflt(const ADefaultValue: LongInt): LongInt;
begin
  case ValueType of
   uvtUnassigned, uvtNull: Result := ADefaultValue;
   else Result := Self;
  end;
end;

function RGMGenericUnionValue<TStrType>.AsInt64Dflt(const ADefaultValue: Int64): Int64;
begin
  case ValueType of
   uvtUnassigned, uvtNull: Result := ADefaultValue;
   else Result := Self;
  end;
end;

function RGMGenericUnionValue<TStrType>.AsDoubleDflt(const ADefaultValue: Double): Double;
begin
  case ValueType of
   uvtUnassigned, uvtNull: Result := ADefaultValue;
   else Result := Self;
  end;
end;

function RGMGenericUnionValue<TStrType>.AsDateTimeDflt(const ADefaultValue: TDateTime): TDateTime;
begin
  case ValueType of
   uvtUnassigned, uvtNull: Result := ADefaultValue;
   else Result := Self;
  end;
end;

function RGMGenericUnionValue<TStrType>.AsPointerDflt(const ADefaultValue: Pointer): Pointer;
begin
  case ValueType of
   uvtUnassigned, uvtNull: Result := ADefaultValue;
   else Result := Self;
  end;
end;

function RGMGenericUnionValue<TStrType>.AsStringDflt(const ADefaultValue: TGMString): TGMString;
begin
  case ValueType of
   uvtUnassigned, uvtNull: Result := ADefaultValue;
   else Result := Self;
  end;
end;


end.