From 742a354000241d25406ffbe9a38f9eb2e6d0e128 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Thu, 14 Nov 2024 21:10:13 +0100 Subject: Add dispatch codecs --- src/main/java/moe/nea/pcj/Result.java | 5 +- src/main/java/moe/nea/pcj/json/MapCodec.java | 39 ++++++- src/main/java/moe/nea/pcj/json/RecordCodec.java | 13 +-- src/main/java/moe/nea/pcj/json/RecordJoiners.java | 127 ++++++++++------------ 4 files changed, 98 insertions(+), 86 deletions(-) (limited to 'src/main/java/moe') diff --git a/src/main/java/moe/nea/pcj/Result.java b/src/main/java/moe/nea/pcj/Result.java index af5398e..a9c2494 100644 --- a/src/main/java/moe/nea/pcj/Result.java +++ b/src/main/java/moe/nea/pcj/Result.java @@ -7,7 +7,6 @@ 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 { @@ -37,6 +36,10 @@ public sealed interface Result permits Result.Ok, Result.Fail { Result mapErrors(Function, List> mapper); + default Result appendError(Bad error) { + return appendErrors(List.of(error)); + } + Result appendErrors(List error); record Ok(Good okValue) implements Result { diff --git a/src/main/java/moe/nea/pcj/json/MapCodec.java b/src/main/java/moe/nea/pcj/json/MapCodec.java index 4b76150..b18a639 100644 --- a/src/main/java/moe/nea/pcj/json/MapCodec.java +++ b/src/main/java/moe/nea/pcj/json/MapCodec.java @@ -5,14 +5,49 @@ import moe.nea.pcj.Result; import java.util.function.Function; public interface MapCodec { - Result decode( + Result decode( RecordView record, JsonLikeOperations ops); Result, JsonLikeError> encode(T value, JsonLikeOperations ops); + default MapCodec dispatch( + Function keyExtractor, + Function> codecGenerator + ) { + // TODO: the codecGenerator function is not exactly typesafe. there should be some limit on keyExtractor and codecGenerator working in tandem + return new MapCodec<>() { + @Override + public Result decode(RecordView record, JsonLikeOperations ops) { + return MapCodec.this.decode(record, ops) + .map(codecGenerator::apply) + .flatMap(codec -> codec.decode(record, ops)); + } + + @Override + public Result, JsonLikeError> encode(O value, JsonLikeOperations ops) { + var key = keyExtractor.apply(value); + var codec = codecGenerator.apply(key); + return MapCodec.this + .encode(key, ops) + .flatMap(keyEncoded -> ((MapCodec) codec).encode(value, ops).flatMap(keyEncoded::mergeWith)); + } + }; + } + default JsonCodec codec() { - return RecordJoiners.join(withGetter(it -> it), it -> it); + return new JsonCodec<>() { + @Override + public Result decode(Format format, JsonLikeOperations ops) { + return Result., JsonLikeError>cast(ops.getObject(format)) + .flatMap(record -> MapCodec.this.decode(record, ops)); + } + + @Override + public Result encode(T data, JsonLikeOperations ops) { + return Result.cast(MapCodec.this.encode(data, ops)).map(RecordBuilder::complete); + } + }; } default RecordCodec withGetter(Function getter) { diff --git a/src/main/java/moe/nea/pcj/json/RecordCodec.java b/src/main/java/moe/nea/pcj/json/RecordCodec.java index cb6d696..fa7aac7 100644 --- a/src/main/java/moe/nea/pcj/json/RecordCodec.java +++ b/src/main/java/moe/nea/pcj/json/RecordCodec.java @@ -14,21 +14,10 @@ public record RecordCodec( } Result dec(RecordView data, JsonLikeOperations ops) { - return codec().decode(data, ops); + return Result.cast(codec().decode(data, ops)); } static Result, JsonLikeError> merge(Result, JsonLikeError> left, Result, JsonLikeError> right) { return left.flatMap(l -> right.flatMap(l::mergeWith)); } - - abstract static class RecordCompleteCodec implements JsonCodec { - @Override - public Result decode(Format format, JsonLikeOperations ops) { - return Result., JsonLikeError>cast(ops.getObject(format)) - .flatMap(record -> (decode(record, ops))); - } - - protected abstract Result decode(RecordView record, JsonLikeOperations ops); - } - } diff --git a/src/main/java/moe/nea/pcj/json/RecordJoiners.java b/src/main/java/moe/nea/pcj/json/RecordJoiners.java index 3af622d..57bdd63 100644 --- a/src/main/java/moe/nea/pcj/json/RecordJoiners.java +++ b/src/main/java/moe/nea/pcj/json/RecordJoiners.java @@ -2,21 +2,19 @@ package moe.nea.pcj.json; import moe.nea.pcj.*; -import moe.nea.pcj.json.RecordCodec.*; import java.util.stream.*; @SuppressWarnings("unused") public class RecordJoiners { - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, Tuple.Func1 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -25,17 +23,16 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, Tuple.Func2 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -44,18 +41,17 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, Tuple.Func3 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -64,19 +60,18 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, RecordCodec arg3, Tuple.Func4 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -85,7 +80,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -93,12 +88,11 @@ public class RecordJoiners { RecordCodec arg4, Tuple.Func5 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -107,7 +101,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -116,12 +110,11 @@ public class RecordJoiners { RecordCodec arg5, Tuple.Func6 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops), arg5.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -130,7 +123,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -140,12 +133,11 @@ public class RecordJoiners { RecordCodec arg6, Tuple.Func7 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops), arg5.enc(data, ops), arg6.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -154,7 +146,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -165,12 +157,11 @@ public class RecordJoiners { RecordCodec arg7, Tuple.Func8 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops), arg5.enc(data, ops), arg6.enc(data, ops), arg7.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -179,7 +170,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -191,12 +182,11 @@ public class RecordJoiners { RecordCodec arg8, Tuple.Func9 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops), arg5.enc(data, ops), arg6.enc(data, ops), arg7.enc(data, ops), arg8.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -205,7 +195,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -218,12 +208,11 @@ public class RecordJoiners { RecordCodec arg9, Tuple.Func10 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops), arg5.enc(data, ops), arg6.enc(data, ops), arg7.enc(data, ops), arg8.enc(data, ops), arg9.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -232,7 +221,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -246,12 +235,11 @@ public class RecordJoiners { RecordCodec arg10, Tuple.Func11 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops), arg5.enc(data, ops), arg6.enc(data, ops), arg7.enc(data, ops), arg8.enc(data, ops), arg9.enc(data, ops), arg10.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -260,7 +248,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -275,12 +263,11 @@ public class RecordJoiners { RecordCodec arg11, Tuple.Func12 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops), arg5.enc(data, ops), arg6.enc(data, ops), arg7.enc(data, ops), arg8.enc(data, ops), arg9.enc(data, ops), arg10.enc(data, ops), arg11.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -289,7 +276,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -305,12 +292,11 @@ public class RecordJoiners { RecordCodec arg12, Tuple.Func13 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops), arg5.enc(data, ops), arg6.enc(data, ops), arg7.enc(data, ops), arg8.enc(data, ops), arg9.enc(data, ops), arg10.enc(data, ops), arg11.enc(data, ops), arg12.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { @@ -319,7 +305,7 @@ public class RecordJoiners { } }; } - public static JsonCodec join( + public static MapCodec join( RecordCodec arg0, RecordCodec arg1, RecordCodec arg2, @@ -336,12 +322,11 @@ public class RecordJoiners { RecordCodec arg13, Tuple.Func14 joiner ) { - return new RecordCompleteCodec<>() { + return new MapCodec<>() { @Override - public Result encode(O data, JsonLikeOperations ops) { + public Result, JsonLikeError> encode(O data, JsonLikeOperations ops) { return Stream.of(arg0.enc(data, ops), arg1.enc(data, ops), arg2.enc(data, ops), arg3.enc(data, ops), arg4.enc(data, ops), arg5.enc(data, ops), arg6.enc(data, ops), arg7.enc(data, ops), arg8.enc(data, ops), arg9.enc(data, ops), arg10.enc(data, ops), arg11.enc(data, ops), arg12.enc(data, ops), arg13.enc(data, ops)) - .reduce(Result.ok(ops.createObject()), RecordCodec::merge) - .map(RecordBuilder::complete); + .reduce(Result.ok(ops.createObject()), RecordCodec::merge); } @Override public Result decode(RecordView format, JsonLikeOperations ops) { -- cgit