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 }