Advertisement
Guest User

Untitled

a guest
Jul 18th, 2019
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.26 KB | None | 0 0
  1. struct ModelA {
  2. class Animal {
  3. TypeInfo eat() {
  4. return typeid(typeof(this));
  5. }
  6. Food eatsFood() {
  7. return null;
  8. }
  9. mixin fixCast!();
  10. }
  11. class Dog : Animal {
  12. override TypeInfo eat() {
  13. return typeid(typeof(this));
  14. }
  15. TypeInfo bark() {
  16. return typeid(typeof(this));
  17. }
  18. TypeInfo bite() {
  19. return typeid(typeof(this));
  20. }
  21. override Food eatsFood() {
  22. return new Food();
  23. }
  24. }
  25. class Food {
  26. mixin fixCast!();
  27. }
  28. }
  29.  
  30. struct ModelB {
  31. class Animal {
  32. mixin inherit!ModelA;
  33. }
  34. class Dog : Animal {
  35. mixin inherit!ModelA;
  36. TypeInfo bark() {
  37. return typeid(typeof(this));
  38. }
  39. Food eatsFood() {
  40. return new Food();
  41. }
  42. }
  43. class Food {
  44. mixin inherit!ModelA;
  45. }
  46. }
  47.  
  48. unittest {
  49. // Implicit conversions to ModelA:
  50. ModelB.Dog a = new ModelB.Dog();
  51. ModelA.Dog b = a;
  52. ModelB.Animal c = a;
  53. ModelA.Animal d = c;
  54.  
  55. assert(a !is null);
  56. assert(b !is null);
  57. assert(c !is null);
  58. assert(d !is null);
  59.  
  60. assert(a == b);
  61. assert(a == c);
  62. assert(a == d);
  63. assert(b == c);
  64. assert(b == d);
  65. assert(c == d);
  66.  
  67. // Methods are inherited from the corresponding class in the base model:
  68. assert(a.eat() == typeid(ModelA.Dog));
  69. assert(b.eat() == typeid(ModelA.Dog));
  70. assert(c.eat() == typeid(ModelA.Dog));
  71. assert(d.eat() == typeid(ModelA.Dog));
  72.  
  73. // bark() is overridden in ModelB.Dog, so that's the version what's being called:
  74. assert(a.bark() == typeid(ModelB.Dog));
  75. assert(b.bark() == typeid(ModelB.Dog));
  76.  
  77. // bite(), however, is not overridden, so ModelA's version is used:
  78. assert(a.bite() == typeid(ModelA.Dog));
  79. assert(b.bite() == typeid(ModelA.Dog));
  80.  
  81. // Managed to fix casting from ModelA to ModelB:
  82. assert(cast(ModelB.Dog)d !is null);
  83. assert(cast(ModelB.Animal)d !is null);
  84.  
  85. //
  86. ModelB.Food food1 = a.eatsFood;
  87. ModelA.Food food3 = b.eatsFood;
  88. ModelA.Food food4 = d.eatsFood;
  89.  
  90. // Can't do - ModelB.Animal does not override eatsFood(),
  91. // so this is ModelA.Animal's eatsFood() method.
  92. //ModelB.Food food2 = c.eatsFood;
  93. }
  94.  
  95. mixin template fixCast() {
  96. static if (!__traits(hasMember, typeof(this), "_hasFixCast")) {
  97. enum _hasFixCast = true;
  98. inout(T) opCast(T)() inout if (is(T == class)) {
  99. auto tmp = _opCastImpl(typeid(T));
  100. return *cast(inout(T)*)&tmp;
  101. }
  102.  
  103. inout(void)* _opCastImpl(TypeInfo_Class) inout {
  104. return null;
  105. }
  106. }
  107. }
  108.  
  109. mixin template inherit(ParentModel) {
  110. static assert(is(typeof(this) == class), "inherit only works for classes");
  111. static assert(__traits(hasMember, ParentModel, typeof(this).stringof), "inherit works only for models matching the same class structure");
  112.  
  113. alias ThisClass = typeof(this);
  114. alias ParentClass = __traits(getMember, ParentModel, typeof(this).stringof);
  115.  
  116. static assert(__traits(hasMember, ParentClass, "_opCastImpl"), "Base model class doesn't correctly implement `opCast`. Please use `mixin fixCast!();` in `"~ParentClass.stringof~"`");
  117.  
  118.  
  119. private inout(ParentClass) _getProxyParentImpl() inout {
  120. if (_proxyParent !is null) {
  121. return _proxyParent;
  122. }
  123.  
  124. import std.typecons : AutoImplement;
  125.  
  126. static class Base : ParentClass {
  127. ThisClass zis;
  128. this(inout(ThisClass) a) inout {
  129. zis = a;
  130. }
  131.  
  132. // Manually check if we're casting ThisClass or a supertype, otherwise return null.
  133. override inout(void)* _opCastImpl(TypeInfo_Class t) inout {
  134. auto thisType = typeid(ThisClass);
  135. while (thisType !is null && thisType != t) {
  136. thisType = thisType.base;
  137. }
  138.  
  139. if (!t) return null;
  140. union A {
  141. ThisClass a;
  142. void* b;
  143. }
  144. inout(A) a = {zis};
  145. return a.b;
  146. }
  147.  
  148. override bool opEquals(Object o) {
  149. if (*cast(void**)&o == *cast(void**)&zis) return true;
  150. auto tmp = this;
  151. return *cast(void**)&o == *cast(void**)&tmp;
  152. }
  153.  
  154. override size_t toHash() @trusted nothrow {
  155. return zis.toHash();
  156. }
  157. }
  158.  
  159. // AutoImplement should only implement methods that are overridden in ThisClass.
  160. template What(alias func) {
  161. import std.algorithm.comparison : among;
  162.  
  163. enum funcName = __traits(identifier, func);
  164. static if (funcName.among(__traits(allMembers, ThisClass))) {
  165. alias thisFunc = __traits(getMember, ThisClass, __traits(identifier, func));
  166. enum What = __traits(isVirtualFunction, func) &&
  167. __traits(isVirtualFunction, thisFunc);
  168. } else {
  169. enum What = false;
  170. }
  171. }
  172.  
  173. // AutoImplement should forward calls to ThisClass where it defines an override.
  174. template How(T, alias func) {
  175. import std.format : format;
  176. enum How = q{return zis.%1$s(args);}
  177. .format(__traits(identifier, func));
  178. }
  179. auto tmp = new inout(AutoImplement!(Base, How, What))(this);
  180. // Ugly as fuck. I'm sorry.
  181. *cast(ParentClass*)&_proxyParent = *cast(ParentClass*)&tmp;
  182. return tmp;
  183. }
  184.  
  185. ParentClass _proxyParent;
  186.  
  187. import std.traits : BaseClassesTuple;
  188. static if (__traits(hasMember, BaseClassesTuple!ThisClass[0], "_getProxyParent")) {
  189. override inout(ParentClass) _getProxyParent() inout {
  190. return _getProxyParentImpl();
  191. }
  192. } else {
  193. inout(ParentClass) _getProxyParent() inout {
  194. return _getProxyParentImpl();
  195. }
  196. }
  197. alias _getProxyParent this;
  198.  
  199. override bool opEquals(Object o) {
  200. auto zis = _getProxyParent();
  201. if (*cast(void**)&o == *cast(void**)&zis) return true;
  202. auto tmp = this;
  203. return *cast(void**)&o == *cast(void**)&tmp;
  204. }
  205. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement