Files
MycLib/Src/Myc.Core.Future.pas
2025-07-14 15:07:36 +02:00

151 lines
3.4 KiB
ObjectPascal

unit Myc.Core.Future;
interface
uses
System.SysUtils,
Myc.Signals,
Myc.TaskManager,
Myc.Futures;
type
TMycFuture<T> = class abstract(TInterfacedObject, TFuture<T>.IFuture)
protected
function GetValue: T; virtual; abstract;
function GetDone: TState; virtual; abstract;
public
procedure BeforeDestruction; override;
end;
TMycNullFuture<T> = class(TMycFuture<T>)
private
FValue: T;
protected
function GetValue: T; override;
function GetDone: TState; override;
public
constructor Create(const AValue: T);
end;
TMycGateFuncFuture<T> = class(TMycFuture<T>)
private
FDone: TState;
FResult: T;
protected
function GetValue: T; override;
function GetDone: TState; override;
public
constructor Create(const ATaskManager: TTaskManager; const AGate: TState.IState; AProc: TFunc<T>);
destructor Destroy; override;
end;
TMycFutureManaged<T> = class(TMycFuture<T>)
private
FFuture: TFuture<T>.IFuture;
protected
function GetValue: T; override;
function GetDone: TState; override;
public
constructor Create(const AFuture: TFuture<T>.IFuture);
destructor Destroy; override;
end;
implementation
{ TMycFuture<T> }
procedure TMycFuture<T>.BeforeDestruction;
begin
inherited;
Assert(GetDone.IsSet, 'Trying to destroy an unfinished future');
end;
constructor TMycNullFuture<T>.Create(const AValue: T);
begin
inherited Create;
FValue := AValue;
end;
{ TMycNullFuture<T> }
function TMycNullFuture<T>.GetDone: TState;
begin
Result := TState.Null;
end;
function TMycNullFuture<T>.GetValue: T;
begin
Result := FValue;
end;
{ TMycGateFuncFuture<T> }
constructor TMycGateFuncFuture<T>.Create(const ATaskManager: TTaskManager; const AGate: TState.IState; AProc: TFunc<T>);
begin
inherited Create;
// Subscribe the job execution to AGate.
// The job will run when AGate notifies the subscriber returned by Run.
FDone :=
ATaskManager.RunTask(
AGate,
function: TState
begin
try
Self.FResult := AProc();
except
Self.FResult := Default(T); // Set result to Default(T) on error
raise; // Re-raise for TaskFactory to handle
end;
end
);
end;
destructor TMycGateFuncFuture<T>.Destroy;
begin
inherited Destroy;
end;
function TMycGateFuncFuture<T>.GetDone: TState;
begin
Result := FDone;
end;
function TMycGateFuncFuture<T>.GetValue: T;
begin
Assert(FDone.IsSet, 'Result is not yet available.');
Result := FResult;
end;
{ TMycFutureManaged<T> }
constructor TMycFutureManaged<T>.Create(const AFuture: TFuture<T>.IFuture);
begin
inherited Create;
FFuture := AFuture;
end;
destructor TMycFutureManaged<T>.Destroy;
begin
if GetTypeKind(T) = tkClass then
begin
var val := GetValue;
var obj := TObject(PPointer(@val)^);
if obj <> nil then
obj.Free;
end;
inherited;
end;
function TMycFutureManaged<T>.GetDone: TState;
begin
Result := FFuture.Done;
end;
function TMycFutureManaged<T>.GetValue: T;
begin
Result := FFuture.Value;
end;
end.