1 module des.util.arch.base;
2 
3 import std.stdio;
4 import std..string;
5 
6 import des.util.arch.sig;
7 import des.util.arch.slot;
8 import des.util.arch.emm;
9 
10 import des.util.stdext.traits;
11 
12 import des.util.logsys;
13 
14 ///
15 template isObject(alias f) { enum isObject = __traits(compiles,typeof(f)); }
16 
17 ///
18 template isSignalObj(alias f)
19 {
20     static if( isObject!f ) enum isSignalObj = isSignal!(typeof(f));
21     else enum isSignalObj = false;
22 }
23 
24 ///
25 interface DesBase : ExternalMemoryManager, SlotHandler
26 {
27     protected
28     {
29         ///
30         void createSlotController();
31 
32         void __createSignals();
33 
34         ///
35         final void prepareDES()
36         {
37             createSlotController();
38             __createSignals();
39         }
40     }
41 
42     ///
43     mixin template DES()
44     {
45         import des.util.stdext.traits;
46 
47         static if( !is(typeof(__DES_BASE_CLASS)) )
48         {
49             mixin EMM;
50 
51             enum __DES_BASE_CLASS = true;
52 
53             private SlotController __slot_controller;
54             final SlotController slotController() @property { return __slot_controller; }
55 
56             protected
57             {
58                 void createSlotController() { __slot_controller = newEMM!SlotController; }
59                 void __createSignals() { mixin( __createSignalsMixin!(typeof(this)) ); }
60             }
61         }
62         else
63         {
64             override protected
65             {
66                 void __createSignals() { mixin( __createSignalsMixin!(typeof(this)) ); }
67             }
68         }
69     }
70 
71     template allSignalNames(T)
72     {
73         template isSignalMember(string n)
74         {
75             static if( __traits(compiles,typeof(__traits(getMember,T,n))) )
76                 enum isSignalMember = isSignal!(typeof(__traits(getMember,T,n)));
77             else enum isSignalMember = false;
78         }
79 
80         alias allSignalNames = staticFilter!( isSignalMember, __traits(allMembers,T) );
81     }
82 
83     static final protected @property
84     {
85         string __createSignalsMixin(T)()//if( is( T : DesBase ) )
86         {
87             string[] ret;
88 
89             enum list = [ allSignalNames!T ];
90 
91             static if( list.length == 0 ) return "";
92             else
93             {
94                 foreach( sig; list )
95                     ret ~= format( "%1$s = newEMM!(typeof(%1$s))();", sig );
96 
97                 return ret.join("\n");
98             }
99         }
100     }
101 
102     ///
103     final auto newSlot(Args...)( void delegate(Args) fnc )
104     { return newEMM!(Slot!Args)( this, fnc ); }
105 
106     ///
107     final auto connect(Args...)( Signal!Args sig, void delegate(Args) fnc )
108     in { assert( sig !is null, "signal is null" ); } body
109     {
110         auto ret = newSlot!Args( fnc );
111         sig.connect( ret );
112         logger.Debug( "sig: %s, fnc: %s", sig, fnc );
113         return ret;
114     }
115 }
116 
117 ///
118 class DesObject : DesBase
119 {
120     mixin DES;
121     this() { prepareDES(); }
122 }
123 
124 ///
125 unittest
126 {
127     static class Sigsig : DesObject
128     {
129         mixin DES;
130         Signal!string message;
131         Signal!float number;
132 
133         Signal!(string,int) comp;
134     }
135 
136     static class C1 : DesObject
137     {
138         mixin DES;
139         string[] messages;
140         void notSlot( float x ) { }
141         void listen( string msg ) { messages ~= msg; }
142     }
143 
144     class C2 : C1
145     {
146         mixin DES;
147         float a;
148         void abcFunc12( float x ) { a = x + 3.15; }
149     }
150 
151     class C3 : DesObject
152     {
153         mixin DES;
154 
155         string str;
156         int num;
157 
158         void cfunc( string s, int i )
159         {
160             str = s;
161             num = i;
162         }
163     }
164 
165     auto sigsig = new Sigsig;
166     auto client = new C2;
167     auto c3 = new C3;
168 
169     sigsig.message.connect( client.newSlot( &(client.listen) ) );
170     auto client_abcFunc12_slot = sigsig.number.connect( client.newSlot( &(client.abcFunc12) ) );
171 
172     sigsig.message( "hello" );
173 
174     assert( client.messages.length == 1 );
175     assert( client.messages[0] == "hello" );
176 
177     sigsig.number( 0 );
178 
179     import std.math;
180     assert( abs(client.a - 3.15) < float.epsilon );
181 
182     sigsig.number.disconnect( client_abcFunc12_slot );
183 
184     sigsig.number( 2 );
185     assert( abs(client.a - 3.15) < float.epsilon );
186     sigsig.number.connect( client_abcFunc12_slot );
187     sigsig.number( 2 );
188     assert( abs(client.a - 5.15) < float.epsilon );
189 
190     sigsig.comp.connect( c3.newSlot( &c3.cfunc ) );
191     sigsig.comp( "okda", 13 );
192     assert( c3.str == "okda" );
193     assert( c3.num == 13 );
194 }
195 
196 unittest
197 {
198     class Sig : DesObject
199     {
200         mixin DES;
201         Signal!(string,int) s;
202     }
203 
204     class Obj : DesObject {}
205 
206     auto sig = new Sig;
207     auto obj = new Obj;
208 
209     string[] str_arr;
210     int[] int_arr;
211 
212     sig.s.connect( obj.newSlot(( string s, int i )
213                 {
214                     str_arr ~= s;
215                     int_arr ~= i;
216                 }) );
217 
218     sig.s( "hello", 3 );
219     sig.s( "world", 5 );
220 
221     assert( str_arr == ["hello","world"] );
222     assert( int_arr == [3,5] );
223 }
224 
225 unittest
226 {
227     class C1 : DesObject
228     {
229         mixin DES;
230         Signal!(string) sig;
231     }
232 
233     class C2 : C1 
234     {
235         string[] buf;
236         this() { connect( sig, (string s){ buf ~= s; } ); }
237     }
238 
239     auto c2 = new C2;
240 
241     c2.sig( "hello" );
242     assert( c2.buf == ["hello"] );
243 }
244 
245 
246 unittest
247 {
248     class C1 : DesObject
249     {
250         mixin DES;
251         Signal!() empty;
252         SignalBox!int number;
253     }
254 
255     auto c1 = new C1;
256 
257     bool empty_call = false;
258     c1.connect( c1.empty, { empty_call = true; } );
259 
260     assert( !empty_call );
261     c1.empty();
262     assert( empty_call );
263 
264     int xx = 0;
265     int ss = 0;
266     int ee = 0;
267     c1.connect( c1.number.begin, (int v){ ss = v; } );
268     c1.connect( c1.number.end, (int v){ ee = v; } );
269     c1.connect( c1.number, (int v){ xx = v; } );
270     assert( xx == 0 );
271     c1.number(12);
272     assert( xx == 12 );
273     assert( ss == 12 );
274     assert( ee == 12 );
275 }