unit Myc.Data.Types deprecated;

interface

uses
    System.SysUtils;

type
    TDataKind = (dkVoid, dkOrdinal, dkFloat, dkText, dkTimestamp, dkDecimal, dkRecord, dkTuple, dkArray, dkVector, 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}
        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;

    TDataRecordField = 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): TDataRecordField;
        {$endregion}
        function IndexOf(const AName: string): Integer;
        function CreateValue(const AItems: array of IDataValue): IDataRecordValue;
        property FieldCount: Integer read GetFieldCount;
        property Fields[Idx: Integer]: TDataRecordField 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)
        {$region 'private'}
        function GetItemCount: Integer;
        function GetItemType(Idx: Integer): IDataType;
        {$endregion}
        function CreateValue(const AItems: array of IDataValue): IDataTupleValue;
        property ItemCount: Integer read GetItemCount;
        property ItemType[Idx: Integer]: IDataType read GetItemType;
    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;

    // Represents a fixed-size vector of data values.
    IDataVectorValue = 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;

    // Represents the type of a fixed-size vector.
    IDataVectorType = interface(IDataType)
        {$region 'private'}
        function GetElementType: IDataType;
        function GetElementCount: Integer;
        {$endregion}
        function CreateValue(const AItems: array of IDataValue): IDataVectorValue;
        property ElementType: IDataType read GetElementType;
        property ElementCount: Integer read GetElementCount;
    end;

    TDataType = record
        type
            TValue = record
            private
                FDataValue: IDataValue;
                function GetDataType: IDataType; inline;
            public
                constructor Create(const ADataValue: IDataValue);

                class operator Implicit(const A: IDataValue): TDataType.TValue; overload; inline;
                class operator Implicit(const A: TDataType.TValue): IDataValue; overload; inline;

                property DataValue: IDataValue read FDataValue;
                property DataType: IDataType read GetDataType;
            end;

            TVoid = record
                type
                    TValue = record
                    private
                        FVoidValue: IDataVoidValue;
                        function GetDataType: TDataType.TVoid;
                    public
                        constructor Create(const AVoidValue: IDataVoidValue);
                        class operator Implicit(const A: IDataVoidValue): TDataType.TVoid.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TVoid.TValue): IDataVoidValue; overload; inline;
                        class operator Implicit(const A: TDataType.TVoid.TValue): TDataType.TValue; overload; inline;
                        property DataType: TDataType.TVoid read GetDataType;
                    end;
            private
                FVoidType: IDataVoidType;
                function GetValue: TDataType.TVoid.TValue; 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: TDataType.TVoid.TValue read GetValue;
            end;

            TOrdinal = record
                type
                    TValue = record
                    private
                        FOrdinalValue: IDataOrdinalValue;
                        function GetDataType: TDataType.TOrdinal;
                        function GetValue: Int64; inline;
                    public
                        constructor Create(const AOrdinalValue: IDataOrdinalValue);
                        class operator Implicit(const A: IDataOrdinalValue): TDataType.TOrdinal.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TOrdinal.TValue): IDataOrdinalValue; overload; inline;
                        class operator Implicit(const A: TDataType.TOrdinal.TValue): TDataType.TValue; overload; inline;
                        property Value: Int64 read GetValue;
                        property DataType: TDataType.TOrdinal read GetDataType;
                    end;
            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): TDataType.TOrdinal.TValue; inline;
            end;

            TFloat = record
                type
                    TValue = record
                    private
                        FFloatValue: IDataFloatValue;
                        function GetDataType: TDataType.TFloat;
                        function GetValue: Double; inline;
                    public
                        constructor Create(const AFloatValue: IDataFloatValue);
                        class operator Implicit(const A: IDataFloatValue): TDataType.TFloat.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TFloat.TValue): IDataFloatValue; overload; inline;
                        class operator Implicit(const A: TDataType.TFloat.TValue): TDataType.TValue; overload; inline;
                        property Value: Double read GetValue;
                        property DataType: TDataType.TFloat read GetDataType;
                    end;
            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): TDataType.TFloat.TValue; inline;
            end;

            TText = record
                type
                    TValue = record
                    private
                        FTextValue: IDataTextValue;
                        function GetDataType: TDataType.TText;
                        function GetValue: string; inline;
                    public
                        constructor Create(const ATextValue: IDataTextValue);
                        class operator Implicit(const A: IDataTextValue): TDataType.TText.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TText.TValue): IDataTextValue; overload; inline;
                        class operator Implicit(const A: TDataType.TText.TValue): TDataType.TValue; overload; inline;
                        property Value: string read GetValue;
                        property DataType: TDataType.TText read GetDataType;
                    end;
            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): TDataType.TText.TValue; inline;
            end;

            TTimestamp = record
                type
                    TValue = record
                    private
                        FTimestampValue: IDataTimestampValue;
                        function GetDataType: TDataType.TTimestamp;
                        function GetValue: TDateTime; inline;
                    public
                        constructor Create(const ATimestampValue: IDataTimestampValue);
                        class operator Implicit(const A: IDataTimestampValue): TDataType.TTimestamp.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TTimestamp.TValue): IDataTimestampValue; overload; inline;
                        class operator Implicit(const A: TDataType.TTimestamp.TValue): TDataType.TValue; overload; inline;
                        property Value: TDateTime read GetValue;
                        property DataType: TDataType.TTimestamp read GetDataType;
                    end;
            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): TDataType.TTimestamp.TValue; inline;
            end;

            TDecimal = record
                type
                    TValue = record
                    private
                        FDecimalValue: IDataDecimalValue;
                        function GetDataType: TDataType.TDecimal;
                        function GetScale: Integer; inline;
                        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;
                        class operator Implicit(const A: TDataType.TDecimal.TValue): TDataType.TValue; overload; inline;
                        function ToDouble: Double;
                        property Value: Int64 read GetValue;
                        property Scale: Integer read GetScale;
                        property DataType: TDataType.TDecimal read GetDataType;
                    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
                type
                    TValue = record
                    private
                        FEnumValue: IDataEnumValue;
                        function GetDataType: TDataType.TEnum;
                        function GetValue: Integer; inline;
                    public
                        constructor Create(const AEnumValue: IDataEnumValue);
                        class operator Implicit(const A: IDataEnumValue): TDataType.TEnum.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TEnum.TValue): IDataEnumValue; overload; inline;
                        class operator Implicit(const A: TDataType.TEnum.TValue): TDataType.TValue; overload; inline;
                        property Value: Integer read GetValue;
                        property DataType: TDataType.TEnum read GetDataType;
                    end;
            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): TDataType.TEnum.TValue; overload; inline;
                function CreateValue(const AIdentifier: string): TDataType.TEnum.TValue; overload; inline;
                property IdentifierCount: Integer read GetIdentifierCount;
                property Identifiers[Idx: Integer]: string read GetIdentifier; default;
            end;

            TRecord = record
                type
                    TValue = record
                    private
                        FRecordValue: IDataRecordValue;
                        function GetDataType: TDataType.TRecord;
                        function GetItems(Idx: Integer): TDataType.TValue; inline;
                    public
                        constructor Create(const ARecordValue: IDataRecordValue);
                        class operator Implicit(const A: IDataRecordValue): TDataType.TRecord.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TRecord.TValue): IDataRecordValue; overload; inline;
                        class operator Implicit(const A: TDataType.TRecord.TValue): TDataType.TValue; overload; inline;
                        property Items[Idx: Integer]: TDataType.TValue read GetItems; default;
                        property DataType: TDataType.TRecord read GetDataType;
                    end;
            private
                FRecordType: IDataRecordType;
                function GetFieldCount: Integer; inline;
                function GetField(Idx: Integer): TDataRecordField; 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): TDataType.TRecord.TValue;
                property FieldCount: Integer read GetFieldCount;
                property Fields[Idx: Integer]: TDataRecordField read GetField; default;
            end;

            TTuple = record
                type
                    TValue = record
                    private
                        FTupleValue: IDataTupleValue;
                        function GetDataType: TDataType.TTuple;
                        function GetItems(Idx: Integer): TDataType.TValue; inline;
                        function GetItemCount: Integer; inline;
                    public
                        constructor Create(const ATupleValue: IDataTupleValue);
                        class operator Implicit(const A: IDataTupleValue): TDataType.TTuple.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TTuple.TValue): IDataTupleValue; overload; inline;
                        class operator Implicit(const A: TDataType.TTuple.TValue): TDataType.TValue; overload; inline;
                        property ItemCount: Integer read GetItemCount;
                        property Items[Idx: Integer]: TDataType.TValue read GetItems; default;
                        property DataType: TDataType.TTuple read GetDataType;
                    end;
            private
                FTupleType: IDataTupleType;
                function GetItemCount: Integer; inline;
                function GetItemType(Idx: Integer): IDataType; inline;
            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): TDataType.TTuple.TValue;
                property ItemCount: Integer read GetItemCount;
                property ItemType[Idx: Integer]: IDataType read GetItemType;
            end;

            TArray = record
                type
                    TValue = record
                    private
                        FArrayValue: IDataArrayValue;
                        function GetDataType: TDataType.TArray;
                        function GetItems(Idx: Integer): TDataType.TValue; inline;
                        function GetElementCount: Integer; inline;
                    public
                        constructor Create(const AArrayValue: IDataArrayValue);
                        class operator Implicit(const A: IDataArrayValue): TDataType.TArray.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TArray.TValue): IDataArrayValue; overload; inline;
                        class operator Implicit(const A: TDataType.TArray.TValue): TDataType.TValue; overload; inline;
                        property ElementCount: Integer read GetElementCount;
                        property Items[Idx: Integer]: TDataType.TValue read GetItems; default;
                        property DataType: TDataType.TArray read GetDataType;
                    end;
            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): TDataType.TArray.TValue;
                property ElementType: IDataType read GetElementType;
            end;

            TVector = record
                type
                    TValue = record
                    private
                        FVectorValue: IDataVectorValue;
                        function GetDataType: TDataType.TVector;
                        function GetItems(Idx: Integer): TDataType.TValue; inline;
                        function GetElementCount: Integer; inline;
                    public
                        constructor Create(const AVectorValue: IDataVectorValue);
                        class operator Implicit(const A: IDataVectorValue): TDataType.TVector.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TVector.TValue): IDataVectorValue; overload; inline;
                        class operator Implicit(const A: TDataType.TVector.TValue): TDataType.TValue; overload; inline;
                        property ElementCount: Integer read GetElementCount;
                        property Items[Idx: Integer]: TDataType.TValue read GetItems; default;
                        property DataType: TDataType.TVector read GetDataType;
                    end;
            private
                FVectorType: IDataVectorType;
                function GetElementType: IDataType; inline;
                function GetElementCount: Integer; inline;
            public
                constructor Create(const AVectorType: IDataVectorType);
                class operator Implicit(const A: IDataVectorType): TDataType.TVector; overload; inline;
                class operator Implicit(const A: TDataType.TVector): IDataVectorType; overload; inline;
                function CreateValue(const AItems: array of IDataValue): TDataType.TVector.TValue;
                property ElementType: IDataType read GetElementType;
                property ElementCount: Integer read GetElementCount;
            end;

            TMethod = record
                type
                    TProc = reference to function(const AValue: TDataType.TValue): TDataType.TValue;
                    TValue = record
                    private
                        FMethodValue: IDataMethodValue;
                        function GetDataType: TDataType.TMethod;
                        function GetValue: TDataMethodProc; inline;
                    public
                        constructor Create(const AMethodValue: IDataMethodValue);
                        class operator Implicit(const A: IDataMethodValue): TDataType.TMethod.TValue; overload; inline;
                        class operator Implicit(const A: TDataType.TMethod.TValue): IDataMethodValue; overload; inline;
                        class operator Implicit(const A: TDataType.TMethod.TValue): TDataType.TValue; overload; inline;
                        property Value: TDataMethodProc read GetValue;
                        property DataType: TDataType.TMethod read GetDataType;
                    end;
            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): TDataType.TMethod.TValue;
            end;

            // Helper to cast a generic TValue to a specific value helper.
            TValueHelper = record helper for TValue
            public
                function AsVoid: TVoid.TValue; inline;
                function AsOrdinal: TOrdinal.TValue; inline;
                function AsFloat: TFloat.TValue; inline;
                function AsText: TText.TValue; inline;
                function AsTimestamp: TTimestamp.TValue; inline;
                function AsDecimal: TDecimal.TValue; inline;
                function AsRecord: TRecord.TValue; inline;
                function AsTuple: TTuple.TValue; inline;
                function AsArray: TArray.TValue; inline;
                function AsVector: TVector.TValue; inline;
                function AsEnum: TEnum.TValue; inline;
                function AsMethod: TMethod.TValue; inline;
            end;

    strict private
        FDataType: IDataType;
        function GetName: String; inline;
        function GetKind: TDataKind; inline;
        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;
        class operator Implicit(const A: TDataType.TVector): TDataType; overload; inline;

        // Type factories
        class function Void: TDataType.TVoid; static;
        class function Ordinal: TDataType.TOrdinal; static;
        class function Float: TDataType.TFloat; static;
        class function Text: TDataType.TText; static;
        class function Timestamp: TDataType.TTimestamp; static;
        class function DecimalOf(const AScale: Integer): TDataType.TDecimal; static;
        class function TupleOf(const AItemTypes: array of IDataType): TDataType.TTuple; overload; static;
        class function TupleOf(const AItemValues: array of IDataValue): TDataType.TTuple.TValue; overload; static;
        class function MethodOf(const AArgType, AResultType: IDataType): TDataType.TMethod; static;
        class function ArrayOf(const AElementType: IDataType): TDataType.TArray; static;
        class function VectorOf(const AElementType: IDataType; const AElementCount: Integer): TDataType.TVector; static;
        class function RecordOf(const Fields: array of TDataRecordField): TDataType.TRecord; overload; static;
        class function RecordOf<T>: 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 AsVector: TDataType.TVector; 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.Math,
    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.Vector,
    Myc.Data.Types.Records,
    Myc.Data.Types.Tuple,
    Myc.Data.Types.Enum,
    Myc.Data.Types.Method;

