1 module des.arch.base; 2 3 import std..string; 4 5 import des.ts; 6 import des.log; 7 8 import des.arch.util; 9 import des.arch.sig; 10 import des.arch.slot; 11 import des.arch.emm; 12 13 /// 14 template isObject(alias f) { enum isObject = __traits(compiles,typeof(f)); } 15 16 /// 17 template isSignalObj(alias f) 18 { 19 static if( isObject!f ) enum isSignalObj = isSignal!(typeof(f)); 20 else enum isSignalObj = false; 21 } 22 23 /// 24 interface DesBase : ExternalMemoryManager, SlotHandler 25 { 26 protected 27 { 28 /// 29 void createSlotController(); 30 31 void __createSignals(); 32 33 /// 34 final void prepareDES() 35 { 36 createSlotController(); 37 __createSignals(); 38 } 39 } 40 41 /// 42 mixin template DES() 43 { 44 import des.arch.util; 45 46 static if( !is(typeof(__DES_BASE_CLASS)) ) 47 { 48 mixin EMM; 49 50 enum __DES_BASE_CLASS = true; 51 52 private SlotController __slot_controller; 53 final SlotController slotController() @property { return __slot_controller; } 54 55 protected 56 { 57 void createSlotController() { __slot_controller = newEMM!SlotController; } 58 void __createSignals() { mixin( __createSignalsMixin!(typeof(this)) ); } 59 } 60 } 61 else 62 { 63 override protected 64 { 65 void __createSignals() { mixin( __createSignalsMixin!(typeof(this)) ); } 66 } 67 } 68 } 69 70 template allSignalNames(T) 71 { 72 template isSignalMember(string n) 73 { 74 static if( __traits(compiles,typeof(__traits(getMember,T,n))) ) 75 enum isSignalMember = isSignal!(typeof(__traits(getMember,T,n))); 76 else enum isSignalMember = false; 77 } 78 79 alias allSignalNames = staticFilter!( isSignalMember, __traits(allMembers,T) ); 80 } 81 82 static final protected @property 83 { 84 string __createSignalsMixin(T)()//if( is( T : DesBase ) ) 85 { 86 string[] ret; 87 88 enum list = [ allSignalNames!T ]; 89 90 static if( list.length == 0 ) return ""; 91 else 92 { 93 foreach( sig; list ) 94 ret ~= format( "%1$s = newEMM!(typeof(%1$s))();", sig ); 95 96 return ret.join("\n"); 97 } 98 } 99 } 100 101 /// 102 final auto newSlot(Args...)( void delegate(Args) fnc ) 103 { return newEMM!(Slot!Args)( this, fnc ); } 104 105 /// 106 final auto connect(Args...)( Signal!Args sig, void delegate(Args) fnc ) 107 in { assert( sig !is null, "signal is null" ); } body 108 { 109 auto ret = newSlot!Args( fnc ); 110 sig.connect( ret ); 111 logger.Debug( "sig: %s, fnc: %s", sig, fnc ); 112 return ret; 113 } 114 } 115 116 /// 117 class DesObject : DesBase 118 { 119 mixin DES; 120 this() { prepareDES(); } 121 } 122 123 /// 124 unittest 125 { 126 static class Sigsig : DesObject 127 { 128 mixin DES; 129 Signal!string message; 130 Signal!float number; 131 132 Signal!(string,int) comp; 133 } 134 135 static class C1 : DesObject 136 { 137 mixin DES; 138 string[] messages; 139 void notSlot( float x ) { } 140 void listen( string msg ) { messages ~= msg; } 141 } 142 143 class C2 : C1 144 { 145 mixin DES; 146 float a; 147 void abcFunc12( float x ) { a = x + 3.15; } 148 } 149 150 class C3 : DesObject 151 { 152 mixin DES; 153 154 string str; 155 int num; 156 157 void cfunc( string s, int i ) 158 { 159 str = s; 160 num = i; 161 } 162 } 163 164 auto sigsig = new Sigsig; 165 auto client = new C2; 166 auto c3 = new C3; 167 168 sigsig.message.connect( client.newSlot( &(client.listen) ) ); 169 auto client_abcFunc12_slot = sigsig.number.connect( client.newSlot( &(client.abcFunc12) ) ); 170 171 sigsig.message( "hello" ); 172 173 assertEq( client.messages.length, 1 ); 174 assertEq( client.messages[0], "hello" ); 175 176 sigsig.number( 0 ); 177 178 assertEq( client.a, 3.15 ); 179 180 sigsig.number.disconnect( client_abcFunc12_slot ); 181 182 sigsig.number( 2 ); 183 assertEq( client.a, 3.15 ); 184 sigsig.number.connect( client_abcFunc12_slot ); 185 sigsig.number( 2 ); 186 assertEq( client.a, 5.15 ); 187 188 sigsig.comp.connect( c3.newSlot( &c3.cfunc ) ); 189 sigsig.comp( "okda", 13 ); 190 assertEq( c3.str, "okda" ); 191 assertEq( 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 assertEq( str_arr, ["hello","world"] ); 220 assertEq( 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 assertEq( 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 assertEq( xx, 0 ); 269 c1.number(12); 270 assertEq( xx, 12 ); 271 assertEq( ss, 12 ); 272 assertEq( ee, 12 ); 273 }