1 module glued.application.scanlisteners.interfaces; 2 3 import std.array; 4 import std.algorithm; 5 import std.traits; 6 7 import glued.logging; 8 import glued.utils; 9 import glued.set; 10 11 import glued.codescan.scannable; 12 import glued.codescan.listener; 13 14 import glued.application.stereotypes; 15 16 import glued.adhesives.typeresolver; 17 import glued.adhesives.typeindex: InheritanceIndex, TypeKind; 18 19 import dejector; 20 21 class InterfaceListener: ScanListener!Dejector { 22 mixin CreateLogger; 23 private Logger log; 24 private Dejector injector; 25 private InheritanceIndex inheritanceIndex; 26 private InterfaceResolver resolver; 27 28 void init(Dejector injector) 29 { 30 this.injector = injector; 31 log = Logger(injector.get!LogSink); 32 inheritanceIndex = new InheritanceIndex(injector.get!LogSink); 33 injector.bind!(InheritanceIndex)(new InstanceProvider(inheritanceIndex)); 34 resolver = new InterfaceResolver(injector); 35 injector.bind!(InterfaceResolver)(new InstanceProvider(resolver)); 36 37 } 38 39 void onScannable(alias scannable)() if (isScannable!scannable) 40 { 41 //todo track what scannable does asset come from 42 } 43 44 void onType(A)() //A is for "aggregate" 45 { 46 static if (canHandle!A()) //todo log about it 47 { 48 immutable key = fullyQualifiedName!A; //todo queryString? 49 log.debug_.emit("Handling ", key); 50 static if (is(A == interface)) 51 { 52 immutable kind = TypeKind.INTERFACE; 53 } 54 else 55 { 56 static if (__traits(isAbstractClass, A)) 57 { 58 immutable kind = TypeKind.ABSTRACT_CLASS; 59 } 60 else 61 { 62 immutable kind = TypeKind.CONCRETE_CLASS; 63 } 64 } 65 log.debug_.emit("Kind: ", kind); 66 inheritanceIndex.markExists(key, kind); 67 import std.traits; 68 static foreach (b; BaseTypeTuple!A){ 69 static if (!is(b == Object)){ 70 //todo ditto 71 log.trace.emit(fullyQualifiedName!A, " extends ", fullyQualifiedName!b); 72 inheritanceIndex.markExtends(fullyQualifiedName!A, fullyQualifiedName!b); 73 onType!(b)(); 74 } 75 } 76 } 77 } 78 79 void onBundleModule(string modName)() 80 { 81 } 82 83 void onScannerFreeze() 84 { 85 log.debug_.emit("Trying to bind interfaces"); 86 foreach (i; inheritanceIndex.find(TypeKind.INTERFACE)){ 87 auto impls = inheritanceIndex.getImplementations(i).array; 88 if (impls.length == 1){ 89 log.debug_.emit("Binding interface ", i, " with sole implementation ", impls[0]); 90 injector.bind(i, impls[0]); 91 } else { 92 if (impls.length == 0){ //todo turn off somehow; by log level, or maybe by dedicated config entry? 93 log.warn.emit("Interface ", i, " has no implementation in current context!"); 94 } 95 } 96 } 97 } 98 99 private static bool canHandle(A)(){ 100 //todo reuse isObjectType from dejector 101 return is(A == interface) || is(A == class); 102 } 103 }