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 }