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 void connect(Args...)( Signal!Args sig, void delegate(Args) fnc )
108     in { assert( sig !is null, "signal is null" ); } body
109     {
110         sig.connect( newSlot!Args( fnc ) );
111         logger.Debug( "sig: %s, fnc: %s", sig, fnc );
112     }
113 }
114 
115 ///
116 class DesObject : DesBase
117 {
118     mixin DES;
119     this() { prepareDES(); }
120 }
121 
122 ///
123 unittest
124 {
125     static class Sigsig : DesObject
126     {
127         mixin DES;
128         Signal!string message;
129         Signal!float number;
130 
131         Signal!(string,int) comp;
132     }
133 
134     static class C1 : DesObject
135     {
136         mixin DES;
137         string[] messages;
138         void notSlot( float x ) { }
139         void listen( string msg ) { messages ~= msg; }
140     }
141 
142     class C2 : C1
143     {
144         mixin DES;
145         float a;
146         void abcFunc12( float x ) { a = x + 3.15; }
147     }
148 
149     class C3 : DesObject
150     {
151         mixin DES;
152 
153         string str;
154         int num;
155 
156         void cfunc( string s, int i )
157         {
158             str = s;
159             num = i;
160         }
161     }
162 
163     auto sigsig = new Sigsig;
164     auto client = new C2;
165     auto c3 = new C3;
166 
167     sigsig.message.connect( client.newSlot( &(client.listen) ) );
168     auto client_abcFunc12_slot = sigsig.number.connect( client.newSlot( &(client.abcFunc12) ) );
169 
170     sigsig.message( "hello" );
171 
172     assert( client.messages.length == 1 );
173     assert( client.messages[0] == "hello" );
174 
175     sigsig.number( 0 );
176 
177     import std.math;
178     assert( abs(client.a - 3.15) < float.epsilon );
179 
180     sigsig.number.disconnect( client_abcFunc12_slot );
181 
182     sigsig.number( 2 );
183     assert( abs(client.a - 3.15) < float.epsilon );
184     sigsig.number.connect( client_abcFunc12_slot );
185     sigsig.number( 2 );
186     assert( abs(client.a - 5.15) < float.epsilon );
187 
188     sigsig.comp.connect( c3.newSlot( &c3.cfunc ) );
189     sigsig.comp( "okda", 13 );
190     assert( c3.str == "okda" );
191     assert( c3.num == 13 );
192 }
193 
194 unittest
195 {
196     class Sig : DesObject
197     {
198         mixin DES;
199         Signal!(string,int) s;
200     }
201 
202     class Obj : DesObject {}
203 
204     auto sig = new Sig;
205     auto obj = new Obj;
206 
207     string[] str_arr;
208     int[] int_arr;
209 
210     sig.s.connect( obj.newSlot(( string s, int i )
211                 {
212                     str_arr ~= s;
213                     int_arr ~= i;
214                 }) );
215 
216     sig.s( "hello", 3 );
217     sig.s( "world", 5 );
218 
219     assert( str_arr == ["hello","world"] );
220     assert( int_arr == [3,5] );
221 }
222 
223 unittest
224 {
225     class C1 : DesObject
226     {
227         mixin DES;
228         Signal!(string) sig;
229     }
230 
231     class C2 : C1 
232     {
233         string[] buf;
234         this() { connect( sig, (string s){ buf ~= s; } ); }
235     }
236 
237     auto c2 = new C2;
238 
239     c2.sig( "hello" );
240     assert( c2.buf == ["hello"] );
241 }
242 
243 
244 unittest
245 {
246     class C1 : DesObject
247     {
248         mixin DES;
249         Signal!() empty;
250         SignalBox!int number;
251     }
252 
253     auto c1 = new C1;
254 
255     bool empty_call = false;
256     c1.connect( c1.empty, { empty_call = true; } );
257 
258     assert( !empty_call );
259     c1.empty();
260     assert( empty_call );
261 
262     int xx = 0;
263     int ss = 0;
264     int ee = 0;
265     c1.connect( c1.number.begin, (int v){ ss = v; } );
266     c1.connect( c1.number.end, (int v){ ee = v; } );
267     c1.connect( c1.number, (int v){ xx = v; } );
268     assert( xx == 0 );
269     c1.number(12);
270     assert( xx == 12 );
271     assert( ss == 12 );
272     assert( ee == 12 );
273 }