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 }