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; FRecordTypeRegistry: TDictionary, IDataRecordType>; FMethodTypeRegistry: TDictionary, IDataMethodType>; FDecimalTypes: TArray; 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): 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; 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.Create; FRecordTypeRegistry := TDictionary, IDataRecordType>.Create(TRecordFieldComparer.Create); SetLength(FDecimalTypes, 19); for i := 0 to 18 do FDecimalTypes[i] := TImplDataDecimalType.Create(i); FMethodTypeRegistry := TDictionary, IDataMethodType>.Create( TEqualityComparer>.Construct( function(const Left, Right: TPair): Boolean begin Result := (Left.Key = Right.Key) and (Left.Value = Right.Value); end, function(const Value: TPair): 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; res: IDataMethodType; begin key := TPair.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): 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; 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; end.