unit Myc.Trade.DataPoint; interface uses Myc.Signals, Myc.Trade.Types; type // Represents a time-stamped data point in a series. TDataPoint = record Time: TDateTime; Data: T; constructor Create(ATime: TDateTime; const AData: T); end; IMycProcessor = interface function ProcessData(const Value: T): TState; end; TDataProvider = record type TTag = Pointer; IDataProvider = interface function Link(const Receiver: IMycProcessor): TTag; procedure Unlink(Tag: TTag); end; {$REGION 'private'} strict private class var FNull: IDataProvider; class constructor CreateClass; private FDataProvider: IDataProvider; {$ENDREGION} public constructor Create(const ADataProvider: IDataProvider); // Managed record operators class operator Initialize(out Dest: TDataProvider); class operator Implicit(const A: IDataProvider): TDataProvider; overload; class operator Implicit(const A: TDataProvider): IDataProvider; overload; // Wrapper for IMycDataProvider methods function Link(const Receiver: IMycProcessor): TTag; inline; procedure Unlink(Tag: TTag); inline; // Provides access to the null object instance. class property Null: IDataProvider read FNull; end; // Interface helper for IMycConverter providing the null object pattern. TConverter = record type IConverter = interface(IMycProcessor) function GetSender: TDataProvider.IDataProvider; property Sender: TDataProvider.IDataProvider read GetSender; end; {$REGION 'private'} strict private class var FNull: IConverter; class constructor CreateClass; private FConverter: IConverter; function GetSender: TDataProvider; inline; {$ENDREGION} public constructor Create(const AConverter: IConverter); // Managed record operators class operator Initialize(out Dest: TConverter); class operator Implicit(const A: IConverter): TConverter; overload; class operator Implicit(const A: TConverter): IConverter; overload; class function CreateGeneric(const Func: TConstFunc): TConverter; static; // Wrapper for IMycProcessor.ProcessData function ProcessData(const Value: S): TState; inline; function Chain(const Next: TConverter): TConverter; overload; inline; function Chain(const Func: TConstFunc): TConverter; overload; inline; function Field(const FieldName: String): TConverter; overload; inline; // Provides access to the null object instance. class property Null: IConverter read FNull; // Wrapper for IMycConverter.Sender property Sender: TDataProvider read GetSender; end; TConverter = record class function CreateCounter: TConverter; static; class function CreateTicker: TConverter, T>; static; class function CreateRecordField(const FieldName: String): TConverter; static; end; implementation uses Myc.Trade.DataPoint.Impl; { TDataPoint } constructor TDataPoint.Create(ATime: TDateTime; const AData: T); begin Time := ATime; Data := AData; end; { TDataProvider } class constructor TDataProvider.CreateClass; begin // Create the singleton null object instance. FNull := TNullDataProvider.Create; end; constructor TDataProvider.Create(const ADataProvider: IDataProvider); begin FDataProvider := ADataProvider; // Ensure that the internal interface is never nil. if not Assigned(FDataProvider) then FDataProvider := FNull; end; class operator TDataProvider.Initialize(out Dest: TDataProvider); begin // Initialize new record instances with the null object. Dest.FDataProvider := FNull; end; class operator TDataProvider.Implicit(const A: IDataProvider): TDataProvider; begin // Allow implicit conversion from the interface to the helper. Result.Create(A); end; class operator TDataProvider.Implicit(const A: TDataProvider): IDataProvider; begin // Allow implicit conversion from the helper to the interface. Result := A.FDataProvider; end; function TDataProvider.Link(const Receiver: IMycProcessor): TTag; begin // Forward the call to the wrapped interface. Result := FDataProvider.Link(Receiver); end; procedure TDataProvider.Unlink(Tag: TTag); begin // Forward the call to the wrapped interface. FDataProvider.Unlink(Tag); end; { TConverter } class constructor TConverter.CreateClass; begin // Create the singleton null object instance. FNull := TNullConverter.Create; end; constructor TConverter.Create(const AConverter: IConverter); begin FConverter := AConverter; // Ensure that the internal interface is never nil. if not Assigned(FConverter) then FConverter := FNull; end; function TConverter.Chain(const Next: TConverter): TConverter; begin FConverter.Sender.Link(Next); Result := Next; end; function TConverter.Chain(const Func: TConstFunc): TConverter; begin Result := Chain(TMycGenericConverter.Create(Func)); end; class function TConverter.CreateGeneric(const Func: TConstFunc): TConverter; begin Result := TMycGenericConverter.Create(Func); end; function TConverter.Field(const FieldName: String): TConverter; begin Result := Chain(TMycRecordFieldReader.Create(FieldName)); end; function TConverter.GetSender: TDataProvider; begin // Forward the call to the wrapped interface. Result := FConverter.Sender; end; class operator TConverter.Initialize(out Dest: TConverter); begin // Initialize new record instances with the null object. Dest.FConverter := FNull; end; class operator TConverter.Implicit(const A: IConverter): TConverter; begin // Allow implicit conversion from the interface to the helper. Result.Create(A); end; class operator TConverter.Implicit(const A: TConverter): IConverter; begin // Allow implicit conversion from the helper to the interface. Result := A.FConverter; end; function TConverter.ProcessData(const Value: S): TState; begin // Forward the call to the wrapped interface. Result := FConverter.ProcessData(Value); end; class function TConverter.CreateCounter: TConverter; begin Result := TMycDataCounter.Create; end; class function TConverter.CreateRecordField(const FieldName: String): TConverter; begin Result := TMycRecordFieldReader.Create(FieldName); end; class function TConverter.CreateTicker: TConverter, T>; begin Result := TMycTicker.Create; end; end.