Implementing BuildingBlocks for one type can look like quite a bit of code, but it is very simple and always the same. The following is a complete implementation of BuildingBlocks for a class called MyClass:
using Chickensoft.Collections;
using Chickensoft.Sync;
using Cubusky.BuildingBlocks;
public interface IMyClass : IAutoObject<MyClass.Binding>, IOperator<MyClass>;
public class MyClass : IMyClass, IPerform<PerformOp<MyClass>>
{
protected SyncSubject Subject { get; }
public MyClass()
{
Subject = new(this);
}
private static readonly Blackboard _operationCallbacks = new Blackboard();
public static void Set<TOperation>(OperationCallback<MyClass>, TOperation> operation)
where TOperation : struct, IOperation<MyClass>
{
_operationCallbacks.Set(operation);
}
private readonly BoxlessQueue<IOperation<MyClass>> _operationQueue = new();
private Broadcaster? _operationBroadcaster;
private Broadcaster OperationBroadcaster => _operationBroadcaster ??= new(Subject);
void IOperator<MyClass>.Perform<TOperation>(in TOperation operation)
{
_operationQueue.Enqueue(operation);
Subject.Perform(new PerformOp<MyClass>(this, _operationCallbacks, OperationBroadcaster));
}
void IPerform<PerformOp<MyClass>>.Perform(in PerformOp<MyClass> op)
{
_operationQueue.Dequeue(op);
}
public class Broadcaster : IBroadcaster<MyClass>
{
protected SyncSubject Subject { get; }
internal Broadcaster(SyncSubject subject) => Subject = subject;
void IBroadcaster<MyClass>.Broadcast<TBroadcast>(in TBroadcast broadcast)
{
Subject.Broadcast(broadcast);
}
}
public Binding Bind() => new(Subject);
public void ClearBindings() => Subject.ClearBindings();
public void Dispose()
{
GC.SuppressFinalize(this);
Subject.Dispose();
}
public class Binding : SyncBinding, IBinding<MyClass, Binding>
{
internal Binding(ISyncSubject subject) : base(subject) {}
Binding IBinding<MyClass, Binding>.On<TBroadcast>(Callback<TBroadcast> callback, Condition<TBroadcast>? condition)
{
AddCallback(callback, condition);
return this;
}
}
}Let's break it down:
Blackboard _operationCallbacksis a static field that stores operation callbacks, a.k.a methods, forMyClass.- The 2
Performmethods are responsible for executing your operations based on [Sync]'s [no reentrancy]-policy. Broadcastercan only be created internally and is used to broadcast messages to all subscribers ofMyClass.Bindingcan only be created internally and is used to listen for broadcasts fromMyClass.