-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathStringIdentifiable.java
More file actions
133 lines (112 loc) · 5.27 KB
/
StringIdentifiable.java
File metadata and controls
133 lines (112 loc) · 5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package net.modificationstation.stationapi.api.util;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Keyable;
import net.modificationstation.stationapi.api.util.dynamic.Codecs;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* An interface, usually implemented by enums, that allows the object to be serialized
* by codecs. An instance is identified using a string.
*
* @apiNote To make an enum serializable with codecs, implement this on the enum class,
* implement {@link #asString} to return a unique ID, and add a {@code static final}
* field that holds {@linkplain #createCodec the codec for the enum}.
*/
public interface StringIdentifiable {
int MAPIFY_THRESHOLD = 16;
/**
* {@return the unique string representation of the enum, used for serialization}
*/
String asString();
/**
* Creates a codec that serializes an enum implementing this interface either
* using its ordinals (when compressed) or using its {@link #asString()} method.
*/
static <E extends Enum<E> & StringIdentifiable> StringIdentifiable.EnumCodec<E> createCodec(Supplier<E[]> enumValues) {
return createCodec(enumValues, id -> id);
}
/**
* Creates a codec that serializes an enum implementing this interface either
* using its ordinals (when compressed) or using its {@link #asString()} method
* and a given decode function.
*/
static <E extends Enum<E> & StringIdentifiable> StringIdentifiable.EnumCodec<E> createCodec(
Supplier<E[]> enumValues, Function<String, String> valueNameTransformer
) {
E[] enums = (E[])enumValues.get();
Function<String, E> function = createMapper(enums, valueNameTransformer);
return new StringIdentifiable.EnumCodec<>(enums, function);
}
static <T extends StringIdentifiable> Codec<T> createBasicCodec(Supplier<T[]> values) {
T[] identifiableValues = values.get();
Function<String, T> function = createMapper(identifiableValues, valueName -> valueName);
ToIntFunction<T> toIntFunction = Util.lastIndexGetter(Arrays.asList(identifiableValues));
return new StringIdentifiable.BasicCodec<>(identifiableValues, function, toIntFunction);
}
static <T extends StringIdentifiable> Function<String, T> createMapper(T[] values, Function<String, String> valueNameTransformer) {
if (values.length > 16) {
Map<String, T> map = Arrays.stream(values)
.collect(Collectors.toMap(value -> valueNameTransformer.apply(value.asString()), value -> value));
return name -> name == null ? null : map.get(name);
} else {
return name -> {
for (T stringIdentifiable : values) {
if (valueNameTransformer.apply(stringIdentifiable.asString()).equals(name)) {
return stringIdentifiable;
}
}
return null;
};
}
}
static Keyable toKeyable(final StringIdentifiable[] values) {
return new Keyable(){
@Override
public <T> Stream<T> keys(DynamicOps<T> ops) {
return Arrays.stream(values).map(StringIdentifiable::asString).map(ops::createString);
}
};
}
class BasicCodec<S extends StringIdentifiable> implements Codec<S> {
private final Codec<S> codec;
public BasicCodec(S[] values, Function<String, S> idToIdentifiable, ToIntFunction<S> identifiableToOrdinal) {
this.codec = Codecs.orCompressed(
Codec.stringResolver(StringIdentifiable::asString, idToIdentifiable),
Codecs.rawIdChecked(identifiableToOrdinal, ordinal -> ordinal >= 0 && ordinal < values.length ? values[ordinal] : null, -1)
);
}
@Override
public <T> DataResult<com.mojang.datafixers.util.Pair<S, T>> decode(DynamicOps<T> ops, T input) {
return this.codec.decode(ops, input);
}
public <T> DataResult<T> encode(S stringIdentifiable, DynamicOps<T> dynamicOps, T object) {
return this.codec.encode(stringIdentifiable, dynamicOps, object);
}
}
class EnumCodec<E extends Enum<E> & StringIdentifiable> extends StringIdentifiable.BasicCodec<E> {
private final Function<String, E> idToIdentifiable;
public EnumCodec(E[] values, Function<String, E> idToIdentifiable) {
super(values, idToIdentifiable, Enum::ordinal);
this.idToIdentifiable = idToIdentifiable;
}
@Nullable
public E byId(@Nullable String id) {
return (E)this.idToIdentifiable.apply(id);
}
public E byId(@Nullable String id, E fallback) {
return Objects.requireNonNullElse(this.byId(id), fallback);
}
public E byId(@Nullable String id, Supplier<? extends E> fallbackSupplier) {
return Objects.requireNonNullElseGet(this.byId(id), fallbackSupplier);
}
}
}