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 import std.string : format; 29 30 import core.time; 31 32 import des.util.data.pdata; 33 34 import des.flow.base; 35 import des.flow.sysevdata; 36 37 /// Pass data between threads 38 struct Event 39 { 40 /// `ulong.max` reserved system event code 41 enum system_code = ulong.max; 42 43 alias typeof(this) Self; 44 45 /// 46 ulong code; 47 48 /// 49 ulong timestamp; 50 51 /// information in event 52 PData data; 53 54 /++ generate system event 55 returns: 56 Event 57 +/ 58 static auto system( SysEvData sed ) 59 { 60 Self ev; 61 ev.code = system_code; 62 ev.timestamp = currentTick; 63 ev.data = PData(sed); 64 return ev; 65 } 66 67 /// 68 this(T)( ulong code, in T value ) 69 if( is( typeof(PData(value)) ) ) 70 in { assert( code != system_code ); } body 71 { 72 this.code = code; 73 timestamp = currentTick; 74 data = PData(value); 75 } 76 77 private enum base_ctor = 78 q{ 79 this( in Event ev ) %s 80 { 81 code = ev.code; 82 timestamp = ev.timestamp; 83 data = ev.data; 84 } 85 }; 86 87 mixin( format( base_ctor, "" ) ); 88 mixin( format( base_ctor, "const" ) ); 89 mixin( format( base_ctor, "immutable" ) ); 90 mixin( format( base_ctor, "shared" ) ); 91 mixin( format( base_ctor, "shared const" ) ); 92 93 @property 94 { 95 /// 96 bool isSystem() pure const 97 { return code == system_code; } 98 99 /// elapsed time before create event 100 ulong elapsed() const 101 { return currentTick - timestamp; } 102 103 /// get data as type T 104 T as(T)() const { return data.as!T; } 105 /// get data as type T 106 T as(T)() shared const { return data.as!T; } 107 /// get data as type T 108 T as(T)() immutable { return data.as!T; } 109 110 /// get pdata 111 immutable(void)[] pdata() const { return data.data; } 112 /// get pdata 113 immutable(void)[] pdata() shared const { return data.data; } 114 /// get pdata 115 immutable(void)[] pdata() immutable { return data.data; } 116 } 117 } 118 119 /// 120 interface EventProcessor { /++ +/ void processEvent( in Event ); } 121 122 /// 123 interface EventBus { /++ +/ void pushEvent( in Event ); } 124 125 /// 126 unittest 127 { 128 auto a = Event( 1, [ 0.1, 0.2, 0.3 ] ); 129 auto gg = a.as!(double[]); 130 assert( gg == [ 0.1, 0.2, 0.3 ] ); 131 auto b = Event( 1, "some string"w ); 132 auto nn = b.as!wstring; 133 assert( nn == "some string"w ); 134 auto c = Event( 1, "some str" ); 135 auto d = shared Event( c ); 136 assert( c.as!string == "some str" ); 137 assert( d.as!string == "some str" ); 138 assert( c.code == d.code ); 139 140 struct TestStruct { double x, y; string info; immutable(int)[] data; } 141 142 auto ts = TestStruct( 10.1, 12.3, "hello", [1,2,3,4] ); 143 auto e = Event( 1, ts ); 144 145 auto f = shared Event( e ); 146 auto g = immutable Event( e ); 147 auto h = shared const Event( e ); 148 149 assert( e.as!TestStruct == ts ); 150 assert( f.as!TestStruct == ts ); 151 assert( g.as!TestStruct == ts ); 152 assert( h.as!TestStruct == ts ); 153 154 auto l = Event( f ); 155 auto m = Event( g ); 156 auto n = Event( h ); 157 158 assert( l.as!TestStruct == ts ); 159 assert( m.as!TestStruct == ts ); 160 assert( n.as!TestStruct == ts ); 161 } 162 163 unittest 164 { 165 auto a = Event( 1, [ 0.1, 0.2, 0.3 ] ); 166 assert( !a.isSystem ); 167 auto b = Event.system( SysEvData.init ); 168 assert( b.isSystem ); 169 } 170 171 unittest 172 { 173 static class Test { int[string] info; } 174 static assert( !__traits(compiles,PData(0,new Test)) ); 175 } 176 177 unittest 178 { 179 import std.conv; 180 import std.string; 181 182 static class Test 183 { 184 int[string] info; 185 186 static Test load( in void[] data ) 187 { 188 auto str = cast(string)data.dup; 189 auto elems = str.split(","); 190 int[string] buf; 191 foreach( elem; elems ) 192 { 193 auto key = elem.split(":")[0]; 194 auto val = to!int( elem.split(":")[1] ); 195 buf[key] = val; 196 } 197 return new Test( buf ); 198 } 199 200 this( in int[string] I ) 201 { 202 foreach( key, val; I ) 203 info[key] = val; 204 info.rehash(); 205 } 206 207 auto dump() const 208 { 209 string[] buf; 210 foreach( key, val; info ) buf ~= format( "%s:%s", key, val ); 211 return cast(immutable(void)[])( buf.join(",").idup ); 212 } 213 } 214 215 auto tt = new Test( [ "ok":1, "no":3, "yes":5 ] ); 216 auto a = Event( 1, tt.dump() ); 217 auto ft = Test.load( a.data ); 218 assert( tt.info == ft.info ); 219 tt.info.remove("yes"); 220 assert( tt.info != ft.info ); 221 222 auto b = Event( 1, "ok:1,no:3" ); 223 auto ft2 = Test.load( b.data ); 224 assert( tt.info == ft2.info ); 225 } 226 227 /// 228 unittest 229 { 230 static struct TestStruct { double x, y; string info; immutable(int)[] data; } 231 auto ts = TestStruct( 3.14, 2.7, "hello", [ 2, 3, 4 ] ); 232 233 auto a = Event( 8, ts ); 234 auto ac = const Event( a ); 235 auto ai = immutable Event( a ); 236 auto as = shared Event( a ); 237 auto acs = const shared Event( a ); 238 239 assert( a.as!TestStruct == ts ); 240 assert( ac.as!TestStruct == ts ); 241 assert( ai.as!TestStruct == ts ); 242 assert( as.as!TestStruct == ts ); 243 assert( acs.as!TestStruct == ts ); 244 }