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 }