unit Myc.Signals; interface uses System.SysUtils; type IMycSubscriber = interface // Interface for an entity that can be notified by a State or State. // Returns true if this subscriber expects further notifications from the source, false otherwise. function Notify: Boolean; end; IMycState = interface; TMycSubscription = record private FState: IMycState; FTag: Pointer; // Tag identifying this subscription within the notifier list. function GetState: IMycState; public constructor Create( const AState: IMycState; ATag: Pointer ); // Unsubscribes from the associated State. procedure Unsubscribe; class operator Initialize( out Dest: TMycSubscription ); property State: IMycState read GetState; end; IMycState = interface // Represents a subscribable state that can be queried. {$REGION 'property access'} function GetIsSet: Boolean; {$ENDREGION} // Subscribes a given subscriber to this State. function Subscribe( Subscriber: IMycSubscriber ): TMycSubscription; procedure Unsubscribe( Tag: Pointer ); // IsSet is true if the state has been reached or the condition is met. property IsSet: Boolean read GetIsSet; end; // IMycLatch is a specific type of flag that, once set, remains set (non-resettable). // It typically becomes set when an internal countdown reaches zero. IMycLatch = interface( IMycSubscriber ) // Provides access to the IMycState interface of the flag. function GetState: IMycState; property State: IMycState read GetState; // Inherits IMycSubscriber and State property from IMycFlag. No new members. end; // IMycDirty represents a resettable flag, typically indicating if a state is "dirty" (requiring attention) or "clean". // It inherits from IMycFlag, meaning it has a state, can be notified, and subscribed to. IMycDirty = interface( IMycSubscriber ) // Provides access to the IMycState interface of the flag. function GetState: IMycState; // Resets the flag to its "clean" (not set / not dirty) state. // Returns true if the flag was actually dirty before this reset, false otherwise. function Reset: Boolean; property State: IMycState read GetState; end; State = record private class function GetNull: IMycState; static; public class function CreateLatch( Count: Integer ): IMycLatch; static; class function CreateDirty: IMycDirty; static; class function All( const States: TArray ): IMycState; static; class function Any( const States: TArray ): IMycState; static; class property Null: IMycState read GetNull; end; implementation uses Myc.Core.Notifier, Myc.Core.Signals; { TMycSubscription } constructor TMycSubscription.Create( const AState: IMycState; ATag: TMycNotifyList.TTag ); begin Assert( Assigned( AState ) ); FState := AState; FTag := ATag; end; procedure TMycSubscription.Unsubscribe; begin FState.Unsubscribe( FTag ); FState := TMycState.Null; FTag := nil; end; function TMycSubscription.GetState: IMycState; begin Result := FState end; class operator TMycSubscription.Initialize( out Dest: TMycSubscription ); begin Dest.FState := TMycState.Null; Dest.FTag := nil; end; { State } class function State.CreateLatch( Count: Integer ): IMycLatch; begin Result := TMycLatch.CreateLatch( Count ); end; class function State.All( const States: TArray ): IMycState; var Latch: IMycLatch; begin Latch := CreateLatch( Length( States ) ); for var i := 0 to High( States ) do States[i].Subscribe( Latch ); Result := Latch.State; end; class function State.Any( const States: TArray ): IMycState; var Latch: IMycLatch; begin if Length( States ) = 0 then begin Result := State.Null; end else begin Latch := CreateLatch( 1 ); for var i := 0 to High( States ) do States[i].Subscribe( Latch ); Result := Latch.State; end; end; class function State.CreateDirty: IMycDirty; begin Result := TMycDirty.CreateDirty; end; class function State.GetNull: IMycState; begin Result := TMycState.Null; end; end.