unit Myc.Futures; interface uses System.SysUtils, Myc.Signals, Myc.TaskManager; type // Represents the eventual Value of an asynchronous operation. TFuture = record type IFuture = interface {$REGION 'property access'} function GetValue: T; function GetDone: TState; {$ENDREGION} // Provides access to the computed Value. property Value: T read GetValue; // Provides access to the completion state. property Done: TState read GetDone; end; TFuncConst = reference to function(const Arg1: S): TResult; TProcConst = reference to function(const Arg1: S): TResult; {$REGION 'private'} strict private class var FNull: IFuture; class constructor CreateClass; private FFuture: IFuture; function GetDone: TState.IState; inline; function GetValue: T; inline; {$ENDREGION} public constructor Create(const AFuture: IFuture); class operator Initialize(out Dest: TFuture); class operator Implicit(const A: IFuture): TFuture; overload; class operator Implicit(const A: TFuture): IFuture; overload; class function Construct(const Proc: TFunc): TFuture; overload; static; class function Construct(const Gate: TState; const Proc: TFunc): TFuture; overload; static; class function Construct(const ConstVal: T): TFuture; overload; static; class property Null: IFuture read FNull; procedure Manage; function Chain(const Proc: TFunc): TFuture; overload; function Chain(const Proc: TFuncConst): TFuture; overload; function Chain(const Proc: TProcConst): TState; overload; function WaitFor: T; class function WhenAll(const Futures: TArray; const Func: TFuncConst, S>): TFuture; static; experimental; property Done: TState.IState read GetDone; property Value: T read GetValue; end; TFuture = record public class function FromArray(const Arr: TArray>): TFuture>; static; end; IObjectRef = interface function GetObj: T; function Pop: T; property Obj: T read GetObj; end; TObjectRef = class(TInterfacedObject, IObjectRef) private FObj: T; function GetObj: T; public constructor Create(const ARef: T); destructor Destroy; override; function Pop: T; end; implementation uses Myc.Core.Future; constructor TFuture.Create(const AFuture: IFuture); begin FFuture := AFuture; if not Assigned(FFuture) then FFuture := FNull; end; class constructor TFuture.CreateClass; begin FNull := TMycNullFuture.Create(Default(T)); end; function TFuture.Chain(const Proc: TProcConst): TState; begin var cFuture := FFuture; Result := TaskManager.RunTask(cFuture.Done, function: TState begin Result := Proc(cFuture.Value); end); end; function TFuture.Chain(const Proc: TFunc): TFuture; begin var cFuture := FFuture; Result := TFuture.Construct(cFuture.Done, function: S begin Result := Proc(cFuture.Value); end); end; function TFuture.Chain(const Proc: TFuncConst): TFuture; begin var cFuture := FFuture; Result := TFuture.Construct(cFuture.Done, function: S begin Result := Proc(cFuture.Value); end); end; class function TFuture.Construct(const Proc: TFunc): TFuture; begin Result := TMycGateFuncFuture.Create(TaskManager, nil, Proc); end; class function TFuture.Construct(const Gate: TState; const Proc: TFunc): TFuture; begin Result := TMycGateFuncFuture.Create(TaskManager, Gate, Proc); end; class function TFuture.Construct(const ConstVal: T): TFuture; begin Result := TMycNullFuture.Create(ConstVal); end; function TFuture.GetDone: TState.IState; begin Result := FFuture.Done; end; function TFuture.GetValue: T; begin Result := FFuture.Value; end; procedure TFuture.Manage; begin if GetTypeKind(T) = tkClass then FFuture := TMycFutureManaged.Create(FFuture); end; function TFuture.WaitFor: T; begin TaskManager.WaitFor(FFuture.Done); Result := FFuture.Value; end; class function TFuture.WhenAll(const Futures: TArray; const Func: TFuncConst, S>): TFuture; var DoneStates: TArray; begin SetLength(DoneStates, Length(Futures)); for var i := 0 to High(DoneStates) do DoneStates[i] := Futures[i].Done; var cFutures := Futures; Result := TFuture.Construct( TState.All(DoneStates), function: S var Vals: TArray; begin SetLength(Vals, Length(cFutures)); for var i := 0 to High(Vals) do Vals[i] := Futures[i].Value; Result := Func(Vals); end ); end; class operator TFuture.Implicit(const A: IFuture): TFuture; begin Result.Create(A); end; class operator TFuture.Implicit(const A: TFuture): IFuture; begin Result := A.FFuture; end; class operator TFuture.Initialize(out Dest: TFuture); begin Dest.FFuture := FNull; end; constructor TObjectRef.Create(const ARef: T); begin inherited Create; FObj := ARef; end; destructor TObjectRef.Destroy; begin FObj.Free; inherited Destroy; end; function TObjectRef.GetObj: T; begin Result := FObj; end; function TObjectRef.Pop: T; begin Result := FObj; FreeAndNil(FObj); end; class function TFuture.FromArray(const Arr: TArray>): TFuture>; var DoneStates: TArray; begin var cFutures := Arr; SetLength(DoneStates, Length(cFutures)); for var i := 0 to High(DoneStates) do DoneStates[i] := cFutures[i].Done; Result := TFuture>.Construct( TState.All(DoneStates), function: TArray begin SetLength(Result, Length(cFutures)); for var i := 0 to High(Result) do Result[i] := cFutures[i].Value; end ); end; end.