unit Myc.Mutable; interface uses System.SysUtils, Myc.Signals; type TMutable = record type IMutable = interface {$REGION 'property access'} function GetChanged: TSignal; function GetValue: T; {$ENDREGION} property Changed: TSignal read GetChanged; property Value: T read GetValue; end; {$REGION 'private'} strict private class var FNull: IMutable; class constructor CreateClass; private FMutable: IMutable; function GetChanged: TSignal; inline; function GetValue: T; inline; {$ENDREGION} public constructor Create(const AMutable: IMutable); class operator Initialize(out Dest: TMutable); class operator Implicit(const A: IMutable): TMutable; overload; class operator Implicit(const A: TMutable): IMutable; overload; class property Null: IMutable read FNull; class function Construct(const Changing: TSignal; const Proc: TFunc): TMutable; overload; static; class function Constant(const Value: T): TMutable; overload; static; property Value: T read GetValue; property Changed: TSignal read GetChanged; end; TWriteable = record type IWriteable = interface(TMutable.IMutable) procedure SetValue(const Value: T); end; {$REGION 'private'} private FWriteable: IWriteable; function GetChanged: TSignal; inline; function GetValue: T; inline; procedure SetValue(const Value: T); {$ENDREGION} public constructor Create(const AWriteable: IWriteable); class operator Implicit(const A: IWriteable): TWriteable; overload; class operator Implicit(const A: TWriteable): IWriteable; overload; class function CreateWriteable: TWriteable; overload; static; class function CreateWriteable(const Init: T): TWriteable; overload; static; function Protect: TWriteable; function AsMutable: TMutable; property Value: T read GetValue write SetValue; property Changed: TSignal read GetChanged; end; TLazy = record private FMutable: TMutable; FChanged: TFlag; FChangeState: TSignal.TSubscription; function GetValue: T; inline; public constructor Create(const AMutable: TMutable); function Update: Boolean; property Value: T read GetValue; end; implementation uses Myc.Core.Mutable; { TMutable } constructor TMutable.Create(const AMutable: IMutable); begin if Assigned(AMutable) then FMutable := AMutable; end; class constructor TMutable.CreateClass; begin FNull := TMycNullMutable.Create(Default(T)); end; class function TMutable.Constant(const Value: T): TMutable; begin Result := TMycNullMutable.Create(Value); end; class function TMutable.Construct(const Changing: TSignal; const Proc: TFunc): TMutable; begin Result := TMycFuncMutable.Create(Changing, Proc); end; function TMutable.GetChanged: TSignal; begin Result := FMutable.Changed; end; function TMutable.GetValue: T; begin Result := FMutable.Value; end; class operator TMutable.Implicit(const A: TMutable): IMutable; begin Result := A.FMutable; end; class operator TMutable.Implicit(const A: IMutable): TMutable; begin Result.Create(A); end; class operator TMutable.Initialize(out Dest: TMutable); begin Dest.FMutable := FNull; end; { TWriteable } constructor TWriteable.Create(const AWriteable: IWriteable); begin FWriteable := AWriteable; Assert(Assigned(FWriteable)); end; function TWriteable.AsMutable: TMutable; begin Result.Create(FWriteable); end; class function TWriteable.CreateWriteable: TWriteable; begin Result := CreateWriteable(Default(T)); end; class function TWriteable.CreateWriteable(const Init: T): TWriteable; begin Result := TMycWriteableMutable.Create(Init); end; function TWriteable.GetChanged: TSignal; begin Result := FWriteable.Changed; end; function TWriteable.GetValue: T; begin Result := FWriteable.Value; end; function TWriteable.Protect: TWriteable; begin if not (FWriteable is TMycProtectedMutable) then Result := TMycProtectedMutable.Create(FWriteable) else Result := FWriteable; end; procedure TWriteable.SetValue(const Value: T); begin FWriteable.SetValue(Value); end; class operator TWriteable.Implicit(const A: IWriteable): TWriteable; begin Result.Create(A); end; class operator TWriteable.Implicit(const A: TWriteable): IWriteable; begin Result := A.FWriteable; end; { TLazy } constructor TLazy.Create(const AMutable: TMutable); begin FMutable := AMutable; FChanged := TFlag.CreateFlag; FChangeState := AMutable.Changed.Subscribe(FChanged); end; function TLazy.GetValue: T; begin Result := FMutable.Value; end; function TLazy.Update: Boolean; begin Result := FChanged.State.IsSet; if Result then FChanged.Reset; end; end.