{ TDataRecordField }

constructor TDataRecordField.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.GetDataType: TDataType.TDecimal;
begin
    Result := IDataDecimalType(FDecimalValue.DataType);
end;

function TDataType.TDecimal.TValue.GetScale: Integer;
begin
    Result := GetDataType.Scale;
end;

function TDataType.TDecimal.TValue.GetValue: Int64;
begin
    Result := FDecimalValue.Value;
end;

function TDataType.TDecimal.TValue.ToDouble: Double;
var
    scaleValue: Integer;
begin
    scaleValue := GetDataType.Scale;
    if (scaleValue > 0) then
        Result := FDecimalValue.Value / Power(10, scaleValue)
    else
        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;

class operator TDataType.TDecimal.TValue.Implicit(const A: TDataType.TDecimal.TValue): TDataType.TValue;
begin
    Result.Create(A.FDecimalValue);
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.TVoid.TValue }

constructor TDataType.TVoid.TValue.Create(const AVoidValue: IDataVoidValue);
begin
    FVoidValue := AVoidValue;
end;

function TDataType.TVoid.TValue.GetDataType: TDataType.TVoid;
begin
    Result := IDataVoidType(FVoidValue.DataType);
end;

class operator TDataType.TVoid.TValue.Implicit(const A: IDataVoidValue): TDataType.TVoid.TValue;
begin
    Result.FVoidValue := A;
