unit Myc.Core.Futures; interface uses System.SysUtils, Myc.Signals, Myc.TaskManager, Myc.Futures; type // Abstract base class for IMycFuture implementations. TMycFuture = class abstract( TInterfacedObject, IMycFuture ) protected function GetResult: T; virtual; abstract; function GetDone: IMycState; virtual; abstract; end; // Concrete future implementation triggered by an initial state, executing a TFunc. TMycInitStateFuncFuture = class( TMycFuture ) private FInit: TMycSubscription; FDone: IMycLatch; FResult: T; protected function GetResult: T; override; function GetDone: IMycState; override; public // Creates a future that executes AProc after AGate is set, using ATaskFactory. constructor Create( const ATaskManager: IMycTaskManager; const AGate: IMycState; AProc: TFunc ); destructor Destroy; override; end; implementation { TMycInitStateFuncFuture } constructor TMycInitStateFuncFuture.Create( const ATaskManager: IMycTaskManager; const AGate: IMycState; AProc: TFunc ); begin inherited Create; FDone := State.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 TMycInitStateFuncFuture.Destroy; begin Assert( FDone.State.IsSet ); FInit.Unsubscribe; inherited Destroy; end; function TMycInitStateFuncFuture.GetDone: IMycState; begin Result := FDone.State; end; function TMycInitStateFuncFuture.GetResult: T; begin Assert( FDone.State.IsSet, 'Result is not yet available.' ); Result := FResult; end; end.