1 /*
2 __
3 / _|
4 __ _ _ _ _ __ ___ _ __ __ _ | |_ ___ ___ ___
5 / _` | | | | '__/ _ \| '__/ _` | | _/ _ \/ __/ __|
6 | (_| | |_| | | | (_) | | | (_| | | || (_) \__ \__ \
7 \__,_|\__,_|_| \___/|_| \__,_| |_| \___/|___/___/
8
9 Copyright (C) 2018-2020 Aurora Free Open Source Software.
10 Copyright (C) 2018-2020 Luís Ferreira <luis@aurorafoss.org>
11
12 This file is part of the Aurora Free Open Source Software. This
13 organization promote free and open source software that you can
14 redistribute and/or modify under the terms of the GNU Lesser General
15 Public License Version 3 as published by the Free Software Foundation or
16 (at your option) any later version approved by the Aurora Free Open Source
17 Software Organization. The license is available in the package root path
18 as 'LICENSE' file. Please review the following information to ensure the
19 GNU Lesser General Public License version 3 requirements will be met:
20 https://www.gnu.org/licenses/lgpl.html .
21
22 Alternatively, this file may be used under the terms of the GNU General
23 Public License version 3 or later as published by the Free Software
24 Foundation. Please review the following information to ensure the GNU
25 General Public License requirements will be met:
26 http://www.gnu.org/licenses/gpl-3.0.html.
27
28 NOTE: All products, services or anything associated to trademarks and
29 service marks used or referenced on this file are the property of their
30 respective companies/owners or its subsidiaries. Other names and brands
31 may be claimed as the property of others.
32
33 For more info about intellectual property visit: aurorafoss.org or
34 directly send an email to: contact (at) aurorafoss.org .
35
36 This file has code provided on dlang forum and on bolts package check them out
37 here: https://forum.dlang.org/post/gdipbdsoqdywuabnpzpe@forum.dlang.org and at
38 code.dlang.org or even https://github.com/aliak00/bolts/ .
39 */
40
41 /++
42 Extras to object module
43
44 This file defines extra functions to object module.
45
46 Authors: Luís Ferreira <luis@aurorafoss.org>
47 Copyright: All rights reserved, Aurora Free Open Source Software
48 License: GNU Lesser General Public License (Version 3, 29 June 2007)
49 Date: 2018-2020
50 +/
51 module aurorafw.stdx.object;
52
53 import std.traits;
54 import std.meta;
55
56 import aurorafw.stdx.traits;
57
58 version (unittest) import aurorafw.unit.assertion;
59
60 public template match(handlers...)
61 {
62 MatchReturnType!handlers match(T)(auto ref T obj) if (is(T == class) || is(T == interface))
63 {
64 alias TL = staticMap!(Unqual, staticMap!(FunctionTypeOf, handlers));
65 static assert(is(NoDuplicates!(TL) == TL));
66
67 enum CompParams(alias H1, alias H2) = Parameters!H1.length > Parameters!H2.length;
68 alias matchReturnType = typeof(return);
69 alias sortedHandlers = AliasSeq!(
70 staticSort!(CompParams, handlers), // default if everything fails
71 () => matchReturnType.init);
72 foreach (handler; sortedHandlers)
73 {
74 alias paramsHandler = Parameters!handler;
75 static assert(paramsHandler.length <= 1);
76 static if (paramsHandler.length == 1)
77 {
78 alias firstParam = Parameters!handler[0];
79
80 // runtime verifications
81 if (typeid(obj) == typeid(firstParam))
82 return handler(cast(firstParam) obj);
83 }
84 else static if (paramsHandler.length == 0)
85 {
86 return handler();
87 }
88 }
89 }
90 }
91
92 private version (unittest)
93 {
94 // dfmt off
95 @safe pure
96 class UnittestFoobar {}
97
98 @safe pure
99 class UnittestFoo : UnittestFoobar {}
100
101 @safe pure
102 class UnittestBar : UnittestFoobar {}
103 // dfmt on
104 }
105
106 public enum from = FromImpl!()();
107
108 public template _from(string moduleName = null)
109 {
110 enum _from = FromImpl!(moduleName)();
111 }
112
113 private struct FromImpl(string moduleName = null)
114 {
115 template opDispatch(string symbolName)
116 {
117 static if (ModuleContainsSymbol!(moduleName, symbolName))
118 {
119 mixin("import " ~ moduleName ~ ";");
120 mixin("alias opDispatch = " ~ symbolName ~ ";");
121 }
122 else
123 {
124 static if (moduleName.length == 0)
125 {
126 enum opDispatch = FromImpl!(symbolName)();
127 }
128 else
129 {
130 enum importString = moduleName ~ "." ~ symbolName;
131 static assert(
132 CanImport!importString,
133 "Symbol \"" ~ symbolName ~ "\" not found in " ~ moduleName
134 );
135 enum opDispatch = FromImpl!importString();
136 }
137 }
138 }
139 }
140
141 ///
142 @safe pure
143 @("Object: from opDispatch sugar")
144 unittest
145 {
146 assertTrue(__traits(compiles, { _from!"std.math".abs(-1); }));
147 assertTrue(__traits(compiles, { _from!().std.math.abs(-1); }));
148 assertTrue(__traits(compiles, { from.std.math.abs(-1); }));
149 assertTrue(__traits(compiles, { _from!"std.math".abs(-1); }));
150 assertFalse(__traits(compiles, { from.std.math.thisFunctionDoesNotExist(42); }));
151 assertFalse(__traits(compiles, { _from!"std.math".thisFunctionDoesNotExist(42); }));
152
153 // check for static eval
154 static assert(__traits(compiles, { _from!"std.math".abs(-1); }));
155 static assert(__traits(compiles, { from.std.math.abs(-1); }));
156
157 // test if it actually imports the right symbol
158 assertEquals(1, from.std.math.abs(-1));
159 }
160
161 ///
162 @system
163 @("Object: Type pattern matching")
164 unittest
165 {
166 UnittestFoobar foo = new UnittestFoo();
167 assertEquals("yes", foo.match!(
168 (UnittestFoo _) => "yes", (UnittestBar _) => "bar", () => "no"
169 ));
170
171 Object bar = new UnittestBar();
172 assertEquals("yes", bar.match!(
173 (UnittestBar _) => "yes", () => "no"
174 ));
175
176 assertEquals(bar, bar.match!(
177 (UnittestBar _) => _, () => null
178 ));
179
180 assertEquals(null, bar.match!((UnittestFoo _) => _));
181 }