end;

class operator TDataType.TVoid.TValue.Implicit(const A: TDataType.TVoid.TValue): IDataVoidValue;
begin
    Result := A.FVoidValue;
end;

class operator TDataType.TVoid.TValue.Implicit(const A: TDataType.TVoid.TValue): TDataType.TValue;
begin
    Result.Create(A.FVoidValue);
end;

{ TDataType.TVoid }

constructor TDataType.TVoid.Create(const AVoidType: IDataVoidType);
begin
    FVoidType := AVoidType;
end;

function TDataType.TVoid.GetValue: TDataType.TVoid.TValue;
begin
    Result.Create(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.TValue }

constructor TDataType.TOrdinal.TValue.Create(const AOrdinalValue: IDataOrdinalValue);
begin
    FOrdinalValue := AOrdinalValue;
end;

function TDataType.TOrdinal.TValue.GetDataType: TDataType.TOrdinal;
begin
    Result := IDataOrdinalType(FOrdinalValue.DataType);
end;

function TDataType.TOrdinal.TValue.GetValue: Int64;
begin
    Result := FOrdinalValue.Value;
end;

class operator TDataType.TOrdinal.TValue.Implicit(const A: IDataOrdinalValue): TDataType.TOrdinal.TValue;
begin
    Result.FOrdinalValue := A;
