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 }