From 5eea18ea497d4bc11466b2bd875582ba26f188f5 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Thu, 14 Nov 2024 02:59:11 +0100 Subject: Add lists --- .../java/moe/nea/jcp/gson/GsonRecordBuilder.java | 5 ++- .../test/java/moe/nea/jcp/gson/test/TestBasic.java | 21 ++++++++++++ src/main/java/moe/nea/pcj/Result.java | 1 + src/main/java/moe/nea/pcj/json/AtIndex.java | 4 +++ src/main/java/moe/nea/pcj/json/JsonCodec.java | 40 ++++++++++++++++++++++ src/main/java/moe/nea/pcj/json/MapCodec.java | 4 +++ 6 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 src/main/java/moe/nea/pcj/json/AtIndex.java diff --git a/gson/src/main/java/moe/nea/jcp/gson/GsonRecordBuilder.java b/gson/src/main/java/moe/nea/jcp/gson/GsonRecordBuilder.java index ded1953..43498ac 100644 --- a/gson/src/main/java/moe/nea/jcp/gson/GsonRecordBuilder.java +++ b/gson/src/main/java/moe/nea/jcp/gson/GsonRecordBuilder.java @@ -23,9 +23,8 @@ public class GsonRecordBuilder extends GsonRecordView implements RecordBuilder ((JsonObject) it).entrySet().stream()) .map(it -> next.add(it.getKey(), it.getValue())) - .reduce((left, right) -> left.appendErrors(right.errors())) - .map(it -> it.map(unit -> next)) - .orElse(Result.ok(next))); + .reduce(Result.ok(Unit.INSTANCE), (left, right) -> left.appendErrors(right.errors())) + .map(unit -> next)); } @Override diff --git a/gson/src/test/java/moe/nea/jcp/gson/test/TestBasic.java b/gson/src/test/java/moe/nea/jcp/gson/test/TestBasic.java index 58727f2..861656e 100644 --- a/gson/src/test/java/moe/nea/jcp/gson/test/TestBasic.java +++ b/gson/src/test/java/moe/nea/jcp/gson/test/TestBasic.java @@ -1,5 +1,6 @@ package moe.nea.jcp.gson.test; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; @@ -10,6 +11,7 @@ import moe.nea.pcj.Codec; import moe.nea.pcj.Decode; import moe.nea.pcj.Result; import moe.nea.pcj.json.AtField; +import moe.nea.pcj.json.AtIndex; import moe.nea.pcj.json.DuplicateJsonKey; import moe.nea.pcj.json.JsonLikeError; import moe.nea.pcj.json.JsonLikeOperations; @@ -21,6 +23,7 @@ import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.stream.Collectors; public class TestBasic { @@ -55,6 +58,14 @@ public class TestBasic { throw new IllegalArgumentException("Cannot convert " + arg + " to json object"); } + static JsonArray mkJsonArray(Object... args) { + JsonArray array = new JsonArray(); + for (Object arg : args) { + array.add(mkPrim(arg)); + } + return array; + } + static JsonObject mkJsonObject(Object... args) { JsonObject obj = new JsonObject(); for (int i = 0; i < args.length; i += 2) { @@ -99,6 +110,7 @@ public class TestBasic { assertFail(decode(codec, mkJsonObject("foo", "fooValue", "bar", "test")), new AtField("bar", new UnexpectedJsonElement("number", mkPrim("test")))); } + @Test void testDuplicateKeys() { var codec = RecordJoiners.join( @@ -110,5 +122,14 @@ public class TestBasic { assertFail(codec.encode(new TestObject("", 0), GsonOperations.INSTANCE), new DuplicateJsonKey("foo")); } + + @Test + void testList() { + var codec = codecs.STRING.fieldOf("hello").codec().listOf(); + assertSuccess(decode(codec, mkJsonArray(mkJsonObject("hello", "foo"), mkJsonObject("hello", "bar"))), + List.of("foo", "bar")); + assertFail(decode(codec, mkJsonArray("foo", mkJsonObject("hello", "bar"))), + new AtIndex(0, new UnexpectedJsonElement("object", mkPrim("foo")))); + } } diff --git a/src/main/java/moe/nea/pcj/Result.java b/src/main/java/moe/nea/pcj/Result.java index 22c94f9..af5398e 100644 --- a/src/main/java/moe/nea/pcj/Result.java +++ b/src/main/java/moe/nea/pcj/Result.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; public sealed interface Result permits Result.Ok, Result.Fail { diff --git a/src/main/java/moe/nea/pcj/json/AtIndex.java b/src/main/java/moe/nea/pcj/json/AtIndex.java new file mode 100644 index 0000000..ec01112 --- /dev/null +++ b/src/main/java/moe/nea/pcj/json/AtIndex.java @@ -0,0 +1,4 @@ +package moe.nea.pcj.json; + +public record AtIndex(int index, JsonLikeError error) implements JsonLikeError { +} diff --git a/src/main/java/moe/nea/pcj/json/JsonCodec.java b/src/main/java/moe/nea/pcj/json/JsonCodec.java index 65f4a5e..6195bee 100644 --- a/src/main/java/moe/nea/pcj/json/JsonCodec.java +++ b/src/main/java/moe/nea/pcj/json/JsonCodec.java @@ -2,11 +2,51 @@ package moe.nea.pcj.json; import moe.nea.pcj.Codec; import moe.nea.pcj.Result; +import moe.nea.pcj.Unit; + +import java.util.ArrayList; +import java.util.List; public interface JsonCodec extends Codec< T, Format, JsonLikeOperations, JsonLikeError, JsonLikeError> { + default JsonCodec, Format> listOf() { + return new JsonCodec<>() { + @Override + public Result encode(List data, JsonLikeOperations ops) { + var list = ops.createList(); + var erros = new ArrayList(); + for (int i = 0; i < data.size(); i++) { + var datum = data.get(i); + final var index = i; + var result = JsonCodec.this.encode(datum, ops) + .mapError(it -> new AtIndex(index, it)); + erros.addAll(result.errors()); + result.valueOrPartial().ifPresent(list::add); + } + return Result.ok(list.complete()).appendErrors(erros); + } + + @Override + public Result, JsonLikeError> decode(Format format, JsonLikeOperations ops) { + var view = Result., JsonLikeError>cast(ops.getList(format)); + return view.flatMap(elements -> { + var acc = new ArrayList(elements.length()); + var errors = new ArrayList(); + for (int i = 0; i < elements.length(); i++) { + final var index = i; + var result = JsonCodec.this.decode(elements.getUnsafe(i), ops) + .mapError(it -> new AtIndex(index, it)); + errors.addAll(result.errors()); + result.valueOrPartial().ifPresent(acc::add); + } + return Result., JsonLikeError>ok(acc).appendErrors(errors); + }); + } + }; + } + default MapCodec fieldOf(String key) { return new MapCodec<>() { @Override diff --git a/src/main/java/moe/nea/pcj/json/MapCodec.java b/src/main/java/moe/nea/pcj/json/MapCodec.java index 468e4cf..4b76150 100644 --- a/src/main/java/moe/nea/pcj/json/MapCodec.java +++ b/src/main/java/moe/nea/pcj/json/MapCodec.java @@ -11,6 +11,10 @@ public interface MapCodec { Result, JsonLikeError> encode(T value, JsonLikeOperations ops); + default JsonCodec codec() { + return RecordJoiners.join(withGetter(it -> it), it -> it); + } + default RecordCodec withGetter(Function getter) { return new RecordCodec<>(this, getter); } -- cgit