end;

class operator TDataType.TOrdinal.TValue.Implicit(const A: TDataType.TOrdinal.TValue): IDataOrdinalValue;
begin
    Result := A.FOrdinalValue;
end;

class operator TDataType.TOrdinal.TValue.Implicit(const A: TDataType.TOrdinal.TValue): TDataType.TValue;
begin
    Result.Create(A.FOrdinalValue);
end;

{ TDataType.TOrdinal }

constructor TDataType.TOrdinal.Create(const AOrdinalType: IDataOrdinalType);
begin
    FOrdinalType := AOrdinalType;
end;

function TDataType.TOrdinal.CreateValue(Init: Int64): TDataType.TOrdinal.TValue;
begin
    Result.Create(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.TValue }

constructor TDataType.TFloat.TValue.Create(const AFloatValue: IDataFloatValue);
begin
    FFloatValue := AFloatValue;
end;

function TDataType.TFloat.TValue.GetDataType: TDataType.TFloat;
begin
    Result := IDataFloatType(FFloatValue.DataType);
end;

function TDataType.TFloat.TValue.GetValue: Double;
begin
    Result := FFloatValue.Value;
end;

class operator TDataType.TFloat.TValue.Implicit(const A: IDataFloatValue): TDataType.TFloat.TValue;
begin
    Result.FFloatValue := A;
end;

class operator TDataType.TFloat.TValue.Implicit(const A: TDataType.TFloat.TValue): IDataFloatValue;
begin
    Result := A.FFloatValue;
end;

