Files
MycLib/Src/Data/Myc.Data.Types.pas
T
2025-08-26 13:55:10 +02:00

1257 lines
41 KiB
ObjectPascal

unit Myc.Data.Types;
interface
uses
System.Generics.Collections,
System.SysUtils,
System.RTTI;
type
TDataKind = (dkVoid, dkOrdinal, dkFloat, dkText, dkTimestamp, dkDecimal, dkRecord, dkTuple, dkArray, dkEnum, dkMethod);
IDataType = interface
{$region 'private'}
function GetName: String;
function GetKind: TDataKind;
{$endregion}
property Name: String read GetName;
property Kind: TDataKind read GetKind;
end;
IDataValue = interface
{$region 'private'}
function GetDataType: IDataType;
function GetAsString: string;
{$endregion}
function AsTValue: TValue;
property DataType: IDataType read GetDataType;
property AsString: string read GetAsString;
end;
IDataVoidValue = interface(IDataValue)
end;
IDataVoidType = interface(IDataType)
function GetValue: IDataVoidValue;
property Value: IDataVoidValue read GetValue;
end;
IDataOrdinalValue = interface(IDataValue)
{$region 'private'}
function GetValue: Int64;
{$endregion}
property Value: Int64 read GetValue;
end;
IDataOrdinalType = interface(IDataType)
function CreateValue(Init: Int64): IDataOrdinalValue;
end;
IDataFloatValue = interface(IDataValue)
{$region 'private'}
function GetValue: Double;
{$endregion}
property Value: Double read GetValue;
end;
IDataFloatType = interface(IDataType)
function CreateValue(Init: Double): IDataFloatValue;
end;
IDataTextValue = interface(IDataValue)
{$region 'private'}
function GetValue: string;
{$endregion}
property Value: string read GetValue;
end;
IDataTextType = interface(IDataType)
function CreateValue(const AValue: string): IDataTextValue;
end;
IDataTimestampValue = interface(IDataValue)
{$region 'private'}
function GetValue: TDateTime;
{$endregion}
property Value: TDateTime read GetValue;
end;
IDataTimestampType = interface(IDataType)
function CreateValue(const AValue: TDateTime): IDataTimestampValue;
end;
// Represents a fixed-point decimal data value.
IDataDecimalValue = interface(IDataValue)
{$region 'private'}
function GetValue: Int64;
{$endregion}
property Value: Int64 read GetValue;
end;
// Represents the type of a fixed-point decimal data value.
IDataDecimalType = interface(IDataType)
{$region 'private'}
function GetScale: Integer;
{$endregion}
function CreateValue(const AValue: Int64): IDataDecimalValue;
property Scale: Integer read GetScale;
end;
IDataEnumValue = interface(IDataValue)
{$region 'private'}
function GetValue: Integer;
{$endregion}
property Value: Integer read GetValue;
end;
IDataEnumType = interface(IDataType)
{$region 'private'}
function GetIdentifier(Idx: Integer): string;
function GetIdentifierCount: Integer;
{$endregion}
function IndexOf(const AIdentifier: string): Integer;
function CreateValue(const AValue: Integer): IDataEnumValue;
property IdentifierCount: Integer read GetIdentifierCount;
property Identifiers[Idx: Integer]: string read GetIdentifier; default;
end;
// A method that transforms one data value into another.
TDataMethodProc = reference to function(const AValue: IDataValue): IDataValue;
// Represents an executable method data value.
IDataMethodValue = interface(IDataValue)
{$region 'private'}
function GetValue: TDataMethodProc;
{$endregion}
property Value: TDataMethodProc read GetValue;
end;
// Represents the type of a method data value, including its signature.
IDataMethodType = interface(IDataType)
{$region 'private'}
function GetArgType: IDataType;
function GetResultType: IDataType;
{$endregion}
property ArgType: IDataType read GetArgType;
property ResultType: IDataType read GetResultType;
function CreateValue(const AValue: TDataMethodProc): IDataMethodValue;
end;
IDataRecordValue = interface(IDataValue)
{$region 'private'}
function GetItem(Idx: Integer): IDataValue;
{$endregion}
property Items[Idx: Integer]: IDataValue read GetItem; default;
end;
TRecordField = record
DataType: IDataType;
Name: string;
constructor Create(const AName: string; const ADataType: IDataType);
end;
IDataRecordType = interface(IDataType)
{$region 'private'}
function GetFieldCount: Integer;
function GetField(Idx: Integer): TRecordField;
{$endregion}
function IndexOf(const AName: string): Integer;
function CreateValue(const AItems: array of IDataValue): IDataRecordValue;
property FieldCount: Integer read GetFieldCount;
property Fields[Idx: Integer]: TRecordField read GetField; default;
end;
IDataTupleValue = interface(IDataValue)
{$region 'private'}
function GetItemCount: Integer;
function GetItem(Idx: Integer): IDataValue;
{$endregion}
property ItemCount: Integer read GetItemCount;
property Items[Idx: Integer]: IDataValue read GetItem; default;
end;
IDataTupleType = interface(IDataType)
function CreateValue(const AItems: array of IDataValue): IDataTupleValue;
end;
IDataArrayValue = interface(IDataValue)
{$region 'private'}
function GetElementCount: Integer;
function GetItem(Idx: Integer): IDataValue;
{$endregion}
property ElementCount: Integer read GetElementCount;
property Items[Idx: Integer]: IDataValue read GetItem; default;
end;
IDataArrayType = interface(IDataType)
{$region 'private'}
function GetElementType: IDataType;
{$endregion}
function CreateValue(const AItems: array of IDataValue): IDataArrayValue;
property ElementType: IDataType read GetElementType;
end;
TDataType = record
type
TValue = record
private
FDataValue: IDataValue;
function GetDataType: IDataType; inline;
public
constructor Create(const ADataValue: IDataValue);
// Casting
function AsOrdinal: IDataOrdinalValue; inline;
function AsFloat: IDataFloatValue; inline;
function AsText: IDataTextValue; inline;
function AsTimestamp: IDataTimestampValue; inline;
function AsDecimal: IDataDecimalValue; inline;
function AsRecord: IDataRecordValue; inline;
function AsTuple: IDataTupleValue; inline;
function AsArray: IDataArrayValue; inline;
function AsEnum: IDataEnumValue; inline;
function AsMethod: IDataMethodValue; inline;
function AsVoid: IDataVoidValue; inline;
class operator Implicit(const A: IDataValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: TDataType.TValue): IDataValue; overload; inline;
class operator Implicit(const A: IDataOrdinalValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataFloatValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataTextValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataTimestampValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataDecimalValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataEnumValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataMethodValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataRecordValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataTupleValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataArrayValue): TDataType.TValue; overload; inline;
class operator Implicit(const A: IDataVoidValue): TDataType.TValue; overload; inline;
property DataValue: IDataValue read FDataValue;
property DataType: IDataType read GetDataType;
end;
TVoid = record
private
FVoidType: IDataVoidType;
function GetValue: IDataVoidValue; inline;
public
constructor Create(const AVoidType: IDataVoidType);
class operator Implicit(const A: IDataVoidType): TDataType.TVoid; overload; inline;
class operator Implicit(const A: TDataType.TVoid): IDataVoidType; overload; inline;
property Value: IDataVoidValue read GetValue;
end;
TOrdinal = record
private
FOrdinalType: IDataOrdinalType;
public
constructor Create(const AOrdinalType: IDataOrdinalType);
class operator Implicit(const A: IDataOrdinalType): TDataType.TOrdinal; overload; inline;
class operator Implicit(const A: TDataType.TOrdinal): IDataOrdinalType; overload; inline;
function CreateValue(Init: Int64): IDataOrdinalValue; inline;
end;
TFloat = record
private
FFloatType: IDataFloatType;
public
constructor Create(const AFloatType: IDataFloatType);
class operator Implicit(const A: IDataFloatType): TDataType.TFloat; overload; inline;
class operator Implicit(const A: TDataType.TFloat): IDataFloatType; overload; inline;
function CreateValue(Init: Double): IDataFloatValue; inline;
end;
TText = record
private
FTextType: IDataTextType;
public
constructor Create(const ATextType: IDataTextType);
class operator Implicit(const A: IDataTextType): TDataType.TText; overload; inline;
class operator Implicit(const A: TDataType.TText): IDataTextType; overload; inline;
function CreateValue(const AValue: string): IDataTextValue; inline;
end;
TTimestamp = record
private
FTimestampType: IDataTimestampType;
public
constructor Create(const ATimestampType: IDataTimestampType);
class operator Implicit(const A: IDataTimestampType): TDataType.TTimestamp; overload; inline;
class operator Implicit(const A: TDataType.TTimestamp): IDataTimestampType; overload; inline;
function CreateValue(const AValue: TDateTime): IDataTimestampValue; inline;
end;
TDecimal = record
type
TValue = record
private
// The wrapped interface instance.
FDecimalValue: IDataDecimalValue;
function GetValue: Int64; inline;
public
constructor Create(const ADecimalValue: IDataDecimalValue);
class operator Implicit(const A: IDataDecimalValue): TDataType.TDecimal.TValue; overload; inline;
class operator Implicit(const A: TDataType.TDecimal.TValue): IDataDecimalValue; overload; inline;
property Value: Int64 read GetValue;
end;
private
FDecimalType: IDataDecimalType;
function GetScale: Integer; inline;
public
constructor Create(const ADecimalType: IDataDecimalType);
class operator Implicit(const A: IDataDecimalType): TDataType.TDecimal; overload; inline;
class operator Implicit(const A: TDataType.TDecimal): IDataDecimalType; overload; inline;
function CreateValue(const AValue: Int64): TDataType.TDecimal.TValue; inline;
property Scale: Integer read GetScale;
end;
TEnum = record
private
FEnumType: IDataEnumType;
function GetIdentifier(Idx: Integer): string; inline;
function GetIdentifierCount: Integer; inline;
public
constructor Create(const AEnumType: IDataEnumType);
class operator Implicit(const A: IDataEnumType): TDataType.TEnum; overload; inline;
class operator Implicit(const A: TDataType.TEnum): IDataEnumType; overload; inline;
function IndexOf(const AIdentifier: string): Integer; inline;
function CreateValue(const AValue: Integer): IDataEnumValue; overload; inline;
function CreateValue(const AIdentifier: string): IDataEnumValue; overload; inline;
property IdentifierCount: Integer read GetIdentifierCount;
property Identifiers[Idx: Integer]: string read GetIdentifier; default;
end;
TRecord = record
private
FRecordType: IDataRecordType;
function GetFieldCount: Integer; inline;
function GetField(Idx: Integer): TRecordField; inline;
public
constructor Create(const ARecordType: IDataRecordType);
class operator Implicit(const A: IDataRecordType): TDataType.TRecord; overload; inline;
class operator Implicit(const A: TDataType.TRecord): IDataRecordType; overload; inline;
function IndexOf(const AName: string): Integer; inline;
function CreateValue(const AItems: array of IDataValue): IDataRecordValue;
property FieldCount: Integer read GetFieldCount;
property Fields[Idx: Integer]: TRecordField read GetField; default;
end;
TTuple = record
private
FTupleType: IDataTupleType;
public
constructor Create(const ATupleType: IDataTupleType);
class operator Implicit(const A: IDataTupleType): TDataType.TTuple; overload; inline;
class operator Implicit(const A: TDataType.TTuple): IDataTupleType; overload; inline;
function CreateValue(const AItems: array of IDataValue): IDataTupleValue;
end;
TArray = record
private
FArrayType: IDataArrayType;
function GetElementType: IDataType; inline;
public
constructor Create(const AArrayType: IDataArrayType);
class operator Implicit(const A: IDataArrayType): TDataType.TArray; overload; inline;
class operator Implicit(const A: TDataType.TArray): IDataArrayType; overload; inline;
function CreateValue(const AItems: array of IDataValue): IDataArrayValue;
property ElementType: IDataType read GetElementType;
end;
TMethod = record
type
TProc = reference to function(const AValue: TDataType.TValue): TDataType.TValue;
private
FMethodType: IDataMethodType;
function GetArgType: IDataType; inline;
function GetResultType: IDataType; inline;
public
constructor Create(const AMethodType: IDataMethodType);
class operator Implicit(const A: IDataMethodType): TDataType.TMethod; overload; inline;
class operator Implicit(const A: TDataType.TMethod): IDataMethodType; overload; inline;
property ArgType: IDataType read GetArgType;
property ResultType: IDataType read GetResultType;
function CreateValue(const Proc: TProc): IDataMethodValue; inline;
end;
strict private
FDataType: IDataType;
function GetName: String; inline;
function GetKind: TDataKind; inline;
class var
FArrayTypeRegistry: TDictionary<IDataType, IDataArrayType>;
FRecordTypeRegistry: TDictionary<TArray<TRecordField>, IDataRecordType>;
FMethodTypeRegistry: TDictionary<TPair<IDataType, IDataType>, IDataMethodType>;
FDecimalTypes: TArray<IDataDecimalType>;
class constructor CreateClass;
class destructor DestroyClass;
public
constructor Create(const ADataType: IDataType);
class operator Implicit(const A: IDataType): TDataType; overload; inline;
class operator Implicit(const A: TDataType): IDataType; overload; inline;
class operator Implicit(const A: TDataType.TVoid): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TOrdinal): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TFloat): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TText): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TTimestamp): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TDecimal): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TEnum): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TMethod): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TRecord): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TTuple): TDataType; overload; inline;
class operator Implicit(const A: TDataType.TArray): TDataType; overload; inline;
// Type factories
class function Void: TDataType.TVoid; static; inline;
class function Ordinal: TDataType.TOrdinal; static; inline;
class function Float: TDataType.TFloat; static; inline;
class function Text: TDataType.TText; static; inline;
class function Timestamp: TDataType.TTimestamp; static; inline;
class function DecimalOf(const AScale: Integer): TDataType.TDecimal; static;
class function Tuple: TDataType.TTuple; static; inline;
class function MethodOf(const AArgType, AResultType: IDataType): TDataType.TMethod; static;
class function ArrayOf(const AElementType: IDataType): TDataType.TArray; static;
class function RecordOf(const Fields: TArray<TRecordField>): TDataType.TRecord; overload; static;
class function RecordOf(const Fields: array of TRecordField): TDataType.TRecord; overload; static;
class function EnumOf(const AName: string; const AIdentifiers: array of string): TDataType.TEnum; static;
function AsOrdinal: TDataType.TOrdinal; inline;
function AsFloat: TDataType.TFloat; inline;
function AsText: TDataType.TText; inline;
function AsTimestamp: TDataType.TTimestamp; inline;
function AsDecimal: TDataType.TDecimal; inline;
function AsRecord: TDataType.TRecord; inline;
function AsTuple: TDataType.TTuple; inline;
function AsArray: TDataType.TArray; inline;
function AsEnum: TDataType.TEnum; inline;
function AsMethod: TDataType.TMethod; inline;
property DataType: IDataType read FDataType;
property Name: String read GetName;
property Kind: TDataKind read GetKind;
end;
implementation
uses
System.SyncObjs,
System.Generics.Defaults,
Myc.Data.Types.Void,
Myc.Data.Types.Ordinal,
Myc.Data.Types.Float,
Myc.Data.Types.Text,
Myc.Data.Types.Timestamp,
Myc.Data.Types.Decimal,
Myc.Data.Types.Arrays,
Myc.Data.Types.Records,
Myc.Data.Types.Tuple,
Myc.Data.Types.Enum,
Myc.Data.Types.Method;
{ TRecordField }
constructor TRecordField.Create(const AName: string; const ADataType: IDataType);
begin
Name := AName;
DataType := ADataType;
end;
{ TDataType.TDecimal.TValue }
constructor TDataType.TDecimal.TValue.Create(const ADecimalValue: IDataDecimalValue);
begin
FDecimalValue := ADecimalValue;
end;
function TDataType.TDecimal.TValue.GetValue: Int64;
begin
Result := FDecimalValue.Value;
end;
class operator TDataType.TDecimal.TValue.Implicit(const A: IDataDecimalValue): TDataType.TDecimal.TValue;
begin
Result.FDecimalValue := A;
end;
class operator TDataType.TDecimal.TValue.Implicit(const A: TDataType.TDecimal.TValue): IDataDecimalValue;
begin
Result := A.FDecimalValue;
end;
{ TDataType.TVoid }
constructor TDataType.TVoid.Create(const AVoidType: IDataVoidType);
begin
FVoidType := AVoidType;
end;
function TDataType.TVoid.GetValue: IDataVoidValue;
begin
Result := FVoidType.Value;
end;
class operator TDataType.TVoid.Implicit(const A: IDataVoidType): TDataType.TVoid;
begin
Result.FVoidType := A;
end;
class operator TDataType.TVoid.Implicit(const A: TDataType.TVoid): IDataVoidType;
begin
Result := A.FVoidType;
end;
{ TDataType.TOrdinal }
constructor TDataType.TOrdinal.Create(const AOrdinalType: IDataOrdinalType);
begin
FOrdinalType := AOrdinalType;
end;
function TDataType.TOrdinal.CreateValue(Init: Int64): IDataOrdinalValue;
begin
Result := FOrdinalType.CreateValue(Init);
end;
class operator TDataType.TOrdinal.Implicit(const A: TDataType.TOrdinal): IDataOrdinalType;
begin
Result := A.FOrdinalType;
end;
class operator TDataType.TOrdinal.Implicit(const A: IDataOrdinalType): TDataType.TOrdinal;
begin
Result.FOrdinalType := A;
end;
{ TDataType.TFloat }
constructor TDataType.TFloat.Create(const AFloatType: IDataFloatType);
begin
FFloatType := AFloatType;
end;
function TDataType.TFloat.CreateValue(Init: Double): IDataFloatValue;
begin
Result := FFloatType.CreateValue(Init);
end;
class operator TDataType.TFloat.Implicit(const A: IDataFloatType): TDataType.TFloat;
begin
Result.FFloatType := A;
end;
class operator TDataType.TFloat.Implicit(const A: TDataType.TFloat): IDataFloatType;
begin
Result := A.FFloatType;
end;
{ TDataType.TText }
constructor TDataType.TText.Create(const ATextType: IDataTextType);
begin
FTextType := ATextType;
end;
function TDataType.TText.CreateValue(const AValue: string): IDataTextValue;
begin
Result := FTextType.CreateValue(AValue);
end;
class operator TDataType.TText.Implicit(const A: IDataTextType): TDataType.TText;
begin
Result.FTextType := A;
end;
class operator TDataType.TText.Implicit(const A: TDataType.TText): IDataTextType;
begin
Result := A.FTextType;
end;
{ TDataType.TTimestamp }
constructor TDataType.TTimestamp.Create(const ATimestampType: IDataTimestampType);
begin
FTimestampType := ATimestampType;
end;
function TDataType.TTimestamp.CreateValue(const AValue: TDateTime): IDataTimestampValue;
begin
Result := FTimestampType.CreateValue(AValue);
end;
class operator TDataType.TTimestamp.Implicit(const A: IDataTimestampType): TDataType.TTimestamp;
begin
Result.FTimestampType := A;
end;
class operator TDataType.TTimestamp.Implicit(const A: TDataType.TTimestamp): IDataTimestampType;
begin
Result := A.FTimestampType;
end;
{ TDataType.TDecimal }
constructor TDataType.TDecimal.Create(const ADecimalType: IDataDecimalType);
begin
FDecimalType := ADecimalType;
end;
function TDataType.TDecimal.CreateValue(const AValue: Int64): TDataType.TDecimal.TValue;
begin
Result.Create(FDecimalType.CreateValue(AValue));
end;
function TDataType.TDecimal.GetScale: Integer;
begin
Result := FDecimalType.Scale;
end;
class operator TDataType.TDecimal.Implicit(const A: IDataDecimalType): TDataType.TDecimal;
begin
Result.FDecimalType := A;
end;
class operator TDataType.TDecimal.Implicit(const A: TDataType.TDecimal): IDataDecimalType;
begin
Result := A.FDecimalType;
end;
{ TDataType.TEnum }
constructor TDataType.TEnum.Create(const AEnumType: IDataEnumType);
begin
FEnumType := AEnumType;
end;
function TDataType.TEnum.CreateValue(const AValue: Integer): IDataEnumValue;
begin
Result := FEnumType.CreateValue(AValue);
end;
function TDataType.TEnum.CreateValue(const AIdentifier: string): IDataEnumValue;
var
idx: Integer;
begin
idx := IndexOf(AIdentifier);
if idx < 0 then
raise EArgumentException.CreateFmt('Unknown identifier: %s', [AIdentifier]);
Result := CreateValue(idx);
end;
function TDataType.TEnum.GetIdentifier(Idx: Integer): string;
begin
Result := FEnumType.GetIdentifier(Idx);
end;
function TDataType.TEnum.GetIdentifierCount: Integer;
begin
Result := FEnumType.IdentifierCount;
end;
function TDataType.TEnum.IndexOf(const AIdentifier: string): Integer;
begin
Result := FEnumType.IndexOf(AIdentifier);
end;
class operator TDataType.TEnum.Implicit(const A: IDataEnumType): TDataType.TEnum;
begin
Result.FEnumType := A;
end;
class operator TDataType.TEnum.Implicit(const A: TDataType.TEnum): IDataEnumType;
begin
Result := A.FEnumType;
end;
{ TDataType.TMethod }
constructor TDataType.TMethod.Create(const AMethodType: IDataMethodType);
begin
FMethodType := AMethodType;
end;
function TDataType.TMethod.CreateValue(const Proc: TProc): IDataMethodValue;
begin
if not Assigned(Proc) then
raise EArgumentException.Create('Proc');
var cProc: TProc := Proc;
Result := FMethodType.CreateValue(function(const Value: IDataValue): IDataValue begin Result := cProc(Value); end);
end;
function TDataType.TMethod.GetArgType: IDataType;
begin
Result := FMethodType.ArgType;
end;
function TDataType.TMethod.GetResultType: IDataType;
begin
Result := FMethodType.ResultType;
end;
class operator TDataType.TMethod.Implicit(const A: IDataMethodType): TDataType.TMethod;
begin
Result.FMethodType := A;
end;
class operator TDataType.TMethod.Implicit(const A: TDataType.TMethod): IDataMethodType;
begin
Result := A.FMethodType;
end;
{ TDataType.TRecord }
constructor TDataType.TRecord.Create(const ARecordType: IDataRecordType);
begin
FRecordType := ARecordType;
end;
function TDataType.TRecord.CreateValue(const AItems: array of IDataValue): IDataRecordValue;
begin
Result := FRecordType.CreateValue(AItems);
end;
function TDataType.TRecord.GetField(Idx: Integer): TRecordField;
begin
Result := FRecordType.GetField(Idx);
end;
function TDataType.TRecord.GetFieldCount: Integer;
begin
Result := FRecordType.FieldCount;
end;
function TDataType.TRecord.IndexOf(const AName: string): Integer;
begin
Result := FRecordType.IndexOf(AName);
end;
class operator TDataType.TRecord.Implicit(const A: IDataRecordType): TDataType.TRecord;
begin
Result.FRecordType := A;
end;
class operator TDataType.TRecord.Implicit(const A: TDataType.TRecord): IDataRecordType;
begin
Result := A.FRecordType;
end;
{ TDataType.TTuple }
constructor TDataType.TTuple.Create(const ATupleType: IDataTupleType);
begin
FTupleType := ATupleType;
end;
function TDataType.TTuple.CreateValue(const AItems: array of IDataValue): IDataTupleValue;
begin
Result := FTupleType.CreateValue(AItems);
end;
class operator TDataType.TTuple.Implicit(const A: IDataTupleType): TDataType.TTuple;
begin
Result.FTupleType := A;
end;
class operator TDataType.TTuple.Implicit(const A: TDataType.TTuple): IDataTupleType;
begin
Result := A.FTupleType;
end;
{ TDataType.TArray }
constructor TDataType.TArray.Create(const AArrayType: IDataArrayType);
begin
FArrayType := AArrayType;
end;
function TDataType.TArray.CreateValue(const AItems: array of IDataValue): IDataArrayValue;
begin
Result := FArrayType.CreateValue(AItems);
end;
function TDataType.TArray.GetElementType: IDataType;
begin
Result := FArrayType.ElementType;
end;
class operator TDataType.TArray.Implicit(const A: IDataArrayType): TDataType.TArray;
begin
Result.FArrayType := A;
end;
class operator TDataType.TArray.Implicit(const A: TDataType.TArray): IDataArrayType;
begin
Result := A.FArrayType;
end;
{ TDataType }
constructor TDataType.Create(const ADataType: IDataType);
begin
Assert(Assigned(ADataType));
FDataType := ADataType;
end;
class constructor TDataType.CreateClass;
var
i: Integer;
begin
FArrayTypeRegistry := TDictionary<IDataType, IDataArrayType>.Create;
FRecordTypeRegistry := TDictionary<TArray<TRecordField>, IDataRecordType>.Create(TRecordFieldComparer.Create);
SetLength(FDecimalTypes, 19);
for i := 0 to 18 do
FDecimalTypes[i] := TImplDataDecimalType.Create(i);
FMethodTypeRegistry :=
TDictionary<TPair<IDataType, IDataType>, IDataMethodType>.Create(
TEqualityComparer<TPair<IDataType, IDataType>>.Construct(
function(const Left, Right: TPair<IDataType, IDataType>): Boolean
begin
Result := (Left.Key = Right.Key) and (Left.Value = Right.Value);
end,
function(const Value: TPair<IDataType, IDataType>): Integer
var
hash1, hash2: NativeInt;
begin
hash1 := NativeInt(Value.Key);
hash2 := NativeInt(Value.Value);
// Simple XOR combination for pointer hashes
Result := Integer(hash1 xor hash2);
end
)
);
end;
class destructor TDataType.DestroyClass;
begin
FArrayTypeRegistry.Free;
FRecordTypeRegistry.Free;
FDecimalTypes := nil;
FMethodTypeRegistry.Free;
end;
class function TDataType.ArrayOf(const AElementType: IDataType): TDataType.TArray;
var
res: IDataArrayType;
begin
if not Assigned(AElementType) then
raise EArgumentException.Create('Cannot create an array type with a nil element type.');
TMonitor.Enter(FArrayTypeRegistry);
try
if not FArrayTypeRegistry.TryGetValue(AElementType, res) then
begin
res := TImplDataArrayType.Create(AElementType);
FArrayTypeRegistry.Add(AElementType, res);
end;
finally
TMonitor.Exit(FArrayTypeRegistry);
end;
Result.Create(res);
end;
class function TDataType.DecimalOf(const AScale: Integer): TDataType.TDecimal;
begin
if (AScale < 0) or (AScale > 18) then
raise EArgumentException.Create('Scale for decimal must be between 0 and 18.');
Result.Create(FDecimalTypes[AScale]);
end;
class function TDataType.EnumOf(const AName: string; const AIdentifiers: array of string): TDataType.TEnum;
begin
Result.Create(TImplDataEnumType.Create(AName, AIdentifiers));
end;
class function TDataType.Float: TDataType.TFloat;
begin
Result.Create(TImplDataFloatType.Singleton);
end;
function TDataType.GetKind: TDataKind;
begin
Result := FDataType.Kind;
end;
function TDataType.GetName: String;
begin
if Assigned(FDataType) then
Result := FDataType.Name
else
Result := '';
end;
class function TDataType.MethodOf(const AArgType, AResultType: IDataType): TDataType.TMethod;
var
key: TPair<IDataType, IDataType>;
res: IDataMethodType;
begin
key := TPair<IDataType, IDataType>.Create(AArgType, AResultType);
TMonitor.Enter(FMethodTypeRegistry);
try
if not FMethodTypeRegistry.TryGetValue(key, res) then
begin
res := TImplDataMethodType.Create(AArgType, AResultType);
FMethodTypeRegistry.Add(key, res);
end;
finally
TMonitor.Exit(FMethodTypeRegistry);
end;
Result.Create(res);
end;
class function TDataType.Ordinal: TDataType.TOrdinal;
begin
Result.Create(TImplDataOrdinalType.Singleton);
end;
class function TDataType.RecordOf(const Fields: TArray<TRecordField>): TDataType.TRecord;
var
res: IDataRecordType;
begin
TMonitor.Enter(FRecordTypeRegistry);
try
if not FRecordTypeRegistry.TryGetValue(Fields, res) then
begin
res := TImplDataRecordType.Create(Fields);
FRecordTypeRegistry.Add(Fields, res);
end;
finally
TMonitor.Exit(FRecordTypeRegistry);
end;
Result.Create(res);
end;
class function TDataType.RecordOf(const Fields: array of TRecordField): TDataType.TRecord;
var
tFields: TArray<TRecordField>;
i: Integer;
begin
SetLength(tFields, Length(Fields));
for i := 0 to High(Fields) do
tFields[i] := Fields[i];
Result := RecordOf(tFields);
end;
class function TDataType.Text: TDataType.TText;
begin
Result.Create(TImplDataTextType.Singleton);
end;
class function TDataType.Timestamp: TDataType.TTimestamp;
begin
Result.Create(TImplDataTimestampType.Singleton);
end;
class function TDataType.Tuple: TDataType.TTuple;
begin
Result.Create(TImplDataTupleType.Singleton);
end;
class function TDataType.Void: TDataType.TVoid;
begin
Result.Create(TImplDataVoidType.Singleton);
end;
class operator TDataType.Implicit(const A: TDataType): IDataType;
begin
Result := A.FDataType;
end;
class operator TDataType.Implicit(const A: IDataType): TDataType;
begin
Result.FDataType := A;
end;
class operator TDataType.Implicit(const A: TDataType.TArray): TDataType;
begin
Result.FDataType := A.FArrayType;
end;
class operator TDataType.Implicit(const A: TDataType.TDecimal): TDataType;
begin
Result.FDataType := A.FDecimalType;
end;
class operator TDataType.Implicit(const A: TDataType.TEnum): TDataType;
begin
Result.FDataType := A.FEnumType;
end;
class operator TDataType.Implicit(const A: TDataType.TFloat): TDataType;
begin
Result.FDataType := A.FFloatType;
end;
class operator TDataType.Implicit(const A: TDataType.TMethod): TDataType;
begin
Result.FDataType := A.FMethodType;
end;
class operator TDataType.Implicit(const A: TDataType.TOrdinal): TDataType;
begin
Result.FDataType := A.FOrdinalType;
end;
class operator TDataType.Implicit(const A: TDataType.TRecord): TDataType;
begin
Result.FDataType := A.FRecordType;
end;
class operator TDataType.Implicit(const A: TDataType.TText): TDataType;
begin
Result.FDataType := A.FTextType;
end;
class operator TDataType.Implicit(const A: TDataType.TTimestamp): TDataType;
begin
Result.FDataType := A.FTimestampType;
end;
class operator TDataType.Implicit(const A: TDataType.TTuple): TDataType;
begin
Result.FDataType := A.FTupleType;
end;
class operator TDataType.Implicit(const A: TDataType.TVoid): TDataType;
begin
Result.FDataType := A.FVoidType;
end;
{ TDataType.TValue }
constructor TDataType.TValue.Create(const ADataValue: IDataValue);
begin
Assert(Assigned(ADataValue));
FDataValue := ADataValue;
end;
function TDataType.TValue.AsArray: IDataArrayValue;
begin
if (FDataValue.DataType.Kind <> dkArray) then
raise EInvalidCast.Create('Array expected');
Result := IDataArrayValue(FDataValue);
end;
function TDataType.TValue.AsDecimal: IDataDecimalValue;
begin
if (FDataValue.DataType.Kind <> dkDecimal) then
raise EInvalidCast.Create('Decimal expected');
Result := IDataDecimalValue(FDataValue);
end;
function TDataType.TValue.AsEnum: IDataEnumValue;
begin
if (FDataValue.DataType.Kind <> dkEnum) then
raise EInvalidCast.Create('Enum expected');
Result := IDataEnumValue(FDataValue);
end;
function TDataType.TValue.AsFloat: IDataFloatValue;
begin
if (FDataValue.DataType.Kind <> dkFloat) then
raise EInvalidCast.Create('Float expected');
Result := IDataFloatValue(FDataValue);
end;
function TDataType.TValue.AsMethod: IDataMethodValue;
begin
if (FDataValue.DataType.Kind <> dkMethod) then
raise EInvalidCast.Create('Method expected');
Result := IDataMethodValue(FDataValue);
end;
function TDataType.TValue.AsOrdinal: IDataOrdinalValue;
begin
if (FDataValue.DataType.Kind <> dkOrdinal) then
raise EInvalidCast.Create('Ordinal expected');
Result := IDataOrdinalValue(FDataValue);
end;
function TDataType.TValue.AsRecord: IDataRecordValue;
begin
if (FDataValue.DataType.Kind <> dkRecord) then
raise EInvalidCast.Create('Record expected');
Result := IDataRecordValue(FDataValue);
end;
function TDataType.TValue.AsText: IDataTextValue;
begin
if (FDataValue.DataType.Kind <> dkText) then
raise EInvalidCast.Create('Text expected');
Result := IDataTextValue(FDataValue);
end;
function TDataType.TValue.AsTimestamp: IDataTimestampValue;
begin
if (FDataValue.DataType.Kind <> dkTimestamp) then
raise EInvalidCast.Create('Timestamp expected');
Result := IDataTimestampValue(FDataValue);
end;
function TDataType.TValue.AsTuple: IDataTupleValue;
begin
if (FDataValue.DataType.Kind <> dkTuple) then
raise EInvalidCast.Create('Tuple expected');
Result := IDataTupleValue(FDataValue);
end;
function TDataType.TValue.AsVoid: IDataVoidValue;
begin
if (FDataValue.DataType.Kind <> dkVoid) then
raise EInvalidCast.Create('Void expected');
Result := IDataVoidValue(FDataValue);
end;
function TDataType.TValue.GetDataType: IDataType;
begin
if Assigned(FDataValue) then
Result := FDataValue.DataType
else
Result := nil;
end;
class operator TDataType.TValue.Implicit(const A: TDataType.TValue): IDataValue;
begin
Result := A.FDataValue;
end;
class operator TDataType.TValue.Implicit(const A: IDataArrayValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataDecimalValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataEnumValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataFloatValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataMethodValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataOrdinalValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataRecordValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataTextValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataTimestampValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataTupleValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
class operator TDataType.TValue.Implicit(const A: IDataVoidValue): TDataType.TValue;
begin
Result.FDataValue := A;
end;
function TDataType.AsArray: TDataType.TArray;
begin
if (FDataType.Kind <> dkArray) then
raise EInvalidCast.Create('Array expected');
Result.Create(IDataArrayType(FDataType));
end;
function TDataType.AsDecimal: TDataType.TDecimal;
begin
if (FDataType.Kind <> dkDecimal) then
raise EInvalidCast.Create('Decimal expected');
Result.Create(IDataDecimalType(FDataType));
end;
function TDataType.AsEnum: TDataType.TEnum;
begin
if (FDataType.Kind <> dkEnum) then
raise EInvalidCast.Create('Enum expected');
Result.Create(IDataEnumType(FDataType));
end;
function TDataType.AsFloat: TDataType.TFloat;
begin
if (FDataType.Kind <> dkFloat) then
raise EInvalidCast.Create('Float expected');
Result.Create(IDataFloatType(FDataType));
end;
function TDataType.AsMethod: TDataType.TMethod;
begin
if (FDataType.Kind <> dkMethod) then
raise EInvalidCast.Create('Method expected');
Result.Create(IDataMethodType(FDataType));
end;
function TDataType.AsOrdinal: TDataType.TOrdinal;
begin
if (FDataType.Kind <> dkOrdinal) then
raise EInvalidCast.Create('Ordinal expected');
Result.Create(IDataOrdinalType(FDataType));
end;
function TDataType.AsRecord: TDataType.TRecord;
begin
if (FDataType.Kind <> dkRecord) then
raise EInvalidCast.Create('Record expected');
Result.Create(IDataRecordType(FDataType));
end;
function TDataType.AsText: TDataType.TText;
begin
if (FDataType.Kind <> dkText) then
raise EInvalidCast.Create('Text expected');
Result.Create(IDataTextType(FDataType));
end;
function TDataType.AsTimestamp: TDataType.TTimestamp;
begin
if (FDataType.Kind <> dkTimestamp) then
raise EInvalidCast.Create('Timestamp expected');
Result.Create(IDataTimestampType(FDataType));
end;
function TDataType.AsTuple: TDataType.TTuple;
begin
if (FDataType.Kind <> dkTuple) then
raise EInvalidCast.Create('Tuple expected');
Result.Create(IDataTupleType(FDataType));
end;
end.