Skip to content

Commit 8050319

Browse files
committed
replaced backing map in deconstructed object with list
1 parent e2f4a36 commit 8050319

3 files changed

Lines changed: 49 additions & 50 deletions

File tree

foundry-core/src/main/java/org/machinemc/foundry/model/DeconstructedObject.java

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public final class DeconstructedObject implements Iterable<DeconstructedObject.F
2525
* @param <T> type of the object
2626
* @return a codec that converts an instance of {@link T} into a deconstructed object and back
2727
*/
28+
// TODO overload method that takes class model
2829
public static <T> Codec<T, DeconstructedObject> codec(Class<T> type) {
2930
ClassModel classModel = ClassModel.of(type);
3031
ObjectFactory<T> objectFactory = ObjectFactory.create(type, classModel);
@@ -44,6 +45,7 @@ public static <T> Codec<T, DeconstructedObject> codec(Class<T> type) {
4445
* @param <T> type of the object
4546
* @return a data handler that converts an instance of {@link T} into a deconstructed object
4647
*/
48+
// TODO overload method that takes class model
4749
public static <T> DataHandler<T, DeconstructedObject> createDeconstructor(Class<T> type) {
4850
ClassModel classModel = ClassModel.of(type);
4951
return createDeconstructor(classModel, ObjectFactory.create(type, classModel));
@@ -62,36 +64,16 @@ public static <T> DataHandler<T, DeconstructedObject> createDeconstructor(Class<
6264
* @param <T> type of the object
6365
* @return a data handler that converts deconstructed object into an instance of {@link T}
6466
*/
67+
// TODO overload method that takes class model
6568
public static <T> DataHandler<DeconstructedObject, T> createConstructor(Class<T> type) {
6669
ClassModel classModel = ClassModel.of(type);
6770
return createConstructor(classModel, ObjectFactory.create(type, classModel));
6871
}
6972

70-
// TODO this must also take source class as field names can overlap
71-
private final @Unmodifiable Map<String, Field> fields;
73+
private final @Unmodifiable List<Field> fields;
7274

73-
DeconstructedObject(Map<String, Field> fields) {
74-
this.fields = Collections.unmodifiableMap(fields);
75-
}
76-
77-
/**
78-
* Returns field with given name of empty if none exists.
79-
*
80-
* @param name name of the field
81-
* @return field with given name
82-
*/
83-
public Optional<Field> getField(String name) {
84-
return Optional.ofNullable(fields.get(name));
85-
}
86-
87-
/**
88-
* Returns an unmodifiable map of the fields in this deconstructed object, mapped
89-
* by their names.
90-
*
91-
* @return map of fields
92-
*/
93-
public @Unmodifiable Map<String, Field> asMap() {
94-
return fields;
75+
DeconstructedObject(List<Field> fields) {
76+
this.fields = Collections.unmodifiableList(fields);
9577
}
9678

9779
/**
@@ -100,7 +82,7 @@ public Optional<Field> getField(String name) {
10082
* @return list of fields
10183
*/
10284
public @Unmodifiable List<Field> asList() {
103-
return List.copyOf(fields.values());
85+
return fields;
10486
}
10587

10688
/**
@@ -111,8 +93,8 @@ public int size() {
11193
}
11294

11395
@Override
114-
public @NotNull Iterator<Field> iterator() {
115-
return fields.values().iterator();
96+
public @NotNull ListIterator<Field> iterator() {
97+
return fields.listIterator();
11698
}
11799

118100
@Override
@@ -147,6 +129,13 @@ public sealed interface Field {
147129
*/
148130
AnnotatedType annotatedType();
149131

132+
/**
133+
* @return whether this field is primitive
134+
*/
135+
default boolean primitive() {
136+
return type().isPrimitive();
137+
}
138+
150139
}
151140

152141
/**
@@ -235,6 +224,7 @@ public Class<?> type() {
235224
public record ObjectField(String name, Class<?> type, AnnotatedType annotatedType, Object value) implements Field {
236225
}
237226

227+
// TODO this should possibly be in a different class
238228
private static <T> DataHandler<T, DeconstructedObject> createDeconstructor(ClassModel classModel,
239229
ObjectFactory<T> objectFactory) {
240230
FieldsExtractor fieldsExtractor = FieldsExtractor.of(classModel);
@@ -245,6 +235,7 @@ private static <T> DataHandler<T, DeconstructedObject> createDeconstructor(Class
245235
};
246236
}
247237

238+
// TODO this should possibly be in a different class
248239
private static <T> DataHandler<DeconstructedObject, T> createConstructor(ClassModel classModel,
249240
ObjectFactory<T> objectFactory) {
250241
FieldsInjector fieldsInjector = FieldsInjector.of(classModel);

foundry-core/src/main/java/org/machinemc/foundry/model/FieldsExtractor.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package org.machinemc.foundry.model;
22

3-
import com.google.common.collect.ImmutableMap;
4-
import com.google.common.collect.Maps;
53
import org.jetbrains.annotations.ApiStatus;
64

75
import java.lang.reflect.AnnotatedType;
8-
import java.util.Map;
6+
import java.util.ArrayList;
7+
import java.util.List;
98
import java.util.function.Function;
109

1110
/**
@@ -70,16 +69,14 @@ static FieldsExtractor of(ClassModel model) {
7069
* Reads fields from a container.
7170
*
7271
* @param dataContainer container to read
73-
* @return map of fields
72+
* @return list of fields
7473
*/
75-
Map<String, DeconstructedObject.Field> read(ModelDataContainer dataContainer) {
76-
//noinspection unchecked
77-
Map.Entry<String, DeconstructedObject.Field>[] fields = new Map.Entry[fieldReaders.length];
78-
for (int i = 0; i < fieldReaders.length; i++) {
79-
var field = fieldReaders[i].apply(dataContainer);
80-
fields[i] = Maps.immutableEntry(field.name(), field);
74+
List<DeconstructedObject.Field> read(ModelDataContainer dataContainer) {
75+
List<DeconstructedObject.Field> fields = new ArrayList<>(fieldReaders.length);
76+
for (var reader : fieldReaders) {
77+
fields.add(reader.apply(dataContainer));
8178
}
82-
return ImmutableMap.ofEntries(fields);
79+
return fields;
8380
}
8481

8582
}

foundry-core/src/test/java/org/machinemc/foundry/model/DeconstructedObjectTest.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,17 @@ void testDirectFields() throws Exception {
4545
assertEquals(3, deconstructed.size());
4646

4747
DeconstructedObject.ObjectField textField = (DeconstructedObject.ObjectField)
48-
deconstructed.getField("text").orElseThrow();
48+
getField(deconstructed, "text").orElseThrow();
4949
assertNotNull(textField);
5050
assertEquals("Direct Access", textField.value());
5151

5252
DeconstructedObject.IntField numField = (DeconstructedObject.IntField)
53-
deconstructed.getField("number").orElseThrow();
53+
getField(deconstructed, "number").orElseThrow();
5454
assertNotNull(numField);
5555
assertEquals(42, numField.value());
5656

5757
DeconstructedObject.DoubleField decField = (DeconstructedObject.DoubleField)
58-
deconstructed.getField("decimal").orElseThrow();
58+
getField(deconstructed, "decimal").orElseThrow();
5959
assertNotNull(decField);
6060
assertEquals(3.14, decField.value());
6161

@@ -119,7 +119,7 @@ void testAccessors() throws Exception {
119119
assertEquals(2, original.getCalls, "Should have called getters during deconstruction");
120120

121121
DeconstructedObject.BoolField activeField = (DeconstructedObject.BoolField)
122-
deconstructed.getField("active").orElseThrow();
122+
getField(deconstructed, "active").orElseThrow();
123123
assertNotNull(activeField);
124124
assertTrue(activeField.value());
125125

@@ -143,9 +143,9 @@ void testRecord() throws Exception {
143143

144144
DeconstructedObject deconstructed = deconstructor.transform(original);
145145

146-
assertInstanceOf(DeconstructedObject.IntField.class, deconstructed.getField("value").orElseThrow());
147-
assertInstanceOf(DeconstructedObject.FloatField.class, deconstructed.getField("factor").orElseThrow());
148-
assertInstanceOf(DeconstructedObject.ObjectField.class, deconstructed.getField("key").orElseThrow());
146+
assertInstanceOf(DeconstructedObject.IntField.class, getField(deconstructed, "value").orElseThrow());
147+
assertInstanceOf(DeconstructedObject.FloatField.class, getField(deconstructed, "factor").orElseThrow());
148+
assertInstanceOf(DeconstructedObject.ObjectField.class, getField(deconstructed, "key").orElseThrow());
149149

150150
SimpleRecord copy = constructor.transform(deconstructed);
151151

@@ -181,7 +181,7 @@ void testFieldAccessAnnotation() throws Exception {
181181
DeconstructedObject deconstructed = deconstructor.transform(original);
182182

183183
DeconstructedObject.IntField fooField = (DeconstructedObject.IntField)
184-
deconstructed.getField("foo").orElseThrow();
184+
getField(deconstructed, "foo").orElseThrow();
185185
assertNotNull(fooField);
186186
assertEquals(99, fooField.value());
187187
assertTrue(original.calledGet, "Custom getter should be called");
@@ -200,11 +200,14 @@ void testManualModification() throws Exception {
200200
SimpleRecord original = new SimpleRecord("Original", 1, 1.0f);
201201
DeconstructedObject deconstructed = deconstructor.transform(original);
202202

203-
Map<String, DeconstructedObject.Field> map = new LinkedHashMap<>(deconstructed.asMap());
204-
DeconstructedObject.Field toReplace = map.get("value");
205-
map.replace("value", new DeconstructedObject.IntField("value", toReplace.annotatedType(), 999));
203+
var modifiedFields = deconstructed.asList().stream().map(f -> {
204+
if (f.name().equals("value"))
205+
return new DeconstructedObject.IntField("value", f.annotatedType(), 999);
206+
else
207+
return f;
208+
}).toList();
206209

207-
DeconstructedObject modified = new DeconstructedObject(map);
210+
DeconstructedObject modified = new DeconstructedObject(modifiedFields);
208211

209212
SimpleRecord copy = constructor.transform(modified);
210213

@@ -227,4 +230,12 @@ void testMultipleConstructions() throws Exception {
227230
}
228231
}
229232

233+
Optional<DeconstructedObject.Field> getField(DeconstructedObject obj, String name) {
234+
for (var field : obj) {
235+
if (field.name().equals(name))
236+
return Optional.of(field);
237+
}
238+
return Optional.empty();
239+
}
240+
230241
}

0 commit comments

Comments
 (0)