1 module autoimpl.parameters; 2 import std.format : format; 3 import std.ascii : toUpper, isLower; 4 import std.traits : FieldNameTuple, Fields, Parameters; 5 6 enum NewFields(T) = () { 7 alias fields = FieldNameTuple!T; 8 string[] fs = []; 9 static foreach (f; fields) 10 { 11 static assert(f[0].isLower, "Field must be in camel case, and starts from lower letter"); 12 fs ~= (f[0].toUpper ~ f[1 .. $]); 13 } 14 return fs; 15 }(); 16 /// Used to create types for "named" params 17 /// Params: 18 /// T = struct 19 mixin template MixinParameters(T) 20 { 21 import std.traits : FieldNameTuple, Fields, Parameters; 22 import std.format : format; 23 24 alias fields = FieldNameTuple!T; 25 alias fieldTypes = Fields!T; 26 enum newFields = NewFields!T; 27 static foreach (i, f; newFields) 28 { 29 mixin(q{ 30 struct %s 31 { 32 %s value; 33 } 34 }.format(f, fieldTypes[i].stringof)); 35 } 36 } 37 38 /// 39 unittest 40 { 41 struct S 42 { 43 int i; 44 } 45 46 mixin MixinParameters!S; 47 I i = I(42); 48 assert(i.value == 42); 49 } 50 51 /// Used for get struct from variadic arguments 52 /// Params: 53 /// T = Type of struct 54 /// argv = fields of struct 55 /// Returns: struct of T type field by argv values; 56 T atos(T, ARGS...)(ARGS argv) 57 { 58 import std.algorithm : countUntil; 59 60 T _t; 61 enum fields = FieldNameTuple!T; 62 enum newFields = NewFields!T; 63 static foreach (i, A; ARGS) 64 { 65 66 static if (newFields.countUntil(A.stringof) >= 0) 67 { 68 mixin("_t." ~ fields[newFields.countUntil(A.stringof)] ~ " = argv[i].value;"); 69 } 70 else 71 pragma(msg, "Warning: " ~ A.stringof ~ "is not a valid field name! Value skiped"); 72 } 73 return _t; 74 } 75 76 /// 77 unittest 78 { 79 struct MyStruct 80 { 81 int i; 82 float f = 0.0f; 83 string s; 84 } 85 86 mixin MixinParameters!MyStruct; 87 88 assert(atos!MyStruct(I(42)) == MyStruct(42, 0, "")); 89 assert(atos!MyStruct(F(42)) == MyStruct(0, 42, "")); 90 assert(atos!MyStruct(S("42")) == MyStruct(0, 0, "42")); 91 assert(atos!MyStruct(S("42"), I(42)) == MyStruct(42, 0, "42")); 92 assert(atos!MyStruct(F(42), S("42"), I(42)) == MyStruct(42, 42, "42")); 93 94 } 95 /// Used to create function whith "Named" arguments 96 /// Params: 97 /// func = function/delegate which accept as param 1 struct 98 /// argv = arumments of new function 99 auto atosed(alias func, ARGS...)(ARGS argv) 100 { 101 alias params = Parameters!func; 102 static assert(params.length == 1, "Function must have one parameter"); 103 alias T = params[0]; 104 static assert(is(T == struct), "Functions must accept struct argument"); 105 return func(argv.atos!T); 106 } 107 108 /// 109 unittest 110 { 111 struct MyStruct 112 { 113 int i; 114 string s; 115 } 116 117 mixin MixinParameters!MyStruct; 118 119 auto str(MyStruct m) 120 { 121 import std.conv : to; 122 123 return m.to!string; 124 } 125 126 assert(atosed!str(I(42)) == str(MyStruct(42, ""))); 127 assert(atosed!str(S("42"), I(42)) == str(MyStruct(42, "42"))); 128 } 129 130 unittest 131 { 132 /// Arguments of function printS 133 struct S 134 { 135 int i; 136 int arg2; 137 string sv; 138 } 139 140 string printS(S s) 141 { 142 import std.conv : to; 143 144 return s.to!string; 145 } 146 147 mixin MixinParameters!S; 148 149 auto v1 = I(1); 150 auto v2 = Arg2(2); 151 auto v3 = Sv("string"); 152 assert(v1.value == 1); 153 assert(v2.value == 2); 154 assert(v3.value == "string"); 155 S s = atos!S(v1, v2, v3); 156 assert(s == S(1, 2, "string")); 157 assert(atosed!printS(v1, v2, v3) == printS(s)); 158 assert(atosed!printS(v3, v2, v1) == printS(s)); 159 160 assert(atosed!printS(I(1), Sv("data")) == printS(S(1, 0, "data"))); 161 assert(atosed!printS(Sv("data")) == printS(S(0, 0, "data"))); 162 assert(atosed!printS(Arg2(100)) == printS(S(0, 100, ""))); 163 assert(atosed!printS() == printS(S(0, 0, ""))); 164 }