Skip to content

Commit acee308

Browse files
Named command args (#280)
* initial named args implementation * move arg retrieval, validation, and mapping into Argument class * ignore empty path strings * add missing type param * use MAPPING_OUTPUT instead of OUTPUT_FOLDER arg in InvertMappingsCommand * add clarifying comment * add DecompileCommand::run override accepting enum * add ArgsParser * add ArgsParserTest * make ArgsParserTest DRYer * add ArgMapTest with valid input tests * reject unreconized named args * improve missing required args exception * add invalid args tests * javadoc Command's type params * add missing Command type params * javadoc * fix strings according to code review Co-authored-by: ix0rai <[email protected]> * fix string format arg order Co-authored-by: ix0rai <[email protected]> * minor test improvements --------- Co-authored-by: ix0rai <[email protected]>
1 parent 919c1ba commit acee308

21 files changed

+1462
-329
lines changed
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package org.quiltmc.enigma.command;
2+
3+
import com.google.common.collect.ImmutableList;
4+
import com.google.common.collect.UnmodifiableIterator;
5+
6+
import javax.annotation.Nonnull;
7+
import java.util.Map;
8+
import java.util.function.BiFunction;
9+
import java.util.stream.Stream;
10+
11+
final class ArgsParser<P> implements Iterable<Argument<?>> {
12+
static <T> ArgsParser<T> of(Argument<T> arg) {
13+
return new ArgsParser<>(ImmutableList.of(arg), (values, from) -> from.parse(arg, values));
14+
}
15+
16+
static <T1, T2, P> ArgsParser<P> of(Argument<T1> arg1, Argument<T2> arg2, BiFunction<T1, T2, P> packer) {
17+
return new ArgsParser<>(ImmutableList.of(arg1, arg2), (values, from) -> packer.apply(
18+
from.parse(arg1, values), from.parse(arg2, values)
19+
));
20+
}
21+
22+
static <T1, T2, T3, P> ArgsParser<P> of(
23+
Argument<T1> arg1, Argument<T2> arg2, Argument<T3> arg3,
24+
Packer3<T1, T2, T3, P> packer
25+
) {
26+
return new ArgsParser<>(ImmutableList.of(arg1, arg2, arg3), (values, from) -> packer.pack(
27+
from.parse(arg1, values), from.parse(arg2, values), from.parse(arg3, values)
28+
));
29+
}
30+
31+
static <T1, T2, T3, T4, P> ArgsParser<P> of(
32+
Argument<T1> arg1, Argument<T2> arg2, Argument<T3> arg3, Argument<T4> arg4,
33+
Packer4<T1, T2, T3, T4, P> packer
34+
) {
35+
return new ArgsParser<>(ImmutableList.of(arg1, arg2, arg3, arg4), (values, from) -> packer.pack(
36+
from.parse(arg1, values), from.parse(arg2, values), from.parse(arg3, values), from.parse(arg4, values)
37+
));
38+
}
39+
40+
static <T1, T2, T3, T4, T5, P> ArgsParser<P> of(
41+
Argument<T1> arg1, Argument<T2> arg2, Argument<T3> arg3, Argument<T4> arg4, Argument<T5> arg5,
42+
Packer5<T1, T2, T3, T4, T5, P> packer
43+
) {
44+
return new ArgsParser<>(ImmutableList.of(arg1, arg2, arg3, arg4, arg5), (values, from) -> packer.pack(
45+
from.parse(arg1, values), from.parse(arg2, values), from.parse(arg3, values),
46+
from.parse(arg4, values), from.parse(arg5, values)
47+
));
48+
}
49+
50+
static <T1, T2, T3, T4, T5, T6, P> ArgsParser<P> of(
51+
Argument<T1> arg1, Argument<T2> arg2, Argument<T3> arg3,
52+
Argument<T4> arg4, Argument<T5> arg5, Argument<T6> arg6,
53+
Packer6<T1, T2, T3, T4, T5, T6, P> packer
54+
) {
55+
return new ArgsParser<>(ImmutableList.of(arg1, arg2, arg3, arg4, arg5, arg6), (values, from) -> packer.pack(
56+
from.parse(arg1, values), from.parse(arg2, values), from.parse(arg3, values),
57+
from.parse(arg4, values), from.parse(arg5, values), from.parse(arg6, values)
58+
));
59+
}
60+
61+
static <T1, T2, T3, T4, T5, T6, T7, P> ArgsParser<P> of(
62+
Argument<T1> arg1, Argument<T2> arg2, Argument<T3> arg3, Argument<T4> arg4,
63+
Argument<T5> arg5, Argument<T6> arg6, Argument<T7> arg7,
64+
Packer7<T1, T2, T3, T4, T5, T6, T7, P> packer
65+
) {
66+
return new ArgsParser<>(
67+
ImmutableList.of(arg1, arg2, arg3, arg4, arg5, arg6, arg7),
68+
(values, from) -> packer.pack(
69+
from.parse(arg1, values), from.parse(arg2, values), from.parse(arg3, values),
70+
from.parse(arg4, values), from.parse(arg5, values), from.parse(arg6, values),
71+
from.parse(arg7, values)
72+
)
73+
);
74+
}
75+
76+
static <T1, T2, T3, T4, T5, T6, T7, T8, P> ArgsParser<P> of(
77+
Argument<T1> arg1, Argument<T2> arg2, Argument<T3> arg3, Argument<T4> arg4,
78+
Argument<T5> arg5, Argument<T6> arg6, Argument<T7> arg7, Argument<T8> arg8,
79+
Packer8<T1, T2, T3, T4, T5, T6, T7, T8, P> packer
80+
) {
81+
return new ArgsParser<>(
82+
ImmutableList.of(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8),
83+
(values, from) -> packer.pack(
84+
from.parse(arg1, values), from.parse(arg2, values), from.parse(arg3, values),
85+
from.parse(arg4, values), from.parse(arg5, values), from.parse(arg6, values),
86+
from.parse(arg7, values), from.parse(arg8, values)
87+
)
88+
);
89+
}
90+
91+
static <T1, T2, T3, T4, T5, T6, T7, T8, T9, P> ArgsParser<P> of(
92+
Argument<T1> arg1, Argument<T2> arg2, Argument<T3> arg3, Argument<T4> arg4, Argument<T5> arg5,
93+
Argument<T6> arg6, Argument<T7> arg7, Argument<T8> arg8, Argument<T9> arg9,
94+
Packer9<T1, T2, T3, T4, T5, T6, T7, T8, T9, P> packer
95+
) {
96+
return new ArgsParser<>(
97+
ImmutableList.of(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9),
98+
(values, from) -> packer.pack(
99+
from.parse(arg1, values), from.parse(arg2, values), from.parse(arg3, values),
100+
from.parse(arg4, values), from.parse(arg5, values), from.parse(arg6, values),
101+
from.parse(arg7, values), from.parse(arg8, values), from.parse(arg9, values)
102+
)
103+
);
104+
}
105+
106+
static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, P> ArgsParser<P> of(
107+
Argument<T1> arg1, Argument<T2> arg2, Argument<T3> arg3, Argument<T4> arg4, Argument<T5> arg5,
108+
Argument<T6> arg6, Argument<T7> arg7, Argument<T8> arg8, Argument<T9> arg9, Argument<T10> arg10,
109+
Packer10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, P> packer
110+
) {
111+
return new ArgsParser<>(
112+
ImmutableList.of(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10),
113+
(values, from) -> packer.pack(
114+
from.parse(arg1, values), from.parse(arg2, values), from.parse(arg3, values),
115+
from.parse(arg4, values), from.parse(arg5, values), from.parse(arg6, values),
116+
from.parse(arg7, values), from.parse(arg8, values), from.parse(arg9, values),
117+
from.parse(arg10, values)
118+
)
119+
);
120+
}
121+
122+
private final ImmutableList<Argument<?>> args;
123+
124+
private final BiFunction<Map<String, String>, ArgParser, P> impl;
125+
126+
private ArgsParser(ImmutableList<Argument<?>> args, BiFunction<Map<String, String>, ArgParser, P> impl) {
127+
this.args = args;
128+
this.impl = impl;
129+
}
130+
131+
P parse(Map<String, String> values, ArgParser from) {
132+
return this.impl.apply(values, from);
133+
}
134+
135+
Argument<?> get(int index) {
136+
return this.args.get(index);
137+
}
138+
139+
int count() {
140+
return this.args.size();
141+
}
142+
143+
boolean isEmpty() {
144+
return this.args.isEmpty();
145+
}
146+
147+
@Override
148+
@Nonnull
149+
public UnmodifiableIterator<Argument<?>> iterator() {
150+
return this.args.iterator();
151+
}
152+
153+
Stream<Argument<?>> stream() {
154+
return this.args.stream();
155+
}
156+
157+
@FunctionalInterface
158+
interface ArgParser {
159+
<T> T parse(Argument<T> arg, Map<String, String> values);
160+
}
161+
162+
@FunctionalInterface
163+
interface Packer3<T1, T2, T3, P> {
164+
P pack(T1 v1, T2 v2, T3 v3);
165+
}
166+
167+
@FunctionalInterface
168+
interface Packer4<T1, T2, T3, T4, P> {
169+
P pack(T1 v1, T2 v2, T3 v3, T4 v4);
170+
}
171+
172+
@FunctionalInterface
173+
interface Packer5<T1, T2, T3, T4, T5, P> {
174+
P pack(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5);
175+
}
176+
177+
@FunctionalInterface
178+
interface Packer6<T1, T2, T3, T4, T5, T6, P> {
179+
P pack(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6);
180+
}
181+
182+
@FunctionalInterface
183+
interface Packer7<T1, T2, T3, T4, T5, T6, T7, P> {
184+
P pack(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7);
185+
}
186+
187+
@FunctionalInterface
188+
interface Packer8<T1, T2, T3, T4, T5, T6, T7, T8, P> {
189+
P pack(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8);
190+
}
191+
192+
@FunctionalInterface
193+
interface Packer9<T1, T2, T3, T4, T5, T6, T7, T8, T9, P> {
194+
P pack(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9);
195+
}
196+
197+
@FunctionalInterface
198+
interface Packer10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, P> {
199+
P pack(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10);
200+
}
201+
202+
static final class Empty {
203+
static final Empty INSTANCE = new Empty();
204+
205+
static final ArgsParser<Empty> PARSER = new ArgsParser<>(ImmutableList.of(), (values, from) -> INSTANCE);
206+
207+
private Empty() { }
208+
}
209+
}

0 commit comments

Comments
 (0)