Refactoring
This commit is contained in:
+36
-69
@@ -4,7 +4,7 @@ interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
Myc.Signals, Myc.Core.Tasks;
|
||||
Myc.Signals, Myc.TaskManager;
|
||||
|
||||
type
|
||||
// Represents the eventual result of an asynchronous operation.
|
||||
@@ -19,91 +19,58 @@ type
|
||||
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;
|
||||
Future<T> = record
|
||||
strict private
|
||||
FFuture: IMycFuture<T>;
|
||||
class constructor CreateClass;
|
||||
class destructor DestroyClass;
|
||||
constructor Create(const AFuture: IMycFuture<T>);
|
||||
public
|
||||
class function Construct(const Proc: TFunc<T>): Future<T>; overload; static;
|
||||
class function Construct(const Gate: IMycState; const Proc: TFunc<T>): Future<T>; overload; static;
|
||||
|
||||
// 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;
|
||||
function Chain<S>(const Proc: TFunc<T, S>): Future<S>;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TMycInitStateFuncFuture<T> }
|
||||
uses
|
||||
Myc.Core.Futures, Myc.Core.Tasks;
|
||||
|
||||
constructor TMycInitStateFuncFuture<T>.Create(const ATaskFactory:
|
||||
IMycTaskFactory; const AInitState: IMycState; AProc: TFunc<T>);
|
||||
constructor Future<T>.Create(const AFuture: IMycFuture<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(
|
||||
|
||||
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
|
||||
)
|
||||
);
|
||||
FFuture := AFuture;
|
||||
end;
|
||||
|
||||
destructor TMycInitStateFuncFuture<T>.Destroy;
|
||||
class constructor Future<T>.CreateClass;
|
||||
begin
|
||||
Assert( FInit.State.IsSet );
|
||||
|
||||
// Explicitly unsubscribe from the initial state to ensure cleanup.
|
||||
FInit.Unsubscribe;
|
||||
inherited Destroy;
|
||||
TMycTaskFactory.AquireTaskManager;
|
||||
end;
|
||||
|
||||
|
||||
function TMycInitStateFuncFuture<T>.GetDone: IMycState;
|
||||
class destructor Future<T>.DestroyClass;
|
||||
begin
|
||||
Result := FDone.State;
|
||||
TMycTaskFactory.ReleaseTaskManager;
|
||||
end;
|
||||
|
||||
function TMycInitStateFuncFuture<T>.GetResult: T;
|
||||
function Future<T>.Chain<S>(const Proc: TFunc<T, S>): Future<S>;
|
||||
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;
|
||||
var Cap := FFuture;
|
||||
|
||||
// Returns FResult. If AProc failed, FResult is Default(T) and the exception
|
||||
// was raised to be handled by the TaskFactory.
|
||||
Result := FResult;
|
||||
Result := Future<S>.Construct( FFuture.Done,
|
||||
function: S
|
||||
begin
|
||||
Result := Proc( Cap.Result );
|
||||
end );
|
||||
end;
|
||||
|
||||
class function Future<T>.Construct(const Proc: TFunc<T>): Future<T>;
|
||||
begin
|
||||
Result.Create( TMycInitStateFuncFuture<T>.Create( TaskManager, nil, Proc ) );
|
||||
end;
|
||||
|
||||
class function Future<T>.Construct(const Gate: IMycState; const Proc: TFunc<T>): Future<T>;
|
||||
begin
|
||||
Result.Create( TMycInitStateFuncFuture<T>.Create( TaskManager, Gate, Proc ) );
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user