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 trpc.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.ref_)
107                     pr.storetype = "ref";
108                 else if (_paramstoretype[pi] == ParameterStorageClass.return_)
109                     pr.storetype = "return";
110                 else if (_paramstoretype[pi] == ParameterStorageClass.none)
111                     pr.storetype = "none";
112                 static if (__VERSION__ > 2093L) {
113                     if (_paramstoretype[pi] == ParameterStorageClass.in_)
114                         pr.storetype = "in";
115                 }
116                 methodInfos[i].params ~= pr;
117             }
118             methodInfos[i].rettype = ReturnType!f.stringof;
119             if (! isBuiltinType!(ReturnType!f)) {
120                 methodInfos[i]._customtypes ~= methodInfos[i].rettype;
121             }
122         }
123 
124         return methodInfos;
125     }
126 
127     private template SubInterfaceType(alias F) {
128         import std.traits : ReturnType, isInstanceOf;
129 
130         alias RT = ReturnType!F;
131         static if (is(RT == interface))
132             alias SubInterfaceType = RT;
133         else
134             alias SubInterfaceType = void;
135     }
136 
137     private template GetMembers() {
138         import std.traits : MemberFunctionsTuple;
139         template Impl(size_t idx) {
140             static if (idx < membernames.length) {
141                 enum name = membernames[idx];
142                 static if (name.length != 0)
143                     alias Impl = TypeTuple!(MemberFunctionsTuple!(I, name), Impl!(idx + 1));
144                 else
145                     alias Impl = Impl!(idx + 1);
146             }
147             else
148                 alias Impl = TypeTuple!();
149         }
150 
151         alias GetMembers = Impl!0;
152     }
153 
154     private template GetMethods() {
155         template Impl(size_t idx) {
156             static if (idx < Members.length) {
157                 alias F = Members[idx];
158                 alias SI = SubInterfaceType!F;
159                 static if (is(SI == void) && isEnabledMethod!F)
160                     alias Impl = TypeTuple!(F, Impl!(idx + 1));
161                 else
162                     alias Impl = Impl!(idx + 1);
163             }
164             else
165                 alias Impl = TypeTuple!();
166         }
167 
168         alias GetMethods = Impl!0;
169     }
170 }