1 /+ 2 The MIT License (MIT) 3 4 Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)> 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in 14 all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 THE SOFTWARE. 23 +/ 24 25 module des.flow.event; 26 27 import std.traits; 28 29 import core.time; 30 31 import des.util.pdata; 32 33 import des.flow.base; 34 import des.flow.sysevdata; 35 /++ 36 code=ulong.max-1 is reserved for system 37 +/ 38 struct Event 39 { 40 enum ulong system_code = ulong.max-1; 41 alias typeof(this) Self; 42 43 ulong code; 44 ulong timestamp; 45 PData data; 46 47 static auto system( SysEvData sed ) 48 { 49 Self ev; 50 ev.code = system_code; 51 ev.timestamp = currentTick; 52 ev.data = PData(sed); 53 return ev; 54 } 55 56 this(T)( ulong code, in T value ) 57 if( is( typeof(PData(value)) ) ) 58 in { assert( code != system_code ); } body 59 { 60 this.code = code; 61 timestamp = currentTick; 62 data = PData(value); 63 } 64 65 private enum base_ctor = 66 ` this( in Event ev ) 67 { 68 code = ev.code; 69 timestamp = ev.timestamp; 70 data = ev.data; 71 }`; 72 73 mixin( base_ctor ); 74 mixin( "const" ~ base_ctor ); 75 mixin( "immutable" ~ base_ctor ); 76 mixin( "shared" ~ base_ctor ); 77 mixin( "shared const" ~ base_ctor ); 78 79 @property 80 { 81 bool isSystem() const 82 { return code == system_code; } 83 84 ulong elapsed() const 85 { return currentTick - timestamp; } 86 87 @property 88 { 89 T as(T)() const { return data.as!T; } 90 T as(T)() shared const { return data.as!T; } 91 T as(T)() immutable { return data.as!T; } 92 } 93 } 94 } 95 96 interface EventProcessor { void processEvent( in Event ); } 97 98 final class FunctionEventProcessor : EventProcessor 99 { 100 private void delegate( in Event ) func; 101 102 this( void delegate( in Event ) f ) { setFunction( f ); } 103 104 void setFunction( void delegate( in Event ) f ) 105 in { assert( f !is null ); } body { func = f; } 106 107 void processEvent( in Event ev ) { func(ev); } 108 } 109 110 final class EventProcessorList : EventProcessor 111 { 112 EventProcessor[] list; 113 this( EventProcessor[] list ) { this.list = list; } 114 void processEvent( in Event ev ) 115 { foreach( p; list ) p.processEvent( ev ); } 116 } 117 118 unittest 119 { 120 auto a = Event( 1, [ 0.1, 0.2, 0.3 ] ); 121 auto gg = a.as!(double[]); 122 assert( gg == [ 0.1, 0.2, 0.3 ] ); 123 auto b = Event( 1, "some string"w ); 124 auto nn = b.as!wstring; 125 assert( nn == "some string"w ); 126 auto c = Event( 1, "some str" ); 127 auto d = shared Event( c ); 128 assert( c.as!string == "some str" ); 129 assert( d.as!string == "some str" ); 130 assert( c.code == d.code ); 131 132 struct TestStruct { double x, y; string info; immutable(int)[] data; } 133 134 auto ts = TestStruct( 10.1, 12.3, "hello", [1,2,3,4] ); 135 auto e = Event( 1, ts ); 136 137 auto f = shared Event( e ); 138 auto g = immutable Event( e ); 139 auto h = shared immutable Event( e ); 140 auto i = immutable shared Event( e ); 141 auto j = shared const Event( e ); 142 auto k = const shared Event( e ); 143 144 assert( e.as!TestStruct == ts ); 145 assert( f.as!TestStruct == ts ); 146 assert( g.as!TestStruct == ts ); 147 assert( h.as!TestStruct == ts ); 148 assert( h.as!TestStruct == ts ); 149 assert( j.as!TestStruct == ts ); 150 assert( k.as!TestStruct == ts ); 151 152 auto l = Event( f ); 153 auto m = Event( g ); 154 auto n = Event( h ); 155 156 assert( l.as!TestStruct == ts ); 157 assert( m.as!TestStruct == ts ); 158 assert( n.as!TestStruct == ts ); 159 } 160 161 unittest 162 { 163 auto a = Event( 1, [ 0.1, 0.2, 0.3 ] ); 164 assert( !a.isSystem ); 165 auto b = Event.system( SysEvData.init ); 166 assert( b.isSystem ); 167 } 168 169 unittest 170 { 171 static class Test { int[string] info; } 172 static assert( !__traits(compiles,PData(0,new Test)) ); 173 } 174 175 unittest 176 { 177 import std.conv; 178 import std.string; 179 180 static class Test 181 { 182 int[string] info; 183 184 static Test load( in void[] data ) 185 { 186 auto str = cast(string)data.dup; 187 auto elems = str.split(","); 188 int[string] buf; 189 foreach( elem; elems ) 190 { 191 auto key = elem.split(":")[0]; 192 auto val = to!int( elem.split(":")[1] ); 193 buf[key] = val; 194 } 195 return new Test( buf ); 196 } 197 198 this( in int[string] I ) 199 { 200 foreach( key, val; I ) 201 info[key] = val; 202 info.rehash(); 203 } 204 205 auto dump() const 206 { 207 string[] buf; 208 foreach( key, val; info ) buf ~= format( "%s:%s", key, val ); 209 return cast(immutable(void)[])( buf.join(",").idup ); 210 } 211 } 212 213 auto tt = new Test( [ "ok":1, "no":3, "yes":5 ] ); 214 auto a = Event( 1, tt ); 215 auto ft = a.as!Test; 216 assert( tt.info == ft.info ); 217 tt.info.remove("yes"); 218 assert( tt.info != ft.info ); 219 220 auto b = Event( 1, "ok:1,no:3" ); 221 auto ft2 = b.as!Test; 222 assert( tt.info == ft2.info ); 223 }