class operator TDataType.TFloat.TValue.Implicit(const A: TDataType.TFloat.TValue): TDataType.TValue;
begin
    Result.Create(A.FFloatValue);
end;

{ TDataType.TFloat }

constructor TDataType.TFloat.Create(const AFloatType: IDataFloatType);
begin
    FFloatType := AFloatType;
end;

function TDataType.TFloat.CreateValue(Init: Double): TDataType.TFloat.TValue;
begin
    Result.Create(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.TValue }

constructor TDataType.TText.TValue.Create(const ATextValue: IDataTextValue);
begin
    FTextValue := ATextValue;
end;

function TDataType.TText.TValue.GetDataType: TDataType.TText;
begin
    Result := IDataTextType(FTextValue.DataType);
end;

function TDataType.TText.TValue.GetValue: string;
begin
    Result := FTextValue.Value;
end;

class operator TDataType.TText.TValue.Implicit(const A: IDataTextValue): TDataType.TText.TValue;
begin
    Result.FTextValue := A;
end;

class operator TDataType.TText.TValue.Implicit(const A: TDataType.TText.TValue): IDataTextValue;
begin
    Result := A.FTextValue;
end;

class operator TDataType.TText.TValue.Implicit(const A: TDataType.TText.TValue): TDataType.TValue;
begin
    Result.Create(A.FTextValue);
end;

{ TDataType.TText }

constructor TDataType.TText.Create(const ATextType: IDataTextType);
begin
    FTextType := ATextType;
end;

function TDataType.TText.CreateValue(const AValue: string): TDataType.TText.TValue;
begin
    Result.Create(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.TValue }

constructor TDataType.TTimestamp.TValue.Create(const ATimestampValue: IDataTimestampValue);
begin
    FTimestampValue := ATimestampValue;
end;

function TDataType.TTimestamp.TValue.GetDataType: TDataType.TTimestamp;
begin
    Result := IDataTimestampType(FTimestampValue.DataType);
end;

function TDataType.TTimestamp.TValue.GetValue: TDateTime;
begin
    Result := FTimestampValue.Value;
end;

class operator TDataType.TTimestamp.TValue.Implicit(const A: IDataTimestampValue): TDataType.TTimestamp.TValue;
begin
    Result.FTimestampValue := A;
end;

class operator TDataType.TTimestamp.TValue.Implicit(const A: TDataType.TTimestamp.TValue): IDataTimestampValue;
begin
    Result := A.FTimestampValue;
end;

class operator TDataType.TTimestamp.TValue.Implicit(const A: TDataType.TTimestamp.TValue): TDataType.TValue;
begin
    Result.Create(A.FTimestampValue);
end;

{ TDataType.TTimestamp }

constructor TDataType.TTimestamp.Create(const ATimestampType: IDataTimestampType);
begin
    FTimestampType := ATimestampType;
end;

function TDataType.TTimestamp.CreateValue(const AValue: TDateTime): TDataType.TTimestamp.TValue;
begin
    Result.Create(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.TEnum.TValue }

constructor TDataType.TEnum.TValue.Create(const AEnumValue: IDataEnumValue);
begin
    FEnumValue := AEnumValue;
end;

function TDataType.TEnum.TValue.GetDataType: TDataType.TEnum;
begin
    Result := IDataEnumType(FEnumValue.DataType);
end;

function TDataType.TEnum.TValue.GetValue: Integer;
begin
    Result := FEnumValue.Value;
end;

class operator TDataType.TEnum.TValue.Implicit(const A: IDataEnumValue): TDataType.TEnum.TValue;
begin
    Result.FEnumValue := A;
end;

class operator TDataType.TEnum.TValue.Implicit(const A: TDataType.TEnum.TValue): IDataEnumValue;
begin
    Result := A.FEnumValue;
end;

class operator TDataType.TEnum.TValue.Implicit(const A: TDataType.TEnum.TValue): TDataType.TValue;
begin
    Result.Create(A.FEnumValue);
end;

{ TDataType.TEnum }

constructor TDataType.TEnum.Create(const AEnumType: IDataEnumType);
begin
    FEnumType := AEnumType;
end;

function TDataType.TEnum.CreateValue(const AValue: Integer): TDataType.TEnum.TValue;
begin
    Result.Create(FEnumType.CreateValue(AValue));
end;

function TDataType.TEnum.CreateValue(const AIdentifier: string): TDataType.TEnum.TValue;
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.TValue }

constructor TDataType.TMethod.TValue.Create(const AMethodValue: IDataMethodValue);
begin
    FMethodValue := AMethodValue;
end;

function TDataType.TMethod.TValue.GetDataType: TDataType.TMethod;
begin
    Result := IDataMethodType(FMethodValue.DataType);
