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 }