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 }