end;

function TDataType.TMethod.TValue.GetValue: TDataMethodProc;
begin
    Result := FMethodValue.Value;
end;

class operator TDataType.TMethod.TValue.Implicit(const A: IDataMethodValue): TDataType.TMethod.TValue;
begin
    Result.FMethodValue := A;
end;

class operator TDataType.TMethod.TValue.Implicit(const A: TDataType.TMethod.TValue): IDataMethodValue;
begin
    Result := A.FMethodValue;
end;

class operator TDataType.TMethod.TValue.Implicit(const A: TDataType.TMethod.TValue): TDataType.TValue;
begin
    Result.Create(A.FMethodValue);
end;

{ TDataType.TMethod }

constructor TDataType.TMethod.Create(const AMethodType: IDataMethodType);
begin
    FMethodType := AMethodType;
end;

function TDataType.TMethod.CreateValue(const Proc: TProc): TDataType.TMethod.TValue;
begin
    if not Assigned(Proc) then
        raise EArgumentException.Create('Proc');

    var cProc: TProc := Proc;
    Result.Create(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.TValue }

constructor TDataType.TRecord.TValue.Create(const ARecordValue: IDataRecordValue);
begin
    FRecordValue := ARecordValue;
end;

function TDataType.TRecord.TValue.GetDataType: TDataType.TRecord;
begin
    Result := IDataRecordType(FRecordValue.DataType);
end;

function TDataType.TRecord.TValue.GetItems(Idx: Integer): TDataType.TValue;
begin
    Result.Create(FRecordValue.Items[Idx]);
end;

class operator TDataType.TRecord.TValue.Implicit(const A: IDataRecordValue): TDataType.TRecord.TValue;
begin
    Result.FRecordValue := A;
end;

class operator TDataType.TRecord.TValue.Implicit(const A: TDataType.TRecord.TValue): IDataRecordValue;
begin
    Result := A.FRecordValue;
end;

class operator TDataType.TRecord.TValue.Implicit(const A: TDataType.TRecord.TValue): TDataType.TValue;
begin
    Result.Create(A.FRecordValue);
end;

{ TDataType.TRecord }

constructor TDataType.TRecord.Create(const ARecordType: IDataRecordType);
begin
    FRecordType := ARecordType;
end;

function TDataType.TRecord.CreateValue(const AItems: array of IDataValue): TDataType.TRecord.TValue;
begin
    Result.Create(FRecordType.CreateValue(AItems));
end;

function TDataType.TRecord.GetField(Idx: Integer): TDataRecordField;
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.TValue }

constructor TDataType.TTuple.TValue.Create(const ATupleValue: IDataTupleValue);
begin
    FTupleValue := ATupleValue;
end;

function TDataType.TTuple.TValue.GetDataType: TDataType.TTuple;
begin
    Result := IDataTupleType(FTupleValue.DataType);
end;

function TDataType.TTuple.TValue.GetItems(Idx: Integer): TDataType.TValue;
begin
    Result.Create(FTupleValue.Items[Idx]);
end;

function TDataType.TTuple.TValue.GetItemCount: Integer;
begin
    Result := FTupleValue.ItemCount;
end;

class operator TDataType.TTuple.TValue.Implicit(const A: IDataTupleValue): TDataType.TTuple.TValue;
begin
    Result.FTupleValue := A;
end;

class operator TDataType.TTuple.TValue.Implicit(const A: TDataType.TTuple.TValue): IDataTupleValue;
begin
    Result := A.FTupleValue;
end;

class operator TDataType.TTuple.TValue.Implicit(const A: TDataType.TTuple.TValue): TDataType.TValue;
begin
    Result.Create(A.FTupleValue);
end;

{ TDataType.TTuple }

constructor TDataType.TTuple.Create(const ATupleType: IDataTupleType);
begin
    FTupleType := ATupleType;
end;

function TDataType.TTuple.CreateValue(const AItems: array of IDataValue): TDataType.TTuple.TValue;
begin
    Result.Create(FTupleType.CreateValue(AItems));
end;

function TDataType.TTuple.GetItemCount: Integer;
begin
    Result := FTupleType.ItemCount;
end;

function TDataType.TTuple.GetItemType(Idx: Integer): IDataType;
begin
    Result := FTupleType.ItemType[Idx];
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.TValue }

constructor TDataType.TArray.TValue.Create(const AArrayValue: IDataArrayValue);
begin
    FArrayValue := AArrayValue;
end;

function TDataType.TArray.TValue.GetDataType: TDataType.TArray;
begin
    Result := IDataArrayType(FArrayValue.DataType);
end;

