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