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 }