function TDataType.TArray.TValue.GetElementCount: Integer;
begin
    Result := FArrayValue.ElementCount;
end;

function TDataType.TArray.TValue.GetItems(Idx: Integer): TDataType.TValue;
begin
    Result.Create(FArrayValue.Items[Idx]);
end;

class operator TDataType.TArray.TValue.Implicit(const A: IDataArrayValue): TDataType.TArray.TValue;
begin
    Result.FArrayValue := A;
end;

class operator TDataType.TArray.TValue.Implicit(const A: TDataType.TArray.TValue): IDataArrayValue;
begin
    Result := A.FArrayValue;
end;

class operator TDataType.TArray.TValue.Implicit(const A: TDataType.TArray.TValue): TDataType.TValue;
begin
    Result.Create(A.FArrayValue);
end;

{ TDataType.TArray }

constructor TDataType.TArray.Create(const AArrayType: IDataArrayType);
begin
    FArrayType := AArrayType;
end;

function TDataType.TArray.CreateValue(const AItems: array of IDataValue): TDataType.TArray.TValue;
begin
    Result.Create(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.TVector.TValue }

constructor TDataType.TVector.TValue.Create(const AVectorValue: IDataVectorValue);
begin
    FVectorValue := AVectorValue;
end;

function TDataType.TVector.TValue.GetDataType: TDataType.TVector;
begin
    Result := IDataVectorType(FVectorValue.DataType);
end;

function TDataType.TVector.TValue.GetElementCount: Integer;
begin
    Result := FVectorValue.ElementCount;
end;

function TDataType.TVector.TValue.GetItems(Idx: Integer): TDataType.TValue;
begin
    Result.Create(FVectorValue.Items[Idx]);
end;

class operator TDataType.TVector.TValue.Implicit(const A: IDataVectorValue): TDataType.TVector.TValue;
begin
    Result.FVectorValue := A;
end;

class operator TDataType.TVector.TValue.Implicit(const A: TDataType.TVector.TValue): IDataVectorValue;
begin
    Result := A.FVectorValue;
end;

class operator TDataType.TVector.TValue.Implicit(const A: TDataType.TVector.TValue): TDataType.TValue;
begin
    Result.Create(A.FVectorValue);
end;

{ TDataType.TVector }

constructor TDataType.TVector.Create(const AVectorType: IDataVectorType);
begin
    FVectorType := AVectorType;
end;

function TDataType.TVector.CreateValue(const AItems: array of IDataValue): TDataType.TVector.TValue;
begin
    Result.Create(FVectorType.CreateValue(AItems));
end;

function TDataType.TVector.GetElementCount: Integer;
begin
    Result := FVectorType.ElementCount;
end;

function TDataType.TVector.GetElementType: IDataType;
begin
    Result := FVectorType.ElementType;
end;

class operator TDataType.TVector.Implicit(const A: IDataVectorType): TDataType.TVector;
begin
    Result.FVectorType := A;
end;

class operator TDataType.TVector.Implicit(const A: TDataType.TVector): IDataVectorType;
begin
    Result := A.FVectorType;
end;

{ TDataType }

constructor TDataType.Create(const ADataType: IDataType);
begin
    Assert(Assigned(ADataType));
    FDataType := ADataType;
end;

class constructor TDataType.CreateClass;
begin
    // Registries are now managed by their respective implementation units.
end;

class destructor TDataType.DestroyClass;
begin
    // Registries are now managed by their respective implementation units.
end;

class function TDataType.ArrayOf(const AElementType: IDataType): TDataType.TArray;
begin
    // The TImplDataArrayType now manages its own instances.
    Result.Create(TImplDataArrayType.GetInstance(AElementType));
end;

