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