1 /**
2 *   Copyright: © 2014-2015 Anton Gushcha
3 *   License: Subject to the terms of the Boost 1.0 license as specified in LICENSE file
4 *   Authors: Anton Gushcha <ncrashed@gmail.com>
5 *
6 *   Template for compile time key-value list - extension of std.traits;
7 */
8 module stribog.meta.ctinterface;
9 
10 import std.traits;
11 import std.typetuple;
12 
13 import stribog.meta.base;
14 import stribog.meta.satisfy;
15 import stribog.meta.filter;
16 import stribog.meta.members;
17 import stribog.meta.replicate;
18 import stribog.meta.map;
19 import stribog.meta.robin;
20 import stribog.meta.overload;
21 
22 /// UDA if you don't want to match element in interface
23 enum trasient;
24 
25 /**
26 *   Checks $(B Type) to satisfy compile-time interfaces listed in $(B Interfaces). 
27 *
28 *   $(B Type) should expose all methods and fields that are defined in each interface.
29 *   Compile-time interface description is struct with fields and methods without 
30 *   implementation. There are no implementations to not use the struct in usual way,
31 *   linker will stop you. 
32 *
33 *   Overloaded methods are handled as expected. Check is provided by name, return type and
34 *   parameters types of the method that is looked up.
35 */
36 template isExpose(Type, Interfaces...)
37 {
38     private template getMembers(T)
39     {
40         alias getMembers = ExpressionList!(__traits(allMembers, T));
41     }
42     
43     private template isExposeSingle(Interface)
44     {
45         alias intMembers = StrictExpressionList!(staticFilter!(filterTrasient, fieldsAndMethods!Interface));
46         alias intTypes = StrictExpressionList!(staticReplicate!(Interface, intMembers.expand.length)); 
47         alias pairs = staticMap2!(bindType, staticRobin!(intTypes, intMembers)); 
48     
49         private template filterTrasient(string name) // and aliases
50         {
51             static if(__traits(compiles, __traits(getAttributes, __traits(getMember, Interface, name))))
52             {
53                 enum filterTrasient 
54                     = staticIndexOf!(trasient, __traits(getAttributes, __traits(getMember, Interface, name))) == -1;
55             }
56             else
57             {
58                 enum filterTrasient = false;
59             }
60         }
61         
62         private template bindType(Base, string T) // also expanding overloads
63         {
64             private template getType(alias T)
65             {
66                 alias getType = typeof(T);
67             }
68             
69             alias overloads_ = staticMap!(getType , ExpressionList!(__traits(getOverloads, Base, T)));
70             static if(overloads_.length == 0)
71                 alias overloads = ExpressionList!(typeof(__traits(getMember, Base, T)));
72             else
73                 alias overloads = overloads_;
74                             
75             alias names = staticReplicate!(T, overloads.length);
76             alias bindType = staticRobin!(StrictExpressionList!overloads, StrictExpressionList!names);
77         }
78         
79         template checkMember(MemberType, string MemberName)
80         {
81             static if(hasMember!(Type, MemberName))
82             { 
83                 enum checkMember = hasOverload!(Type, Unqual!MemberType, MemberName);
84             }
85             else
86             { 
87                 enum checkMember = false;
88             }
89         }
90         
91         enum isExposeSingle = allSatisfy2!(checkMember, pairs); 
92     }
93     
94     enum isExpose = allSatisfy!(isExposeSingle, Interfaces);
95 }
96 /// Example
97 version(unittest)
98 {
99     struct CITest1
100     {
101         string a;
102         string meth1();
103         bool meth2();
104     }
105     
106     struct CITest2
107     {
108         bool delegate(string) meth3();
109     }
110     
111     struct CITest3
112     {
113         bool meth1();
114     }
115     
116     struct Test1
117     {
118         string meth1() {return "";}
119         bool meth2() {return true;}
120         
121         string a;
122         
123         bool delegate(string) meth3() { return (string) {return true;}; };
124     }
125     
126     static assert(isExpose!(Test1, CITest1, CITest2));
127     static assert(!isExpose!(Test1, CITest3));
128     
129     struct CITest4
130     {
131         bool meth1();
132         int  meth1();
133     }
134     
135     struct Test2
136     {
137         bool meth1() {return true;}
138     }
139     
140     static assert(!isExpose!(Test2, CITest4));
141     
142     struct CITest5
143     {
144         immutable string const1;
145         immutable bool const2;
146     }
147     
148     struct Test3
149     {
150         enum const1 = "";
151         enum const2 = true;
152     }
153     
154     static assert(isExpose!(Test3, CITest5));
155     
156     struct CITest6
157     {
158         
159     }
160     static assert(isExpose!(Test3, CITest6));
161 }