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 }