1 /**
2  * tools to get Interface meta info for auto-generate implementation.
3  * 
4  *   Copied from https://github.com/boolangery/d-autointf
5  *   Modified to remove extra vibe.d dependency for better footprint size.
6  *   
7  *   Copyright: © 2018 Eliott Dumeix
8  *   License: Subject to the terms of the MIT license
9  *
10  */
11 module ifinfo;
12 
13 
14 import std.traits : hasUDA, moduleName;
15 
16 /**
17  * No-Auto-Implement attribute
18  */
19 package struct NoAutoImplMethod {
20 }
21 
22 /**
23  * noImpl attribute
24  */
25 NoAutoImplMethod noImpl() @safe
26 {
27     return NoAutoImplMethod();
28 }
29 
30 /*  attributes utils */
31 private enum isEnabledMethod(alias M) = !hasUDA!(M, NoAutoImplMethod);
32 
33 /// Method Param
34 struct MethodParam {
35     string name;      /// param name
36     string type;      /// param type
37     string storetype; /// param storage-type : in or out
38 }
39 
40 /// Method info
41 struct MethodInfo {
42     string        name;     /// method name
43     MethodParam[] params;   /// method params
44     string        rettype;  /// method return type
45     string[] _customtypes;  /// method related user defined types
46 }
47 
48 /// Get Interfaces Info for a class or pure interface.
49 struct IfInfo(T) if (is(T == class) || is(T == interface))
50 {
51     import std.traits : InterfacesTuple, Parameters, ReturnType,
52                         ParameterStorageClassTuple, ParameterStorageClass, ParameterIdentifierTuple, isBuiltinType;
53     import std.typetuple : TypeTuple;
54 
55 	alias _interfaces =  InterfacesTuple!(T);
56 
57     static if (is(T == interface))
58         alias I = T;
59     else
60         alias I = _interfaces[0];
61 
62     /// members
63     static immutable membernames = [__traits(allMembers, I)];
64 
65     //pragma(msg, "member is ", membernames);
66 
67     /// Aliases to all interface methods (Compile-time).
68     alias Members = GetMembers!(); 
69 
70     /** Aliases for each method (Compile-time).
71     This tuple has the same number of entries as `methods`. */
72     alias Methods = GetMethods!();
73 
74     /// Number of methods
75     enum mthcnt = membernames.length;
76 
77     /// the method Infos of an Interface or Class
78     MethodInfo[mthcnt] methodInfos;
79 
80     /// Fills the struct with information.
81     this(int dummy) {
82         getInfos();
83     }
84 
85     // copying this struct is costly, so we forbid it
86     @disable this(this);
87 
88 	/// Get all interface method infos.
89     MethodInfo[] getInfos() {
90         foreach (i, f; Methods) {      
91             methodInfos[i].name = membernames[i];
92             alias _paramtypes = Parameters!f;
93             alias _paramident = ParameterIdentifierTuple!f;
94             alias _paramstoretype = ParameterStorageClassTuple!f;
95             //pragma(msg, "ptype: ", _paramtypes);
96             //pragma(msg, "paramstoretype: ", _paramstoretype);
97             foreach (pi, p; _paramtypes) {
98                 MethodParam pr;
99                 pr.type = p.stringof;
100                 if (! isBuiltinType!p) {
101                     methodInfos[i]._customtypes ~= p.stringof;
102                 }
103                 pr.name = _paramident[pi];
104                 if (_paramstoretype[pi] == ParameterStorageClass.out_)
105                     pr.storetype = "out";
106                 else if (_paramstoretype[pi] == ParameterStorageClass.in_)
107                     pr.storetype = "in";
108                 else if (_paramstoretype[pi] == ParameterStorageClass.ref_)
109                     pr.storetype = "ref";
110                 else if (_paramstoretype[pi] == ParameterStorageClass.return_)
111                     pr.storetype = "return";
112                 else if (_paramstoretype[pi] == ParameterStorageClass.none)
113                     pr.storetype = "none";
114                 methodInfos[i].params ~= pr;
115             }
116             methodInfos[i].rettype = ReturnType!f.stringof;
117             if (! isBuiltinType!(ReturnType!f)) {
118                 methodInfos[i]._customtypes ~= methodInfos[i].rettype;
119             }
120         }
121 
122         return methodInfos;
123     }
124 
125     private template SubInterfaceType(alias F) {
126         import std.traits : ReturnType, isInstanceOf;
127 
128         alias RT = ReturnType!F;
129         static if (is(RT == interface))
130             alias SubInterfaceType = RT;
131         else
132             alias SubInterfaceType = void;
133     }
134 
135     private template GetMembers() {
136         import std.traits : MemberFunctionsTuple;
137         template Impl(size_t idx) {
138             static if (idx < membernames.length) {
139                 enum name = membernames[idx];
140                 static if (name.length != 0)
141                     alias Impl = TypeTuple!(MemberFunctionsTuple!(I, name), Impl!(idx + 1));
142                 else
143                     alias Impl = Impl!(idx + 1);
144             }
145             else
146                 alias Impl = TypeTuple!();
147         }
148 
149         alias GetMembers = Impl!0;
150     }
151 
152     private template GetMethods() {
153         template Impl(size_t idx) {
154             static if (idx < Members.length) {
155                 alias F = Members[idx];
156                 alias SI = SubInterfaceType!F;
157                 static if (is(SI == void) && isEnabledMethod!F)
158                     alias Impl = TypeTuple!(F, Impl!(idx + 1));
159                 else
160                     alias Impl = Impl!(idx + 1);
161             }
162             else
163                 alias Impl = TypeTuple!();
164         }
165 
166         alias GetMethods = Impl!0;
167     }
168 }