1 module minibus; 2 3 import std.stdio; 4 import std.variant; 5 import std.array; 6 import std.algorithm; 7 static import std.uuid; 8 9 alias Callback = void delegate(Variant); 10 11 class Minibus { 12 class Subscription { 13 string key; 14 Callback callback; 15 string id; 16 17 this(string key, Callback callback) { 18 this.key = key; 19 this.callback = callback; 20 this.id = std.uuid.randomUUID().toString(); 21 } 22 } 23 24 Subscription[] subscriptions; 25 26 string subscribe(string key, Callback callback) { 27 auto appender = appender(this.subscriptions); 28 auto sub = new Subscription(key, callback); 29 appender.put(sub); 30 this.subscriptions = appender[]; 31 return sub.id; 32 } 33 34 void emit(string key, Variant *arg) { 35 auto matching = this.subscriptions.filter!(sub => sub.key == key); 36 foreach(Subscription sub; matching.array) { 37 sub.callback(*arg); 38 } 39 } 40 41 void emit(string key) { 42 auto dummy_arg = new Variant(); 43 this.emit(key, dummy_arg); 44 } 45 46 void unsubscribe(string id) { 47 this.subscriptions = this.subscriptions.filter!(sub => sub.id != id).array; 48 } 49 } 50 51 // event without parameter 52 unittest { 53 struct Counter { 54 public int value; 55 56 void increment() { 57 this.value++; 58 } 59 } 60 61 auto bus = new Minibus(); 62 auto counter = Counter(0); 63 64 bus.subscribe("increment", (x) => counter.increment()); 65 assert(counter.value == 0); 66 67 bus.emit("increment"); 68 assert(counter.value == 1); 69 70 bus.emit("increment"); 71 assert(counter.value == 2); 72 73 bus.emit("decrement"); 74 assert(counter.value == 2); 75 } 76 77 // event with a parameter 78 unittest { 79 struct Counter { 80 public int value; 81 82 void increment(int by) { 83 this.value += by; 84 } 85 86 void decrement(int by) { 87 this.value -= by; 88 } 89 } 90 91 auto bus = new Minibus(); 92 auto counter = Counter(0); 93 auto counter2 = Counter(1); 94 95 bus.subscribe("increment", (x) => counter.increment(x.get!(int))); 96 bus.subscribe("increment", (x) => counter2.increment(x.get!(int))); 97 bus.subscribe("decrement", (x) => counter.decrement(x.get!(int))); 98 assert(counter.value == 0); 99 100 bus.emit("increment", new Variant(5)); 101 assert(counter.value == 5); 102 assert(counter2.value == 6); 103 104 bus.emit("increment", new Variant(3)); 105 assert(counter.value == 8); 106 assert(counter2.value == 9); 107 108 bus.emit("decrement", new Variant(6)); 109 assert(counter.value == 2); 110 assert(counter2.value == 9); 111 } 112 113 // unsubscribe 114 unittest { 115 struct Counter { 116 public int value; 117 118 void increment() { 119 this.value++; 120 } 121 } 122 123 auto bus = new Minibus(); 124 auto counter = Counter(0); 125 126 auto sub_id = bus.subscribe("increment", (x) => counter.increment()); 127 assert(counter.value == 0); 128 129 bus.emit("increment"); 130 assert(counter.value == 1); 131 132 bus.unsubscribe(sub_id); 133 134 bus.emit("increment"); 135 assert(counter.value == 1); 136 } 137 138 // unsubscribe non-existing subscription 139 unittest { 140 import std.exception : assertNotThrown; 141 142 auto bus = new Minibus(); 143 assertNotThrown(bus.unsubscribe("abc")); 144 }