class function TDataType.DecimalOf(const AScale: Integer): TDataType.TDecimal;
begin
    // The TImplDataDecimalType now manages its own instances.
    Result.Create(TImplDataDecimalType.GetInstance(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;
begin
    // The TImplDataMethodType now manages its own instances.
    Result.Create(TImplDataMethodType.GetInstance(AArgType, AResultType));
end;

class function TDataType.Ordinal: TDataType.TOrdinal;
begin
    Result.Create(TImplDataOrdinalType.Singleton);
end;

class function TDataType.RecordOf(const Fields: array of TDataRecordField): TDataType.TRecord;
begin
    Result.Create(TImplDataRecordType.GetInstance(Fields));
end;

class function TDataType.RecordOf<T>: TDataType.TRecord;
begin
    Result.Create(TImplDataRecordType.GetInstance<T>);
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.TupleOf(const AItemTypes: array of IDataType): TDataType.TTuple;
var
    tItems: TArray<IDataType>;
    i: Integer;
begin
    SetLength(tItems, Length(AItemTypes));
    for i := 0 to High(AItemTypes) do
        tItems[i] := AItemTypes[i];

    // Use the instance manager to get a tuple type for the given element types.
    Result.Create(TImplDataTupleType.GetInstance(tItems));
end;

class function TDataType.TupleOf(const AItemValues: array of IDataValue): TDataType.TTuple.TValue;
var
    tItems: TArray<IDataType>;
    i: Integer;
begin
    SetLength(tItems, Length(AItemValues));
    for i := 0 to High(AItemValues) do
        tItems[i] := AItemValues[i].DataType;

    var tTuple := TImplDataTupleType.GetInstance(tItems);

    Result := tTuple.CreateValue(AItemValues);
end;

class function TDataType.VectorOf(const AElementType: IDataType; const AElementCount: Integer): TDataType.TVector;
begin
    // The TImplDataVectorType now manages its own instances.
    Result.Create(TImplDataVectorType.GetInstance(AElementType, AElementCount));
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.TVector): TDataType;
begin
    Result.FDataType := A.FVectorType;
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.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: IDataValue): 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;

function TDataType.AsVector: TDataType.TVector;
begin
    if (FDataType.Kind <> dkVector) then
        raise EInvalidCast.Create('Vector expected');
    Result.Create(IDataVectorType(FDataType));
end;

{ TDataType.TValueHelper }

function TDataType.TValueHelper.AsArray: TDataType.TArray.TValue;
begin
    if (FDataValue.DataType.Kind <> dkArray) then
        raise EInvalidCast.Create('Array expected');
    Result.Create(IDataArrayValue(FDataValue));
end;

function TDataType.TValueHelper.AsDecimal: TDecimal.TValue;
begin
    if (FDataValue.DataType.Kind <> dkDecimal) then
        raise EInvalidCast.Create('Decimal expected');
    Result.Create(IDataDecimalValue(FDataValue));
end;

function TDataType.TValueHelper.AsEnum: TDataType.TEnum.TValue;
begin
    if (FDataValue.DataType.Kind <> dkEnum) then
        raise EInvalidCast.Create('Enum expected');
    Result.Create(IDataEnumValue(FDataValue));
end;

function TDataType.TValueHelper.AsFloat: TDataType.TFloat.TValue;
begin
    if (FDataValue.DataType.Kind <> dkFloat) then
        raise EInvalidCast.Create('Float expected');
    Result.Create(IDataFloatValue(FDataValue));
end;

function TDataType.TValueHelper.AsMethod: TDataType.TMethod.TValue;
begin
    if (FDataValue.DataType.Kind <> dkMethod) then
        raise EInvalidCast.Create('Method expected');
    Result.Create(IDataMethodValue(FDataValue));
end;

function TDataType.TValueHelper.AsOrdinal: TDataType.TOrdinal.TValue;
begin
    if (FDataValue.DataType.Kind <> dkOrdinal) then
        raise EInvalidCast.Create('Ordinal expected');
    Result.Create(IDataOrdinalValue(FDataValue));
end;

function TDataType.TValueHelper.AsRecord: TDataType.TRecord.TValue;
begin
    if (FDataValue.DataType.Kind <> dkRecord) then
        raise EInvalidCast.Create('Record expected');
    Result.Create(IDataRecordValue(FDataValue));
end;

function TDataType.TValueHelper.AsText: TDataType.TText.TValue;
begin
    if (FDataValue.DataType.Kind <> dkText) then
        raise EInvalidCast.Create('Text expected');
    Result.Create(IDataTextValue(FDataValue));
end;

function TDataType.TValueHelper.AsTimestamp: TDataType.TTimestamp.TValue;
begin
    if (FDataValue.DataType.Kind <> dkTimestamp) then
        raise EInvalidCast.Create('Timestamp expected');
    Result.Create(IDataTimestampValue(FDataValue));
end;

function TDataType.TValueHelper.AsTuple: TDataType.TTuple.TValue;
begin
    if (FDataValue.DataType.Kind <> dkTuple) then
        raise EInvalidCast.Create('Tuple expected');
    Result.Create(IDataTupleValue(FDataValue));
end;

function TDataType.TValueHelper.AsVector: TDataType.TVector.TValue;
begin
    if (FDataValue.DataType.Kind <> dkVector) then
        raise EInvalidCast.Create('Vector expected');
    Result.Create(IDataVectorValue(FDataValue));
end;

function TDataType.TValueHelper.AsVoid: TDataType.TVoid.TValue;
begin
    if (FDataValue.DataType.Kind <> dkVoid) then
        raise EInvalidCast.Create('Void expected');
    Result.Create(IDataVoidValue(FDataValue));
end;

end.
