1 module clid.core.util;
2 
3 import std.traits : hasUDA, getUDAs;
4 import std.meta : Alias, anySatisfy;
5 
6 import clid.attributes;
7 import clid.validate;
8 
9 /**
10  * Checks if a given struct is a valid configuration struct.
11  */
12 void validateStruct(C)()
13 {
14 	static assert(is(C == struct), "Configuration object must be a struct");
15 	static foreach (member; __traits(allMembers, C))
16 	{
17 		static if (!hasUDAV!(C, member, Parameter))
18 		{
19 			static assert(!hasUDAV!(C, member, Description),
20 					"Cannot have @Description without @Parameter in command line argument struct.");
21 			static assert(!hasUDAV!(C, member, Validate),
22 					"Cannot have @Validate without @Parameter in command line argument struct.");
23 		}
24 	}
25 }
26 
27 /**
28  * Wrapper around __traits(getMember, ...)
29  */
30 template value(C, alias m)
31 {
32 	alias value = __traits(getMember, C, m);
33 }
34 
35 /**
36  * Wrapper around __traits(getMember, ...)
37  */
38 template value(alias c, alias m)
39 {
40 	alias value = __traits(getMember, c, m);
41 }
42 
43 /**
44  * Wrapper around hasUDA!(...)
45  */
46 template hasUDAV(C, alias m, T)
47 {
48 	alias hasUDAV = hasUDA!(value!(C, m), T);
49 }
50 
51 /**
52  * Wrapper around hasUDA!(...)
53  */
54 template hasUDAV(C, alias m, alias t)
55 {
56 	alias hasUDAV = hasUDA!(value!(C, m), t);
57 }
58 
59 /**
60  * Wrapper around hasUDA!(...)
61  */
62 template hasUDAV(alias c, alias m, alias t)
63 {
64 	alias hasUDAV = hasUDA!(value!(c, m), t);
65 }
66 
67 /**
68  * Checks if given template has a parameter attribute.
69  */
70 template hasParameter(alias E)
71 {
72 	alias hasParameter = Alias!(hasUDA!(E, Parameter));
73 }
74 
75 /**
76  * Checks if given template has a parameter attribute.
77  */
78 template hasParameter(C, alias E)
79 {
80 	alias hasParameter = Alias!(hasUDA!(value!(C, E), Parameter));
81 }
82 
83 /**
84  * Checks if the given struct has a short parameter.
85  * Params:
86  *  parameter The short flag that the parameter should have.
87  */
88 bool hasShortParameter(C)(dchar parameter)
89 {
90 	static foreach (member; __traits(allMembers, C))
91 	{
92 		static if (hasParameter!(member) && getParameter!(member).shortName == parameter)
93 		{
94 			return true;
95 		}
96 	}
97 
98 	return false;
99 }
100 
101 /**
102  * Checks if the given struct has a long parameter.
103  * Params:
104  *  parameter The long flag that the parameter should have.
105  */
106 bool hasLongParameter(C)(string parameter)
107 {
108 	static foreach (member; __traits(allMembers, C))
109 	{
110 		if (hasParameter!(C, member) && getParameter!(C, member).longName == parameter)
111 			return true;
112 	}
113 	return false;
114 }
115 
116 /**
117  * Gets the parameter attribute connected to an element.
118  */
119 template getParameter(alias E)
120 {
121 	alias getParameter = Alias!(getUDAs!(E, Parameter)[0]);
122 }
123 
124 /**
125  * Gets the parameter attribute connected to an element.
126  */
127 template getParameter(C, alias e)
128 {
129 	alias getParameter = Alias!(getUDAs!(value!(C, e), Parameter)[0]);
130 }
131 
132 /**
133  * Checks if the element has a description attribute.
134  */
135 template hasDescription(alias E)
136 {
137 	alias hasDescription = Alias!(hasUDA!(E, Description));
138 }
139 
140 /**
141  * Gets the description attribute of an element.
142  */
143 template getDescription(alias E)
144 {
145 	alias getDescription = Alias!(getUDAs!(E, Description)[0]);
146 }
147 
148 /**
149  * Checks if a given parameter is required.
150  */
151 template isRequired(alias E)
152 {
153 	alias isRequired = Alias!(hasUDA!(E, Required));
154 }
155 
156 /**
157  * Checks if a given parameter is required.
158  */
159 template isRequired(C, alias e)
160 {
161 	alias isRequired = Alias!(isRequired!(value!(C, e)));
162 }
163 
164 /**
165  * Checks if a given parameter is a named parameter.
166  */
167 template isNamedParameter(alias e)
168 {
169 	alias isNamedParameter = Alias!(getParameter!(e).longName.length > 0);
170 }
171 
172 /**
173  * Checks if a given parameter is a named parameter.
174  */
175 template isNamedParameter(alias C, alias e)
176 {
177 	alias isNamedParameter = isNamedParameter!(value!(C, e));
178 }
179 
180 /**
181  * Checks if a given parameter is an unnamed parameter.
182  */
183 template isUnnamedParameter(alias C, alias e)
184 {
185 	alias isUnnamedParameter = Alias!(hasParameter!(value!(C, e)) && !isNamedParameter!(C, e));
186 }
187 
188 private template hasNamedParameters(C, members...)
189 {
190 	static if (isNamedParameter!(C, members[0]))
191 		alias hasNamedParameters = Alias!true;
192 	else static if (members.length == 1)
193 		alias hasNamedParameters = isNamedParameter!(C, members[0]);
194 	else
195 		alias hasNamedParameters = hasNamedParameters!(C, members[1 .. $]);
196 }
197 
198 private template hasNamedParameters(C, member)
199 {
200 	alias hasNamedParameters = isNamedParameter!(C, members[i]);
201 }
202 
203 /**
204  * Checks if the struct has a named parameter.
205  */
206 alias hasNamedParameters(C) = hasNamedParameters!(C, __traits(allMembers, C));
207 
208 private template hasUnnamedParameters(C, members...)
209 {
210 	static if (!isNamedParameter!(C, members[0]))
211 		alias hasUnnamedParameters = Alias!true;
212 	else static if (members.length == 1)
213 		alias hasUnnamedParameters = Alias!(!isNamedParameter!(C, members[0]));
214 	else
215 		alias hasUnnamedParameters = hasUnnamedParameters!(C, members[1 .. $]);
216 }
217 
218 /**
219  * Checks if the struct has an unamed parameter.
220  */
221 alias hasUnnamedParameters(C) = hasUnnamedParameters!(C, __traits(allMembers, C));
222 
223 /*
224 private template getUnnamedParameters(C)
225 {
226 	import std.algorithm.iteration : filter;
227 
228 	alias getUnnamedParameters = Alias!(__traits(allMembers, C).filter!(b => !isNamedParameter(b)));
229 }
230 */