1 /+ 2 The MIT License (MIT) 3 4 Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)> 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in 14 all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 THE SOFTWARE. 23 +/ 24 25 /+ 26 using: 27 28 void func(T)( T v ) 29 if( isPseudoInterface(Interface,T) ) 30 { 31 } 32 33 +/ 34 module des.util.pseudointerface; 35 36 import std.traits; 37 38 bool isPseudoInterface(I,T, bool _assert=true, string FILE=__FILE__, int LINE=__LINE__ )() 39 { 40 import std.string; 41 import std.conv; 42 bool fail(Args...)( string fmt, Args args ) 43 { 44 if( _assert ) assert( 0, FILE ~ "(" ~ to!string(LINE) ~ ") " ~ format( fmt, args ) ); 45 else return false; 46 } 47 bool checkMembers( I, T, mem... )() 48 { 49 static if( is(typeof(mem[0]) == string ) && mem.length > 1 ) 50 return checkMembers!(I,T,mem[0])() && checkMembers!(I,T,mem[1 .. $])(); 51 else 52 { 53 // существует ли тип поля mem в I 54 static if( is( typeof( __traits(getMember, I, mem ) ) ) ) 55 { 56 alias typeof( __traits(getMember, I, mem ) ) i; 57 58 // если поле "интерфейса" не вызываемое 59 static if( !isCallable!i ) return true; 60 61 // найден ли искомый метод в T 62 static if( __traits(compiles, __traits(getMember, T, mem) ) ) 63 { 64 alias typeof(__traits(getMember, T, mem )) t; 65 66 static if( !isCallable!t ) 67 return fail( "member %s in class %s is not cllable", mem, T.stringof ); 68 else 69 static if( !is( ReturnType!i == ReturnType!t ) ) 70 return fail( "return type of %s in %s must be %s (not %s)", 71 mem, typeid(T), typeid(ReturnType!i), typeid(ReturnType!t) ); 72 else 73 static if( !is( ParameterTypeTuple!i == ParameterTypeTuple!t ) ) 74 return fail( "parameter type tuple of %s in %s must be %s (not %s)", 75 mem, typeid(T), typeid(ParameterTypeTuple!i), typeid(ParameterTypeTuple!t) ); 76 else 77 static if( [ParameterStorageClassTuple!i] != [ParameterStorageClassTuple!t] ) 78 return fail( "parameter storage class tuple of %s in %s must be %s (not %s)", 79 mem, typeid(T), to!string(ParameterStorageClassTuple!i), 80 to!string(ParameterStorageClassTuple!t) ); 81 else 82 return true; 83 } 84 else return fail( "member %s not found in class %s", mem, typeid(T) ); 85 } 86 else return true; 87 } 88 } 89 return checkMembers!(I,T,__traits(allMembers,I))(); 90 } 91 92 unittest 93 { 94 interface IFace 95 { 96 void func1( int ); 97 size_t func2( string ); 98 } 99 100 struct Afunc1 { void opCall( int ){} } 101 struct Afunc2 { size_t opCall( string ){ return 0; } } 102 103 class A 104 { 105 Afunc1 func1; 106 Afunc2 func2; 107 } 108 109 struct B 110 { 111 void func1( int ) { } 112 size_t func2( string str ) { return 0; } 113 } 114 115 class C 116 { 117 void func1( int ) { } 118 size_t func2( string str ) { return 0; } 119 } 120 121 class D: A 122 { 123 void func1( int ) { } 124 size_t func2( string str ) { return 0; } 125 } 126 127 class E 128 { 129 int func1; 130 size_t func2( string str ){ return 0; } 131 } 132 133 class F 134 { 135 void func1() { } 136 size_t func2( string str ){ return 0; } 137 } 138 139 class G 140 { 141 void func1( in int ){} 142 size_t func2( string str ){ return 0; } 143 } 144 145 static assert( isPseudoInterface!( IFace,A,false ) ); 146 static assert( isPseudoInterface!( IFace,B,false ) ); 147 static assert( isPseudoInterface!( IFace,C,false ) ); 148 static assert( isPseudoInterface!( IFace,D,false ) ); 149 150 static assert( isPseudoInterface!(A,C,false) ); 151 152 static assert( !isPseudoInterface!( IFace,E,false ) ); 153 static assert( !isPseudoInterface!( IFace,F,false ) ); 154 static assert( !isPseudoInterface!( IFace,G,false ) ); 155 } 156 157 unittest 158 { 159 interface A 160 { 161 void func1( int ); 162 } 163 164 class B : A 165 { 166 void func1( int ) {} 167 int func2( string ){ return 0; } 168 } 169 170 struct Cfunc1 { void opCall( int ) { } } 171 172 interface iB: A 173 { 174 int func2( string ); 175 } 176 177 struct C 178 { 179 Cfunc1 func1; 180 int func2( string ){ return 0; } 181 } 182 183 // функции базового Object тоже учитываются 184 assert( !isPseudoInterface!( B, C,false ) ); 185 186 assert( isPseudoInterface!( iB, C,false ) ); 187 }