added Futures
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
unit Myc.Futures;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
Myc.Signals, Myc.Core.Tasks;
|
||||
|
||||
type
|
||||
// Represents the eventual result of an asynchronous operation.
|
||||
IMycFuture<T> = 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<T> implementations.
|
||||
TMycFuture<T> = class abstract(TInterfacedObject, IMycFuture<T>)
|
||||
protected
|
||||
function GetResult: T; virtual; abstract;
|
||||
function GetDone: IMycState; virtual; abstract;
|
||||
end;
|
||||
|
||||
// Concrete future implementation triggered by an initial state, executing a TFunc<T>.
|
||||
TMycInitStateFuncFuture<T> = class(TMycFuture<T>)
|
||||
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<T>);
|
||||
// Cleans up resources, primarily by unsubscribing from the initial state.
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TMycInitStateFuncFuture<T> }
|
||||
|
||||
constructor TMycInitStateFuncFuture<T>.Create(const ATaskFactory:
|
||||
IMycTaskFactory; const AInitState: IMycState; AProc: TFunc<T>);
|
||||
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<T>.Destroy;
|
||||
begin
|
||||
Assert( FInit.State.IsSet );
|
||||
|
||||
// Explicitly unsubscribe from the initial state to ensure cleanup.
|
||||
FInit.Unsubscribe;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TMycInitStateFuncFuture<T>.GetDone: IMycState;
|
||||
begin
|
||||
Result := FDone.State;
|
||||
end;
|
||||
|
||||
function TMycInitStateFuncFuture<T>.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.
|
||||
Reference in New Issue
Block a user