unit Myc.Core.Futures; interface uses System.SysUtils, Myc.Signals, Myc.TaskManager, Myc.Futures; type TMycFuture = class abstract(TInterfacedObject, TFuture.IFuture) protected function GetValue: T; virtual; abstract; function GetDone: TState; virtual; abstract; end; TMycNullFuture = class(TMycFuture) protected function GetValue: T; override; function GetDone: TState; override; end; TMycGateFuncFuture = class(TMycFuture) private FInit: TSignal.TSubscription; FDone: TLatch.ILatch; FResult: T; protected function GetValue: T; override; function GetDone: TState; override; public constructor Create(const ATaskManager: IMycTaskManager; const AGate: TState.IState; AProc: TFunc); destructor Destroy; override; end; implementation { TMycNullFuture } function TMycNullFuture.GetDone: TState; begin Result := TState.Null; end; function TMycNullFuture.GetValue: T; begin Result := Default(T); end; { TMycGateFuncFuture } constructor TMycGateFuncFuture.Create(const ATaskManager: IMycTaskManager; const AGate: TState.IState; AProc: TFunc); begin inherited Create; FDone := TLatch.CreateLatch(1); // Subscribe the job execution to AGate. // The job will run when AGate notifies the subscriber returned by Run. FInit := ATaskManager.CreateTask( AGate, procedure begin try try Self.FResult := AProc(); except Self.FResult := Default(T); // Set result to Default(T) on error raise; // Re-raise for TaskFactory to handle end; finally Self.FDone.Notify; // Signal that this future is done (successfully or with error) end; end ); end; destructor TMycGateFuncFuture.Destroy; begin Assert(FDone.State.IsSet, 'Future not done'); FInit.Unsubscribe; inherited Destroy; end; function TMycGateFuncFuture.GetDone: TState; begin Result := FDone.State; end; function TMycGateFuncFuture.GetValue: T; begin Assert(FDone.State.IsSet, 'Result is not yet available.'); Result := FResult; end; end.