Skip to content

Commit

Permalink
Merge pull request #4 from wlindley/eventless-commands
Browse files Browse the repository at this point in the history
Eventless commands
  • Loading branch information
wlindley authored Jul 15, 2016
2 parents c3f5aba + ba06388 commit c121cfe
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 9 deletions.
1 change: 1 addition & 0 deletions Bantam/CommandChain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Bantam
{
public delegate void CommandInitializer<U, T>(U cmd, T evt) where U : Command where T : Event;
public delegate void SimpleCommandInitializer<U>(U cmd) where U : Command;

public abstract class CommandChain
{
Expand Down
52 changes: 47 additions & 5 deletions Bantam/CommandChainExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,49 @@

namespace Bantam
{
internal class CommandChainExecutor : Poolable
internal interface CommandChainExecutor : Poolable
{
void CurrentCommandComplete();
void CurrentCommandFailed();
}

internal class SimpleCommandChainExecutor<T> : CommandChainExecutor where T : Command, new()
{
private CommandRelay manager;
private ObjectPool pool;
private T command;

public void Reset()
{
manager = null;
pool = null;
command = null;
}

internal void Start(CommandRelay manager, ObjectPool pool, SimpleCommandInitializer<T> initializer = null)
{
this.manager = manager;
this.pool = pool;
command = pool.Allocate<T>();
if (null != initializer)
initializer(command);
command.Start(this);
}

public void CurrentCommandComplete()
{
pool.Free<T>(command);
manager.CompleteChainExecution<SimpleCommandChainExecutor<T>>(this);
}

public void CurrentCommandFailed()
{
pool.Free<T>(command);
manager.CompleteChainExecution<SimpleCommandChainExecutor<T>>(this);
}
}

internal class EventCommandChainExecutor : CommandChainExecutor
{
private CommandRelay manager;
private Event triggeringEvent;
Expand All @@ -30,21 +72,21 @@ internal void Start(Event triggeringEvent, CommandChain chain, CommandRelay mana
Next();
}

internal void CurrentCommandComplete()
public void CurrentCommandComplete()
{
enumerator.Current.FreeCommand(pool, currentCommand);
currentCommand = null;
if (enumerator.MoveNext())
Next();
else
manager.CompleteChainExecution(this);
manager.CompleteChainExecution<EventCommandChainExecutor>(this);
}

internal void CurrentCommandFailed()
public void CurrentCommandFailed()
{
enumerator.Current.FreeCommand(pool, currentCommand);
currentCommand = null;
manager.CompleteChainExecution(this);
manager.CompleteChainExecution<EventCommandChainExecutor>(this);
}

private void Next()
Expand Down
13 changes: 10 additions & 3 deletions Bantam/CommandRelay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,24 @@ public CommandRelay(EventBus eventBus, ObjectPool pool)
chains[typeof(T)].Add(chain);
eventBus.AddListener<T>(ev =>
{
var executor = pool.Allocate<CommandChainExecutor>();
var executor = pool.Allocate<EventCommandChainExecutor>();
activeExecutors.Add(executor);
executor.Start(ev, chain, this, pool);
});
return chain;
}

internal void CompleteChainExecution(CommandChainExecutor executor)
public void Launch<U>(SimpleCommandInitializer<U> initializer = null) where U : Command, new()
{
var executor = pool.Allocate<SimpleCommandChainExecutor<U>>();
activeExecutors.Add(executor);
executor.Start(this, pool, initializer);
}

internal void CompleteChainExecution<V>(V executor) where V : CommandChainExecutor
{
activeExecutors.Remove(executor);
pool.Free<CommandChainExecutor>(executor);
pool.Free<V>(executor);
}

private void EnsureKeyExists<T>() where T : Event
Expand Down
14 changes: 14 additions & 0 deletions BantamTest/CommandRelayTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ public void CommandFailureStopsChainExecution()
eventBus.Dispatch<DummyEvent>();
Assert.AreEqual(0, DummyCommand.ExecuteCount);
}

[Test]
public void LaunchCreatesCommandDirectly()
{
testObj.Launch<DummyCommand>();
Assert.AreEqual(1, DummyCommand.ExecuteCount);
}

[Test]
public void LaunchRunsInitializerOnCommandIfProvided()
{
testObj.Launch<DummyCommand>(cmd => cmd.value = 7500);
Assert.AreEqual(7500, DummyCommand.LastValue);
}
}

public class DummyCommand : Command
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ A lightweight, no garbage application framework for C# that's compatible with Un
## Features
1. **Object Pool** can be used with generic type parameters or Type object parameters. Pools expose the number of instances of each type they have created to aid with debugging and profiling.
1. **Event Bus** ensures all Events are pooled while still allowing custom data to be assigned to each instance. Supports adding/removing Event listeners, listeners that only get called once, and listeners that will receive all Events on the bus.
1. **Command Relay** will execute sequential chains of Commands in response to Events. Multiple Command chains can be registered for an Event, in which case they will run in parallel. Commands are synchronous by default, but can be made asynchronous on demand. If a Command fails, subsequent Commands in the chain will not be executed.
1. **Command Relay** will execute sequential chains of Commands in response to Events or individually. Multiple Command chains can be registered for an Event, in which case they will run in parallel. Commands are synchronous by default, but can be made asynchronous on demand. If a Command fails, subsequent Commands in the chain will not be executed.
1. **Model Registry** will manage a pool of active Models and let you retrieve them by type. Also emits events when Models are created and deleted, making it easy to write a wrapper for whatever GUI system you're using to bind views to Models.

## Examples
```csharp
Expand All @@ -27,4 +28,7 @@ eventBus.Dispatch<LoginEvent>(evt => {
commandRelay.On<LoginEvent>()
.Do<ShowUsernameCommand>((cmd, evt) => cmd.loginEvent = evt)
.Do<ShowOptionsCommand>();

//Create a Model.
modelRegistry.Create<UserDataModel>(mdl => mdl.username = "Jane Doe");
```

0 comments on commit c121cfe

Please sign in to comment.