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 }