unit Myc.Core.Futures; interface uses System.SysUtils, Myc.Signals, Myc.TaskManager, Myc.Futures; type TMycFuture = class abstract( TInterfacedObject, IMycFuture ) protected function GetResult: T; virtual; abstract; function GetDone: TState; virtual; abstract; end; TMycNullFuture = class( TMycFuture ) protected function GetResult: T; override; function GetDone: TState; override; end; TMycGateFuncFuture = class( TMycFuture ) private FInit: TState.TSubscription; FDone: IMycLatch; FResult: T; protected function GetResult: T; override; function GetDone: TState; override; public constructor Create( const ATaskManager: IMycTaskManager; const AGate: IMycState; AProc: TFunc ); destructor Destroy; override; end; implementation { TMycNullFuture } function TMycNullFuture.GetDone: TState; begin Result := TState.Null; end; function TMycNullFuture.GetResult: T; begin Result := Default ( T ); end; { TMycGateFuncFuture } constructor TMycGateFuncFuture.Create( const ATaskManager: IMycTaskManager; const AGate: IMycState; AProc: TFunc ); begin inherited Create; FDone := TLatch.Construct( 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 ); FInit.Unsubscribe; inherited Destroy; end; function TMycGateFuncFuture.GetDone: TState; begin Result := FDone.State; end; function TMycGateFuncFuture.GetResult: T; begin Assert( FDone.State.IsSet, 'Result is not yet available.' ); Result := FResult; end; end.