unit Myc.Core.Mutable;

interface

uses
    System.Classes,
    System.SysUtils,
    System.SyncObjs,
    Myc.Signals,
    Myc.Mutable;

type
    TMycConstMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable)
    private
        FValue: T;
        function GetChanged: TSignal;
        function GetValue: T;
    public
        constructor Create(AValue: T);
    end;

    TMycMutableBase<T> = class(TInterfacedObject, TMutable<T>.IMutable)
    strict private
        FChanged: TEvent;
        FChangeState: TSignal.TSubscription;
        function GetChanged: TSignal;
    protected
        function GetValue: T; virtual; abstract;
    public
        constructor Create(const AChanged: TSignal);
        destructor Destroy; override;
    end;

    TMycFuncMutable<T> = class(TMycMutableBase<T>)
    private
        FProc: TFunc<T>;
    protected
        function GetValue: T; override;
    public
        constructor Create(const AChanged: TSignal; const AProc: TFunc<T>);
    end;

    TMycWriteableMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TWriteable<T>.IWriteable)
    private
        FValue: T;
        FChanged: TEvent;
    protected
        function GetChanged: TSignal;
        function GetValue: T;
    public
        constructor Create(const AValue: T);
        procedure SetValue(const Value: T);
    end;

    TMycProtectedMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TWriteable<T>.IWriteable)
    private
        FWriteable: TWriteable<T>.IWriteable;
        FLock: TLightweightMREW;
    protected
        function GetChanged: TSignal;
        function GetValue: T;
    public
        constructor Create(const AWriteable: TWriteable<T>.IWriteable);
        procedure SetValue(const Value: T);
    end;

    TMycConstLazy<T> = class(TInterfacedObject, TLazy<T>.ILazy)
    private
        FValue: T;
        function GetChanged: TState;
        function Update(var Value: T): Boolean;
    public
        constructor Create(AValue: T);
    end;

implementation

uses
    System.Generics.Defaults;

constructor TMycConstMutable<T>.Create(AValue: T);
begin
    inherited Create;
    FValue := AValue;
end;

{ TMycConstMutable<T> }

function TMycConstMutable<T>.GetChanged: TSignal;
begin
    Result := TSignal.Null;
end;

function TMycConstMutable<T>.GetValue: T;
begin
    Result := FValue;
end;

{ TMycMutableBase<T> }

constructor TMycMutableBase<T>.Create(const AChanged: TSignal);
begin
    inherited Create;
    FChanged := TEvent.CreateEvent;
    FChangeState := AChanged.Subscribe(FChanged);
end;

destructor TMycMutableBase<T>.Destroy;
begin
    FChangeState.Unsubscribe;
    inherited;
end;

function TMycMutableBase<T>.GetChanged: TSignal;
begin
    Result := FChanged.Signal;
end;

{ TMycWriteableMutable<T> }

constructor TMycWriteableMutable<T>.Create(const AValue: T);
begin
    inherited Create;
    FValue := AValue;
    FChanged := TEvent.CreateEvent;
end;

function TMycWriteableMutable<T>.GetChanged: TSignal;
begin
    Result := FChanged.Signal;
end;

function TMycWriteableMutable<T>.GetValue: T;
begin
    Result := FValue;
end;

procedure TMycWriteableMutable<T>.SetValue(const Value: T);
begin
    if not TEqualityComparer<T>.Default.Equals(FValue, Value) then
    begin
        FValue := Value;
        FChanged.Notify;
    end;
end;

constructor TMycFuncMutable<T>.Create(const AChanged: TSignal; const AProc: TFunc<T>);
begin
    inherited Create(AChanged);
    FProc := AProc;
end;

function TMycFuncMutable<T>.GetValue: T;
begin
    Result := FProc();
end;

{ TMycProtectedMutable<T> }

constructor TMycProtectedMutable<T>.Create(const AWriteable: TWriteable<T>.IWriteable);
begin
    inherited Create;
    FWriteable := AWriteable;
end;

function TMycProtectedMutable<T>.GetChanged: TSignal;
begin
    Result := FWriteable.Changed;
end;

function TMycProtectedMutable<T>.GetValue: T;
begin
    FLock.BeginRead;
    try
        Result := FWriteable.Value;
    finally
        FLock.EndRead;
    end;
end;

procedure TMycProtectedMutable<T>.SetValue(const Value: T);
begin
    FLock.BeginWrite;
    try
        FWriteable.SetValue(Value);
    finally
        Flock.EndWrite;
    end;
end;

constructor TMycConstLazy<T>.Create(AValue: T);
begin
    inherited Create;
    FValue := AValue;
end;

{ TMycConstLazy<T> }

function TMycConstLazy<T>.GetChanged: TState;
begin
    Result := TState.Null;
end;

function TMycConstLazy<T>.Update(var Value: T): Boolean;
begin
    Result := false;
end;

end.
