unit Myc.Futures; interface uses System.SysUtils, Myc.Signals, Myc.Core.Tasks; type // Represents the eventual result of an asynchronous operation. IMycFuture = interface {$REGION 'property access'} function GetResult: T; function GetDone: IMycState; {$ENDREGION} // Provides access to the computed result. property Result: T read GetResult; // Provides access to the completion state. property Done: IMycState read GetDone; end; // 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 AInitState is set, using ATaskFactory. constructor Create(const ATaskFactory: IMycTaskFactory; const AInitState: IMycState; AProc: TFunc); // Cleans up resources, primarily by unsubscribing from the initial state. destructor Destroy; override; end; implementation { TMycInitStateFuncFuture } constructor TMycInitStateFuncFuture.Create(const ATaskFactory: IMycTaskFactory; const AInitState: IMycState; AProc: TFunc); begin inherited Create; Assert(Assigned(AInitState), 'AInitState must be assigned.'); FDone := TMycLatch.CreateLatch(1); // Subscribe the job execution to AInitState. // The job will run when AInitState notifies the subscriber returned by Run. // AStartCount for Run is 1, meaning it waits for one Notify from AInitState's subscription. FInit := AInitState.Subscribe( ATaskFactory.Run(1, 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( FInit.State.IsSet ); // Explicitly unsubscribe from the initial state to ensure cleanup. FInit.Unsubscribe; inherited Destroy; end; function TMycInitStateFuncFuture.GetDone: IMycState; begin Result := FDone.State; end; function TMycInitStateFuncFuture.GetResult: T; begin if not FDone.State.IsSet then begin // Design decision: Caller must ensure future is done. raise Exception.Create('Result is not yet available for the future.'); end; // Returns FResult. If AProc failed, FResult is Default(T) and the exception // was raised to be handled by the TaskFactory. Result := FResult; end; end.