1 module glued.adhesives.typeindex;
2 
3 import std.array;
4 import std.algorithm.iteration;
5 
6 import glued.logging;
7 
8 import glued.set;
9 
10 enum TypeKind { INTERFACE, ABSTRACT_CLASS, CONCRETE_CLASS }
11 
12 class InheritanceIndex {
13     import std.algorithm;
14     TypeKind[string] kinds;
15     Set!(string)[string] implementations;
16     mixin CreateLogger;
17     Logger log;
18 
19     this(LogSink logSink){
20         log = Logger(logSink);
21     }
22 
23     override string toString(){
24         import std.conv: to;
25         string[] pairs;
26         foreach (k; implementations.keys()){
27             pairs ~= "'"~k~"': Set!string("~to!string(implementations[k].asRange.array)~")";
28         }
29         return typeof(this).stringof~"(kinds="~to!string(kinds)~", implementations=["~pairs.join(", ")~"])";
30     }
31 
32     void markExists(string query, TypeKind kind){
33         log.debug_.emit(query, " is of kind ", kind);
34         if (query in kinds)
35         {
36             assert(kinds[query] == kind); //todo better exception
37             log.debug_.emit("Checks out with previous knowledge");
38         } 
39         else 
40         {
41             kinds[query] = kind;
42             log.debug_.emit("That's new knowledge");
43         }
44     }
45 
46     void markExtends(string extending, string extended){
47         log.debug_.emit(extending, " extends ", extended);
48         if (!(extended in implementations))
49             implementations[extended] = Set!string();
50         implementations[extended].put(extending);
51     }
52 
53     TypeKind getTypeKind(string typeName){
54         return TypeKind.INTERFACE;
55     }
56 
57     Set!string getDirectSubtypes(string typeName){
58         auto result = Set!string();
59         if (typeName in implementations) {
60             result.addAll(implementations[typeName].asRange);
61         }
62         return result;
63     }
64 
65     Set!string getSubtypes(string typeName){
66         auto result = Set!string();
67         auto direct = getDirectSubtypes(typeName);
68         auto indirect = direct.asRange.map!(d => getSubtypes(d).asRange.array).joiner;
69         result.addAll(direct.asRange);
70         result.addAll(indirect);
71         return result;
72     }
73 
74     auto getImplementations(string typeName){
75         return getSubtypes(typeName).asRange.filter!(n => kinds[n] == TypeKind.CONCRETE_CLASS);
76     }
77 
78     auto getDirectImplementations(string typeName){
79         return getDirectSubtypes(typeName).asRange.filter!(n => kinds[n] == TypeKind.CONCRETE_CLASS);
80     }
81 
82     auto find(TypeKind kind){
83         return kinds.keys().filter!(x => kinds[x] == kind);
84     }
85 
86 }