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