1 class ObservableNumber : IObservable!int 2 { 3 private int number; 4 private IObserver!int[] observers; 5 6 private void publish() 7 { 8 foreach (o; observers) 9 o.onNext(this.number); 10 } 11 12 int opUnary(string op)() 13 { 14 this.number = mixin (op ~ "this.number"); 15 publish(); 16 return this.number; 17 } 18 19 int opBinary(string op, T)(T other) const 20 if (is(T : int)) 21 { 22 return mixin ("this.number" ~ op ~ "other"); 23 } 24 25 int opAssign(T)(T other) if (is(T : int)) 26 { 27 this.number = other; 28 publish(); 29 return this.number; 30 } 31 32 int opOpAssign(string op, T)(T other) if (is(T : int)) 33 { 34 mixin ("this = this " ~ op ~ " other;"); 35 return this.number; 36 } 37 38 class Ticket : IDisposable 39 { 40 this(size_t idx) { this.idx = idx; } 41 private const size_t idx; 42 bool dispose() 43 { 44 if (this.outer.observers[idx] !is null) 45 { 46 this.outer.observers[idx] = null; 47 return true; 48 } 49 else 50 return false; 51 } 52 } 53 54 IDisposable subscribe(IObserver!int o) 55 { 56 observers ~= o; 57 o.onNext(this.number); 58 return new Ticket(observers.length - 1); 59 } 60 } 61 62 class NumberObserver : IObserver!int 63 { 64 int[] result; 65 void onNext(int x) { result ~= x; } 66 void onError(Exception error) { assert (0); } 67 void onCompleted() { assert (0); } 68 } 69 70 auto observervable = new ObservableNumber; 71 auto observer = new NumberObserver; 72 73 auto ticket = observervable.subscribe(observer); 74 assert ((cast(ObservableNumber.Ticket)ticket).idx == 0); 75 assert (observervable.observers.length == 1); 76 assert (observer.result == [ 0 ]); 77 78 observervable++; 79 observervable += 3; 80 observervable *= 2; 81 82 assert (observervable.number == 8); 83 assert (observer.result == [ 0, 1, 4, 8 ]);