1 /** 2 License: 3 Boost Software License - Version 1.0 - August 17th, 2003 4 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 27 Authors: 28 aermicioi 29 **/ 30 module aermicioi.util.traits.enforce; 31 32 import aermicioi.util.traits.partial; 33 import aermicioi.util.traits.traits; 34 import std.traits; 35 import std.meta; 36 37 template enforceTypeTuple(Original...) { 38 39 template enforceTypeTuple(Enforced...) { 40 41 static if (Original.length != Enforced.length) { 42 enum bool enforceTypeTuple = false; 43 } else { 44 45 bool enforceTypeTuple() { 46 47 bool state = true; 48 foreach (index, Type; Original) { 49 50 static if (!is(Enforced[index] : Type)) { 51 52 state = false; 53 } 54 } 55 56 return state; 57 } 58 } 59 } 60 } 61 62 template enforceMethodSignature(InterfaceFunction, Function) { 63 alias enforceInterfaceFunctionParameters = enforceTypeTuple!(Parameters!InterfaceFunction); 64 enum bool enforceMethodSignature = 65 is(ReturnType!Function : ReturnType!InterfaceFunction) && 66 enforceInterfaceFunctionParameters!(Parameters!Function); 67 } 68 69 template enforceMethodSignature(InterfaceFunction, Overloads...) 70 if (Overloads.length > 1) { 71 72 static if (enforceMethodSignature!(InterfaceFunction, Overloads[0])) { 73 74 enum bool enforceMethodSignature = true; 75 } else static if (Overloads.length > 1) { 76 77 enum bool enforceMethodSignature = enforceMethodSignature!(InterfaceFunction, Overloads[1 .. $]); 78 } else { 79 80 enum bool enforceMethodSignature = false; 81 } 82 } 83 84 template enforceTypeSignature(InterfaceType, Type) { 85 86 enum bool enforceTypeSignature = 87 Filter!( 88 templateNot!( 89 templateAnd!( 90 partialPrefixed!( 91 hasMember, 92 Type 93 ), 94 chain!( 95 isSomeFunction, 96 partialPrefixed!( 97 getMember, 98 Type 99 ) 100 ), 101 chain!( 102 partialPrefixed!( 103 allSatisfy, 104 chain!( 105 enforceMethodSignature, 106 partial!( 107 typeOf, 108 chain!( 109 partialPrefixed!( 110 staticMap, 111 typeOf 112 ), 113 partialPrefixed!( 114 getOverloads, 115 Type 116 ), 117 identifier 118 ) 119 ) 120 ) 121 ), 122 partialPrefixed!( 123 getOverloads, 124 InterfaceType 125 ), 126 ) 127 ) 128 ), 129 Filter!( 130 failable!( 131 chain!( 132 isSomeFunction, 133 partialPrefixed!( 134 getMember, 135 InterfaceType 136 ), 137 ), 138 false 139 ), 140 __traits(allMembers, InterfaceType) 141 ) 142 ).length == 0; 143 } 144 145 unittest { 146 static interface Interface { 147 string method(double); 148 void method(int); 149 150 void* secondMethod(); 151 float secondMethod(int, double, float); 152 } 153 154 import std.stdio; 155 156 struct Implementor { 157 void method(int); 158 string method(double); 159 160 float secondMethod(ubyte, double, double); 161 void* secondMethod(); 162 } 163 164 struct WrongImplementor { 165 long method(int); // wrong here 166 string method(double); 167 168 float secondMethod(int, double, float); 169 void* secondMethod(); 170 } 171 172 static assert(enforceTypeSignature!(Interface, Implementor)); 173 static assert(!enforceTypeSignature!(Interface, WrongImplementor)); 174 }