1 /*
2 Copyright (c) 2015-2021 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 /**
30  * Prototype-based OOP system for structs.
31  *
32  * Description:
33  * Supports multiple inheritance, parametric polymorphism (struct interfaces),
34  * interface inheritance
35  *
36  * Copyright: Timur Gafarov 2015-2021.
37  * License: $(LINK2 https://boost.org/LICENSE_1_0.txt, Boost License 1.0).
38  * Authors: Timur Gafarov
39  */
40 module dlib.core.oop;
41 
42 import std.traits;
43 
44 /**
45  * Inheritance mixin
46  *
47  * Description:
48  * Inserts structs specified by PT type tuple as members and a dispatcher method
49  * that statically transfers any method calls and member accesses to corresponding
50  * child struct.
51  */
52 mixin template Inherit(PT...)
53 {
54     PT _parent;
55     alias _parentTypeTuple = PT;
56     alias _parent this;
57 
58     template opDispatch(string s)
59     {
60         enum e = tupleElemWithMember!(s, PT);
61 
62         static if (hasMethod!(typeof(_parent[e]), s))
63         {
64             @property auto ref opDispatch(T...)(T params)
65             {
66                 return __traits(getMember, _parent[e], s)(params);
67             }
68         }
69         else
70         {
71             @property auto ref opDispatch()
72             {
73                 return __traits(getMember, _parent[e], s);
74             }
75 
76             @property auto ref opDispatch(T)(T val)
77             {
78                 return __traits(getMember, _parent[e], s) = val;
79             }
80         }
81     }
82 }
83 
84 ///
85 unittest
86 {
87     struct Foo
88     {
89         int x = 100;
90         int foo() { return 11; }
91     }
92 
93     struct Bar
94     {
95         int y = 99;
96         int bar() { return 22; }
97     }
98 
99     struct TestObj
100     {
101         mixin Inherit!(Foo, Bar);
102     }
103 
104     TestObj obj;
105 
106     obj.x *= 2;
107     obj.y = 10;
108 
109     assert(obj.x == 200);
110     assert(obj.y == 10);
111 
112     assert(obj.foo() == 11);
113     assert(obj.bar() == 22);
114 }
115 
116 /**
117  * Returns index of a tuple element which has specified member (s)
118  */
119 size_t tupleElemWithMember(string s, T...)()
120 {
121     foreach(i, type; T)
122     {
123         static if (__traits(hasMember, type, s))
124             return i;
125     }
126     assert(0);
127 }
128 
129 /**
130  * Test if type (T) has specified method (m), local or derived
131  */
132 bool hasMethod(T, string m)()
133 {
134     static if (__traits(hasMember, T, m))
135     {
136         static if (isMethod!(__traits(getMember, T, m)))
137         {
138             return true;
139         }
140     }
141 
142     static if (__traits(hasMember, T, "_parentTypeTuple"))
143     {
144         foreach(i, parentType; T._parentTypeTuple)
145         {
146             static if (hasMethod!(parentType, m))
147             {
148                 return true;
149             }
150         }
151 
152         return false;
153     }
154     else
155     {
156         return false;
157     }
158 }
159 
160 ///
161 unittest
162 {
163     struct Foo
164     {
165         int bar() { return 0; }
166     }
167     
168     assert(hasMethod!(Foo, "bar")() == true);
169     assert(hasMethod!(Foo, "foo")() == false);
170 }
171 
172 /**
173  * Check if given type (T) corresponds to given signature (I)
174  *
175  * Description:
176  * Returns true if struct T has the same members and methods as struct I.
177  * This allows to use structs as static interfaces in generic code.
178  */
179 /*
180 bool implements(T, I)()
181 {
182     foreach(i, name; __traits(allMembers, I))
183     {
184         static if (name == "_parentTypeTuple") {}
185         else static if (name == "_parent")
186         {
187             foreach(ParI; I._parentTypeTuple)
188             {
189                 static if (!implements!(T, ParI))
190                     return false;
191             }
192         }
193         else static if (isMethod!(__traits(getMember, I, name)))
194         {
195             static if (!hasMethod!(T, name))
196                 return false;
197         }
198         else
199         {
200             static if (!__traits(hasMember, T, name))
201                 return false;
202             else
203             {
204                 alias t1 = typeof(__traits(getMember, T, name));
205                 alias t2 = typeof(__traits(getMember, I, name));
206                 static if (!is(t1 == t2))
207                     return false;
208             }
209         }
210     }
211     return true;
212 }
213 
214 ///
215 unittest
216 {
217     struct Foo
218     {
219         int bar() { return 10; }
220     }
221     
222     struct FooInterface
223     {
224         int bar() { return 0; }
225     }
226     
227     assert(implements!(Foo, FooInterface)() == true);
228 }
229 */
230 
231 /**
232  * Test if F is a method
233  */
234 template isMethod(alias F)
235 {
236     enum isMethod =
237            isSomeFunction!F &&
238           !isFunctionPointer!F &&
239           !isDelegate!F;
240 }