1 /** 2 * Named method and struct literal arguments 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.meta.args; 15 16 import std.traits; 17 18 // Inspired by 19 // http://forum.dlang.org/post/awjuoemsnmxbfgzhgkgx@forum.dlang.org 20 21 /// Simulates named arguments for function calls. 22 /// Accepts arguments as lambdas (name => value) on the template parameter list, 23 /// and positional arguments on the runtime parameter list (see examples below). 24 template args(alias fun, dgs...) 25 if (is(typeof(fun) == function)) 26 { 27 auto args(PosArgs...)(auto ref PosArgs posArgs) 28 { 29 ParameterTypeTuple!fun args; 30 enum names = ParameterIdentifierTuple!fun; 31 32 foreach (i, ref arg; posArgs) 33 args[i] = posArgs[i]; 34 foreach (i, arg; ParameterDefaults!fun) 35 static if (i >= posArgs.length) 36 args[i] = ParameterDefaults!fun[i]; 37 38 // anything works here, but use a custom type to avoid user errors 39 static struct DummyType {} 40 41 foreach (dg; dgs) 42 { 43 alias fun = dg!DummyType; 44 static if (is(FunctionTypeOf!fun PT == __parameters)) 45 { 46 enum name = __traits(identifier, PT); 47 foreach (i, argName; names) 48 static if (name == argName) 49 args[i] = fun(DummyType.init); 50 } 51 else 52 static assert(false, "Failed to extract parameter name from " ~ fun.stringof); 53 } 54 return fun(args); 55 } 56 } 57 58 /// 59 unittest 60 { 61 static int fun(int a=1, int b=2, int c=3, int d=4, int e=5) 62 { 63 return a+b+c+d+e; 64 } 65 66 assert(args!(fun) == 15); 67 assert(args!(fun, b=>3) == 16); 68 assert(args!(fun, b=>3, d=>3) == 15); 69 } 70 71 /// Mixing named and positional arguments 72 unittest 73 { 74 static int fun(int a, int b=2, int c=3, int d=4, int e=5) 75 { 76 return a+b+c+d+e; 77 } 78 79 assert(args!(fun)(1) == 15); 80 assert(args!(fun, b=>3)(1) == 16); 81 } 82 83 /// Simulates named arguments for struct literals. 84 template args(S, dgs...) 85 if (is(S == struct)) 86 { 87 @property S args() 88 { 89 S s; 90 91 // anything works here, but use a custom type to avoid user errors 92 static struct DummyType {} 93 94 foreach (dg; dgs) 95 { 96 alias fun = dg!DummyType; 97 static if (is(FunctionTypeOf!fun PT == __parameters)) 98 { 99 enum name = __traits(identifier, PT); 100 foreach (i, field; s.tupleof) 101 static if (__traits(identifier, S.tupleof[i]) == name) 102 s.tupleof[i] = fun(DummyType.init); 103 } 104 else 105 static assert(false, "Failed to extract parameter name from " ~ fun.stringof); 106 } 107 return s; 108 } 109 } 110 111 unittest 112 { 113 static struct S 114 { 115 int a = 1, b = 2, c = 3, d = 4, e = 5; 116 @property int sum() { return a + b + c + d + e; } 117 } 118 119 assert(args!(S).sum == 15); 120 assert(args!(S, b=>3).sum == 16); 121 assert(args!(S, b=>3, d=>3).sum == 15); 122 123 static assert(!is(typeof(args!(S, b=>b)))); 124 }