unit Myc.Data.Value; interface uses System.SysUtils, Myc.Data.Scalar, Myc.Data.Series, Myc.Data.Decimal; type TDataValueKind = (vkVoid, vkScalar, vkInterface, vkText, vkSeries, vkRecordSeries, vkRecord, vkMemberSeries, vkGeneric); TDataValue = record public type TVal = class(TInterfacedObject) Value: T; constructor Create(const AValue: T); end; private var FKind: TDataValueKind; FScalar: TScalar; FInterface: IInterface; function GetKind: TDataValueKind; inline; function GetIsVoid: Boolean; inline; public class operator Initialize(out Dest: TDataValue); class function Void: TDataValue; inline; static; class operator Implicit(const AValue: TScalar): TDataValue; overload; inline; class operator Implicit(const AValue: String): TDataValue; overload; inline; class operator Implicit(const AValue: IInterface): TDataValue; overload; inline; class function From(const [ref] AValue: T): TDataValue; static; inline; function AsVal: TVal; inline; class function FromSeries(const [ref] AValue: TScalarSeries): TDataValue; static; inline; class function FromRecordSeries(const [ref] AValue: TScalarRecordSeries): TDataValue; static; inline; class function FromRecord(const [ref] AValue: TScalarRecord): TDataValue; static; inline; class function FromMemberSeries(const [ref] AValue: TScalarMemberSeries): TDataValue; static; inline; function AsScalar: TScalar; inline; function AsInterface: IInterface; inline; function AsText: String; inline; function AsRecordSeries: TVal; inline; function AsRecord: TVal; inline; function AsMemberSeries: TVal; inline; function AsSeries: TVal; inline; procedure SetVoid; function ToString: String; property IsVoid: Boolean read GetIsVoid; property Kind: TDataValueKind read GetKind; end; implementation uses TypInfo; { TDataValue.TVal } constructor TDataValue.TVal.Create(const AValue: T); begin inherited Create; Value := AValue; end; { TDataValue } class operator TDataValue.Initialize(out Dest: TDataValue); begin Dest.FKind := vkVoid; Dest.FInterface := nil; end; function TDataValue.AsInterface: IInterface; begin if (FKind <> vkInterface) then raise EInvalidCast.Create('Cannot read value as an Interface.'); Result := FInterface; end; function TDataValue.AsMemberSeries: TVal; begin if (FKind <> vkMemberSeries) then raise EInvalidCast.Create('Cannot read value as MemberSeries.'); Result := TVal(FInterface); end; function TDataValue.AsVal: TVal; begin if (FKind <> vkGeneric) then raise EInvalidCast.Create('Cannot read value as ' + PTypeInfo(TypeInfo(T)).Name + '.'); Result := TVal(FInterface); end; function TDataValue.AsRecord: TVal; begin if (FKind <> vkRecord) then raise EInvalidCast.Create('Cannot read value as Record.'); Result := (FInterface as TVal); end; function TDataValue.AsRecordSeries: TVal; begin if (FKind <> vkRecordSeries) then raise EInvalidCast.Create('Cannot read value as RecordSeries.'); Result := TVal(FInterface); end; function TDataValue.AsScalar: TScalar; begin if (FKind <> vkScalar) then raise EInvalidCast.Create('Cannot read value as a Scalar.'); Result := FScalar; end; function TDataValue.AsSeries: TVal; begin if (FKind <> vkSeries) then raise EInvalidCast.Create('Cannot read value as Series.'); Result := TVal(FInterface); end; function TDataValue.AsText: String; begin if (FKind <> vkText) then raise EInvalidCast.Create('Cannot read value as Text.'); Result := (FInterface as TVal).Value; end; class function TDataValue.From(const [ref] AValue: T): TDataValue; begin Result.FKind := vkGeneric; Result.FInterface := TVal.Create(AValue); end; class function TDataValue.FromMemberSeries(const [ref] AValue: TScalarMemberSeries): TDataValue; begin Result.FKind := vkMemberSeries; Result.FInterface := TVal.Create(AValue); Result.FScalar := Default(TScalar); end; class function TDataValue.FromRecord(const [ref] AValue: TScalarRecord): TDataValue; begin Result.FKind := vkRecord; Result.FInterface := TVal.Create(AValue); Result.FScalar := Default(TScalar); end; class function TDataValue.FromRecordSeries(const [ref] AValue: TScalarRecordSeries): TDataValue; begin Result.FKind := vkRecordSeries; Result.FInterface := TVal.Create(AValue); Result.FScalar := Default(TScalar); end; class function TDataValue.FromSeries(const [ref] AValue: TScalarSeries): TDataValue; begin Result.FKind := vkSeries; Result.FInterface := TVal.Create(AValue); Result.FScalar := Default(TScalar); end; class operator TDataValue.Implicit(const AValue: IInterface): TDataValue; begin Result.FKind := vkInterface; Result.FInterface := AValue; Result.FScalar := Default(TScalar); end; class operator TDataValue.Implicit(const AValue: TScalar): TDataValue; begin Result.FKind := vkScalar; Result.FScalar := AValue; Result.FInterface := nil; end; class operator TDataValue.Implicit(const AValue: String): TDataValue; begin Result.FKind := vkText; Result.FInterface := TVal.Create(AValue); Result.FScalar := Default(TScalar); end; function TDataValue.GetIsVoid: Boolean; begin Result := FKind = vkVoid; end; function TDataValue.GetKind: TDataValueKind; begin Result := FKind; end; procedure TDataValue.SetVoid; begin FKind := vkVoid; FInterface := nil; end; function TDataValue.ToString: String; begin case FKind of vkScalar: Result := FScalar.ToString; vkInterface: Result := ''; vkText: Result := AsText; vkSeries: Result := ''; vkRecordSeries: Result := ''; vkRecord: Result := ''; vkMemberSeries: Result := ''; vkVoid: Result := ''; else Result := '[Unknown DataValue]'; end; end; class function TDataValue.Void: TDataValue; begin Result := Default(TDataValue); end; end.