From bd067a61e44a2d9cfaf0c392e67fc29d4cd223be Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 12 Mar 2020 10:32:08 +0100 Subject: [PATCH 01/96] Version bump --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 66a62f35..a07d0e62 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -majorMinor: 2.0 +majorMinor: 3.0 From 86514dc781e4dbdd5207ea314a0027f2cf6050e2 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 9 Mar 2020 04:59:25 +0100 Subject: [PATCH 02/96] Posfix function application helper for Dynamic --- src/main/java/com/mojang/datafixers/Dynamic.java | 4 ++++ src/main/java/com/mojang/datafixers/OptionalDynamic.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/com/mojang/datafixers/Dynamic.java b/src/main/java/com/mojang/datafixers/Dynamic.java index e114b07e..663583ca 100644 --- a/src/main/java/com/mojang/datafixers/Dynamic.java +++ b/src/main/java/com/mojang/datafixers/Dynamic.java @@ -185,6 +185,10 @@ public Dynamic convert(final DynamicOps outOps) { return new Dynamic<>(outOps, convert(ops, outOps, value)); } + public V into(final Function, ? extends V> action) { + return action.apply(this); + } + @SuppressWarnings("unchecked") public static T convert(final DynamicOps inOps, final DynamicOps outOps, final S input) { if (Objects.equals(inOps, outOps)) { diff --git a/src/main/java/com/mojang/datafixers/OptionalDynamic.java b/src/main/java/com/mojang/datafixers/OptionalDynamic.java index 8177b5f1..b9f4958e 100644 --- a/src/main/java/com/mojang/datafixers/OptionalDynamic.java +++ b/src/main/java/com/mojang/datafixers/OptionalDynamic.java @@ -99,4 +99,8 @@ public Dynamic orElseEmptyMap() { public Dynamic orElseEmptyList() { return delegate.orElseGet(this::emptyList); } + + public Optional into(final Function, ? extends V> action) { + return get().map(action); + } } From 83fc8f71fbab7d249e74fc9ece3f13dc55347a09 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 9 Mar 2020 06:24:25 +0100 Subject: [PATCH 03/96] Moved dynamic-related code to a separate package --- src/main/java/com/mojang/datafixers/DSL.java | 2 +- src/main/java/com/mojang/datafixers/DataFix.java | 3 ++- src/main/java/com/mojang/datafixers/DataFixer.java | 1 + src/main/java/com/mojang/datafixers/DataFixerUpper.java | 1 + src/main/java/com/mojang/datafixers/Typed.java | 3 ++- src/main/java/com/mojang/datafixers/View.java | 2 +- src/main/java/com/mojang/datafixers/functions/Apply.java | 2 +- src/main/java/com/mojang/datafixers/functions/Bang.java | 2 +- src/main/java/com/mojang/datafixers/functions/Comp.java | 2 +- src/main/java/com/mojang/datafixers/functions/Fold.java | 2 +- .../com/mojang/datafixers/functions/FunctionWrapper.java | 2 +- src/main/java/com/mojang/datafixers/functions/Functions.java | 2 +- src/main/java/com/mojang/datafixers/functions/Id.java | 2 +- src/main/java/com/mojang/datafixers/functions/In.java | 2 +- src/main/java/com/mojang/datafixers/functions/Out.java | 2 +- src/main/java/com/mojang/datafixers/functions/PointFree.java | 2 +- .../mojang/datafixers/functions/ProfunctorTransformer.java | 2 +- src/main/java/com/mojang/datafixers/types/Func.java | 1 + src/main/java/com/mojang/datafixers/types/Type.java | 3 ++- .../java/com/mojang/datafixers/types/constant/BoolType.java | 2 +- .../java/com/mojang/datafixers/types/constant/ByteType.java | 2 +- .../com/mojang/datafixers/types/constant/DoubleType.java | 2 +- .../java/com/mojang/datafixers/types/constant/FloatType.java | 2 +- .../java/com/mojang/datafixers/types/constant/IntType.java | 2 +- .../java/com/mojang/datafixers/types/constant/LongType.java | 2 +- .../datafixers/types/constant/NamespacedStringType.java | 2 +- .../java/com/mojang/datafixers/types/constant/NilDrop.java | 2 +- .../java/com/mojang/datafixers/types/constant/NilSave.java | 4 ++-- .../java/com/mojang/datafixers/types/constant/ShortType.java | 2 +- .../com/mojang/datafixers/types/constant/StringType.java | 2 +- .../java/com/mojang/datafixers/types/templates/Check.java | 2 +- .../com/mojang/datafixers/types/templates/CompoundList.java | 2 +- .../java/com/mojang/datafixers/types/templates/Hook.java | 2 +- .../java/com/mojang/datafixers/types/templates/List.java | 2 +- .../java/com/mojang/datafixers/types/templates/Named.java | 2 +- .../java/com/mojang/datafixers/types/templates/Product.java | 2 +- .../mojang/datafixers/types/templates/RecursivePoint.java | 2 +- src/main/java/com/mojang/datafixers/types/templates/Sum.java | 2 +- src/main/java/com/mojang/datafixers/types/templates/Tag.java | 2 +- .../com/mojang/datafixers/types/templates/TaggedChoice.java | 2 +- .../com/mojang/{datafixers => serialization}/Dynamic.java | 5 +++-- .../mojang/{datafixers => serialization}/DynamicLike.java | 3 +-- .../{datafixers/types => serialization}/DynamicOps.java | 4 ++-- .../mojang/{datafixers/types => serialization}/JsonOps.java | 3 ++- .../{datafixers => serialization}/OptionalDynamic.java | 4 +--- 45 files changed, 53 insertions(+), 48 deletions(-) rename src/main/java/com/mojang/{datafixers => serialization}/Dynamic.java (98%) rename src/main/java/com/mojang/{datafixers => serialization}/DynamicLike.java (98%) rename src/main/java/com/mojang/{datafixers/types => serialization}/DynamicOps.java (98%) rename src/main/java/com/mojang/{datafixers/types => serialization}/JsonOps.java (99%) rename src/main/java/com/mojang/{datafixers => serialization}/OptionalDynamic.java (97%) diff --git a/src/main/java/com/mojang/datafixers/DSL.java b/src/main/java/com/mojang/datafixers/DSL.java index be9d3f51..7260ffa0 100644 --- a/src/main/java/com/mojang/datafixers/DSL.java +++ b/src/main/java/com/mojang/datafixers/DSL.java @@ -6,7 +6,6 @@ import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Unit; -import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.types.Func; import com.mojang.datafixers.types.Type; @@ -33,6 +32,7 @@ import com.mojang.datafixers.types.templates.Tag; import com.mojang.datafixers.types.templates.TaggedChoice; import com.mojang.datafixers.types.templates.TypeTemplate; +import com.mojang.serialization.Dynamic; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.tuple.Triple; diff --git a/src/main/java/com/mojang/datafixers/DataFix.java b/src/main/java/com/mojang/datafixers/DataFix.java index f396fcbb..fb66eb82 100644 --- a/src/main/java/com/mojang/datafixers/DataFix.java +++ b/src/main/java/com/mojang/datafixers/DataFix.java @@ -3,7 +3,8 @@ package com.mojang.datafixers; import com.mojang.datafixers.schemas.Schema; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/com/mojang/datafixers/DataFixer.java b/src/main/java/com/mojang/datafixers/DataFixer.java index e8b8b2bb..234eaa3b 100644 --- a/src/main/java/com/mojang/datafixers/DataFixer.java +++ b/src/main/java/com/mojang/datafixers/DataFixer.java @@ -3,6 +3,7 @@ package com.mojang.datafixers; import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; public interface DataFixer { Dynamic update(DSL.TypeReference type, Dynamic input, int version, int newVersion); diff --git a/src/main/java/com/mojang/datafixers/DataFixerUpper.java b/src/main/java/com/mojang/datafixers/DataFixerUpper.java index b6eca89e..e7ce1225 100644 --- a/src/main/java/com/mojang/datafixers/DataFixerUpper.java +++ b/src/main/java/com/mojang/datafixers/DataFixerUpper.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import com.mojang.serialization.Dynamic; import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap; import it.unimi.dsi.fastutil.ints.IntSortedSet; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; diff --git a/src/main/java/com/mojang/datafixers/Typed.java b/src/main/java/com/mojang/datafixers/Typed.java index a6195abd..6195d5a4 100644 --- a/src/main/java/com/mojang/datafixers/Typed.java +++ b/src/main/java/com/mojang/datafixers/Typed.java @@ -17,7 +17,8 @@ import com.mojang.datafixers.optics.ReForgetC; import com.mojang.datafixers.optics.Traversal; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.templates.RecursivePoint; diff --git a/src/main/java/com/mojang/datafixers/View.java b/src/main/java/com/mojang/datafixers/View.java index 53234c72..1ff3d483 100644 --- a/src/main/java/com/mojang/datafixers/View.java +++ b/src/main/java/com/mojang/datafixers/View.java @@ -7,7 +7,7 @@ import com.mojang.datafixers.functions.PointFreeRule; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import java.util.Objects; diff --git a/src/main/java/com/mojang/datafixers/functions/Apply.java b/src/main/java/com/mojang/datafixers/functions/Apply.java index 6325412b..189fa987 100644 --- a/src/main/java/com/mojang/datafixers/functions/Apply.java +++ b/src/main/java/com/mojang/datafixers/functions/Apply.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.functions; import com.mojang.datafixers.DSL; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import java.util.Objects; diff --git a/src/main/java/com/mojang/datafixers/functions/Bang.java b/src/main/java/com/mojang/datafixers/functions/Bang.java index a3d756a6..03db0265 100644 --- a/src/main/java/com/mojang/datafixers/functions/Bang.java +++ b/src/main/java/com/mojang/datafixers/functions/Bang.java @@ -2,7 +2,7 @@ // Licensed under the MIT license. package com.mojang.datafixers.functions; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/functions/Comp.java b/src/main/java/com/mojang/datafixers/functions/Comp.java index 2d0245c2..d3d88776 100644 --- a/src/main/java/com/mojang/datafixers/functions/Comp.java +++ b/src/main/java/com/mojang/datafixers/functions/Comp.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.functions; import com.mojang.datafixers.DSL; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Func; import com.mojang.datafixers.types.Type; diff --git a/src/main/java/com/mojang/datafixers/functions/Fold.java b/src/main/java/com/mojang/datafixers/functions/Fold.java index c6cd021f..419e4639 100644 --- a/src/main/java/com/mojang/datafixers/functions/Fold.java +++ b/src/main/java/com/mojang/datafixers/functions/Fold.java @@ -5,7 +5,7 @@ import com.google.common.collect.Maps; import com.mojang.datafixers.RewriteResult; import com.mojang.datafixers.View; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.families.Algebra; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.templates.RecursivePoint; diff --git a/src/main/java/com/mojang/datafixers/functions/FunctionWrapper.java b/src/main/java/com/mojang/datafixers/functions/FunctionWrapper.java index c58aed2a..07ec5b61 100644 --- a/src/main/java/com/mojang/datafixers/functions/FunctionWrapper.java +++ b/src/main/java/com/mojang/datafixers/functions/FunctionWrapper.java @@ -2,7 +2,7 @@ // Licensed under the MIT license. package com.mojang.datafixers.functions; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/functions/Functions.java b/src/main/java/com/mojang/datafixers/functions/Functions.java index f0b5562a..a113353b 100644 --- a/src/main/java/com/mojang/datafixers/functions/Functions.java +++ b/src/main/java/com/mojang/datafixers/functions/Functions.java @@ -5,7 +5,7 @@ import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.RewriteResult; import com.mojang.datafixers.optics.Optic; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.Algebra; import com.mojang.datafixers.types.templates.RecursivePoint; diff --git a/src/main/java/com/mojang/datafixers/functions/Id.java b/src/main/java/com/mojang/datafixers/functions/Id.java index 7be4a901..c27cb2c6 100644 --- a/src/main/java/com/mojang/datafixers/functions/Id.java +++ b/src/main/java/com/mojang/datafixers/functions/Id.java @@ -2,7 +2,7 @@ // Licensed under the MIT license. package com.mojang.datafixers.functions; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/functions/In.java b/src/main/java/com/mojang/datafixers/functions/In.java index 98249d89..9479d787 100644 --- a/src/main/java/com/mojang/datafixers/functions/In.java +++ b/src/main/java/com/mojang/datafixers/functions/In.java @@ -2,7 +2,7 @@ // Licensed under the MIT license. package com.mojang.datafixers.functions; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.RecursivePoint; import java.util.Objects; diff --git a/src/main/java/com/mojang/datafixers/functions/Out.java b/src/main/java/com/mojang/datafixers/functions/Out.java index 8242d3b3..84367060 100644 --- a/src/main/java/com/mojang/datafixers/functions/Out.java +++ b/src/main/java/com/mojang/datafixers/functions/Out.java @@ -2,7 +2,7 @@ // Licensed under the MIT license. package com.mojang.datafixers.functions; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.RecursivePoint; import java.util.Objects; diff --git a/src/main/java/com/mojang/datafixers/functions/PointFree.java b/src/main/java/com/mojang/datafixers/functions/PointFree.java index bcdbaad7..cf080f1d 100644 --- a/src/main/java/com/mojang/datafixers/functions/PointFree.java +++ b/src/main/java/com/mojang/datafixers/functions/PointFree.java @@ -2,7 +2,7 @@ // Licensed under the MIT license. package com.mojang.datafixers.functions; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import org.apache.commons.lang3.StringUtils; diff --git a/src/main/java/com/mojang/datafixers/functions/ProfunctorTransformer.java b/src/main/java/com/mojang/datafixers/functions/ProfunctorTransformer.java index 5e032e7e..a6240b48 100644 --- a/src/main/java/com/mojang/datafixers/functions/ProfunctorTransformer.java +++ b/src/main/java/com/mojang/datafixers/functions/ProfunctorTransformer.java @@ -5,7 +5,7 @@ import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.optics.Optic; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/types/Func.java b/src/main/java/com/mojang/datafixers/types/Func.java index 2d943bce..74b6511d 100644 --- a/src/main/java/com/mojang/datafixers/types/Func.java +++ b/src/main/java/com/mojang/datafixers/types/Func.java @@ -4,6 +4,7 @@ import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.types.templates.TypeTemplate; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/Type.java b/src/main/java/com/mojang/datafixers/types/Type.java index 2f44051b..8213ab4d 100644 --- a/src/main/java/com/mojang/datafixers/types/Type.java +++ b/src/main/java/com/mojang/datafixers/types/Type.java @@ -5,7 +5,7 @@ import com.google.common.collect.Maps; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; -import com.mojang.datafixers.Dynamic; +import com.mojang.serialization.Dynamic; import com.mojang.datafixers.FieldFinder; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.OpticFinder; @@ -23,6 +23,7 @@ import com.mojang.datafixers.types.templates.TypeTemplate; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DynamicOps; import org.apache.commons.lang3.tuple.Triple; import javax.annotation.Nullable; diff --git a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java index 8a0f22e4..3ca0b9d2 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java index 03878a5f..8472005a 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java index 86777ca5..255bd5c4 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java index 6f396d84..1d1fc564 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/constant/IntType.java b/src/main/java/com/mojang/datafixers/types/constant/IntType.java index 50269611..70626fd6 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/IntType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/IntType.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/constant/LongType.java b/src/main/java/com/mojang/datafixers/types/constant/LongType.java index 987f5eaa..b892f2cf 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/LongType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/LongType.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java index 33fe1698..c67ebdf8 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.types.constant; import com.google.common.base.Function; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; diff --git a/src/main/java/com/mojang/datafixers/types/constant/NilDrop.java b/src/main/java/com/mojang/datafixers/types/constant/NilDrop.java index 0503270b..b0b272c8 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/NilDrop.java +++ b/src/main/java/com/mojang/datafixers/types/constant/NilDrop.java @@ -4,7 +4,7 @@ import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Unit; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/constant/NilSave.java b/src/main/java/com/mojang/datafixers/types/constant/NilSave.java index 8a8a3198..cbd2b302 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/NilSave.java +++ b/src/main/java/com/mojang/datafixers/types/constant/NilSave.java @@ -3,8 +3,8 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.Dynamic; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java index 3557eff1..7ee6023e 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/constant/StringType.java b/src/main/java/com/mojang/datafixers/types/constant/StringType.java index ef855366..ee991f9c 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/StringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/StringType.java @@ -3,7 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/types/templates/Check.java b/src/main/java/com/mojang/datafixers/types/templates/Check.java index a2c76238..b58ee9a0 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Check.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Check.java @@ -11,7 +11,7 @@ import com.mojang.datafixers.TypeRewriteRule; import com.mojang.datafixers.TypedOptic; import com.mojang.datafixers.functions.Functions; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java index 33bda0e0..a5485ec4 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java +++ b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java @@ -20,7 +20,7 @@ import com.mojang.datafixers.optics.Optic; import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/types/templates/Hook.java b/src/main/java/com/mojang/datafixers/types/templates/Hook.java index 84db30bb..bca59b22 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Hook.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Hook.java @@ -10,7 +10,7 @@ import com.mojang.datafixers.TypeRewriteRule; import com.mojang.datafixers.TypedOptic; import com.mojang.datafixers.functions.Functions; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/types/templates/List.java b/src/main/java/com/mojang/datafixers/types/templates/List.java index 956bea11..a03dc1ed 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/List.java +++ b/src/main/java/com/mojang/datafixers/types/templates/List.java @@ -17,7 +17,7 @@ import com.mojang.datafixers.optics.ListTraversal; import com.mojang.datafixers.optics.Optic; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/types/templates/Named.java b/src/main/java/com/mojang/datafixers/types/templates/Named.java index 8cb96e16..f650413d 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Named.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Named.java @@ -15,7 +15,7 @@ import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.profunctors.Cartesian; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/types/templates/Product.java b/src/main/java/com/mojang/datafixers/types/templates/Product.java index 448e95c8..dfd545d6 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Product.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Product.java @@ -21,7 +21,7 @@ import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.Traversal; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java index 2ffadfb9..4734609e 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java +++ b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java @@ -12,7 +12,7 @@ import com.mojang.datafixers.View; import com.mojang.datafixers.functions.Functions; import com.mojang.datafixers.functions.PointFreeRule; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/types/templates/Sum.java b/src/main/java/com/mojang/datafixers/types/templates/Sum.java index 997c81da..b0dbaa3e 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Sum.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Sum.java @@ -20,7 +20,7 @@ import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.Traversal; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index c13e09ff..da1df179 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -11,7 +11,7 @@ import com.mojang.datafixers.TypedOptic; import com.mojang.datafixers.View; import com.mojang.datafixers.functions.Functions; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index 847b1332..fe5d8efc 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -29,7 +29,7 @@ import com.mojang.datafixers.optics.profunctors.AffineP; import com.mojang.datafixers.optics.profunctors.Cartesian; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; diff --git a/src/main/java/com/mojang/datafixers/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java similarity index 98% rename from src/main/java/com/mojang/datafixers/Dynamic.java rename to src/main/java/com/mojang/serialization/Dynamic.java index 663583ca..a92ab0fa 100644 --- a/src/main/java/com/mojang/datafixers/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -package com.mojang.datafixers; +package com.mojang.serialization; import com.google.common.collect.ImmutableMap; -import com.mojang.datafixers.types.DynamicOps; +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.util.Pair; diff --git a/src/main/java/com/mojang/datafixers/DynamicLike.java b/src/main/java/com/mojang/serialization/DynamicLike.java similarity index 98% rename from src/main/java/com/mojang/datafixers/DynamicLike.java rename to src/main/java/com/mojang/serialization/DynamicLike.java index 9fb0fc4d..30a03d1b 100644 --- a/src/main/java/com/mojang/datafixers/DynamicLike.java +++ b/src/main/java/com/mojang/serialization/DynamicLike.java @@ -1,8 +1,7 @@ -package com.mojang.datafixers; +package com.mojang.serialization; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.mojang.datafixers.types.DynamicOps; import java.nio.ByteBuffer; import java.util.List; diff --git a/src/main/java/com/mojang/datafixers/types/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java similarity index 98% rename from src/main/java/com/mojang/datafixers/types/DynamicOps.java rename to src/main/java/com/mojang/serialization/DynamicOps.java index 010595f5..dcda8209 100644 --- a/src/main/java/com/mojang/datafixers/types/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -package com.mojang.datafixers.types; +package com.mojang.serialization; import com.google.common.collect.ImmutableMap; -import com.mojang.datafixers.Dynamic; +import com.mojang.datafixers.types.Type; import java.nio.ByteBuffer; import java.util.List; diff --git a/src/main/java/com/mojang/datafixers/types/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java similarity index 99% rename from src/main/java/com/mojang/datafixers/types/JsonOps.java rename to src/main/java/com/mojang/serialization/JsonOps.java index 8ef11236..88113383 100644 --- a/src/main/java/com/mojang/datafixers/types/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -package com.mojang.datafixers.types; +package com.mojang.serialization; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -8,6 +8,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.mojang.datafixers.DSL; +import com.mojang.datafixers.types.Type; import com.mojang.datafixers.util.Pair; import java.math.BigDecimal; diff --git a/src/main/java/com/mojang/datafixers/OptionalDynamic.java b/src/main/java/com/mojang/serialization/OptionalDynamic.java similarity index 97% rename from src/main/java/com/mojang/datafixers/OptionalDynamic.java rename to src/main/java/com/mojang/serialization/OptionalDynamic.java index b9f4958e..abb18b95 100644 --- a/src/main/java/com/mojang/datafixers/OptionalDynamic.java +++ b/src/main/java/com/mojang/serialization/OptionalDynamic.java @@ -1,6 +1,4 @@ -package com.mojang.datafixers; - -import com.mojang.datafixers.types.DynamicOps; +package com.mojang.serialization; import java.nio.ByteBuffer; import java.util.List; From e188d4b51af4a1b7b348564d9a5e59c3968fa7d0 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 10 Mar 2020 08:14:03 +0100 Subject: [PATCH 04/96] Renamed NilSave to EmptyPartSaving and NilDrop to EmptyPart; Added DataResult for keeping track of serialization errors and to allow partial recovery; made Type.write use it. --- src/main/java/com/mojang/datafixers/DSL.java | 20 +-- .../java/com/mojang/datafixers/DataFix.java | 13 +- .../com/mojang/datafixers/DataFixerUpper.java | 18 +-- .../java/com/mojang/datafixers/Typed.java | 3 +- .../datafixers/functions/PointFreeRule.java | 6 +- .../com/mojang/datafixers/types/Func.java | 7 +- .../com/mojang/datafixers/types/Type.java | 33 ++--- .../datafixers/types/constant/BoolType.java | 6 +- .../datafixers/types/constant/ByteType.java | 6 +- .../datafixers/types/constant/DoubleType.java | 6 +- .../constant/{NilDrop.java => EmptyPart.java} | 32 +++-- .../types/constant/EmptyPartSaving.java | 71 +++++++++++ .../datafixers/types/constant/FloatType.java | 6 +- .../datafixers/types/constant/IntType.java | 6 +- .../datafixers/types/constant/LongType.java | 6 +- .../types/constant/NamespacedStringType.java | 6 +- .../datafixers/types/constant/NilSave.java | 37 ------ .../datafixers/types/constant/ShortType.java | 6 +- .../datafixers/types/constant/StringType.java | 6 +- .../datafixers/types/templates/Check.java | 3 +- .../types/templates/CompoundList.java | 37 ++++-- .../datafixers/types/templates/Const.java | 14 ++- .../datafixers/types/templates/Hook.java | 5 +- .../datafixers/types/templates/List.java | 22 +++- .../datafixers/types/templates/Named.java | 5 +- .../datafixers/types/templates/Product.java | 5 +- .../types/templates/RecursivePoint.java | 3 +- .../datafixers/types/templates/Sum.java | 3 +- .../datafixers/types/templates/Tag.java | 7 +- .../types/templates/TaggedChoice.java | 59 +++++---- .../types/templates/TypeTemplate.java | 2 +- .../com/mojang/serialization/DataResult.java | 118 ++++++++++++++++++ .../com/mojang/serialization/Dynamic.java | 39 +++--- .../com/mojang/serialization/DynamicLike.java | 2 + .../com/mojang/serialization/DynamicOps.java | 44 +++++-- .../com/mojang/serialization/JsonOps.java | 115 +++++++++-------- .../mojang/serialization/OptionalDynamic.java | 24 ++-- 37 files changed, 531 insertions(+), 270 deletions(-) rename src/main/java/com/mojang/datafixers/types/constant/{NilDrop.java => EmptyPart.java} (50%) create mode 100644 src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/NilSave.java create mode 100644 src/main/java/com/mojang/serialization/DataResult.java diff --git a/src/main/java/com/mojang/datafixers/DSL.java b/src/main/java/com/mojang/datafixers/DSL.java index 7260ffa0..bf358326 100644 --- a/src/main/java/com/mojang/datafixers/DSL.java +++ b/src/main/java/com/mojang/datafixers/DSL.java @@ -16,8 +16,8 @@ import com.mojang.datafixers.types.constant.IntType; import com.mojang.datafixers.types.constant.LongType; import com.mojang.datafixers.types.constant.NamespacedStringType; -import com.mojang.datafixers.types.constant.NilDrop; -import com.mojang.datafixers.types.constant.NilSave; +import com.mojang.datafixers.types.constant.EmptyPart; +import com.mojang.datafixers.types.constant.EmptyPartSaving; import com.mojang.datafixers.types.constant.ShortType; import com.mojang.datafixers.types.constant.StringType; import com.mojang.datafixers.types.templates.Check; @@ -88,12 +88,12 @@ static Type namespacedString() { return Instances.NAMESPACED_STRING_TYPE; } - static TypeTemplate nil() { - return constType(Instances.NIL_DROP); + static TypeTemplate emptyPart() { + return constType(Instances.EMPTY_PART); } - static Type nilType() { - return Instances.NIL_DROP; + static Type emptyPartType() { + return Instances.EMPTY_PART; } static TypeTemplate remainder() { @@ -223,11 +223,11 @@ static Type> func(final Type input, final Type outpu // Helpers static Type> optional(final Type type) { - return or(type, nilType()); + return or(type, emptyPartType()); } static TypeTemplate optional(final TypeTemplate value) { - return or(value, nil()); + return or(value, emptyPart()); } static TypeTemplate fields( @@ -456,8 +456,8 @@ final class Instances { private static final Type DOUBLE_TYPE = new DoubleType(); private static final Type STRING_TYPE = new StringType(); private static final Type NAMESPACED_STRING_TYPE = new NamespacedStringType(); - private static final Type NIL_DROP = new NilDrop(); - private static final Type> NIL_SAVE = new NilSave(); + private static final Type EMPTY_PART = new EmptyPart(); + private static final Type> NIL_SAVE = new EmptyPartSaving(); private static final OpticFinder> REMAINDER_FINDER = remainderType().finder(); diff --git a/src/main/java/com/mojang/datafixers/DataFix.java b/src/main/java/com/mojang/datafixers/DataFix.java index fb66eb82..77a5416c 100644 --- a/src/main/java/com/mojang/datafixers/DataFix.java +++ b/src/main/java/com/mojang/datafixers/DataFix.java @@ -3,6 +3,7 @@ package com.mojang.datafixers; import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; @@ -12,6 +13,7 @@ import javax.annotation.Nullable; import java.util.BitSet; import java.util.Objects; +import java.util.Optional; import java.util.function.Function; public abstract class DataFix { @@ -41,9 +43,14 @@ protected TypeRewriteRule writeAndRead(final String name, final Type type, fi } protected TypeRewriteRule writeFixAndRead(final String name, final Type type, final Type newType, final Function, Dynamic> fix) { - return fixTypeEverywhere(name, type, newType, ops -> input -> - newType.readTyped(fix.apply(type.writeDynamic(ops, input))).getSecond().orElseThrow(() -> new IllegalStateException("Could not read new type in \"" + name + "\"")).getValue() - ); + return fixTypeEverywhere(name, type, newType, ops -> input -> { + final Optional> written = type.writeDynamic(ops, input).resultOrPartial(LOGGER::error); + if (!written.isPresent()) { + throw new RuntimeException("Could not write the object"); + } + final Optional> read = newType.readTyped(fix.apply(written.get())).getSecond(); + return read.orElseThrow(() -> new IllegalStateException("Could not read new type in \"" + name + "\"")).getValue(); + }); } protected TypeRewriteRule fixTypeEverywhere(final String name, final Type type, final Type newType, final Function, Function> function) { diff --git a/src/main/java/com/mojang/datafixers/DataFixerUpper.java b/src/main/java/com/mojang/datafixers/DataFixerUpper.java index e7ce1225..62912d06 100644 --- a/src/main/java/com/mojang/datafixers/DataFixerUpper.java +++ b/src/main/java/com/mojang/datafixers/DataFixerUpper.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap; import it.unimi.dsi.fastutil.ints.IntSortedSet; @@ -79,18 +80,11 @@ protected DataFixerUpper(final Int2ObjectSortedMap schemas, final List Dynamic update(final DSL.TypeReference type, final Dynamic input, final int version, final int newVersion) { - try { - if (version < newVersion) { - final Type dataType = getType(type, version); - final Optional read = dataType.readAndWrite(input.getOps(), getType(type, newVersion), getRule(version, newVersion), OPTIMIZATION_RULE, input.getValue()); - if (!read.isPresent()) { - throw new IllegalStateException("Could not parse for fixing " + dataType); - } - - return new Dynamic<>(input.getOps(), read.get()); - } - } catch (final Throwable t) { - LOGGER.error("Something went wrong upgrading!", t); + if (version < newVersion) { + final Type dataType = getType(type, version); + final DataResult read = dataType.readAndWrite(input.getOps(), getType(type, newVersion), getRule(version, newVersion), OPTIMIZATION_RULE, input.getValue()); + final T result = read.resultOrPartial(LOGGER::error).orElse(input.getValue()); + return new Dynamic<>(input.getOps(), result); } return input; } diff --git a/src/main/java/com/mojang/datafixers/Typed.java b/src/main/java/com/mojang/datafixers/Typed.java index 6195d5a4..75bf9622 100644 --- a/src/main/java/com/mojang/datafixers/Typed.java +++ b/src/main/java/com/mojang/datafixers/Typed.java @@ -17,6 +17,7 @@ import com.mojang.datafixers.optics.ReForgetC; import com.mojang.datafixers.optics.Traversal; import com.mojang.datafixers.optics.profunctors.TraversalP; +import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; @@ -206,7 +207,7 @@ public A getValue() { return value; } - public Dynamic write() { + public DataResult> write() { return type.writeDynamic(ops, value); } } diff --git a/src/main/java/com/mojang/datafixers/functions/PointFreeRule.java b/src/main/java/com/mojang/datafixers/functions/PointFreeRule.java index 68747734..cf5afb88 100644 --- a/src/main/java/com/mojang/datafixers/functions/PointFreeRule.java +++ b/src/main/java/com/mojang/datafixers/functions/PointFreeRule.java @@ -8,17 +8,15 @@ import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; -import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.RewriteResult; import com.mojang.datafixers.View; -import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.Optic; import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.types.Func; import com.mojang.datafixers.types.Type; -import com.mojang.datafixers.types.constant.NilDrop; +import com.mojang.datafixers.types.constant.EmptyPart; import com.mojang.datafixers.types.families.Algebra; import com.mojang.datafixers.types.families.ListAlgebra; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -75,7 +73,7 @@ public Optional> rewrite(final Type type, final Po } if (type instanceof Func) { final Func func = (Func) type; - if (func.second() instanceof NilDrop) { + if (func.second() instanceof EmptyPart) { return Optional.of((PointFree) Functions.bang()); } } diff --git a/src/main/java/com/mojang/datafixers/types/Func.java b/src/main/java/com/mojang/datafixers/types/Func.java index 74b6511d..b367d90a 100644 --- a/src/main/java/com/mojang/datafixers/types/Func.java +++ b/src/main/java/com/mojang/datafixers/types/Func.java @@ -2,8 +2,9 @@ // Licensed under the MIT license. package com.mojang.datafixers.types; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.types.templates.TypeTemplate; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import java.util.Objects; @@ -30,8 +31,8 @@ public Pair>> read(final DynamicOps ops, final } @Override - public T write(final DynamicOps ops, final T rest, final Function value) { - return rest; + public DataResult write(final DynamicOps ops, final T rest, final Function value) { + return DataResult.error("Cannot save a function " + value, rest); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/Type.java b/src/main/java/com/mojang/datafixers/types/Type.java index 8213ab4d..145e8c24 100644 --- a/src/main/java/com/mojang/datafixers/types/Type.java +++ b/src/main/java/com/mojang/datafixers/types/Type.java @@ -5,6 +5,7 @@ import com.google.common.collect.Maps; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; +import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.datafixers.FieldFinder; import com.mojang.datafixers.FunctionType; @@ -113,18 +114,14 @@ public final Pair, Optional> read(final Dynamic input) { public abstract Pair> read(final DynamicOps ops, final T input); - public abstract T write(final DynamicOps ops, final T rest, final A value); + public abstract DataResult write(final DynamicOps ops, final T rest, final A value); - public final T write(final DynamicOps ops, final A value) { + public final DataResult write(final DynamicOps ops, final A value) { return write(ops, ops.empty(), value); } - public final Dynamic writeDynamic(final DynamicOps ops, final T rest, final A value) { - return new Dynamic<>(ops, write(ops, rest, value)); - } - - public final Dynamic writeDynamic(final DynamicOps ops, final A value) { - return new Dynamic<>(ops, write(ops, value)); + public final DataResult> writeDynamic(final DynamicOps ops, final A value) { + return write(ops, value).map(result -> new Dynamic<>(ops, result)); } public Pair>> readTyped(final Dynamic input) { @@ -142,16 +139,22 @@ public Pair> read(final DynamicOps ops, final TypeRewriteR )); } - public Optional readAndWrite(final DynamicOps ops, final Type expectedType, final TypeRewriteRule rule, final PointFreeRule fRule, final T input) { + public DataResult readAndWrite(final DynamicOps ops, final Type expectedType, final TypeRewriteRule rule, final PointFreeRule fRule, final T input) { + final Optional> rewriteResult = rewrite(rule, fRule); + if (!rewriteResult.isPresent()) { + return DataResult.error("Could not build a rewrite rule: " + rule + " " + fRule, input); + } + final View view = rewriteResult.get().view(); + final Pair> po = read(ops, input); - return po.getSecond().flatMap(v -> - rewrite(rule, fRule).map(r -> - capWrite(ops, expectedType, po.getFirst(), v, r.view()) - ) - ); + if (!po.getSecond().isPresent()) { + return DataResult.error("Could not parse input: " + input + " ", input); + } + + return capWrite(ops, expectedType, po.getFirst(), po.getSecond().get(), view); } - public T capWrite(final DynamicOps ops, final Type expectedType, final T rest, final A value, final View f) { + private DataResult capWrite(final DynamicOps ops, final Type expectedType, final T rest, final A value, final View f) { if (!expectedType.equals(f.newType(), true, true)) { throw new IllegalStateException("Rewritten type doesn't match."); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java index 3ca0b9d2..3ed73d04 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.constant; +import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; import java.util.Optional; -public final class BoolType extends Const.ConstType { +public final class BoolType extends Const.PrimitiveType { @Override public Pair> read(final DynamicOps ops, final T input) { return ops @@ -18,7 +18,7 @@ public Pair> read(final DynamicOps ops, final T inpu } @Override - public T write(final DynamicOps ops, final T rest, final Boolean value) { + public T doWrite(final DynamicOps ops, final Boolean value) { return ops.createBoolean(value); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java index 8472005a..48813bcd 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.constant; +import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; import java.util.Optional; -public final class ByteType extends Const.ConstType { +public final class ByteType extends Const.PrimitiveType { @Override public Pair> read(final DynamicOps ops, final T input) { return ops @@ -18,7 +18,7 @@ public Pair> read(final DynamicOps ops, final T input) } @Override - public T write(final DynamicOps ops, final T rest, final Byte value) { + public T doWrite(final DynamicOps ops, final Byte value) { return ops.createByte(value); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java index 255bd5c4..ddcdd995 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.constant; +import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; import java.util.Optional; -public final class DoubleType extends Const.ConstType { +public final class DoubleType extends Const.PrimitiveType { @Override public Pair> read(final DynamicOps ops, final T input) { return ops @@ -18,7 +18,7 @@ public Pair> read(final DynamicOps ops, final T input } @Override - public T write(final DynamicOps ops, final T rest, final Double value) { + public T doWrite(final DynamicOps ops, final Double value) { return ops.createDouble(value); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/NilDrop.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java similarity index 50% rename from src/main/java/com/mojang/datafixers/types/constant/NilDrop.java rename to src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java index b0b272c8..c4c03c74 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/NilDrop.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java @@ -2,31 +2,43 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.constant; +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.types.templates.TypeTemplate; import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Unit; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; import java.util.Optional; -public final class NilDrop extends Const.ConstType { +public final class EmptyPart extends com.mojang.datafixers.types.Type { @Override - public Pair> read(final DynamicOps ops, final T input) { - return Pair.of(input, point(ops)); + public String toString() { + return "EmptyPart"; } @Override - public T write(final DynamicOps ops, final T rest, final Unit value) { - return rest; + public Optional point(final DynamicOps ops) { + return Optional.of(Unit.INSTANCE); } @Override - public String toString() { - return "NilDrop"; + public boolean equals(final Object o, final boolean ignoreRecursionPoints, final boolean checkIndex) { + return this == o; } @Override - public Optional point(final DynamicOps ops) { - return Optional.of(Unit.INSTANCE); + public TypeTemplate buildTemplate() { + return DSL.constType(this); + } + + @Override + public Pair> read(final DynamicOps ops, final T input) { + return Pair.of(input, point(ops)); + } + + @Override + public final DataResult write(final DynamicOps ops, final T rest, final Unit value) { + return DataResult.success(rest); } } diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java new file mode 100644 index 00000000..8d5d0e41 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.datafixers.types.constant; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.types.templates.TypeTemplate; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; + +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class EmptyPartSaving extends com.mojang.datafixers.types.Type> { + @Override + public String toString() { + return "EmptyPartSaving"; + } + + @Override + public Optional> point(final DynamicOps ops) { + return Optional.of(capEmpty(ops)); + } + + private Dynamic capEmpty(final DynamicOps ops) { + return new Dynamic<>(ops, ops.emptyMap()); + } + + @Override + public boolean equals(final Object o, final boolean ignoreRecursionPoints, final boolean checkIndex) { + return this == o; + } + + @Override + public TypeTemplate buildTemplate() { + return DSL.constType(this); + } + + @Override + public Pair>> read(final DynamicOps ops, final T input) { + return Pair.of(ops.empty(), Optional.of(new Dynamic<>(ops, input))); + } + + @Override + public final DataResult write(final DynamicOps ops, final T rest, final Dynamic value) { + if (value.getValue() == value.getOps().empty()) { + // nothing to merge, return rest + return DataResult.success(rest); + } + + final T casted = value.cast(ops); + if (rest == ops.empty()) { + // no need to merge anything, return the old value + return DataResult.success(casted); + } + + final Optional>> map = ops.getMapValues(casted); + if (map.isPresent()) { + return ops.mergeInto(rest, map.get().collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); + } + + final Optional> stream = ops.getStream(casted); + if (stream.isPresent()) { + return ops.mergeInto(rest, stream.get().collect(Collectors.toList())); + } + + return DataResult.error("Don't know how to merge " + rest + " and " + casted, rest); + } +} diff --git a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java index 1d1fc564..0dd0be9b 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.constant; +import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; import java.util.Optional; -public final class FloatType extends Const.ConstType { +public final class FloatType extends Const.PrimitiveType { @Override public Pair> read(final DynamicOps ops, final T input) { return ops @@ -18,7 +18,7 @@ public Pair> read(final DynamicOps ops, final T input) } @Override - public T write(final DynamicOps ops, final T rest, final Float value) { + public T doWrite(final DynamicOps ops, final Float value) { return ops.createFloat(value); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/IntType.java b/src/main/java/com/mojang/datafixers/types/constant/IntType.java index 70626fd6..0c72bf0b 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/IntType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/IntType.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.constant; +import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; import java.util.Optional; -public final class IntType extends Const.ConstType { +public final class IntType extends Const.PrimitiveType { @Override public Pair> read(final DynamicOps ops, final T input) { return ops @@ -18,7 +18,7 @@ public Pair> read(final DynamicOps ops, final T inpu } @Override - public T write(final DynamicOps ops, final T rest, final Integer value) { + public T doWrite(final DynamicOps ops, final Integer value) { return ops.createInt(value); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/LongType.java b/src/main/java/com/mojang/datafixers/types/constant/LongType.java index b892f2cf..388343a9 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/LongType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/LongType.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.constant; +import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; import java.util.Optional; -public final class LongType extends Const.ConstType { +public final class LongType extends Const.PrimitiveType { @Override public Pair> read(final DynamicOps ops, final T input) { return ops @@ -18,7 +18,7 @@ public Pair> read(final DynamicOps ops, final T input) } @Override - public T write(final DynamicOps ops, final T rest, final Long value) { + public T doWrite(final DynamicOps ops, final Long value) { return ops.createLong(value); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java index c67ebdf8..e3a40e96 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java @@ -3,13 +3,13 @@ package com.mojang.datafixers.types.constant; import com.google.common.base.Function; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DynamicOps; import java.util.Optional; -public final class NamespacedStringType extends Const.ConstType { +public final class NamespacedStringType extends Const.PrimitiveType { public static Function ENSURE_NAMESPACE = s -> s; @Override @@ -21,7 +21,7 @@ public Pair> read(final DynamicOps ops, final T input } @Override - public T write(final DynamicOps ops, final T rest, final String value) { + public T doWrite(final DynamicOps ops, final String value) { return ops.createString(value); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/NilSave.java b/src/main/java/com/mojang/datafixers/types/constant/NilSave.java deleted file mode 100644 index cbd2b302..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/NilSave.java +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Dynamic; -import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; - -import java.util.Optional; - -public final class NilSave extends Const.ConstType> { - @Override - public Pair>> read(final DynamicOps ops, final T input) { - return Pair.of(ops.empty(), Optional.of(new Dynamic<>(ops, input))); - } - - @SuppressWarnings("unchecked") - @Override - public T write(final DynamicOps ops, final T rest, final Dynamic value) { - return ops.mergeInto(ops.mergeInto(ops.emptyMap(), rest), value.cast(ops)); - } - - @Override - public String toString() { - return "NilSave"; - } - - @Override - public Optional> point(final DynamicOps ops) { - return Optional.of(capEmpty(ops)); - } - - private Dynamic capEmpty(final DynamicOps ops) { - return new Dynamic<>(ops, ops.emptyMap()); - } -} diff --git a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java index 7ee6023e..b643fd89 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.constant; +import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; import java.util.Optional; -public final class ShortType extends Const.ConstType { +public final class ShortType extends Const.PrimitiveType { @Override public Pair> read(final DynamicOps ops, final T input) { return ops @@ -18,7 +18,7 @@ public Pair> read(final DynamicOps ops, final T input) } @Override - public T write(final DynamicOps ops, final T rest, final Short value) { + public T doWrite(final DynamicOps ops, final Short value) { return ops.createShort(value); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/StringType.java b/src/main/java/com/mojang/datafixers/types/constant/StringType.java index ee991f9c..a227231d 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/StringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/StringType.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.constant; +import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.templates.Const; import java.util.Optional; -public final class StringType extends Const.ConstType { +public final class StringType extends Const.PrimitiveType { @Override public Pair> read(final DynamicOps ops, final T input) { return ops @@ -18,7 +18,7 @@ public Pair> read(final DynamicOps ops, final T input } @Override - public T write(final DynamicOps ops, final T rest, final String value) { + public T doWrite(final DynamicOps ops, final String value) { return ops.createString(value); } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Check.java b/src/main/java/com/mojang/datafixers/types/templates/Check.java index b58ee9a0..6267b34f 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Check.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Check.java @@ -11,6 +11,7 @@ import com.mojang.datafixers.TypeRewriteRule; import com.mojang.datafixers.TypedOptic; import com.mojang.datafixers.functions.Functions; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -127,7 +128,7 @@ public Pair> read(final DynamicOps ops, final T input) { } @Override - public T write(final DynamicOps ops, final T rest, final A value) { + public DataResult write(final DynamicOps ops, final T rest, final A value) { return delegate.write(ops, rest, value); } diff --git a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java index a5485ec4..23d69c80 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java +++ b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.reflect.TypeToken; import com.mojang.datafixers.util.Either; @@ -20,6 +21,7 @@ import com.mojang.datafixers.optics.Optic; import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.profunctors.TraversalP; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -177,24 +179,41 @@ public Pair>>> read(final DynamicOps ops, fin return ops.getMapValues(input).map(map -> { final ImmutableList.Builder> builder = ImmutableList.builder(); final ImmutableMap.Builder restBuilder = ImmutableMap.builder(); - for (final Map.Entry entry : map.entrySet()) { - final Pair> keyValue = key.read(ops, entry.getKey()); - final Pair> elementValue = element.read(ops, entry.getValue()); + map.forEach(entry -> { + final Pair> keyValue = key.read(ops, entry.getFirst()); + final Pair> elementValue = element.read(ops, entry.getSecond()); if (keyValue.getSecond().isPresent() && elementValue.getSecond().isPresent()) { builder.add(Pair.of(keyValue.getSecond().get(), elementValue.getSecond().get())); } else { - restBuilder.put(entry); + restBuilder.put(entry.getFirst(), entry.getSecond()); } - } + }); return Pair.of(ops.createMap(restBuilder.build()), Optional.of((List>) builder.build())); }).orElseGet(() -> Pair.of(input, Optional.empty())); } @Override - public T write(final DynamicOps ops, final T rest, final List> value) { - final ImmutableMap.Builder builder = ImmutableMap.builder(); - value.forEach(pair -> builder.put(key.write(ops, ops.empty(), pair.getFirst()), element.write(ops, ops.empty(), pair.getSecond()))); - return ops.merge(rest, ops.createMap(builder.build())); + public DataResult write(final DynamicOps ops, final T rest, final List> value) { + final Map map = Maps.newHashMap(); + + DataResult> result = DataResult.success(map); + + for (final Pair pair : value) { + result = result.flatMap(m -> { + final DataResult element = this.element.write(ops, ops.empty(), pair.getSecond()); + final DataResult> entry = element.flatMap(e -> key.write(ops, ops.empty(), pair.getFirst()).map(k -> Pair.of(k, e))); + return entry.flatMap(e -> { + final T key = e.getFirst(); + if (m.containsKey(key)) { + return DataResult.error("Duplicate key: " + key, m); + } + m.put(key, e.getSecond()); + return DataResult.success(m); + }); + }); + } + + return result.flatMap(m -> ops.mergeInto(rest, m)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Const.java b/src/main/java/com/mojang/datafixers/types/templates/Const.java index 2e0d0b75..639dee7f 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Const.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Const.java @@ -14,6 +14,8 @@ import com.mojang.datafixers.optics.profunctors.Profunctor; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.Objects; @@ -95,7 +97,7 @@ public Type type() { return type; } - public abstract static class ConstType extends Type { + public abstract static class PrimitiveType extends Type { @Override public boolean equals(final Object o, final boolean ignoreRecursionPoints, final boolean checkIndex) { return this == o; @@ -105,5 +107,15 @@ public boolean equals(final Object o, final boolean ignoreRecursionPoints, final public TypeTemplate buildTemplate() { return DSL.constType(this); } + + @Override + public final DataResult write(final DynamicOps ops, final T rest, final A value) { + if (rest != ops.empty()) { + return DataResult.error("Do not know how to append a primitive value " + value + " to " + rest, doWrite(ops, value)); + } + return DataResult.success(doWrite(ops, value)); + } + + protected abstract T doWrite(final DynamicOps ops, final A value); } } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Hook.java b/src/main/java/com/mojang/datafixers/types/templates/Hook.java index bca59b22..03ac9d88 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Hook.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Hook.java @@ -10,6 +10,7 @@ import com.mojang.datafixers.TypeRewriteRule; import com.mojang.datafixers.TypedOptic; import com.mojang.datafixers.functions.Functions; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -113,8 +114,8 @@ public Pair> read(final DynamicOps ops, final T input) { } @Override - public T write(final DynamicOps ops, final T rest, final A value) { - return postWrite.apply(ops, delegate.write(ops, rest, value)); + public DataResult write(final DynamicOps ops, final T rest, final A value) { + return delegate.write(ops, rest, value).map(v -> postWrite.apply(ops, v)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/List.java b/src/main/java/com/mojang/datafixers/types/templates/List.java index a03dc1ed..9d113cc2 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/List.java +++ b/src/main/java/com/mojang/datafixers/types/templates/List.java @@ -17,12 +17,14 @@ import com.mojang.datafixers.optics.ListTraversal; import com.mojang.datafixers.optics.Optic; import com.mojang.datafixers.optics.profunctors.TraversalP; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -168,9 +170,25 @@ public Pair>> read(final DynamicOps ops, fi }).orElseGet(() -> Pair.of(input, Optional.empty())); } + /** + * Will write `ops.empty()` value into the partial result if the element failed to serialize + */ @Override - public T write(final DynamicOps ops, final T rest, final java.util.List value) { - return ops.merge(rest, ops.createList(value.stream().map(a -> element.write(ops, ops.empty(), a)))); + public DataResult write(final DynamicOps ops, final T rest, final java.util.List value) { + final java.util.List list = new ArrayList<>(value.size()); + DataResult> result = DataResult.success(list); + + for (final A a : value) { + result = result.flatMap(t -> { + final DataResult written = element.write(ops, ops.empty(), a); + return written.map(e -> { + list.add(e); + return list; + }); + }); + } + + return result.flatMap(l -> ops.mergeInto(rest, l)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Named.java b/src/main/java/com/mojang/datafixers/types/templates/Named.java index f650413d..8cf74d75 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Named.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Named.java @@ -15,6 +15,7 @@ import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.profunctors.Cartesian; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -143,9 +144,9 @@ public Pair>> read(final DynamicOps ops, fina } @Override - public T write(final DynamicOps ops, final T rest, final Pair value) { + public DataResult write(final DynamicOps ops, final T rest, final Pair value) { if (!Objects.equals(value.getFirst(), name)) { - throw new IllegalStateException("Named type name doesn't match: expected: " + name + ", got: " + value.getFirst()); + return DataResult.error("Named type name doesn't match: expected: " + name + ", got: " + value.getFirst(), rest); } return element.write(ops, rest, value.getSecond()); } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Product.java b/src/main/java/com/mojang/datafixers/types/templates/Product.java index dfd545d6..79ffad26 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Product.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Product.java @@ -21,6 +21,7 @@ import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.Traversal; import com.mojang.datafixers.optics.profunctors.TraversalP; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -223,8 +224,8 @@ public Pair>> read(final DynamicOps ops, final T i } @Override - public T write(final DynamicOps ops, final T rest, final Pair value) { - return second.write(ops, first.write(ops, rest, value.getFirst()), value.getSecond()); + public DataResult write(final DynamicOps ops, final T rest, final Pair value) { + return first.write(ops, rest, value.getFirst()).flatMap(f -> second.write(ops, f, value.getSecond())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java index 4734609e..1d35d7db 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java +++ b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java @@ -12,6 +12,7 @@ import com.mojang.datafixers.View; import com.mojang.datafixers.functions.Functions; import com.mojang.datafixers.functions.PointFreeRule; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -142,7 +143,7 @@ public Pair> read(final DynamicOps ops, final T input) { } @Override - public T write(final DynamicOps ops, final T rest, final A value) { + public DataResult write(final DynamicOps ops, final T rest, final A value) { return unfold().write(ops, rest, value); } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Sum.java b/src/main/java/com/mojang/datafixers/types/templates/Sum.java index b0dbaa3e..dc756d37 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Sum.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Sum.java @@ -20,6 +20,7 @@ import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.Traversal; import com.mojang.datafixers.optics.profunctors.TraversalP; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -220,7 +221,7 @@ public Pair>> read(final DynamicOps ops, final T } @Override - public T write(final DynamicOps ops, final T rest, final Either value) { + public DataResult write(final DynamicOps ops, final T rest, final Either value) { return value.map( value1 -> first.write(ops, rest, value1), value2 -> second.write(ops, rest, value2) diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index da1df179..41190983 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -11,6 +11,7 @@ import com.mojang.datafixers.TypedOptic; import com.mojang.datafixers.View; import com.mojang.datafixers.functions.Functions; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -173,7 +174,7 @@ public TypeTemplate buildTemplate() { @Override public Pair> read(final DynamicOps ops, final T input) { - final Optional> map = ops.getMapValues(input); + final Optional> map = ops.getMapValues(input).map(s -> s.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); final T nameObject = ops.createString(name); final T elementValue; if (map.isPresent() && (elementValue = map.get().get(nameObject)) != null) { @@ -186,8 +187,8 @@ public Pair> read(final DynamicOps ops, final T input) { } @Override - public T write(final DynamicOps ops, final T rest, final A value) { - return ops.mergeInto(rest, ops.createString(name), element.write(ops, ops.empty(), value)); + public DataResult write(final DynamicOps ops, final T rest, final A value) { + return element.write(ops, ops.empty(), value).flatMap(result -> ops.mergeInto(rest, ops.createString(name), result)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index fe5d8efc..503aa5ba 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -29,6 +29,7 @@ import com.mojang.datafixers.optics.profunctors.AffineP; import com.mojang.datafixers.optics.profunctors.Cartesian; import com.mojang.datafixers.optics.profunctors.TraversalP; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; @@ -185,45 +186,49 @@ public TypeTemplate buildTemplate() { @Override public Pair>> read(final DynamicOps ops, final T input) { - final Optional> values = ops.getMapValues(input); - if (values.isPresent()) { - final Map map = values.get(); - final T nameObject = ops.createString(name); - final T mapValue = map.get(nameObject); - if (mapValue != null) { - final Optional key = keyType.read(ops, mapValue).getSecond(); - //noinspection OptionalIsPresent - final K keyValue = key.isPresent() ? key.get() : null; - final Type type = keyValue != null ? types.get(keyValue) : null; - if (type == null) { - if (DataFixerUpper.ERRORS_ARE_FATAL) { - throw new IllegalArgumentException("Unsupported key: " + keyValue + " in " + this); - } else { - LOGGER.warn("Unsupported key: {} in {}", keyValue, this); - return Pair.of(input, Optional.empty()); - } - } + final Optional> values = ops.getMapValues(input).map(s -> s.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); + if (!values.isPresent()) { + return Pair.of(input, Optional.empty()); + } - return type.read(ops, input).mapSecond(vo -> vo.map(v -> Pair.of(keyValue, v))); - } + final Map map = values.get(); + final T nameObject = ops.createString(name); + final T mapValue = map.get(nameObject); + if (mapValue == null) { + return Pair.of(input, Optional.empty()); + } + + final Optional key = keyType.read(ops, mapValue).getSecond(); + final K keyValue = key.orElse(null); + final Type type = keyValue != null ? types.get(keyValue) : null; + if (type != null) { + return type.read(ops, input).mapSecond(vo -> vo.map(v -> Pair.of(keyValue, v))); + } + + if (DataFixerUpper.ERRORS_ARE_FATAL) { + throw new IllegalArgumentException("Unsupported key: " + keyValue + " in " + this); + } else { + LOGGER.warn("Unsupported key: {} in {}", keyValue, this); + return Pair.of(input, Optional.empty()); } - return Pair.of(input, Optional.empty()); } @Override - public T write(final DynamicOps ops, final T rest, final Pair value) { + public DataResult write(final DynamicOps ops, final T rest, final Pair value) { final Type type = types.get(value.getFirst()); if (type == null) { - // TODO: better error handling? - // TODO: See todo in read method - throw new IllegalArgumentException("Unsupported key: " + value.getFirst() + " in " + this); + return DataResult.error("Unsupported key: " + value.getFirst() + " in " + this, rest); } return capWrite(ops, type, value.getFirst(), value.getSecond(), rest); } @SuppressWarnings("unchecked") - private T capWrite(final DynamicOps ops, final Type type, final K key, final Object value, final T rest) { - return ops.mergeInto(type.write(ops, rest, (A) value), ops.createString(name), keyType.write(ops, ops.empty(), key)); + private DataResult capWrite(final DynamicOps ops, final Type type, final K key, final Object value, final T rest) { + return keyType.write(ops, ops.empty(), key).flatMap(k -> + type.write(ops, rest, (A) value).flatMap(v -> + ops.mergeInto(v, ops.createString(name), k) + ) + ); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/TypeTemplate.java b/src/main/java/com/mojang/datafixers/types/templates/TypeTemplate.java index f6e2f3a5..61671c5a 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TypeTemplate.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TypeTemplate.java @@ -21,7 +21,7 @@ default Type toSimpleType() { return apply(new TypeFamily() { @Override public Type apply(final int index) { - return DSL.nilType(); + return DSL.emptyPartType(); } /*@Override diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java new file mode 100644 index 00000000..c0e7c012 --- /dev/null +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +import com.mojang.datafixers.util.Either; + +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; + +public class DataResult { + private final Either> result; + + public static DataResult success(final R result) { + return new DataResult<>(Either.left(result)); + } + + public static DataResult error(final String message, final R partialResult) { + return new DataResult<>(Either.right(new DynamicException<>(message, Optional.of(partialResult)))); + } + + public static DataResult error(final String message) { + return new DataResult<>(Either.right(new DynamicException<>(message, Optional.empty()))); + } + + public static DataResult create(final Either> result) { + return new DataResult<>(result); + } + + private DataResult(final Either> result) { + this.result = result; + } + + public Either> get() { + return result; + } + + public Optional result() { + return result.left(); + } + + public T resultOrPartial(final Function onSuccess, final BiFunction, T> onFailure) { + return result.map( + onSuccess, + r -> onFailure.apply(r.message, r.partialResult) + ); + } + + public Optional resultOrPartial(final Consumer onError) { + return result.map( + Optional::of, + r -> { + onError.accept(r.message); + return r.partialResult; + } + ); + } + + public Optional> error() { + return result.right(); + } + + public DataResult map(final Function function) { + return create(result.mapBoth( + function, + r -> new DynamicException<>(r.message, r.partialResult.map(function)) + )); + } + + /** + * Applies the function to either full or partial result, in case of partial concatenates errors. + */ + public DataResult flatMap(final Function> function) { + return create(result.map( + l -> function.apply(l).get(), + r -> Either.right(r.partialResult + .map(value -> function.apply(value).get().map( + l2 -> new DynamicException<>(r.message, Optional.of(l2)), + r2 -> new DynamicException<>(r.message + "; " + r2.message, r2.partialResult) + )) + .orElseGet( + () -> new DynamicException<>(r.message, Optional.empty()) + ) + ) + )); + } + + public static class DynamicException { + private final String message; + private final Optional partialResult; + + public DynamicException(final String message, final Optional partialResult) { + this.message = message; + this.partialResult = partialResult; + } + + public RuntimeException error() { + return new RuntimeException(message); + } + + public DynamicException map(final Function function) { + return new DynamicException<>(message, partialResult.map(function)); + } + + public DynamicException flatMap(final Function> function) { + if (partialResult.isPresent()) { + final DynamicException result = function.apply(partialResult.get()); + return new DynamicException<>(message + "; " + result.message, result.partialResult); + } + return new DynamicException<>(message, Optional.empty()); + } + + public String message() { + return message; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index a92ab0fa..e2f48767 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -53,20 +53,20 @@ public U cast(final DynamicOps ops) { return castTyped(ops).getValue(); } - public Dynamic merge(final Dynamic value) { - return map(v -> ops.mergeInto(v, value.cast(ops))); + public OptionalDynamic merge(final Dynamic value) { + final DataResult merged = ops.mergeInto(this.value, value.cast(ops)); + return new OptionalDynamic<>(ops, merged.map(m -> new Dynamic<>(ops, m))); } - public Dynamic merge(final Dynamic key, final Dynamic value) { - return map(v -> ops.mergeInto(v, key.cast(ops), value.cast(ops))); + public OptionalDynamic merge(final Dynamic key, final Dynamic value) { + final DataResult merged = ops.mergeInto(this.value, key.cast(ops), value.cast(ops)); + return new OptionalDynamic<>(ops, merged.map(m -> new Dynamic<>(ops, m))); } public Optional, Dynamic>> getMapValues() { return ops.getMapValues(value).map(map -> { final ImmutableMap.Builder, Dynamic> builder = ImmutableMap.builder(); - for (final Map.Entry entry : map.entrySet()) { - builder.put(new Dynamic<>(ops, entry.getKey()), new Dynamic<>(ops, entry.getValue())); - } + map.forEach(entry -> builder.put(new Dynamic<>(ops, entry.getFirst()), new Dynamic<>(ops, entry.getSecond()))); return builder.build(); }); } @@ -110,7 +110,16 @@ public Optional asLongStreamOpt() { @Override public OptionalDynamic get(final String key) { - return new OptionalDynamic<>(ops, ops.get(value, key).map(v -> new Dynamic<>(ops, v))); + final Optional>> map = ops.getMapValues(value); + if (!map.isPresent()) { + return new OptionalDynamic<>(ops, DataResult.error("not a map: " + value)); + } + final T keyString = ops.createString(key); + final Optional value = map.get().filter(p -> Objects.equals(keyString, p.getFirst())).map(Pair::getSecond).findFirst(); + if (!value.isPresent()) { + return new OptionalDynamic<>(ops, DataResult.error("key missing: " + key + " in " + this.value)); + } + return new OptionalDynamic(ops, DataResult.success(new Dynamic<>(ops, value.get()))); } @Override @@ -141,7 +150,7 @@ public Optional getElement(final String key) { @Override public Optional getElementGeneric(final T key) { - return ops.getMapValues(value).flatMap(m -> Optional.ofNullable(m.get(key))); + return ops.getGeneric(value, key); } @Override @@ -153,9 +162,9 @@ public Optional> asListOpt(final Function, U> deserialize public Optional> asMapOpt(final Function, K> keyDeserializer, final Function, V> valueDeserializer) { return ops.getMapValues(value).map(map -> { final ImmutableMap.Builder builder = ImmutableMap.builder(); - for (final Map.Entry entry : map.entrySet()) { - builder.put(keyDeserializer.apply(new Dynamic<>(ops, entry.getKey())), valueDeserializer.apply(new Dynamic<>(ops, entry.getValue()))); - } + map.forEach(entry -> + builder.put(keyDeserializer.apply(new Dynamic<>(ops, entry.getFirst())), valueDeserializer.apply(new Dynamic<>(ops, entry.getSecond()))) + ); return builder.build(); }); } @@ -196,7 +205,7 @@ public static T convert(final DynamicOps inOps, final DynamicOps ou return (T) input; } final Type type = inOps.getType(input); - if (Objects.equals(type, DSL.nilType())) { + if (Objects.equals(type, DSL.emptyPartType())) { return outOps.empty(); } if (Objects.equals(type, DSL.byteType())) { @@ -236,8 +245,8 @@ public static T convert(final DynamicOps inOps, final DynamicOps ou return outOps.createList(inOps.getStream(input).orElse(Stream.empty()).map(e -> convert(inOps, outOps, e))); } if (Objects.equals(type, DSL.compoundList(DSL.remainderType(), DSL.remainderType()))) { - return outOps.createMap(inOps.getMapValues(input).orElse(ImmutableMap.of()).entrySet().stream().map(e -> - Pair.of(convert(inOps, outOps, e.getKey()), convert(inOps, outOps, e.getValue())) + return outOps.createMap(inOps.getMapValues(input).orElse(Stream.empty()).map(e -> + Pair.of(convert(inOps, outOps, e.getFirst()), convert(inOps, outOps, e.getSecond())) ).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); } throw new IllegalStateException("Could not convert value of type " + type); diff --git a/src/main/java/com/mojang/serialization/DynamicLike.java b/src/main/java/com/mojang/serialization/DynamicLike.java index 30a03d1b..4277c9fd 100644 --- a/src/main/java/com/mojang/serialization/DynamicLike.java +++ b/src/main/java/com/mojang/serialization/DynamicLike.java @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. package com.mojang.serialization; import com.google.common.collect.ImmutableList; diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index dcda8209..66fe0f38 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -4,10 +4,13 @@ import com.google.common.collect.ImmutableMap; import com.mojang.datafixers.types.Type; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -80,21 +83,36 @@ default T createBoolean(final boolean value) { T createString(String value); /** - * keeps input unchanged if it's not list-like + * Only successful if first argument is a list/array + * @return */ - T mergeInto(T input, T value); + DataResult mergeInto(T list, T value); - /** - * keeps input unchanged if it's not map-like - */ - T mergeInto(T input, T key, T value); + default DataResult mergeInto(final T list, final List values) { + DataResult result = DataResult.success(list); + + for (final T value : values) { + result = result.flatMap(r -> mergeInto(r, value)); + } + return result; + } /** - * merges 2 values together, if possible (list + list, map + map, empty + anything) + * Only successful if first argument is a map + * @return */ - T merge(T first, T second); + DataResult mergeInto(T map, T key, T value); + + default DataResult mergeInto(final T map, final Map values) { + DataResult result = DataResult.success(map); + + for (final Map.Entry entry : values.entrySet()) { + result = result.flatMap(r -> mergeInto(r, entry.getKey(), entry.getValue())); + } + return result; + } - Optional> getMapValues(T input); + Optional>> getMapValues(T input); T createMap(Map map); @@ -156,18 +174,20 @@ default Optional get(final T input, final String key) { } default Optional getGeneric(final T input, final T key) { - return getMapValues(input).flatMap(map -> Optional.ofNullable(map.get(key))); + return getMapValues(input).flatMap(map -> map.filter(p -> Objects.equals(key, p.getFirst())).map(Pair::getSecond).findFirst()); } + // TODO: eats error if input is not a map default T set(final T input, final String key, final T value) { - return mergeInto(input, createString(key), value); + return mergeInto(input, createString(key), value).result().orElse(input); } + // TODO: eats error if input is not a map default T update(final T input, final String key, final Function function) { return get(input, key).map(value -> set(input, key, function.apply(value))).orElse(input); } default T updateGeneric(final T input, final T key, final Function function) { - return getGeneric(input, key).map(value -> mergeInto(input, key, function.apply(value))).orElse(input); + return getGeneric(input, key).flatMap(value -> mergeInto(input, key, function.apply(value)).result()).orElse(input); } } diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 88113383..08459a8d 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -2,6 +2,7 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.google.common.collect.Lists; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; @@ -12,10 +13,10 @@ import com.mojang.datafixers.util.Pair; import java.math.BigDecimal; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -39,7 +40,7 @@ public Type getType(final JsonElement input) { return DSL.list(DSL.remainderType()); } if (input.isJsonNull()) { - return DSL.nilType(); + return DSL.emptyPartType(); } final JsonPrimitive primitive = input.getAsJsonPrimitive(); if (primitive.isString()) { @@ -118,79 +119,77 @@ public JsonElement createString(final String value) { } @Override - public JsonElement mergeInto(final JsonElement input, final JsonElement value) { - final JsonArray result; - if (value.isJsonNull()) { - return input; - } - if (input.isJsonObject()) { - if (value.isJsonObject()) { - final JsonObject resultObject = new JsonObject(); - final JsonObject first = input.getAsJsonObject(); - for (final Map.Entry entry : first.entrySet()) { - resultObject.add(entry.getKey(), entry.getValue()); - } - final JsonObject second = value.getAsJsonObject(); - for (final Map.Entry entry : second.entrySet()) { - resultObject.add(entry.getKey(), entry.getValue()); - } - return resultObject; - } - return input; - } else if (input.isJsonNull()) { - throw new IllegalArgumentException("mergeInto called with null input."); - } else if (input.isJsonArray()) { - result = new JsonArray(); - StreamSupport.stream(input.getAsJsonArray().spliterator(), false).forEach(result::add); - } else { - return input; + public DataResult mergeInto(final JsonElement list, final JsonElement value) { + if (!list.isJsonArray()) { + return DataResult.error("mergeInto called with not a list: " + list, list); } + + final JsonArray result = new JsonArray(); + result.addAll(list.getAsJsonArray()); result.add(value); - return result; + return DataResult.success(result); } @Override - public JsonElement mergeInto(final JsonElement input, final JsonElement key, final JsonElement value) { - final JsonObject output; - if (input.isJsonNull()) { - output = new JsonObject(); - } else if (input.isJsonObject()) { - output = new JsonObject(); - input.getAsJsonObject().entrySet().forEach(entry -> output.add(entry.getKey(), entry.getValue())); - } else { - return input; + public DataResult mergeInto(final JsonElement list, final List values) { + if (!list.isJsonArray()) { + return DataResult.error("mergeInto called with not a list: " + list, list); } - output.add(key.getAsString(), value); - return output; + + final JsonArray result = new JsonArray(); + result.addAll(list.getAsJsonArray()); + values.forEach(result::add); + return DataResult.success(result); } @Override - public JsonElement merge(final JsonElement first, final JsonElement second) { - if (first.isJsonNull()) { - return second; + public DataResult mergeInto(final JsonElement map, final JsonElement key, final JsonElement value) { + if (!map.isJsonObject()) { + return DataResult.error("mergeInto called with not a map: " + map, map); } - if (second.isJsonNull()) { - return first; + if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString()) { + return DataResult.error("key is not a string: " + key, map); } - if (first.isJsonObject() && second.isJsonObject()) { - JsonObject result = new JsonObject(); - first.getAsJsonObject().entrySet().forEach(entry -> result.add(entry.getKey(), entry.getValue())); - second.getAsJsonObject().entrySet().forEach(entry -> result.add(entry.getKey(), entry.getValue())); - return result; + + final JsonObject output = new JsonObject(); + map.getAsJsonObject().entrySet().forEach(entry -> output.add(entry.getKey(), entry.getValue())); + output.add(key.getAsString(), value); + + return DataResult.success(output); + } + + @Override + public DataResult mergeInto(final JsonElement map, final Map values) { + if (!map.isJsonObject()) { + return DataResult.error("mergeInto called with not a map: " + map, map); } - if (first.isJsonArray() && second.isJsonArray()) { - JsonArray result = new JsonArray(); - first.getAsJsonArray().forEach(result::add); - second.getAsJsonArray().forEach(result::add); - return result; + + final JsonObject output = new JsonObject(); + map.getAsJsonObject().entrySet().forEach(entry -> output.add(entry.getKey(), entry.getValue())); + + final List missed = Lists.newArrayList(); + + for (final Map.Entry entry : values.entrySet()) { + final JsonElement key = entry.getKey(); + if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString()) { + missed.add(key); + continue; + } + + output.add(key.getAsString(), entry.getValue()); } - throw new IllegalArgumentException("Could not merge " + first + " and " + second); + + if (!missed.isEmpty()) { + return DataResult.error("some keys are not strings: " + missed, output); + } + + return DataResult.success(output); } @Override - public Optional> getMapValues(final JsonElement input) { + public Optional>> getMapValues(final JsonElement input) { if (input.isJsonObject()) { - return Optional.of(input.getAsJsonObject().entrySet().stream().map(entry -> Pair.of(new JsonPrimitive(entry.getKey()), entry.getValue())).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); + return Optional.of(input.getAsJsonObject().entrySet().stream().map(entry -> Pair.of(new JsonPrimitive(entry.getKey()), entry.getValue()))); } return Optional.empty(); } diff --git a/src/main/java/com/mojang/serialization/OptionalDynamic.java b/src/main/java/com/mojang/serialization/OptionalDynamic.java index abb18b95..4c362446 100644 --- a/src/main/java/com/mojang/serialization/OptionalDynamic.java +++ b/src/main/java/com/mojang/serialization/OptionalDynamic.java @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. package com.mojang.serialization; import java.nio.ByteBuffer; @@ -11,23 +13,23 @@ @SuppressWarnings("unused") public final class OptionalDynamic extends DynamicLike { - private final Optional> delegate; + private final DataResult> delegate; - public OptionalDynamic(final DynamicOps ops, final Optional> delegate) { + public OptionalDynamic(final DynamicOps ops, final DataResult> delegate) { super(ops); this.delegate = delegate; } - public Optional> get() { - return delegate; + public Optional> result() { + return delegate.result(); } - public Optional map(Function, ? extends U> mapper) { + public DataResult map(final Function, U> mapper) { return delegate.map(mapper); } - public Optional flatMap(Function, Optional> mapper) { - return delegate.flatMap(mapper); + public Optional flatMap(final Function, Optional> mapper) { + return result().flatMap(mapper); } @Override @@ -62,7 +64,7 @@ public Optional asLongStreamOpt() { @Override public OptionalDynamic get(final String key) { - return new OptionalDynamic<>(ops, flatMap(k -> k.get(key).get())); + return new OptionalDynamic<>(ops, delegate.flatMap(k -> k.get(key).delegate)); } @Override @@ -91,14 +93,14 @@ public Optional> asMapOpt(final Function, K> keyDese } public Dynamic orElseEmptyMap() { - return delegate.orElseGet(this::emptyMap); + return result().orElseGet(this::emptyMap); } public Dynamic orElseEmptyList() { - return delegate.orElseGet(this::emptyList); + return result().orElseGet(this::emptyList); } public Optional into(final Function, ? extends V> action) { - return get().map(action); + return result().map(action); } } From 1701c4393767cea3d6d3bfa001e5109127b4b18b Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 10 Mar 2020 12:46:37 +0100 Subject: [PATCH 05/96] Replaced read with a version that returns DataResult. --- .../java/com/mojang/datafixers/DataFix.java | 10 ++-- .../com/mojang/datafixers/types/Func.java | 5 +- .../com/mojang/datafixers/types/Type.java | 27 +++++----- .../datafixers/types/constant/BoolType.java | 9 ++-- .../datafixers/types/constant/ByteType.java | 9 ++-- .../datafixers/types/constant/DoubleType.java | 9 ++-- .../datafixers/types/constant/EmptyPart.java | 4 +- .../types/constant/EmptyPartSaving.java | 4 +- .../datafixers/types/constant/FloatType.java | 9 ++-- .../datafixers/types/constant/IntType.java | 9 ++-- .../datafixers/types/constant/LongType.java | 9 ++-- .../types/constant/NamespacedStringType.java | 10 ++-- .../datafixers/types/constant/ShortType.java | 9 ++-- .../datafixers/types/constant/StringType.java | 9 ++-- .../datafixers/types/templates/Check.java | 4 +- .../types/templates/CompoundList.java | 35 ++++++++----- .../datafixers/types/templates/Hook.java | 2 +- .../datafixers/types/templates/List.java | 28 ++++++++--- .../datafixers/types/templates/Named.java | 4 +- .../datafixers/types/templates/Product.java | 15 +++--- .../types/templates/RecursivePoint.java | 2 +- .../datafixers/types/templates/Sum.java | 8 +-- .../datafixers/types/templates/Tag.java | 29 +++++++---- .../types/templates/TaggedChoice.java | 50 ++++++++----------- .../com/mojang/serialization/DynamicOps.java | 8 --- 25 files changed, 160 insertions(+), 157 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/DataFix.java b/src/main/java/com/mojang/datafixers/DataFix.java index 77a5416c..6bb9bc13 100644 --- a/src/main/java/com/mojang/datafixers/DataFix.java +++ b/src/main/java/com/mojang/datafixers/DataFix.java @@ -3,6 +3,7 @@ package com.mojang.datafixers; import com.mojang.datafixers.schemas.Schema; +import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; @@ -46,10 +47,13 @@ protected TypeRewriteRule writeFixAndRead(final String name, final Type input -> { final Optional> written = type.writeDynamic(ops, input).resultOrPartial(LOGGER::error); if (!written.isPresent()) { - throw new RuntimeException("Could not write the object"); + throw new RuntimeException("Could not write the object in " + name); } - final Optional> read = newType.readTyped(fix.apply(written.get())).getSecond(); - return read.orElseThrow(() -> new IllegalStateException("Could not read new type in \"" + name + "\"")).getValue(); + final Optional, ?>> read = newType.readTyped(fix.apply(written.get())).resultOrPartial(LOGGER::error); + if (!read.isPresent()) { + throw new RuntimeException("Could not read the new object in " + name); + } + return read.get().getFirst().getValue(); }); } diff --git a/src/main/java/com/mojang/datafixers/types/Func.java b/src/main/java/com/mojang/datafixers/types/Func.java index b367d90a..7bf2a4f4 100644 --- a/src/main/java/com/mojang/datafixers/types/Func.java +++ b/src/main/java/com/mojang/datafixers/types/Func.java @@ -8,7 +8,6 @@ import com.mojang.serialization.DynamicOps; import java.util.Objects; -import java.util.Optional; import java.util.function.Function; public final class Func extends Type> { @@ -26,8 +25,8 @@ public TypeTemplate buildTemplate() { } @Override - public Pair>> read(final DynamicOps ops, final T input) { - return Pair.of(input, Optional.empty()); + public DataResult, T>> read(final DynamicOps ops, final T input) { + return DataResult.error("Cannot read a function"); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/Type.java b/src/main/java/com/mojang/datafixers/types/Type.java index 145e8c24..a35a0797 100644 --- a/src/main/java/com/mojang/datafixers/types/Type.java +++ b/src/main/java/com/mojang/datafixers/types/Type.java @@ -108,11 +108,11 @@ public Optional> findCheckedType(final int index) { return Optional.empty(); } - public final Pair, Optional> read(final Dynamic input) { - return read(input.getOps(), input.getValue()).mapFirst(v -> new Dynamic<>(input.getOps(), v)); + public final DataResult>> read(final Dynamic input) { + return read(input.getOps(), input.getValue()).map(v -> v.mapSecond(t -> new Dynamic(input.getOps(), t))); } - public abstract Pair> read(final DynamicOps ops, final T input); + public abstract DataResult> read(final DynamicOps ops, final T input); public abstract DataResult write(final DynamicOps ops, final T rest, final A value); @@ -124,16 +124,16 @@ public final DataResult> writeDynamic(final DynamicOps ops, fi return write(ops, value).map(result -> new Dynamic<>(ops, result)); } - public Pair>> readTyped(final Dynamic input) { + public DataResult, T>> readTyped(final Dynamic input) { return readTyped(input.getOps(), input.getValue()); } - public Pair>> readTyped(final DynamicOps ops, final T input) { - return read(ops, input).mapSecond(vo -> vo.map(v -> new Typed<>(this, ops, v))); + public DataResult, T>> readTyped(final DynamicOps ops, final T input) { + return read(ops, input).map(vo -> vo.mapFirst(v -> new Typed<>(this, ops, v))); } - public Pair> read(final DynamicOps ops, final TypeRewriteRule rule, final PointFreeRule fRule, final T input) { - return read(ops, input).mapSecond(vo -> vo.map(v -> + public DataResult, T>> read(final DynamicOps ops, final TypeRewriteRule rule, final PointFreeRule fRule, final T input) { + return read(ops, input).map(vo -> vo.mapFirst(v -> rewrite(rule, fRule).map(r -> r.view().function().evalCached().apply(ops).apply(v) ) )); @@ -146,17 +146,14 @@ public DataResult readAndWrite(final DynamicOps ops, final Type exp } final View view = rewriteResult.get().view(); - final Pair> po = read(ops, input); - if (!po.getSecond().isPresent()) { - return DataResult.error("Could not parse input: " + input + " ", input); - } - - return capWrite(ops, expectedType, po.getFirst(), po.getSecond().get(), view); + return read(ops, input).flatMap(pair -> + capWrite(ops, expectedType, pair.getSecond(), pair.getFirst(), view) + ); } private DataResult capWrite(final DynamicOps ops, final Type expectedType, final T rest, final A value, final View f) { if (!expectedType.equals(f.newType(), true, true)) { - throw new IllegalStateException("Rewritten type doesn't match."); + return DataResult.error("Rewritten type doesn't match"); } return f.newType().write(ops, rest, f.function().evalCached().apply(ops).apply(value)); } diff --git a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java index 3ed73d04..80e1eb39 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java @@ -4,17 +4,16 @@ import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import java.util.Optional; - public final class BoolType extends Const.PrimitiveType { @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(ops.empty(), Optional.of(v.intValue() != 0))) - .orElseGet(() -> Pair.of(input, Optional.empty())); + .map(v -> DataResult.success(Pair.of(v.intValue() != 0, ops.empty()))) + .orElseGet(() -> DataResult.error("Input is not a number: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java index 48813bcd..08dfdbfe 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java @@ -4,17 +4,16 @@ import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import java.util.Optional; - public final class ByteType extends Const.PrimitiveType { @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(ops.empty(), Optional.of(v.byteValue()))) - .orElseGet(() -> Pair.of(input, Optional.empty())); + .map(v -> DataResult.success(Pair.of(v.byteValue(), ops.empty()))) + .orElseGet(() -> DataResult.error("Input is not a number: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java index ddcdd995..2e7dd022 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java @@ -4,17 +4,16 @@ import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import java.util.Optional; - public final class DoubleType extends Const.PrimitiveType { @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(ops.empty(), Optional.of(v.doubleValue()))) - .orElseGet(() -> Pair.of(input, Optional.empty())); + .map(v -> DataResult.success(Pair.of(v.doubleValue(), ops.empty()))) + .orElseGet(() -> DataResult.error("Input is not a number: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java index c4c03c74..14afb8c1 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java @@ -33,8 +33,8 @@ public TypeTemplate buildTemplate() { } @Override - public Pair> read(final DynamicOps ops, final T input) { - return Pair.of(input, point(ops)); + public DataResult> read(final DynamicOps ops, final T input) { + return DataResult.success(Pair.of(Unit.INSTANCE, input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java index 8d5d0e41..1993a5aa 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -39,8 +39,8 @@ public TypeTemplate buildTemplate() { } @Override - public Pair>> read(final DynamicOps ops, final T input) { - return Pair.of(ops.empty(), Optional.of(new Dynamic<>(ops, input))); + public DataResult, T>> read(final DynamicOps ops, final T input) { + return DataResult.success(Pair.of(new Dynamic<>(ops, input), ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java index 0dd0be9b..ebc7f4be 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java @@ -4,17 +4,16 @@ import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import java.util.Optional; - public final class FloatType extends Const.PrimitiveType { @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(ops.empty(), Optional.of(v.floatValue()))) - .orElseGet(() -> Pair.of(input, Optional.empty())); + .map(v -> DataResult.success(Pair.of(v.floatValue(), ops.empty()))) + .orElseGet(() -> DataResult.error("Input is not a number: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/IntType.java b/src/main/java/com/mojang/datafixers/types/constant/IntType.java index 0c72bf0b..18b75bc5 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/IntType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/IntType.java @@ -4,17 +4,16 @@ import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import java.util.Optional; - public final class IntType extends Const.PrimitiveType { @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(ops.empty(), Optional.of(v.intValue()))) - .orElseGet(() -> Pair.of(input, Optional.empty())); + .map(v -> DataResult.success(Pair.of(v.intValue(), ops.empty()))) + .orElseGet(() -> DataResult.error("Input is not a number: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/LongType.java b/src/main/java/com/mojang/datafixers/types/constant/LongType.java index 388343a9..79f3729c 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/LongType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/LongType.java @@ -4,17 +4,16 @@ import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import java.util.Optional; - public final class LongType extends Const.PrimitiveType { @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(ops.empty(), Optional.of(v.longValue()))) - .orElseGet(() -> Pair.of(input, Optional.empty())); + .map(v -> DataResult.success(Pair.of(v.longValue(), ops.empty()))) + .orElseGet(() -> DataResult.error("Input is not a number: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java index e3a40e96..7f668159 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java @@ -5,19 +5,19 @@ import com.google.common.base.Function; import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import java.util.Optional; - +// FIXME: move out of this project? public final class NamespacedStringType extends Const.PrimitiveType { public static Function ENSURE_NAMESPACE = s -> s; @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return ops .getStringValue(input) - .map(v -> Pair.of(ops.empty(), Optional.of(ENSURE_NAMESPACE.apply(v)))) - .orElseGet(() -> Pair.of(input, Optional.empty())); + .map(v -> DataResult.success(Pair.of(ENSURE_NAMESPACE.apply(v), ops.empty()))) + .orElseGet(() -> DataResult.error("Input is not a string: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java index b643fd89..58c59365 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java @@ -4,17 +4,16 @@ import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import java.util.Optional; - public final class ShortType extends Const.PrimitiveType { @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(ops.empty(), Optional.of(v.shortValue()))) - .orElseGet(() -> Pair.of(input, Optional.empty())); + .map(v -> DataResult.success(Pair.of(v.shortValue(), ops.empty()))) + .orElseGet(() -> DataResult.error("Input is not a number: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/StringType.java b/src/main/java/com/mojang/datafixers/types/constant/StringType.java index a227231d..7d93fec5 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/StringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/StringType.java @@ -4,17 +4,16 @@ import com.mojang.datafixers.types.templates.Const; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import java.util.Optional; - public final class StringType extends Const.PrimitiveType { @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return ops .getStringValue(input) - .map(v -> Pair.of(ops.empty(), Optional.of(v))) - .orElseGet(() -> Pair.of(input, Optional.empty())); + .map(v -> DataResult.success(Pair.of(v, ops.empty()))) + .orElseGet(() -> DataResult.error("Input is not a string: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Check.java b/src/main/java/com/mojang/datafixers/types/templates/Check.java index 6267b34f..550843c9 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Check.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Check.java @@ -120,9 +120,9 @@ public CheckType(final String name, final int index, final int expectedIndex, fi } @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { if (index != expectedIndex) { - return Pair.of(input, Optional.empty()); + return DataResult.error("Index mismatch: " + index + " != " + expectedIndex); } return delegate.read(ops, input); } diff --git a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java index 23d69c80..5c77200b 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java +++ b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java @@ -33,7 +33,9 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; +import java.util.stream.Stream; public final class CompoundList implements TypeTemplate { private final TypeTemplate key; @@ -175,21 +177,30 @@ public Optional>> point(final DynamicOps ops) { } @Override - public Pair>>> read(final DynamicOps ops, final T input) { + public DataResult>, T>> read(final DynamicOps ops, final T input) { return ops.getMapValues(input).map(map -> { - final ImmutableList.Builder> builder = ImmutableList.builder(); - final ImmutableMap.Builder restBuilder = ImmutableMap.builder(); + final AtomicReference>, ImmutableMap.Builder>>> result = + new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableMap.builder()))); + map.forEach(entry -> { - final Pair> keyValue = key.read(ops, entry.getFirst()); - final Pair> elementValue = element.read(ops, entry.getSecond()); - if (keyValue.getSecond().isPresent() && elementValue.getSecond().isPresent()) { - builder.add(Pair.of(keyValue.getSecond().get(), elementValue.getSecond().get())); - } else { - restBuilder.put(entry.getFirst(), entry.getSecond()); - } + result.set(result.get().flatMap(pair -> { + final DataResult> readEntry = key.read(ops, entry.getFirst()).flatMap(keyValue -> + element.read(ops, entry.getSecond()).map(elementValue -> + Pair.of(keyValue.getFirst(), elementValue.getFirst()) + ) + ); + readEntry.error().ifPresent(e -> { + pair.getSecond().put(entry.getFirst(), entry.getSecond()); + }); + return readEntry.map(r -> { + pair.getFirst().add(r); + return pair; + }); + })); }); - return Pair.of(ops.createMap(restBuilder.build()), Optional.of((List>) builder.build())); - }).orElseGet(() -> Pair.of(input, Optional.empty())); + + return result.get().map(pair -> Pair.of((List>) pair.getFirst().build(), ops.createMap(pair.getSecond().build()))); + }).orElseGet(() -> DataResult.error("Input is not a map: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Hook.java b/src/main/java/com/mojang/datafixers/types/templates/Hook.java index 03ac9d88..e62d4bdc 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Hook.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Hook.java @@ -109,7 +109,7 @@ public HookType(final Type delegate, final HookFunction preRead, final HookFu } @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return delegate.read(ops, preRead.apply(ops, input)); } diff --git a/src/main/java/com/mojang/datafixers/types/templates/List.java b/src/main/java/com/mojang/datafixers/types/templates/List.java index 9d113cc2..9d6fe4cc 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/List.java +++ b/src/main/java/com/mojang/datafixers/types/templates/List.java @@ -28,6 +28,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; import java.util.stream.Collectors; @@ -159,15 +160,26 @@ public Optional> point(final DynamicOps ops) { } @Override - public Pair>> read(final DynamicOps ops, final T input) { - // TODO: read the same way we read CompoundList? (as much elements as possible) + public DataResult, T>> read(final DynamicOps ops, final T input) { return ops.getStream(input).map(stream -> { - final java.util.List> list = stream.map(value -> element.read(ops, value).getSecond()).collect(Collectors.toList()); - if (list.stream().anyMatch(o -> !o.isPresent())) { - return Pair.of(input, Optional.>empty()); - } - return Pair.of(ops.empty(), Optional.of(list.stream().map(Optional::get).collect(Collectors.toList()))); - }).orElseGet(() -> Pair.of(input, Optional.empty())); + final AtomicReference, ImmutableList.Builder>>> result = + new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableList.builder()))); + + stream.forEach(t -> + result.set(result.get().flatMap(pair -> { + final DataResult> read = element.read(ops, t); + + read.error().ifPresent(e -> pair.getSecond().add(t)); + + return read.map(value -> { + pair.getFirst().add(value.getFirst()); + return pair; + }); + })) + ); + + return result.get().map(pair -> Pair.of((java.util.List) pair.getFirst().build(), ops.createList(pair.getSecond().build().stream()))); + }).orElseGet(() -> DataResult.error("Input is not a list " + input)); } /** diff --git a/src/main/java/com/mojang/datafixers/types/templates/Named.java b/src/main/java/com/mojang/datafixers/types/templates/Named.java index 8cf74d75..a365b22a 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Named.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Named.java @@ -139,8 +139,8 @@ public Optional> findCheckedType(final int index) { } @Override - public Pair>> read(final DynamicOps ops, final T input) { - return element.read(ops, input).mapSecond(vo -> vo.map(v -> Pair.of(name, v))); + public DataResult, T>> read(final DynamicOps ops, final T input) { + return element.read(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(name, v))); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Product.java b/src/main/java/com/mojang/datafixers/types/templates/Product.java index 79ffad26..fcd41f05 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Product.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Product.java @@ -212,15 +212,12 @@ public Optional> findCheckedType(final int index) { } @Override - public Pair>> read(final DynamicOps ops, final T input) { - final Pair> first = this.first.read(ops, input); - if (first.getSecond().isPresent()) { - final Pair> second = this.second.read(ops, first.getFirst()); - if (second.getSecond().isPresent()) { - return Pair.of(second.getFirst(), Optional.of(Pair.of(first.getSecond().get(), second.getSecond().get()))); - } - } - return Pair.of(input, Optional.empty()); + public DataResult, T>> read(final DynamicOps ops, final T input) { + return first.read(ops, input).flatMap(p1 -> + second.read(ops, p1.getSecond()).map(p2 -> + Pair.of(Pair.of(p1.getFirst(), p2.getFirst()), p2.getSecond()) + ) + ); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java index 1d35d7db..6c5c1f94 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java +++ b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java @@ -138,7 +138,7 @@ public Type unfold() { } @Override - public Pair> read(final DynamicOps ops, final T input) { + public DataResult> read(final DynamicOps ops, final T input) { return unfold().read(ops, input); } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Sum.java b/src/main/java/com/mojang/datafixers/types/templates/Sum.java index dc756d37..d68b04b7 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Sum.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Sum.java @@ -212,12 +212,12 @@ public Optional> findCheckedType(final int index) { } @Override - public Pair>> read(final DynamicOps ops, final T input) { - final Pair>> firstRead = first.read(ops, input).mapSecond(vo -> vo.map(Either::left)); - if (firstRead.getSecond().isPresent()) { + public DataResult, T>> read(final DynamicOps ops, final T input) { + final DataResult, T>> firstRead = first.read(ops, input).map(vo -> vo.mapFirst(Either::left)); + if (firstRead.result().isPresent()) { return firstRead; } - return second.read(ops, input).mapSecond(vo -> vo.map(Either::right)); + return second.read(ops, input).map(vo -> vo.mapFirst(Either::right)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index 41190983..db418f85 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -18,12 +18,14 @@ import com.mojang.datafixers.types.families.TypeFamily; import javax.annotation.Nullable; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.function.IntFunction; import java.util.stream.Collectors; +import java.util.stream.Stream; public final class Tag implements TypeTemplate { private final String name; @@ -173,17 +175,24 @@ public TypeTemplate buildTemplate() { } @Override - public Pair> read(final DynamicOps ops, final T input) { - final Optional> map = ops.getMapValues(input).map(s -> s.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); - final T nameObject = ops.createString(name); - final T elementValue; - if (map.isPresent() && (elementValue = map.get().get(nameObject)) != null) { - final Optional value = element.read(ops, elementValue).getSecond(); - if (value.isPresent()) { - return Pair.of(ops.createMap(map.get().entrySet().stream().filter(e -> !Objects.equals(e.getKey(), nameObject)).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))), value); + public DataResult> read(final DynamicOps ops, final T input) { + return ops.getMapValues(input).>>map(map -> { + final T nameObject = ops.createString(name); + + final Map>> partitioned = map.collect(Collectors.partitioningBy(p -> Objects.equals(p.getFirst(), nameObject))); + final List> matched = partitioned.get(true); + final List> rest = partitioned.get(false); + if (matched.isEmpty()) { + return DataResult.error("No keys matched " + name); } - } - return Pair.of(input, Optional.empty()); + if (matched.size() != 1) { + return DataResult.error("Too many keys matched " + name + ": " + matched); + } + + return element.read(ops, matched.get(0).getSecond()).map(value -> + Pair.of(value.getFirst(), ops.createMap(rest.stream().collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)))) + ); + }).orElseGet(() -> DataResult.error("Input is not a map: " + input)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index 503aa5ba..bd4b9cdb 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -6,10 +6,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; -import com.mojang.datafixers.DataFixerUpper; import com.mojang.datafixers.FamilyOptic; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.RewriteResult; @@ -29,13 +26,13 @@ import com.mojang.datafixers.optics.profunctors.AffineP; import com.mojang.datafixers.optics.profunctors.Cartesian; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.Arrays; @@ -47,10 +44,9 @@ import java.util.function.Function; import java.util.function.IntFunction; import java.util.stream.Collectors; +import java.util.stream.Stream; public final class TaggedChoice implements TypeTemplate { - private static final Logger LOGGER = LogManager.getLogger(); - private final String name; private final Type keyType; private final Map templates; @@ -185,32 +181,26 @@ public TypeTemplate buildTemplate() { } @Override - public Pair>> read(final DynamicOps ops, final T input) { - final Optional> values = ops.getMapValues(input).map(s -> s.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); + public DataResult, T>> read(final DynamicOps ops, final T input) { + final Optional>> values = ops.getMapValues(input); if (!values.isPresent()) { - return Pair.of(input, Optional.empty()); - } - - final Map map = values.get(); - final T nameObject = ops.createString(name); - final T mapValue = map.get(nameObject); - if (mapValue == null) { - return Pair.of(input, Optional.empty()); + return DataResult.error("Input is not a map: " + input); } - final Optional key = keyType.read(ops, mapValue).getSecond(); - final K keyValue = key.orElse(null); - final Type type = keyValue != null ? types.get(keyValue) : null; - if (type != null) { - return type.read(ops, input).mapSecond(vo -> vo.map(v -> Pair.of(keyValue, v))); + final T nameString = ops.createString(name); + final Optional> nameEntry = values.get().filter(v -> v.getFirst() == nameString).findFirst(); + if (!nameEntry.isPresent()) { + return DataResult.error("Input does not contain a key [" + name + "] with the name: " + input); } - if (DataFixerUpper.ERRORS_ARE_FATAL) { - throw new IllegalArgumentException("Unsupported key: " + keyValue + " in " + this); - } else { - LOGGER.warn("Unsupported key: {} in {}", keyValue, this); - return Pair.of(input, Optional.empty()); - } + return keyType.read(ops, nameEntry.get().getSecond()).flatMap(key -> { + final K keyValue = key.getFirst(); + final Type type = types.get(keyValue); + if (type != null) { + return type.read(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(keyValue, v))); + } + return DataResult.error("Unsupported key: " + keyValue + " in " + this); + }); } @Override diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index 66fe0f38..e3bfc9c1 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableMap; import com.mojang.datafixers.types.Type; -import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; import java.nio.ByteBuffer; @@ -31,13 +30,6 @@ default T emptyList() { Type getType(final T input); - default Optional cast(final T input, final Type type) { - if (type == getType(input)) { - return Optional.of(type.readTyped(new Dynamic<>(this, input)).getSecond().orElseThrow(() -> new IllegalStateException("Parse error during dynamic cast")).getValue()); - } - return Optional.empty(); - } - Optional getNumberValue(T input); default Number getNumberValue(final T input, final Number defaultValue) { From 1b441264d20908ab295100dcbb56715adc2befb5 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 10 Mar 2020 13:38:30 +0100 Subject: [PATCH 06/96] Convert EmptyPartSaving instead of only casting. --- .../com/mojang/datafixers/types/constant/EmptyPartSaving.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java index 1993a5aa..53353f22 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -50,7 +50,7 @@ public final DataResult write(final DynamicOps ops, final T rest, fina return DataResult.success(rest); } - final T casted = value.cast(ops); + final T casted = value.convert(ops).getValue(); if (rest == ops.empty()) { // no need to merge anything, return the old value return DataResult.success(casted); From 165b35c5af58f21a51346b58feb4cd05a3eac365 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 10 Mar 2020 13:57:36 +0100 Subject: [PATCH 07/96] Added a Codec interface --- src/main/java/com/mojang/datafixers/types/Type.java | 13 ++++++++++++- src/main/java/com/mojang/serialization/Codec.java | 6 ++++++ src/main/java/com/mojang/serialization/Decoder.java | 9 +++++++++ src/main/java/com/mojang/serialization/Encoder.java | 7 +++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/mojang/serialization/Codec.java create mode 100644 src/main/java/com/mojang/serialization/Decoder.java create mode 100644 src/main/java/com/mojang/serialization/Encoder.java diff --git a/src/main/java/com/mojang/datafixers/types/Type.java b/src/main/java/com/mojang/datafixers/types/Type.java index a35a0797..071f487d 100644 --- a/src/main/java/com/mojang/datafixers/types/Type.java +++ b/src/main/java/com/mojang/datafixers/types/Type.java @@ -5,6 +5,7 @@ import com.google.common.collect.Maps; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; +import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.datafixers.FieldFinder; @@ -34,7 +35,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; -public abstract class Type implements App { +public abstract class Type implements App, Codec { private static final Map, TypeRewriteRule, PointFreeRule>, CompletableFuture>>> PENDING_REWRITE_CACHE = Maps.newConcurrentMap(); private static final Map, TypeRewriteRule, PointFreeRule>, Optional>> REWRITE_CACHE = Maps.newConcurrentMap(); @@ -116,6 +117,16 @@ public final DataResult>> read(final Dynamic input) { public abstract DataResult write(final DynamicOps ops, final T rest, final A value); + @Override + public final DataResult> decode(final DynamicOps ops, final T input) { + return read(ops, input); + } + + @Override + public final DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return write(ops, prefix, input); + } + public final DataResult write(final DynamicOps ops, final A value) { return write(ops, ops.empty(), value); } diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java new file mode 100644 index 00000000..0e6e4a09 --- /dev/null +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +public interface Codec extends Encoder, Decoder { +} diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java new file mode 100644 index 00000000..aa4ad695 --- /dev/null +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +import com.mojang.datafixers.util.Pair; + +public interface Decoder { + DataResult> decode(final DynamicOps ops, final T input); +} diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java new file mode 100644 index 00000000..70067697 --- /dev/null +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +public interface Encoder { + DataResult encode(final DynamicOps ops, final T prefix, final A input); +} From d6b5502bf65cce515e9d4c4ea03dff4ce2c74c3f Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 11 Mar 2020 08:11:07 +0100 Subject: [PATCH 08/96] Changed error handling functions slightly --- .../com/mojang/serialization/DataResult.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index c0e7c012..0f4710e2 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -5,7 +5,6 @@ import com.mojang.datafixers.util.Either; import java.util.Optional; -import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; @@ -40,19 +39,25 @@ public Optional result() { return result.left(); } - public T resultOrPartial(final Function onSuccess, final BiFunction, T> onFailure) { + public Optional resultOrPartial(final Consumer onError) { return result.map( - onSuccess, - r -> onFailure.apply(r.message, r.partialResult) + Optional::of, + r -> { + onError.accept(r.message); + return r.partialResult; + } ); } - public Optional resultOrPartial(final Consumer onError) { + public R getOrThrow(final boolean allowPartial, final Consumer onError) { return result.map( - Optional::of, + l -> l, r -> { onError.accept(r.message); - return r.partialResult; + if (allowPartial && r.partialResult.isPresent()) { + return r.partialResult.get(); + } + throw new RuntimeException(r.message); } ); } From 00331a22f15cea23e91d977328cad77da0e26495 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 11 Mar 2020 08:12:13 +0100 Subject: [PATCH 09/96] Added list and map builder helpers to DynamicOps. --- .../com/mojang/serialization/DynamicOps.java | 32 +++++++++ .../com/mojang/serialization/JsonOps.java | 39 ++++++++++ .../com/mojang/serialization/ListBuilder.java | 61 ++++++++++++++++ .../mojang/serialization/RecordBuilder.java | 72 +++++++++++++++++++ .../mojang/serialization/Serializable.java | 7 ++ 5 files changed, 211 insertions(+) create mode 100644 src/main/java/com/mojang/serialization/ListBuilder.java create mode 100644 src/main/java/com/mojang/serialization/RecordBuilder.java create mode 100644 src/main/java/com/mojang/serialization/Serializable.java diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index e3bfc9c1..2017ba22 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -182,4 +182,36 @@ default T update(final T input, final String key, final Function function) default T updateGeneric(final T input, final T key, final Function function) { return getGeneric(input, key).flatMap(value -> mergeInto(input, key, function.apply(value)).result()).orElse(input); } + + default ListBuilder listBuilder() { + return new ListBuilder.Builder<>(this); + } + + default DataResult list(final Iterable list) { + return list(list, empty()); + } + + default DataResult list(final Iterable list, final T prefix) { + return list(list, prefix, e -> e.serialize(this, empty())); + } + + default DataResult list(final Iterable list, final T prefix, final Function> elementSerializer) { + final ListBuilder builder = listBuilder(); + list.forEach(element -> builder.add(elementSerializer.apply(element))); + return builder.build(prefix); + } + + default RecordBuilder mapBuilder() { + return new RecordBuilder.Builder<>(this); + } + + default DataResult map(final Map map, final T prefix) { + return map(map, prefix, Function.identity(), e -> e.serialize(this, empty())); + } + + default DataResult map(final Map map, final T prefix, final Function keySerializer, final Function> elementSerializer) { + final RecordBuilder builder = mapBuilder(); + map.forEach((key, value) -> builder.add(keySerializer.apply(key), elementSerializer.apply(value))); + return builder.build(prefix); + } } diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 08459a8d..9bb91ef3 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -232,4 +232,43 @@ public JsonElement remove(final JsonElement input, final String key) { public String toString() { return "JSON"; } + + @Override + public ListBuilder listBuilder() { + return new ArrayBuilder(); + } + + private static final class ArrayBuilder implements ListBuilder { + private DataResult builder = DataResult.success(new JsonArray()); + + @Override + public DynamicOps ops() { + return INSTANCE; + } + + @Override + public ListBuilder add(final JsonElement value) { + builder = builder.map(b -> { + b.add(value); + return b; + }); + return this; + } + + @Override + public ListBuilder add(final DataResult value) { + builder = builder.flatMap(b -> value.map(element -> { + b.add(element); + return b; + })); + return this; + } + + @Override + public DataResult build(final JsonElement prefix) { + final DataResult result = builder.flatMap(b -> INSTANCE.mergeInto(prefix, b)); + builder = DataResult.success(new JsonArray()); + return result; + } + } } diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java new file mode 100644 index 00000000..f9546713 --- /dev/null +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +import com.google.common.collect.ImmutableList; + +public interface ListBuilder { + DynamicOps ops(); + + DataResult build(T prefix); + + ListBuilder add(final T value); + + ListBuilder add(final DataResult value); + + default ListBuilder add(final Serializable value) { + return add(value, ops().empty()); + } + + default ListBuilder add(final Serializable value, final T elementPrefix) { + return add(value.serialize(ops(), elementPrefix)); + } + + default ListBuilder addAll(final Iterable values) { + values.forEach(this::add); + return this; + } + + final class Builder implements ListBuilder { + private final DynamicOps ops; + private DataResult> builder = DataResult.success(ImmutableList.builder()); + + public Builder(final DynamicOps ops) { + this.ops = ops; + } + + @Override + public DynamicOps ops() { + return ops; + } + + @Override + public ListBuilder add(final T value) { + builder = builder.map(b -> b.add(value)); + return this; + } + + @Override + public ListBuilder add(final DataResult value) { + builder = builder.flatMap(b -> value.map(b::add)); + return this; + } + + @Override + public DataResult build(final T prefix) { + final DataResult result = builder.flatMap(b -> ops.mergeInto(prefix, b.build())); + builder = DataResult.success(ImmutableList.builder()); + return result; + } + } +} diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java new file mode 100644 index 00000000..825618f3 --- /dev/null +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +import com.google.common.collect.ImmutableMap; + +public interface RecordBuilder { + DynamicOps ops(); + + RecordBuilder add(T key, T value); + + RecordBuilder add(T key, DataResult value); + + RecordBuilder add(DataResult key, DataResult value); + + DataResult build(T prefix); + + default RecordBuilder add(final String key, final T value) { + return add(ops().createString(key), value); + } + + default RecordBuilder add(final String key, final DataResult value) { + return add(ops().createString(key), value); + } + + default RecordBuilder add(final String key, final Serializable value) { + return add(key, value, ops().empty()); + } + + default RecordBuilder add(final String key, final Serializable value, final T elementPrefix) { + return add(key, value.serialize(ops(), elementPrefix)); + } + + final class Builder implements RecordBuilder { + private final DynamicOps ops; + private DataResult> builder = DataResult.success(ImmutableMap.builder()); + + public Builder(final DynamicOps ops) { + this.ops = ops; + } + + @Override + public DynamicOps ops() { + return ops; + } + + @Override + public RecordBuilder add(final T key, final T value) { + builder = builder.map(b -> b.put(key, value)); + return this; + } + + @Override + public RecordBuilder add(final T key, final DataResult value) { + builder = builder.flatMap(b -> value.map(v -> b.put(key, v))); + return this; + } + + @Override + public RecordBuilder add(final DataResult key, final DataResult value) { + builder = builder.flatMap(b -> key.flatMap(k -> value.map(v -> b.put(k, v)))); + return this; + } + + @Override + public DataResult build(final T prefix) { + final DataResult result = builder.flatMap(b -> ops.mergeInto(prefix, b.build())); + builder = DataResult.success(ImmutableMap.builder()); + return result; + } + } +} diff --git a/src/main/java/com/mojang/serialization/Serializable.java b/src/main/java/com/mojang/serialization/Serializable.java new file mode 100644 index 00000000..3b98e244 --- /dev/null +++ b/src/main/java/com/mojang/serialization/Serializable.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +public interface Serializable { + DataResult serialize(final DynamicOps ops, final T prefix); +} From 3ae1c1992878c7678144c3bcfe010cb52bb0db1c Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 11 Mar 2020 09:15:32 +0100 Subject: [PATCH 10/96] Re-added empty as a valid input for mergeInto methods. --- .../types/constant/EmptyPartSaving.java | 6 +---- .../com/mojang/serialization/DynamicOps.java | 10 ++++---- .../com/mojang/serialization/JsonOps.java | 24 ++++++++++++------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java index 53353f22..deed769e 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -21,11 +21,7 @@ public String toString() { @Override public Optional> point(final DynamicOps ops) { - return Optional.of(capEmpty(ops)); - } - - private Dynamic capEmpty(final DynamicOps ops) { - return new Dynamic<>(ops, ops.emptyMap()); + return Optional.of(new Dynamic<>(ops)); } @Override diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index 2017ba22..4aa2f901 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -75,7 +75,7 @@ default T createBoolean(final boolean value) { T createString(String value); /** - * Only successful if first argument is a list/array + * Only successful if first argument is a list/array or empty * @return */ DataResult mergeInto(T list, T value); @@ -90,7 +90,7 @@ default DataResult mergeInto(final T list, final List values) { } /** - * Only successful if first argument is a map + * Only successful if first argument is a map or empty * @return */ DataResult mergeInto(T map, T key, T value); @@ -188,11 +188,11 @@ default ListBuilder listBuilder() { } default DataResult list(final Iterable list) { - return list(list, empty()); + return list(list, empty(), empty()); } - default DataResult list(final Iterable list, final T prefix) { - return list(list, prefix, e -> e.serialize(this, empty())); + default DataResult list(final Iterable list, final T prefix, final T elementPrefix) { + return list(list, prefix, e -> e.serialize(this, elementPrefix)); } default DataResult list(final Iterable list, final T prefix, final Function> elementSerializer) { diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 9bb91ef3..181e8c86 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -120,31 +120,35 @@ public JsonElement createString(final String value) { @Override public DataResult mergeInto(final JsonElement list, final JsonElement value) { - if (!list.isJsonArray()) { + if (!list.isJsonArray() && list != empty()) { return DataResult.error("mergeInto called with not a list: " + list, list); } final JsonArray result = new JsonArray(); - result.addAll(list.getAsJsonArray()); + if (list != empty()) { + result.addAll(list.getAsJsonArray()); + } result.add(value); return DataResult.success(result); } @Override public DataResult mergeInto(final JsonElement list, final List values) { - if (!list.isJsonArray()) { + if (!list.isJsonArray() && list != empty()) { return DataResult.error("mergeInto called with not a list: " + list, list); } final JsonArray result = new JsonArray(); - result.addAll(list.getAsJsonArray()); + if (list != empty()) { + result.addAll(list.getAsJsonArray()); + } values.forEach(result::add); return DataResult.success(result); } @Override public DataResult mergeInto(final JsonElement map, final JsonElement key, final JsonElement value) { - if (!map.isJsonObject()) { + if (!map.isJsonObject() && map != empty()) { return DataResult.error("mergeInto called with not a map: " + map, map); } if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString()) { @@ -152,7 +156,9 @@ public DataResult mergeInto(final JsonElement map, final JsonElemen } final JsonObject output = new JsonObject(); - map.getAsJsonObject().entrySet().forEach(entry -> output.add(entry.getKey(), entry.getValue())); + if (map != empty()) { + map.getAsJsonObject().entrySet().forEach(entry -> output.add(entry.getKey(), entry.getValue())); + } output.add(key.getAsString(), value); return DataResult.success(output); @@ -160,12 +166,14 @@ public DataResult mergeInto(final JsonElement map, final JsonElemen @Override public DataResult mergeInto(final JsonElement map, final Map values) { - if (!map.isJsonObject()) { + if (!map.isJsonObject() && map != empty()) { return DataResult.error("mergeInto called with not a map: " + map, map); } final JsonObject output = new JsonObject(); - map.getAsJsonObject().entrySet().forEach(entry -> output.add(entry.getKey(), entry.getValue())); + if (map != empty()) { + map.getAsJsonObject().entrySet().forEach(entry -> output.add(entry.getKey(), entry.getValue())); + } final List missed = Lists.newArrayList(); From 6378f3d46098469525e0b77bea43ba9cf86ca197 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 12 Mar 2020 09:56:28 +0100 Subject: [PATCH 11/96] Applicative syntax helpers, decoder helpers, decoder-based helpers in Dynamic --- .../mojang/datafixers/kinds/Applicative.java | 255 +++++++++++++++++- .../com/mojang/datafixers/kinds/ListBox.java | 60 +++++ .../mojang/datafixers/kinds/OptionalBox.java | 15 +- .../mojang/datafixers/kinds/Traversable.java | 2 +- .../com/mojang/datafixers/util/Function3.java | 16 ++ .../com/mojang/datafixers/util/Function4.java | 20 ++ .../com/mojang/datafixers/util/Function5.java | 24 ++ .../com/mojang/datafixers/util/Function6.java | 28 ++ .../com/mojang/datafixers/util/Function7.java | 32 +++ .../java/com/mojang/serialization/Codec.java | 48 ++++ .../com/mojang/serialization/DataResult.java | 44 ++- .../com/mojang/serialization/Decoder.java | 79 ++++++ .../com/mojang/serialization/Dynamic.java | 27 +- .../com/mojang/serialization/DynamicLike.java | 36 ++- .../com/mojang/serialization/Encoder.java | 14 + .../mojang/serialization/OptionalDynamic.java | 48 ++-- 16 files changed, 698 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/mojang/datafixers/kinds/ListBox.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function3.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function4.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function5.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function6.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function7.java diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index e7f0c8c5..fd960b15 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -2,6 +2,12 @@ // Licensed under the MIT license. package com.mojang.datafixers.kinds; +import com.mojang.datafixers.util.Function3; +import com.mojang.datafixers.util.Function4; +import com.mojang.datafixers.util.Function5; +import com.mojang.datafixers.util.Function6; +import com.mojang.datafixers.util.Function7; + import java.util.function.BiFunction; import java.util.function.Function; @@ -16,14 +22,37 @@ interface Mu extends Functor.Mu {} Function, App> lift1(final App> function); - BiFunction, App, App> lift2(final App> function); + default BiFunction, App, App> lift2(final App> function) { + final Function, Function>> curry = f -> a -> b -> f.apply(a, b); + return (fa, fb) -> ap(lift1(map(curry, function)).apply(fa), fb); + } + + default Function3, App, App, App> lift3(final App> function) { + return (ft1, ft2, ft3) -> lift2(lift1(map(Function3::curry, function)).apply(ft1)).apply(ft2, ft3); + } + + default Function4, App, App, App, App> lift4(final App> function) { + return (ft1, ft2, ft3, ft4) -> lift2(lift2(map(Function4::curry2, function)).apply(ft1, ft2)).apply(ft3, ft4); + } + + default Function5, App, App, App, App, App> lift5(final App> function) { + return (ft1, ft2, ft3, ft4, ft5) -> lift3(lift2(map(Function5::curry2, function)).apply(ft1, ft2)).apply(ft3, ft4, ft5); + } + + default Function6, App, App, App, App, App, App> lift6(final App> function) { + return (ft1, ft2, ft3, ft4, ft5, ft6) -> lift3(lift3(map(Function6::curry3, function)).apply(ft1, ft2, ft3)).apply(ft4, ft5, ft6); + } + + default Function7, App, App, App, App, App, App, App> lift7(final App> function) { + return (ft1, ft2, ft3, ft4, ft5, ft6, ft7) -> lift4(lift3(map(Function7::curry3, function)).apply(ft1, ft2, ft3)).apply(ft4, ft5, ft6, ft7); + } default App ap(final App> func, final App arg) { return lift1(func).apply(arg); } default App ap(final Function func, final App arg) { - return lift1(point(func)).apply(arg); + return ap(point(func), arg); } default App ap2(final App> func, final App a, final App b) { @@ -31,6 +60,226 @@ default App ap2(final App> func, final Ap } default App ap2(final BiFunction func, final App a, final App b) { - return lift2(point(func)).apply(a, b); + return ap2(point(func), a, b); + } + + default P1 group(final App t1) { + return new P1<>(this, t1); + } + + default P2 group(final App t1, final App t2) { + return new P2<>(this, t1, t2); + } + + default P3 group(final App t1, final App t2, final App t3) { + return new P3<>(this, t1, t2, t3); + } + + default P4 group(final App t1, final App t2, final App t3, final App t4) { + return new P4<>(this, t1, t2, t3, t4); + } + + default P5 group(final App t1, final App t2, final App t3, final App t4, final App t5) { + return new P5<>(this, t1, t2, t3, t4, t5); + } + + default P6 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { + return new P6<>(this, t1, t2, t3, t4, t5, t6); + } + + default P7 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { + return new P7<>(this, t1, t2, t3, t4, t5, t6, t7); + } + + final class P1 { + private final Applicative instance; + private final App t1; + + private P1(final Applicative instance, final App t1) { + this.instance = instance; + this.t1 = t1; + } + + public P2 and(final App t2) { + return new P2<>(instance, t1, t2); + } + + public App apply(final Function function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap(function, t1); + } + } + + final class P2 { + private final Applicative instance; + private final App t1; + private final App t2; + + private P2(final Applicative instance, final App t1, final App t2) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + } + + public P3 and(final App t3) { + return new P3<>(instance, t1, t2, t3); + } + + public App apply(final BiFunction function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap2(function, t1, t2); + } + } + + final class P3 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + + private P3(final Applicative instance, final App t1, final App t2, final App t3) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + } + + public P4 and(final App t4) { + return new P4<>(instance, t1, t2, t3, t4); + } + + public App apply(final Function3 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.lift3(function).apply(t1, t2, t3); + } + } + + final class P4 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + + private P4(final Applicative instance, final App t1, final App t2, final App t3, final App t4) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + } + + public P5 and(final App t5) { + return new P5<>(instance, t1, t2, t3, t4, t5); + } + + public App apply(final Function4 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.lift4(function).apply(t1, t2, t3, t4); + } + } + + final class P5 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + + private P5(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + } + + public P6 and(final App t6) { + return new P6<>(instance, t1, t2, t3, t4, t5, t6); + } + + public App apply(final Function5 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.lift5(function).apply(t1, t2, t3, t4, t5); + } + } + + final class P6 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + + private P6(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + } + + public P7 and(final App t7) { + return new P7<>(instance, t1, t2, t3, t4, t5, t6, t7); + } + + public App apply(final Function6 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.lift6(function).apply(t1, t2, t3, t4, t5, t6); + } + } + + final class P7 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + + private P7(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + } + + public App apply(final Function7 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.lift7(function).apply(t1, t2, t3, t4, t5, t6, t7); + } } } diff --git a/src/main/java/com/mojang/datafixers/kinds/ListBox.java b/src/main/java/com/mojang/datafixers/kinds/ListBox.java new file mode 100644 index 00000000..b5993a72 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/kinds/ListBox.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.datafixers.kinds; + +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +public final class ListBox implements App { + public static final class Mu implements K1 {} + + public static List unbox(final App box) { + return ((ListBox) box).value; + } + + public static ListBox create(final List value) { + return new ListBox<>(value); + } + + private final List value; + + private ListBox(final List value) { + this.value = value; + } + + public static App> traverse(final Applicative applicative, final Function> function, final List input) { + return applicative.map(ListBox::unbox, Instance.INSTANCE.traverse(applicative, function, create(input))); + } + + public static App> flip(final Applicative applicative, final List> input) { + return applicative.map(ListBox::unbox, Instance.INSTANCE.flip(applicative, create(input))); + } + + public enum Instance implements Traversable { + INSTANCE; + + public static final class Mu implements Traversable.Mu {} + + @Override + public App map(final Function func, final App ts) { + return create(ListBox.unbox(ts).stream().map(func).collect(Collectors.toList())); + } + + @Override + public App> traverse(final Applicative applicative, final Function> function, final App input) { + final List list = unbox(input); + + App> result = applicative.point(ImmutableList.builder()); + + for (final A a : list) { + final App fb = function.apply(a); + result = applicative.ap2(ImmutableList.Builder::add, result, fb); + } + + return applicative.map(b -> create(b.build()), result); + } + } +} diff --git a/src/main/java/com/mojang/datafixers/kinds/OptionalBox.java b/src/main/java/com/mojang/datafixers/kinds/OptionalBox.java index 2c9623f5..01724a0f 100644 --- a/src/main/java/com/mojang/datafixers/kinds/OptionalBox.java +++ b/src/main/java/com/mojang/datafixers/kinds/OptionalBox.java @@ -19,14 +19,14 @@ public static OptionalBox create(final Optional value) { private final Optional value; - OptionalBox(final Optional value) { + private OptionalBox(final Optional value) { this.value = value; } - public enum Instance implements Applicative { + public enum Instance implements Applicative, Traversable { INSTANCE; - public static final class Mu implements Applicative.Mu {} + public static final class Mu implements Applicative.Mu, Traversable.Mu {} @Override public App map(final Function func, final App ts) { @@ -47,5 +47,14 @@ public Function, App> lift1(fin public BiFunction, App, App> lift2(final App> function) { return (a, b) -> create(OptionalBox.unbox(function).flatMap(f -> OptionalBox.unbox(a).flatMap(av -> OptionalBox.unbox(b).map(bv -> f.apply(av, bv))))); } + + @Override + public App> traverse(final Applicative applicative, final Function> function, final App input) { + final Optional> traversed = unbox(input).map(function); + if (traversed.isPresent()) { + return applicative.map(b -> OptionalBox.create(Optional.of(b)), traversed.get()); + } + return applicative.point(OptionalBox.create(Optional.empty())); + } } } diff --git a/src/main/java/com/mojang/datafixers/kinds/Traversable.java b/src/main/java/com/mojang/datafixers/kinds/Traversable.java index 7725859e..760d1175 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Traversable.java +++ b/src/main/java/com/mojang/datafixers/kinds/Traversable.java @@ -13,7 +13,7 @@ interface Mu extends Functor.Mu {} App> traverse(final Applicative applicative, final Function> function, final App input); - default App> sequenceA(final Applicative applicative, final App> input) { + default App> flip(final Applicative applicative, final App> input) { return traverse(applicative, Function.identity(), input); } } diff --git a/src/main/java/com/mojang/datafixers/util/Function3.java b/src/main/java/com/mojang/datafixers/util/Function3.java new file mode 100644 index 00000000..1e3fe820 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function3.java @@ -0,0 +1,16 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function3 { + R apply(T1 t1, T2 t2, T3 t3); + + default Function> curry() { + return t1 -> (t2, t3) -> apply(t1, t2, t3); + } + + default BiFunction> curry2() { + return (t1, t2) -> t3 -> apply(t1, t2, t3); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function4.java b/src/main/java/com/mojang/datafixers/util/Function4.java new file mode 100644 index 00000000..c33e4d89 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function4.java @@ -0,0 +1,20 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function4 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4); + + default Function> curry() { + return t1 -> (t2, t3, t4) -> apply(t1, t2, t3, t4); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4) -> apply(t1, t2, t3, t4); + } + + default Function3> curry3() { + return (t1, t2, t3) -> t4 -> apply(t1, t2, t3, t4); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function5.java b/src/main/java/com/mojang/datafixers/util/Function5.java new file mode 100644 index 00000000..87112d23 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function5.java @@ -0,0 +1,24 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function5 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5) -> apply(t1, t2, t3, t4, t5); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5) -> apply(t1, t2, t3, t4, t5); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5) -> apply(t1, t2, t3, t4, t5); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5) -> apply(t1, t2, t3, t4, t5); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function6.java b/src/main/java/com/mojang/datafixers/util/Function6.java new file mode 100644 index 00000000..37a7366d --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function6.java @@ -0,0 +1,28 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function6 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6) -> apply(t1, t2, t3, t4, t5, t6); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6) -> apply(t1, t2, t3, t4, t5, t6); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6) -> apply(t1, t2, t3, t4, t5, t6); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6) -> apply(t1, t2, t3, t4, t5, t6); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> t6 -> apply(t1, t2, t3, t4, t5, t6); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function7.java b/src/main/java/com/mojang/datafixers/util/Function7.java new file mode 100644 index 00000000..b2aaa167 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function7.java @@ -0,0 +1,32 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function7 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7) -> apply(t1, t2, t3, t4, t5, t6, t7); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7) -> apply(t1, t2, t3, t4, t5, t6, t7); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7) -> apply(t1, t2, t3, t4, t5, t6, t7); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7) -> apply(t1, t2, t3, t4, t5, t6, t7); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7) -> apply(t1, t2, t3, t4, t5, t6, t7); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> t7 -> apply(t1, t2, t3, t4, t5, t6, t7); + } +} diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 0e6e4a09..a7c49d0c 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -2,5 +2,53 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.mojang.datafixers.util.Pair; + public interface Codec extends Encoder, Decoder { + static Codec of(final Decoder decoder) { + return of(Encoder.of(), decoder); + } + + static Codec of(final Terminal terminal) { + return of(Encoder.of(), terminal.decoder()); + } + + static Codec of(final Boxed boxed) { + return of(Encoder.of(), boxed.decoder()); + } + + static Codec of(final Simple simple) { + return of(Encoder.of(), simple.decoder()); + } + + static Codec of(final Encoder encoder, final Terminal terminal) { + return of(encoder, terminal.decoder()); + } + + static Codec of(final Encoder encoder, final Boxed boxed) { + return of(encoder, boxed.decoder()); + } + + static Codec of(final Encoder encoder, final Simple terminal) { + return of(encoder, terminal.decoder()); + } + + static Codec of(final Encoder encoder, final Decoder decoder) { + return new Codec() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return decoder.decode(ops, input); + } + + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return encoder.encode(ops, prefix, input); + } + + @Override + public String toString() { + return "Codec[" + encoder + " " + decoder + "]"; + } + }; + } } diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 0f4710e2..ced5eab3 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -2,13 +2,23 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.mojang.datafixers.kinds.App; +import com.mojang.datafixers.kinds.Applicative; +import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.util.Either; import java.util.Optional; +import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; -public class DataResult { +public class DataResult implements App { + public static final class Mu implements K1 {} + + public static DataResult unbox(final App box) { + return (DataResult) box; + } + private final Either> result; public static DataResult success(final R result) { @@ -76,7 +86,7 @@ public DataResult map(final Function function) { /** * Applies the function to either full or partial result, in case of partial concatenates errors. */ - public DataResult flatMap(final Function> function) { + public DataResult flatMap(final Function> function) { return create(result.map( l -> function.apply(l).get(), r -> Either.right(r.partialResult @@ -91,6 +101,10 @@ public DataResult flatMap(final Function> function) { )); } + public static Instance instance() { + return Instance.INSTANCE; + } + public static class DynamicException { private final String message; private final Optional partialResult; @@ -120,4 +134,30 @@ public String message() { return message; } } + + public enum Instance implements Applicative { + INSTANCE; + + public static final class Mu implements Applicative.Mu {} + + @Override + public App map(final Function func, final App ts) { + return DataResult.unbox(ts).map(func); + } + + @Override + public App point(final A a) { + return DataResult.success(a); + } + + @Override + public Function, App> lift1(final App> function) { + return a -> DataResult.unbox(function).flatMap(f -> DataResult.unbox(a).map(f)); + } + + @Override + public BiFunction, App, App> lift2(final App> function) { + return (a, b) -> DataResult.unbox(function).flatMap(f -> DataResult.unbox(a).flatMap(av -> DataResult.unbox(b).map(bv -> f.apply(av, bv)))); + } + } } \ No newline at end of file diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index aa4ad695..8a4e4bb2 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -6,4 +6,83 @@ public interface Decoder { DataResult> decode(final DynamicOps ops, final T input); + + // TODO: rename to read after Type.read is no more + default DataResult parse(final DynamicOps ops, final T input) { + return decode(ops, input).map(Pair::getFirst); + } + + default DataResult> decode(final Dynamic input) { + return decode(input.getOps(), input.getValue()); + } + + default DataResult parse(final Dynamic input) { + return decode(input).map(Pair::getFirst); + } + + default Terminal terminal() { + return this::parse; + } + + default Boxed boxed() { + return this::decode; + } + + default Simple simple() { + return this::parse; + } + + interface Terminal { + DataResult decode(final DynamicOps ops, final T input); + + default Decoder decoder() { + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return Terminal.this.decode(ops, input).map(a -> Pair.of(a, ops.empty())); + } + + @Override + public String toString() { + return "TerminalDecoder[" + Terminal.this + "]"; + } + }; + } + } + + interface Boxed { + DataResult> decode(final Dynamic input); + + default Decoder decoder() { + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return Boxed.this.decode(new Dynamic<>(ops, input)); + } + + @Override + public String toString() { + return "BoxedDecoder[" + Boxed.this + "]"; + } + }; + } + } + + interface Simple { + DataResult decode(final Dynamic input); + + default Decoder decoder() { + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return Simple.this.decode(new Dynamic<>(ops, input)).map(a -> Pair.of(a, ops.empty())); + } + + @Override + public String toString() { + return "SimpleDecoder[" + Simple.this + "]"; + } + }; + } + } } diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index e2f48767..a3c11c4b 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -10,7 +10,6 @@ import javax.annotation.Nullable; import java.nio.ByteBuffer; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -93,6 +92,11 @@ public Optional>> asStreamOpt() { return ops.getStream(value).map(s -> s.map(e -> new Dynamic<>(ops, e))); } + @Override + public Optional, Dynamic>>> asMapOpt() { + return ops.getMapValues(value).map(s -> s.map(p -> Pair.of(new Dynamic<>(ops, p.getFirst()), new Dynamic<>(ops, p.getSecond())))); + } + @Override public Optional asByteBufferOpt() { return ops.getByteBuffer(value); @@ -153,22 +157,6 @@ public Optional getElementGeneric(final T key) { return ops.getGeneric(value, key); } - @Override - public Optional> asListOpt(final Function, U> deserializer) { - return asStreamOpt().map(stream -> stream.map(deserializer).collect(Collectors.toList())); - } - - @Override - public Optional> asMapOpt(final Function, K> keyDeserializer, final Function, V> valueDeserializer) { - return ops.getMapValues(value).map(map -> { - final ImmutableMap.Builder builder = ImmutableMap.builder(); - map.forEach(entry -> - builder.put(keyDeserializer.apply(new Dynamic<>(ops, entry.getFirst())), valueDeserializer.apply(new Dynamic<>(ops, entry.getSecond()))) - ); - return builder.build(); - }); - } - @Override public boolean equals(final Object o) { if (this == o) { @@ -199,6 +187,11 @@ public V into(final Function, ? extends V> action) { return action.apply(this); } + @Override + public DataResult> decode(final Decoder decoder) { + return decoder.decode(ops, value).map(p -> p.mapFirst(Function.identity())); + } + @SuppressWarnings("unchecked") public static T convert(final DynamicOps inOps, final DynamicOps outOps, final S input) { if (Objects.equals(inOps, outOps)) { diff --git a/src/main/java/com/mojang/serialization/DynamicLike.java b/src/main/java/com/mojang/serialization/DynamicLike.java index 4277c9fd..6afc1cf2 100644 --- a/src/main/java/com/mojang/serialization/DynamicLike.java +++ b/src/main/java/com/mojang/serialization/DynamicLike.java @@ -4,12 +4,15 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.kinds.ListBox; +import com.mojang.datafixers.util.Pair; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.LongStream; import java.util.stream.Stream; @@ -29,6 +32,7 @@ public DynamicOps getOps() { public abstract Optional asNumber(); public abstract Optional asString(); public abstract Optional>> asStreamOpt(); + public abstract Optional, Dynamic>>> asMapOpt(); public abstract Optional asByteBufferOpt(); public abstract Optional asIntStreamOpt(); public abstract Optional asLongStreamOpt(); @@ -36,8 +40,36 @@ public DynamicOps getOps() { public abstract Optional getGeneric(T key); public abstract Optional getElement(String key); public abstract Optional getElementGeneric(T key); - public abstract Optional> asListOpt(Function, U> deserializer); - public abstract Optional> asMapOpt(Function, K> keyDeserializer, Function, V> valueDeserializer); + + public abstract DataResult> decode(final Decoder decoder); + + public Optional> asListOpt(final Function, U> deserializer) { + return asStreamOpt().map(stream -> stream.map(deserializer).collect(Collectors.toList())); + } + + public Optional> asMapOpt(final Function, K> keyDeserializer, final Function, V> valueDeserializer) { + return asMapOpt().map(map -> { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + map.forEach(entry -> + builder.put(keyDeserializer.apply(entry.getFirst()), valueDeserializer.apply(entry.getSecond())) + ); + return builder.build(); + }); + } + + public DataResult read(final Decoder decoder) { + return decode(decoder).map(Pair::getFirst); + } + + public DataResult> readList(final Decoder decoder) { + final DataResult>> stream = asStreamOpt() + .map(DataResult::success) + .orElseGet(() -> DataResult.error("Not a list")); + + return stream + .map(s -> s.>map(d -> d.read(decoder)).collect(Collectors.toList())) + .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); + } public Number asNumber(final Number defaultValue) { return asNumber().orElse(defaultValue); diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index 70067697..16233967 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -4,4 +4,18 @@ public interface Encoder { DataResult encode(final DynamicOps ops, final T prefix, final A input); + + static Encoder of() { + return new Encoder() { + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return input.serialize(ops, prefix); + } + + @Override + public String toString() { + return "SerializableEncoder"; + } + }; + } } diff --git a/src/main/java/com/mojang/serialization/OptionalDynamic.java b/src/main/java/com/mojang/serialization/OptionalDynamic.java index 4c362446..3a9df1c3 100644 --- a/src/main/java/com/mojang/serialization/OptionalDynamic.java +++ b/src/main/java/com/mojang/serialization/OptionalDynamic.java @@ -2,9 +2,9 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.mojang.datafixers.util.Pair; + import java.nio.ByteBuffer; -import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.function.Function; import java.util.stream.IntStream; @@ -28,38 +28,47 @@ public DataResult map(final Function, U> mapper) { return delegate.map(mapper); } - public Optional flatMap(final Function, Optional> mapper) { + public Optional flatMapOpt(final Function, Optional> mapper) { return result().flatMap(mapper); } + public DataResult flatMap(final Function, ? extends DataResult> mapper) { + return delegate.flatMap(mapper); + } + @Override public Optional asNumber() { - return flatMap(DynamicLike::asNumber); + return flatMapOpt(DynamicLike::asNumber); } @Override public Optional asString() { - return flatMap(DynamicLike::asString); + return flatMapOpt(DynamicLike::asString); } @Override public Optional>> asStreamOpt() { - return flatMap(DynamicLike::asStreamOpt); + return flatMapOpt(DynamicLike::asStreamOpt); + } + + @Override + public Optional, Dynamic>>> asMapOpt() { + return flatMapOpt(DynamicLike::asMapOpt); } @Override public Optional asByteBufferOpt() { - return flatMap(DynamicLike::asByteBufferOpt); + return flatMapOpt(DynamicLike::asByteBufferOpt); } @Override public Optional asIntStreamOpt() { - return flatMap(DynamicLike::asIntStreamOpt); + return flatMapOpt(DynamicLike::asIntStreamOpt); } @Override public Optional asLongStreamOpt() { - return flatMap(DynamicLike::asLongStreamOpt); + return flatMapOpt(DynamicLike::asLongStreamOpt); } @Override @@ -69,27 +78,17 @@ public OptionalDynamic get(final String key) { @Override public Optional getGeneric(final T key) { - return flatMap(v -> v.getGeneric(key)); + return flatMapOpt(v -> v.getGeneric(key)); } @Override public Optional getElement(final String key) { - return flatMap(v -> v.getElement(key)); + return flatMapOpt(v -> v.getElement(key)); } @Override public Optional getElementGeneric(final T key) { - return flatMap(v -> v.getElementGeneric(key)); - } - - @Override - public Optional> asListOpt(final Function, U> deserializer) { - return flatMap(t -> t.asListOpt(deserializer)); - } - - @Override - public Optional> asMapOpt(final Function, K> keyDeserializer, final Function, V> valueDeserializer) { - return flatMap(input -> input.asMapOpt(keyDeserializer, valueDeserializer)); + return flatMapOpt(v -> v.getElementGeneric(key)); } public Dynamic orElseEmptyMap() { @@ -103,4 +102,9 @@ public Dynamic orElseEmptyList() { public Optional into(final Function, ? extends V> action) { return result().map(action); } + + @Override + public DataResult> decode(final Decoder decoder) { + return delegate.flatMap(t -> t.decode(decoder)); + } } From cd0da2077dea4e8d7c1a088ec3f2a6cce68e27ca Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 12 Mar 2020 10:31:59 +0100 Subject: [PATCH 12/96] Replaced remaining usages of Optional in Dynamic API with DataResult. --- .../datafixers/types/constant/BoolType.java | 3 +- .../datafixers/types/constant/ByteType.java | 3 +- .../datafixers/types/constant/DoubleType.java | 3 +- .../types/constant/EmptyPartSaving.java | 18 +++--- .../datafixers/types/constant/FloatType.java | 3 +- .../datafixers/types/constant/IntType.java | 3 +- .../datafixers/types/constant/LongType.java | 3 +- .../types/constant/NamespacedStringType.java | 3 +- .../datafixers/types/constant/ShortType.java | 3 +- .../datafixers/types/constant/StringType.java | 3 +- .../types/templates/CompoundList.java | 4 +- .../datafixers/types/templates/List.java | 13 ++--- .../datafixers/types/templates/Tag.java | 4 +- .../types/templates/TaggedChoice.java | 32 +++++------ .../com/mojang/serialization/Dynamic.java | 56 +++++++++---------- .../com/mojang/serialization/DynamicLike.java | 51 ++++++++--------- .../com/mojang/serialization/DynamicOps.java | 55 +++++++++--------- .../com/mojang/serialization/JsonOps.java | 35 ++++++------ .../mojang/serialization/OptionalDynamic.java | 48 ++++++++-------- 19 files changed, 160 insertions(+), 183 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java index 80e1eb39..1cceecab 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java @@ -12,8 +12,7 @@ public final class BoolType extends Const.PrimitiveType { public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> DataResult.success(Pair.of(v.intValue() != 0, ops.empty()))) - .orElseGet(() -> DataResult.error("Input is not a number: " + input)); + .map(v -> Pair.of(v.intValue() != 0, ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java index 08dfdbfe..637bd68e 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java @@ -12,8 +12,7 @@ public final class ByteType extends Const.PrimitiveType { public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> DataResult.success(Pair.of(v.byteValue(), ops.empty()))) - .orElseGet(() -> DataResult.error("Input is not a number: " + input)); + .map(v -> Pair.of(v.byteValue(), ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java index 2e7dd022..e4e83d63 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java @@ -12,8 +12,7 @@ public final class DoubleType extends Const.PrimitiveType { public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> DataResult.success(Pair.of(v.doubleValue(), ops.empty()))) - .orElseGet(() -> DataResult.error("Input is not a number: " + input)); + .map(v -> Pair.of(v.doubleValue(), ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java index deed769e..d95330b6 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -52,16 +52,12 @@ public final DataResult write(final DynamicOps ops, final T rest, fina return DataResult.success(casted); } - final Optional>> map = ops.getMapValues(casted); - if (map.isPresent()) { - return ops.mergeInto(rest, map.get().collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); - } - - final Optional> stream = ops.getStream(casted); - if (stream.isPresent()) { - return ops.mergeInto(rest, stream.get().collect(Collectors.toList())); - } - - return DataResult.error("Don't know how to merge " + rest + " and " + casted, rest); + final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeInto(rest, map.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)))); + return toMap.result().map(DataResult::success).orElseGet(() -> { + final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeInto(rest, stream.collect(Collectors.toList()))); + return toList.result().map(DataResult::success).orElseGet(() -> + DataResult.error("Don't know how to merge " + rest + " and " + casted, rest) + ); + }); } } diff --git a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java index ebc7f4be..870353de 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java @@ -12,8 +12,7 @@ public final class FloatType extends Const.PrimitiveType { public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> DataResult.success(Pair.of(v.floatValue(), ops.empty()))) - .orElseGet(() -> DataResult.error("Input is not a number: " + input)); + .map(v -> Pair.of(v.floatValue(), ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/IntType.java b/src/main/java/com/mojang/datafixers/types/constant/IntType.java index 18b75bc5..abadbbc7 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/IntType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/IntType.java @@ -12,8 +12,7 @@ public final class IntType extends Const.PrimitiveType { public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> DataResult.success(Pair.of(v.intValue(), ops.empty()))) - .orElseGet(() -> DataResult.error("Input is not a number: " + input)); + .map(v -> Pair.of(v.intValue(), ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/LongType.java b/src/main/java/com/mojang/datafixers/types/constant/LongType.java index 79f3729c..49871ba0 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/LongType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/LongType.java @@ -12,8 +12,7 @@ public final class LongType extends Const.PrimitiveType { public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> DataResult.success(Pair.of(v.longValue(), ops.empty()))) - .orElseGet(() -> DataResult.error("Input is not a number: " + input)); + .map(v -> Pair.of(v.longValue(), ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java index 7f668159..13de7391 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java @@ -16,8 +16,7 @@ public final class NamespacedStringType extends Const.PrimitiveType { public DataResult> read(final DynamicOps ops, final T input) { return ops .getStringValue(input) - .map(v -> DataResult.success(Pair.of(ENSURE_NAMESPACE.apply(v), ops.empty()))) - .orElseGet(() -> DataResult.error("Input is not a string: " + input)); + .map(v -> Pair.of(ENSURE_NAMESPACE.apply(v), ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java index 58c59365..833aa6b6 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java @@ -12,8 +12,7 @@ public final class ShortType extends Const.PrimitiveType { public DataResult> read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> DataResult.success(Pair.of(v.shortValue(), ops.empty()))) - .orElseGet(() -> DataResult.error("Input is not a number: " + input)); + .map(v -> Pair.of(v.shortValue(), ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/StringType.java b/src/main/java/com/mojang/datafixers/types/constant/StringType.java index 7d93fec5..67bc24c9 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/StringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/StringType.java @@ -12,8 +12,7 @@ public final class StringType extends Const.PrimitiveType { public DataResult> read(final DynamicOps ops, final T input) { return ops .getStringValue(input) - .map(v -> DataResult.success(Pair.of(v, ops.empty()))) - .orElseGet(() -> DataResult.error("Input is not a string: " + input)); + .map(v -> Pair.of(v, ops.empty())); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java index 5c77200b..526408f5 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java +++ b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java @@ -178,7 +178,7 @@ public Optional>> point(final DynamicOps ops) { @Override public DataResult>, T>> read(final DynamicOps ops, final T input) { - return ops.getMapValues(input).map(map -> { + return ops.getMapValues(input).flatMap(map -> { final AtomicReference>, ImmutableMap.Builder>>> result = new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableMap.builder()))); @@ -200,7 +200,7 @@ public DataResult>, T>> read(final DynamicOps ops, f }); return result.get().map(pair -> Pair.of((List>) pair.getFirst().build(), ops.createMap(pair.getSecond().build()))); - }).orElseGet(() -> DataResult.error("Input is not a map: " + input)); + }); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/List.java b/src/main/java/com/mojang/datafixers/types/templates/List.java index 9d6fe4cc..6fea5628 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/List.java +++ b/src/main/java/com/mojang/datafixers/types/templates/List.java @@ -5,8 +5,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.FamilyOptic; import com.mojang.datafixers.OpticParts; @@ -17,11 +15,13 @@ import com.mojang.datafixers.optics.ListTraversal; import com.mojang.datafixers.optics.Optic; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.ArrayList; @@ -30,7 +30,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; -import java.util.stream.Collectors; public final class List implements TypeTemplate { private final TypeTemplate element; @@ -161,7 +160,7 @@ public Optional> point(final DynamicOps ops) { @Override public DataResult, T>> read(final DynamicOps ops, final T input) { - return ops.getStream(input).map(stream -> { + return ops.getStream(input).flatMap(stream -> { final AtomicReference, ImmutableList.Builder>>> result = new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableList.builder()))); @@ -179,7 +178,7 @@ public DataResult, T>> read(final DynamicOps ops, ); return result.get().map(pair -> Pair.of((java.util.List) pair.getFirst().build(), ops.createList(pair.getSecond().build().stream()))); - }).orElseGet(() -> DataResult.error("Input is not a list " + input)); + }); } /** diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index db418f85..e6ed4de1 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -176,7 +176,7 @@ public TypeTemplate buildTemplate() { @Override public DataResult> read(final DynamicOps ops, final T input) { - return ops.getMapValues(input).>>map(map -> { + return ops.getMapValues(input).flatMap(map -> { final T nameObject = ops.createString(name); final Map>> partitioned = map.collect(Collectors.partitioningBy(p -> Objects.equals(p.getFirst(), nameObject))); @@ -192,7 +192,7 @@ public DataResult> read(final DynamicOps ops, final T input) { return element.read(ops, matched.get(0).getSecond()).map(value -> Pair.of(value.getFirst(), ops.createMap(rest.stream().collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)))) ); - }).orElseGet(() -> DataResult.error("Input is not a map: " + input)); + }); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index bd4b9cdb..affa3e80 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -182,24 +182,22 @@ public TypeTemplate buildTemplate() { @Override public DataResult, T>> read(final DynamicOps ops, final T input) { - final Optional>> values = ops.getMapValues(input); - if (!values.isPresent()) { - return DataResult.error("Input is not a map: " + input); - } - - final T nameString = ops.createString(name); - final Optional> nameEntry = values.get().filter(v -> v.getFirst() == nameString).findFirst(); - if (!nameEntry.isPresent()) { - return DataResult.error("Input does not contain a key [" + name + "] with the name: " + input); - } - - return keyType.read(ops, nameEntry.get().getSecond()).flatMap(key -> { - final K keyValue = key.getFirst(); - final Type type = types.get(keyValue); - if (type != null) { - return type.read(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(keyValue, v))); + final DataResult>> values = ops.getMapValues(input); + return values.flatMap(vs -> { + final T nameString = ops.createString(name); + final Optional> nameEntry = vs.filter(v -> v.getFirst() == nameString).findFirst(); + if (!nameEntry.isPresent()) { + return DataResult.error("Input does not contain a key [" + name + "] with the name: " + input); } - return DataResult.error("Unsupported key: " + keyValue + " in " + this); + + return keyType.read(ops, nameEntry.get().getSecond()).flatMap(key -> { + final K keyValue = key.getFirst(); + final Type type = types.get(keyValue); + if (type != null) { + return type.read(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(keyValue, v))); + } + return DataResult.error("Unsupported key: " + keyValue + " in " + this); + }); }); } diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index a3c11c4b..886ed4b2 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -62,7 +62,7 @@ public OptionalDynamic merge(final Dynamic key, final Dynamic value) { return new OptionalDynamic<>(ops, merged.map(m -> new Dynamic<>(ops, m))); } - public Optional, Dynamic>> getMapValues() { + public DataResult, Dynamic>> getMapValues() { return ops.getMapValues(value).map(map -> { final ImmutableMap.Builder, Dynamic> builder = ImmutableMap.builder(); map.forEach(entry -> builder.put(new Dynamic<>(ops, entry.getFirst()), new Dynamic<>(ops, entry.getSecond()))); @@ -74,60 +74,58 @@ public Dynamic updateMapValues(final Function, Dynamic>, P return DataFixUtils.orElse(getMapValues().map(map -> map.entrySet().stream().map(e -> { final Pair, Dynamic> pair = updater.apply(Pair.of(e.getKey(), e.getValue())); return Pair.of(pair.getFirst().castTyped(ops), pair.getSecond().castTyped(ops)); - }).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))).map(this::createMap), this); + }).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))).map(this::createMap).result(), this); } @Override - public Optional asNumber() { + public DataResult asNumber() { return ops.getNumberValue(value); } @Override - public Optional asString() { + public DataResult asString() { return ops.getStringValue(value); } @Override - public Optional>> asStreamOpt() { + public DataResult>> asStreamOpt() { return ops.getStream(value).map(s -> s.map(e -> new Dynamic<>(ops, e))); } @Override - public Optional, Dynamic>>> asMapOpt() { + public DataResult, Dynamic>>> asMapOpt() { return ops.getMapValues(value).map(s -> s.map(p -> Pair.of(new Dynamic<>(ops, p.getFirst()), new Dynamic<>(ops, p.getSecond())))); } @Override - public Optional asByteBufferOpt() { + public DataResult asByteBufferOpt() { return ops.getByteBuffer(value); } @Override - public Optional asIntStreamOpt() { + public DataResult asIntStreamOpt() { return ops.getIntStream(value); } @Override - public Optional asLongStreamOpt() { + public DataResult asLongStreamOpt() { return ops.getLongStream(value); } @Override public OptionalDynamic get(final String key) { - final Optional>> map = ops.getMapValues(value); - if (!map.isPresent()) { - return new OptionalDynamic<>(ops, DataResult.error("not a map: " + value)); - } - final T keyString = ops.createString(key); - final Optional value = map.get().filter(p -> Objects.equals(keyString, p.getFirst())).map(Pair::getSecond).findFirst(); - if (!value.isPresent()) { - return new OptionalDynamic<>(ops, DataResult.error("key missing: " + key + " in " + this.value)); - } - return new OptionalDynamic(ops, DataResult.success(new Dynamic<>(ops, value.get()))); + return new OptionalDynamic<>(ops, ops.getMapValues(value).flatMap(m -> { + final T keyString = ops.createString(key); + final Optional value = m.filter(p -> Objects.equals(keyString, p.getFirst())).map(Pair::getSecond).findFirst(); + if (!value.isPresent()) { + return DataResult.error("key missing: " + key + " in " + this.value); + } + return DataResult.success(new Dynamic<>(ops, value.get())); + })); } @Override - public Optional getGeneric(final T key) { + public DataResult getGeneric(final T key) { return ops.getGeneric(value, key); } @@ -148,12 +146,12 @@ public Dynamic updateGeneric(final T key, final Function function) { } @Override - public Optional getElement(final String key) { + public DataResult getElement(final String key) { return getElementGeneric(ops.createString(key)); } @Override - public Optional getElementGeneric(final T key) { + public DataResult getElementGeneric(final T key) { return ops.getGeneric(value, key); } @@ -220,25 +218,25 @@ public static T convert(final DynamicOps inOps, final DynamicOps ou return outOps.createDouble(inOps.getNumberValue(input, 0).doubleValue()); } if (Objects.equals(type, DSL.bool())) { - return outOps.createBoolean(inOps.getBooleanValue(input).orElse(false)); + return outOps.createBoolean(inOps.getBooleanValue(input).result().orElse(false)); } if (Objects.equals(type, DSL.string())) { - return outOps.createString(inOps.getStringValue(input).orElse("")); + return outOps.createString(inOps.getStringValue(input).result().orElse("")); } if (Objects.equals(type, DSL.list(DSL.byteType()))) { - return outOps.createByteList(inOps.getByteBuffer(input).orElse(ByteBuffer.wrap(new byte[0]))); + return outOps.createByteList(inOps.getByteBuffer(input).result().orElse(ByteBuffer.wrap(new byte[0]))); } if (Objects.equals(type, DSL.list(DSL.intType()))) { - return outOps.createIntList(inOps.getIntStream(input).orElse(IntStream.empty())); + return outOps.createIntList(inOps.getIntStream(input).result().orElse(IntStream.empty())); } if (Objects.equals(type, DSL.list(DSL.longType()))) { - return outOps.createLongList(inOps.getLongStream(input).orElse(LongStream.empty())); + return outOps.createLongList(inOps.getLongStream(input).result().orElse(LongStream.empty())); } if (Objects.equals(type, DSL.list(DSL.remainderType()))) { - return outOps.createList(inOps.getStream(input).orElse(Stream.empty()).map(e -> convert(inOps, outOps, e))); + return outOps.createList(inOps.getStream(input).result().orElse(Stream.empty()).map(e -> convert(inOps, outOps, e))); } if (Objects.equals(type, DSL.compoundList(DSL.remainderType(), DSL.remainderType()))) { - return outOps.createMap(inOps.getMapValues(input).orElse(Stream.empty()).map(e -> + return outOps.createMap(inOps.getMapValues(input).result().orElse(Stream.empty()).map(e -> Pair.of(convert(inOps, outOps, e.getFirst()), convert(inOps, outOps, e.getSecond())) ).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); } diff --git a/src/main/java/com/mojang/serialization/DynamicLike.java b/src/main/java/com/mojang/serialization/DynamicLike.java index 6afc1cf2..a14a15d9 100644 --- a/src/main/java/com/mojang/serialization/DynamicLike.java +++ b/src/main/java/com/mojang/serialization/DynamicLike.java @@ -10,7 +10,6 @@ import java.nio.ByteBuffer; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -29,25 +28,25 @@ public DynamicOps getOps() { return ops; } - public abstract Optional asNumber(); - public abstract Optional asString(); - public abstract Optional>> asStreamOpt(); - public abstract Optional, Dynamic>>> asMapOpt(); - public abstract Optional asByteBufferOpt(); - public abstract Optional asIntStreamOpt(); - public abstract Optional asLongStreamOpt(); + public abstract DataResult asNumber(); + public abstract DataResult asString(); + public abstract DataResult>> asStreamOpt(); + public abstract DataResult, Dynamic>>> asMapOpt(); + public abstract DataResult asByteBufferOpt(); + public abstract DataResult asIntStreamOpt(); + public abstract DataResult asLongStreamOpt(); public abstract OptionalDynamic get(String key); - public abstract Optional getGeneric(T key); - public abstract Optional getElement(String key); - public abstract Optional getElementGeneric(T key); + public abstract DataResult getGeneric(T key); + public abstract DataResult getElement(String key); + public abstract DataResult getElementGeneric(T key); public abstract DataResult> decode(final Decoder decoder); - public Optional> asListOpt(final Function, U> deserializer) { + public DataResult> asListOpt(final Function, U> deserializer) { return asStreamOpt().map(stream -> stream.map(deserializer).collect(Collectors.toList())); } - public Optional> asMapOpt(final Function, K> keyDeserializer, final Function, V> valueDeserializer) { + public DataResult> asMapOpt(final Function, K> keyDeserializer, final Function, V> valueDeserializer) { return asMapOpt().map(map -> { final ImmutableMap.Builder builder = ImmutableMap.builder(); map.forEach(entry -> @@ -62,17 +61,13 @@ public DataResult read(final Decoder decoder) { } public DataResult> readList(final Decoder decoder) { - final DataResult>> stream = asStreamOpt() - .map(DataResult::success) - .orElseGet(() -> DataResult.error("Not a list")); - - return stream + return asStreamOpt() .map(s -> s.>map(d -> d.read(decoder)).collect(Collectors.toList())) .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); } public Number asNumber(final Number defaultValue) { - return asNumber().orElse(defaultValue); + return asNumber().result().orElse(defaultValue); } public int asInt(final int defaultValue) { @@ -104,39 +99,39 @@ public boolean asBoolean(final boolean defaultValue) { } public String asString(final String defaultValue) { - return asString().orElse(defaultValue); + return asString().result().orElse(defaultValue); } public Stream> asStream() { - return asStreamOpt().orElseGet(Stream::empty); + return asStreamOpt().result().orElseGet(Stream::empty); } public ByteBuffer asByteBuffer() { - return asByteBufferOpt().orElseGet(() -> ByteBuffer.wrap(new byte[0])); + return asByteBufferOpt().result().orElseGet(() -> ByteBuffer.wrap(new byte[0])); } public IntStream asIntStream() { - return asIntStreamOpt().orElseGet(IntStream::empty); + return asIntStreamOpt().result().orElseGet(IntStream::empty); } public LongStream asLongStream() { - return asLongStreamOpt().orElseGet(LongStream::empty); + return asLongStreamOpt().result().orElseGet(LongStream::empty); } public List asList(final Function, U> deserializer) { - return asListOpt(deserializer).orElseGet(ImmutableList::of); + return asListOpt(deserializer).result().orElseGet(ImmutableList::of); } public Map asMap(final Function, K> keyDeserializer, final Function, V> valueDeserializer) { - return asMapOpt(keyDeserializer, valueDeserializer).orElseGet(ImmutableMap::of); + return asMapOpt(keyDeserializer, valueDeserializer).result().orElseGet(ImmutableMap::of); } public T getElement(final String key, final T defaultValue) { - return getElement(key).orElse(defaultValue); + return getElement(key).result().orElse(defaultValue); } public T getElementGeneric(final T key, final T defaultValue) { - return getElementGeneric(key).orElse(defaultValue); + return getElementGeneric(key).result().orElse(defaultValue); } public Dynamic emptyList() { diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index 4aa2f901..ccbf6546 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -30,10 +29,10 @@ default T emptyList() { Type getType(final T input); - Optional getNumberValue(T input); + DataResult getNumberValue(T input); default Number getNumberValue(final T input, final Number defaultValue) { - return getNumberValue(input).orElse(defaultValue); + return getNumberValue(input).result().orElse(defaultValue); } T createNumeric(Number i); @@ -62,7 +61,7 @@ default T createDouble(final double value) { return createNumeric(value); } - default Optional getBooleanValue(final T input) { + default DataResult getBooleanValue(final T input) { return getNumberValue(input).map(number -> number.byteValue() != 0); } @@ -70,7 +69,7 @@ default T createBoolean(final boolean value) { return createByte((byte) (value ? 1 : 0)); } - Optional getStringValue(T input); + DataResult getStringValue(T input); T createString(String value); @@ -104,25 +103,25 @@ default DataResult mergeInto(final T map, final Map values) { return result; } - Optional>> getMapValues(T input); + DataResult>> getMapValues(T input); T createMap(Map map); - Optional> getStream(T input); + DataResult> getStream(T input); T createList(Stream input); - default Optional getByteBuffer(final T input) { + default DataResult getByteBuffer(final T input) { return getStream(input).flatMap(stream -> { final List list = stream.collect(Collectors.toList()); - if (list.stream().allMatch(element -> getNumberValue(element).isPresent())) { + if (list.stream().allMatch(element -> getNumberValue(element).result().isPresent())) { final ByteBuffer buffer = ByteBuffer.wrap(new byte[list.size()]); for (int i = 0; i < list.size(); i++) { - buffer.put(i, getNumberValue(list.get(i)).get().byteValue()); + buffer.put(i, getNumberValue(list.get(i)).result().get().byteValue()); } - return Optional.of(buffer); + return DataResult.success(buffer); } - return Optional.empty(); + return DataResult.error("Some elements are not bytes: " + input); }); } @@ -131,13 +130,13 @@ default T createByteList(final ByteBuffer input) { return createList(Stream.generate(() -> createByte(input.get(i[0]++))).limit(input.capacity())); } - default Optional getIntStream(final T input) { + default DataResult getIntStream(final T input) { return getStream(input).flatMap(stream -> { final List list = stream.collect(Collectors.toList()); - if (list.stream().allMatch(element -> getNumberValue(element).isPresent())) { - return Optional.of(list.stream().mapToInt(element -> getNumberValue(element).get().intValue())); + if (list.stream().allMatch(element -> getNumberValue(element).result().isPresent())) { + return DataResult.success(list.stream().mapToInt(element -> getNumberValue(element).result().get().intValue())); } - return Optional.empty(); + return DataResult.error("Some elements are not ints: " + input); }); } @@ -145,13 +144,13 @@ default T createIntList(final IntStream input) { return createList(input.mapToObj(this::createInt)); } - default Optional getLongStream(final T input) { + default DataResult getLongStream(final T input) { return getStream(input).flatMap(stream -> { final List list = stream.collect(Collectors.toList()); - if (list.stream().allMatch(element -> getNumberValue(element).isPresent())) { - return Optional.of(list.stream().mapToLong(element -> getNumberValue(element).get().longValue())); + if (list.stream().allMatch(element -> getNumberValue(element).result().isPresent())) { + return DataResult.success(list.stream().mapToLong(element -> getNumberValue(element).result().get().longValue())); } - return Optional.empty(); + return DataResult.error("Some elements are not longs: " + input); }); } @@ -161,12 +160,18 @@ default T createLongList(final LongStream input) { T remove(T input, String key); - default Optional get(final T input, final String key) { + default DataResult get(final T input, final String key) { return getGeneric(input, createString(key)); } - default Optional getGeneric(final T input, final T key) { - return getMapValues(input).flatMap(map -> map.filter(p -> Objects.equals(key, p.getFirst())).map(Pair::getSecond).findFirst()); + default DataResult getGeneric(final T input, final T key) { + return getMapValues(input).flatMap(map -> map + .filter(p -> Objects.equals(key, p.getFirst())) + .map(Pair::getSecond) + .findFirst() + .map(DataResult::success) + .orElseGet(() -> DataResult.error("No element " + key + " in the map " + input)) + ); } // TODO: eats error if input is not a map @@ -176,11 +181,11 @@ default T set(final T input, final String key, final T value) { // TODO: eats error if input is not a map default T update(final T input, final String key, final Function function) { - return get(input, key).map(value -> set(input, key, function.apply(value))).orElse(input); + return get(input, key).map(value -> set(input, key, function.apply(value))).result().orElse(input); } default T updateGeneric(final T input, final T key, final Function function) { - return getGeneric(input, key).flatMap(value -> mergeInto(input, key, function.apply(value)).result()).orElse(input); + return getGeneric(input, key).flatMap(value -> mergeInto(input, key, function.apply(value))).result().orElse(input); } default ListBuilder listBuilder() { diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 181e8c86..84dc74d2 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -16,7 +16,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -72,15 +71,15 @@ public Type getType(final JsonElement input) { } @Override - public Optional getNumberValue(final JsonElement input) { + public DataResult getNumberValue(final JsonElement input) { if (input.isJsonPrimitive()) { if (input.getAsJsonPrimitive().isNumber()) { - return Optional.of(input.getAsNumber()); + return DataResult.success(input.getAsNumber()); } else if (input.getAsJsonPrimitive().isBoolean()) { - return Optional.of(input.getAsBoolean() ? 1 : 0); + return DataResult.success(input.getAsBoolean() ? 1 : 0); } } - return Optional.empty(); + return DataResult.error("Not a number: " + input); } @Override @@ -89,15 +88,15 @@ public JsonElement createNumeric(final Number i) { } @Override - public Optional getBooleanValue(final JsonElement input) { + public DataResult getBooleanValue(final JsonElement input) { if (input.isJsonPrimitive()) { if (input.getAsJsonPrimitive().isBoolean()) { - return Optional.of(input.getAsBoolean()); + return DataResult.success(input.getAsBoolean()); } else if (input.getAsJsonPrimitive().isNumber()) { - return Optional.of(input.getAsNumber().byteValue() != 0); + return DataResult.success(input.getAsNumber().byteValue() != 0); } } - return Optional.empty(); + return DataResult.error("Not a boolean: " + input); } @Override @@ -106,11 +105,11 @@ public JsonElement createBoolean(final boolean value) { } @Override - public Optional getStringValue(final JsonElement input) { + public DataResult getStringValue(final JsonElement input) { if (input.isJsonPrimitive() && input.getAsJsonPrimitive().isString()) { - return Optional.of(input.getAsString()); + return DataResult.success(input.getAsString()); } - return Optional.empty(); + return DataResult.error("Not a string: " + input); } @Override @@ -195,11 +194,11 @@ public DataResult mergeInto(final JsonElement map, final Map>> getMapValues(final JsonElement input) { + public DataResult>> getMapValues(final JsonElement input) { if (input.isJsonObject()) { - return Optional.of(input.getAsJsonObject().entrySet().stream().map(entry -> Pair.of(new JsonPrimitive(entry.getKey()), entry.getValue()))); + return DataResult.success(input.getAsJsonObject().entrySet().stream().map(entry -> Pair.of(new JsonPrimitive(entry.getKey()), entry.getValue()))); } - return Optional.empty(); + return DataResult.error("Not a JSON object: " + input); } @Override @@ -212,11 +211,11 @@ public JsonElement createMap(final Map map) { } @Override - public Optional> getStream(final JsonElement input) { + public DataResult> getStream(final JsonElement input) { if (input.isJsonArray()) { - return Optional.of(StreamSupport.stream(input.getAsJsonArray().spliterator(), false)); + return DataResult.success(StreamSupport.stream(input.getAsJsonArray().spliterator(), false)); } - return Optional.empty(); + return DataResult.error("Not a json array: " + input); } @Override diff --git a/src/main/java/com/mojang/serialization/OptionalDynamic.java b/src/main/java/com/mojang/serialization/OptionalDynamic.java index 3a9df1c3..53a6d7b6 100644 --- a/src/main/java/com/mojang/serialization/OptionalDynamic.java +++ b/src/main/java/com/mojang/serialization/OptionalDynamic.java @@ -28,47 +28,43 @@ public DataResult map(final Function, U> mapper) { return delegate.map(mapper); } - public Optional flatMapOpt(final Function, Optional> mapper) { - return result().flatMap(mapper); - } - public DataResult flatMap(final Function, ? extends DataResult> mapper) { return delegate.flatMap(mapper); } @Override - public Optional asNumber() { - return flatMapOpt(DynamicLike::asNumber); + public DataResult asNumber() { + return flatMap(DynamicLike::asNumber); } @Override - public Optional asString() { - return flatMapOpt(DynamicLike::asString); + public DataResult asString() { + return flatMap(DynamicLike::asString); } @Override - public Optional>> asStreamOpt() { - return flatMapOpt(DynamicLike::asStreamOpt); + public DataResult>> asStreamOpt() { + return flatMap(DynamicLike::asStreamOpt); } @Override - public Optional, Dynamic>>> asMapOpt() { - return flatMapOpt(DynamicLike::asMapOpt); + public DataResult, Dynamic>>> asMapOpt() { + return flatMap(DynamicLike::asMapOpt); } @Override - public Optional asByteBufferOpt() { - return flatMapOpt(DynamicLike::asByteBufferOpt); + public DataResult asByteBufferOpt() { + return flatMap(DynamicLike::asByteBufferOpt); } @Override - public Optional asIntStreamOpt() { - return flatMapOpt(DynamicLike::asIntStreamOpt); + public DataResult asIntStreamOpt() { + return flatMap(DynamicLike::asIntStreamOpt); } @Override - public Optional asLongStreamOpt() { - return flatMapOpt(DynamicLike::asLongStreamOpt); + public DataResult asLongStreamOpt() { + return flatMap(DynamicLike::asLongStreamOpt); } @Override @@ -77,18 +73,18 @@ public OptionalDynamic get(final String key) { } @Override - public Optional getGeneric(final T key) { - return flatMapOpt(v -> v.getGeneric(key)); + public DataResult getGeneric(final T key) { + return flatMap(v -> v.getGeneric(key)); } @Override - public Optional getElement(final String key) { - return flatMapOpt(v -> v.getElement(key)); + public DataResult getElement(final String key) { + return flatMap(v -> v.getElement(key)); } @Override - public Optional getElementGeneric(final T key) { - return flatMapOpt(v -> v.getElementGeneric(key)); + public DataResult getElementGeneric(final T key) { + return flatMap(v -> v.getElementGeneric(key)); } public Dynamic orElseEmptyMap() { @@ -99,8 +95,8 @@ public Dynamic orElseEmptyList() { return result().orElseGet(this::emptyList); } - public Optional into(final Function, ? extends V> action) { - return result().map(action); + public DataResult into(final Function, ? extends V> action) { + return delegate.map(action); } @Override From a84c574a954055c1681530bb92f9a971ad4e3b56 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 12 Mar 2020 11:55:24 +0100 Subject: [PATCH 13/96] Pair map collector --- src/main/java/com/mojang/datafixers/DSL.java | 6 +++--- .../datafixers/types/constant/EmptyPartSaving.java | 2 +- .../com/mojang/datafixers/types/templates/Tag.java | 2 +- .../datafixers/types/templates/TaggedChoice.java | 12 ++++++------ src/main/java/com/mojang/datafixers/util/Pair.java | 7 +++++++ src/main/java/com/mojang/serialization/Dynamic.java | 4 ++-- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/DSL.java b/src/main/java/com/mojang/datafixers/DSL.java index bf358326..913cbfb2 100644 --- a/src/main/java/com/mojang/datafixers/DSL.java +++ b/src/main/java/com/mojang/datafixers/DSL.java @@ -208,11 +208,11 @@ static TaggedChoice taggedChoice(final String name, final Type keyType } static TaggedChoice taggedChoiceLazy(final String name, final Type keyType, final Map> templates) { - return taggedChoice(name, keyType, templates.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue().get())).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); + return taggedChoice(name, keyType, templates.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue().get())).collect(Pair.toMap())); } @SuppressWarnings("unchecked") - static Type> taggedChoiceType(final String name, final Type keyType, final Map> types) { + static Type> taggedChoiceType(final String name, final Type keyType, final Map> types) { return (Type>) Instances.TAGGED_CHOICE_TYPE_CACHE.computeIfAbsent(Triple.of(name, keyType, types), k -> new TaggedChoice.TaggedChoiceType<>(k.getLeft(), (Type) k.getMiddle(), (Map>) k.getRight())); } @@ -461,6 +461,6 @@ final class Instances { private static final OpticFinder> REMAINDER_FINDER = remainderType().finder(); - private static final Map, Map>>, Type>> TAGGED_CHOICE_TYPE_CACHE = Maps.newConcurrentMap(); + private static final Map, Map>>, Type>> TAGGED_CHOICE_TYPE_CACHE = Maps.newConcurrentMap(); } } diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java index d95330b6..e27e1611 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -52,7 +52,7 @@ public final DataResult write(final DynamicOps ops, final T rest, fina return DataResult.success(casted); } - final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeInto(rest, map.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)))); + final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeInto(rest, map.collect(Pair.toMap()))); return toMap.result().map(DataResult::success).orElseGet(() -> { final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeInto(rest, stream.collect(Collectors.toList()))); return toList.result().map(DataResult::success).orElseGet(() -> diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index e6ed4de1..91d3c479 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -190,7 +190,7 @@ public DataResult> read(final DynamicOps ops, final T input) { } return element.read(ops, matched.get(0).getSecond()).map(value -> - Pair.of(value.getFirst(), ops.createMap(rest.stream().collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)))) + Pair.of(value.getFirst(), ops.createMap(rest.stream().collect(Pair.toMap()))) ); }); } diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index affa3e80..0a9af501 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -68,7 +68,7 @@ public int size() { @Override public TypeFamily apply(final TypeFamily family) { return index -> types.computeIfAbsent(Pair.of(family, index), key -> - DSL.taggedChoiceType(name, keyType, templates.entrySet().stream().map(e -> Pair.>of(e.getKey(), e.getValue().apply(key.getFirst()).apply(key.getSecond()))).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))) + DSL.taggedChoiceType(name, keyType, templates.entrySet().stream().map(e -> Pair.>of(e.getKey(), e.getValue().apply(key.getFirst()).apply(key.getSecond()))).collect(Pair.toMap())) ); } @@ -138,7 +138,7 @@ public TaggedChoiceType(final String name, final Type keyType, final Map keyType, final Map updateMu(final RecursiveTypeFamily newFamily) { - return DSL.taggedChoiceType(name, keyType, types.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue().updateMu(newFamily))).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); + return DSL.taggedChoiceType(name, keyType, types.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue().updateMu(newFamily))).collect(Pair.toMap())); } @Override public TypeTemplate buildTemplate() { - return DSL.taggedChoice(name, keyType, types.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue().template())).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); + return DSL.taggedChoice(name, keyType, types.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue().template())).collect(Pair.toMap())); } @Override @@ -244,7 +244,7 @@ public Optional> findFieldTypeOpt(final String name) { e -> e.getSecond().left().isPresent() ).map( e -> e.mapSecond(o -> o.left().get()) - ).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)); + ).collect(Pair.toMap()); if (optics.isEmpty()) { return Either.right(new FieldNotFoundException("Not found in any choices")); @@ -343,7 +343,7 @@ private FT capView(final Pair s, final TypedOptic opt throw new IllegalStateException("Could not merge TaggedChoiceType optics, unknown bound: " + Arrays.toString(bounds.toArray())); } - final Map> newTypes = types.entrySet().stream().map(e -> Pair.of(e.getKey(), optics.containsKey(e.getKey()) ? optics.get(e.getKey()).tType() : e.getValue())).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)); + final Map> newTypes = types.entrySet().stream().map(e -> Pair.of(e.getKey(), optics.containsKey(e.getKey()) ? optics.get(e.getKey()).tType() : e.getValue())).collect(Pair.toMap()); return Either.left(new TypedOptic<>( bound, diff --git a/src/main/java/com/mojang/datafixers/util/Pair.java b/src/main/java/com/mojang/datafixers/util/Pair.java index b6677aeb..dfa0280e 100644 --- a/src/main/java/com/mojang/datafixers/util/Pair.java +++ b/src/main/java/com/mojang/datafixers/util/Pair.java @@ -8,8 +8,11 @@ import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.kinds.Traversable; +import java.util.Map; import java.util.Objects; import java.util.function.Function; +import java.util.stream.Collector; +import java.util.stream.Collectors; public class Pair implements App, F> { public static final class Mu implements K1 {} @@ -69,6 +72,10 @@ public static Pair of(final F first, final S second) { return new Pair<>(first, second); } + public static Collector, ?, Map> toMap() { + return Collectors.toMap(Pair::getFirst, Pair::getSecond); + } + public static final class Instance implements Traversable, Instance.Mu>, CartesianLike, S2, Instance.Mu> { public static final class Mu implements Traversable.Mu, CartesianLike.Mu {} diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index 886ed4b2..95bfb5db 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -74,7 +74,7 @@ public Dynamic updateMapValues(final Function, Dynamic>, P return DataFixUtils.orElse(getMapValues().map(map -> map.entrySet().stream().map(e -> { final Pair, Dynamic> pair = updater.apply(Pair.of(e.getKey(), e.getValue())); return Pair.of(pair.getFirst().castTyped(ops), pair.getSecond().castTyped(ops)); - }).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))).map(this::createMap).result(), this); + }).collect(Pair.toMap())).map(this::createMap).result(), this); } @Override @@ -238,7 +238,7 @@ public static T convert(final DynamicOps inOps, final DynamicOps ou if (Objects.equals(type, DSL.compoundList(DSL.remainderType(), DSL.remainderType()))) { return outOps.createMap(inOps.getMapValues(input).result().orElse(Stream.empty()).map(e -> Pair.of(convert(inOps, outOps, e.getFirst()), convert(inOps, outOps, e.getSecond())) - ).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); + ).collect(Pair.toMap())); } throw new IllegalStateException("Could not convert value of type " + type); } From ffbd838cbef3fbd42fd1238a5e18891a061fdf87 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 12 Mar 2020 12:44:50 +0100 Subject: [PATCH 14/96] Java boilerplate for DataResult --- .../com/mojang/serialization/DataResult.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index ced5eab3..fc94378e 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -7,6 +7,7 @@ import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.util.Either; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -105,6 +106,28 @@ public static Instance instance() { return Instance.INSTANCE; } + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final DataResult that = (DataResult) o; + return Objects.equals(result, that.result); + } + + @Override + public int hashCode() { + return Objects.hash(result); + } + + @Override + public String toString() { + return "DataResult[" + result + ']'; + } + public static class DynamicException { private final String message; private final Optional partialResult; @@ -133,6 +156,28 @@ public DynamicException flatMap(final Function> public String message() { return message; } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final DynamicException that = (DynamicException) o; + return Objects.equals(message, that.message) && Objects.equals(partialResult, that.partialResult); + } + + @Override + public int hashCode() { + return Objects.hash(message, partialResult); + } + + @Override + public String toString() { + return "DynamicException[" + message + ' ' + partialResult + ']'; + } } public enum Instance implements Applicative { From 4f838a617c9d815654d86b18d844db2c437e39c1 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 12 Mar 2020 14:12:13 +0100 Subject: [PATCH 15/96] Decoder factories improvements --- .../datafixers/types/templates/Named.java | 13 ++++------ .../datafixers/types/templates/Tag.java | 14 ++++------- .../java/com/mojang/serialization/Codec.java | 24 ------------------- .../com/mojang/serialization/Decoder.java | 24 +++++++++++++++++++ 4 files changed, 32 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/types/templates/Named.java b/src/main/java/com/mojang/datafixers/types/templates/Named.java index a365b22a..f18fbee8 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Named.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Named.java @@ -4,8 +4,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.FamilyOptic; import com.mojang.datafixers.RewriteResult; @@ -15,16 +13,17 @@ import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.profunctors.Cartesian; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.Objects; import java.util.Optional; -import java.util.function.Function; import java.util.function.IntFunction; public final class Named implements TypeTemplate { @@ -181,10 +180,6 @@ public int hashCode() { return Objects.hash(name, element); } - public NamedType map(final Function, ? extends Type> function) { - return new NamedType<>(name, function.apply(element)); - } - @Override public Optional> findFieldTypeOpt(final String name) { return element.findFieldTypeOpt(name); diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index 91d3c479..ccba5283 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -2,8 +2,6 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.templates; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.FamilyOptic; import com.mojang.datafixers.RewriteResult; @@ -11,21 +9,21 @@ import com.mojang.datafixers.TypedOptic; import com.mojang.datafixers.View; import com.mojang.datafixers.functions.Functions; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.function.Function; import java.util.function.IntFunction; import java.util.stream.Collectors; -import java.util.stream.Stream; public final class Tag implements TypeTemplate { private final String name; @@ -222,10 +220,6 @@ public int hashCode() { return Objects.hash(name, element); } - public TagType map(final Function, ? extends Type> function) { - return new TagType<>(name, function.apply(element)); - } - @Override public Optional> findFieldTypeOpt(final String name) { if (Objects.equals(name, this.name)) { diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index a7c49d0c..c4ae1457 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -9,30 +9,6 @@ static Codec of(final Decoder decoder) { return of(Encoder.of(), decoder); } - static Codec of(final Terminal terminal) { - return of(Encoder.of(), terminal.decoder()); - } - - static Codec of(final Boxed boxed) { - return of(Encoder.of(), boxed.decoder()); - } - - static Codec of(final Simple simple) { - return of(Encoder.of(), simple.decoder()); - } - - static Codec of(final Encoder encoder, final Terminal terminal) { - return of(encoder, terminal.decoder()); - } - - static Codec of(final Encoder encoder, final Boxed boxed) { - return of(encoder, boxed.decoder()); - } - - static Codec of(final Encoder encoder, final Simple terminal) { - return of(encoder, terminal.decoder()); - } - static Codec of(final Encoder encoder, final Decoder decoder) { return new Codec() { @Override diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 8a4e4bb2..b984b837 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -4,6 +4,8 @@ import com.mojang.datafixers.util.Pair; +import java.util.function.Function; + public interface Decoder { DataResult> decode(final DynamicOps ops, final T input); @@ -32,6 +34,28 @@ default Simple simple() { return this::parse; } + default Decoder map(final Function function) { + final Decoder self = this; + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return self.decode(ops, input).map(p -> p.mapFirst(function)); + } + }; + } + + static Decoder ofTerminal(final Terminal terminal) { + return terminal.decoder().map(Function.identity()); + } + + static Decoder ofBoxed(final Boxed boxed) { + return boxed.decoder().map(Function.identity()); + } + + static Decoder ofSimple(final Simple simple) { + return simple.decoder().map(Function.identity()); + } + interface Terminal { DataResult decode(final DynamicOps ops, final T input); From f7f622402a5f36227b07473c2cc01efd4bfdf439 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 14 Mar 2020 08:46:24 +0100 Subject: [PATCH 16/96] Renamed mergeInto to either mergeToList or mergeToMap, added mergeToPrimitive. --- .../types/constant/EmptyPartSaving.java | 5 ++-- .../types/templates/CompoundList.java | 3 +- .../datafixers/types/templates/Const.java | 5 +--- .../datafixers/types/templates/List.java | 2 +- .../datafixers/types/templates/Tag.java | 2 +- .../types/templates/TaggedChoice.java | 3 +- .../com/mojang/serialization/Dynamic.java | 5 ++-- .../com/mojang/serialization/DynamicOps.java | 28 ++++++++++++------- .../com/mojang/serialization/JsonOps.java | 18 ++++++------ .../com/mojang/serialization/ListBuilder.java | 2 +- .../mojang/serialization/RecordBuilder.java | 2 +- 11 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java index e27e1611..080ac932 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -11,7 +11,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import java.util.stream.Stream; public final class EmptyPartSaving extends com.mojang.datafixers.types.Type> { @Override @@ -52,9 +51,9 @@ public final DataResult write(final DynamicOps ops, final T rest, fina return DataResult.success(casted); } - final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeInto(rest, map.collect(Pair.toMap()))); + final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeToMap(rest, map.collect(Pair.toMap()))); return toMap.result().map(DataResult::success).orElseGet(() -> { - final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeInto(rest, stream.collect(Collectors.toList()))); + final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeToList(rest, stream.collect(Collectors.toList()))); return toList.result().map(DataResult::success).orElseGet(() -> DataResult.error("Don't know how to merge " + rest + " and " + casted, rest) ); diff --git a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java index 526408f5..4eeffe67 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java +++ b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java @@ -35,7 +35,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; -import java.util.stream.Stream; public final class CompoundList implements TypeTemplate { private final TypeTemplate key; @@ -224,7 +223,7 @@ public DataResult write(final DynamicOps ops, final T rest, final List }); } - return result.flatMap(m -> ops.mergeInto(rest, m)); + return result.flatMap(m -> ops.mergeToMap(rest, m)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Const.java b/src/main/java/com/mojang/datafixers/types/templates/Const.java index 639dee7f..5093ab86 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Const.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Const.java @@ -110,10 +110,7 @@ public TypeTemplate buildTemplate() { @Override public final DataResult write(final DynamicOps ops, final T rest, final A value) { - if (rest != ops.empty()) { - return DataResult.error("Do not know how to append a primitive value " + value + " to " + rest, doWrite(ops, value)); - } - return DataResult.success(doWrite(ops, value)); + return ops.mergeToPrimitive(rest, doWrite(ops, value)); } protected abstract T doWrite(final DynamicOps ops, final A value); diff --git a/src/main/java/com/mojang/datafixers/types/templates/List.java b/src/main/java/com/mojang/datafixers/types/templates/List.java index 6fea5628..6483d70a 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/List.java +++ b/src/main/java/com/mojang/datafixers/types/templates/List.java @@ -199,7 +199,7 @@ public DataResult write(final DynamicOps ops, final T rest, final java }); } - return result.flatMap(l -> ops.mergeInto(rest, l)); + return result.flatMap(l -> ops.mergeToList(rest, l)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index ccba5283..5aaa9dc0 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -195,7 +195,7 @@ public DataResult> read(final DynamicOps ops, final T input) { @Override public DataResult write(final DynamicOps ops, final T rest, final A value) { - return element.write(ops, ops.empty(), value).flatMap(result -> ops.mergeInto(rest, ops.createString(name), result)); + return element.write(ops, ops.empty(), value).flatMap(result -> ops.mergeToMap(rest, ops.createString(name), result)); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index 0a9af501..ec093861 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -43,7 +43,6 @@ import java.util.Set; import java.util.function.Function; import java.util.function.IntFunction; -import java.util.stream.Collectors; import java.util.stream.Stream; public final class TaggedChoice implements TypeTemplate { @@ -214,7 +213,7 @@ public DataResult write(final DynamicOps ops, final T rest, final Pair private DataResult capWrite(final DynamicOps ops, final Type type, final K key, final Object value, final T rest) { return keyType.write(ops, ops.empty(), key).flatMap(k -> type.write(ops, rest, (A) value).flatMap(v -> - ops.mergeInto(v, ops.createString(name), k) + ops.mergeToMap(v, ops.createString(name), k) ) ); } diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index 95bfb5db..70577b96 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -14,7 +14,6 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.LongStream; import java.util.stream.Stream; @@ -53,12 +52,12 @@ public U cast(final DynamicOps ops) { } public OptionalDynamic merge(final Dynamic value) { - final DataResult merged = ops.mergeInto(this.value, value.cast(ops)); + final DataResult merged = ops.mergeToList(this.value, value.cast(ops)); return new OptionalDynamic<>(ops, merged.map(m -> new Dynamic<>(ops, m))); } public OptionalDynamic merge(final Dynamic key, final Dynamic value) { - final DataResult merged = ops.mergeInto(this.value, key.cast(ops), value.cast(ops)); + final DataResult merged = ops.mergeToMap(this.value, key.cast(ops), value.cast(ops)); return new OptionalDynamic<>(ops, merged.map(m -> new Dynamic<>(ops, m))); } diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index ccbf6546..fea11254 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -75,34 +75,42 @@ default T createBoolean(final boolean value) { /** * Only successful if first argument is a list/array or empty - * @return */ - DataResult mergeInto(T list, T value); + DataResult mergeToList(T list, T value); - default DataResult mergeInto(final T list, final List values) { + default DataResult mergeToList(final T list, final List values) { DataResult result = DataResult.success(list); for (final T value : values) { - result = result.flatMap(r -> mergeInto(r, value)); + result = result.flatMap(r -> mergeToList(r, value)); } return result; } /** * Only successful if first argument is a map or empty - * @return */ - DataResult mergeInto(T map, T key, T value); + DataResult mergeToMap(T map, T key, T value); - default DataResult mergeInto(final T map, final Map values) { + default DataResult mergeToMap(final T map, final Map values) { DataResult result = DataResult.success(map); for (final Map.Entry entry : values.entrySet()) { - result = result.flatMap(r -> mergeInto(r, entry.getKey(), entry.getValue())); + result = result.flatMap(r -> mergeToMap(r, entry.getKey(), entry.getValue())); } return result; } + /** + * Only successful if first argument is empty + */ + default DataResult mergeToPrimitive(final T prefix, final T value) { + if (!Objects.equals(prefix, empty())) { + return DataResult.error("Do not know how to append a primitive value " + value + " to " + prefix, value); + } + return DataResult.success(value); + } + DataResult>> getMapValues(T input); T createMap(Map map); @@ -176,7 +184,7 @@ default DataResult getGeneric(final T input, final T key) { // TODO: eats error if input is not a map default T set(final T input, final String key, final T value) { - return mergeInto(input, createString(key), value).result().orElse(input); + return mergeToMap(input, createString(key), value).result().orElse(input); } // TODO: eats error if input is not a map @@ -185,7 +193,7 @@ default T update(final T input, final String key, final Function function) } default T updateGeneric(final T input, final T key, final Function function) { - return getGeneric(input, key).flatMap(value -> mergeInto(input, key, function.apply(value))).result().orElse(input); + return getGeneric(input, key).flatMap(value -> mergeToMap(input, key, function.apply(value))).result().orElse(input); } default ListBuilder listBuilder() { diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 84dc74d2..d6ba90f2 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -118,9 +118,9 @@ public JsonElement createString(final String value) { } @Override - public DataResult mergeInto(final JsonElement list, final JsonElement value) { + public DataResult mergeToList(final JsonElement list, final JsonElement value) { if (!list.isJsonArray() && list != empty()) { - return DataResult.error("mergeInto called with not a list: " + list, list); + return DataResult.error("mergeToList called with not a list: " + list, list); } final JsonArray result = new JsonArray(); @@ -132,9 +132,9 @@ public DataResult mergeInto(final JsonElement list, final JsonEleme } @Override - public DataResult mergeInto(final JsonElement list, final List values) { + public DataResult mergeToList(final JsonElement list, final List values) { if (!list.isJsonArray() && list != empty()) { - return DataResult.error("mergeInto called with not a list: " + list, list); + return DataResult.error("mergeToList called with not a list: " + list, list); } final JsonArray result = new JsonArray(); @@ -146,9 +146,9 @@ public DataResult mergeInto(final JsonElement list, final List mergeInto(final JsonElement map, final JsonElement key, final JsonElement value) { + public DataResult mergeToMap(final JsonElement map, final JsonElement key, final JsonElement value) { if (!map.isJsonObject() && map != empty()) { - return DataResult.error("mergeInto called with not a map: " + map, map); + return DataResult.error("mergeToMap called with not a map: " + map, map); } if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString()) { return DataResult.error("key is not a string: " + key, map); @@ -164,9 +164,9 @@ public DataResult mergeInto(final JsonElement map, final JsonElemen } @Override - public DataResult mergeInto(final JsonElement map, final Map values) { + public DataResult mergeToMap(final JsonElement map, final Map values) { if (!map.isJsonObject() && map != empty()) { - return DataResult.error("mergeInto called with not a map: " + map, map); + return DataResult.error("mergeToMap called with not a map: " + map, map); } final JsonObject output = new JsonObject(); @@ -273,7 +273,7 @@ public ListBuilder add(final DataResult value) { @Override public DataResult build(final JsonElement prefix) { - final DataResult result = builder.flatMap(b -> INSTANCE.mergeInto(prefix, b)); + final DataResult result = builder.flatMap(b -> INSTANCE.mergeToList(prefix, b)); builder = DataResult.success(new JsonArray()); return result; } diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index f9546713..fb31e4dd 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -53,7 +53,7 @@ public ListBuilder add(final DataResult value) { @Override public DataResult build(final T prefix) { - final DataResult result = builder.flatMap(b -> ops.mergeInto(prefix, b.build())); + final DataResult result = builder.flatMap(b -> ops.mergeToList(prefix, b.build())); builder = DataResult.success(ImmutableList.builder()); return result; } diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 825618f3..70b7b569 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -64,7 +64,7 @@ public RecordBuilder add(final DataResult key, final DataResult value) @Override public DataResult build(final T prefix) { - final DataResult result = builder.flatMap(b -> ops.mergeInto(prefix, b.build())); + final DataResult result = builder.flatMap(b -> ops.mergeToMap(prefix, b.build())); builder = DataResult.success(ImmutableMap.builder()); return result; } From 70f54be0f718a1ed41e72c269c7f38be353fea78 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 14 Mar 2020 08:47:26 +0100 Subject: [PATCH 17/96] Made ListBox invariant, added a bunch of dynamic helpers. --- .../com/mojang/datafixers/kinds/ListBox.java | 12 +++---- .../com/mojang/serialization/DataResult.java | 9 +++++ .../com/mojang/serialization/Decoder.java | 9 +++++ .../com/mojang/serialization/DynamicLike.java | 33 ++++++++++++++++-- .../com/mojang/serialization/DynamicOps.java | 34 ++++++++++++++++--- .../com/mojang/serialization/Encoder.java | 4 +++ .../com/mojang/serialization/ListBuilder.java | 9 +++++ .../mojang/serialization/RecordBuilder.java | 4 +++ .../mojang/serialization/Serializable.java | 4 +++ 9 files changed, 105 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/kinds/ListBox.java b/src/main/java/com/mojang/datafixers/kinds/ListBox.java index b5993a72..0e3ccd86 100644 --- a/src/main/java/com/mojang/datafixers/kinds/ListBox.java +++ b/src/main/java/com/mojang/datafixers/kinds/ListBox.java @@ -11,25 +11,25 @@ public final class ListBox implements App { public static final class Mu implements K1 {} - public static List unbox(final App box) { + public static List unbox(final App box) { return ((ListBox) box).value; } - public static ListBox create(final List value) { + public static ListBox create(final List value) { return new ListBox<>(value); } - private final List value; + private final List value; - private ListBox(final List value) { + private ListBox(final List value) { this.value = value; } - public static App> traverse(final Applicative applicative, final Function> function, final List input) { + public static App> traverse(final Applicative applicative, final Function> function, final List input) { return applicative.map(ListBox::unbox, Instance.INSTANCE.traverse(applicative, function, create(input))); } - public static App> flip(final Applicative applicative, final List> input) { + public static App> flip(final Applicative applicative, final List> input) { return applicative.map(ListBox::unbox, Instance.INSTANCE.flip(applicative, create(input))); } diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index fc94378e..876266d8 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -12,6 +12,7 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; public class DataResult implements App { public static final class Mu implements K1 {} @@ -102,6 +103,14 @@ public DataResult flatMap(final Function setPartial(final Supplier partial) { + return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial.get())))); + } + + public DataResult setPartial(final R partial) { + return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial)))); + } + public static Instance instance() { return Instance.INSTANCE; } diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index b984b837..27577e35 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -56,6 +56,15 @@ static Decoder ofSimple(final Simple simple) { return simple.decoder().map(Function.identity()); } + static Decoder unit(final A instance) { + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return DataResult.success(Pair.of(instance, input)); + } + }; + } + interface Terminal { DataResult decode(final DynamicOps ops, final T input); diff --git a/src/main/java/com/mojang/serialization/DynamicLike.java b/src/main/java/com/mojang/serialization/DynamicLike.java index a14a15d9..3adc5b7a 100644 --- a/src/main/java/com/mojang/serialization/DynamicLike.java +++ b/src/main/java/com/mojang/serialization/DynamicLike.java @@ -4,12 +4,15 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.ListBox; +import com.mojang.datafixers.util.Function3; import com.mojang.datafixers.util.Pair; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -60,12 +63,38 @@ public DataResult read(final Decoder decoder) { return decode(decoder).map(Pair::getFirst); } - public DataResult> readList(final Decoder decoder) { + public DataResult> readList(final Decoder decoder) { return asStreamOpt() - .map(s -> s.>map(d -> d.read(decoder)).collect(Collectors.toList())) + .map(s -> s.map(d -> d.read(decoder)).collect(Collectors.>toList())) + .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); + } + + public DataResult> readList(final Function, ? extends DataResult> decoder) { + return asStreamOpt() + .map(s -> s.map(decoder).map(r -> r.map(e -> (E) e)).collect(Collectors.>toList())) + .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); + } + + public DataResult>> readMap(final Decoder keyDecoder, final Decoder valueDecoder) { + return asMapOpt() + .map(stream -> stream.map(p -> p.getFirst().read(keyDecoder).flatMap(f -> p.getSecond().read(valueDecoder).map(s -> Pair.of(f, s)))).collect(Collectors.>>toList())) .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); } + public DataResult>> readMap(final Decoder keyDecoder, final Function> valueDecoder) { + return asMapOpt() + .map(stream -> stream.map(p -> p.getFirst().read(keyDecoder).flatMap(f -> p.getSecond().read(valueDecoder.apply(f)).map(s -> Pair.of(f, s)))).collect(Collectors.>>toList())) + .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); + } + + public DataResult readMap(final DataResult empty, final Function3, Dynamic, DataResult> combiner) { + return asMapOpt().flatMap(stream -> { + final AtomicReference> result = new AtomicReference<>(empty); + stream.forEach(p -> result.set(result.get().flatMap(r -> combiner.apply(r, p.getFirst(), p.getSecond())))); + return result.get(); + }); + } + public Number asNumber(final Number defaultValue) { return asNumber().result().orElse(defaultValue); } diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index fea11254..ecf14332 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -4,12 +4,14 @@ import com.google.common.collect.ImmutableMap; import com.mojang.datafixers.types.Type; +import com.mojang.datafixers.util.Function3; import com.mojang.datafixers.util.Pair; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -208,6 +210,12 @@ default DataResult list(final Iterable list, final T return list(list, prefix, e -> e.serialize(this, elementPrefix)); } + default DataResult list(final Iterable list, final T prefix, final Encoder encoder) { + final ListBuilder builder = listBuilder(); + builder.addAll(list, encoder); + return builder.build(prefix); + } + default DataResult list(final Iterable list, final T prefix, final Function> elementSerializer) { final ListBuilder builder = listBuilder(); list.forEach(element -> builder.add(elementSerializer.apply(element))); @@ -218,13 +226,29 @@ default RecordBuilder mapBuilder() { return new RecordBuilder.Builder<>(this); } - default DataResult map(final Map map, final T prefix) { - return map(map, prefix, Function.identity(), e -> e.serialize(this, empty())); - } - - default DataResult map(final Map map, final T prefix, final Function keySerializer, final Function> elementSerializer) { + default DataResult map(final Map map, final T prefix, final Function> keySerializer, final Function> elementSerializer) { final RecordBuilder builder = mapBuilder(); map.forEach((key, value) -> builder.add(keySerializer.apply(key), elementSerializer.apply(value))); return builder.build(prefix); } + + default DataResult readMap(final T input, final DataResult empty, final Function3> combiner) { + return getMapValues(input).flatMap(stream -> { + final AtomicReference> result = new AtomicReference<>(empty); + stream.forEach(p -> result.set(result.get().flatMap(r -> combiner.apply(r, p.getFirst(), p.getSecond())))); + return result.get(); + }); + } + + default Function> withEncoder(final Encoder encoder) { + return e -> encoder.encodeStart(this, e); + } + + default Function>> withDecoder(final Decoder decoder) { + return t -> decoder.decode(this, t); + } + + default Function> withParser(final Decoder decoder) { + return t -> decoder.parse(this, t); + } } diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index 16233967..e3ca01fd 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -5,6 +5,10 @@ public interface Encoder { DataResult encode(final DynamicOps ops, final T prefix, final A input); + default DataResult encodeStart(final DynamicOps ops, final A input) { + return encode(ops, ops.empty(), input); + } + static Encoder of() { return new Encoder() { @Override diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index fb31e4dd..36d935bb 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -13,6 +13,10 @@ public interface ListBuilder { ListBuilder add(final DataResult value); + default DataResult build(final DataResult prefix) { + return prefix.flatMap(this::build); + } + default ListBuilder add(final Serializable value) { return add(value, ops().empty()); } @@ -26,6 +30,11 @@ default ListBuilder addAll(final Iterable values) { return this; } + default ListBuilder addAll(final Iterable values, final Encoder encoder) { + values.forEach(v -> encoder.encode(ops(), ops().empty(), v)); + return this; + } + final class Builder implements ListBuilder { private final DynamicOps ops; private DataResult> builder = DataResult.success(ImmutableList.builder()); diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 70b7b569..6b00a3fa 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -15,6 +15,10 @@ public interface RecordBuilder { DataResult build(T prefix); + default DataResult build(final DataResult prefix) { + return prefix.flatMap(this::build); + } + default RecordBuilder add(final String key, final T value) { return add(ops().createString(key), value); } diff --git a/src/main/java/com/mojang/serialization/Serializable.java b/src/main/java/com/mojang/serialization/Serializable.java index 3b98e244..4415e3c7 100644 --- a/src/main/java/com/mojang/serialization/Serializable.java +++ b/src/main/java/com/mojang/serialization/Serializable.java @@ -4,4 +4,8 @@ public interface Serializable { DataResult serialize(final DynamicOps ops, final T prefix); + + default DataResult serializeStart(final DynamicOps ops) { + return serialize(ops, ops.empty()); + } } From 7ababc215f24e3e59ba0c373d03b18117fa6bca9 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 14 Mar 2020 09:53:48 +0100 Subject: [PATCH 18/96] Split off codecs and types. --- src/main/java/com/mojang/datafixers/DSL.java | 11 +- .../com/mojang/datafixers/types/Func.java | 18 ++-- .../com/mojang/datafixers/types/Type.java | 30 +++--- .../datafixers/types/constant/BoolType.java | 5 +- .../datafixers/types/constant/ByteType.java | 5 +- .../datafixers/types/constant/DoubleType.java | 5 +- .../datafixers/types/constant/EmptyPart.java | 14 +-- .../types/constant/EmptyPartSaving.java | 52 +++++---- .../datafixers/types/constant/FloatType.java | 5 +- .../datafixers/types/constant/IntType.java | 5 +- .../datafixers/types/constant/LongType.java | 5 +- .../types/constant/NamespacedStringType.java | 5 +- .../datafixers/types/constant/ShortType.java | 5 +- .../datafixers/types/constant/StringType.java | 6 +- .../datafixers/types/templates/Check.java | 27 ++--- .../types/templates/CompoundList.java | 63 ++--------- .../datafixers/types/templates/Const.java | 20 +++- .../datafixers/types/templates/Hook.java | 28 +++-- .../datafixers/types/templates/List.java | 49 +-------- .../datafixers/types/templates/Named.java | 26 +++-- .../datafixers/types/templates/Product.java | 21 ++-- .../types/templates/RecursivePoint.java | 27 +++-- .../datafixers/types/templates/Sum.java | 23 +--- .../datafixers/types/templates/Tag.java | 48 +++++---- .../types/templates/TaggedChoice.java | 71 +++++++------ .../com/mojang/datafixers/util/Either.java | 62 ++++++++++- .../java/com/mojang/datafixers/util/Pair.java | 53 ++++++++++ .../com/mojang/serialization/Decoder.java | 19 ++++ .../com/mojang/serialization/Encoder.java | 28 +++++ .../codecs/CompoundListCodec.java | 100 ++++++++++++++++++ .../serialization/codecs/ListCodec.java | 85 +++++++++++++++ 31 files changed, 592 insertions(+), 329 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java create mode 100644 src/main/java/com/mojang/serialization/codecs/ListCodec.java diff --git a/src/main/java/com/mojang/datafixers/DSL.java b/src/main/java/com/mojang/datafixers/DSL.java index 913cbfb2..65bb7fa9 100644 --- a/src/main/java/com/mojang/datafixers/DSL.java +++ b/src/main/java/com/mojang/datafixers/DSL.java @@ -3,21 +3,18 @@ package com.mojang.datafixers; import com.google.common.collect.Maps; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.util.Unit; import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.types.Func; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.constant.BoolType; import com.mojang.datafixers.types.constant.ByteType; import com.mojang.datafixers.types.constant.DoubleType; +import com.mojang.datafixers.types.constant.EmptyPart; +import com.mojang.datafixers.types.constant.EmptyPartSaving; import com.mojang.datafixers.types.constant.FloatType; import com.mojang.datafixers.types.constant.IntType; import com.mojang.datafixers.types.constant.LongType; import com.mojang.datafixers.types.constant.NamespacedStringType; -import com.mojang.datafixers.types.constant.EmptyPart; -import com.mojang.datafixers.types.constant.EmptyPartSaving; import com.mojang.datafixers.types.constant.ShortType; import com.mojang.datafixers.types.constant.StringType; import com.mojang.datafixers.types.templates.Check; @@ -32,6 +29,9 @@ import com.mojang.datafixers.types.templates.Tag; import com.mojang.datafixers.types.templates.TaggedChoice; import com.mojang.datafixers.types.templates.TypeTemplate; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.datafixers.util.Unit; import com.mojang.serialization.Dynamic; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.tuple.Triple; @@ -39,7 +39,6 @@ import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; -import java.util.stream.Collectors; public interface DSL { interface TypeReference { diff --git a/src/main/java/com/mojang/datafixers/types/Func.java b/src/main/java/com/mojang/datafixers/types/Func.java index 7bf2a4f4..07c2a3f5 100644 --- a/src/main/java/com/mojang/datafixers/types/Func.java +++ b/src/main/java/com/mojang/datafixers/types/Func.java @@ -3,9 +3,9 @@ package com.mojang.datafixers.types; import com.mojang.datafixers.types.templates.TypeTemplate; -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Codec; +import com.mojang.serialization.Decoder; +import com.mojang.serialization.Encoder; import java.util.Objects; import java.util.function.Function; @@ -25,13 +25,11 @@ public TypeTemplate buildTemplate() { } @Override - public DataResult, T>> read(final DynamicOps ops, final T input) { - return DataResult.error("Cannot read a function"); - } - - @Override - public DataResult write(final DynamicOps ops, final T rest, final Function value) { - return DataResult.error("Cannot save a function " + value, rest); + protected Codec> buildCodec() { + return Codec.of( + Encoder.error("Cannot save a function"), + Decoder.error("Cannot read a function") + ); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/Type.java b/src/main/java/com/mojang/datafixers/types/Type.java index 071f487d..d70d450e 100644 --- a/src/main/java/com/mojang/datafixers/types/Type.java +++ b/src/main/java/com/mojang/datafixers/types/Type.java @@ -35,7 +35,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; -public abstract class Type implements App, Codec { +public abstract class Type implements App { private static final Map, TypeRewriteRule, PointFreeRule>, CompletableFuture>>> PENDING_REWRITE_CACHE = Maps.newConcurrentMap(); private static final Map, TypeRewriteRule, PointFreeRule>, Optional>> REWRITE_CACHE = Maps.newConcurrentMap(); @@ -48,6 +48,8 @@ public static Type unbox(final App box) { @Nullable private TypeTemplate template; + private final Codec codec = buildCodec(); + public RewriteResult rewriteOrNop(final TypeRewriteRule rule) { return DataFixUtils.orElseGet(rule.rewrite(this), () -> RewriteResult.nop(this)); } @@ -110,25 +112,17 @@ public Optional> findCheckedType(final int index) { } public final DataResult>> read(final Dynamic input) { - return read(input.getOps(), input.getValue()).map(v -> v.mapSecond(t -> new Dynamic(input.getOps(), t))); + return codec().decode(input.getOps(), input.getValue()).map(v -> v.mapSecond(t -> new Dynamic(input.getOps(), t))); } - public abstract DataResult> read(final DynamicOps ops, final T input); - - public abstract DataResult write(final DynamicOps ops, final T rest, final A value); - - @Override - public final DataResult> decode(final DynamicOps ops, final T input) { - return read(ops, input); + public final Codec codec() { + return codec; } - @Override - public final DataResult encode(final DynamicOps ops, final T prefix, final A input) { - return write(ops, prefix, input); - } + protected abstract Codec buildCodec(); public final DataResult write(final DynamicOps ops, final A value) { - return write(ops, ops.empty(), value); + return codec().encode(ops, ops.empty(), value); } public final DataResult> writeDynamic(final DynamicOps ops, final A value) { @@ -140,11 +134,11 @@ public DataResult, T>> readTyped(final Dynamic input) { } public DataResult, T>> readTyped(final DynamicOps ops, final T input) { - return read(ops, input).map(vo -> vo.mapFirst(v -> new Typed<>(this, ops, v))); + return codec().decode(ops, input).map(vo -> vo.mapFirst(v -> new Typed<>(this, ops, v))); } public DataResult, T>> read(final DynamicOps ops, final TypeRewriteRule rule, final PointFreeRule fRule, final T input) { - return read(ops, input).map(vo -> vo.mapFirst(v -> + return codec().decode(ops, input).map(vo -> vo.mapFirst(v -> rewrite(rule, fRule).map(r -> r.view().function().evalCached().apply(ops).apply(v) ) )); @@ -157,7 +151,7 @@ public DataResult readAndWrite(final DynamicOps ops, final Type exp } final View view = rewriteResult.get().view(); - return read(ops, input).flatMap(pair -> + return codec().decode(ops, input).flatMap(pair -> capWrite(ops, expectedType, pair.getSecond(), pair.getFirst(), view) ); } @@ -166,7 +160,7 @@ private DataResult capWrite(final DynamicOps ops, final Type exp if (!expectedType.equals(f.newType(), true, true)) { return DataResult.error("Rewritten type doesn't match"); } - return f.newType().write(ops, rest, f.function().evalCached().apply(ops).apply(value)); + return f.newType().codec().encode(ops, rest, f.function().evalCached().apply(ops).apply(value)); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java index 1cceecab..0db0f205 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java @@ -3,16 +3,15 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.types.templates.Const; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; public final class BoolType extends Const.PrimitiveType { @Override - public DataResult> read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(v.intValue() != 0, ops.empty())); + .map(v -> v.intValue() != 0); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java index 637bd68e..1d2b7d5f 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java @@ -3,16 +3,15 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.types.templates.Const; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; public final class ByteType extends Const.PrimitiveType { @Override - public DataResult> read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(v.byteValue(), ops.empty())); + .map(Number::byteValue); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java index e4e83d63..91533b62 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java @@ -3,16 +3,15 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.types.templates.Const; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; public final class DoubleType extends Const.PrimitiveType { @Override - public DataResult> read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(v.doubleValue(), ops.empty())); + .map(Number::doubleValue); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java index 14afb8c1..da166aad 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java @@ -4,10 +4,11 @@ import com.mojang.datafixers.DSL; import com.mojang.datafixers.types.templates.TypeTemplate; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Unit; -import com.mojang.serialization.DataResult; +import com.mojang.serialization.Codec; +import com.mojang.serialization.Decoder; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Encoder; import java.util.Optional; @@ -33,12 +34,7 @@ public TypeTemplate buildTemplate() { } @Override - public DataResult> read(final DynamicOps ops, final T input) { - return DataResult.success(Pair.of(Unit.INSTANCE, input)); - } - - @Override - public final DataResult write(final DynamicOps ops, final T rest, final Unit value) { - return DataResult.success(rest); + protected Codec buildCodec() { + return Codec.of(Encoder.empty(), Decoder.unit(Unit.INSTANCE)); } } diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java index 080ac932..4474a513 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -5,6 +5,7 @@ import com.mojang.datafixers.DSL; import com.mojang.datafixers.types.templates.TypeTemplate; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; @@ -34,29 +35,34 @@ public TypeTemplate buildTemplate() { } @Override - public DataResult, T>> read(final DynamicOps ops, final T input) { - return DataResult.success(Pair.of(new Dynamic<>(ops, input), ops.empty())); - } + public Codec> buildCodec() { + return new Codec>() { + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + return DataResult.success(Pair.of(new Dynamic<>(ops, input), ops.empty())); + } - @Override - public final DataResult write(final DynamicOps ops, final T rest, final Dynamic value) { - if (value.getValue() == value.getOps().empty()) { - // nothing to merge, return rest - return DataResult.success(rest); - } - - final T casted = value.convert(ops).getValue(); - if (rest == ops.empty()) { - // no need to merge anything, return the old value - return DataResult.success(casted); - } - - final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeToMap(rest, map.collect(Pair.toMap()))); - return toMap.result().map(DataResult::success).orElseGet(() -> { - final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeToList(rest, stream.collect(Collectors.toList()))); - return toList.result().map(DataResult::success).orElseGet(() -> - DataResult.error("Don't know how to merge " + rest + " and " + casted, rest) - ); - }); + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final Dynamic input) { + if (input.getValue() == input.getOps().empty()) { + // nothing to merge, return rest + return DataResult.success(prefix); + } + + final T casted = input.convert(ops).getValue(); + if (prefix == ops.empty()) { + // no need to merge anything, return the old value + return DataResult.success(casted); + } + + final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeToMap(prefix, map.collect(Pair.toMap()))); + return toMap.result().map(DataResult::success).orElseGet(() -> { + final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeToList(prefix, stream.collect(Collectors.toList()))); + return toList.result().map(DataResult::success).orElseGet(() -> + DataResult.error("Don't know how to merge " + prefix + " and " + casted, prefix) + ); + }); + } + }; } } diff --git a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java index 870353de..c44ef0d9 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java @@ -3,16 +3,15 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.types.templates.Const; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; public final class FloatType extends Const.PrimitiveType { @Override - public DataResult> read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(v.floatValue(), ops.empty())); + .map(Number::floatValue); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/IntType.java b/src/main/java/com/mojang/datafixers/types/constant/IntType.java index abadbbc7..97f92e3e 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/IntType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/IntType.java @@ -3,16 +3,15 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.types.templates.Const; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; public final class IntType extends Const.PrimitiveType { @Override - public DataResult> read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(v.intValue(), ops.empty())); + .map(Number::intValue); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/LongType.java b/src/main/java/com/mojang/datafixers/types/constant/LongType.java index 49871ba0..02d2b61a 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/LongType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/LongType.java @@ -3,16 +3,15 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.types.templates.Const; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; public final class LongType extends Const.PrimitiveType { @Override - public DataResult> read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(v.longValue(), ops.empty())); + .map(Number::longValue); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java index 13de7391..c7038ab5 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java @@ -4,7 +4,6 @@ import com.google.common.base.Function; import com.mojang.datafixers.types.templates.Const; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; @@ -13,10 +12,10 @@ public final class NamespacedStringType extends Const.PrimitiveType { public static Function ENSURE_NAMESPACE = s -> s; @Override - public DataResult> read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getStringValue(input) - .map(v -> Pair.of(ENSURE_NAMESPACE.apply(v), ops.empty())); + .map(ENSURE_NAMESPACE); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java index 833aa6b6..238492d7 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java @@ -3,16 +3,15 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.types.templates.Const; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; public final class ShortType extends Const.PrimitiveType { @Override - public DataResult> read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(v -> Pair.of(v.shortValue(), ops.empty())); + .map(Number::shortValue); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/constant/StringType.java b/src/main/java/com/mojang/datafixers/types/constant/StringType.java index 67bc24c9..cc64526e 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/StringType.java +++ b/src/main/java/com/mojang/datafixers/types/constant/StringType.java @@ -3,16 +3,14 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.types.templates.Const; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; public final class StringType extends Const.PrimitiveType { @Override - public DataResult> read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops - .getStringValue(input) - .map(v -> Pair.of(v, ops.empty())); + .getStringValue(input); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Check.java b/src/main/java/com/mojang/datafixers/types/templates/Check.java index 550843c9..9780bc31 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Check.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Check.java @@ -2,20 +2,21 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.templates; -import com.mojang.datafixers.functions.PointFreeRule; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.FamilyOptic; import com.mojang.datafixers.RewriteResult; import com.mojang.datafixers.TypeRewriteRule; import com.mojang.datafixers.TypedOptic; import com.mojang.datafixers.functions.Functions; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; +import com.mojang.datafixers.functions.PointFreeRule; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.Objects; @@ -120,16 +121,18 @@ public CheckType(final String name, final int index, final int expectedIndex, fi } @Override - public DataResult> read(final DynamicOps ops, final T input) { + protected Codec buildCodec() { + return Codec.of( + delegate.codec(), + this::read + ); + } + + private DataResult> read(final DynamicOps ops, final T input) { if (index != expectedIndex) { return DataResult.error("Index mismatch: " + index + " != " + expectedIndex); } - return delegate.read(ops, input); - } - - @Override - public DataResult write(final DynamicOps ops, final T rest, final A value) { - return delegate.write(ops, rest, value); + return delegate.codec().decode(ops, input); } public static RewriteResult fix(final CheckType type, final RewriteResult instance) { diff --git a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java index 4eeffe67..0e3ffe61 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java +++ b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java @@ -3,12 +3,8 @@ package com.mojang.datafixers.types.templates; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.FamilyOptic; @@ -21,19 +17,20 @@ import com.mojang.datafixers.optics.Optic; import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.codecs.CompoundListCodec; import javax.annotation.Nullable; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; public final class CompoundList implements TypeTemplate { @@ -176,54 +173,8 @@ public Optional>> point(final DynamicOps ops) { } @Override - public DataResult>, T>> read(final DynamicOps ops, final T input) { - return ops.getMapValues(input).flatMap(map -> { - final AtomicReference>, ImmutableMap.Builder>>> result = - new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableMap.builder()))); - - map.forEach(entry -> { - result.set(result.get().flatMap(pair -> { - final DataResult> readEntry = key.read(ops, entry.getFirst()).flatMap(keyValue -> - element.read(ops, entry.getSecond()).map(elementValue -> - Pair.of(keyValue.getFirst(), elementValue.getFirst()) - ) - ); - readEntry.error().ifPresent(e -> { - pair.getSecond().put(entry.getFirst(), entry.getSecond()); - }); - return readEntry.map(r -> { - pair.getFirst().add(r); - return pair; - }); - })); - }); - - return result.get().map(pair -> Pair.of((List>) pair.getFirst().build(), ops.createMap(pair.getSecond().build()))); - }); - } - - @Override - public DataResult write(final DynamicOps ops, final T rest, final List> value) { - final Map map = Maps.newHashMap(); - - DataResult> result = DataResult.success(map); - - for (final Pair pair : value) { - result = result.flatMap(m -> { - final DataResult element = this.element.write(ops, ops.empty(), pair.getSecond()); - final DataResult> entry = element.flatMap(e -> key.write(ops, ops.empty(), pair.getFirst()).map(k -> Pair.of(k, e))); - return entry.flatMap(e -> { - final T key = e.getFirst(); - if (m.containsKey(key)) { - return DataResult.error("Duplicate key: " + key, m); - } - m.put(key, e.getSecond()); - return DataResult.success(m); - }); - }); - } - - return result.flatMap(m -> ops.mergeToMap(rest, m)); + protected Codec>> buildCodec() { + return new CompoundListCodec<>(key.codec(), element.codec()); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Const.java b/src/main/java/com/mojang/datafixers/types/templates/Const.java index 5093ab86..4d0ff6b5 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Const.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Const.java @@ -3,7 +3,6 @@ package com.mojang.datafixers.types.templates; import com.google.common.collect.ImmutableSet; -import com.mojang.datafixers.util.Either; import com.mojang.datafixers.DSL; import com.mojang.datafixers.FamilyOptic; import com.mojang.datafixers.OpticParts; @@ -14,6 +13,9 @@ import com.mojang.datafixers.optics.profunctors.Profunctor; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; @@ -109,10 +111,22 @@ public TypeTemplate buildTemplate() { } @Override - public final DataResult write(final DynamicOps ops, final T rest, final A value) { - return ops.mergeToPrimitive(rest, doWrite(ops, value)); + protected Codec buildCodec() { + return new Codec() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return read(ops, input).map(r -> Pair.of(r, ops.empty())); + } + + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return ops.mergeToPrimitive(prefix, doWrite(ops, input)); + } + }; } + protected abstract DataResult read(final DynamicOps ops, final T input); + protected abstract T doWrite(final DynamicOps ops, final A value); } } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Hook.java b/src/main/java/com/mojang/datafixers/types/templates/Hook.java index e62d4bdc..1591f363 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Hook.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Hook.java @@ -2,19 +2,20 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.templates; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.FamilyOptic; import com.mojang.datafixers.RewriteResult; import com.mojang.datafixers.TypeRewriteRule; import com.mojang.datafixers.TypedOptic; import com.mojang.datafixers.functions.Functions; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.Objects; @@ -109,13 +110,18 @@ public HookType(final Type delegate, final HookFunction preRead, final HookFu } @Override - public DataResult> read(final DynamicOps ops, final T input) { - return delegate.read(ops, preRead.apply(ops, input)); - } - - @Override - public DataResult write(final DynamicOps ops, final T rest, final A value) { - return delegate.write(ops, rest, value).map(v -> postWrite.apply(ops, v)); + protected Codec buildCodec() { + return new Codec() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return delegate.codec().decode(ops, preRead.apply(ops, input)); + } + + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return delegate.codec().encode(ops, prefix, input).map(v -> postWrite.apply(ops, v)); + } + }; } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/List.java b/src/main/java/com/mojang/datafixers/types/templates/List.java index 6483d70a..003d4b24 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/List.java +++ b/src/main/java/com/mojang/datafixers/types/templates/List.java @@ -19,16 +19,14 @@ import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.DataResult; +import com.mojang.serialization.Codec; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.codecs.ListCodec; import javax.annotation.Nullable; -import java.util.ArrayList; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; public final class List implements TypeTemplate { @@ -159,47 +157,8 @@ public Optional> point(final DynamicOps ops) { } @Override - public DataResult, T>> read(final DynamicOps ops, final T input) { - return ops.getStream(input).flatMap(stream -> { - final AtomicReference, ImmutableList.Builder>>> result = - new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableList.builder()))); - - stream.forEach(t -> - result.set(result.get().flatMap(pair -> { - final DataResult> read = element.read(ops, t); - - read.error().ifPresent(e -> pair.getSecond().add(t)); - - return read.map(value -> { - pair.getFirst().add(value.getFirst()); - return pair; - }); - })) - ); - - return result.get().map(pair -> Pair.of((java.util.List) pair.getFirst().build(), ops.createList(pair.getSecond().build().stream()))); - }); - } - - /** - * Will write `ops.empty()` value into the partial result if the element failed to serialize - */ - @Override - public DataResult write(final DynamicOps ops, final T rest, final java.util.List value) { - final java.util.List list = new ArrayList<>(value.size()); - DataResult> result = DataResult.success(list); - - for (final A a : value) { - result = result.flatMap(t -> { - final DataResult written = element.write(ops, ops.empty(), a); - return written.map(e -> { - list.add(e); - return list; - }); - }); - } - - return result.flatMap(l -> ops.mergeToList(rest, l)); + public Codec> buildCodec() { + return new ListCodec<>(element.codec()); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Named.java b/src/main/java/com/mojang/datafixers/types/templates/Named.java index f18fbee8..a7e0d50f 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Named.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Named.java @@ -18,6 +18,7 @@ import com.mojang.datafixers.types.families.TypeFamily; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; @@ -138,16 +139,21 @@ public Optional> findCheckedType(final int index) { } @Override - public DataResult, T>> read(final DynamicOps ops, final T input) { - return element.read(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(name, v))); - } - - @Override - public DataResult write(final DynamicOps ops, final T rest, final Pair value) { - if (!Objects.equals(value.getFirst(), name)) { - return DataResult.error("Named type name doesn't match: expected: " + name + ", got: " + value.getFirst(), rest); - } - return element.write(ops, rest, value.getSecond()); + protected Codec> buildCodec() { + return new Codec>() { + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + return element.codec().decode(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(name, v))); + } + + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final Pair input) { + if (!Objects.equals(input.getFirst(), name)) { + return DataResult.error("Named type name doesn't match: expected: " + name + ", got: " + input.getFirst(), prefix); + } + return element.codec().encode(ops, prefix, input.getSecond()); + } + }; } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Product.java b/src/main/java/com/mojang/datafixers/types/templates/Product.java index fcd41f05..001e353c 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Product.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Product.java @@ -4,8 +4,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.FamilyOptic; @@ -21,11 +19,13 @@ import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.Traversal; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.Objects; @@ -212,17 +212,8 @@ public Optional> findCheckedType(final int index) { } @Override - public DataResult, T>> read(final DynamicOps ops, final T input) { - return first.read(ops, input).flatMap(p1 -> - second.read(ops, p1.getSecond()).map(p2 -> - Pair.of(Pair.of(p1.getFirst(), p2.getFirst()), p2.getSecond()) - ) - ); - } - - @Override - public DataResult write(final DynamicOps ops, final T rest, final Pair value) { - return first.write(ops, rest, value.getFirst()).flatMap(f -> second.write(ops, f, value.getSecond())); + public Codec> buildCodec() { + return Pair.codec(first.codec(), second.codec()); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java index 6c5c1f94..5f73dc2f 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java +++ b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java @@ -2,8 +2,6 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.templates; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.FamilyOptic; import com.mojang.datafixers.RewriteResult; @@ -12,11 +10,14 @@ import com.mojang.datafixers.View; import com.mojang.datafixers.functions.Functions; import com.mojang.datafixers.functions.PointFreeRule; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import org.apache.commons.lang3.ObjectUtils; import javax.annotation.Nullable; @@ -137,14 +138,20 @@ public Type unfold() { return type; } + /** needs to be lazy */ @Override - public DataResult> read(final DynamicOps ops, final T input) { - return unfold().read(ops, input); - } + protected Codec buildCodec() { + return new Codec() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return unfold().codec().decode(ops, input); + } - @Override - public DataResult write(final DynamicOps ops, final T rest, final A value) { - return unfold().write(ops, rest, value); + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return unfold().codec().encode(ops, prefix, input); + } + }; } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Sum.java b/src/main/java/com/mojang/datafixers/types/templates/Sum.java index d68b04b7..59718aa1 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Sum.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Sum.java @@ -4,8 +4,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.FamilyOptic; @@ -20,11 +18,12 @@ import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.Traversal; import com.mojang.datafixers.optics.profunctors.TraversalP; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.Objects; @@ -212,20 +211,8 @@ public Optional> findCheckedType(final int index) { } @Override - public DataResult, T>> read(final DynamicOps ops, final T input) { - final DataResult, T>> firstRead = first.read(ops, input).map(vo -> vo.mapFirst(Either::left)); - if (firstRead.result().isPresent()) { - return firstRead; - } - return second.read(ops, input).map(vo -> vo.mapFirst(Either::right)); - } - - @Override - public DataResult write(final DynamicOps ops, final T rest, final Either value) { - return value.map( - value1 -> first.write(ops, rest, value1), - value2 -> second.write(ops, rest, value2) - ); + protected Codec> buildCodec() { + return Either.codec(first.codec(), second.codec()); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index 5aaa9dc0..fab83862 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -14,6 +14,7 @@ import com.mojang.datafixers.types.families.TypeFamily; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; @@ -173,29 +174,34 @@ public TypeTemplate buildTemplate() { } @Override - public DataResult> read(final DynamicOps ops, final T input) { - return ops.getMapValues(input).flatMap(map -> { - final T nameObject = ops.createString(name); - - final Map>> partitioned = map.collect(Collectors.partitioningBy(p -> Objects.equals(p.getFirst(), nameObject))); - final List> matched = partitioned.get(true); - final List> rest = partitioned.get(false); - if (matched.isEmpty()) { - return DataResult.error("No keys matched " + name); - } - if (matched.size() != 1) { - return DataResult.error("Too many keys matched " + name + ": " + matched); + protected Codec buildCodec() { + return new Codec() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return ops.getMapValues(input).flatMap(map -> { + final T nameObject = ops.createString(name); + + final Map>> partitioned = map.collect(Collectors.partitioningBy(p -> Objects.equals(p.getFirst(), nameObject))); + final List> matched = partitioned.get(true); + final List> rest = partitioned.get(false); + if (matched.isEmpty()) { + return DataResult.error("No keys matched " + name); + } + if (matched.size() != 1) { + return DataResult.error("Too many keys matched " + name + ": " + matched); + } + + return element.codec().decode(ops, matched.get(0).getSecond()).map(value -> + Pair.of(value.getFirst(), ops.createMap(rest.stream().collect(Pair.toMap()))) + ); + }); } - return element.read(ops, matched.get(0).getSecond()).map(value -> - Pair.of(value.getFirst(), ops.createMap(rest.stream().collect(Pair.toMap()))) - ); - }); - } - - @Override - public DataResult write(final DynamicOps ops, final T rest, final A value) { - return element.write(ops, ops.empty(), value).flatMap(result -> ops.mergeToMap(rest, ops.createString(name), result)); + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return element.codec().encodeStart(ops, input).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); + } + }; } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index ec093861..a507149f 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -31,8 +31,10 @@ import com.mojang.datafixers.types.families.TypeFamily; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Encoder; import javax.annotation.Nullable; import java.util.Arrays; @@ -180,42 +182,47 @@ public TypeTemplate buildTemplate() { } @Override - public DataResult, T>> read(final DynamicOps ops, final T input) { - final DataResult>> values = ops.getMapValues(input); - return values.flatMap(vs -> { - final T nameString = ops.createString(name); - final Optional> nameEntry = vs.filter(v -> v.getFirst() == nameString).findFirst(); - if (!nameEntry.isPresent()) { - return DataResult.error("Input does not contain a key [" + name + "] with the name: " + input); + protected Codec> buildCodec() { + return new Codec>() { + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + final DataResult>> values = ops.getMapValues(input); + return values.flatMap(vs -> { + final T nameString = ops.createString(name); + final Optional> nameEntry = vs.filter(v -> v.getFirst() == nameString).findFirst(); + if (!nameEntry.isPresent()) { + return DataResult.error("Input does not contain a key [" + name + "] with the name: " + input); + } + + return keyType.codec().decode(ops, nameEntry.get().getSecond()).flatMap(key -> { + final K keyValue = key.getFirst(); + final Type type = types.get(keyValue); + if (type != null) { + return type.codec().decode(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(keyValue, v))); + } + return DataResult.error("Unsupported key: " + keyValue + " in " + this); + }); + }); } - return keyType.read(ops, nameEntry.get().getSecond()).flatMap(key -> { - final K keyValue = key.getFirst(); - final Type type = types.get(keyValue); - if (type != null) { - return type.read(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(keyValue, v))); + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final Pair input) { + final Type type = types.get(input.getFirst()); + if (type == null) { + return DataResult.error("Unsupported key: " + input.getFirst() + " in " + this, prefix); } - return DataResult.error("Unsupported key: " + keyValue + " in " + this); - }); - }); - } - - @Override - public DataResult write(final DynamicOps ops, final T rest, final Pair value) { - final Type type = types.get(value.getFirst()); - if (type == null) { - return DataResult.error("Unsupported key: " + value.getFirst() + " in " + this, rest); - } - return capWrite(ops, type, value.getFirst(), value.getSecond(), rest); - } + return capWrite(ops, type.codec(), input.getFirst(), input.getSecond(), prefix); + } - @SuppressWarnings("unchecked") - private DataResult capWrite(final DynamicOps ops, final Type type, final K key, final Object value, final T rest) { - return keyType.write(ops, ops.empty(), key).flatMap(k -> - type.write(ops, rest, (A) value).flatMap(v -> - ops.mergeToMap(v, ops.createString(name), k) - ) - ); + @SuppressWarnings("unchecked") + private DataResult capWrite(final DynamicOps ops, final Encoder encoder, final K key, final Object value, final T rest) { + return keyType.codec().encodeStart(ops, key).flatMap(k -> + encoder.encode(ops, rest, (A) value).flatMap(v -> + ops.mergeToMap(v, ops.createString(name), k) + ) + ); + } + }; } @Override diff --git a/src/main/java/com/mojang/datafixers/util/Either.java b/src/main/java/com/mojang/datafixers/util/Either.java index a90adac7..b55b02f3 100644 --- a/src/main/java/com/mojang/datafixers/util/Either.java +++ b/src/main/java/com/mojang/datafixers/util/Either.java @@ -7,6 +7,9 @@ import com.mojang.datafixers.kinds.CocartesianLike; import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.kinds.Traversable; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.Optional; @@ -15,7 +18,8 @@ import java.util.function.Function; public abstract class Either implements App, L> { - public static final class Mu implements K1 {} + public static final class Mu implements K1 { + } public static Either unbox(final App, L> box) { return (Either) box; @@ -192,7 +196,8 @@ public Either flatMap(final Function> function) { } public static final class Instance implements Applicative, Instance.Mu>, Traversable, Instance.Mu>, CocartesianLike, R2, Instance.Mu> { - public static final class Mu implements Applicative.Mu, Traversable.Mu, CocartesianLike.Mu {} + public static final class Mu implements Applicative.Mu, Traversable.Mu, CocartesianLike.Mu { + } @Override public App, R> map(final Function func, final App, T> ts) { @@ -241,4 +246,57 @@ public App, A> from(final App, A> input) { return input; } } + + public static Codec> codec(final Codec first, final Codec second) { + return new EitherCodec<>(first, second); + } + + private static final class EitherCodec implements Codec> { + private final Codec first; + private final Codec second; + + private EitherCodec(final Codec first, final Codec second) { + this.first = first; + this.second = second; + } + + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + final DataResult, T>> firstRead = first.decode(ops, input).map(vo -> vo.mapFirst(Either::left)); + if (firstRead.result().isPresent()) { + return firstRead; + } + return second.decode(ops, input).map(vo -> vo.mapFirst(Either::right)); + } + + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final Either input) { + return input.map( + value1 -> first.encode(ops, prefix, value1), + value2 -> second.encode(ops, prefix, value2) + ); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final EitherCodec eitherCodec = ((EitherCodec) o); + return Objects.equals(first, eitherCodec.first) && Objects.equals(second, eitherCodec.second); + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + + @Override + public String toString() { + return "EitherCodec[" + first + ", " + second + ']'; + } + } } diff --git a/src/main/java/com/mojang/datafixers/util/Pair.java b/src/main/java/com/mojang/datafixers/util/Pair.java index dfa0280e..a607de8e 100644 --- a/src/main/java/com/mojang/datafixers/util/Pair.java +++ b/src/main/java/com/mojang/datafixers/util/Pair.java @@ -7,6 +7,9 @@ import com.mojang.datafixers.kinds.CartesianLike; import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.kinds.Traversable; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import java.util.Map; import java.util.Objects; @@ -100,4 +103,54 @@ public App, A> from(final App, A> input) { return input; } } + + public static Codec> codec(final Codec first, final Codec second) { + return new PairCodec<>(first, second); + } + + private static final class PairCodec implements Codec> { + private final Codec first; + private final Codec second; + + private PairCodec(final Codec first, final Codec second) { + this.first = first; + this.second = second; + } + + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + return first.decode(ops, input).flatMap(p1 -> + second.decode(ops, p1.getSecond()).map(p2 -> + Pair.of(Pair.of(p1.getFirst(), p2.getFirst()), p2.getSecond()) + ) + ); + } + + @Override + public DataResult encode(final DynamicOps ops, final T rest, final Pair value) { + return first.encode(ops, rest, value.getFirst()).flatMap(f -> second.encode(ops, f, value.getSecond())); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final PairCodec pairCodec = (PairCodec) o; + return Objects.equals(first, pairCodec.first) && Objects.equals(second, pairCodec.second); + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + + @Override + public String toString() { + return "PairCodec[" + first + ", " + second + ']'; + } + } } diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 27577e35..9f84395a 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -62,6 +62,25 @@ static Decoder unit(final A instance) { public DataResult> decode(final DynamicOps ops, final T input) { return DataResult.success(Pair.of(instance, input)); } + + @Override + public String toString() { + return "UnitDecoder[" + instance + "]"; + } + }; + } + + static Decoder error(final String error) { + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return DataResult.error(error); + } + + @Override + public String toString() { + return "ErrorDecoder[" + error + ']'; + } }; } diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index e3ca01fd..9851b1f4 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -22,4 +22,32 @@ public String toString() { } }; } + + static Encoder empty() { + return new Encoder() { + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return DataResult.success(prefix); + } + + @Override + public String toString() { + return "EmptyEncoder"; + } + }; + } + + static Encoder error(final String error) { + return new Encoder() { + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return DataResult.error(error + " " + input); + } + + @Override + public String toString() { + return "EmptyEncoder[" + error + "]"; + } + }; + } } diff --git a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java new file mode 100644 index 00000000..c03f9d4e --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +public final class CompoundListCodec implements Codec>> { + private final Codec keyCodec; + private final Codec elementCodec; + + public CompoundListCodec(final Codec keyCodec, final Codec elementCodec) { + this.keyCodec = keyCodec; + this.elementCodec = elementCodec; + } + + @Override + public DataResult>, T>> decode(final DynamicOps ops, final T input) { + return ops.getMapValues(input).flatMap(map -> { + final AtomicReference>, ImmutableMap.Builder>>> result = + new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableMap.builder()))); + + map.forEach(entry -> { + result.set(result.get().flatMap(pair -> { + final DataResult> readEntry = keyCodec.parse(ops, entry.getFirst()).flatMap(keyValue -> + elementCodec.parse(ops, entry.getSecond()).map(elementValue -> + Pair.of(keyValue, elementValue) + ) + ); + readEntry.error().ifPresent(e -> { + pair.getSecond().put(entry.getFirst(), entry.getSecond()); + }); + return readEntry.map(r -> { + pair.getFirst().add(r); + return pair; + }); + })); + }); + + return result.get().map(pair -> Pair.of(pair.getFirst().build(), ops.createMap(pair.getSecond().build()))); + }); + } + + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final List> input) { + final Map map = Maps.newHashMap(); + + DataResult> result = DataResult.success(map); + + for (final Pair pair : input) { + result = result.flatMap(m -> { + final DataResult element = elementCodec.encodeStart(ops, pair.getSecond()); + final DataResult> entry = element.flatMap(e -> keyCodec.encodeStart(ops, pair.getFirst()).map(k -> Pair.of(k, e))); + return entry.flatMap(e -> { + final T key = e.getFirst(); + if (m.containsKey(key)) { + return DataResult.error("Duplicate key: " + key, m); + } + m.put(key, e.getSecond()); + return DataResult.success(m); + }); + }); + } + + return result.flatMap(m -> ops.mergeToMap(prefix, m)); + } + + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final CompoundListCodec that = (CompoundListCodec) o; + return Objects.equals(keyCodec, that.keyCodec) && Objects.equals(elementCodec, that.elementCodec); + } + + @Override + public int hashCode() { + return Objects.hash(keyCodec, elementCodec); + } + + @Override + public String toString() { + return "CompoundListCodec[" + keyCodec + " -> " + elementCodec + ']'; + } +} diff --git a/src/main/java/com/mojang/serialization/codecs/ListCodec.java b/src/main/java/com/mojang/serialization/codecs/ListCodec.java new file mode 100644 index 00000000..bc3a3300 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/ListCodec.java @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.google.common.collect.ImmutableList; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +public final class ListCodec implements Codec> { + private final Codec elementCodec; + + public ListCodec(final Codec elementCodec) { + this.elementCodec = elementCodec; + } + + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final java.util.List input) { + final java.util.List list = new ArrayList<>(input.size()); + DataResult> result = DataResult.success(list); + + for (final A a : input) { + result = result.flatMap(t -> { + final DataResult written = elementCodec.encode(ops, ops.empty(), a); + return written.map(e -> { + list.add(e); + return list; + }); + }); + } + + return result.flatMap(l -> ops.mergeToList(prefix, l)); + } + + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + return ops.getStream(input).flatMap(stream -> { + final AtomicReference, ImmutableList.Builder>>> result = + new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableList.builder()))); + + stream.forEach(t -> + result.set(result.get().flatMap(pair -> { + final DataResult> read = elementCodec.decode(ops, t); + + read.error().ifPresent(e -> pair.getSecond().add(t)); + + return read.map(value -> { + pair.getFirst().add(value.getFirst()); + return pair; + }); + })) + ); + + return result.get().map(pair -> Pair.of(pair.getFirst().build(), ops.createList(pair.getSecond().build().stream()))); + }); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ListCodec listCodec = (ListCodec) o; + return Objects.equals(elementCodec, listCodec.elementCodec); + } + + @Override + public int hashCode() { + return Objects.hash(elementCodec); + } + + @Override + public String toString() { + return "ListCodec[" + elementCodec + ']'; + } +} From 0ca33966b614023526e23b964e072b509bb1d33b Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 14 Mar 2020 10:36:09 +0100 Subject: [PATCH 19/96] Split off primitive codecs, removed NamespacedString. --- src/main/java/com/mojang/datafixers/DSL.java | 31 +--- .../datafixers/types/constant/BoolType.java | 26 --- .../datafixers/types/constant/ByteType.java | 26 --- .../datafixers/types/constant/DoubleType.java | 26 --- .../datafixers/types/constant/FloatType.java | 26 --- .../datafixers/types/constant/IntType.java | 26 --- .../datafixers/types/constant/LongType.java | 26 --- .../types/constant/NamespacedStringType.java | 30 --- .../datafixers/types/constant/ShortType.java | 26 --- .../datafixers/types/constant/StringType.java | 25 --- .../types/templates/CompoundList.java | 2 +- .../datafixers/types/templates/Const.java | 30 ++- .../datafixers/types/templates/List.java | 2 +- .../datafixers/types/templates/Product.java | 2 +- .../datafixers/types/templates/Sum.java | 2 +- .../com/mojang/datafixers/util/Either.java | 56 ------ .../java/com/mojang/datafixers/util/Pair.java | 53 ------ .../java/com/mojang/serialization/Codec.java | 175 ++++++++++++++++++ .../serialization/codecs/EitherCodec.java | 60 ++++++ .../serialization/codecs/PairCodec.java | 56 ++++++ .../serialization/codecs/PrimitiveCodec.java | 24 +++ 21 files changed, 340 insertions(+), 390 deletions(-) delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/BoolType.java delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/ByteType.java delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/DoubleType.java delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/FloatType.java delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/IntType.java delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/LongType.java delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/ShortType.java delete mode 100644 src/main/java/com/mojang/datafixers/types/constant/StringType.java create mode 100644 src/main/java/com/mojang/serialization/codecs/EitherCodec.java create mode 100644 src/main/java/com/mojang/serialization/codecs/PairCodec.java create mode 100644 src/main/java/com/mojang/serialization/codecs/PrimitiveCodec.java diff --git a/src/main/java/com/mojang/datafixers/DSL.java b/src/main/java/com/mojang/datafixers/DSL.java index 65bb7fa9..a7ed01c1 100644 --- a/src/main/java/com/mojang/datafixers/DSL.java +++ b/src/main/java/com/mojang/datafixers/DSL.java @@ -6,17 +6,8 @@ import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.types.Func; import com.mojang.datafixers.types.Type; -import com.mojang.datafixers.types.constant.BoolType; -import com.mojang.datafixers.types.constant.ByteType; -import com.mojang.datafixers.types.constant.DoubleType; import com.mojang.datafixers.types.constant.EmptyPart; import com.mojang.datafixers.types.constant.EmptyPartSaving; -import com.mojang.datafixers.types.constant.FloatType; -import com.mojang.datafixers.types.constant.IntType; -import com.mojang.datafixers.types.constant.LongType; -import com.mojang.datafixers.types.constant.NamespacedStringType; -import com.mojang.datafixers.types.constant.ShortType; -import com.mojang.datafixers.types.constant.StringType; import com.mojang.datafixers.types.templates.Check; import com.mojang.datafixers.types.templates.CompoundList; import com.mojang.datafixers.types.templates.Const; @@ -32,6 +23,7 @@ import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Unit; +import com.mojang.serialization.Codec; import com.mojang.serialization.Dynamic; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.tuple.Triple; @@ -83,10 +75,6 @@ static Type string() { return Instances.STRING_TYPE; } - static Type namespacedString() { - return Instances.NAMESPACED_STRING_TYPE; - } - static TypeTemplate emptyPart() { return constType(Instances.EMPTY_PART); } @@ -446,15 +434,14 @@ static Unit unit() { } final class Instances { - private static final Type BOOL_TYPE = new BoolType(); - private static final Type INT_TYPE = new IntType(); - private static final Type LONG_TYPE = new LongType(); - private static final Type BYTE_TYPE = new ByteType(); - private static final Type SHORT_TYPE = new ShortType(); - private static final Type FLOAT_TYPE = new FloatType(); - private static final Type DOUBLE_TYPE = new DoubleType(); - private static final Type STRING_TYPE = new StringType(); - private static final Type NAMESPACED_STRING_TYPE = new NamespacedStringType(); + private static final Type BOOL_TYPE = new Const.PrimitiveType<>(Codec.BOOL); + private static final Type INT_TYPE = new Const.PrimitiveType<>(Codec.INT); + private static final Type LONG_TYPE = new Const.PrimitiveType<>(Codec.LONG); + private static final Type BYTE_TYPE = new Const.PrimitiveType<>(Codec.BYTE); + private static final Type SHORT_TYPE = new Const.PrimitiveType<>(Codec.SHORT); + private static final Type FLOAT_TYPE = new Const.PrimitiveType<>(Codec.FLOAT); + private static final Type DOUBLE_TYPE = new Const.PrimitiveType<>(Codec.DOUBLE); + private static final Type STRING_TYPE = new Const.PrimitiveType<>(Codec.STRING); private static final Type EMPTY_PART = new EmptyPart(); private static final Type> NIL_SAVE = new EmptyPartSaving(); diff --git a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java b/src/main/java/com/mojang/datafixers/types/constant/BoolType.java deleted file mode 100644 index 0db0f205..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/BoolType.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.mojang.datafixers.types.templates.Const; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; - -public final class BoolType extends Const.PrimitiveType { - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getNumberValue(input) - .map(v -> v.intValue() != 0); - } - - @Override - public T doWrite(final DynamicOps ops, final Boolean value) { - return ops.createBoolean(value); - } - - @Override - public String toString() { - return "Bool"; - } -} diff --git a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java b/src/main/java/com/mojang/datafixers/types/constant/ByteType.java deleted file mode 100644 index 1d2b7d5f..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/ByteType.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.mojang.datafixers.types.templates.Const; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; - -public final class ByteType extends Const.PrimitiveType { - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getNumberValue(input) - .map(Number::byteValue); - } - - @Override - public T doWrite(final DynamicOps ops, final Byte value) { - return ops.createByte(value); - } - - @Override - public String toString() { - return "Byte"; - } -} diff --git a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java b/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java deleted file mode 100644 index 91533b62..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/DoubleType.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.mojang.datafixers.types.templates.Const; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; - -public final class DoubleType extends Const.PrimitiveType { - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getNumberValue(input) - .map(Number::doubleValue); - } - - @Override - public T doWrite(final DynamicOps ops, final Double value) { - return ops.createDouble(value); - } - - @Override - public String toString() { - return "Double"; - } -} diff --git a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java b/src/main/java/com/mojang/datafixers/types/constant/FloatType.java deleted file mode 100644 index c44ef0d9..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/FloatType.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.mojang.datafixers.types.templates.Const; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; - -public final class FloatType extends Const.PrimitiveType { - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getNumberValue(input) - .map(Number::floatValue); - } - - @Override - public T doWrite(final DynamicOps ops, final Float value) { - return ops.createFloat(value); - } - - @Override - public String toString() { - return "Float"; - } -} diff --git a/src/main/java/com/mojang/datafixers/types/constant/IntType.java b/src/main/java/com/mojang/datafixers/types/constant/IntType.java deleted file mode 100644 index 97f92e3e..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/IntType.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.mojang.datafixers.types.templates.Const; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; - -public final class IntType extends Const.PrimitiveType { - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getNumberValue(input) - .map(Number::intValue); - } - - @Override - public T doWrite(final DynamicOps ops, final Integer value) { - return ops.createInt(value); - } - - @Override - public String toString() { - return "Int"; - } -} diff --git a/src/main/java/com/mojang/datafixers/types/constant/LongType.java b/src/main/java/com/mojang/datafixers/types/constant/LongType.java deleted file mode 100644 index 02d2b61a..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/LongType.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.mojang.datafixers.types.templates.Const; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; - -public final class LongType extends Const.PrimitiveType { - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getNumberValue(input) - .map(Number::longValue); - } - - @Override - public T doWrite(final DynamicOps ops, final Long value) { - return ops.createLong(value); - } - - @Override - public String toString() { - return "Long"; - } -} diff --git a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java b/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java deleted file mode 100644 index c7038ab5..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/NamespacedStringType.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.google.common.base.Function; -import com.mojang.datafixers.types.templates.Const; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; - -// FIXME: move out of this project? -public final class NamespacedStringType extends Const.PrimitiveType { - public static Function ENSURE_NAMESPACE = s -> s; - - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getStringValue(input) - .map(ENSURE_NAMESPACE); - } - - @Override - public T doWrite(final DynamicOps ops, final String value) { - return ops.createString(value); - } - - @Override - public String toString() { - return "NamespacedString"; - } -} diff --git a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java b/src/main/java/com/mojang/datafixers/types/constant/ShortType.java deleted file mode 100644 index 238492d7..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/ShortType.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.mojang.datafixers.types.templates.Const; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; - -public final class ShortType extends Const.PrimitiveType { - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getNumberValue(input) - .map(Number::shortValue); - } - - @Override - public T doWrite(final DynamicOps ops, final Short value) { - return ops.createShort(value); - } - - @Override - public String toString() { - return "Short"; - } -} diff --git a/src/main/java/com/mojang/datafixers/types/constant/StringType.java b/src/main/java/com/mojang/datafixers/types/constant/StringType.java deleted file mode 100644 index cc64526e..00000000 --- a/src/main/java/com/mojang/datafixers/types/constant/StringType.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.datafixers.types.constant; - -import com.mojang.datafixers.types.templates.Const; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; - -public final class StringType extends Const.PrimitiveType { - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getStringValue(input); - } - - @Override - public T doWrite(final DynamicOps ops, final String value) { - return ops.createString(value); - } - - @Override - public String toString() { - return "String"; - } -} diff --git a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java index 0e3ffe61..182ccad9 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java +++ b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java @@ -174,7 +174,7 @@ public Optional>> point(final DynamicOps ops) { @Override protected Codec>> buildCodec() { - return new CompoundListCodec<>(key.codec(), element.codec()); + return Codec.compoundList(key.codec(), element.codec()); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Const.java b/src/main/java/com/mojang/datafixers/types/templates/Const.java index 4d0ff6b5..66db5eae 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Const.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Const.java @@ -14,10 +14,7 @@ import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.TypeFamily; import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; import java.util.Objects; @@ -99,7 +96,13 @@ public Type type() { return type; } - public abstract static class PrimitiveType extends Type { + public static final class PrimitiveType extends Type { + private final Codec codec; + + public PrimitiveType(final Codec codec) { + this.codec = codec; + } + @Override public boolean equals(final Object o, final boolean ignoreRecursionPoints, final boolean checkIndex) { return this == o; @@ -112,21 +115,12 @@ public TypeTemplate buildTemplate() { @Override protected Codec buildCodec() { - return new Codec() { - @Override - public DataResult> decode(final DynamicOps ops, final T input) { - return read(ops, input).map(r -> Pair.of(r, ops.empty())); - } - - @Override - public DataResult encode(final DynamicOps ops, final T prefix, final A input) { - return ops.mergeToPrimitive(prefix, doWrite(ops, input)); - } - }; + return codec; } - protected abstract DataResult read(final DynamicOps ops, final T input); - - protected abstract T doWrite(final DynamicOps ops, final A value); + @Override + public String toString() { + return codec.toString(); + } } } diff --git a/src/main/java/com/mojang/datafixers/types/templates/List.java b/src/main/java/com/mojang/datafixers/types/templates/List.java index 003d4b24..d99a4d37 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/List.java +++ b/src/main/java/com/mojang/datafixers/types/templates/List.java @@ -158,7 +158,7 @@ public Optional> point(final DynamicOps ops) { @Override public Codec> buildCodec() { - return new ListCodec<>(element.codec()); + return Codec.list(element.codec()); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Product.java b/src/main/java/com/mojang/datafixers/types/templates/Product.java index 001e353c..26210a2e 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Product.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Product.java @@ -213,7 +213,7 @@ public Optional> findCheckedType(final int index) { @Override public Codec> buildCodec() { - return Pair.codec(first.codec(), second.codec()); + return Codec.pair(first.codec(), second.codec()); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/Sum.java b/src/main/java/com/mojang/datafixers/types/templates/Sum.java index 59718aa1..bfbf21dd 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Sum.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Sum.java @@ -212,7 +212,7 @@ public Optional> findCheckedType(final int index) { @Override protected Codec> buildCodec() { - return Either.codec(first.codec(), second.codec()); + return Codec.either(first.codec(), second.codec()); } @Override diff --git a/src/main/java/com/mojang/datafixers/util/Either.java b/src/main/java/com/mojang/datafixers/util/Either.java index b55b02f3..612c3539 100644 --- a/src/main/java/com/mojang/datafixers/util/Either.java +++ b/src/main/java/com/mojang/datafixers/util/Either.java @@ -7,9 +7,6 @@ import com.mojang.datafixers.kinds.CocartesianLike; import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.kinds.Traversable; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.Optional; @@ -246,57 +243,4 @@ public App, A> from(final App, A> input) { return input; } } - - public static Codec> codec(final Codec first, final Codec second) { - return new EitherCodec<>(first, second); - } - - private static final class EitherCodec implements Codec> { - private final Codec first; - private final Codec second; - - private EitherCodec(final Codec first, final Codec second) { - this.first = first; - this.second = second; - } - - @Override - public DataResult, T>> decode(final DynamicOps ops, final T input) { - final DataResult, T>> firstRead = first.decode(ops, input).map(vo -> vo.mapFirst(Either::left)); - if (firstRead.result().isPresent()) { - return firstRead; - } - return second.decode(ops, input).map(vo -> vo.mapFirst(Either::right)); - } - - @Override - public DataResult encode(final DynamicOps ops, final T prefix, final Either input) { - return input.map( - value1 -> first.encode(ops, prefix, value1), - value2 -> second.encode(ops, prefix, value2) - ); - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final EitherCodec eitherCodec = ((EitherCodec) o); - return Objects.equals(first, eitherCodec.first) && Objects.equals(second, eitherCodec.second); - } - - @Override - public int hashCode() { - return Objects.hash(first, second); - } - - @Override - public String toString() { - return "EitherCodec[" + first + ", " + second + ']'; - } - } } diff --git a/src/main/java/com/mojang/datafixers/util/Pair.java b/src/main/java/com/mojang/datafixers/util/Pair.java index a607de8e..dfa0280e 100644 --- a/src/main/java/com/mojang/datafixers/util/Pair.java +++ b/src/main/java/com/mojang/datafixers/util/Pair.java @@ -7,9 +7,6 @@ import com.mojang.datafixers.kinds.CartesianLike; import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.kinds.Traversable; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; import java.util.Map; import java.util.Objects; @@ -103,54 +100,4 @@ public App, A> from(final App, A> input) { return input; } } - - public static Codec> codec(final Codec first, final Codec second) { - return new PairCodec<>(first, second); - } - - private static final class PairCodec implements Codec> { - private final Codec first; - private final Codec second; - - private PairCodec(final Codec first, final Codec second) { - this.first = first; - this.second = second; - } - - @Override - public DataResult, T>> decode(final DynamicOps ops, final T input) { - return first.decode(ops, input).flatMap(p1 -> - second.decode(ops, p1.getSecond()).map(p2 -> - Pair.of(Pair.of(p1.getFirst(), p2.getFirst()), p2.getSecond()) - ) - ); - } - - @Override - public DataResult encode(final DynamicOps ops, final T rest, final Pair value) { - return first.encode(ops, rest, value.getFirst()).flatMap(f -> second.encode(ops, f, value.getSecond())); - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final PairCodec pairCodec = (PairCodec) o; - return Objects.equals(first, pairCodec.first) && Objects.equals(second, pairCodec.second); - } - - @Override - public int hashCode() { - return Objects.hash(first, second); - } - - @Override - public String toString() { - return "PairCodec[" + first + ", " + second + ']'; - } - } } diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index c4ae1457..3ede99f9 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -2,7 +2,15 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.codecs.CompoundListCodec; +import com.mojang.serialization.codecs.EitherCodec; +import com.mojang.serialization.codecs.ListCodec; +import com.mojang.serialization.codecs.PairCodec; +import com.mojang.serialization.codecs.PrimitiveCodec; + +import java.util.List; public interface Codec extends Encoder, Decoder { static Codec of(final Decoder decoder) { @@ -27,4 +35,171 @@ public String toString() { } }; } + + static Codec> pair(final Codec first, final Codec second) { + return new PairCodec<>(first, second); + } + + static Codec> either(final Codec first, final Codec second) { + return new EitherCodec<>(first, second); + } + + static Codec> list(final Codec elementCodec) { + return new ListCodec<>(elementCodec); + } + + static Codec>> compoundList(final Codec keyCodec, final Codec elementCodec) { + return new CompoundListCodec<>(keyCodec, elementCodec); + } + + PrimitiveCodec FLOAT = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getNumberValue(input) + .map(Number::floatValue); + } + + @Override + public T write(final DynamicOps ops, final Float value) { + return ops.createFloat(value); + } + + @Override + public String toString() { + return "Float"; + } + }; + + PrimitiveCodec INT = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getNumberValue(input) + .map(Number::intValue); + } + + @Override + public T write(final DynamicOps ops, final Integer value) { + return ops.createInt(value); + } + + @Override + public String toString() { + return "Int"; + } + }; + + PrimitiveCodec BYTE = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getNumberValue(input) + .map(Number::byteValue); + } + + @Override + public T write(final DynamicOps ops, final Byte value) { + return ops.createByte(value); + } + + @Override + public String toString() { + return "Byte"; + } + }; + + PrimitiveCodec LONG = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getNumberValue(input) + .map(Number::longValue); + } + + @Override + public T write(final DynamicOps ops, final Long value) { + return ops.createLong(value); + } + + @Override + public String toString() { + return "Long"; + } + }; + + PrimitiveCodec BOOL = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getNumberValue(input) + .map(v -> v.intValue() != 0); + } + + @Override + public T write(final DynamicOps ops, final Boolean value) { + return ops.createBoolean(value); + } + + @Override + public String toString() { + return "Bool"; + } + }; + + PrimitiveCodec SHORT = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getNumberValue(input) + .map(Number::shortValue); + } + + @Override + public T write(final DynamicOps ops, final Short value) { + return ops.createShort(value); + } + + @Override + public String toString() { + return "Short"; + } + }; + + PrimitiveCodec STRING = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getStringValue(input); + } + + @Override + public T write(final DynamicOps ops, final String value) { + return ops.createString(value); + } + + @Override + public String toString() { + return "String"; + } + }; + + PrimitiveCodec DOUBLE = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getNumberValue(input) + .map(Number::doubleValue); + } + + @Override + public T write(final DynamicOps ops, final Double value) { + return ops.createDouble(value); + } + + @Override + public String toString() { + return "Double"; + } + }; } diff --git a/src/main/java/com/mojang/serialization/codecs/EitherCodec.java b/src/main/java/com/mojang/serialization/codecs/EitherCodec.java new file mode 100644 index 00000000..e4e28382 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/EitherCodec.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; + +import java.util.Objects; + +public final class EitherCodec implements Codec> { + private final Codec first; + private final Codec second; + + public EitherCodec(final Codec first, final Codec second) { + this.first = first; + this.second = second; + } + + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + final DataResult, T>> firstRead = first.decode(ops, input).map(vo -> vo.mapFirst(Either::left)); + if (firstRead.result().isPresent()) { + return firstRead; + } + return second.decode(ops, input).map(vo -> vo.mapFirst(Either::right)); + } + + @Override + public DataResult encode(final DynamicOps ops, final T prefix, final Either input) { + return input.map( + value1 -> first.encode(ops, prefix, value1), + value2 -> second.encode(ops, prefix, value2) + ); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final EitherCodec eitherCodec = ((EitherCodec) o); + return Objects.equals(first, eitherCodec.first) && Objects.equals(second, eitherCodec.second); + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + + @Override + public String toString() { + return "EitherCodec[" + first + ", " + second + ']'; + } +} diff --git a/src/main/java/com/mojang/serialization/codecs/PairCodec.java b/src/main/java/com/mojang/serialization/codecs/PairCodec.java new file mode 100644 index 00000000..9481b095 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/PairCodec.java @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; + +import java.util.Objects; + +public final class PairCodec implements Codec> { + private final Codec first; + private final Codec second; + + public PairCodec(final Codec first, final Codec second) { + this.first = first; + this.second = second; + } + + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + return first.decode(ops, input).flatMap(p1 -> + second.decode(ops, p1.getSecond()).map(p2 -> + Pair.of(Pair.of(p1.getFirst(), p2.getFirst()), p2.getSecond()) + ) + ); + } + + @Override + public DataResult encode(final DynamicOps ops, final T rest, final Pair value) { + return first.encode(ops, rest, value.getFirst()).flatMap(f -> second.encode(ops, f, value.getSecond())); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final PairCodec pairCodec = (PairCodec) o; + return Objects.equals(first, pairCodec.first) && Objects.equals(second, pairCodec.second); + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + + @Override + public String toString() { + return "PairCodec[" + first + ", " + second + ']'; + } +} diff --git a/src/main/java/com/mojang/serialization/codecs/PrimitiveCodec.java b/src/main/java/com/mojang/serialization/codecs/PrimitiveCodec.java new file mode 100644 index 00000000..d1de90a6 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/PrimitiveCodec.java @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; + +public interface PrimitiveCodec extends Codec { + DataResult read(final DynamicOps ops, final T input); + + T write(final DynamicOps ops, final A value); + + @Override + default DataResult> decode(final DynamicOps ops, final T input) { + return read(ops, input).map(r -> Pair.of(r, ops.empty())); + } + + @Override + default DataResult encode(final DynamicOps ops, final T prefix, final A input) { + return ops.mergeToPrimitive(prefix, write(ops, input)); + } +} From 8fcfa8c8caccffe1d6a743d0b133264e7451acdc Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 14 Mar 2020 11:47:27 +0100 Subject: [PATCH 20/96] Fixed early initialization of codec field. --- src/main/java/com/mojang/datafixers/types/Type.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/datafixers/types/Type.java b/src/main/java/com/mojang/datafixers/types/Type.java index d70d450e..ee224025 100644 --- a/src/main/java/com/mojang/datafixers/types/Type.java +++ b/src/main/java/com/mojang/datafixers/types/Type.java @@ -48,7 +48,8 @@ public static Type unbox(final App box) { @Nullable private TypeTemplate template; - private final Codec codec = buildCodec(); + @Nullable + private Codec codec; public RewriteResult rewriteOrNop(final TypeRewriteRule rule) { return DataFixUtils.orElseGet(rule.rewrite(this), () -> RewriteResult.nop(this)); @@ -116,6 +117,9 @@ public final DataResult>> read(final Dynamic input) { } public final Codec codec() { + if (codec == null) { + codec = buildCodec(); + } return codec; } From 8f216b52048d002ec26d4c7cc82ac2a3b5b3a6ae Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 14 Mar 2020 12:23:51 +0100 Subject: [PATCH 21/96] builder.add overload --- src/main/java/com/mojang/serialization/ListBuilder.java | 4 ++++ src/main/java/com/mojang/serialization/RecordBuilder.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index 36d935bb..7220a2d5 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -25,6 +25,10 @@ default ListBuilder add(final Serializable value, final T elementPrefix) { return add(value.serialize(ops(), elementPrefix)); } + default ListBuilder add(final E value, final Encoder encoder) { + return add(encoder.encodeStart(ops(), value)); + } + default ListBuilder addAll(final Iterable values) { values.forEach(this::add); return this; diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 6b00a3fa..dd092473 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -35,6 +35,10 @@ default RecordBuilder add(final String key, final Serializable value, final T return add(key, value.serialize(ops(), elementPrefix)); } + default RecordBuilder add(final String key, final E value, final Encoder encoder) { + return add(key, encoder.encodeStart(ops(), value)); + } + final class Builder implements RecordBuilder { private final DynamicOps ops; private DataResult> builder = DataResult.success(ImmutableMap.builder()); From ae6eedd81118c362a1f094eaad90cfd91ac8b2d8 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 14 Mar 2020 12:24:43 +0100 Subject: [PATCH 22/96] Moved input to a first argument of Encoder.encode to allow instance method references. --- src/main/java/com/mojang/datafixers/types/Type.java | 4 ++-- .../datafixers/types/constant/EmptyPartSaving.java | 2 +- .../com/mojang/datafixers/types/templates/Hook.java | 4 ++-- .../com/mojang/datafixers/types/templates/Named.java | 4 ++-- .../datafixers/types/templates/RecursivePoint.java | 4 ++-- .../com/mojang/datafixers/types/templates/Tag.java | 2 +- .../datafixers/types/templates/TaggedChoice.java | 4 ++-- src/main/java/com/mojang/serialization/Codec.java | 4 ++-- src/main/java/com/mojang/serialization/Encoder.java | 10 +++++----- .../java/com/mojang/serialization/ListBuilder.java | 2 +- .../mojang/serialization/codecs/CompoundListCodec.java | 2 +- .../com/mojang/serialization/codecs/EitherCodec.java | 6 +++--- .../com/mojang/serialization/codecs/ListCodec.java | 4 ++-- .../com/mojang/serialization/codecs/PairCodec.java | 4 ++-- .../mojang/serialization/codecs/PrimitiveCodec.java | 2 +- 15 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/types/Type.java b/src/main/java/com/mojang/datafixers/types/Type.java index ee224025..a988ed54 100644 --- a/src/main/java/com/mojang/datafixers/types/Type.java +++ b/src/main/java/com/mojang/datafixers/types/Type.java @@ -126,7 +126,7 @@ public final Codec codec() { protected abstract Codec buildCodec(); public final DataResult write(final DynamicOps ops, final A value) { - return codec().encode(ops, ops.empty(), value); + return codec().encode(value, ops, ops.empty()); } public final DataResult> writeDynamic(final DynamicOps ops, final A value) { @@ -164,7 +164,7 @@ private DataResult capWrite(final DynamicOps ops, final Type exp if (!expectedType.equals(f.newType(), true, true)) { return DataResult.error("Rewritten type doesn't match"); } - return f.newType().codec().encode(ops, rest, f.function().evalCached().apply(ops).apply(value)); + return f.newType().codec().encode(f.function().evalCached().apply(ops).apply(value), ops, rest); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java index 4474a513..7640342d 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -43,7 +43,7 @@ public DataResult, T>> decode(final DynamicOps ops, final } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final Dynamic input) { + public DataResult encode(final Dynamic input, final DynamicOps ops, final T prefix) { if (input.getValue() == input.getOps().empty()) { // nothing to merge, return rest return DataResult.success(prefix); diff --git a/src/main/java/com/mojang/datafixers/types/templates/Hook.java b/src/main/java/com/mojang/datafixers/types/templates/Hook.java index 1591f363..e81f9c90 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Hook.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Hook.java @@ -118,8 +118,8 @@ public DataResult> decode(final DynamicOps ops, final T input) } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final A input) { - return delegate.codec().encode(ops, prefix, input).map(v -> postWrite.apply(ops, v)); + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return delegate.codec().encode(input, ops, prefix).map(v -> postWrite.apply(ops, v)); } }; } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Named.java b/src/main/java/com/mojang/datafixers/types/templates/Named.java index a7e0d50f..bd5441fd 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Named.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Named.java @@ -147,11 +147,11 @@ public DataResult, T>> decode(final DynamicOps ops, } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final Pair input) { + public DataResult encode(final Pair input, final DynamicOps ops, final T prefix) { if (!Objects.equals(input.getFirst(), name)) { return DataResult.error("Named type name doesn't match: expected: " + name + ", got: " + input.getFirst(), prefix); } - return element.codec().encode(ops, prefix, input.getSecond()); + return element.codec().encode(input.getSecond(), ops, prefix); } }; } diff --git a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java index 5f73dc2f..8c47364e 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java +++ b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java @@ -148,8 +148,8 @@ public DataResult> decode(final DynamicOps ops, final T input) } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final A input) { - return unfold().codec().encode(ops, prefix, input); + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return unfold().codec().encode(input, ops, prefix); } }; } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index fab83862..ad347745 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -198,7 +198,7 @@ public DataResult> decode(final DynamicOps ops, final T input) } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { return element.codec().encodeStart(ops, input).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); } }; diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index a507149f..94dd468e 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -206,7 +206,7 @@ public TypeTemplate buildTemplate() { } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final Pair input) { + public DataResult encode(final Pair input, final DynamicOps ops, final T prefix) { final Type type = types.get(input.getFirst()); if (type == null) { return DataResult.error("Unsupported key: " + input.getFirst() + " in " + this, prefix); @@ -217,7 +217,7 @@ public DataResult encode(final DynamicOps ops, final T prefix, final P @SuppressWarnings("unchecked") private DataResult capWrite(final DynamicOps ops, final Encoder encoder, final K key, final Object value, final T rest) { return keyType.codec().encodeStart(ops, key).flatMap(k -> - encoder.encode(ops, rest, (A) value).flatMap(v -> + encoder.encode((A) value, ops, rest).flatMap(v -> ops.mergeToMap(v, ops.createString(name), k) ) ); diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 3ede99f9..69e19144 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -25,8 +25,8 @@ public DataResult> decode(final DynamicOps ops, final T input) } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final A input) { - return encoder.encode(ops, prefix, input); + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return encoder.encode(input, ops, prefix); } @Override diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index 9851b1f4..d2343a5f 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -3,16 +3,16 @@ package com.mojang.serialization; public interface Encoder { - DataResult encode(final DynamicOps ops, final T prefix, final A input); + DataResult encode(final A input, final DynamicOps ops, final T prefix); default DataResult encodeStart(final DynamicOps ops, final A input) { - return encode(ops, ops.empty(), input); + return encode(input, ops, ops.empty()); } static Encoder of() { return new Encoder() { @Override - public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { return input.serialize(ops, prefix); } @@ -26,7 +26,7 @@ public String toString() { static Encoder empty() { return new Encoder() { @Override - public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { return DataResult.success(prefix); } @@ -40,7 +40,7 @@ public String toString() { static Encoder error(final String error) { return new Encoder() { @Override - public DataResult encode(final DynamicOps ops, final T prefix, final A input) { + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { return DataResult.error(error + " " + input); } diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index 7220a2d5..0531b8a7 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -35,7 +35,7 @@ default ListBuilder addAll(final Iterable values) { } default ListBuilder addAll(final Iterable values, final Encoder encoder) { - values.forEach(v -> encoder.encode(ops(), ops().empty(), v)); + values.forEach(v -> encoder.encode(v, ops(), ops().empty())); return this; } diff --git a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java index c03f9d4e..727d6024 100644 --- a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java @@ -52,7 +52,7 @@ public DataResult>, T>> decode(final DynamicOps ops, } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final List> input) { + public DataResult encode(final List> input, final DynamicOps ops, final T prefix) { final Map map = Maps.newHashMap(); DataResult> result = DataResult.success(map); diff --git a/src/main/java/com/mojang/serialization/codecs/EitherCodec.java b/src/main/java/com/mojang/serialization/codecs/EitherCodec.java index e4e28382..544e49c2 100644 --- a/src/main/java/com/mojang/serialization/codecs/EitherCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/EitherCodec.java @@ -29,10 +29,10 @@ public DataResult, T>> decode(final DynamicOps ops, fin } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final Either input) { + public DataResult encode(final Either input, final DynamicOps ops, final T prefix) { return input.map( - value1 -> first.encode(ops, prefix, value1), - value2 -> second.encode(ops, prefix, value2) + value1 -> first.encode(value1, ops, prefix), + value2 -> second.encode(value2, ops, prefix) ); } diff --git a/src/main/java/com/mojang/serialization/codecs/ListCodec.java b/src/main/java/com/mojang/serialization/codecs/ListCodec.java index bc3a3300..2a516178 100644 --- a/src/main/java/com/mojang/serialization/codecs/ListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/ListCodec.java @@ -21,13 +21,13 @@ public ListCodec(final Codec elementCodec) { } @Override - public DataResult encode(final DynamicOps ops, final T prefix, final java.util.List input) { + public DataResult encode(final List input, final DynamicOps ops, final T prefix) { final java.util.List list = new ArrayList<>(input.size()); DataResult> result = DataResult.success(list); for (final A a : input) { result = result.flatMap(t -> { - final DataResult written = elementCodec.encode(ops, ops.empty(), a); + final DataResult written = elementCodec.encode(a, ops, ops.empty()); return written.map(e -> { list.add(e); return list; diff --git a/src/main/java/com/mojang/serialization/codecs/PairCodec.java b/src/main/java/com/mojang/serialization/codecs/PairCodec.java index 9481b095..48453ce1 100644 --- a/src/main/java/com/mojang/serialization/codecs/PairCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/PairCodec.java @@ -28,8 +28,8 @@ public DataResult, T>> decode(final DynamicOps ops, final } @Override - public DataResult encode(final DynamicOps ops, final T rest, final Pair value) { - return first.encode(ops, rest, value.getFirst()).flatMap(f -> second.encode(ops, f, value.getSecond())); + public DataResult encode(final Pair value, final DynamicOps ops, final T rest) { + return first.encode(value.getFirst(), ops, rest).flatMap(f -> second.encode(value.getSecond(), ops, f)); } @Override diff --git a/src/main/java/com/mojang/serialization/codecs/PrimitiveCodec.java b/src/main/java/com/mojang/serialization/codecs/PrimitiveCodec.java index d1de90a6..78671fb7 100644 --- a/src/main/java/com/mojang/serialization/codecs/PrimitiveCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/PrimitiveCodec.java @@ -18,7 +18,7 @@ default DataResult> decode(final DynamicOps ops, final T input } @Override - default DataResult encode(final DynamicOps ops, final T prefix, final A input) { + default DataResult encode(final A input, final DynamicOps ops, final T prefix) { return ops.mergeToPrimitive(prefix, write(ops, input)); } } From b15d1141d4774d3331af04403c4468e314638326 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 14 Mar 2020 13:36:25 +0100 Subject: [PATCH 23/96] Lazy unit decoder --- .../java/com/mojang/serialization/Decoder.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 9f84395a..ef589373 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -5,6 +5,7 @@ import com.mojang.datafixers.util.Pair; import java.util.function.Function; +import java.util.function.Supplier; public interface Decoder { DataResult> decode(final DynamicOps ops, final T input); @@ -70,6 +71,20 @@ public String toString() { }; } + static Decoder unit(final Supplier instance) { + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return DataResult.success(Pair.of(instance.get(), input)); + } + + @Override + public String toString() { + return "UnitDecoder[" + instance.get() + "]"; + } + }; + } + static Decoder error(final String error) { return new Decoder() { @Override From ca9885c90cb93e22fdb04bdb8359ca14108798a7 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 14 Mar 2020 13:36:43 +0100 Subject: [PATCH 24/96] Fixed error in JsonOps list builder override --- .../java/com/mojang/serialization/JsonOps.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index d6ba90f2..ed51ef63 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -273,7 +273,19 @@ public ListBuilder add(final DataResult value) { @Override public DataResult build(final JsonElement prefix) { - final DataResult result = builder.flatMap(b -> INSTANCE.mergeToList(prefix, b)); + final DataResult result = builder.flatMap(b -> { + if (!prefix.isJsonArray() && prefix != ops().empty()) { + return DataResult.error("Cannot append a list to not a list: " + prefix, prefix); + } + + final JsonArray array = new JsonArray(); + if (prefix != ops().empty()) { + array.addAll(prefix.getAsJsonArray()); + } + array.addAll(b); + return DataResult.success(array); + }); + builder = DataResult.success(new JsonArray()); return result; } From 77be75c8a5e2f870c092f797ef164e04a2f24faf Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 00:08:06 +0100 Subject: [PATCH 25/96] Replaced Type with Codec in DynamicOps --- .../datafixers/types/constant/EmptyPart.java | 4 +-- .../types/constant/EmptyPartSaving.java | 32 +----------------- .../java/com/mojang/serialization/Codec.java | 33 +++++++++++++++++++ .../com/mojang/serialization/Dynamic.java | 32 +++++++++--------- .../com/mojang/serialization/DynamicOps.java | 3 +- .../com/mojang/serialization/JsonOps.java | 28 ++++++++-------- 6 files changed, 64 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java index da166aad..997453fb 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java @@ -6,9 +6,7 @@ import com.mojang.datafixers.types.templates.TypeTemplate; import com.mojang.datafixers.util.Unit; import com.mojang.serialization.Codec; -import com.mojang.serialization.Decoder; import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.Encoder; import java.util.Optional; @@ -35,6 +33,6 @@ public TypeTemplate buildTemplate() { @Override protected Codec buildCodec() { - return Codec.of(Encoder.empty(), Decoder.unit(Unit.INSTANCE)); + return Codec.EMPTY; } } diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java index 7640342d..399f62ca 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java @@ -4,14 +4,11 @@ import com.mojang.datafixers.DSL; import com.mojang.datafixers.types.templates.TypeTemplate; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; import java.util.Optional; -import java.util.stream.Collectors; public final class EmptyPartSaving extends com.mojang.datafixers.types.Type> { @Override @@ -36,33 +33,6 @@ public TypeTemplate buildTemplate() { @Override public Codec> buildCodec() { - return new Codec>() { - @Override - public DataResult, T>> decode(final DynamicOps ops, final T input) { - return DataResult.success(Pair.of(new Dynamic<>(ops, input), ops.empty())); - } - - @Override - public DataResult encode(final Dynamic input, final DynamicOps ops, final T prefix) { - if (input.getValue() == input.getOps().empty()) { - // nothing to merge, return rest - return DataResult.success(prefix); - } - - final T casted = input.convert(ops).getValue(); - if (prefix == ops.empty()) { - // no need to merge anything, return the old value - return DataResult.success(casted); - } - - final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeToMap(prefix, map.collect(Pair.toMap()))); - return toMap.result().map(DataResult::success).orElseGet(() -> { - final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeToList(prefix, stream.collect(Collectors.toList()))); - return toList.result().map(DataResult::success).orElseGet(() -> - DataResult.error("Don't know how to merge " + prefix + " and " + casted, prefix) - ); - }); - } - }; + return Codec.SAVING; } } diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 69e19144..b6e76eec 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -4,6 +4,7 @@ import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; +import com.mojang.datafixers.util.Unit; import com.mojang.serialization.codecs.CompoundListCodec; import com.mojang.serialization.codecs.EitherCodec; import com.mojang.serialization.codecs.ListCodec; @@ -11,6 +12,7 @@ import com.mojang.serialization.codecs.PrimitiveCodec; import java.util.List; +import java.util.stream.Collectors; public interface Codec extends Encoder, Decoder { static Codec of(final Decoder decoder) { @@ -202,4 +204,35 @@ public String toString() { return "Double"; } }; + + Codec> SAVING = new Codec>() { + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + return DataResult.success(Pair.of(new Dynamic<>(ops, input), ops.empty())); + } + + @Override + public DataResult encode(final Dynamic input, final DynamicOps ops, final T prefix) { + if (input.getValue() == input.getOps().empty()) { + // nothing to merge, return rest + return DataResult.success(prefix); + } + + final T casted = input.convert(ops).getValue(); + if (prefix == ops.empty()) { + // no need to merge anything, return the old value + return DataResult.success(casted); + } + + final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeToMap(prefix, map.collect(Pair.toMap()))); + return toMap.result().map(DataResult::success).orElseGet(() -> { + final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeToList(prefix, stream.collect(Collectors.toList()))); + return toList.result().map(DataResult::success).orElseGet(() -> + DataResult.error("Don't know how to merge " + prefix + " and " + casted, prefix) + ); + }); + } + }; + + Codec EMPTY = Codec.of(Encoder.empty(), Decoder.unit(Unit.INSTANCE)); } diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index 70577b96..1ec37eec 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -3,9 +3,7 @@ package com.mojang.serialization; import com.google.common.collect.ImmutableMap; -import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; -import com.mojang.datafixers.types.Type; import com.mojang.datafixers.util.Pair; import javax.annotation.Nullable; @@ -194,47 +192,47 @@ public static T convert(final DynamicOps inOps, final DynamicOps ou if (Objects.equals(inOps, outOps)) { return (T) input; } - final Type type = inOps.getType(input); - if (Objects.equals(type, DSL.emptyPartType())) { + final Codec type = inOps.getType(input); + if (Objects.equals(type, Codec.EMPTY)) { return outOps.empty(); } - if (Objects.equals(type, DSL.byteType())) { + if (Objects.equals(type, Codec.BYTE)) { return outOps.createByte(inOps.getNumberValue(input, 0).byteValue()); } - if (Objects.equals(type, DSL.shortType())) { + if (Objects.equals(type, Codec.SHORT)) { return outOps.createShort(inOps.getNumberValue(input, 0).shortValue()); } - if (Objects.equals(type, DSL.intType())) { + if (Objects.equals(type, Codec.INT)) { return outOps.createInt(inOps.getNumberValue(input, 0).intValue()); } - if (Objects.equals(type, DSL.longType())) { + if (Objects.equals(type, Codec.LONG)) { return outOps.createLong(inOps.getNumberValue(input, 0).longValue()); } - if (Objects.equals(type, DSL.floatType())) { + if (Objects.equals(type, Codec.FLOAT)) { return outOps.createFloat(inOps.getNumberValue(input, 0).floatValue()); } - if (Objects.equals(type, DSL.doubleType())) { + if (Objects.equals(type, Codec.DOUBLE)) { return outOps.createDouble(inOps.getNumberValue(input, 0).doubleValue()); } - if (Objects.equals(type, DSL.bool())) { + if (Objects.equals(type, Codec.BOOL)) { return outOps.createBoolean(inOps.getBooleanValue(input).result().orElse(false)); } - if (Objects.equals(type, DSL.string())) { + if (Objects.equals(type, Codec.STRING)) { return outOps.createString(inOps.getStringValue(input).result().orElse("")); } - if (Objects.equals(type, DSL.list(DSL.byteType()))) { + if (Objects.equals(type, Codec.list(Codec.BYTE))) { return outOps.createByteList(inOps.getByteBuffer(input).result().orElse(ByteBuffer.wrap(new byte[0]))); } - if (Objects.equals(type, DSL.list(DSL.intType()))) { + if (Objects.equals(type, Codec.list(Codec.INT))) { return outOps.createIntList(inOps.getIntStream(input).result().orElse(IntStream.empty())); } - if (Objects.equals(type, DSL.list(DSL.longType()))) { + if (Objects.equals(type, Codec.list(Codec.LONG))) { return outOps.createLongList(inOps.getLongStream(input).result().orElse(LongStream.empty())); } - if (Objects.equals(type, DSL.list(DSL.remainderType()))) { + if (Objects.equals(type, Codec.list(Codec.SAVING))) { return outOps.createList(inOps.getStream(input).result().orElse(Stream.empty()).map(e -> convert(inOps, outOps, e))); } - if (Objects.equals(type, DSL.compoundList(DSL.remainderType(), DSL.remainderType()))) { + if (Objects.equals(type, Codec.compoundList(Codec.SAVING, Codec.SAVING))) { return outOps.createMap(inOps.getMapValues(input).result().orElse(Stream.empty()).map(e -> Pair.of(convert(inOps, outOps, e.getFirst()), convert(inOps, outOps, e.getSecond())) ).collect(Pair.toMap())); diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index ecf14332..5d0d2a56 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -3,7 +3,6 @@ package com.mojang.serialization; import com.google.common.collect.ImmutableMap; -import com.mojang.datafixers.types.Type; import com.mojang.datafixers.util.Function3; import com.mojang.datafixers.util.Pair; @@ -29,7 +28,7 @@ default T emptyList() { return createList(Stream.empty()); } - Type getType(final T input); + Codec getType(final T input); DataResult getNumberValue(T input); diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index ed51ef63..57b0f13e 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -8,8 +8,6 @@ import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -import com.mojang.datafixers.DSL; -import com.mojang.datafixers.types.Type; import com.mojang.datafixers.util.Pair; import java.math.BigDecimal; @@ -31,42 +29,42 @@ public JsonElement empty() { } @Override - public Type getType(final JsonElement input) { + public Codec getType(final JsonElement input) { if (input.isJsonObject()) { - return DSL.compoundList(DSL.remainderType(), DSL.remainderType()); + return Codec.compoundList(Codec.SAVING, Codec.SAVING); } if (input.isJsonArray()) { - return DSL.list(DSL.remainderType()); + return Codec.list(Codec.SAVING); } if (input.isJsonNull()) { - return DSL.emptyPartType(); + return Codec.EMPTY; } final JsonPrimitive primitive = input.getAsJsonPrimitive(); if (primitive.isString()) { - return DSL.string(); + return Codec.STRING; } if (primitive.isBoolean()) { - return DSL.bool(); + return Codec.BOOL; } final BigDecimal value = primitive.getAsBigDecimal(); try { final long l = value.longValueExact(); if ((byte) l == l) { - return DSL.byteType(); + return Codec.BYTE; } if ((short) l == l) { - return DSL.shortType(); + return Codec.SHORT; } if ((int) l == l) { - return DSL.intType(); + return Codec.INT; } - return DSL.longType(); + return Codec.LONG; } catch (final ArithmeticException e) { final double d = value.doubleValue(); if ((float) d == d) { - return DSL.floatType(); + return Codec.FLOAT; } - return DSL.doubleType(); + return Codec.DOUBLE; } } @@ -285,7 +283,7 @@ public DataResult build(final JsonElement prefix) { array.addAll(b); return DataResult.success(array); }); - + builder = DataResult.success(new JsonArray()); return result; } From 1e8fe073dc58d0e28671ac74969c21244df074f8 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 11:22:22 +0100 Subject: [PATCH 26/96] Better map interface for DynamicOps, allows returning a wrapper instead of building a new map. --- .../types/templates/TaggedChoice.java | 10 ++-- .../java/com/mojang/serialization/Codec.java | 2 +- .../com/mojang/serialization/Dynamic.java | 11 ++-- .../com/mojang/serialization/DynamicOps.java | 36 +++++++++---- .../com/mojang/serialization/JsonOps.java | 52 +++++++++++++------ .../com/mojang/serialization/MapLike.java | 36 +++++++++++++ 6 files changed, 109 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/MapLike.java diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index 94dd468e..0dd2bcbf 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -186,15 +186,13 @@ public TypeTemplate buildTemplate() { return new Codec>() { @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { - final DataResult>> values = ops.getMapValues(input); - return values.flatMap(vs -> { - final T nameString = ops.createString(name); - final Optional> nameEntry = vs.filter(v -> v.getFirst() == nameString).findFirst(); - if (!nameEntry.isPresent()) { + return ops.getMap(input).flatMap(map -> { + final T value = map.get(ops.createString(name)); + if (value == null) { return DataResult.error("Input does not contain a key [" + name + "] with the name: " + input); } - return keyType.codec().decode(ops, nameEntry.get().getSecond()).flatMap(key -> { + return keyType.codec().decode(ops, value).flatMap(key -> { final K keyValue = key.getFirst(); final Type type = types.get(keyValue); if (type != null) { diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index b6e76eec..0d1653ce 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -224,7 +224,7 @@ public DataResult encode(final Dynamic input, final DynamicOps ops, return DataResult.success(casted); } - final DataResult toMap = ops.getMapValues(casted).flatMap(map -> ops.mergeToMap(prefix, map.collect(Pair.toMap()))); + final DataResult toMap = ops.getMap(casted).flatMap(map -> ops.mergeToMap(prefix, map)); return toMap.result().map(DataResult::success).orElseGet(() -> { final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeToList(prefix, stream.collect(Collectors.toList()))); return toList.result().map(DataResult::success).orElseGet(() -> diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index 1ec37eec..c9519be7 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -111,13 +111,12 @@ public DataResult asLongStreamOpt() { @Override public OptionalDynamic get(final String key) { - return new OptionalDynamic<>(ops, ops.getMapValues(value).flatMap(m -> { - final T keyString = ops.createString(key); - final Optional value = m.filter(p -> Objects.equals(keyString, p.getFirst())).map(Pair::getSecond).findFirst(); - if (!value.isPresent()) { + return new OptionalDynamic<>(ops, ops.getMap(value).flatMap(m -> { + final T value = m.get(ops.createString(key)); + if (value == null) { return DataResult.error("key missing: " + key + " in " + this.value); } - return DataResult.success(new Dynamic<>(ops, value.get())); + return DataResult.success(new Dynamic<>(ops, value)); })); } @@ -235,7 +234,7 @@ public static T convert(final DynamicOps inOps, final DynamicOps ou if (Objects.equals(type, Codec.compoundList(Codec.SAVING, Codec.SAVING))) { return outOps.createMap(inOps.getMapValues(input).result().orElse(Stream.empty()).map(e -> Pair.of(convert(inOps, outOps, e.getFirst()), convert(inOps, outOps, e.getSecond())) - ).collect(Pair.toMap())); + )); } throw new IllegalStateException("Could not convert value of type " + type); } diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index 5d0d2a56..e3cda829 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; @@ -94,12 +95,16 @@ default DataResult mergeToList(final T list, final List values) { DataResult mergeToMap(T map, T key, T value); default DataResult mergeToMap(final T map, final Map values) { - DataResult result = DataResult.success(map); + return mergeToMap(map, MapLike.forMap(values)); + } - for (final Map.Entry entry : values.entrySet()) { - result = result.flatMap(r -> mergeToMap(r, entry.getKey(), entry.getValue())); - } - return result; + default DataResult mergeToMap(final T map, final MapLike values) { + final AtomicReference> result = new AtomicReference<>(DataResult.success(map)); + + values.entries().forEach(entry -> + result.set(result.get().flatMap(r -> mergeToMap(r, entry.getFirst(), entry.getSecond()))) + ); + return result.get(); } /** @@ -114,7 +119,21 @@ default DataResult mergeToPrimitive(final T prefix, final T value) { DataResult>> getMapValues(T input); - T createMap(Map map); + T createMap(Stream> map); + + default DataResult> getMap(final T input) { + return getMapValues(input).flatMap(s -> { + try { + return DataResult.success(MapLike.forMap(s.collect(Pair.toMap()))); + } catch (final IllegalStateException e) { + return DataResult.error("Error while building map: " + e.getMessage()); + } + }); + } + + default T createMap(final Map map) { + return createMap(map.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue()))); + } DataResult> getStream(T input); @@ -174,10 +193,7 @@ default DataResult get(final T input, final String key) { } default DataResult getGeneric(final T input, final T key) { - return getMapValues(input).flatMap(map -> map - .filter(p -> Objects.equals(key, p.getFirst())) - .map(Pair::getSecond) - .findFirst() + return getMap(input).flatMap(map -> Optional.ofNullable(map.get(key)) .map(DataResult::success) .orElseGet(() -> DataResult.error("No element " + key + " in the map " + input)) ); diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 57b0f13e..bf212430 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -10,9 +10,9 @@ import com.google.gson.JsonPrimitive; import com.mojang.datafixers.util.Pair; +import javax.annotation.Nullable; import java.math.BigDecimal; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -162,7 +162,7 @@ public DataResult mergeToMap(final JsonElement map, final JsonEleme } @Override - public DataResult mergeToMap(final JsonElement map, final Map values) { + public DataResult mergeToMap(final JsonElement map, final MapLike values) { if (!map.isJsonObject() && map != empty()) { return DataResult.error("mergeToMap called with not a map: " + map, map); } @@ -174,15 +174,14 @@ public DataResult mergeToMap(final JsonElement map, final Map missed = Lists.newArrayList(); - for (final Map.Entry entry : values.entrySet()) { - final JsonElement key = entry.getKey(); + values.entries().forEach(entry -> { + final JsonElement key = entry.getFirst(); if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString()) { missed.add(key); - continue; + return; } - - output.add(key.getAsString(), entry.getValue()); - } + output.add(key.getAsString(), entry.getSecond()); + }); if (!missed.isEmpty()) { return DataResult.error("some keys are not strings: " + missed, output); @@ -193,18 +192,41 @@ public DataResult mergeToMap(final JsonElement map, final Map>> getMapValues(final JsonElement input) { - if (input.isJsonObject()) { - return DataResult.success(input.getAsJsonObject().entrySet().stream().map(entry -> Pair.of(new JsonPrimitive(entry.getKey()), entry.getValue()))); + if (!input.isJsonObject()) { + return DataResult.error("Not a JSON object: " + input); } - return DataResult.error("Not a JSON object: " + input); + return DataResult.success(input.getAsJsonObject().entrySet().stream().map(entry -> Pair.of(new JsonPrimitive(entry.getKey()), entry.getValue()))); } @Override - public JsonElement createMap(final Map map) { - final JsonObject result = new JsonObject(); - for (final Map.Entry entry : map.entrySet()) { - result.add(entry.getKey().getAsString(), entry.getValue()); + public DataResult> getMap(final JsonElement input) { + if (!input.isJsonObject()) { + return DataResult.error("Not a JSON object: " + input); } + final JsonObject object = input.getAsJsonObject(); + return DataResult.success(new MapLike() { + @Nullable + @Override + public JsonElement get(final JsonElement key) { + return object.get(key.getAsString()); + } + + @Override + public Stream> entries() { + return object.entrySet().stream().map(e -> Pair.of(new JsonPrimitive(e.getKey()), e.getValue())); + } + + @Override + public String toString() { + return "MapLike[" + object + "]"; + } + }); + } + + @Override + public JsonElement createMap(final Stream> map) { + final JsonObject result = new JsonObject(); + map.forEach(p -> result.add(p.getFirst().getAsString(), p.getSecond())); return result; } diff --git a/src/main/java/com/mojang/serialization/MapLike.java b/src/main/java/com/mojang/serialization/MapLike.java new file mode 100644 index 00000000..2af07962 --- /dev/null +++ b/src/main/java/com/mojang/serialization/MapLike.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +import com.mojang.datafixers.util.Pair; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.stream.Stream; + +public interface MapLike { + @Nullable + T get(final T key); + + Stream> entries(); + + static MapLike forMap(final Map map) { + return new MapLike() { + @Nullable + @Override + public T get(final T key) { + return map.get(key); + } + + @Override + public Stream> entries() { + return map.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue())); + } + + @Override + public String toString() { + return "MapLike[" + map + "]"; + } + }; + } +} From 6bde925cfce0d29cf15def42a90a5ba3cce656bc Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 12:19:48 +0100 Subject: [PATCH 27/96] Applicative codec builder; switched applicative implementation from lift-based to apply-based --- .../mojang/datafixers/kinds/Applicative.java | 68 ++++- .../com/mojang/datafixers/kinds/ListBox.java | 2 +- .../datafixers/optics/ListTraversal.java | 2 +- .../datafixers/types/templates/Product.java | 2 +- .../datafixers/types/templates/Tag.java | 33 +-- .../types/templates/TaggedChoice.java | 1 - .../java/com/mojang/serialization/Codec.java | 13 + .../com/mojang/serialization/DataResult.java | 40 ++- .../com/mojang/serialization/Decoder.java | 19 +- .../com/mojang/serialization/Encoder.java | 9 +- .../com/mojang/serialization/MapDecoder.java | 27 ++ .../com/mojang/serialization/MapEncoder.java | 12 + .../serialization/codecs/FieldCodec.java | 86 ++++++ .../codecs/RecordCodecBuilder.java | 279 ++++++++++++++++++ 14 files changed, 524 insertions(+), 69 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/MapDecoder.java create mode 100644 src/main/java/com/mojang/serialization/MapEncoder.java create mode 100644 src/main/java/com/mojang/serialization/codecs/FieldCodec.java create mode 100644 src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index fd960b15..6cf5298d 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -23,28 +23,27 @@ interface Mu extends Functor.Mu {} Function, App> lift1(final App> function); default BiFunction, App, App> lift2(final App> function) { - final Function, Function>> curry = f -> a -> b -> f.apply(a, b); - return (fa, fb) -> ap(lift1(map(curry, function)).apply(fa), fb); + return (fa, fb) -> ap2(function, fa, fb); } default Function3, App, App, App> lift3(final App> function) { - return (ft1, ft2, ft3) -> lift2(lift1(map(Function3::curry, function)).apply(ft1)).apply(ft2, ft3); + return (ft1, ft2, ft3) -> ap3(function, ft1, ft2, ft3); } default Function4, App, App, App, App> lift4(final App> function) { - return (ft1, ft2, ft3, ft4) -> lift2(lift2(map(Function4::curry2, function)).apply(ft1, ft2)).apply(ft3, ft4); + return (ft1, ft2, ft3, ft4) -> ap4(function, ft1, ft2, ft3, ft4); } default Function5, App, App, App, App, App> lift5(final App> function) { - return (ft1, ft2, ft3, ft4, ft5) -> lift3(lift2(map(Function5::curry2, function)).apply(ft1, ft2)).apply(ft3, ft4, ft5); + return (ft1, ft2, ft3, ft4, ft5) -> ap5(function, ft1, ft2, ft3, ft4, ft5); } default Function6, App, App, App, App, App, App> lift6(final App> function) { - return (ft1, ft2, ft3, ft4, ft5, ft6) -> lift3(lift3(map(Function6::curry3, function)).apply(ft1, ft2, ft3)).apply(ft4, ft5, ft6); + return (ft1, ft2, ft3, ft4, ft5, ft6) -> ap6(function, ft1, ft2, ft3, ft4, ft5, ft6); } default Function7, App, App, App, App, App, App, App> lift7(final App> function) { - return (ft1, ft2, ft3, ft4, ft5, ft6, ft7) -> lift4(lift3(map(Function7::curry3, function)).apply(ft1, ft2, ft3)).apply(ft4, ft5, ft6, ft7); + return (ft1, ft2, ft3, ft4, ft5, ft6, ft7) -> ap7(function, ft1, ft2, ft3, ft4, ft5, ft6, ft7); } default App ap(final App> func, final App arg) { @@ -56,13 +55,54 @@ default App ap(final Function func, final App arg) { } default App ap2(final App> func, final App a, final App b) { - return lift2(func).apply(a, b); + final Function, Function>> curry = f -> a1 -> b1 -> f.apply(a1, b1); + return ap(ap(map(curry, func), a), b); } - default App ap2(final BiFunction func, final App a, final App b) { + default App apply2(BiFunction func, final App a, final App b) { return ap2(point(func), a, b); } + default App ap3(final App> func, final App t1, final App t2, final App t3) { + return ap2(ap(map(Function3::curry, func), t1), t2, t3); + } + + default App apply3(final Function3 func, final App t1, final App t2, final App t3) { + return ap3(point(func), t1, t2, t3); + } + + default App ap4(final App> func, final App t1, final App t2, final App t3, final App t4) { + return ap2(ap2(map(Function4::curry2, func), t1, t2), t3, t4); + } + + default App apply4(final Function4 func, final App t1, final App t2, final App t3, final App t4) { + return ap4(point(func), t1, t2, t3, t4); + } + + default App ap5(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5) { + return ap3(ap2(map(Function5::curry2, func), t1, t2), t3, t4, t5); + } + + default App apply5(final Function5 func, final App t1, final App t2, final App t3, final App t4, final App t5) { + return ap5(point(func), t1, t2, t3, t4, t5); + } + + default App ap6(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { + return ap3(ap3(map(Function6::curry3, func), t1, t2, t3), t4, t5, t6); + } + + default App apply6(final Function6 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { + return ap6(point(func), t1, t2, t3, t4, t5, t6); + } + + default App ap7(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { + return ap4(ap3(map(Function7::curry3, func), t1, t2, t3), t4, t5, t6, t7); + } + + default App apply7(final Function7 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { + return ap7(point(func), t1, t2, t3, t4, t5, t6, t7); + } + default P1 group(final App t1) { return new P1<>(this, t1); } @@ -159,7 +199,7 @@ public App apply(final Function3 function) { } public App apply(final App> function) { - return instance.lift3(function).apply(t1, t2, t3); + return instance.ap3(function, t1, t2, t3); } } @@ -187,7 +227,7 @@ public App apply(final Function4 function) { } public App apply(final App> function) { - return instance.lift4(function).apply(t1, t2, t3, t4); + return instance.ap4(function, t1, t2, t3, t4); } } @@ -217,7 +257,7 @@ public App apply(final Function5 function) { } public App apply(final App> function) { - return instance.lift5(function).apply(t1, t2, t3, t4, t5); + return instance.ap5(function, t1, t2, t3, t4, t5); } } @@ -249,7 +289,7 @@ public App apply(final Function6 function) } public App apply(final App> function) { - return instance.lift6(function).apply(t1, t2, t3, t4, t5, t6); + return instance.ap6(function, t1, t2, t3, t4, t5, t6); } } @@ -279,7 +319,7 @@ public App apply(final Function7 functi } public App apply(final App> function) { - return instance.lift7(function).apply(t1, t2, t3, t4, t5, t6, t7); + return instance.ap7(function, t1, t2, t3, t4, t5, t6, t7); } } } diff --git a/src/main/java/com/mojang/datafixers/kinds/ListBox.java b/src/main/java/com/mojang/datafixers/kinds/ListBox.java index 0e3ccd86..334cce7a 100644 --- a/src/main/java/com/mojang/datafixers/kinds/ListBox.java +++ b/src/main/java/com/mojang/datafixers/kinds/ListBox.java @@ -51,7 +51,7 @@ public App> traverse(final Applicativ for (final A a : list) { final App fb = function.apply(a); - result = applicative.ap2(ImmutableList.Builder::add, result, fb); + result = applicative.ap2(applicative.point(ImmutableList.Builder::add), result, fb); } return applicative.map(b -> create(b.build()), result); diff --git a/src/main/java/com/mojang/datafixers/optics/ListTraversal.java b/src/main/java/com/mojang/datafixers/optics/ListTraversal.java index b24d88ad..3f5d6880 100644 --- a/src/main/java/com/mojang/datafixers/optics/ListTraversal.java +++ b/src/main/java/com/mojang/datafixers/optics/ListTraversal.java @@ -16,7 +16,7 @@ public FunctionType, App>> wander(final Applic return as -> { App> result = applicative.point(ImmutableList.builder()); for (final A a : as) { - result = applicative.ap2(ImmutableList.Builder::add, result, input.apply(a)); + result = applicative.ap2(applicative.point(ImmutableList.Builder::add), result, input.apply(a)); } return applicative.map(ImmutableList.Builder::build, result); }; diff --git a/src/main/java/com/mojang/datafixers/types/templates/Product.java b/src/main/java/com/mojang/datafixers/types/templates/Product.java index 26210a2e..5f2eb76b 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Product.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Product.java @@ -101,7 +101,7 @@ private OpticParts cap(final FamilyOptic lo, new Traversal, Pair, A, B>() { @Override public FunctionType, App>> wander(final Applicative applicative, final FunctionType> input) { - return p -> applicative.ap2(Pair::of, + return p -> applicative.ap2(applicative.point(Pair::of), lt.wander(applicative, input).apply(p.getFirst()), rt.wander(applicative, input).apply(p.getSecond()) ); diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index ad347745..e0589d03 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -13,18 +13,13 @@ import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.families.TypeFamily; import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import javax.annotation.Nullable; -import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.IntFunction; -import java.util.stream.Collectors; public final class Tag implements TypeTemplate { private final String name; @@ -175,33 +170,7 @@ public TypeTemplate buildTemplate() { @Override protected Codec buildCodec() { - return new Codec() { - @Override - public DataResult> decode(final DynamicOps ops, final T input) { - return ops.getMapValues(input).flatMap(map -> { - final T nameObject = ops.createString(name); - - final Map>> partitioned = map.collect(Collectors.partitioningBy(p -> Objects.equals(p.getFirst(), nameObject))); - final List> matched = partitioned.get(true); - final List> rest = partitioned.get(false); - if (matched.isEmpty()) { - return DataResult.error("No keys matched " + name); - } - if (matched.size() != 1) { - return DataResult.error("Too many keys matched " + name + ": " + matched); - } - - return element.codec().decode(ops, matched.get(0).getSecond()).map(value -> - Pair.of(value.getFirst(), ops.createMap(rest.stream().collect(Pair.toMap()))) - ); - }); - } - - @Override - public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return element.codec().encodeStart(ops, input).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); - } - }; + return element.codec().fieldOf(name); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index 0dd2bcbf..dadd50e0 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -45,7 +45,6 @@ import java.util.Set; import java.util.function.Function; import java.util.function.IntFunction; -import java.util.stream.Stream; public final class TaggedChoice implements TypeTemplate { private final String name; diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 0d1653ce..5220db17 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -7,6 +7,7 @@ import com.mojang.datafixers.util.Unit; import com.mojang.serialization.codecs.CompoundListCodec; import com.mojang.serialization.codecs.EitherCodec; +import com.mojang.serialization.codecs.FieldCodec; import com.mojang.serialization.codecs.ListCodec; import com.mojang.serialization.codecs.PairCodec; import com.mojang.serialization.codecs.PrimitiveCodec; @@ -54,6 +55,18 @@ static Codec>> compoundList(final Codec keyCodec, fina return new CompoundListCodec<>(keyCodec, elementCodec); } + static FieldCodec field(final String name, final Codec elementCodec) { + return new FieldCodec<>(name, elementCodec); + } + + default Codec> listOf() { + return list(this); + } + + default FieldCodec fieldOf(final String name) { + return field(name, this); + } + PrimitiveCodec FLOAT = new PrimitiveCodec() { @Override public DataResult read(final DynamicOps ops, final T input) { diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 876266d8..4d7f75ce 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -6,6 +6,7 @@ import com.mojang.datafixers.kinds.Applicative; import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Function3; import java.util.Objects; import java.util.Optional; @@ -196,22 +197,51 @@ public static final class Mu implements Applicative.Mu {} @Override public App map(final Function func, final App ts) { - return DataResult.unbox(ts).map(func); + return unbox(ts).map(func); } @Override public App point(final A a) { - return DataResult.success(a); + return success(a); } @Override public Function, App> lift1(final App> function) { - return a -> DataResult.unbox(function).flatMap(f -> DataResult.unbox(a).map(f)); + return fa -> ap(function, fa); } + /** Argument error before the function */ @Override - public BiFunction, App, App> lift2(final App> function) { - return (a, b) -> DataResult.unbox(function).flatMap(f -> DataResult.unbox(a).flatMap(av -> DataResult.unbox(b).map(bv -> f.apply(av, bv)))); + public App ap(final App> func, final App arg) { + return unbox(arg).flatMap(av -> + unbox(func).map(f -> + f.apply(av) + ) + ); + } + + @Override + public App ap2(final App> func, final App a, final App b) { + return unbox(a).flatMap(av -> + unbox(b).flatMap(bv -> + unbox(func).map(f -> + f.apply(av, bv) + ) + ) + ); + } + + @Override + public App ap3(final App> func, final App t1, final App t2, final App t3) { + return unbox(t1).flatMap(r1 -> + unbox(t2).flatMap(r2 -> + unbox(t3).flatMap(r3 -> + unbox(func).map(f -> + f.apply(r1, r2, r3) + ) + ) + ) + ); } } } \ No newline at end of file diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index ef589373..00c63d67 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -57,22 +57,17 @@ static Decoder ofSimple(final Simple simple) { return simple.decoder().map(Function.identity()); } - static Decoder unit(final A instance) { - return new Decoder() { - @Override - public DataResult> decode(final DynamicOps ops, final T input) { - return DataResult.success(Pair.of(instance, input)); - } + static MapDecoder unit(final A instance) { + return unit(() -> instance); + } + static MapDecoder unit(final Supplier instance) { + return new MapDecoder() { @Override - public String toString() { - return "UnitDecoder[" + instance + "]"; + public DataResult decode(final DynamicOps ops, final MapLike input) { + return DataResult.success(instance.get()); } - }; - } - static Decoder unit(final Supplier instance) { - return new Decoder() { @Override public DataResult> decode(final DynamicOps ops, final T input) { return DataResult.success(Pair.of(instance.get(), input)); diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index d2343a5f..8796027e 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -23,8 +23,13 @@ public String toString() { }; } - static Encoder empty() { - return new Encoder() { + static MapEncoder empty() { + return new MapEncoder() { + @Override + public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { + return prefix; + } + @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { return DataResult.success(prefix); diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java new file mode 100644 index 00000000..4441980b --- /dev/null +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +import com.mojang.datafixers.util.Pair; + +import java.util.function.Function; + +public interface MapDecoder extends Decoder { + DataResult decode(DynamicOps ops, MapLike input); + + @Override + default DataResult> decode(final DynamicOps ops, final T input) { + return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> Pair.of(r, input))); + } + + @Override + default MapDecoder map(final Function function) { + final MapDecoder self = this; + return new MapDecoder() { + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return self.decode(ops, input).map(function); + } + }; + } +} diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java new file mode 100644 index 00000000..a00c4cda --- /dev/null +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +public interface MapEncoder extends Encoder { + RecordBuilder encode(A input, DynamicOps ops, RecordBuilder prefix); + + @Override + default DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return encode(input, ops, ops.mapBuilder()).build(prefix); + } +} diff --git a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java new file mode 100644 index 00000000..c57c53c7 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.MapDecoder; +import com.mojang.serialization.MapEncoder; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; + +import java.util.Objects; +import java.util.function.Function; + +public class FieldCodec implements MapEncoder, MapDecoder, Codec { + public static boolean REMOVE_FIELD_WHEN_PARSING = false; + + private final String name; + private final Codec elementCodec; + + public FieldCodec(final String name, final Codec elementCodec) { + this.name = name; + this.elementCodec = elementCodec; + } + + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> { + final T output; + if (REMOVE_FIELD_WHEN_PARSING) { + final T nameObject = ops.createString(name); + output = ops.createMap(map.entries().filter(e -> !Objects.equals(e.getFirst(), nameObject))); + } else { + output = input; + } + return Pair.of(r, output); + })); + } + + @Override + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return elementCodec.encodeStart(ops, input).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); + } + + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + final T value = input.get(ops.createString(name)); + if (value == null) { + return DataResult.error("No key " + name + " in " + input); + } + return elementCodec.parse(ops, value); + } + + @Override + public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { + return prefix.add(name, elementCodec.encodeStart(ops, input)); + } + + public RecordCodecBuilder forGetter(final Function getter) { + return RecordCodecBuilder.of(getter, this); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final FieldCodec that = (FieldCodec) o; + return Objects.equals(name, that.name) && Objects.equals(elementCodec, that.elementCodec); + } + + @Override + public int hashCode() { + return Objects.hash(name, elementCodec); + } + + @Override + public String toString() { + return "FieldCodec[" + name + ": " + elementCodec + ']'; + } +} diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java new file mode 100644 index 00000000..b46197cc --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -0,0 +1,279 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.datafixers.kinds.App; +import com.mojang.datafixers.kinds.Applicative; +import com.mojang.datafixers.kinds.K1; +import com.mojang.datafixers.util.Function3; +import com.mojang.datafixers.util.Function4; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Decoder; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Encoder; +import com.mojang.serialization.MapDecoder; +import com.mojang.serialization.MapEncoder; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public final class RecordCodecBuilder implements App, F> { + public static final class Mu implements K1 { + } + + public static RecordCodecBuilder unbox(final App, F> box) { + return ((RecordCodecBuilder) box); + } + + private final Function getter; + private final Function> encoder; + private final MapDecoder decoder; + + private RecordCodecBuilder(final Function getter, final Function> encoder, final MapDecoder decoder) { + this.getter = getter; + this.encoder = encoder; + this.decoder = decoder; + } + + public static Instance instance() { + return new Instance<>(); + } + + public static RecordCodecBuilder of(final Function getter, final String name, final Codec fieldCodec) { + return of(getter, fieldCodec.fieldOf(name)); + } + + public static & MapEncoder> RecordCodecBuilder of(final Function getter, final C codec) { + return new RecordCodecBuilder<>(getter, o -> codec, codec); + } + + public static RecordCodecBuilder point(final F instance) { + return new RecordCodecBuilder<>(o -> instance, o -> Encoder.empty(), Decoder.unit(instance)); + } + + public static Codec build(final App, O> builder) { + return build(unbox(builder)); + } + + public static Codec build(final RecordCodecBuilder builder) { + return new Codec() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return builder.decoder.decode(ops, input); + } + + @Override + public DataResult encode(final O input, final DynamicOps ops, final T prefix) { + return builder.encoder.apply(input).encode(input, ops, prefix); + } + + @Override + public String toString() { + return "RecordCodec[" + builder.decoder + "]"; + } + }; + } + + public static final class Instance implements Applicative, Instance.Mu> { + private static final class Mu implements Applicative.Mu { + } + + @Override + public App, A> point(final A a) { + return RecordCodecBuilder.point(a); + } + + @Override + public Function, A>, App, R>> lift1(final App, Function> function) { + return fa -> { + final RecordCodecBuilder> f = unbox(function); + final RecordCodecBuilder a = unbox(fa); + + return new RecordCodecBuilder<>( + o -> f.getter.apply(o).apply(a.getter.apply(o)), + o -> { + final MapEncoder> fEnc = f.encoder.apply(o); + final MapEncoder aEnc = a.encoder.apply(o); + final A aFromO = a.getter.apply(o); + + return new MapEncoder() { + @Override + public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { + aEnc.encode(aFromO, ops, prefix); + fEnc.encode(a1 -> input, ops, prefix); + return prefix; + } + }; + }, + + new MapDecoder() { + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return a.decoder.decode(ops, input).flatMap(ar -> + f.decoder.decode(ops, input).map(fr -> + fr.apply(ar) + ) + ); + } + } + ); + }; + } + + @Override + public App, R> ap2(final App, BiFunction> func, final App, A> a, final App, B> b) { + final RecordCodecBuilder> function = unbox(func); + final RecordCodecBuilder fa = unbox(a); + final RecordCodecBuilder fb = unbox(b); + + return new RecordCodecBuilder<>( + o -> function.getter.apply(o).apply(fa.getter.apply(o), fb.getter.apply(o)), + o -> { + final MapEncoder> fEncoder = function.encoder.apply(o); + final MapEncoder aEncoder = fa.encoder.apply(o); + final A aFromO = fa.getter.apply(o); + final MapEncoder bEncoder = fb.encoder.apply(o); + final B bFromO = fb.getter.apply(o); + + return new MapEncoder() { + @Override + public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { + aEncoder.encode(aFromO, ops, prefix); + bEncoder.encode(bFromO, ops, prefix); + fEncoder.encode((a1, b1) -> input, ops, prefix); + return prefix; + } + }; + }, + new MapDecoder() { + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return DataResult.unbox(DataResult.instance().group( + fa.decoder.decode(ops, input), + fb.decoder.decode(ops, input) + ).apply(function.decoder.decode(ops, input))); + } + } + ); + } + + @Override + public App, R> ap3(final App, Function3> func, final App, T1> t1, final App, T2> t2, final App, T3> t3) { + final RecordCodecBuilder> function = unbox(func); + final RecordCodecBuilder f1 = unbox(t1); + final RecordCodecBuilder f2 = unbox(t2); + final RecordCodecBuilder f3 = unbox(t3); + + return new RecordCodecBuilder<>( + o -> function.getter.apply(o).apply( + f1.getter.apply(o), + f2.getter.apply(o), + f3.getter.apply(o) + ), + o -> { + final MapEncoder> fEncoder = function.encoder.apply(o); + final MapEncoder e1 = f1.encoder.apply(o); + final T1 v1 = f1.getter.apply(o); + final MapEncoder e2 = f2.encoder.apply(o); + final T2 v2 = f2.getter.apply(o); + final MapEncoder e3 = f3.encoder.apply(o); + final T3 v3 = f3.getter.apply(o); + + return new MapEncoder() { + @Override + public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { + e1.encode(v1, ops, prefix); + e2.encode(v2, ops, prefix); + e3.encode(v3, ops, prefix); + fEncoder.encode((t1, t2, t3) -> input, ops, prefix); + return prefix; + } + }; + }, + new MapDecoder() { + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return DataResult.unbox(DataResult.instance().group( + f1.decoder.decode(ops, input), + f2.decoder.decode(ops, input), + f3.decoder.decode(ops, input) + ).apply(function.decoder.decode(ops, input))); + } + } + ); + } + + @Override + public App, R> ap4(final App, Function4> func, final App, T1> t1, final App, T2> t2, final App, T3> t3, final App, T4> t4) { + final RecordCodecBuilder> function = unbox(func); + final RecordCodecBuilder f1 = unbox(t1); + final RecordCodecBuilder f2 = unbox(t2); + final RecordCodecBuilder f3 = unbox(t3); + final RecordCodecBuilder f4 = unbox(t4); + + return new RecordCodecBuilder<>( + o -> function.getter.apply(o).apply( + f1.getter.apply(o), + f2.getter.apply(o), + f3.getter.apply(o), + f4.getter.apply(o) + ), + o -> { + final MapEncoder> fEncoder = function.encoder.apply(o); + final MapEncoder e1 = f1.encoder.apply(o); + final T1 v1 = f1.getter.apply(o); + final MapEncoder e2 = f2.encoder.apply(o); + final T2 v2 = f2.getter.apply(o); + final MapEncoder e3 = f3.encoder.apply(o); + final T3 v3 = f3.getter.apply(o); + final MapEncoder e4 = f4.encoder.apply(o); + final T4 v4 = f4.getter.apply(o); + + return new MapEncoder() { + @Override + public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { + e1.encode(v1, ops, prefix); + e2.encode(v2, ops, prefix); + e3.encode(v3, ops, prefix); + e4.encode(v4, ops, prefix); + fEncoder.encode((t1, t2, t3, t4) -> input, ops, prefix); + return prefix; + } + }; + }, + new MapDecoder() { + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return DataResult.unbox(DataResult.instance().group( + f1.decoder.decode(ops, input), + f2.decoder.decode(ops, input), + f3.decoder.decode(ops, input), + f4.decoder.decode(ops, input) + ).apply(function.decoder.decode(ops, input))); + } + } + ); + } + + @Override + public App, R> map(final Function func, final App, T> ts) { + final RecordCodecBuilder unbox = unbox(ts); + final Function getter = unbox.getter; + return new RecordCodecBuilder<>( + getter.andThen(func), + o -> new MapEncoder() { + @Override + public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { + return unbox.encoder.apply(o).encode(getter.apply(o), ops, prefix); + } + }, + unbox.decoder.map(func) + ); + } + } +} + From 26fdeffb4315d3382b57a37018d1b86ee9b50d4d Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 12:43:28 +0100 Subject: [PATCH 28/96] Couple more overrides in DataResult.Instance for less recursion. --- .../com/mojang/serialization/DataResult.java | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 4d7f75ce..696c5222 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -222,6 +222,22 @@ public App ap(final App> @Override public App ap2(final App> func, final App a, final App b) { + final DataResult> fr = unbox(func); + final DataResult ra = unbox(a); + final DataResult rb = unbox(b); + + // for less recursion + if (fr.result.left().isPresent() + && ra.result.left().isPresent() + && rb.result.left().isPresent()){ + return DataResult.success( + fr.result.left().get().apply( + ra.result.left().get(), + rb.result.left().get() + ) + ); + } + return unbox(a).flatMap(av -> unbox(b).flatMap(bv -> unbox(func).map(f -> @@ -233,10 +249,29 @@ public App ap2(final App App ap3(final App> func, final App t1, final App t2, final App t3) { - return unbox(t1).flatMap(r1 -> - unbox(t2).flatMap(r2 -> - unbox(t3).flatMap(r3 -> - unbox(func).map(f -> + final DataResult> fr = unbox(func); + final DataResult dr1 = unbox(t1); + final DataResult dr2 = unbox(t2); + final DataResult dr3 = unbox(t3); + + // for less recursion + if (fr.result.left().isPresent() + && dr1.result.left().isPresent() + && dr2.result.left().isPresent() + && dr3.result.left().isPresent()) { + return DataResult.success( + fr.result.left().get().apply( + dr1.result.left().get(), + dr2.result.left().get(), + dr3.result.left().get() + ) + ); + } + + return dr1.flatMap(r1 -> + dr2.flatMap(r2 -> + dr3.flatMap(r3 -> + fr.map(f -> f.apply(r1, r2, r3) ) ) From 3773900d038be276019ee9a61d3fb79eccb97154 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 13:40:27 +0100 Subject: [PATCH 29/96] Added OptionalFieldCodec --- .../java/com/mojang/serialization/Codec.java | 9 ++ .../codecs/OptionalFieldCodec.java | 92 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 5220db17..5d72d883 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -9,6 +9,7 @@ import com.mojang.serialization.codecs.EitherCodec; import com.mojang.serialization.codecs.FieldCodec; import com.mojang.serialization.codecs.ListCodec; +import com.mojang.serialization.codecs.OptionalFieldCodec; import com.mojang.serialization.codecs.PairCodec; import com.mojang.serialization.codecs.PrimitiveCodec; @@ -59,6 +60,10 @@ static FieldCodec field(final String name, final Codec elementCodec) { return new FieldCodec<>(name, elementCodec); } + static OptionalFieldCodec optionalField(final String name, final Codec elementCodec) { + return new OptionalFieldCodec<>(name, elementCodec); + } + default Codec> listOf() { return list(this); } @@ -67,6 +72,10 @@ default FieldCodec fieldOf(final String name) { return field(name, this); } + default OptionalFieldCodec optionalFieldOf(final String name) { + return optionalField(name, this); + } + PrimitiveCodec FLOAT = new PrimitiveCodec() { @Override public DataResult read(final DynamicOps ops, final T input) { diff --git a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java new file mode 100644 index 00000000..6c795611 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.MapDecoder; +import com.mojang.serialization.MapEncoder; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +/** Optimization of `Codec.either(someCodec.field(name), Codec.EMPTY)` */ +public class OptionalFieldCodec implements MapEncoder>, MapDecoder>, Codec> { + private final String name; + private final Codec elementCodec; + + public OptionalFieldCodec(final String name, final Codec elementCodec) { + this.name = name; + this.elementCodec = elementCodec; + } + + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> { + final T output; + if (FieldCodec.REMOVE_FIELD_WHEN_PARSING) { + final T nameObject = ops.createString(name); + output = ops.createMap(map.entries().filter(e -> !Objects.equals(e.getFirst(), nameObject))); + } else { + output = input; + } + return Pair.of(r, output); + })); + } + + @Override + public DataResult encode(final Optional input, final DynamicOps ops, final T prefix) { + if (input.isPresent()) { + return elementCodec.encodeStart(ops, input.get()).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); + } + return DataResult.success(prefix); + } + + @Override + public DataResult> decode(final DynamicOps ops, final MapLike input) { + final T value = input.get(ops.createString(name)); + if (value == null) { + return DataResult.success(Optional.empty()); + } + return elementCodec.parse(ops, value).map(Optional::of); + } + + @Override + public RecordBuilder encode(final Optional input, final DynamicOps ops, final RecordBuilder prefix) { + if (input.isPresent()) { + return prefix.add(name, elementCodec.encodeStart(ops, input.get())); + } + return prefix; + } + + public RecordCodecBuilder> forGetter(final Function> getter) { + return RecordCodecBuilder.of(getter, this); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final OptionalFieldCodec that = (OptionalFieldCodec) o; + return Objects.equals(name, that.name) && Objects.equals(elementCodec, that.elementCodec); + } + + @Override + public int hashCode() { + return Objects.hash(name, elementCodec); + } + + @Override + public String toString() { + return "OptionalFieldCodec[" + name + ": " + elementCodec + ']'; + } +} From ccea94ffc9b4315b7b08e4b061b6f81e067e4500 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 13:47:37 +0100 Subject: [PATCH 30/96] 8-arg applicative boilerplate. --- .../mojang/datafixers/kinds/Applicative.java | 45 +++++++++++++++++++ .../com/mojang/datafixers/util/Function8.java | 36 +++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/main/java/com/mojang/datafixers/util/Function8.java diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index 6cf5298d..06f58d60 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -7,6 +7,7 @@ import com.mojang.datafixers.util.Function5; import com.mojang.datafixers.util.Function6; import com.mojang.datafixers.util.Function7; +import com.mojang.datafixers.util.Function8; import java.util.function.BiFunction; import java.util.function.Function; @@ -103,6 +104,14 @@ default App apply7(final Function7 App ap8(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { + return ap4(ap4(map(Function8::curry4, func), t1, t2, t3, t4), t5, t6, t7, t8); + } + + default App apply8(final Function8 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { + return ap8(point(func), t1, t2, t3, t4, t5, t6, t7, t8); + } + default P1 group(final App t1) { return new P1<>(this, t1); } @@ -131,6 +140,10 @@ default P7 group(fin return new P7<>(this, t1, t2, t3, t4, t5, t6, t7); } + default P8 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { + return new P8<>(this, t1, t2, t3, t4, t5, t6, t7, t8); + } + final class P1 { private final Applicative instance; private final App t1; @@ -322,4 +335,36 @@ public App apply(final App return instance.ap7(function, t1, t2, t3, t4, t5, t6, t7); } } + + final class P8 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + + private P8(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + } + + public App apply(final Function8 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap8(function, t1, t2, t3, t4, t5, t6, t7, t8); + } + } } diff --git a/src/main/java/com/mojang/datafixers/util/Function8.java b/src/main/java/com/mojang/datafixers/util/Function8.java new file mode 100644 index 00000000..859e43c6 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function8.java @@ -0,0 +1,36 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function8 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7, t8) -> apply(t1, t2, t3, t4, t5, t6, t7, t8); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7, t8) -> apply(t1, t2, t3, t4, t5, t6, t7, t8); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7, t8) -> apply(t1, t2, t3, t4, t5, t6, t7, t8); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7, t8) -> apply(t1, t2, t3, t4, t5, t6, t7, t8); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7, t8) -> apply(t1, t2, t3, t4, t5, t6, t7, t8); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> (t7, t8) -> apply(t1, t2, t3, t4, t5, t6, t7, t8); + } + + default Function7> curry7() { + return (t1, t2, t3, t4, t5, t6, t7) -> t8 -> apply(t1, t2, t3, t4, t5, t6, t7, t8); + } +} From cf620f6ea2a1f8936da5cf4bfe3adc1e0090c3a3 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 16:39:24 +0100 Subject: [PATCH 31/96] Codec.withDefault --- .../java/com/mojang/serialization/Codec.java | 28 +++++++++++++-- .../com/mojang/serialization/MapCodec.java | 34 +++++++++++++++++++ .../serialization/codecs/FieldCodec.java | 10 ++---- .../codecs/OptionalFieldCodec.java | 10 ++---- 4 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/MapCodec.java diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 5d72d883..8622bbb3 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -2,6 +2,7 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Unit; @@ -14,6 +15,8 @@ import com.mojang.serialization.codecs.PrimitiveCodec; import java.util.List; +import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; public interface Codec extends Encoder, Decoder { @@ -60,7 +63,7 @@ static FieldCodec field(final String name, final Codec elementCodec) { return new FieldCodec<>(name, elementCodec); } - static OptionalFieldCodec optionalField(final String name, final Codec elementCodec) { + static MapCodec> optionalField(final String name, final Codec elementCodec) { return new OptionalFieldCodec<>(name, elementCodec); } @@ -72,10 +75,31 @@ default FieldCodec fieldOf(final String name) { return field(name, this); } - default OptionalFieldCodec optionalFieldOf(final String name) { + default MapCodec> optionalFieldOf(final String name) { return optionalField(name, this); } + default Codec withDefault(final A value) { + final Codec self = this; + + return new Codec() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return DataResult.success(self.decode(ops, input).result().orElseGet(() -> Pair.of(value, input))); + } + + @Override + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return self.encode(input, ops, prefix); + } + + @Override + public String toString() { + return "WithDefault[" + self + " " + value + "]"; + } + }; + } + PrimitiveCodec FLOAT = new PrimitiveCodec() { @Override public DataResult read(final DynamicOps ops, final T input) { diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java new file mode 100644 index 00000000..4261f81b --- /dev/null +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import java.util.function.Function; + +public interface MapCodec extends MapDecoder, MapEncoder, Codec { + default RecordCodecBuilder forGetter(final Function getter) { + return RecordCodecBuilder.of(getter, this); + } + + @Override + default MapCodec withDefault(final A value) { + final MapCodec self = this; + return new MapCodec() { + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return DataResult.success(self.decode(ops, input).result().orElse(value)); + } + + @Override + public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { + return self.encode(input, ops, prefix); + } + + @Override + public String toString() { + return "WithDefault[" + self + " " + value + "]"; + } + }; + } +} diff --git a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java index c57c53c7..224f4651 100644 --- a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java @@ -6,15 +6,13 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.MapDecoder; -import com.mojang.serialization.MapEncoder; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapLike; import com.mojang.serialization.RecordBuilder; import java.util.Objects; -import java.util.function.Function; -public class FieldCodec implements MapEncoder, MapDecoder, Codec { +public class FieldCodec implements MapCodec { public static boolean REMOVE_FIELD_WHEN_PARSING = false; private final String name; @@ -58,10 +56,6 @@ public RecordBuilder encode(final A input, final DynamicOps ops, final return prefix.add(name, elementCodec.encodeStart(ops, input)); } - public RecordCodecBuilder forGetter(final Function getter) { - return RecordCodecBuilder.of(getter, this); - } - @Override public boolean equals(final Object o) { if (this == o) { diff --git a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java index 6c795611..8210d32a 100644 --- a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java @@ -6,17 +6,15 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.MapDecoder; -import com.mojang.serialization.MapEncoder; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapLike; import com.mojang.serialization.RecordBuilder; import java.util.Objects; import java.util.Optional; -import java.util.function.Function; /** Optimization of `Codec.either(someCodec.field(name), Codec.EMPTY)` */ -public class OptionalFieldCodec implements MapEncoder>, MapDecoder>, Codec> { +public class OptionalFieldCodec implements MapCodec> { private final String name; private final Codec elementCodec; @@ -64,10 +62,6 @@ public RecordBuilder encode(final Optional input, final DynamicOps return prefix; } - public RecordCodecBuilder> forGetter(final Function> getter) { - return RecordCodecBuilder.of(getter, this); - } - @Override public boolean equals(final Object o) { if (this == o) { From ed12c92740f4c6c6dc031515cc7870e4f58aa711 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 17:07:11 +0100 Subject: [PATCH 32/96] Use applicative syntax for DataResult if possible. --- .../mojang/datafixers/kinds/Applicative.java | 2 +- .../com/mojang/serialization/DataResult.java | 46 ++++++++++--------- .../com/mojang/serialization/JsonOps.java | 7 ++- .../com/mojang/serialization/ListBuilder.java | 2 +- .../mojang/serialization/RecordBuilder.java | 4 +- .../serialization/codecs/ListCodec.java | 9 ++-- 6 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index 06f58d60..92eba1f2 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -52,7 +52,7 @@ default App ap(final App> func, final App a } default App ap(final Function func, final App arg) { - return ap(point(func), arg); + return map(func, arg); } default App ap2(final App> func, final App a, final App b) { diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 696c5222..44df6d17 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -104,6 +104,27 @@ public DataResult flatMap(final Function DataResult ap(final DataResult> functionResult) { + return create(result.map( + arg -> functionResult.result.mapBoth( + func -> func.apply(arg), + funcError -> new DynamicException<>(funcError.message, funcError.partialResult.map(f -> f.apply(arg))) + ), + argError -> Either.right(functionResult.result.map( + func -> new DynamicException<>(argError.message, argError.partialResult.map(func)), + funcError -> new DynamicException<>( + argError.message + "; " + funcError.message, + argError.partialResult.flatMap(a -> funcError.partialResult.map(f -> f.apply(a))) + ) + )) + )); + } + + public DataResult ap2(final DataResult second, final BiFunction function) { + final Function> curried = r -> r2 -> function.apply(r, r2); + return second.ap(map(curried)); + } + public DataResult setPartial(final Supplier partial) { return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial.get())))); } @@ -210,14 +231,9 @@ public Function, App> lift1(final return fa -> ap(function, fa); } - /** Argument error before the function */ @Override public App ap(final App> func, final App arg) { - return unbox(arg).flatMap(av -> - unbox(func).map(f -> - f.apply(av) - ) - ); + return unbox(arg).ap(unbox(func)); } @Override @@ -238,13 +254,7 @@ public App ap2(final App - unbox(b).flatMap(bv -> - unbox(func).map(f -> - f.apply(av, bv) - ) - ) - ); + return Applicative.super.ap2(func, a, b); } @Override @@ -268,15 +278,7 @@ public App ap3(final App - dr2.flatMap(r2 -> - dr3.flatMap(r3 -> - fr.map(f -> - f.apply(r1, r2, r3) - ) - ) - ) - ); + return Applicative.super.ap3(func, t1, t2, t3); } } } \ No newline at end of file diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index bf212430..e08e4ee3 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -77,6 +77,9 @@ public DataResult getNumberValue(final JsonElement input) { return DataResult.success(input.getAsBoolean() ? 1 : 0); } } + if (input.isJsonPrimitive() && input.getAsJsonPrimitive().isBoolean()) { + return DataResult.success(input.getAsJsonPrimitive().getAsBoolean() ? 1 : 0); + } return DataResult.error("Not a number: " + input); } @@ -284,10 +287,10 @@ public ListBuilder add(final JsonElement value) { @Override public ListBuilder add(final DataResult value) { - builder = builder.flatMap(b -> value.map(element -> { + builder = builder.ap2(value, (b, element) -> { b.add(element); return b; - })); + }); return this; } diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index 0531b8a7..7050ed03 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -60,7 +60,7 @@ public ListBuilder add(final T value) { @Override public ListBuilder add(final DataResult value) { - builder = builder.flatMap(b -> value.map(b::add)); + builder = builder.ap2(value, ImmutableList.Builder::add); return this; } diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index dd092473..67be0538 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -60,13 +60,13 @@ public RecordBuilder add(final T key, final T value) { @Override public RecordBuilder add(final T key, final DataResult value) { - builder = builder.flatMap(b -> value.map(v -> b.put(key, v))); + builder = builder.ap2(value, (b, v) -> b.put(key, v)); return this; } @Override public RecordBuilder add(final DataResult key, final DataResult value) { - builder = builder.flatMap(b -> key.flatMap(k -> value.map(v -> b.put(k, v)))); + builder = builder.ap(key.ap2(value, (k, v) -> b -> b.put(k, v))); return this; } diff --git a/src/main/java/com/mojang/serialization/codecs/ListCodec.java b/src/main/java/com/mojang/serialization/codecs/ListCodec.java index 2a516178..27a63704 100644 --- a/src/main/java/com/mojang/serialization/codecs/ListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/ListCodec.java @@ -26,12 +26,9 @@ public DataResult encode(final List input, final DynamicOps ops, fi DataResult> result = DataResult.success(list); for (final A a : input) { - result = result.flatMap(t -> { - final DataResult written = elementCodec.encode(a, ops, ops.empty()); - return written.map(e -> { - list.add(e); - return list; - }); + result = result.ap2(elementCodec.encode(a, ops, ops.empty()), (l, e) -> { + l.add(e); + return l; }); } From 69507eeea0332a962ac40c463dfb2b973845002d Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 17:28:55 +0100 Subject: [PATCH 33/96] Made Codec.BOOL use DynamicOps.getBooleanValue --- src/main/java/com/mojang/serialization/Codec.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 8622bbb3..201b0c19 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -180,8 +180,7 @@ public String toString() { @Override public DataResult read(final DynamicOps ops, final T input) { return ops - .getNumberValue(input) - .map(v -> v.intValue() != 0); + .getBooleanValue(input); } @Override From 0a847c0ee89bb10425039acecbd8cc1bdc1cec3b Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 17:48:41 +0100 Subject: [PATCH 34/96] Fixed null being used for Unit instance --- src/main/java/com/mojang/datafixers/DSL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/datafixers/DSL.java b/src/main/java/com/mojang/datafixers/DSL.java index a7ed01c1..53e8ce93 100644 --- a/src/main/java/com/mojang/datafixers/DSL.java +++ b/src/main/java/com/mojang/datafixers/DSL.java @@ -430,7 +430,7 @@ static OpticFinder namedChoice(final String name, final Type type) } static Unit unit() { - return null; + return Unit.INSTANCE; } final class Instances { From cbe67e488c21528808b016c5ecd0f9523b725262 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 19:43:10 +0100 Subject: [PATCH 35/96] Track used keys in map codecs --- .../com/mojang/serialization/Decoder.java | 6 ++ .../com/mojang/serialization/Encoder.java | 7 ++ .../com/mojang/serialization/JsonOps.java | 6 ++ .../com/mojang/serialization/MapCodec.java | 9 +++ .../com/mojang/serialization/MapDecoder.java | 8 +++ .../com/mojang/serialization/MapEncoder.java | 4 ++ .../serialization/codecs/FieldCodec.java | 6 ++ .../codecs/OptionalFieldCodec.java | 6 ++ .../codecs/RecordCodecBuilder.java | 68 ++++++++++++++++++- 9 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 00c63d67..e456e699 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -6,6 +6,7 @@ import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Stream; public interface Decoder { DataResult> decode(final DynamicOps ops, final T input); @@ -68,6 +69,11 @@ public DataResult decode(final DynamicOps ops, final MapLike input) return DataResult.success(instance.get()); } + @Override + public Stream keys(final DynamicOps ops) { + return Stream.empty(); + } + @Override public DataResult> decode(final DynamicOps ops, final T input) { return DataResult.success(Pair.of(instance.get(), input)); diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index 8796027e..2b5e73e9 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -2,6 +2,8 @@ // Licensed under the MIT license. package com.mojang.serialization; +import java.util.stream.Stream; + public interface Encoder { DataResult encode(final A input, final DynamicOps ops, final T prefix); @@ -30,6 +32,11 @@ public RecordBuilder encode(final A input, final DynamicOps ops, final return prefix; } + @Override + public Stream keys(final DynamicOps ops) { + return Stream.empty(); + } + @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { return DataResult.success(prefix); diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index e08e4ee3..cc12d81b 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -214,6 +214,12 @@ public JsonElement get(final JsonElement key) { return object.get(key.getAsString()); } + @Nullable + @Override + public JsonElement get(final String key) { + return object.get(key); + } + @Override public Stream> entries() { return object.entrySet().stream().map(e -> Pair.of(new JsonPrimitive(e.getKey()), e.getValue())); diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 4261f81b..57a8aa84 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -5,12 +5,16 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import java.util.function.Function; +import java.util.stream.Stream; public interface MapCodec extends MapDecoder, MapEncoder, Codec { default RecordCodecBuilder forGetter(final Function getter) { return RecordCodecBuilder.of(getter, this); } + @Override + Stream keys(final DynamicOps ops); + @Override default MapCodec withDefault(final A value) { final MapCodec self = this; @@ -25,6 +29,11 @@ public RecordBuilder encode(final A input, final DynamicOps ops, final return self.encode(input, ops, prefix); } + @Override + public Stream keys(final DynamicOps ops) { + return self.keys(ops); + } + @Override public String toString() { return "WithDefault[" + self + " " + value + "]"; diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index 4441980b..127ddb8a 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -5,10 +5,13 @@ import com.mojang.datafixers.util.Pair; import java.util.function.Function; +import java.util.stream.Stream; public interface MapDecoder extends Decoder { DataResult decode(DynamicOps ops, MapLike input); + Stream keys(final DynamicOps ops); + @Override default DataResult> decode(final DynamicOps ops, final T input) { return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> Pair.of(r, input))); @@ -22,6 +25,11 @@ default MapDecoder map(final Function function) { public DataResult decode(final DynamicOps ops, final MapLike input) { return self.decode(ops, input).map(function); } + + @Override + public Stream keys(final DynamicOps ops) { + return self.keys(ops); + } }; } } diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index a00c4cda..4a085802 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -2,9 +2,13 @@ // Licensed under the MIT license. package com.mojang.serialization; +import java.util.stream.Stream; + public interface MapEncoder extends Encoder { RecordBuilder encode(A input, DynamicOps ops, RecordBuilder prefix); + Stream keys(final DynamicOps ops); + @Override default DataResult encode(final A input, final DynamicOps ops, final T prefix) { return encode(input, ops, ops.mapBuilder()).build(prefix); diff --git a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java index 224f4651..caf28670 100644 --- a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java @@ -11,6 +11,7 @@ import com.mojang.serialization.RecordBuilder; import java.util.Objects; +import java.util.stream.Stream; public class FieldCodec implements MapCodec { public static boolean REMOVE_FIELD_WHEN_PARSING = false; @@ -56,6 +57,11 @@ public RecordBuilder encode(final A input, final DynamicOps ops, final return prefix.add(name, elementCodec.encodeStart(ops, input)); } + @Override + public Stream keys(final DynamicOps ops) { + return Stream.of(ops.createString(name)); + } + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java index 8210d32a..3011d616 100644 --- a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java @@ -12,6 +12,7 @@ import java.util.Objects; import java.util.Optional; +import java.util.stream.Stream; /** Optimization of `Codec.either(someCodec.field(name), Codec.EMPTY)` */ public class OptionalFieldCodec implements MapCodec> { @@ -62,6 +63,11 @@ public RecordBuilder encode(final Optional input, final DynamicOps return prefix; } + @Override + public Stream keys(final DynamicOps ops) { + return Stream.of(ops.createString(name)); + } + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index b46197cc..bdf2b1f2 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -20,6 +20,7 @@ import java.util.function.BiFunction; import java.util.function.Function; +import java.util.stream.Stream; public final class RecordCodecBuilder implements App, F> { public static final class Mu implements K1 { @@ -107,6 +108,11 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final fEnc.encode(a1 -> input, ops, prefix); return prefix; } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat(aEnc.keys(ops), fEnc.keys(ops)); + } }; }, @@ -119,6 +125,11 @@ public DataResult decode(final DynamicOps ops, final MapLike input) ) ); } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat(a.decoder.keys(ops), f.decoder.keys(ops)); + } } ); }; @@ -147,6 +158,11 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final fEncoder.encode((a1, b1) -> input, ops, prefix); return prefix; } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat(aEncoder.keys(ops), Stream.concat(bEncoder.keys(ops), fEncoder.keys(ops))); + } }; }, new MapDecoder() { @@ -157,6 +173,11 @@ public DataResult decode(final DynamicOps ops, final MapLike input) fb.decoder.decode(ops, input) ).apply(function.decoder.decode(ops, input))); } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat(fa.decoder.keys(ops), Stream.concat(fb.decoder.keys(ops), function.decoder.keys(ops))); + } } ); } @@ -192,6 +213,14 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final fEncoder.encode((t1, t2, t3) -> input, ops, prefix); return prefix; } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat( + Stream.concat(e1.keys(ops), e2.keys(ops)), + Stream.concat(e3.keys(ops), fEncoder.keys(ops)) + ); + } }; }, new MapDecoder() { @@ -203,6 +232,14 @@ public DataResult decode(final DynamicOps ops, final MapLike input) f3.decoder.decode(ops, input) ).apply(function.decoder.decode(ops, input))); } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat( + Stream.concat(f1.decoder.keys(ops), f2.decoder.keys(ops)), + Stream.concat(f3.decoder.keys(ops), function.decoder.keys(ops)) + ); + } } ); } @@ -243,6 +280,17 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final fEncoder.encode((t1, t2, t3, t4) -> input, ops, prefix); return prefix; } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat( + Stream.concat( + Stream.concat(e1.keys(ops), e2.keys(ops)), + Stream.concat(e3.keys(ops), e4.keys(ops)) + ), + fEncoder.keys(ops) + ); + } }; }, new MapDecoder() { @@ -255,6 +303,17 @@ public DataResult decode(final DynamicOps ops, final MapLike input) f4.decoder.decode(ops, input) ).apply(function.decoder.decode(ops, input))); } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat( + Stream.concat( + Stream.concat(f1.decoder.keys(ops), f2.decoder.keys(ops)), + Stream.concat(f3.decoder.keys(ops), f4.decoder.keys(ops)) + ), + function.decoder.keys(ops) + ); + } } ); } @@ -266,9 +325,16 @@ public App, R> map(final Function( getter.andThen(func), o -> new MapEncoder() { + private final MapEncoder encoder = unbox.encoder.apply(o); + @Override public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { - return unbox.encoder.apply(o).encode(getter.apply(o), ops, prefix); + return encoder.encode(getter.apply(o), ops, prefix); + } + + @Override + public Stream keys(final DynamicOps ops) { + return encoder.keys(ops); } }, unbox.decoder.map(func) From 8447c28dc0bb3ce5cdd92eddb9c2b12b0fd67a23 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 19:43:40 +0100 Subject: [PATCH 36/96] MapLike.get overload for String keys --- .../java/com/mojang/serialization/DynamicOps.java | 4 ++-- src/main/java/com/mojang/serialization/MapLike.java | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index e3cda829..98f891de 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -95,7 +95,7 @@ default DataResult mergeToList(final T list, final List values) { DataResult mergeToMap(T map, T key, T value); default DataResult mergeToMap(final T map, final Map values) { - return mergeToMap(map, MapLike.forMap(values)); + return mergeToMap(map, MapLike.forMap(values, this)); } default DataResult mergeToMap(final T map, final MapLike values) { @@ -124,7 +124,7 @@ default DataResult mergeToPrimitive(final T prefix, final T value) { default DataResult> getMap(final T input) { return getMapValues(input).flatMap(s -> { try { - return DataResult.success(MapLike.forMap(s.collect(Pair.toMap()))); + return DataResult.success(MapLike.forMap(s.collect(Pair.toMap()), this)); } catch (final IllegalStateException e) { return DataResult.error("Error while building map: " + e.getMessage()); } diff --git a/src/main/java/com/mojang/serialization/MapLike.java b/src/main/java/com/mojang/serialization/MapLike.java index 2af07962..6841cacf 100644 --- a/src/main/java/com/mojang/serialization/MapLike.java +++ b/src/main/java/com/mojang/serialization/MapLike.java @@ -12,9 +12,12 @@ public interface MapLike { @Nullable T get(final T key); + @Nullable + T get(final String key); + Stream> entries(); - static MapLike forMap(final Map map) { + static MapLike forMap(final Map map, final DynamicOps ops) { return new MapLike() { @Nullable @Override @@ -22,6 +25,12 @@ public T get(final T key) { return map.get(key); } + @Nullable + @Override + public T get(final String key) { + return get(ops.createString(key)); + } + @Override public Stream> entries() { return map.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue())); From a042d34445044e2c0a664faf8799ca0c144b022c Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 20:47:28 +0100 Subject: [PATCH 37/96] Compressed map codec --- .../com/mojang/serialization/Decoder.java | 2 +- .../com/mojang/serialization/DynamicOps.java | 4 + .../com/mojang/serialization/Encoder.java | 2 +- .../com/mojang/serialization/MapCodec.java | 9 +- .../mojang/serialization/MapCompressor.java | 50 +++++++++ .../com/mojang/serialization/MapDecoder.java | 49 ++++++++- .../com/mojang/serialization/MapEncoder.java | 101 +++++++++++++++++- .../serialization/codecs/FieldCodec.java | 8 +- .../codecs/OptionalFieldCodec.java | 14 ++- .../codecs/RecordCodecBuilder.java | 18 ++-- 10 files changed, 236 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/MapCompressor.java diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index e456e699..0668919a 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -63,7 +63,7 @@ static MapDecoder unit(final A instance) { } static MapDecoder unit(final Supplier instance) { - return new MapDecoder() { + return new MapDecoder.Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { return DataResult.success(instance.get()); diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index 98f891de..b978f474 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -188,6 +188,10 @@ default T createLongList(final LongStream input) { T remove(T input, String key); + default boolean compressMaps() { + return false; + } + default DataResult get(final T input, final String key) { return getGeneric(input, createString(key)); } diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index 2b5e73e9..a320b0bc 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -26,7 +26,7 @@ public String toString() { } static MapEncoder empty() { - return new MapEncoder() { + return new MapEncoder.Implementation() { @Override public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { return prefix; diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 57a8aa84..a3846167 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -7,16 +7,16 @@ import java.util.function.Function; import java.util.stream.Stream; -public interface MapCodec extends MapDecoder, MapEncoder, Codec { - default RecordCodecBuilder forGetter(final Function getter) { +public abstract class MapCodec extends MapDecoder.Implementation implements MapEncoder, Codec { + public final RecordCodecBuilder forGetter(final Function getter) { return RecordCodecBuilder.of(getter, this); } @Override - Stream keys(final DynamicOps ops); + public abstract Stream keys(final DynamicOps ops); @Override - default MapCodec withDefault(final A value) { + public MapCodec withDefault(final A value) { final MapCodec self = this; return new MapCodec() { @Override @@ -40,4 +40,5 @@ public String toString() { } }; } + } diff --git a/src/main/java/com/mojang/serialization/MapCompressor.java b/src/main/java/com/mojang/serialization/MapCompressor.java new file mode 100644 index 00000000..e08a83eb --- /dev/null +++ b/src/main/java/com/mojang/serialization/MapCompressor.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class MapCompressor { + private final Int2ObjectMap decompress = new Int2ObjectArrayMap<>(); + private final Object2IntMap compress = new Object2IntArrayMap<>(); + private final Object2IntMap compressString = new Object2IntArrayMap<>(); + private final int size; + + public MapCompressor(final DynamicOps ops, final Stream keyStream) { + final List keys = keyStream.map(k -> ops.getStringValue(k).result().get()).sorted(Comparator.naturalOrder()).collect(Collectors.toList()); + + for (int i = 0; i < keys.size(); i++) { + final String string = keys.get(i); + final T key = ops.createString(string); + compress.put(key, i); + compressString.put(string, i); + decompress.put(i, key); + } + + size = keys.size(); + } + + public T decompress(final int key) { + return decompress.get(key); + } + + public int compress(final String key) { + return compressString.getInt(key); + } + + public int compress(final T key) { + return compress.get(key); + } + + public int size() { + return size; + } +} diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index 127ddb8a..f2726cd4 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -3,24 +3,59 @@ package com.mojang.serialization; import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; public interface MapDecoder extends Decoder { DataResult decode(DynamicOps ops, MapLike input); + default DataResult compressedDecode(final DynamicOps ops, final T input) { + if (ops.compressMaps()) { + return decode(ops, new MapLike() { + private final MapCompressor compressor = compressor(ops); + private final List entries = ops.getStream(input).result().get().collect(Collectors.toList()); + + @Nullable + @Override + public T get(final T key) { + return entries.get(compressor.compress(key)); + } + + @Nullable + @Override + public T get(final String key) { + return entries.get(compressor.compress(key)); + } + + @Override + public Stream> entries() { + return IntStream.range(0, entries.size()).mapToObj(i -> Pair.of(compressor.decompress(i), entries.get(i))); + } + }); + } + return ops.getMap(input).flatMap(map -> decode(ops, map)); + } + + MapCompressor compressor(DynamicOps ops); + Stream keys(final DynamicOps ops); @Override default DataResult> decode(final DynamicOps ops, final T input) { - return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> Pair.of(r, input))); + return compressedDecode(ops, input).map(r -> Pair.of(r, input)); } @Override default MapDecoder map(final Function function) { final MapDecoder self = this; - return new MapDecoder() { + return new Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { return self.decode(ops, input).map(function); @@ -32,4 +67,14 @@ public Stream keys(final DynamicOps ops) { } }; } + + abstract class Implementation implements MapDecoder { + private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); + + @SuppressWarnings("unchecked") + @Override + public MapCompressor compressor(final DynamicOps ops) { + return (MapCompressor) compressors.computeIfAbsent(ops, k -> new MapCompressor<>(ops, keys(ops))); + } + } } diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index 4a085802..3bf0e1c2 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -2,15 +2,114 @@ // Licensed under the MIT license. package com.mojang.serialization; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; public interface MapEncoder extends Encoder { RecordBuilder encode(A input, DynamicOps ops, RecordBuilder prefix); + default RecordBuilder compressedBuilder(final DynamicOps ops) { + if (ops.compressMaps()) { + return new MapCodec.CompressedRecordBuilder<>(compressor(ops), ops); + } + return ops.mapBuilder(); + } + Stream keys(final DynamicOps ops); + MapCompressor compressor(final DynamicOps ops); + @Override default DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return encode(input, ops, ops.mapBuilder()).build(prefix); + return encode(input, ops, compressedBuilder(ops)).build(prefix); + } + + abstract class Implementation implements MapEncoder { + private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); + + @SuppressWarnings("unchecked") + @Override + public MapCompressor compressor(final DynamicOps ops) { + return (MapCompressor) compressors.computeIfAbsent(ops, k -> new MapCompressor<>(ops, keys(ops))); + } + } + + class CompressedRecordBuilder implements RecordBuilder { + private final MapCompressor compressor; + private final DynamicOps ops; + private DataResult> builder; + + public CompressedRecordBuilder(final MapCompressor compressor, final DynamicOps ops) { + this.compressor = compressor; + this.ops = ops; + resetBuilder(compressor); + } + + @Override + public DynamicOps ops() { + return ops; + } + + @Override + public RecordBuilder add(final String key, final T value) { + builder = builder.map(b -> { + b.set(compressor.compress(key), value); + return b; + }); + return this; + } + + @Override + public RecordBuilder add(final String key, final DataResult value) { + builder = builder.ap2(value, (b, v) -> { + b.set(compressor.compress(key), v); + return b; + }); + return this; + } + + @Override + public RecordBuilder add(final T key, final T value) { + builder = builder.map(b -> { + b.set(compressor.compress(key), value); + return b; + }); + return this; + } + + @Override + public RecordBuilder add(final T key, final DataResult value) { + builder = builder.ap2(value, (b, v) -> { + b.set(compressor.compress(key), v); + return b; + }); + return this; + } + + @Override + public RecordBuilder add(final DataResult key, final DataResult value) { + builder = builder.ap(key.ap2(value, (k, v) -> b -> { + b.set(compressor.compress(k), v); + return b; + })); + return this; + } + + @Override + public DataResult build(final T prefix) { + final DataResult result = builder.flatMap(l -> ops.mergeToList(prefix, l)); + resetBuilder(compressor); + return result; + } + + private void resetBuilder(final MapCompressor compressor) { + builder = DataResult.success(IntStream.range(0, compressor.size()).mapToObj(i -> null).collect(Collectors.toList())); + } } } diff --git a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java index caf28670..3c58aba0 100644 --- a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java @@ -13,7 +13,7 @@ import java.util.Objects; import java.util.stream.Stream; -public class FieldCodec implements MapCodec { +public class FieldCodec extends MapCodec { public static boolean REMOVE_FIELD_WHEN_PARSING = false; private final String name; @@ -26,6 +26,9 @@ public FieldCodec(final String name, final Codec elementCodec) { @Override public DataResult> decode(final DynamicOps ops, final T input) { + if (ops.compressMaps()) { + return super.decode(ops, input); + } return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> { final T output; if (REMOVE_FIELD_WHEN_PARSING) { @@ -40,6 +43,9 @@ public DataResult> decode(final DynamicOps ops, final T input) @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + if (ops.compressMaps()) { + return super.encode(input, ops, prefix); + } return elementCodec.encodeStart(ops, input).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); } diff --git a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java index 3011d616..1bb8167d 100644 --- a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java @@ -15,7 +15,7 @@ import java.util.stream.Stream; /** Optimization of `Codec.either(someCodec.field(name), Codec.EMPTY)` */ -public class OptionalFieldCodec implements MapCodec> { +public class OptionalFieldCodec extends MapCodec> { private final String name; private final Codec elementCodec; @@ -26,6 +26,9 @@ public OptionalFieldCodec(final String name, final Codec elementCodec) { @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { + if (ops.compressMaps()) { + return super.decode(ops, input); + } return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> { final T output; if (FieldCodec.REMOVE_FIELD_WHEN_PARSING) { @@ -40,6 +43,9 @@ public DataResult, T>> decode(final DynamicOps ops, fina @Override public DataResult encode(final Optional input, final DynamicOps ops, final T prefix) { + if (ops.compressMaps()) { + return super.encode(input, ops, prefix); + } if (input.isPresent()) { return elementCodec.encodeStart(ops, input.get()).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); } @@ -52,7 +58,11 @@ public DataResult> decode(final DynamicOps ops, final MapLike if (value == null) { return DataResult.success(Optional.empty()); } - return elementCodec.parse(ops, value).map(Optional::of); + final DataResult parsed = elementCodec.parse(ops, value); + if (parsed.result().isPresent()) { + return parsed.map(Optional::of); + } + return DataResult.success(Optional.empty()); } @Override diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index bdf2b1f2..2184b16d 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -101,7 +101,7 @@ public Function, A>, App aEnc = a.encoder.apply(o); final A aFromO = a.getter.apply(o); - return new MapEncoder() { + return new MapEncoder.Implementation() { @Override public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { aEnc.encode(aFromO, ops, prefix); @@ -116,7 +116,7 @@ public Stream keys(final DynamicOps ops) { }; }, - new MapDecoder() { + new MapDecoder.Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { return a.decoder.decode(ops, input).flatMap(ar -> @@ -150,7 +150,7 @@ public App, R> ap2(final App bEncoder = fb.encoder.apply(o); final B bFromO = fb.getter.apply(o); - return new MapEncoder() { + return new MapEncoder.Implementation() { @Override public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { aEncoder.encode(aFromO, ops, prefix); @@ -165,7 +165,7 @@ public Stream keys(final DynamicOps ops) { } }; }, - new MapDecoder() { + new MapDecoder.Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { return DataResult.unbox(DataResult.instance().group( @@ -204,7 +204,7 @@ public App, R> ap3(final App e3 = f3.encoder.apply(o); final T3 v3 = f3.getter.apply(o); - return new MapEncoder() { + return new MapEncoder.Implementation() { @Override public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { e1.encode(v1, ops, prefix); @@ -223,7 +223,7 @@ public Stream keys(final DynamicOps ops) { } }; }, - new MapDecoder() { + new MapDecoder.Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { return DataResult.unbox(DataResult.instance().group( @@ -270,7 +270,7 @@ public App, R> ap4(final App e4 = f4.encoder.apply(o); final T4 v4 = f4.getter.apply(o); - return new MapEncoder() { + return new MapEncoder.Implementation() { @Override public RecordBuilder encode(final R input, final DynamicOps ops, final RecordBuilder prefix) { e1.encode(v1, ops, prefix); @@ -293,7 +293,7 @@ public Stream keys(final DynamicOps ops) { } }; }, - new MapDecoder() { + new MapDecoder.Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { return DataResult.unbox(DataResult.instance().group( @@ -324,7 +324,7 @@ public App, R> map(final Function getter = unbox.getter; return new RecordCodecBuilder<>( getter.andThen(func), - o -> new MapEncoder() { + o -> new MapEncoder.Implementation() { private final MapEncoder encoder = unbox.encoder.apply(o); @Override From 70989754ecf13309c438b4c456c20a8a6fc844ce Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 21:33:04 +0100 Subject: [PATCH 38/96] Call MapLike.get(String) if possible --- .../com/mojang/datafixers/types/templates/TaggedChoice.java | 2 +- src/main/java/com/mojang/serialization/Dynamic.java | 2 +- src/main/java/com/mojang/serialization/codecs/FieldCodec.java | 2 +- .../com/mojang/serialization/codecs/OptionalFieldCodec.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index dadd50e0..770f4b97 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -186,7 +186,7 @@ public TypeTemplate buildTemplate() { @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { return ops.getMap(input).flatMap(map -> { - final T value = map.get(ops.createString(name)); + final T value = map.get(name); if (value == null) { return DataResult.error("Input does not contain a key [" + name + "] with the name: " + input); } diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index c9519be7..7b036fd7 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -112,7 +112,7 @@ public DataResult asLongStreamOpt() { @Override public OptionalDynamic get(final String key) { return new OptionalDynamic<>(ops, ops.getMap(value).flatMap(m -> { - final T value = m.get(ops.createString(key)); + final T value = m.get(key); if (value == null) { return DataResult.error("key missing: " + key + " in " + this.value); } diff --git a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java index 3c58aba0..39be6117 100644 --- a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/FieldCodec.java @@ -51,7 +51,7 @@ public DataResult encode(final A input, final DynamicOps ops, final T @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - final T value = input.get(ops.createString(name)); + final T value = input.get(name); if (value == null) { return DataResult.error("No key " + name + " in " + input); } diff --git a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java index 1bb8167d..b75aae67 100644 --- a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java @@ -54,7 +54,7 @@ public DataResult encode(final Optional input, final DynamicOps ops @Override public DataResult> decode(final DynamicOps ops, final MapLike input) { - final T value = input.get(ops.createString(name)); + final T value = input.get(name); if (value == null) { return DataResult.success(Optional.empty()); } From 5ef666cf9b34b0fc33fa724c9ef7242a017b7672 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sun, 15 Mar 2020 22:48:10 +0100 Subject: [PATCH 39/96] Compressable JsonOps instance --- .../com/mojang/serialization/JsonOps.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index cc12d81b..c5e84290 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -18,9 +18,13 @@ import java.util.stream.StreamSupport; public class JsonOps implements DynamicOps { - public static final JsonOps INSTANCE = new JsonOps(); + public static final JsonOps INSTANCE = new JsonOps(false); + public static final JsonOps COMPRESSED = new JsonOps(true); - protected JsonOps() { + private final boolean compressed; + + protected JsonOps(final boolean compressed) { + this.compressed = compressed; } @Override @@ -76,6 +80,13 @@ public DataResult getNumberValue(final JsonElement input) { } else if (input.getAsJsonPrimitive().isBoolean()) { return DataResult.success(input.getAsBoolean() ? 1 : 0); } + if (compressed && input.getAsJsonPrimitive().isString()) { + try { + return DataResult.success(Integer.parseInt(input.getAsString())); + } catch (final NumberFormatException e) { + return DataResult.error("Not a number: " + e + " " + input); + } + } } if (input.isJsonPrimitive() && input.getAsJsonPrimitive().isBoolean()) { return DataResult.success(input.getAsJsonPrimitive().getAsBoolean() ? 1 : 0); @@ -151,7 +162,7 @@ public DataResult mergeToMap(final JsonElement map, final JsonEleme if (!map.isJsonObject() && map != empty()) { return DataResult.error("mergeToMap called with not a map: " + map, map); } - if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString()) { + if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString() && !compressed) { return DataResult.error("key is not a string: " + key, map); } @@ -179,7 +190,7 @@ public DataResult mergeToMap(final JsonElement map, final MapLike { final JsonElement key = entry.getFirst(); - if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString()) { + if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString() && !compressed) { missed.add(key); return; } @@ -319,4 +330,9 @@ public DataResult build(final JsonElement prefix) { return result; } } + + @Override + public boolean compressMaps() { + return compressed; + } } From c03ca067586a778e520208820d7931031120a26b Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 16 Mar 2020 16:48:41 +0100 Subject: [PATCH 40/96] Split FieldDecoder and FieldEncoder from FieldCodec, added a helper for dependent record codecs. --- .../java/com/mojang/serialization/Codec.java | 38 +++------ .../com/mojang/serialization/Decoder.java | 21 +++++ .../com/mojang/serialization/Encoder.java | 17 ++++ .../com/mojang/serialization/MapCodec.java | 69 +++++++++++++++- .../mojang/serialization/MapCompressor.java | 2 +- .../com/mojang/serialization/MapDecoder.java | 39 +++++++++ .../com/mojang/serialization/MapEncoder.java | 18 +++- .../{FieldCodec.java => FieldDecoder.java} | 30 ++----- .../serialization/codecs/FieldEncoder.java | 62 ++++++++++++++ .../codecs/OptionalFieldCodec.java | 2 +- .../codecs/RecordCodecBuilder.java | 82 +++++++++++++++++-- 11 files changed, 321 insertions(+), 59 deletions(-) rename src/main/java/com/mojang/serialization/codecs/{FieldCodec.java => FieldDecoder.java} (67%) create mode 100644 src/main/java/com/mojang/serialization/codecs/FieldEncoder.java diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 201b0c19..b553fce0 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -2,13 +2,11 @@ // Licensed under the MIT license. package com.mojang.serialization; -import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Unit; import com.mojang.serialization.codecs.CompoundListCodec; import com.mojang.serialization.codecs.EitherCodec; -import com.mojang.serialization.codecs.FieldCodec; import com.mojang.serialization.codecs.ListCodec; import com.mojang.serialization.codecs.OptionalFieldCodec; import com.mojang.serialization.codecs.PairCodec; @@ -59,10 +57,6 @@ static Codec>> compoundList(final Codec keyCodec, fina return new CompoundListCodec<>(keyCodec, elementCodec); } - static FieldCodec field(final String name, final Codec elementCodec) { - return new FieldCodec<>(name, elementCodec); - } - static MapCodec> optionalField(final String name, final Codec elementCodec) { return new OptionalFieldCodec<>(name, elementCodec); } @@ -71,33 +65,25 @@ default Codec> listOf() { return list(this); } - default FieldCodec fieldOf(final String name) { - return field(name, this); + default Codec xmap(final Function to, final Function from) { + return Codec.of(comap(from), map(to)); + } + + @Override + default MapCodec fieldOf(final String name) { + return MapCodec.of( + Encoder.super.fieldOf(name), + Decoder.super.fieldOf(name) + ); } default MapCodec> optionalFieldOf(final String name) { return optionalField(name, this); } + @Override default Codec withDefault(final A value) { - final Codec self = this; - - return new Codec() { - @Override - public DataResult> decode(final DynamicOps ops, final T input) { - return DataResult.success(self.decode(ops, input).result().orElseGet(() -> Pair.of(value, input))); - } - - @Override - public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return self.encode(input, ops, prefix); - } - - @Override - public String toString() { - return "WithDefault[" + self + " " + value + "]"; - } - }; + return Codec.of(this, Decoder.super.withDefault(value)); } PrimitiveCodec FLOAT = new PrimitiveCodec() { diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 0668919a..5abfcff0 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -3,6 +3,7 @@ package com.mojang.serialization; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.codecs.FieldDecoder; import java.util.function.Function; import java.util.function.Supplier; @@ -36,6 +37,26 @@ default Simple simple() { return this::parse; } + default MapDecoder fieldOf(final String name) { + return new FieldDecoder<>(name, this); + } + + default Decoder withDefault(final A value) { + final Decoder self = this; + + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return DataResult.success(self.decode(ops, input).result().orElseGet(() -> Pair.of(value, input))); + } + + @Override + public String toString() { + return "WithDefault[" + self + " " + value + "]"; + } + }; + } + default Decoder map(final Function function) { final Decoder self = this; return new Decoder() { diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index a320b0bc..cfb77bd7 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -2,6 +2,9 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.mojang.serialization.codecs.FieldEncoder; + +import java.util.function.Function; import java.util.stream.Stream; public interface Encoder { @@ -11,6 +14,20 @@ default DataResult encodeStart(final DynamicOps ops, final A input) { return encode(input, ops, ops.empty()); } + default MapEncoder fieldOf(final String name) { + return new FieldEncoder<>(name, this); + } + + default Encoder comap(final Function function) { + final Encoder self = this; + return new Encoder() { + @Override + public DataResult encode(final B input, final DynamicOps ops, final T prefix) { + return self.encode(function.apply(input), ops, prefix); + } + }; + } + static Encoder of() { return new Encoder() { @Override diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index a3846167..065468c2 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -2,8 +2,10 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.mojang.datafixers.util.Pair; import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Stream; @@ -12,6 +14,72 @@ public final RecordCodecBuilder forGetter(final Function getter) return RecordCodecBuilder.of(getter, this); } + public static MapCodec of(final MapEncoder encoder, final MapDecoder decoder) { + return new MapCodec() { + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat(encoder.keys(ops), decoder.keys(ops)); + } + + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return decoder.decode(ops, input); + } + + @Override + public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { + return encoder.encode(input, ops, prefix); + } + + @Override + public String toString() { + return "MapCodec[" + encoder + " " + decoder + "]"; + } + }; + } + + public MapCodec xmap(final Function to, final Function from) { + return MapCodec.of(comap(from), map(to)); + } + + public MapCodec dependent(final MapCodec initialInstance, final Function>> splitter, final BiFunction combiner) { + return new Dependent(this, initialInstance, splitter, combiner); + } + + private static class Dependent extends MapCodec { + private final MapCodec initialInstance; + private final Function>> splitter; + private final MapCodec codec; + private final BiFunction combiner; + + public Dependent(final MapCodec codec, final MapCodec initialInstance, final Function>> splitter, final BiFunction combiner) { + this.initialInstance = initialInstance; + this.splitter = splitter; + this.codec = codec; + this.combiner = combiner; + } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat(codec.keys(ops), initialInstance.keys(ops)); + } + + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return codec.decode(ops, input).flatMap((O base) -> + splitter.apply(base).getSecond().decode(ops, input).map(e -> combiner.apply(base, e)) + ); + } + + @Override + public RecordBuilder encode(final O input, final DynamicOps ops, final RecordBuilder prefix) { + codec.encode(input, ops, prefix); + final Pair> e = splitter.apply(input); + e.getSecond().encode(e.getFirst(), ops, prefix); + return prefix; + } + } + @Override public abstract Stream keys(final DynamicOps ops); @@ -40,5 +108,4 @@ public String toString() { } }; } - } diff --git a/src/main/java/com/mojang/serialization/MapCompressor.java b/src/main/java/com/mojang/serialization/MapCompressor.java index e08a83eb..44c3a4fe 100644 --- a/src/main/java/com/mojang/serialization/MapCompressor.java +++ b/src/main/java/com/mojang/serialization/MapCompressor.java @@ -19,7 +19,7 @@ public final class MapCompressor { private final int size; public MapCompressor(final DynamicOps ops, final Stream keyStream) { - final List keys = keyStream.map(k -> ops.getStringValue(k).result().get()).sorted(Comparator.naturalOrder()).collect(Collectors.toList()); + final List keys = keyStream.map(k -> ops.getStringValue(k).result().get()).distinct().sorted(Comparator.naturalOrder()).collect(Collectors.toList()); for (int i = 0; i < keys.size(); i++) { final String string = keys.get(i); diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index f2726cd4..9811fe37 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -68,6 +68,45 @@ public Stream keys(final DynamicOps ops) { }; } + default MapDecoder ap(final MapDecoder> decoder) { + final MapDecoder self = this; + return new Implementation() { + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return self.decode(ops, input).flatMap(f -> + decoder.decode(ops, input).map(e -> e.apply(f)) + ); + } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat(self.keys(ops), decoder.keys(ops)); + } + }; + } + + @Override + default MapDecoder withDefault(final A value) { + final MapDecoder self = this; + + return new Implementation() { + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return DataResult.success(self.decode(ops, input).result().orElse(value)); + } + + @Override + public Stream keys(final DynamicOps ops) { + return self.keys(ops); + } + + @Override + public String toString() { + return "WithDefault[" + self + " " + value + "]"; + } + }; + } + abstract class Implementation implements MapDecoder { private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index 3bf0e1c2..751081b5 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -4,9 +4,9 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -25,6 +25,22 @@ default RecordBuilder compressedBuilder(final DynamicOps ops) { MapCompressor compressor(final DynamicOps ops); + @Override + default MapEncoder comap(final Function function) { + final MapEncoder self = this; + return new MapEncoder.Implementation() { + @Override + public RecordBuilder encode(final B input, final DynamicOps ops, final RecordBuilder prefix) { + return self.encode(function.apply(input), ops, prefix); + } + + @Override + public Stream keys(final DynamicOps ops) { + return self.keys(ops); + } + }; + } + @Override default DataResult encode(final A input, final DynamicOps ops, final T prefix) { return encode(input, ops, compressedBuilder(ops)).build(prefix); diff --git a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java b/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java similarity index 67% rename from src/main/java/com/mojang/serialization/codecs/FieldCodec.java rename to src/main/java/com/mojang/serialization/codecs/FieldDecoder.java index 39be6117..0e7e6327 100644 --- a/src/main/java/com/mojang/serialization/codecs/FieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java @@ -3,23 +3,22 @@ package com.mojang.serialization.codecs; import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Decoder; import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.MapCodec; +import com.mojang.serialization.MapDecoder; import com.mojang.serialization.MapLike; -import com.mojang.serialization.RecordBuilder; import java.util.Objects; import java.util.stream.Stream; -public class FieldCodec extends MapCodec { +public class FieldDecoder extends MapDecoder.Implementation { public static boolean REMOVE_FIELD_WHEN_PARSING = false; - private final String name; - private final Codec elementCodec; + protected final String name; + private final Decoder elementCodec; - public FieldCodec(final String name, final Codec elementCodec) { + public FieldDecoder(final String name, final Decoder elementCodec) { this.name = name; this.elementCodec = elementCodec; } @@ -41,14 +40,6 @@ public DataResult> decode(final DynamicOps ops, final T input) })); } - @Override - public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - if (ops.compressMaps()) { - return super.encode(input, ops, prefix); - } - return elementCodec.encodeStart(ops, input).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); - } - @Override public DataResult decode(final DynamicOps ops, final MapLike input) { final T value = input.get(name); @@ -58,11 +49,6 @@ public DataResult decode(final DynamicOps ops, final MapLike input) return elementCodec.parse(ops, value); } - @Override - public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { - return prefix.add(name, elementCodec.encodeStart(ops, input)); - } - @Override public Stream keys(final DynamicOps ops) { return Stream.of(ops.createString(name)); @@ -76,7 +62,7 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - final FieldCodec that = (FieldCodec) o; + final FieldDecoder that = (FieldDecoder) o; return Objects.equals(name, that.name) && Objects.equals(elementCodec, that.elementCodec); } @@ -87,6 +73,6 @@ public int hashCode() { @Override public String toString() { - return "FieldCodec[" + name + ": " + elementCodec + ']'; + return "FieldDecoder[" + name + ": " + elementCodec + ']'; } } diff --git a/src/main/java/com/mojang/serialization/codecs/FieldEncoder.java b/src/main/java/com/mojang/serialization/codecs/FieldEncoder.java new file mode 100644 index 00000000..e59c5fa1 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/FieldEncoder.java @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Encoder; +import com.mojang.serialization.MapEncoder; +import com.mojang.serialization.RecordBuilder; + +import java.util.Objects; +import java.util.stream.Stream; + +public class FieldEncoder extends MapEncoder.Implementation { + private final String name; + private final Encoder elementCodec; + + public FieldEncoder(final String name, final Encoder elementCodec) { + this.name = name; + this.elementCodec = elementCodec; + } + + @Override + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + if (ops.compressMaps()) { + return super.encode(input, ops, prefix); + } + return elementCodec.encodeStart(ops, input).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); + } + + @Override + public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { + return prefix.add(name, elementCodec.encodeStart(ops, input)); + } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.of(ops.createString(name)); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final FieldEncoder that = (FieldEncoder) o; + return Objects.equals(name, that.name) && Objects.equals(elementCodec, that.elementCodec); + } + + @Override + public int hashCode() { + return Objects.hash(name, elementCodec); + } + + @Override + public String toString() { + return "FieldEncoder[" + name + ": " + elementCodec + ']'; + } +} diff --git a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java index b75aae67..1050eede 100644 --- a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java @@ -31,7 +31,7 @@ public DataResult, T>> decode(final DynamicOps ops, fina } return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> { final T output; - if (FieldCodec.REMOVE_FIELD_WHEN_PARSING) { + if (FieldDecoder.REMOVE_FIELD_WHEN_PARSING) { final T nameObject = ops.createString(name); output = ops.createMap(map.entries().filter(e -> !Objects.equals(e.getFirst(), nameObject))); } else { diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index 2184b16d..1c4e50a2 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -7,12 +7,12 @@ import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.util.Function3; import com.mojang.datafixers.util.Function4; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Decoder; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Encoder; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapDecoder; import com.mojang.serialization.MapEncoder; import com.mojang.serialization.MapLike; @@ -48,7 +48,7 @@ public static RecordCodecBuilder of(final Function getter, fi return of(getter, fieldCodec.fieldOf(name)); } - public static & MapEncoder> RecordCodecBuilder of(final Function getter, final C codec) { + public static RecordCodecBuilder of(final Function getter, final MapCodec codec) { return new RecordCodecBuilder<>(getter, o -> codec, codec); } @@ -56,22 +56,45 @@ public static RecordCodecBuilder point(final F instance) { return new RecordCodecBuilder<>(o -> instance, o -> Encoder.empty(), Decoder.unit(instance)); } - public static Codec build(final App, O> builder) { + public static MapCodec build(final App, O> builder) { return build(unbox(builder)); } - public static Codec build(final RecordCodecBuilder builder) { - return new Codec() { + public RecordCodecBuilder dependent(final Function getter, final MapEncoder encoder, final Function> decoderGetter) { + return new RecordCodecBuilder<>( + getter, + o -> encoder, + new MapDecoder.Implementation() { + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return decoder.decode(ops, input).map(decoderGetter).flatMap(decoder1 -> decoder1.decode(ops, input).map(Function.identity())); + } + + @Override + public Stream keys(final DynamicOps ops) { + return encoder.keys(ops); + } + } + ); + } + + public static MapCodec build(final RecordCodecBuilder builder) { + return new MapCodec() { @Override - public DataResult> decode(final DynamicOps ops, final T input) { + public DataResult decode(final DynamicOps ops, final MapLike input) { return builder.decoder.decode(ops, input); } @Override - public DataResult encode(final O input, final DynamicOps ops, final T prefix) { + public RecordBuilder encode(final O input, final DynamicOps ops, final RecordBuilder prefix) { return builder.encoder.apply(input).encode(input, ops, prefix); } + @Override + public Stream keys(final DynamicOps ops) { + return builder.decoder.keys(ops); + } + @Override public String toString() { return "RecordCodec[" + builder.decoder + "]"; @@ -113,6 +136,11 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final public Stream keys(final DynamicOps ops) { return Stream.concat(aEnc.keys(ops), fEnc.keys(ops)); } + + @Override + public String toString() { + return fEnc + " * " + aEnc; + } }; }, @@ -130,6 +158,11 @@ public DataResult decode(final DynamicOps ops, final MapLike input) public Stream keys(final DynamicOps ops) { return Stream.concat(a.decoder.keys(ops), f.decoder.keys(ops)); } + + @Override + public String toString() { + return f.decoder + " * " + a.decoder; + } } ); }; @@ -163,6 +196,11 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final public Stream keys(final DynamicOps ops) { return Stream.concat(aEncoder.keys(ops), Stream.concat(bEncoder.keys(ops), fEncoder.keys(ops))); } + + @Override + public String toString() { + return fEncoder + " * " + aEncoder + " * " + bEncoder; + } }; }, new MapDecoder.Implementation() { @@ -178,6 +216,11 @@ public DataResult decode(final DynamicOps ops, final MapLike input) public Stream keys(final DynamicOps ops) { return Stream.concat(fa.decoder.keys(ops), Stream.concat(fb.decoder.keys(ops), function.decoder.keys(ops))); } + + @Override + public String toString() { + return function.decoder + " * " + fa.decoder + " * " + fb.decoder; + } } ); } @@ -221,6 +264,11 @@ public Stream keys(final DynamicOps ops) { Stream.concat(e3.keys(ops), fEncoder.keys(ops)) ); } + + @Override + public String toString() { + return fEncoder + " * " + e1 + " * " + e2 + " * " + e3; + } }; }, new MapDecoder.Implementation() { @@ -240,6 +288,11 @@ public Stream keys(final DynamicOps ops) { Stream.concat(f3.decoder.keys(ops), function.decoder.keys(ops)) ); } + + @Override + public String toString() { + return function.decoder + " * " + f1.decoder + " * " + f2.decoder + " * " + f3.decoder; + } } ); } @@ -291,6 +344,11 @@ public Stream keys(final DynamicOps ops) { fEncoder.keys(ops) ); } + + @Override + public String toString() { + return fEncoder + " * " + e1 + " * " + e2 + " * " + e3 + " * " + e4; + } }; }, new MapDecoder.Implementation() { @@ -314,6 +372,11 @@ public Stream keys(final DynamicOps ops) { function.decoder.keys(ops) ); } + + @Override + public String toString() { + return function.decoder + " * " + f1.decoder + " * " + f2.decoder + " * " + f3.decoder + " * " + f4.decoder; + } } ); } @@ -336,6 +399,11 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final public Stream keys(final DynamicOps ops) { return encoder.keys(ops); } + + @Override + public String toString() { + return encoder + "[mapped]"; + } }, unbox.decoder.map(func) ); From 4d863319ced34ca76683fe39a994e421f5b77ea9 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 17 Mar 2020 10:28:59 +0100 Subject: [PATCH 41/96] A bunch of toStrings --- src/main/java/com/mojang/serialization/Codec.java | 11 ++++++++--- src/main/java/com/mojang/serialization/Decoder.java | 5 +++++ src/main/java/com/mojang/serialization/Encoder.java | 5 +++++ src/main/java/com/mojang/serialization/MapCodec.java | 8 ++++++-- .../java/com/mojang/serialization/MapDecoder.java | 10 ++++++++++ .../java/com/mojang/serialization/MapEncoder.java | 5 +++++ .../serialization/codecs/RecordCodecBuilder.java | 5 +++++ 7 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index b553fce0..01cac19d 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -23,6 +23,10 @@ static Codec of(final Decoder decoder) { } static Codec of(final Encoder encoder, final Decoder decoder) { + return of(encoder, decoder, "Codec[" + encoder + " " + decoder + "]"); + } + + static Codec of(final Encoder encoder, final Decoder decoder, final String name) { return new Codec() { @Override public DataResult> decode(final DynamicOps ops, final T input) { @@ -36,7 +40,7 @@ public DataResult encode(final A input, final DynamicOps ops, final T @Override public String toString() { - return "Codec[" + encoder + " " + decoder + "]"; + return name; } }; } @@ -66,14 +70,15 @@ default Codec> listOf() { } default Codec xmap(final Function to, final Function from) { - return Codec.of(comap(from), map(to)); + return Codec.of(comap(from), map(to), toString() + "[xmapped]"); } @Override default MapCodec fieldOf(final String name) { return MapCodec.of( Encoder.super.fieldOf(name), - Decoder.super.fieldOf(name) + Decoder.super.fieldOf(name), + "Field[" + name + ": " + toString() + "]" ); } diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 5abfcff0..0f42db35 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -64,6 +64,11 @@ default Decoder map(final Function function) { public DataResult> decode(final DynamicOps ops, final T input) { return self.decode(ops, input).map(p -> p.mapFirst(function)); } + + @Override + public String toString() { + return self.toString() + "[mapped]"; + } }; } diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index cfb77bd7..ae48e04f 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -25,6 +25,11 @@ default Encoder comap(final Function function) { public DataResult encode(final B input, final DynamicOps ops, final T prefix) { return self.encode(function.apply(input), ops, prefix); } + + @Override + public String toString() { + return self.toString() + "[comapped]"; + } }; } diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 065468c2..22613343 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -15,6 +15,10 @@ public final RecordCodecBuilder forGetter(final Function getter) } public static MapCodec of(final MapEncoder encoder, final MapDecoder decoder) { + return of(encoder, decoder, "MapCodec[" + encoder + " " + decoder + "]"); + } + + public static MapCodec of(final MapEncoder encoder, final MapDecoder decoder, final String name) { return new MapCodec() { @Override public Stream keys(final DynamicOps ops) { @@ -33,13 +37,13 @@ public RecordBuilder encode(final A input, final DynamicOps ops, final @Override public String toString() { - return "MapCodec[" + encoder + " " + decoder + "]"; + return name; } }; } public MapCodec xmap(final Function to, final Function from) { - return MapCodec.of(comap(from), map(to)); + return MapCodec.of(comap(from), map(to), toString() + "[comapped]"); } public MapCodec dependent(final MapCodec initialInstance, final Function>> splitter, final BiFunction combiner) { diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index 9811fe37..fef6a11f 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -65,6 +65,11 @@ public DataResult decode(final DynamicOps ops, final MapLike input) public Stream keys(final DynamicOps ops) { return self.keys(ops); } + + @Override + public String toString() { + return self.toString() + "[mapped]"; + } }; } @@ -82,6 +87,11 @@ public DataResult decode(final DynamicOps ops, final MapLike input) public Stream keys(final DynamicOps ops) { return Stream.concat(self.keys(ops), decoder.keys(ops)); } + + @Override + public String toString() { + return decoder.toString() + " * " + self.toString(); + } }; } diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index 751081b5..1d28379a 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -38,6 +38,11 @@ public RecordBuilder encode(final B input, final DynamicOps ops, final public Stream keys(final DynamicOps ops) { return self.keys(ops); } + + @Override + public String toString() { + return self.toString() + "[comapped]"; + } }; } diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index 1c4e50a2..ce983ea8 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -74,6 +74,11 @@ public DataResult decode(final DynamicOps ops, final MapLike input) public Stream keys(final DynamicOps ops) { return encoder.keys(ops); } + + @Override + public String toString() { + return "Dependent[" + encoder + "]"; + } } ); } From 09299f013b6df0cb7c2ab2a9530015b717c4959d Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 17 Mar 2020 12:10:42 +0100 Subject: [PATCH 42/96] Performance optimizations, specialized record builder for JsonOps --- .../com/mojang/serialization/DynamicOps.java | 12 ++- .../com/mojang/serialization/JsonOps.java | 73 ++++++++++++- .../com/mojang/serialization/MapDecoder.java | 8 +- .../com/mojang/serialization/MapEncoder.java | 98 ++++++----------- .../mojang/serialization/RecordBuilder.java | 100 ++++++++++++++++-- .../codecs/CompoundListCodec.java | 56 ++++------ .../serialization/codecs/ListCodec.java | 16 ++- .../codecs/RecordCodecBuilder.java | 15 +-- 8 files changed, 241 insertions(+), 137 deletions(-) diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index b978f474..86d00d95 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -12,6 +12,8 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -119,6 +121,10 @@ default DataResult mergeToPrimitive(final T prefix, final T value) { DataResult>> getMapValues(T input); + default DataResult>> getMapEntries(final T input) { + return getMapValues(input).map(s -> c -> s.forEach(p -> c.accept(p.getFirst(), p.getSecond()))); + } + T createMap(Stream> map); default DataResult> getMap(final T input) { @@ -137,6 +143,10 @@ default T createMap(final Map map) { DataResult> getStream(T input); + default DataResult>> getList(final T input) { + return getStream(input).map(s -> s::forEach); + } + T createList(Stream input); default DataResult getByteBuffer(final T input) { @@ -242,7 +252,7 @@ default DataResult list(final Iterable list, final T prefix, final Fun } default RecordBuilder mapBuilder() { - return new RecordBuilder.Builder<>(this); + return new RecordBuilder.MapBuilder<>(this); } default DataResult map(final Map map, final T prefix, final Function> keySerializer, final Function> elementSerializer) { diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index c5e84290..2145d801 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -13,7 +13,10 @@ import javax.annotation.Nullable; import java.math.BigDecimal; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -118,8 +121,10 @@ public JsonElement createBoolean(final boolean value) { @Override public DataResult getStringValue(final JsonElement input) { - if (input.isJsonPrimitive() && input.getAsJsonPrimitive().isString()) { - return DataResult.success(input.getAsString()); + if (input.isJsonPrimitive()) { + if (input.getAsJsonPrimitive().isString() || input.getAsJsonPrimitive().isNumber() && compressed) { + return DataResult.success(input.getAsString()); + } } return DataResult.error("Not a string: " + input); } @@ -212,6 +217,18 @@ public DataResult>> getMapValues(final Jso return DataResult.success(input.getAsJsonObject().entrySet().stream().map(entry -> Pair.of(new JsonPrimitive(entry.getKey()), entry.getValue()))); } + @Override + public DataResult>> getMapEntries(final JsonElement input) { + if (!input.isJsonObject()) { + return DataResult.error("Not a JSON object: " + input); + } + return DataResult.success(c -> { + for (final Map.Entry entry : input.getAsJsonObject().entrySet()) { + c.accept(createString(entry.getKey()), entry.getValue()); + } + }); + } + @Override public DataResult> getMap(final JsonElement input) { if (!input.isJsonObject()) { @@ -258,6 +275,18 @@ public DataResult> getStream(final JsonElement input) { return DataResult.error("Not a json array: " + input); } + @Override + public DataResult>> getList(final JsonElement input) { + if (input.isJsonArray()) { + return DataResult.success(c -> { + for (final JsonElement element : input.getAsJsonArray()) { + c.accept(element); + } + }); + } + return DataResult.error("Not a json array: " + input); + } + @Override public JsonElement createList(final Stream input) { final JsonArray result = new JsonArray(); @@ -335,4 +364,44 @@ public DataResult build(final JsonElement prefix) { public boolean compressMaps() { return compressed; } + + @Override + public RecordBuilder mapBuilder() { + return new JsonRecordBuilder(); + } + + private class JsonRecordBuilder extends RecordBuilder.AbstractStringBuilder { + protected JsonRecordBuilder() { + super(JsonOps.this); + } + + @Override + protected JsonObject initBuilder() { + return new JsonObject(); + } + + @Override + protected JsonObject append(final String key, final JsonElement value, final JsonObject builder) { + builder.add(key, value); + return builder; + } + + @Override + protected DataResult build(final JsonObject builder, final JsonElement prefix) { + if (prefix == null || prefix.isJsonNull()) { + return DataResult.success(builder); + } + if (prefix.isJsonObject()) { + final JsonObject result = new JsonObject(); + for (final Map.Entry entry : prefix.getAsJsonObject().entrySet()) { + result.add(entry.getKey(), entry.getValue()); + } + for (final Map.Entry entry : builder.entrySet()) { + result.add(entry.getKey(), entry.getValue()); + } + return DataResult.success(result); + } + return DataResult.error("mergeToMap called with not a map: " + prefix, prefix); + } + } } diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index fef6a11f..af51998f 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -6,10 +6,10 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -20,7 +20,11 @@ default DataResult compressedDecode(final DynamicOps ops, final T inpu if (ops.compressMaps()) { return decode(ops, new MapLike() { private final MapCompressor compressor = compressor(ops); - private final List entries = ops.getStream(input).result().get().collect(Collectors.toList()); + private final List entries = new ArrayList<>(); + + { + ops.getList(input).result().get().accept(entries::add); + } @Nullable @Override diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index 1d28379a..8905d6c8 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -4,11 +4,10 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.IntStream; import java.util.stream.Stream; public interface MapEncoder extends Encoder { @@ -16,7 +15,7 @@ public interface MapEncoder extends Encoder { default RecordBuilder compressedBuilder(final DynamicOps ops) { if (ops.compressMaps()) { - return new MapCodec.CompressedRecordBuilder<>(compressor(ops), ops); + return makeCompressedBuilder(ops, compressor(ops)); } return ops.mapBuilder(); } @@ -61,76 +60,39 @@ public MapCompressor compressor(final DynamicOps ops) { } } - class CompressedRecordBuilder implements RecordBuilder { - private final MapCompressor compressor; - private final DynamicOps ops; - private DataResult> builder; - - public CompressedRecordBuilder(final MapCompressor compressor, final DynamicOps ops) { - this.compressor = compressor; - this.ops = ops; - resetBuilder(compressor); - } - - @Override - public DynamicOps ops() { - return ops; - } - - @Override - public RecordBuilder add(final String key, final T value) { - builder = builder.map(b -> { - b.set(compressor.compress(key), value); - return b; - }); - return this; - } - - @Override - public RecordBuilder add(final String key, final DataResult value) { - builder = builder.ap2(value, (b, v) -> { - b.set(compressor.compress(key), v); - return b; - }); - return this; - } + static RecordBuilder makeCompressedBuilder(final DynamicOps ops, final MapCompressor compressor) { + class CompressedRecordBuilder extends RecordBuilder.AbstractBuilder> { + private CompressedRecordBuilder() { + super(ops); + } - @Override - public RecordBuilder add(final T key, final T value) { - builder = builder.map(b -> { - b.set(compressor.compress(key), value); - return b; - }); - return this; - } + @Override + protected List initBuilder() { + final ArrayList list = new ArrayList<>(compressor.size()); + for (int i = 0; i < compressor.size(); i++) { + list.add(null); + } + return list; + } - @Override - public RecordBuilder add(final T key, final DataResult value) { - builder = builder.ap2(value, (b, v) -> { - b.set(compressor.compress(key), v); - return b; - }); - return this; - } + @Override + protected List append(final T key, final T value, final List builder) { + builder.set(compressor.compress(key), value); + return builder; + } - @Override - public RecordBuilder add(final DataResult key, final DataResult value) { - builder = builder.ap(key.ap2(value, (k, v) -> b -> { - b.set(compressor.compress(k), v); - return b; - })); - return this; - } + @Override + protected List append(final String key, final T value, final List builder) { + builder.set(compressor.compress(key), value); + return builder; + } - @Override - public DataResult build(final T prefix) { - final DataResult result = builder.flatMap(l -> ops.mergeToList(prefix, l)); - resetBuilder(compressor); - return result; + @Override + protected DataResult build(final List builder, final T prefix) { + return ops().mergeToList(prefix, builder); + } } - private void resetBuilder(final MapCompressor compressor) { - builder = DataResult.success(IntStream.range(0, compressor.size()).mapToObj(i -> null).collect(Collectors.toList())); - } + return new CompressedRecordBuilder(); } } diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 67be0538..0cffe560 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -3,6 +3,7 @@ package com.mojang.serialization; import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonElement; public interface RecordBuilder { DynamicOps ops(); @@ -39,11 +40,11 @@ default RecordBuilder add(final String key, final E value, final Encoder< return add(key, encoder.encodeStart(ops(), value)); } - final class Builder implements RecordBuilder { + abstract class AbstractStringBuilder implements RecordBuilder { private final DynamicOps ops; - private DataResult> builder = DataResult.success(ImmutableMap.builder()); + protected DataResult builder = DataResult.success(initBuilder()); - public Builder(final DynamicOps ops) { + protected AbstractStringBuilder(final DynamicOps ops) { this.ops = ops; } @@ -52,29 +53,108 @@ public DynamicOps ops() { return ops; } + protected abstract R initBuilder(); + + protected abstract DataResult build(final R builder, final T prefix); + + protected abstract R append(String key, T value, R builder); + + @Override + public RecordBuilder add(final String key, final T value) { + builder = builder.map(b -> append(key, value, b)); + return this; + } + + @Override + public RecordBuilder add(final String key, final DataResult value) { + builder = builder.ap2(value, (b, v) -> append(key, v, b)); + return this; + } + + @Override + public DataResult build(final T prefix) { + final DataResult result = builder.flatMap(b -> build(b, prefix)); + builder = DataResult.success(initBuilder()); + return result; + } + @Override public RecordBuilder add(final T key, final T value) { - builder = builder.map(b -> b.put(key, value)); + builder = ops.getStringValue(key).flatMap(k -> { + add(k, value); + return builder; + }); return this; } @Override public RecordBuilder add(final T key, final DataResult value) { - builder = builder.ap2(value, (b, v) -> b.put(key, v)); + builder = ops.getStringValue(key).flatMap(k -> { + add(k, value); + return builder; + }); return this; } @Override public RecordBuilder add(final DataResult key, final DataResult value) { - builder = builder.ap(key.ap2(value, (k, v) -> b -> b.put(k, v))); + builder = key.flatMap(ops::getStringValue).flatMap(k -> { + add(k, value); + return builder; + }); return this; } + } + + abstract class AbstractBuilder extends AbstractStringBuilder { + protected AbstractBuilder(final DynamicOps ops) { + super(ops); + } + + protected abstract R append(T key, T value, R builder); @Override - public DataResult build(final T prefix) { - final DataResult result = builder.flatMap(b -> ops.mergeToMap(prefix, b.build())); - builder = DataResult.success(ImmutableMap.builder()); - return result; + protected R append(final String key, final T value, final R builder) { + return append(ops().createString(key), value, builder); + } + + @Override + public RecordBuilder add(final T key, final T value) { + builder = builder.map(b -> append(key, value, b)); + return this; + } + + @Override + public RecordBuilder add(final T key, final DataResult value) { + builder = builder.ap2(value, (b, v) -> append(key, v, b)); + return this; + } + + @Override + public RecordBuilder add(final DataResult key, final DataResult value) { + builder = builder.ap(key.ap2(value, (k, v) -> b -> append(k, v, b))); + return this; + } + } + + final class MapBuilder extends AbstractBuilder> { + public MapBuilder(final DynamicOps ops) { + super(ops); + } + + @Override + protected ImmutableMap.Builder initBuilder() { + return ImmutableMap.builder(); + } + + @Override + protected ImmutableMap.Builder append(final T key, final T value, final ImmutableMap.Builder builder) { + return builder.put(key, value); + } + + @Override + protected DataResult build(final ImmutableMap.Builder builder, final T prefix) { + return ops().mergeToMap(prefix, builder.build()); } } } diff --git a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java index 727d6024..53adbc7e 100644 --- a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java @@ -4,14 +4,13 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.RecordBuilder; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -26,53 +25,34 @@ public CompoundListCodec(final Codec keyCodec, final Codec elementCodec) { @Override public DataResult>, T>> decode(final DynamicOps ops, final T input) { - return ops.getMapValues(input).flatMap(map -> { - final AtomicReference>, ImmutableMap.Builder>>> result = - new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableMap.builder()))); - - map.forEach(entry -> { - result.set(result.get().flatMap(pair -> { - final DataResult> readEntry = keyCodec.parse(ops, entry.getFirst()).flatMap(keyValue -> - elementCodec.parse(ops, entry.getSecond()).map(elementValue -> - Pair.of(keyValue, elementValue) - ) - ); - readEntry.error().ifPresent(e -> { - pair.getSecond().put(entry.getFirst(), entry.getSecond()); - }); - return readEntry.map(r -> { - pair.getFirst().add(r); - return pair; - }); - })); + return ops.getMapEntries(input).flatMap(map -> { + final AtomicReference>>> result = new AtomicReference<>(DataResult.success(ImmutableList.builder())); + final ImmutableMap.Builder errors = ImmutableMap.builder(); + + map.accept((key, value) -> { + final DataResult k = keyCodec.parse(ops, key); + final DataResult v = elementCodec.parse(ops, value); + + final DataResult> readEntry = k.ap2(v, Pair::new); + + readEntry.error().ifPresent(e -> errors.put(key, value)); + + result.set(result.get().ap2(readEntry, ImmutableList.Builder::add)); }); - return result.get().map(pair -> Pair.of(pair.getFirst().build(), ops.createMap(pair.getSecond().build()))); + return result.get().map(builder -> Pair.of(builder.build(), ops.createMap(errors.build()))); }); } @Override public DataResult encode(final List> input, final DynamicOps ops, final T prefix) { - final Map map = Maps.newHashMap(); - - DataResult> result = DataResult.success(map); + final RecordBuilder builder = ops.mapBuilder(); for (final Pair pair : input) { - result = result.flatMap(m -> { - final DataResult element = elementCodec.encodeStart(ops, pair.getSecond()); - final DataResult> entry = element.flatMap(e -> keyCodec.encodeStart(ops, pair.getFirst()).map(k -> Pair.of(k, e))); - return entry.flatMap(e -> { - final T key = e.getFirst(); - if (m.containsKey(key)) { - return DataResult.error("Duplicate key: " + key, m); - } - m.put(key, e.getSecond()); - return DataResult.success(m); - }); - }); + builder.add(keyCodec.encodeStart(ops, pair.getFirst()), elementCodec.encodeStart(ops, pair.getSecond())); } - return result.flatMap(m -> ops.mergeToMap(prefix, m)); + return builder.build(prefix); } diff --git a/src/main/java/com/mojang/serialization/codecs/ListCodec.java b/src/main/java/com/mojang/serialization/codecs/ListCodec.java index 27a63704..1c0c3725 100644 --- a/src/main/java/com/mojang/serialization/codecs/ListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/ListCodec.java @@ -7,8 +7,8 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.ListBuilder; -import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -22,26 +22,22 @@ public ListCodec(final Codec elementCodec) { @Override public DataResult encode(final List input, final DynamicOps ops, final T prefix) { - final java.util.List list = new ArrayList<>(input.size()); - DataResult> result = DataResult.success(list); + final ListBuilder builder = ops.listBuilder(); for (final A a : input) { - result = result.ap2(elementCodec.encode(a, ops, ops.empty()), (l, e) -> { - l.add(e); - return l; - }); + builder.add(elementCodec.encodeStart(ops, a)); } - return result.flatMap(l -> ops.mergeToList(prefix, l)); + return builder.build(prefix); } @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { - return ops.getStream(input).flatMap(stream -> { + return ops.getList(input).flatMap(stream -> { final AtomicReference, ImmutableList.Builder>>> result = new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableList.builder()))); - stream.forEach(t -> + stream.accept(t -> result.set(result.get().flatMap(pair -> { final DataResult> read = elementCodec.decode(ops, t); diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index ce983ea8..adeb4358 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -211,10 +211,11 @@ public String toString() { new MapDecoder.Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - return DataResult.unbox(DataResult.instance().group( + return DataResult.unbox(DataResult.instance().ap2( + function.decoder.decode(ops, input), fa.decoder.decode(ops, input), fb.decoder.decode(ops, input) - ).apply(function.decoder.decode(ops, input))); + )); } @Override @@ -279,11 +280,12 @@ public String toString() { new MapDecoder.Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - return DataResult.unbox(DataResult.instance().group( + return DataResult.unbox(DataResult.instance().ap3( + function.decoder.decode(ops, input), f1.decoder.decode(ops, input), f2.decoder.decode(ops, input), f3.decoder.decode(ops, input) - ).apply(function.decoder.decode(ops, input))); + )); } @Override @@ -359,12 +361,13 @@ public String toString() { new MapDecoder.Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - return DataResult.unbox(DataResult.instance().group( + return DataResult.unbox(DataResult.instance().ap4( + function.decoder.decode(ops, input), f1.decoder.decode(ops, input), f2.decoder.decode(ops, input), f3.decoder.decode(ops, input), f4.decoder.decode(ops, input) - ).apply(function.decoder.decode(ops, input))); + )); } @Override From 8e2ecab75910f4bfde4dbf18f5fdb5a6c39b2eed Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 24 Mar 2020 17:18:33 +0100 Subject: [PATCH 43/96] Exploring slightly alternative syntax for RecordCodecBuilder --- .../mojang/serialization/codecs/RecordCodecBuilder.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index adeb4358..ee0259ba 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -56,8 +56,8 @@ public static RecordCodecBuilder point(final F instance) { return new RecordCodecBuilder<>(o -> instance, o -> Encoder.empty(), Decoder.unit(instance)); } - public static MapCodec build(final App, O> builder) { - return build(unbox(builder)); + public static MapCodec create(final Function, ? extends App, O>> builder) { + return build(builder.apply(instance())); } public RecordCodecBuilder dependent(final Function getter, final MapEncoder encoder, final Function> decoderGetter) { @@ -83,7 +83,8 @@ public String toString() { ); } - public static MapCodec build(final RecordCodecBuilder builder) { + public static MapCodec build(final App, O> builderBox) { + final RecordCodecBuilder builder = unbox(builderBox); return new MapCodec() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { From ea97a3f0bf2df2fd83c652819c629d66e1d96e5d Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 26 Mar 2020 14:05:37 +0100 Subject: [PATCH 44/96] Codecs for lists of primitives specialised in DynamicOps --- .../java/com/mojang/serialization/Codec.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 01cac19d..1d9e77ab 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -12,10 +12,13 @@ import com.mojang.serialization.codecs.PairCodec; import com.mojang.serialization.codecs.PrimitiveCodec; +import java.nio.ByteBuffer; import java.util.List; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.LongStream; public interface Codec extends Encoder, Decoder { static Codec of(final Decoder decoder) { @@ -241,6 +244,60 @@ public String toString() { } }; + PrimitiveCodec BYTE_BUFFER = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getByteBuffer(input); + } + + @Override + public T write(final DynamicOps ops, final ByteBuffer value) { + return ops.createByteList(value); + } + + @Override + public String toString() { + return "ByteBuffer"; + } + }; + + PrimitiveCodec INT_STREAM = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getIntStream(input); + } + + @Override + public T write(final DynamicOps ops, final IntStream value) { + return ops.createIntList(value); + } + + @Override + public String toString() { + return "IntStream"; + } + }; + + PrimitiveCodec LONG_STREAM = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getLongStream(input); + } + + @Override + public T write(final DynamicOps ops, final LongStream value) { + return ops.createLongList(value); + } + + @Override + public String toString() { + return "LongStream"; + } + }; + Codec> SAVING = new Codec>() { @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { From d4f705af54c4f9521fb4e944861a25d2e8f7e4b1 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 21 Apr 2020 21:43:10 +0200 Subject: [PATCH 45/96] Fixed error in compressed OptionalFieldCodec, cleaned up compressed MapCodec code. --- .../com/mojang/serialization/MapDecoder.java | 20 ++++++++++++------- .../codecs/OptionalFieldCodec.java | 6 +++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index af51998f..335928ba 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -9,6 +9,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -18,14 +20,17 @@ public interface MapDecoder extends Decoder { default DataResult compressedDecode(final DynamicOps ops, final T input) { if (ops.compressMaps()) { - return decode(ops, new MapLike() { - private final MapCompressor compressor = compressor(ops); - private final List entries = new ArrayList<>(); + final Optional>> inputList = ops.getList(input).result(); - { - ops.getList(input).result().get().accept(entries::add); - } + if (!inputList.isPresent()) { + return DataResult.error("Input is not a list"); + } + + final MapCompressor compressor = compressor(ops); + final List entries = new ArrayList<>(); + inputList.get().accept(entries::add); + final MapLike map = new MapLike() { @Nullable @Override public T get(final T key) { @@ -42,7 +47,8 @@ public T get(final String key) { public Stream> entries() { return IntStream.range(0, entries.size()).mapToObj(i -> Pair.of(compressor.decompress(i), entries.get(i))); } - }); + }; + return decode(ops, map); } return ops.getMap(input).flatMap(map -> decode(ops, map)); } diff --git a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java index 1050eede..dd3c1ca3 100644 --- a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java @@ -43,10 +43,10 @@ public DataResult, T>> decode(final DynamicOps ops, fina @Override public DataResult encode(final Optional input, final DynamicOps ops, final T prefix) { - if (ops.compressMaps()) { - return super.encode(input, ops, prefix); - } if (input.isPresent()) { + if (ops.compressMaps()) { + return super.encode(input, ops, prefix); + } return elementCodec.encodeStart(ops, input.get()).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); } return DataResult.success(prefix); From a9858d6fe10a2f862d3119c21ed1679ad60b7178 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 21 Apr 2020 21:44:03 +0200 Subject: [PATCH 46/96] Added a direct getter to OptionalDynamic --- src/main/java/com/mojang/serialization/OptionalDynamic.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/mojang/serialization/OptionalDynamic.java b/src/main/java/com/mojang/serialization/OptionalDynamic.java index 53a6d7b6..16beb0bf 100644 --- a/src/main/java/com/mojang/serialization/OptionalDynamic.java +++ b/src/main/java/com/mojang/serialization/OptionalDynamic.java @@ -20,6 +20,10 @@ public OptionalDynamic(final DynamicOps ops, final DataResult> del this.delegate = delegate; } + public DataResult> get() { + return delegate; + } + public Optional> result() { return delegate.result(); } From a9d0d6b1b6ff10a5b09c0de32f96c1b2b63754d6 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 22 Apr 2020 12:50:36 +0200 Subject: [PATCH 47/96] Applicative .and helpers --- .../mojang/datafixers/kinds/Applicative.java | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index 92eba1f2..e7d26c8d 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -157,6 +157,30 @@ public P2 and(final App t2) { return new P2<>(instance, t1, t2); } + public P3 and(final P2 p) { + return new P3<>(instance, t1, p.t1, p.t2); + } + + public P4 and(final P3 p) { + return new P4<>(instance, t1, p.t1, p.t2, p.t3); + } + + public P5 and(final P4 p) { + return new P5<>(instance, t1, p.t1, p.t2, p.t3, p.t4); + } + + public P6 and(final P5 p) { + return new P6<>(instance, t1, p.t1, p.t2, p.t3, p.t4, p.t5); + } + + public P7 and(final P6 p) { + return new P7<>(instance, t1, p.t1, p.t2, p.t3, p.t4, p.t5, p.t6); + } + + public P8 and(final P7 p) { + return new P8<>(instance, t1, p.t1, p.t2, p.t3, p.t4, p.t5, p.t6, p.t7); + } + public App apply(final Function function) { return apply(instance.point(function)); } @@ -181,6 +205,26 @@ public P3 and(final App t3) { return new P3<>(instance, t1, t2, t3); } + public P4 and(final P2 p) { + return new P4<>(instance, t1, t2, p.t1, p.t2); + } + + public P5 and(final P3 p) { + return new P5<>(instance, t1, t2, p.t1, p.t2, p.t3); + } + + public P6 and(final P4 p) { + return new P6<>(instance, t1, t2, p.t1, p.t2, p.t3, p.t4); + } + + public P7 and(final P5 p) { + return new P7<>(instance, t1, t2, p.t1, p.t2, p.t3, p.t4, p.t5); + } + + public P8 and(final P6 p) { + return new P8<>(instance, t1, t2, p.t1, p.t2, p.t3, p.t4, p.t5, p.t6); + } + public App apply(final BiFunction function) { return apply(instance.point(function)); } @@ -207,6 +251,22 @@ public P4 and(final App t4) { return new P4<>(instance, t1, t2, t3, t4); } + public P5 and(final P2 p) { + return new P5<>(instance, t1, t2, t3, p.t1, p.t2); + } + + public P6 and(final P3 p) { + return new P6<>(instance, t1, t2, t3, p.t1, p.t2, p.t3); + } + + public P7 and(final P4 p) { + return new P7<>(instance, t1, t2, t3, p.t1, p.t2, p.t3, p.t4); + } + + public P8 and(final P5 p) { + return new P8<>(instance, t1, t2, t3, p.t1, p.t2, p.t3, p.t4, p.t5); + } + public App apply(final Function3 function) { return apply(instance.point(function)); } @@ -235,6 +295,18 @@ public P5 and(final App t5) { return new P5<>(instance, t1, t2, t3, t4, t5); } + public P6 and(final P2 p) { + return new P6<>(instance, t1, t2, t3, t4, p.t1, p.t2); + } + + public P7 and(final P3 p) { + return new P7<>(instance, t1, t2, t3, t4, p.t1, p.t2, p.t3); + } + + public P8 and(final P4 p) { + return new P8<>(instance, t1, t2, t3, t4, p.t1, p.t2, p.t3, p.t4); + } + public App apply(final Function4 function) { return apply(instance.point(function)); } @@ -265,6 +337,14 @@ public P6 and(final App t6) { return new P6<>(instance, t1, t2, t3, t4, t5, t6); } + public P7 and(final P2 p) { + return new P7<>(instance, t1, t2, t3, t4, t5, p.t1, p.t2); + } + + public P8 and(final P3 p) { + return new P8<>(instance, t1, t2, t3, t4, t5, p.t1, p.t2, p.t3); + } + public App apply(final Function5 function) { return apply(instance.point(function)); } @@ -297,6 +377,10 @@ public P7 and(final App t7) { return new P7<>(instance, t1, t2, t3, t4, t5, t6, t7); } + public P8 and(final P2 p) { + return new P8<>(instance, t1, t2, t3, t4, t5, t6, p.t1, p.t2); + } + public App apply(final Function6 function) { return apply(instance.point(function)); } @@ -327,6 +411,10 @@ private P7(final Applicative instance, final App t1, final App P8 and(final App t8) { + return new P8<>(instance, t1, t2, t3, t4, t5, t6, t7, t8); + } + public App apply(final Function7 function) { return apply(instance.point(function)); } From 438d0629b0ece1dd175b63b7ba1780f2f0be8997 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 22 Apr 2020 13:11:38 +0200 Subject: [PATCH 48/96] Function9 - Function16 --- .../mojang/datafixers/util/Function10.java | 44 ++++++++++++ .../mojang/datafixers/util/Function11.java | 48 +++++++++++++ .../mojang/datafixers/util/Function12.java | 52 ++++++++++++++ .../mojang/datafixers/util/Function13.java | 56 +++++++++++++++ .../mojang/datafixers/util/Function14.java | 60 ++++++++++++++++ .../mojang/datafixers/util/Function15.java | 64 +++++++++++++++++ .../mojang/datafixers/util/Function16.java | 68 +++++++++++++++++++ .../com/mojang/datafixers/util/Function9.java | 40 +++++++++++ 8 files changed, 432 insertions(+) create mode 100644 src/main/java/com/mojang/datafixers/util/Function10.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function11.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function12.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function13.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function14.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function15.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function16.java create mode 100644 src/main/java/com/mojang/datafixers/util/Function9.java diff --git a/src/main/java/com/mojang/datafixers/util/Function10.java b/src/main/java/com/mojang/datafixers/util/Function10.java new file mode 100644 index 00000000..a30c9ec7 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function10.java @@ -0,0 +1,44 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function10 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7, t8, t9, t10) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7, t8, t9, t10) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7, t8, t9, t10) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7, t8, t9, t10) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7, t8, t9, t10) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> (t7, t8, t9, t10) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default Function7> curry7() { + return (t1, t2, t3, t4, t5, t6, t7) -> (t8, t9, t10) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default Function8> curry8() { + return (t1, t2, t3, t4, t5, t6, t7, t8) -> (t9, t10) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default Function9> curry9() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9) -> t10 -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function11.java b/src/main/java/com/mojang/datafixers/util/Function11.java new file mode 100644 index 00000000..65e49904 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function11.java @@ -0,0 +1,48 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function11 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7, t8, t9, t10, t11) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7, t8, t9, t10, t11) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7, t8, t9, t10, t11) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7, t8, t9, t10, t11) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> (t7, t8, t9, t10, t11) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default Function7> curry7() { + return (t1, t2, t3, t4, t5, t6, t7) -> (t8, t9, t10, t11) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default Function8> curry8() { + return (t1, t2, t3, t4, t5, t6, t7, t8) -> (t9, t10, t11) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default Function9> curry9() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9) -> (t10, t11) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default Function10> curry10() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) -> t11 -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function12.java b/src/main/java/com/mojang/datafixers/util/Function12.java new file mode 100644 index 00000000..4eead84a --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function12.java @@ -0,0 +1,52 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function12 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7, t8, t9, t10, t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7, t8, t9, t10, t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7, t8, t9, t10, t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> (t7, t8, t9, t10, t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Function7> curry7() { + return (t1, t2, t3, t4, t5, t6, t7) -> (t8, t9, t10, t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Function8> curry8() { + return (t1, t2, t3, t4, t5, t6, t7, t8) -> (t9, t10, t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Function9> curry9() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9) -> (t10, t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Function10> curry10() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) -> (t11, t12) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Function11> curry11() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) -> t12 -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function13.java b/src/main/java/com/mojang/datafixers/util/Function13.java new file mode 100644 index 00000000..cac973b2 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function13.java @@ -0,0 +1,56 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function13 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12, T13 t13); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7, t8, t9, t10, t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7, t8, t9, t10, t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> (t7, t8, t9, t10, t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function7> curry7() { + return (t1, t2, t3, t4, t5, t6, t7) -> (t8, t9, t10, t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function8> curry8() { + return (t1, t2, t3, t4, t5, t6, t7, t8) -> (t9, t10, t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function9> curry9() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9) -> (t10, t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function10> curry10() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) -> (t11, t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function11> curry11() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) -> (t12, t13) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Function12> curry12() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) -> t13 -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function14.java b/src/main/java/com/mojang/datafixers/util/Function14.java new file mode 100644 index 00000000..5cc5d1a1 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function14.java @@ -0,0 +1,60 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function14 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12, T13 t13, T14 t14); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7, t8, t9, t10, t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7, t8, t9, t10, t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> (t7, t8, t9, t10, t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function7> curry7() { + return (t1, t2, t3, t4, t5, t6, t7) -> (t8, t9, t10, t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function8> curry8() { + return (t1, t2, t3, t4, t5, t6, t7, t8) -> (t9, t10, t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function9> curry9() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9) -> (t10, t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function10> curry10() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) -> (t11, t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function11> curry11() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) -> (t12, t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function12> curry12() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) -> (t13, t14) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Function13> curry13() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) -> t14 -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function15.java b/src/main/java/com/mojang/datafixers/util/Function15.java new file mode 100644 index 00000000..6540da51 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function15.java @@ -0,0 +1,64 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function15 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12, T13 t13, T14 t14, T15 t15); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> (t7, t8, t9, t10, t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function7> curry7() { + return (t1, t2, t3, t4, t5, t6, t7) -> (t8, t9, t10, t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function8> curry8() { + return (t1, t2, t3, t4, t5, t6, t7, t8) -> (t9, t10, t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function9> curry9() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9) -> (t10, t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function10> curry10() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) -> (t11, t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function11> curry11() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) -> (t12, t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function12> curry12() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) -> (t13, t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function13> curry13() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) -> (t14, t15) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Function14> curry14() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14) -> t15 -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function16.java b/src/main/java/com/mojang/datafixers/util/Function16.java new file mode 100644 index 00000000..0b80b904 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function16.java @@ -0,0 +1,68 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function16 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12, T13 t13, T14 t14, T15 t15, T16 t16); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> (t7, t8, t9, t10, t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function7> curry7() { + return (t1, t2, t3, t4, t5, t6, t7) -> (t8, t9, t10, t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function8> curry8() { + return (t1, t2, t3, t4, t5, t6, t7, t8) -> (t9, t10, t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function9> curry9() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9) -> (t10, t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function10> curry10() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) -> (t11, t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function11> curry11() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) -> (t12, t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function12> curry12() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) -> (t13, t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function13> curry13() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) -> (t14, t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function14> curry14() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14) -> (t15, t16) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + + default Function15> curry15() { + return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) -> t16 -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } +} diff --git a/src/main/java/com/mojang/datafixers/util/Function9.java b/src/main/java/com/mojang/datafixers/util/Function9.java new file mode 100644 index 00000000..9deb3961 --- /dev/null +++ b/src/main/java/com/mojang/datafixers/util/Function9.java @@ -0,0 +1,40 @@ +package com.mojang.datafixers.util; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Function9 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9); + + default Function> curry() { + return t1 -> (t2, t3, t4, t5, t6, t7, t8, t9) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + + default BiFunction> curry2() { + return (t1, t2) -> (t3, t4, t5, t6, t7, t8, t9) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + + default Function3> curry3() { + return (t1, t2, t3) -> (t4, t5, t6, t7, t8, t9) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + + default Function4> curry4() { + return (t1, t2, t3, t4) -> (t5, t6, t7, t8, t9) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + + default Function5> curry5() { + return (t1, t2, t3, t4, t5) -> (t6, t7, t8, t9) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + + default Function6> curry6() { + return (t1, t2, t3, t4, t5, t6) -> (t7, t8, t9) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + + default Function7> curry7() { + return (t1, t2, t3, t4, t5, t6, t7) -> (t8, t9) -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + + default Function8> curry8() { + return (t1, t2, t3, t4, t5, t6, t7, t8) -> t9 -> apply(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } +} From 21303f6221b7e3ae004ef0bbd03235354b99ba20 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 22 Apr 2020 13:17:19 +0200 Subject: [PATCH 49/96] 9-arg applicative methods, sorted --- .../mojang/datafixers/kinds/Applicative.java | 65 ++++++++++++------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index e7d26c8d..302e91c6 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -8,6 +8,7 @@ import com.mojang.datafixers.util.Function6; import com.mojang.datafixers.util.Function7; import com.mojang.datafixers.util.Function8; +import com.mojang.datafixers.util.Function9; import java.util.function.BiFunction; import java.util.function.Function; @@ -47,6 +48,14 @@ default Function7, App, App ap7(function, ft1, ft2, ft3, ft4, ft5, ft6, ft7); } + default Function8, App, App, App, App, App, App, App, App> lift8(final App> function) { + return (ft1, ft2, ft3, ft4, ft5, ft6, ft7, ft8) -> ap8(function, ft1, ft2, ft3, ft4, ft5, ft6, ft7, ft8); + } + + default Function9, App, App, App, App, App, App, App, App, App> lift9(final App> function) { + return (ft1, ft2, ft3, ft4, ft5, ft6, ft7, ft8, ft9) -> ap9(function, ft1, ft2, ft3, ft4, ft5, ft6, ft7, ft8, ft9); + } + default App ap(final App> func, final App arg) { return lift1(func).apply(arg); } @@ -60,58 +69,66 @@ default App ap2(final App> func, final Ap return ap(ap(map(curry, func), a), b); } - default App apply2(BiFunction func, final App a, final App b) { - return ap2(point(func), a, b); - } - default App ap3(final App> func, final App t1, final App t2, final App t3) { return ap2(ap(map(Function3::curry, func), t1), t2, t3); } - default App apply3(final Function3 func, final App t1, final App t2, final App t3) { - return ap3(point(func), t1, t2, t3); - } - default App ap4(final App> func, final App t1, final App t2, final App t3, final App t4) { return ap2(ap2(map(Function4::curry2, func), t1, t2), t3, t4); } - default App apply4(final Function4 func, final App t1, final App t2, final App t3, final App t4) { - return ap4(point(func), t1, t2, t3, t4); - } - default App ap5(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5) { return ap3(ap2(map(Function5::curry2, func), t1, t2), t3, t4, t5); } - default App apply5(final Function5 func, final App t1, final App t2, final App t3, final App t4, final App t5) { - return ap5(point(func), t1, t2, t3, t4, t5); - } - default App ap6(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { return ap3(ap3(map(Function6::curry3, func), t1, t2, t3), t4, t5, t6); } - default App apply6(final Function6 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { - return ap6(point(func), t1, t2, t3, t4, t5, t6); - } - default App ap7(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { return ap4(ap3(map(Function7::curry3, func), t1, t2, t3), t4, t5, t6, t7); } - default App apply7(final Function7 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { - return ap7(point(func), t1, t2, t3, t4, t5, t6, t7); - } - default App ap8(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { return ap4(ap4(map(Function8::curry4, func), t1, t2, t3, t4), t5, t6, t7, t8); } + default App ap9(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9) { + return ap5(ap4(map(Function9::curry4, func), t1, t2, t3, t4), t5, t6, t7, t8, t9); + } + + default App apply2(final BiFunction func, final App a, final App b) { + return ap2(point(func), a, b); + } + + default App apply3(final Function3 func, final App t1, final App t2, final App t3) { + return ap3(point(func), t1, t2, t3); + } + + default App apply4(final Function4 func, final App t1, final App t2, final App t3, final App t4) { + return ap4(point(func), t1, t2, t3, t4); + } + + default App apply5(final Function5 func, final App t1, final App t2, final App t3, final App t4, final App t5) { + return ap5(point(func), t1, t2, t3, t4, t5); + } + + default App apply6(final Function6 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { + return ap6(point(func), t1, t2, t3, t4, t5, t6); + } + + default App apply7(final Function7 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { + return ap7(point(func), t1, t2, t3, t4, t5, t6, t7); + } + default App apply8(final Function8 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { return ap8(point(func), t1, t2, t3, t4, t5, t6, t7, t8); } + default App apply9(final Function9 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9) { + return ap9(point(func), t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + default P1 group(final App t1) { return new P1<>(this, t1); } From c324d75944c5f6a16ab31cdee796b2c0ed8432b6 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 22 Apr 2020 13:24:41 +0200 Subject: [PATCH 50/96] ap10 - ap16 --- .../mojang/datafixers/kinds/Applicative.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index 302e91c6..f3cf742e 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -2,6 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.kinds; +import com.mojang.datafixers.util.Function10; +import com.mojang.datafixers.util.Function11; +import com.mojang.datafixers.util.Function12; +import com.mojang.datafixers.util.Function13; +import com.mojang.datafixers.util.Function14; +import com.mojang.datafixers.util.Function15; +import com.mojang.datafixers.util.Function16; import com.mojang.datafixers.util.Function3; import com.mojang.datafixers.util.Function4; import com.mojang.datafixers.util.Function5; @@ -97,6 +104,34 @@ default App ap9(final App App ap10(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10) { + return ap5(ap5(map(Function10::curry5, func), t1, t2, t3, t4, t5), t6, t7, t8, t9, t10); + } + + default App ap11(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11) { + return ap6(ap5(map(Function11::curry5, func), t1, t2, t3, t4, t5), t6, t7, t8, t9, t10, t11); + } + + default App ap12(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12) { + return ap6(ap6(map(Function12::curry6, func), t1, t2, t3, t4, t5, t6), t7, t8, t9, t10, t11, t12); + } + + default App ap13(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13) { + return ap7(ap6(map(Function13::curry6, func), t1, t2, t3, t4, t5, t6), t7, t8, t9, t10, t11, t12, t13); + } + + default App ap14(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14) { + return ap7(ap7(map(Function14::curry7, func), t1, t2, t3, t4, t5, t6, t7), t8, t9, t10, t11, t12, t13, t14); + } + + default App ap15(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15) { + return ap8(ap7(map(Function15::curry7, func), t1, t2, t3, t4, t5, t6, t7), t8, t9, t10, t11, t12, t13, t14, t15); + } + + default App ap16(final App> func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15, final App t16) { + return ap8(ap8(map(Function16::curry8, func), t1, t2, t3, t4, t5, t6, t7, t8), t9, t10, t11, t12, t13, t14, t15, t16); + } + default App apply2(final BiFunction func, final App a, final App b) { return ap2(point(func), a, b); } From 9c28f5cc06199b724b7fa5b0d05882fbacc92e9d Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 22 Apr 2020 13:33:12 +0200 Subject: [PATCH 51/96] P9 - P16 --- .../mojang/datafixers/kinds/Applicative.java | 328 ++++++++++++++++++ 1 file changed, 328 insertions(+) diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index f3cf742e..30c903ce 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -507,4 +507,332 @@ public App apply(final App { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + + private P9(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + } + + public App apply(final Function9 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap9(function, t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + } + + final class P10 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + + private P10(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + } + + public App apply(final Function10 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap10(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + } + + final class P11 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + + private P11(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + } + + public App apply(final Function11 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap11(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + } + + final class P12 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + + private P12(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + } + + public App apply(final Function12 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap12(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + } + + final class P13 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + private final App t13; + + private P13(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + this.t13 = t13; + } + + public App apply(final Function13 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap13(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + } + + final class P14 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + private final App t13; + private final App t14; + + private P14(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + this.t13 = t13; + this.t14 = t14; + } + + public App apply(final Function14 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap14(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + } + + final class P15 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + private final App t13; + private final App t14; + private final App t15; + + private P15(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + this.t13 = t13; + this.t14 = t14; + this.t15 = t15; + } + + public App apply(final Function15 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap15(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + } + + final class P16 { + private final Applicative instance; + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + private final App t13; + private final App t14; + private final App t15; + private final App t16; + + private P16(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15, final App t16) { + this.instance = instance; + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + this.t13 = t13; + this.t14 = t14; + this.t15 = t15; + this.t16 = t16; + } + + public App apply(final Function16 function) { + return apply(instance.point(function)); + } + + public App apply(final App> function) { + return instance.ap16(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + } } From f3a3eefef1e2762d04753572b22f296f25238e34 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 22 Apr 2020 13:37:21 +0200 Subject: [PATCH 52/96] group(9) - group(16) --- .../mojang/datafixers/kinds/Applicative.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index 30c903ce..f5c5a712 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -196,6 +196,38 @@ default P8 g return new P8<>(this, t1, t2, t3, t4, t5, t6, t7, t8); } + default P9 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9) { + return new P9<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + + default P10 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10) { + return new P10<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default P11 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11) { + return new P11<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default P12 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12) { + return new P12<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default P13 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13) { + return new P13<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default P14 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14) { + return new P14<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default P15 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15) { + return new P15<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default P16 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15, final App t16) { + return new P16<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + final class P1 { private final Applicative instance; private final App t1; From 302d259116271757795ee2fab9d5eb20a992244d Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 23 Apr 2020 19:02:27 +0200 Subject: [PATCH 53/96] A bunch of helpers on Codec --- .../java/com/mojang/serialization/Codec.java | 26 ++++++++++++++++ .../com/mojang/serialization/Decoder.java | 31 +++++++++++++++++++ .../com/mojang/serialization/Encoder.java | 15 +++++++++ 3 files changed, 72 insertions(+) diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 1d9e77ab..6b3f3887 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Optional; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.LongStream; @@ -76,6 +77,18 @@ default Codec xmap(final Function to, final Funct return Codec.of(comap(from), map(to), toString() + "[xmapped]"); } + default Codec comapFlatMap(final Function> to, final Function from) { + return Codec.of(comap(from), flatMap(to), toString() + "[comapFlatMapped]"); + } + + default Codec flatComapMap(final Function to, final Function> from) { + return Codec.of(flatComap(from), map(to), toString() + "[flatComapMapped]"); + } + + default Codec flatXmap(final Function> to, final Function> from) { + return Codec.of(flatComap(from), flatMap(to), toString() + "[flatXmapped]"); + } + @Override default MapCodec fieldOf(final String name) { return MapCodec.of( @@ -94,6 +107,19 @@ default Codec withDefault(final A value) { return Codec.of(this, Decoder.super.withDefault(value)); } + @Override + default Codec withDefault(final Supplier value) { + return Codec.of(this, Decoder.super.withDefault(value)); + } + + static MapCodec unit(final A defaultValue) { + return unit(() -> defaultValue); + } + + static MapCodec unit(final Supplier defaultValue) { + return MapCodec.of(Encoder.empty(), Decoder.unit(defaultValue)); + } + PrimitiveCodec FLOAT = new PrimitiveCodec() { @Override public DataResult read(final DynamicOps ops, final T input) { diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 0f42db35..b5bc67c8 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -57,6 +57,37 @@ public String toString() { }; } + default Decoder withDefault(final Supplier value) { + final Decoder self = this; + + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return DataResult.success(self.decode(ops, input).result().orElseGet(() -> Pair.of(value.get(), input))); + } + + @Override + public String toString() { + return "WithDefault[" + self + " " + value.get() + "]"; + } + }; + } + + default Decoder flatMap(final Function> function) { + final Decoder self = this; + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return self.decode(ops, input).flatMap(p -> function.apply(p.getFirst()).map(r -> Pair.of(r, p.getSecond()))); + } + + @Override + public String toString() { + return self.toString() + "[flatMapped]"; + } + }; + } + default Decoder map(final Function function) { final Decoder self = this; return new Decoder() { diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index ae48e04f..db12b7bc 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -33,6 +33,21 @@ public String toString() { }; } + default Encoder flatComap(final Function> function) { + final Encoder self = this; + return new Encoder() { + @Override + public DataResult encode(final B input, final DynamicOps ops, final T prefix) { + return function.apply(input).flatMap(a -> self.encode(a, ops, prefix)); + } + + @Override + public String toString() { + return self.toString() + "[flatComapped]"; + } + }; + } + static Encoder of() { return new Encoder() { @Override From 82b3356fa18519ef30eb4e1815b65c5ce15ede10 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 23 Apr 2020 19:02:58 +0200 Subject: [PATCH 54/96] Method to thread error through RecordBuilder and ListBuilder. --- src/main/java/com/mojang/serialization/JsonOps.java | 6 ++++++ src/main/java/com/mojang/serialization/ListBuilder.java | 8 ++++++++ .../java/com/mojang/serialization/RecordBuilder.java | 9 ++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 2145d801..2b015d2d 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -340,6 +340,12 @@ public ListBuilder add(final DataResult value) { return this; } + @Override + public ListBuilder withErrorsFrom(final DataResult result) { + builder = builder.flatMap(r -> result.map(v -> r)); + return this; + } + @Override public DataResult build(final JsonElement prefix) { final DataResult result = builder.flatMap(b -> { diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index 7050ed03..69f1789f 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -13,6 +13,8 @@ public interface ListBuilder { ListBuilder add(final DataResult value); + ListBuilder withErrorsFrom(final DataResult result); + default DataResult build(final DataResult prefix) { return prefix.flatMap(this::build); } @@ -64,6 +66,12 @@ public ListBuilder add(final DataResult value) { return this; } + @Override + public ListBuilder withErrorsFrom(final DataResult result) { + builder = builder.flatMap(r -> result.map(v -> r)); + return this; + } + @Override public DataResult build(final T prefix) { final DataResult result = builder.flatMap(b -> ops.mergeToList(prefix, b.build())); diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 0cffe560..3f040aad 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -3,7 +3,6 @@ package com.mojang.serialization; import com.google.common.collect.ImmutableMap; -import com.google.gson.JsonElement; public interface RecordBuilder { DynamicOps ops(); @@ -14,6 +13,8 @@ public interface RecordBuilder { RecordBuilder add(DataResult key, DataResult value); + RecordBuilder withErrorsFrom(final DataResult result); + DataResult build(T prefix); default DataResult build(final DataResult prefix) { @@ -104,6 +105,12 @@ public RecordBuilder add(final DataResult key, final DataResult value) }); return this; } + + @Override + public RecordBuilder withErrorsFrom(final DataResult result) { + builder = builder.flatMap(v -> result.map(r -> v)); + return this; + } } abstract class AbstractBuilder extends AbstractStringBuilder { From e7f9e2623cc2cc861509f4c9ff150ec48e8dfe59 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 23 Apr 2020 19:03:13 +0200 Subject: [PATCH 55/96] Fixed json null handling --- .../com/mojang/serialization/JsonOps.java | 64 +++++++++++-------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 2b015d2d..a4b5e079 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -37,13 +37,13 @@ public JsonElement empty() { @Override public Codec getType(final JsonElement input) { - if (input.isJsonObject()) { + if (input instanceof JsonObject) { return Codec.compoundList(Codec.SAVING, Codec.SAVING); } - if (input.isJsonArray()) { + if (input instanceof JsonArray) { return Codec.list(Codec.SAVING); } - if (input.isJsonNull()) { + if (input instanceof JsonNull) { return Codec.EMPTY; } final JsonPrimitive primitive = input.getAsJsonPrimitive(); @@ -77,7 +77,7 @@ public Codec getType(final JsonElement input) { @Override public DataResult getNumberValue(final JsonElement input) { - if (input.isJsonPrimitive()) { + if (input instanceof JsonPrimitive) { if (input.getAsJsonPrimitive().isNumber()) { return DataResult.success(input.getAsNumber()); } else if (input.getAsJsonPrimitive().isBoolean()) { @@ -91,7 +91,7 @@ public DataResult getNumberValue(final JsonElement input) { } } } - if (input.isJsonPrimitive() && input.getAsJsonPrimitive().isBoolean()) { + if (input instanceof JsonPrimitive && input.getAsJsonPrimitive().isBoolean()) { return DataResult.success(input.getAsJsonPrimitive().getAsBoolean() ? 1 : 0); } return DataResult.error("Not a number: " + input); @@ -104,7 +104,7 @@ public JsonElement createNumeric(final Number i) { @Override public DataResult getBooleanValue(final JsonElement input) { - if (input.isJsonPrimitive()) { + if (input instanceof JsonPrimitive) { if (input.getAsJsonPrimitive().isBoolean()) { return DataResult.success(input.getAsBoolean()); } else if (input.getAsJsonPrimitive().isNumber()) { @@ -121,7 +121,7 @@ public JsonElement createBoolean(final boolean value) { @Override public DataResult getStringValue(final JsonElement input) { - if (input.isJsonPrimitive()) { + if (input instanceof JsonPrimitive) { if (input.getAsJsonPrimitive().isString() || input.getAsJsonPrimitive().isNumber() && compressed) { return DataResult.success(input.getAsString()); } @@ -136,7 +136,7 @@ public JsonElement createString(final String value) { @Override public DataResult mergeToList(final JsonElement list, final JsonElement value) { - if (!list.isJsonArray() && list != empty()) { + if (!(list instanceof JsonArray) && list != empty()) { return DataResult.error("mergeToList called with not a list: " + list, list); } @@ -150,7 +150,7 @@ public DataResult mergeToList(final JsonElement list, final JsonEle @Override public DataResult mergeToList(final JsonElement list, final List values) { - if (!list.isJsonArray() && list != empty()) { + if (!(list instanceof JsonArray) && list != empty()) { return DataResult.error("mergeToList called with not a list: " + list, list); } @@ -164,10 +164,10 @@ public DataResult mergeToList(final JsonElement list, final List mergeToMap(final JsonElement map, final JsonElement key, final JsonElement value) { - if (!map.isJsonObject() && map != empty()) { + if (!(map instanceof JsonObject) && map != empty()) { return DataResult.error("mergeToMap called with not a map: " + map, map); } - if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString() && !compressed) { + if (!(key instanceof JsonPrimitive) || !key.getAsJsonPrimitive().isString() && !compressed) { return DataResult.error("key is not a string: " + key, map); } @@ -182,7 +182,7 @@ public DataResult mergeToMap(final JsonElement map, final JsonEleme @Override public DataResult mergeToMap(final JsonElement map, final MapLike values) { - if (!map.isJsonObject() && map != empty()) { + if (!(map instanceof JsonObject) && map != empty()) { return DataResult.error("mergeToMap called with not a map: " + map, map); } @@ -195,7 +195,7 @@ public DataResult mergeToMap(final JsonElement map, final MapLike { final JsonElement key = entry.getFirst(); - if (!key.isJsonPrimitive() || !key.getAsJsonPrimitive().isString() && !compressed) { + if (!(key instanceof JsonPrimitive) || !key.getAsJsonPrimitive().isString() && !compressed) { missed.add(key); return; } @@ -211,27 +211,27 @@ public DataResult mergeToMap(final JsonElement map, final MapLike>> getMapValues(final JsonElement input) { - if (!input.isJsonObject()) { + if (!(input instanceof JsonObject)) { return DataResult.error("Not a JSON object: " + input); } - return DataResult.success(input.getAsJsonObject().entrySet().stream().map(entry -> Pair.of(new JsonPrimitive(entry.getKey()), entry.getValue()))); + return DataResult.success(input.getAsJsonObject().entrySet().stream().map(entry -> Pair.of(new JsonPrimitive(entry.getKey()), entry.getValue() instanceof JsonNull ? null : entry.getValue()))); } @Override public DataResult>> getMapEntries(final JsonElement input) { - if (!input.isJsonObject()) { + if (!(input instanceof JsonObject)) { return DataResult.error("Not a JSON object: " + input); } return DataResult.success(c -> { for (final Map.Entry entry : input.getAsJsonObject().entrySet()) { - c.accept(createString(entry.getKey()), entry.getValue()); + c.accept(createString(entry.getKey()), entry.getValue() instanceof JsonNull ? null : entry.getValue()); } }); } @Override public DataResult> getMap(final JsonElement input) { - if (!input.isJsonObject()) { + if (!(input instanceof JsonObject)) { return DataResult.error("Not a JSON object: " + input); } final JsonObject object = input.getAsJsonObject(); @@ -239,13 +239,21 @@ public DataResult> getMap(final JsonElement input) { @Nullable @Override public JsonElement get(final JsonElement key) { - return object.get(key.getAsString()); + final JsonElement element = object.get(key.getAsString()); + if (element instanceof JsonNull) { + return null; + } + return element; } @Nullable @Override public JsonElement get(final String key) { - return object.get(key); + final JsonElement element = object.get(key); + if (element instanceof JsonNull) { + return null; + } + return element; } @Override @@ -269,18 +277,18 @@ public JsonElement createMap(final Stream> map) { @Override public DataResult> getStream(final JsonElement input) { - if (input.isJsonArray()) { - return DataResult.success(StreamSupport.stream(input.getAsJsonArray().spliterator(), false)); + if (input instanceof JsonArray) { + return DataResult.success(StreamSupport.stream(input.getAsJsonArray().spliterator(), false).map(e -> e instanceof JsonNull ? null : e)); } return DataResult.error("Not a json array: " + input); } @Override public DataResult>> getList(final JsonElement input) { - if (input.isJsonArray()) { + if (input instanceof JsonArray) { return DataResult.success(c -> { for (final JsonElement element : input.getAsJsonArray()) { - c.accept(element); + c.accept(element instanceof JsonNull ? null : element); } }); } @@ -296,7 +304,7 @@ public JsonElement createList(final Stream input) { @Override public JsonElement remove(final JsonElement input, final String key) { - if (input.isJsonObject()) { + if (input instanceof JsonObject) { final JsonObject result = new JsonObject(); input.getAsJsonObject().entrySet().stream().filter(entry -> !Objects.equals(entry.getKey(), key)).forEach(entry -> result.add(entry.getKey(), entry.getValue())); return result; @@ -349,7 +357,7 @@ public ListBuilder withErrorsFrom(final DataResult result) { @Override public DataResult build(final JsonElement prefix) { final DataResult result = builder.flatMap(b -> { - if (!prefix.isJsonArray() && prefix != ops().empty()) { + if (!(prefix instanceof JsonArray) && prefix != ops().empty()) { return DataResult.error("Cannot append a list to not a list: " + prefix, prefix); } @@ -394,10 +402,10 @@ protected JsonObject append(final String key, final JsonElement value, final Jso @Override protected DataResult build(final JsonObject builder, final JsonElement prefix) { - if (prefix == null || prefix.isJsonNull()) { + if (prefix == null || prefix instanceof JsonNull) { return DataResult.success(builder); } - if (prefix.isJsonObject()) { + if (prefix instanceof JsonObject) { final JsonObject result = new JsonObject(); for (final Map.Entry entry : prefix.getAsJsonObject().entrySet()) { result.add(entry.getKey(), entry.getValue()); From 52602ade3dc82de24e78dcbf4ad53b12939bb093 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 23 Apr 2020 19:03:40 +0200 Subject: [PATCH 56/96] Removed useless overrides in field codecs --- .../serialization/codecs/FieldDecoder.java | 20 ------------- .../serialization/codecs/FieldEncoder.java | 9 ------ .../codecs/OptionalFieldCodec.java | 29 ------------------- 3 files changed, 58 deletions(-) diff --git a/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java b/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java index 0e7e6327..47d55a9a 100644 --- a/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java +++ b/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java @@ -2,7 +2,6 @@ // Licensed under the MIT license. package com.mojang.serialization.codecs; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.Decoder; import com.mojang.serialization.DynamicOps; @@ -13,8 +12,6 @@ import java.util.stream.Stream; public class FieldDecoder extends MapDecoder.Implementation { - public static boolean REMOVE_FIELD_WHEN_PARSING = false; - protected final String name; private final Decoder elementCodec; @@ -23,23 +20,6 @@ public FieldDecoder(final String name, final Decoder elementCodec) { this.elementCodec = elementCodec; } - @Override - public DataResult> decode(final DynamicOps ops, final T input) { - if (ops.compressMaps()) { - return super.decode(ops, input); - } - return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> { - final T output; - if (REMOVE_FIELD_WHEN_PARSING) { - final T nameObject = ops.createString(name); - output = ops.createMap(map.entries().filter(e -> !Objects.equals(e.getFirst(), nameObject))); - } else { - output = input; - } - return Pair.of(r, output); - })); - } - @Override public DataResult decode(final DynamicOps ops, final MapLike input) { final T value = input.get(name); diff --git a/src/main/java/com/mojang/serialization/codecs/FieldEncoder.java b/src/main/java/com/mojang/serialization/codecs/FieldEncoder.java index e59c5fa1..d5a491fe 100644 --- a/src/main/java/com/mojang/serialization/codecs/FieldEncoder.java +++ b/src/main/java/com/mojang/serialization/codecs/FieldEncoder.java @@ -2,7 +2,6 @@ // Licensed under the MIT license. package com.mojang.serialization.codecs; -import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Encoder; import com.mojang.serialization.MapEncoder; @@ -20,14 +19,6 @@ public FieldEncoder(final String name, final Encoder elementCodec) { this.elementCodec = elementCodec; } - @Override - public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - if (ops.compressMaps()) { - return super.encode(input, ops, prefix); - } - return elementCodec.encodeStart(ops, input).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); - } - @Override public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { return prefix.add(name, elementCodec.encodeStart(ops, input)); diff --git a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java index dd3c1ca3..03af588d 100644 --- a/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/OptionalFieldCodec.java @@ -2,7 +2,6 @@ // Licensed under the MIT license. package com.mojang.serialization.codecs; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; @@ -24,34 +23,6 @@ public OptionalFieldCodec(final String name, final Codec elementCodec) { this.elementCodec = elementCodec; } - @Override - public DataResult, T>> decode(final DynamicOps ops, final T input) { - if (ops.compressMaps()) { - return super.decode(ops, input); - } - return ops.getMap(input).flatMap(map -> decode(ops, map).map(r -> { - final T output; - if (FieldDecoder.REMOVE_FIELD_WHEN_PARSING) { - final T nameObject = ops.createString(name); - output = ops.createMap(map.entries().filter(e -> !Objects.equals(e.getFirst(), nameObject))); - } else { - output = input; - } - return Pair.of(r, output); - })); - } - - @Override - public DataResult encode(final Optional input, final DynamicOps ops, final T prefix) { - if (input.isPresent()) { - if (ops.compressMaps()) { - return super.encode(input, ops, prefix); - } - return elementCodec.encodeStart(ops, input.get()).flatMap(result -> ops.mergeToMap(prefix, ops.createString(name), result)); - } - return DataResult.success(prefix); - } - @Override public DataResult> decode(final DynamicOps ops, final MapLike input) { final T value = input.get(name); From 7987718da0b30d0ee7ed0931675f8215c47b4555 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 23 Apr 2020 19:42:37 +0200 Subject: [PATCH 57/96] Simple map codec --- .../java/com/mojang/serialization/Codec.java | 5 ++ .../com/mojang/serialization/Keyable.java | 17 ++++ .../com/mojang/serialization/MapDecoder.java | 4 +- .../com/mojang/serialization/MapEncoder.java | 4 +- .../serialization/codecs/SimpleMapCodec.java | 77 +++++++++++++++++++ 5 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/Keyable.java create mode 100644 src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 6b3f3887..b3343d59 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -11,6 +11,7 @@ import com.mojang.serialization.codecs.OptionalFieldCodec; import com.mojang.serialization.codecs.PairCodec; import com.mojang.serialization.codecs.PrimitiveCodec; +import com.mojang.serialization.codecs.SimpleMapCodec; import java.nio.ByteBuffer; import java.util.List; @@ -65,6 +66,10 @@ static Codec>> compoundList(final Codec keyCodec, fina return new CompoundListCodec<>(keyCodec, elementCodec); } + static SimpleMapCodec simpleMap(final Codec keyCodec, final Codec elementCodec, final Keyable keys) { + return new SimpleMapCodec<>(keyCodec, elementCodec, keys); + } + static MapCodec> optionalField(final String name, final Codec elementCodec) { return new OptionalFieldCodec<>(name, elementCodec); } diff --git a/src/main/java/com/mojang/serialization/Keyable.java b/src/main/java/com/mojang/serialization/Keyable.java new file mode 100644 index 00000000..676c04bc --- /dev/null +++ b/src/main/java/com/mojang/serialization/Keyable.java @@ -0,0 +1,17 @@ +package com.mojang.serialization; + +import java.util.function.Supplier; +import java.util.stream.Stream; + +public interface Keyable { + Stream keys(DynamicOps ops); + + static Keyable forStrings(final Supplier> keys) { + return new Keyable() { + @Override + public Stream keys(final DynamicOps ops) { + return keys.get().map(ops::createString); + } + }; + } +} diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index 335928ba..d345eb2f 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -15,7 +15,7 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -public interface MapDecoder extends Decoder { +public interface MapDecoder extends Decoder, Keyable { DataResult decode(DynamicOps ops, MapLike input); default DataResult compressedDecode(final DynamicOps ops, final T input) { @@ -55,8 +55,6 @@ public Stream> entries() { MapCompressor compressor(DynamicOps ops); - Stream keys(final DynamicOps ops); - @Override default DataResult> decode(final DynamicOps ops, final T input) { return compressedDecode(ops, input).map(r -> Pair.of(r, input)); diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index 8905d6c8..c1b1da99 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -10,7 +10,7 @@ import java.util.function.Function; import java.util.stream.Stream; -public interface MapEncoder extends Encoder { +public interface MapEncoder extends Encoder, Keyable { RecordBuilder encode(A input, DynamicOps ops, RecordBuilder prefix); default RecordBuilder compressedBuilder(final DynamicOps ops) { @@ -20,8 +20,6 @@ default RecordBuilder compressedBuilder(final DynamicOps ops) { return ops.mapBuilder(); } - Stream keys(final DynamicOps ops); - MapCompressor compressor(final DynamicOps ops); @Override diff --git a/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java new file mode 100644 index 00000000..1e1aefe7 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Keyable; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +public final class SimpleMapCodec extends MapCodec> { + private final Codec keyCodec; + private final Codec elementCodec; + private final Keyable keys; + + public SimpleMapCodec(final Codec keyCodec, final Codec elementCodec, final Keyable keys) { + this.keyCodec = keyCodec; + this.elementCodec = elementCodec; + this.keys = keys; + } + + @Override + public Stream keys(final DynamicOps ops) { + return keys.keys(ops); + } + + @Override + public DataResult> decode(final DynamicOps ops, final MapLike input) { + final AtomicReference>> result = new AtomicReference<>(DataResult.success(ImmutableMap.builder())); + + input.entries().forEach(pair -> { + final DataResult k = keyCodec.parse(ops, pair.getFirst()); + final DataResult v = elementCodec.parse(ops, pair.getSecond()); + result.set(DataResult.unbox(DataResult.instance().apply3(ImmutableMap.Builder::put, result.get(), k, v))); + }); + + return result.get().map(ImmutableMap.Builder::build); + } + + @Override + public RecordBuilder encode(final Map input, final DynamicOps ops, final RecordBuilder prefix) { + for (final Map.Entry entry : input.entrySet()) { + prefix.add(keyCodec.encodeStart(ops, entry.getKey()), elementCodec.encodeStart(ops, entry.getValue())); + } + return prefix; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final SimpleMapCodec that = (SimpleMapCodec) o; + return Objects.equals(keyCodec, that.keyCodec) && Objects.equals(elementCodec, that.elementCodec); + } + + @Override + public int hashCode() { + return Objects.hash(keyCodec, elementCodec); + } + + @Override + public String toString() { + return "SimpleMapCodec[" + keyCodec + " -> " + elementCodec + ']'; + } +} From 36feaf5632f261335824bab0e0904d71f0dd0e41 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 23 Apr 2020 22:20:34 +0200 Subject: [PATCH 58/96] Extracted KeyDispatchCodec from TaggedChoiceType --- .../types/templates/TaggedChoice.java | 53 ++++------- .../java/com/mojang/serialization/Codec.java | 17 ++++ .../codecs/KeyDispatchCodec.java | 95 +++++++++++++++++++ 3 files changed, 128 insertions(+), 37 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index 770f4b97..c65d0e28 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -35,6 +35,7 @@ import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Encoder; +import com.mojang.serialization.codecs.KeyDispatchCodec; import javax.annotation.Nullable; import java.util.Arrays; @@ -180,46 +181,24 @@ public TypeTemplate buildTemplate() { return DSL.taggedChoice(name, keyType, types.entrySet().stream().map(e -> Pair.of(e.getKey(), e.getValue().template())).collect(Pair.toMap())); } + @SuppressWarnings("unchecked") + private DataResult>> encoder(final Pair pair) { + return getCodec(pair.getFirst()).map(c -> ((Encoder) c).comap(p -> (V) p.getSecond())); + } + @Override protected Codec> buildCodec() { - return new Codec>() { - @Override - public DataResult, T>> decode(final DynamicOps ops, final T input) { - return ops.getMap(input).flatMap(map -> { - final T value = map.get(name); - if (value == null) { - return DataResult.error("Input does not contain a key [" + name + "] with the name: " + input); - } - - return keyType.codec().decode(ops, value).flatMap(key -> { - final K keyValue = key.getFirst(); - final Type type = types.get(keyValue); - if (type != null) { - return type.codec().decode(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(keyValue, v))); - } - return DataResult.error("Unsupported key: " + keyValue + " in " + this); - }); - }); - } - - @Override - public DataResult encode(final Pair input, final DynamicOps ops, final T prefix) { - final Type type = types.get(input.getFirst()); - if (type == null) { - return DataResult.error("Unsupported key: " + input.getFirst() + " in " + this, prefix); - } - return capWrite(ops, type.codec(), input.getFirst(), input.getSecond(), prefix); - } + return new KeyDispatchCodec<>( + name, + keyType.codec(), + p -> DataResult.success(p.getFirst()), + k -> getCodec(k).map(c -> c.map(v -> Pair.of(k, v))), + this::encoder + ); + } - @SuppressWarnings("unchecked") - private DataResult capWrite(final DynamicOps ops, final Encoder encoder, final K key, final Object value, final T rest) { - return keyType.codec().encodeStart(ops, key).flatMap(k -> - encoder.encode((A) value, ops, rest).flatMap(v -> - ops.mergeToMap(v, ops.createString(name), k) - ) - ); - } - }; + private DataResult> getCodec(final K k) { + return Optional.ofNullable(types.get(k)).map(t -> DataResult.success(t.codec())).orElseGet(() -> DataResult.error("Unsupported key: " + k)); } @Override diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index b3343d59..00b94522 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -7,6 +7,7 @@ import com.mojang.datafixers.util.Unit; import com.mojang.serialization.codecs.CompoundListCodec; import com.mojang.serialization.codecs.EitherCodec; +import com.mojang.serialization.codecs.KeyDispatchCodec; import com.mojang.serialization.codecs.ListCodec; import com.mojang.serialization.codecs.OptionalFieldCodec; import com.mojang.serialization.codecs.PairCodec; @@ -125,6 +126,22 @@ static MapCodec unit(final Supplier defaultValue) { return MapCodec.of(Encoder.empty(), Decoder.unit(defaultValue)); } + default MapCodec dispatch(final Function type, final Function> codec) { + return dispatch("type", type, codec); + } + + default MapCodec dispatch(final String typeKey, final Function type, final Function> codec) { + return partialDispatchCodec(typeKey, type.andThen(DataResult::success), codec); + } + + default MapCodec partialDispatchCodec(final String typeKey, final Function> type, final Function> codec) { + return partialDispatch(typeKey, type, codec.andThen(DataResult::success)); + } + + default MapCodec partialDispatch(final String typeKey, final Function> type, final Function>> codec) { + return new KeyDispatchCodec<>(typeKey, this, type, codec); + } + PrimitiveCodec FLOAT = new PrimitiveCodec() { @Override public DataResult read(final DynamicOps ops, final T input) { diff --git a/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java b/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java new file mode 100644 index 00000000..26cf9e0c --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java @@ -0,0 +1,95 @@ +package com.mojang.serialization.codecs; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Decoder; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Encoder; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.MapDecoder; +import com.mojang.serialization.MapEncoder; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; + +import java.util.function.Function; +import java.util.stream.Stream; + +public class KeyDispatchCodec extends MapCodec { + private final String typeKey; + private final Codec keyCodec; + private final String valueKey = "value"; + private final Function> type; + private final Function>> decoder; + private final Function>> encoder; + + public KeyDispatchCodec(final String typeKey, final Codec keyCodec, final Function> type, final Function>> decoder, final Function>> encoder) { + this.typeKey = typeKey; + this.keyCodec = keyCodec; + this.type = type; + this.decoder = decoder; + this.encoder = encoder; + } + + /** + * Assumes codec(type(V)) is Codec + */ + public KeyDispatchCodec(final String typeKey, final Codec keyCodec, final Function> type, final Function>> codec) { + this(typeKey, keyCodec, type, codec, v -> getCodec(type, codec, v)); + } + + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + final T elementName = input.get(typeKey); + if (elementName == null) { + return DataResult.error("Input does not contain a key [" + typeKey + "]: " + input); + } + + return keyCodec.decode(ops, elementName).flatMap(type -> { + final DataResult> elementDecoder = decoder.apply(type.getFirst()); + return elementDecoder.flatMap(c -> { + if (c instanceof MapDecoder && !ops.compressMaps()) { + return ((MapDecoder) c).decode(ops, input).map(Function.identity()); + } + final T value = input.get(ops.createString(valueKey)); + if (value == null) { + return DataResult.error("Input does not have a \"value\" entry: " + input); + } + return c.parse(ops, value).map(Function.identity()); + }); + }); + } + + @Override + public RecordBuilder encode(final V input, final DynamicOps ops, final RecordBuilder prefix) { + final DataResult> elementEncoder = encoder.apply(input); + final RecordBuilder builder = prefix.withErrorsFrom(elementEncoder); + if (!elementEncoder.result().isPresent()) { + return builder; + } + + final Encoder c = elementEncoder.result().get(); + if (c instanceof MapEncoder && !ops.compressMaps()) { + return ((MapEncoder) c).encode(input, ops, prefix) + .add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))); + } + return prefix + .add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))) + .add(valueKey, c.encodeStart(ops, input)); + } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.of(typeKey, valueKey).map(ops::createString); + } + + @SuppressWarnings("unchecked") + private static DataResult> getCodec(final Function> type, final Function>> encoder, final V input) { + return type.apply(input).>flatMap(k -> encoder.apply(k).map(Function.identity())).map(c -> ((Encoder) c)); + } + + @Override + public String toString() { + return "KeyDispatchCodec[" + keyCodec.toString() + " " + type + " " + decoder + "]"; + } +} + From 9d211c47c2b9e9468a5b2a2b35ac4f2352d5f6dc Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 23 Apr 2020 23:08:45 +0200 Subject: [PATCH 59/96] Fixed compressor not falling back to non-string keys gracefully --- .../mojang/serialization/MapCompressor.java | 18 ++++++++++++------ .../com/mojang/serialization/MapDecoder.java | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/mojang/serialization/MapCompressor.java b/src/main/java/com/mojang/serialization/MapCompressor.java index 44c3a4fe..fdafd004 100644 --- a/src/main/java/com/mojang/serialization/MapCompressor.java +++ b/src/main/java/com/mojang/serialization/MapCompressor.java @@ -7,7 +7,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -17,15 +16,21 @@ public final class MapCompressor { private final Object2IntMap compress = new Object2IntArrayMap<>(); private final Object2IntMap compressString = new Object2IntArrayMap<>(); private final int size; + private final DynamicOps ops; public MapCompressor(final DynamicOps ops, final Stream keyStream) { - final List keys = keyStream.map(k -> ops.getStringValue(k).result().get()).distinct().sorted(Comparator.naturalOrder()).collect(Collectors.toList()); + this.ops = ops; + final List keys = keyStream.distinct().collect(Collectors.toList()); + + compressString.defaultReturnValue(-1); for (int i = 0; i < keys.size(); i++) { - final String string = keys.get(i); - final T key = ops.createString(string); + final T key = keys.get(i); compress.put(key, i); - compressString.put(string, i); + final int finalI = i; + ops.getStringValue(key).result().ifPresent(k -> + compressString.put(k, finalI) + ); decompress.put(i, key); } @@ -37,7 +42,8 @@ public T decompress(final int key) { } public int compress(final String key) { - return compressString.getInt(key); + final int id = compressString.getInt(key); + return id == -1 ? compress(ops.createString(key)) : id; } public int compress(final T key) { diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index d345eb2f..a361dab1 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -45,7 +45,7 @@ public T get(final String key) { @Override public Stream> entries() { - return IntStream.range(0, entries.size()).mapToObj(i -> Pair.of(compressor.decompress(i), entries.get(i))); + return IntStream.range(0, entries.size()).mapToObj(i -> Pair.of(compressor.decompress(i), entries.get(i))).filter(p -> p.getSecond() != null); } }; return decode(ops, map); From ea09a02f136daa8ec0128196bc5af4059b61c9fa Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Fri, 24 Apr 2020 12:55:01 +0200 Subject: [PATCH 60/96] Tweaked and expanded error handling, made list and map codecs collect partial results --- .../com/mojang/datafixers/DataFixUtils.java | 8 ++ .../java/com/mojang/serialization/Codec.java | 116 +++++++++++++++++- .../com/mojang/serialization/DataResult.java | 25 +++- .../com/mojang/serialization/Decoder.java | 44 +++---- .../com/mojang/serialization/JsonOps.java | 11 +- .../com/mojang/serialization/ListBuilder.java | 12 +- .../com/mojang/serialization/MapCodec.java | 115 +++++++++++++++-- .../com/mojang/serialization/MapDecoder.java | 22 ---- .../mojang/serialization/RecordBuilder.java | 16 ++- .../codecs/CompoundListCodec.java | 23 +++- .../serialization/codecs/ListCodec.java | 30 +++-- .../serialization/codecs/SimpleMapCodec.java | 21 +++- 12 files changed, 348 insertions(+), 95 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/DataFixUtils.java b/src/main/java/com/mojang/datafixers/DataFixUtils.java index 3a2046a1..83b3fb86 100644 --- a/src/main/java/com/mojang/datafixers/DataFixUtils.java +++ b/src/main/java/com/mojang/datafixers/DataFixUtils.java @@ -5,6 +5,7 @@ import java.nio.ByteBuffer; import java.util.Optional; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; public class DataFixUtils { @@ -93,4 +94,11 @@ public static int getVersion(final int key) { public static int getSubVersion(final int key) { return key % 10; } + + public static Function consumerToFunction(final Consumer consumer) { + return s -> { + consumer.accept(s); + return s; + }; + } } diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 00b94522..37e9e3e3 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -2,6 +2,7 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Unit; @@ -17,6 +18,7 @@ import java.nio.ByteBuffer; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -108,14 +110,120 @@ default MapCodec> optionalFieldOf(final String name) { return optionalField(name, this); } - @Override + interface ResultFunction { + DataResult> apply(final DynamicOps ops, final T input, final DataResult> a); + + DataResult coApply(final DynamicOps ops, final A input, final DataResult t); + } + + default Codec mapResult(final ResultFunction function) { + final Codec self = this; + + return new Codec() { + @Override + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return function.coApply(ops, input, self.encode(input, ops, prefix)); + } + + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return function.apply(ops, input, self.decode(ops, input)); + } + + @Override + public String toString() { + return self + "[mapResult " + function + "]"; + } + }; + } + + default Codec withDefault(final Consumer onError, final A value) { + return withDefault(DataFixUtils.consumerToFunction(onError), value); + } + + default Codec withDefault(final Function onError, final A value) { + return mapResult(new ResultFunction() { + @Override + public DataResult> apply(final DynamicOps ops, final T input, final DataResult> a) { + return DataResult.success(a.mapError(onError).result().orElseGet(() -> Pair.of(value, input))); + } + + @Override + public DataResult coApply(final DynamicOps ops, final A input, final DataResult t) { + return t.mapError(onError); + } + + @Override + public String toString() { + return "WithDefault[" + onError + " " + value + "]"; + } + }); + } + + default Codec withDefault(final Consumer onError, final Supplier value) { + return withDefault(DataFixUtils.consumerToFunction(onError), value); + } + + default Codec withDefault(final Function onError, final Supplier value) { + return mapResult(new ResultFunction() { + @Override + public DataResult> apply(final DynamicOps ops, final T input, final DataResult> a) { + return DataResult.success(a.mapError(onError).result().orElseGet(() -> Pair.of(value.get(), input))); + } + + @Override + public DataResult coApply(final DynamicOps ops, final A input, final DataResult t) { + return t.mapError(onError); + } + + @Override + public String toString() { + return "WithDefault[" + onError + " " + value.get() + "]"; + } + }); + } + default Codec withDefault(final A value) { - return Codec.of(this, Decoder.super.withDefault(value)); + return mapResult(new ResultFunction() { + @Override + public DataResult> apply(final DynamicOps ops, final T input, final DataResult> a) { + return DataResult.success(a.result().orElseGet(() -> Pair.of(value, input))); + } + + @Override + public DataResult coApply(final DynamicOps ops, final A input, final DataResult t) { + return t; + } + + @Override + public String toString() { + return "WithDefault[" + value + "]"; + } + }); } - @Override default Codec withDefault(final Supplier value) { - return Codec.of(this, Decoder.super.withDefault(value)); + return mapResult(new ResultFunction() { + @Override + public DataResult> apply(final DynamicOps ops, final T input, final DataResult> a) { + return DataResult.success(a.result().orElseGet(() -> Pair.of(value.get(), input))); + } + + @Override + public DataResult coApply(final DynamicOps ops, final A input, final DataResult t) { + return t; + } + + @Override + public String toString() { + return "WithDefault[" + value.get() + "]"; + } + }); + } + + @Override + default Codec promotePartial(final Consumer onError) { + return Codec.of(this, Decoder.super.promotePartial(onError)); } static MapCodec unit(final A defaultValue) { diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 44df6d17..6ca3139d 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -86,6 +86,18 @@ public DataResult map(final Function function) { )); } + public DataResult promotePartial(final Consumer onError) { + return result.map( + DataResult::success, + r -> { + onError.accept(r.message); + return r.partialResult + .map(DataResult::success) + .orElseGet(() -> create(Either.right(r))); + } + ); + } + /** * Applies the function to either full or partial result, in case of partial concatenates errors. */ @@ -120,9 +132,12 @@ public DataResult ap(final DataResult> functionResult) )); } - public DataResult ap2(final DataResult second, final BiFunction function) { - final Function> curried = r -> r2 -> function.apply(r, r2); - return second.ap(map(curried)); + public DataResult apply2(final BiFunction function, final DataResult second) { + return unbox(instance().apply2(function, this, second)); + } + + public DataResult apply3(final Function3 function, final DataResult second, final DataResult third) { + return unbox(instance().apply3(function, this, second, third)); } public DataResult setPartial(final Supplier partial) { @@ -133,6 +148,10 @@ public DataResult setPartial(final R partial) { return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial)))); } + public DataResult mapError(final Function function) { + return create(result.mapRight(r -> new DynamicException<>(function.apply(r.message), r.partialResult))); + } + public static Instance instance() { return Instance.INSTANCE; } diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index b5bc67c8..8d251873 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -5,6 +5,7 @@ import com.mojang.datafixers.util.Pair; import com.mojang.serialization.codecs.FieldDecoder; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; @@ -41,64 +42,47 @@ default MapDecoder fieldOf(final String name) { return new FieldDecoder<>(name, this); } - default Decoder withDefault(final A value) { - final Decoder self = this; - - return new Decoder() { - @Override - public DataResult> decode(final DynamicOps ops, final T input) { - return DataResult.success(self.decode(ops, input).result().orElseGet(() -> Pair.of(value, input))); - } - - @Override - public String toString() { - return "WithDefault[" + self + " " + value + "]"; - } - }; - } - - default Decoder withDefault(final Supplier value) { + default Decoder flatMap(final Function> function) { final Decoder self = this; - - return new Decoder() { + return new Decoder() { @Override - public DataResult> decode(final DynamicOps ops, final T input) { - return DataResult.success(self.decode(ops, input).result().orElseGet(() -> Pair.of(value.get(), input))); + public DataResult> decode(final DynamicOps ops, final T input) { + return self.decode(ops, input).flatMap(p -> function.apply(p.getFirst()).map(r -> Pair.of(r, p.getSecond()))); } @Override public String toString() { - return "WithDefault[" + self + " " + value.get() + "]"; + return self.toString() + "[flatMapped]"; } }; } - default Decoder flatMap(final Function> function) { + default Decoder map(final Function function) { final Decoder self = this; return new Decoder() { @Override public DataResult> decode(final DynamicOps ops, final T input) { - return self.decode(ops, input).flatMap(p -> function.apply(p.getFirst()).map(r -> Pair.of(r, p.getSecond()))); + return self.decode(ops, input).map(p -> p.mapFirst(function)); } @Override public String toString() { - return self.toString() + "[flatMapped]"; + return self.toString() + "[mapped]"; } }; } - default Decoder map(final Function function) { + default Decoder promotePartial(final Consumer onError) { final Decoder self = this; - return new Decoder() { + return new Decoder() { @Override - public DataResult> decode(final DynamicOps ops, final T input) { - return self.decode(ops, input).map(p -> p.mapFirst(function)); + public DataResult> decode(final DynamicOps ops, final T input) { + return self.decode(ops, input).promotePartial(onError); } @Override public String toString() { - return self.toString() + "[mapped]"; + return self.toString() + "[promotePartial]"; } }; } diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index a4b5e079..89981aad 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -17,6 +17,7 @@ import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -341,10 +342,10 @@ public ListBuilder add(final JsonElement value) { @Override public ListBuilder add(final DataResult value) { - builder = builder.ap2(value, (b, element) -> { + builder = builder.apply2((b, element) -> { b.add(element); return b; - }); + }, value); return this; } @@ -354,6 +355,12 @@ public ListBuilder withErrorsFrom(final DataResult result) { return this; } + @Override + public ListBuilder mapError(final Function onError) { + builder = builder.mapError(onError); + return this; + } + @Override public DataResult build(final JsonElement prefix) { final DataResult result = builder.flatMap(b -> { diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index 69f1789f..95082688 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -4,6 +4,8 @@ import com.google.common.collect.ImmutableList; +import java.util.function.Function; + public interface ListBuilder { DynamicOps ops(); @@ -15,6 +17,8 @@ public interface ListBuilder { ListBuilder withErrorsFrom(final DataResult result); + ListBuilder mapError(Function onError); + default DataResult build(final DataResult prefix) { return prefix.flatMap(this::build); } @@ -62,7 +66,7 @@ public ListBuilder add(final T value) { @Override public ListBuilder add(final DataResult value) { - builder = builder.ap2(value, ImmutableList.Builder::add); + builder = builder.apply2(ImmutableList.Builder::add, value); return this; } @@ -72,6 +76,12 @@ public ListBuilder withErrorsFrom(final DataResult result) { return this; } + @Override + public ListBuilder mapError(final Function onError) { + builder = builder.mapError(onError); + return this; + } + @Override public DataResult build(final T prefix) { final DataResult result = builder.flatMap(b -> ops.mergeToList(prefix, b.build())); diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 22613343..19c02721 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -2,11 +2,14 @@ // Licensed under the MIT license. package com.mojang.serialization; +import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.codecs.RecordCodecBuilder; import java.util.function.BiFunction; +import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Stream; public abstract class MapCodec extends MapDecoder.Implementation implements MapEncoder, Codec { @@ -87,29 +90,125 @@ public RecordBuilder encode(final O input, final DynamicOps ops, final @Override public abstract Stream keys(final DynamicOps ops); - @Override - public MapCodec withDefault(final A value) { + interface ResultFunction { + DataResult apply(final DynamicOps ops, final MapLike input, final DataResult a); + + RecordBuilder coApply(final DynamicOps ops, final A input, final RecordBuilder t); + } + + private MapCodec mapResult(final MapCodec.ResultFunction function) { final MapCodec self = this; + return new MapCodec() { @Override - public DataResult decode(final DynamicOps ops, final MapLike input) { - return DataResult.success(self.decode(ops, input).result().orElse(value)); + public Stream keys(final DynamicOps ops) { + return self.keys(ops); } @Override public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { - return self.encode(input, ops, prefix); + return function.coApply(ops, input, self.encode(input, ops, prefix)); } @Override - public Stream keys(final DynamicOps ops) { - return self.keys(ops); + public DataResult decode(final DynamicOps ops, final MapLike input) { + return function.apply(ops, input, self.decode(ops, input)); } @Override public String toString() { - return "WithDefault[" + self + " " + value + "]"; + return self + "[mapResult " + function + "]"; } }; } + + @Override + public Codec withDefault(final Consumer onError, final A value) { + return withDefault(DataFixUtils.consumerToFunction(onError), value); + } + + @Override + public MapCodec withDefault(final Function onError, final A value) { + return mapResult(new ResultFunction() { + @Override + public DataResult apply(final DynamicOps ops, final MapLike input, final DataResult a) { + return DataResult.success(a.mapError(onError).result().orElse(value)); + } + + @Override + public RecordBuilder coApply(final DynamicOps ops, final A input, final RecordBuilder t) { + return t.mapError(onError); + } + + @Override + public String toString() { + return "WithDefault[" + onError + " " + value + "]"; + } + }); + } + + @Override + public Codec withDefault(final Consumer onError, final Supplier value) { + return withDefault(DataFixUtils.consumerToFunction(onError), value); + } + + @Override + public MapCodec withDefault(final Function onError, final Supplier value) { + return mapResult(new ResultFunction() { + @Override + public DataResult apply(final DynamicOps ops, final MapLike input, final DataResult a) { + return DataResult.success(a.mapError(onError).result().orElseGet(value)); + } + + @Override + public RecordBuilder coApply(final DynamicOps ops, final A input, final RecordBuilder t) { + return t.mapError(onError); + } + + @Override + public String toString() { + return "WithDefault[" + onError + " " + value.get() + "]"; + } + }); + } + + @Override + public MapCodec withDefault(final A value) { + return mapResult(new ResultFunction() { + @Override + public DataResult apply(final DynamicOps ops, final MapLike input, final DataResult a) { + return DataResult.success(a.result().orElse(value)); + } + + @Override + public RecordBuilder coApply(final DynamicOps ops, final A input, final RecordBuilder t) { + return t; + } + + @Override + public String toString() { + return "WithDefault[" + value + "]"; + } + }); + } + + @Override + public MapCodec withDefault(final Supplier value) { + return mapResult(new ResultFunction() { + @Override + public DataResult apply(final DynamicOps ops, final MapLike input, final DataResult a) { + return DataResult.success(a.result().orElseGet(value)); + } + + @Override + public RecordBuilder coApply(final DynamicOps ops, final A input, final RecordBuilder t) { + return t; + } + + @Override + public String toString() { + return "WithDefault[" + value.get() + "]"; + } + }); + } } diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index a361dab1..01f62cfd 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -103,28 +103,6 @@ public String toString() { }; } - @Override - default MapDecoder withDefault(final A value) { - final MapDecoder self = this; - - return new Implementation() { - @Override - public DataResult decode(final DynamicOps ops, final MapLike input) { - return DataResult.success(self.decode(ops, input).result().orElse(value)); - } - - @Override - public Stream keys(final DynamicOps ops) { - return self.keys(ops); - } - - @Override - public String toString() { - return "WithDefault[" + self + " " + value + "]"; - } - }; - } - abstract class Implementation implements MapDecoder { private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 3f040aad..41e8bb83 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -4,6 +4,8 @@ import com.google.common.collect.ImmutableMap; +import java.util.function.Function; + public interface RecordBuilder { DynamicOps ops(); @@ -15,6 +17,8 @@ public interface RecordBuilder { RecordBuilder withErrorsFrom(final DataResult result); + RecordBuilder mapError(Function onError); + DataResult build(T prefix); default DataResult build(final DataResult prefix) { @@ -68,7 +72,7 @@ public RecordBuilder add(final String key, final T value) { @Override public RecordBuilder add(final String key, final DataResult value) { - builder = builder.ap2(value, (b, v) -> append(key, v, b)); + builder = builder.apply2((b, v) -> append(key, v, b), value); return this; } @@ -111,6 +115,12 @@ public RecordBuilder withErrorsFrom(final DataResult result) { builder = builder.flatMap(v -> result.map(r -> v)); return this; } + + @Override + public RecordBuilder mapError(final Function onError) { + builder = builder.mapError(onError); + return this; + } } abstract class AbstractBuilder extends AbstractStringBuilder { @@ -133,13 +143,13 @@ public RecordBuilder add(final T key, final T value) { @Override public RecordBuilder add(final T key, final DataResult value) { - builder = builder.ap2(value, (b, v) -> append(key, v, b)); + builder = builder.apply2((b, v) -> append(key, v, b), value); return this; } @Override public RecordBuilder add(final DataResult key, final DataResult value) { - builder = builder.ap(key.ap2(value, (k, v) -> b -> append(k, v, b))); + builder = builder.ap(key.apply2((k, v) -> b -> append(k, v, b), value)); return this; } } diff --git a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java index 53adbc7e..387d0ac1 100644 --- a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.mojang.datafixers.util.Pair; +import com.mojang.datafixers.util.Unit; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; @@ -26,21 +27,31 @@ public CompoundListCodec(final Codec keyCodec, final Codec elementCodec) { @Override public DataResult>, T>> decode(final DynamicOps ops, final T input) { return ops.getMapEntries(input).flatMap(map -> { - final AtomicReference>>> result = new AtomicReference<>(DataResult.success(ImmutableList.builder())); - final ImmutableMap.Builder errors = ImmutableMap.builder(); + final ImmutableList.Builder> read = ImmutableList.builder(); + final ImmutableMap.Builder failed = ImmutableMap.builder(); + + final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE)); map.accept((key, value) -> { final DataResult k = keyCodec.parse(ops, key); final DataResult v = elementCodec.parse(ops, value); - final DataResult> readEntry = k.ap2(v, Pair::new); + final DataResult> readEntry = k.apply2(Pair::new, v); - readEntry.error().ifPresent(e -> errors.put(key, value)); + readEntry.error().ifPresent(e -> failed.put(key, value)); - result.set(result.get().ap2(readEntry, ImmutableList.Builder::add)); + result.set(result.get().apply2((u, e) -> { + read.add(e); + return u; + }, readEntry)); }); - return result.get().map(builder -> Pair.of(builder.build(), ops.createMap(errors.build()))); + final ImmutableList> elements = read.build(); + final T errors = ops.createMap(failed.build()); + + final Pair>, T> pair = Pair.of(elements, errors); + + return result.get().map(unit -> pair).setPartial(pair); }); } diff --git a/src/main/java/com/mojang/serialization/codecs/ListCodec.java b/src/main/java/com/mojang/serialization/codecs/ListCodec.java index 1c0c3725..5f6eff75 100644 --- a/src/main/java/com/mojang/serialization/codecs/ListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/ListCodec.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; +import com.mojang.datafixers.util.Unit; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; @@ -34,23 +35,26 @@ public DataResult encode(final List input, final DynamicOps ops, fi @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { return ops.getList(input).flatMap(stream -> { - final AtomicReference, ImmutableList.Builder>>> result = - new AtomicReference<>(DataResult.success(Pair.of(ImmutableList.builder(), ImmutableList.builder()))); + final ImmutableList.Builder read = ImmutableList.builder(); + final ImmutableList.Builder failed = ImmutableList.builder(); + final AtomicReference> result = + new AtomicReference<>(DataResult.success(Unit.INSTANCE)); - stream.accept(t -> - result.set(result.get().flatMap(pair -> { - final DataResult> read = elementCodec.decode(ops, t); + stream.accept(t -> { + final DataResult> element = elementCodec.decode(ops, t); + element.error().ifPresent(e -> failed.add(t)); + result.set(result.get().apply2((r, v) -> { + read.add(v.getFirst()); + return r; + }, element)); + }); - read.error().ifPresent(e -> pair.getSecond().add(t)); + final ImmutableList elements = read.build(); + final T errors = ops.createList(failed.build().stream()); - return read.map(value -> { - pair.getFirst().add(value.getFirst()); - return pair; - }); - })) - ); + final Pair, T> pair = Pair.of(elements, errors); - return result.get().map(pair -> Pair.of(pair.getFirst().build(), ops.createList(pair.getSecond().build().stream()))); + return result.get().map(unit -> pair).setPartial(pair); }); } diff --git a/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java index 1e1aefe7..404d3b06 100644 --- a/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java @@ -2,7 +2,10 @@ // Licensed under the MIT license. package com.mojang.serialization.codecs; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.util.Pair; +import com.mojang.datafixers.util.Unit; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; @@ -34,15 +37,27 @@ public Stream keys(final DynamicOps ops) { @Override public DataResult> decode(final DynamicOps ops, final MapLike input) { - final AtomicReference>> result = new AtomicReference<>(DataResult.success(ImmutableMap.builder())); + final ImmutableMap.Builder read = ImmutableMap.builder(); + final ImmutableList.Builder> failed = ImmutableList.builder(); + final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE)); input.entries().forEach(pair -> { final DataResult k = keyCodec.parse(ops, pair.getFirst()); final DataResult v = elementCodec.parse(ops, pair.getSecond()); - result.set(DataResult.unbox(DataResult.instance().apply3(ImmutableMap.Builder::put, result.get(), k, v))); + + final DataResult> entry = k.apply2(Pair::of, v); + entry.error().ifPresent(e -> failed.add(pair)); + + result.set(result.get().apply2((u, p) -> { + read.put(p.getFirst(), p.getSecond()); + return u; + }, entry)); }); - return result.get().map(ImmutableMap.Builder::build); + final Map elements = read.build(); + final T errors = ops.createMap(failed.build().stream()); + + return result.get().map(unit -> elements).setPartial(elements).mapError(e -> e + " missed input: " + errors); } @Override From 4d4587eeaf734db3a6c9a94a31cadf247745f199 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 4 May 2020 10:38:19 +0200 Subject: [PATCH 61/96] Made KeyDispatchCodec more robust for non-map codecs, added PairMapCodec and EitherMapCodec. --- .../java/com/mojang/serialization/Codec.java | 50 ++++++++++++++ .../serialization/codecs/EitherMapCodec.java | 67 +++++++++++++++++++ .../codecs/KeyDispatchCodec.java | 33 ++++++--- .../serialization/codecs/PairMapCodec.java | 64 ++++++++++++++++++ 4 files changed, 204 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/codecs/EitherMapCodec.java create mode 100644 src/main/java/com/mojang/serialization/codecs/PairMapCodec.java diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 37e9e3e3..22ca2ff1 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -8,10 +8,12 @@ import com.mojang.datafixers.util.Unit; import com.mojang.serialization.codecs.CompoundListCodec; import com.mojang.serialization.codecs.EitherCodec; +import com.mojang.serialization.codecs.EitherMapCodec; import com.mojang.serialization.codecs.KeyDispatchCodec; import com.mojang.serialization.codecs.ListCodec; import com.mojang.serialization.codecs.OptionalFieldCodec; import com.mojang.serialization.codecs.PairCodec; +import com.mojang.serialization.codecs.PairMapCodec; import com.mojang.serialization.codecs.PrimitiveCodec; import com.mojang.serialization.codecs.SimpleMapCodec; @@ -24,6 +26,7 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.LongStream; +import java.util.stream.Stream; public interface Codec extends Encoder, Decoder { static Codec of(final Decoder decoder) { @@ -53,14 +56,56 @@ public String toString() { }; } + static MapCodec of(final MapEncoder encoder, final MapDecoder decoder) { + return of(encoder, decoder, "MapCodec[" + encoder + " " + decoder + "]"); + } + + static MapCodec of(final MapEncoder encoder, final MapDecoder decoder, final String name) { + return new MapCodec() { + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat(encoder.keys(ops), decoder.keys(ops)); + } + + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return decoder.decode(ops, input); + } + + @Override + public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { + return encoder.encode(input, ops, prefix); + } + + @Override + public String toString() { + return name; + } + }; + } + static Codec> pair(final Codec first, final Codec second) { + if (first instanceof MapCodec && second instanceof MapCodec) { + return new PairMapCodec<>(((MapCodec) first), ((MapCodec) second)); + } return new PairCodec<>(first, second); } static Codec> either(final Codec first, final Codec second) { + if (first instanceof MapCodec && second instanceof MapCodec) { + return new EitherMapCodec<>(((MapCodec) first), ((MapCodec) second)); + } return new EitherCodec<>(first, second); } + static MapCodec> mapPair(final MapCodec first, final MapCodec second) { + return new PairMapCodec<>(first, second); + } + + static MapCodec> mapEither(final MapCodec first, final MapCodec second) { + return new EitherMapCodec<>(first, second); + } + static Codec> list(final Codec elementCodec) { return new ListCodec<>(elementCodec); } @@ -481,6 +526,11 @@ public DataResult encode(final Dynamic input, final DynamicOps ops, ); }); } + + @Override + public String toString() { + return "saving"; + } }; Codec EMPTY = Codec.of(Encoder.empty(), Decoder.unit(Unit.INSTANCE)); diff --git a/src/main/java/com/mojang/serialization/codecs/EitherMapCodec.java b/src/main/java/com/mojang/serialization/codecs/EitherMapCodec.java new file mode 100644 index 00000000..a149a5d4 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/EitherMapCodec.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; + +import java.util.Objects; +import java.util.stream.Stream; + +public final class EitherMapCodec extends MapCodec> { + private final MapCodec first; + private final MapCodec second; + + public EitherMapCodec(final MapCodec first, final MapCodec second) { + this.first = first; + this.second = second; + } + + @Override + public DataResult> decode(final DynamicOps ops, final MapLike input) { + final DataResult> firstRead = first.decode(ops, input).map(Either::left); + if (firstRead.result().isPresent()) { + return firstRead; + } + return second.decode(ops, input).map(Either::right); + } + + @Override + public RecordBuilder encode(final Either input, final DynamicOps ops, final RecordBuilder prefix) { + return input.map( + value1 -> first.encode(value1, ops, prefix), + value2 -> second.encode(value2, ops, prefix) + ); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final EitherMapCodec eitherCodec = ((EitherMapCodec) o); + return Objects.equals(first, eitherCodec.first) && Objects.equals(second, eitherCodec.second); + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + + @Override + public String toString() { + return "EitherMapCodec[" + first + ", " + second + ']'; + } + + @Override + public Stream keys(final DynamicOps ops) { + return null; + } +} diff --git a/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java b/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java index 26cf9e0c..731cfe6f 100644 --- a/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java @@ -1,5 +1,6 @@ package com.mojang.serialization.codecs; +import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Decoder; @@ -47,14 +48,17 @@ public DataResult decode(final DynamicOps ops, final MapLike input) return keyCodec.decode(ops, elementName).flatMap(type -> { final DataResult> elementDecoder = decoder.apply(type.getFirst()); return elementDecoder.flatMap(c -> { - if (c instanceof MapDecoder && !ops.compressMaps()) { - return ((MapDecoder) c).decode(ops, input).map(Function.identity()); + if (ops.compressMaps()) { + final T value = input.get(ops.createString(valueKey)); + if (value == null) { + return DataResult.error("Input does not have a \"value\" entry: " + input); + } + return c.parse(ops, value).map(Function.identity()); } - final T value = input.get(ops.createString(valueKey)); - if (value == null) { - return DataResult.error("Input does not have a \"value\" entry: " + input); + if (c instanceof MapDecoder) { + return ((MapDecoder) c).decode(ops, input).map(Function.identity()); } - return c.parse(ops, value).map(Function.identity()); + return c.decode(ops, ops.createMap(input.entries())).map(Pair::getFirst); }); }); } @@ -68,13 +72,22 @@ public RecordBuilder encode(final V input, final DynamicOps ops, final } final Encoder c = elementEncoder.result().get(); - if (c instanceof MapEncoder && !ops.compressMaps()) { + if (ops.compressMaps()) { + return prefix + .add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))) + .add(valueKey, c.encodeStart(ops, input)); + } + if (c instanceof MapEncoder) { return ((MapEncoder) c).encode(input, ops, prefix) .add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))); } - return prefix - .add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))) - .add(valueKey, c.encodeStart(ops, input)); + + prefix.add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))); + final DataResult> element = c.encodeStart(ops, input).flatMap(ops::getMap); + return element.map(map -> { + map.entries().forEach(pair -> prefix.add(pair.getFirst(), pair.getSecond())); + return prefix; + }).result().orElseGet(() -> prefix.withErrorsFrom(element)); } @Override diff --git a/src/main/java/com/mojang/serialization/codecs/PairMapCodec.java b/src/main/java/com/mojang/serialization/codecs/PairMapCodec.java new file mode 100644 index 00000000..33db3ce6 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/PairMapCodec.java @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; + +import java.util.Objects; +import java.util.stream.Stream; + +public final class PairMapCodec extends MapCodec> { + private final MapCodec first; + private final MapCodec second; + + public PairMapCodec(final MapCodec first, final MapCodec second) { + this.first = first; + this.second = second; + } + + @Override + public DataResult> decode(final DynamicOps ops, final MapLike input) { + return first.decode(ops, input).flatMap(p1 -> + second.decode(ops, input).map(p2 -> + Pair.of(p1, p2) + ) + ); + } + + @Override + public RecordBuilder encode(final Pair input, final DynamicOps ops, final RecordBuilder prefix) { + return second.encode(input.getSecond(), ops, first.encode(input.getFirst(), ops, prefix)); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final PairMapCodec pairCodec = (PairMapCodec) o; + return Objects.equals(first, pairCodec.first) && Objects.equals(second, pairCodec.second); + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + + @Override + public String toString() { + return "PairMapCodec[" + first + ", " + second + ']'; + } + + @Override + public Stream keys(final DynamicOps ops) { + return Stream.concat(first.keys(ops), second.keys(ops)); + } +} From 27b00acd2d971cc4de049b54e1890ae9df1a77cf Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 4 May 2020 13:04:09 +0200 Subject: [PATCH 62/96] Pair codecs encode second element first, to make typed entries override the remainder --- src/main/java/com/mojang/serialization/codecs/PairCodec.java | 2 +- src/main/java/com/mojang/serialization/codecs/PairMapCodec.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/mojang/serialization/codecs/PairCodec.java b/src/main/java/com/mojang/serialization/codecs/PairCodec.java index 48453ce1..b03cddaa 100644 --- a/src/main/java/com/mojang/serialization/codecs/PairCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/PairCodec.java @@ -29,7 +29,7 @@ public DataResult, T>> decode(final DynamicOps ops, final @Override public DataResult encode(final Pair value, final DynamicOps ops, final T rest) { - return first.encode(value.getFirst(), ops, rest).flatMap(f -> second.encode(value.getSecond(), ops, f)); + return second.encode(value.getSecond(), ops, rest).flatMap(f -> first.encode(value.getFirst(), ops, f)); } @Override diff --git a/src/main/java/com/mojang/serialization/codecs/PairMapCodec.java b/src/main/java/com/mojang/serialization/codecs/PairMapCodec.java index 33db3ce6..65a84c16 100644 --- a/src/main/java/com/mojang/serialization/codecs/PairMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/PairMapCodec.java @@ -32,7 +32,7 @@ public DataResult> decode(final DynamicOps ops, final MapLike< @Override public RecordBuilder encode(final Pair input, final DynamicOps ops, final RecordBuilder prefix) { - return second.encode(input.getSecond(), ops, first.encode(input.getFirst(), ops, prefix)); + return first.encode(input.getFirst(), ops, second.encode(input.getSecond(), ops, prefix)); } @Override From 658c05f67c1fc9519181dc073097524a76b33664 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 5 May 2020 15:21:54 +0200 Subject: [PATCH 63/96] Lifecycle tracking in codecs and DataResult --- .../datafixers/types/templates/Hook.java | 5 +- .../datafixers/types/templates/Named.java | 5 +- .../types/templates/RecursivePoint.java | 5 +- .../java/com/mojang/serialization/Codec.java | 54 ++++++++- .../com/mojang/serialization/DataResult.java | 105 ++++++++++++------ .../com/mojang/serialization/Decoder.java | 15 +++ .../com/mojang/serialization/Encoder.java | 15 +++ .../com/mojang/serialization/Lifecycle.java | 58 ++++++++++ .../com/mojang/serialization/MapCodec.java | 45 +++++++- .../com/mojang/serialization/MapDecoder.java | 24 +++- .../com/mojang/serialization/MapEncoder.java | 21 ++++ .../mojang/serialization/RecordBuilder.java | 8 ++ .../codecs/CompoundListCodec.java | 3 +- .../serialization/codecs/FieldDecoder.java | 2 +- .../codecs/RecordCodecBuilder.java | 25 +++++ 15 files changed, 334 insertions(+), 56 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/Lifecycle.java diff --git a/src/main/java/com/mojang/datafixers/types/templates/Hook.java b/src/main/java/com/mojang/datafixers/types/templates/Hook.java index e81f9c90..2dc1bd77 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Hook.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Hook.java @@ -16,6 +16,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Lifecycle; import javax.annotation.Nullable; import java.util.Objects; @@ -114,12 +115,12 @@ protected Codec buildCodec() { return new Codec() { @Override public DataResult> decode(final DynamicOps ops, final T input) { - return delegate.codec().decode(ops, preRead.apply(ops, input)); + return delegate.codec().decode(ops, preRead.apply(ops, input)).setLifecycle(Lifecycle.experimental()); } @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return delegate.codec().encode(input, ops, prefix).map(v -> postWrite.apply(ops, v)); + return delegate.codec().encode(input, ops, prefix).map(v -> postWrite.apply(ops, v)).setLifecycle(Lifecycle.experimental()); } }; } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Named.java b/src/main/java/com/mojang/datafixers/types/templates/Named.java index bd5441fd..eee00e4c 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Named.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Named.java @@ -21,6 +21,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Lifecycle; import javax.annotation.Nullable; import java.util.Objects; @@ -143,7 +144,7 @@ protected Codec> buildCodec() { return new Codec>() { @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { - return element.codec().decode(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(name, v))); + return element.codec().decode(ops, input).map(vo -> vo.mapFirst(v -> Pair.of(name, v))).setLifecycle(Lifecycle.experimental()); } @Override @@ -151,7 +152,7 @@ public DataResult encode(final Pair input, final DynamicOps if (!Objects.equals(input.getFirst(), name)) { return DataResult.error("Named type name doesn't match: expected: " + name + ", got: " + input.getFirst(), prefix); } - return element.codec().encode(input.getSecond(), ops, prefix); + return element.codec().encode(input.getSecond(), ops, prefix).setLifecycle(Lifecycle.experimental()); } }; } diff --git a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java index 8c47364e..d20dd60c 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java +++ b/src/main/java/com/mojang/datafixers/types/templates/RecursivePoint.java @@ -18,6 +18,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Lifecycle; import org.apache.commons.lang3.ObjectUtils; import javax.annotation.Nullable; @@ -144,12 +145,12 @@ protected Codec buildCodec() { return new Codec() { @Override public DataResult> decode(final DynamicOps ops, final T input) { - return unfold().codec().decode(ops, input); + return unfold().codec().decode(ops, input).setLifecycle(Lifecycle.experimental()); } @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return unfold().codec().encode(input, ops, prefix); + return unfold().codec().encode(input, ops, prefix).setLifecycle(Lifecycle.experimental()); } }; } diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 22ca2ff1..e4272ea4 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -29,6 +29,35 @@ import java.util.stream.Stream; public interface Codec extends Encoder, Decoder { + @Override + default Codec withLifecycle(final Lifecycle lifecycle) { + final Codec self = this; + return new Codec() { + @Override + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return self.encode(input, ops, prefix).setLifecycle(lifecycle); + } + + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return self.decode(ops, input).setLifecycle(lifecycle); + } + + @Override + public String toString() { + return self.toString(); + } + }; + } + + default Codec stable() { + return withLifecycle(Lifecycle.stable()); + } + + default Codec deprecated(final int since) { + return withLifecycle(Lifecycle.deprecated(since)); + } + static Codec of(final Decoder decoder) { return of(Encoder.of(), decoder); } @@ -284,11 +313,24 @@ default MapCodec dispatch(final Function type, fi } default MapCodec dispatch(final String typeKey, final Function type, final Function> codec) { - return partialDispatchCodec(typeKey, type.andThen(DataResult::success), codec); + return partialDispatch(typeKey, type.andThen(DataResult::success), codec.andThen(DataResult::success)); + } + + default MapCodec dispatchStable(final Function type, final Function> codec) { + return dispatchStable("type", type, codec); + } + + default MapCodec dispatchStable(final String typeKey, final Function type, final Function> codec) { + return partialDispatch(typeKey, e -> DataResult.success(type.apply(e), Lifecycle.stable()), a -> DataResult.success(codec.apply(a), Lifecycle.stable())); + } + + default MapCodec dispatchDeprecated(final int since, final Function type, final Function> codec) { + return dispatchDeprecated(since, "type", type, codec); } - default MapCodec partialDispatchCodec(final String typeKey, final Function> type, final Function> codec) { - return partialDispatch(typeKey, type, codec.andThen(DataResult::success)); + default MapCodec dispatchDeprecated(final int since, final String typeKey, final Function type, final Function> codec) { + final Lifecycle deprecated = Lifecycle.deprecated(since); + return partialDispatch(typeKey, e -> DataResult.success(type.apply(e), deprecated), a -> DataResult.success(codec.apply(a), deprecated)); } default MapCodec partialDispatch(final String typeKey, final Function> type, final Function>> codec) { @@ -509,20 +551,20 @@ public DataResult, T>> decode(final DynamicOps ops, final public DataResult encode(final Dynamic input, final DynamicOps ops, final T prefix) { if (input.getValue() == input.getOps().empty()) { // nothing to merge, return rest - return DataResult.success(prefix); + return DataResult.success(prefix, Lifecycle.experimental()); } final T casted = input.convert(ops).getValue(); if (prefix == ops.empty()) { // no need to merge anything, return the old value - return DataResult.success(casted); + return DataResult.success(casted, Lifecycle.experimental()); } final DataResult toMap = ops.getMap(casted).flatMap(map -> ops.mergeToMap(prefix, map)); return toMap.result().map(DataResult::success).orElseGet(() -> { final DataResult toList = ops.getStream(casted).flatMap(stream -> ops.mergeToList(prefix, stream.collect(Collectors.toList()))); return toList.result().map(DataResult::success).orElseGet(() -> - DataResult.error("Don't know how to merge " + prefix + " and " + casted, prefix) + DataResult.error("Don't know how to merge " + prefix + " and " + casted, prefix, Lifecycle.experimental()) ); }); } diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 6ca3139d..1f5179ad 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -15,6 +15,10 @@ import java.util.function.Function; import java.util.function.Supplier; +/** + * Represents either a successful operation, or a partial operation with an error message and a partial result (if available) + * Also stores an additional lifecycle marker (monoidal) + */ public class DataResult implements App { public static final class Mu implements K1 {} @@ -23,25 +27,39 @@ public static DataResult unbox(final App box) { } private final Either> result; + private final Lifecycle lifecycle; public static DataResult success(final R result) { - return new DataResult<>(Either.left(result)); + return success(result, Lifecycle.experimental()); } public static DataResult error(final String message, final R partialResult) { - return new DataResult<>(Either.right(new DynamicException<>(message, Optional.of(partialResult)))); + return error(message, partialResult, Lifecycle.experimental()); } public static DataResult error(final String message) { - return new DataResult<>(Either.right(new DynamicException<>(message, Optional.empty()))); + return error(message, Lifecycle.experimental()); } - public static DataResult create(final Either> result) { - return new DataResult<>(result); + public static DataResult success(final R result, final Lifecycle experimental) { + return new DataResult<>(Either.left(result), experimental); } - private DataResult(final Either> result) { + public static DataResult error(final String message, final R partialResult, final Lifecycle lifecycle) { + return new DataResult<>(Either.right(new DynamicException<>(message, Optional.of(partialResult))), lifecycle); + } + + public static DataResult error(final String message, final Lifecycle lifecycle) { + return new DataResult<>(Either.right(new DynamicException<>(message, Optional.empty())), lifecycle); + } + + private static DataResult create(final Either> result, final Lifecycle lifecycle) { + return new DataResult<>(result, lifecycle); + } + + private DataResult(final Either> result, final Lifecycle lifecycle) { this.result = result; + this.lifecycle = lifecycle; } public Either> get() { @@ -52,6 +70,10 @@ public Optional result() { return result.left(); } + public Lifecycle lifecycle() { + return lifecycle; + } + public Optional resultOrPartial(final Consumer onError) { return result.map( Optional::of, @@ -83,17 +105,17 @@ public DataResult map(final Function function) { return create(result.mapBoth( function, r -> new DynamicException<>(r.message, r.partialResult.map(function)) - )); + ), lifecycle); } public DataResult promotePartial(final Consumer onError) { return result.map( - DataResult::success, + r -> new DataResult<>(Either.left(r), lifecycle), r -> { onError.accept(r.message); return r.partialResult - .map(DataResult::success) - .orElseGet(() -> create(Either.right(r))); + .map(pr -> new DataResult<>(Either.left(pr), lifecycle)) + .orElseGet(() -> create(Either.right(r), lifecycle)); } ); } @@ -102,18 +124,23 @@ public DataResult promotePartial(final Consumer onError) { * Applies the function to either full or partial result, in case of partial concatenates errors. */ public DataResult flatMap(final Function> function) { - return create(result.map( - l -> function.apply(l).get(), - r -> Either.right(r.partialResult - .map(value -> function.apply(value).get().map( - l2 -> new DynamicException<>(r.message, Optional.of(l2)), - r2 -> new DynamicException<>(r.message + "; " + r2.message, r2.partialResult) - )) + return result.map( + l -> { + final DataResult second = function.apply(l); + return create(second.get(), lifecycle.add(second.lifecycle)); + }, + r -> r.partialResult + .map(value -> { + final DataResult second = function.apply(value); + return create(Either.right(second.get().map( + l2 -> new DynamicException<>(r.message, Optional.of(l2)), + r2 -> new DynamicException<>(r.message + "; " + r2.message, r2.partialResult) + )), lifecycle.add(second.lifecycle)); + }) .orElseGet( - () -> new DynamicException<>(r.message, Optional.empty()) + () -> create(Either.right(new DynamicException<>(r.message, Optional.empty())), lifecycle) ) - ) - )); + ); } public DataResult ap(final DataResult> functionResult) { @@ -129,7 +156,7 @@ public DataResult ap(final DataResult> functionResult) argError.partialResult.flatMap(a -> funcError.partialResult.map(f -> f.apply(a))) ) )) - )); + ), lifecycle.add(functionResult.lifecycle)); } public DataResult apply2(final BiFunction function, final DataResult second) { @@ -141,15 +168,23 @@ public DataResult apply3(final Function3 function, } public DataResult setPartial(final Supplier partial) { - return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial.get())))); + return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial.get()))), lifecycle); } public DataResult setPartial(final R partial) { - return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial)))); + return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial))), lifecycle); } public DataResult mapError(final Function function) { - return create(result.mapRight(r -> new DynamicException<>(function.apply(r.message), r.partialResult))); + return create(result.mapRight(r -> new DynamicException<>(function.apply(r.message), r.partialResult)), lifecycle); + } + + public DataResult setLifecycle(final Lifecycle lifecycle) { + return create(result, lifecycle); + } + + public DataResult addLifecycle(final Lifecycle lifecycle) { + return create(result, this.lifecycle.add(lifecycle)); } public static Instance instance() { @@ -265,12 +300,10 @@ public App ap2(final App(Either.left(fr.result.left().get().apply( + ra.result.left().get(), + rb.result.left().get() + )), fr.lifecycle.add(ra.lifecycle).add(rb.lifecycle)); } return Applicative.super.ap2(func, a, b); @@ -288,13 +321,11 @@ public App ap3(final App(Either.left(fr.result.left().get().apply( + dr1.result.left().get(), + dr2.result.left().get(), + dr3.result.left().get() + )), fr.lifecycle.add(dr1.lifecycle).add(dr2.lifecycle).add(dr3.lifecycle)); } return Applicative.super.ap3(func, t1, t2, t3); diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 8d251873..13b1f4ac 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -87,6 +87,21 @@ public String toString() { }; } + default Decoder withLifecycle(final Lifecycle lifecycle) { + final Decoder self = this; + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return self.decode(ops, input).setLifecycle(lifecycle); + } + + @Override + public String toString() { + return self.toString(); + } + }; + } + static Decoder ofTerminal(final Terminal terminal) { return terminal.decoder().map(Function.identity()); } diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index db12b7bc..9a747090 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -48,6 +48,21 @@ public String toString() { }; } + default Encoder withLifecycle(final Lifecycle lifecycle) { + final Encoder self = this; + return new Encoder() { + @Override + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return self.encode(input, ops, prefix).setLifecycle(lifecycle); + } + + @Override + public String toString() { + return self.toString(); + } + }; + } + static Encoder of() { return new Encoder() { @Override diff --git a/src/main/java/com/mojang/serialization/Lifecycle.java b/src/main/java/com/mojang/serialization/Lifecycle.java new file mode 100644 index 00000000..632f2ab1 --- /dev/null +++ b/src/main/java/com/mojang/serialization/Lifecycle.java @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +public class Lifecycle { + private static final Lifecycle STABLE = new Lifecycle() { + @Override + public String toString() { + return "Stable"; + } + }; + private static final Lifecycle EXPERIMENTAL = new Lifecycle() { + @Override + public String toString() { + return "Experimental"; + } + }; + + private Lifecycle() { + } + + protected static final class Deprecated extends Lifecycle { + private final int since; + + public Deprecated(final int since) { + this.since = since; + } + + public int since() { + return since; + } + } + + public static Lifecycle experimental() { + return EXPERIMENTAL; + } + + public static Lifecycle stable() { + return STABLE; + } + + public static Lifecycle deprecated(final int since) { + return new Deprecated(since); + } + + public Lifecycle add(final Lifecycle other) { + if (this == EXPERIMENTAL || other == EXPERIMENTAL) { + return EXPERIMENTAL; + } + if (this instanceof Deprecated) { + if (other instanceof Deprecated) { + return new Deprecated(Math.min(((Deprecated) this).since, ((Deprecated) other).since)); + } + return this; + } + return STABLE; + } +} diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 19c02721..c5ac4ba2 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -45,6 +45,43 @@ public String toString() { }; } + @Override + public MapCodec withLifecycle(final Lifecycle lifecycle) { + final MapCodec self = this; + + return new MapCodec() { + @Override + public Stream keys(final DynamicOps ops) { + return self.keys(ops); + } + + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return self.decode(ops, input).setLifecycle(lifecycle); + } + + @Override + public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { + return self.encode(input, ops, prefix).setLifecycle(lifecycle); + } + + @Override + public String toString() { + return self.toString(); + } + }; + } + + @Override + public MapCodec stable() { + return withLifecycle(Lifecycle.stable()); + } + + @Override + public MapCodec deprecated(final int since) { + return withLifecycle(Lifecycle.deprecated(since)); + } + public MapCodec xmap(final Function to, final Function from) { return MapCodec.of(comap(from), map(to), toString() + "[comapped]"); } @@ -74,7 +111,7 @@ public Stream keys(final DynamicOps ops) { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { return codec.decode(ops, input).flatMap((O base) -> - splitter.apply(base).getSecond().decode(ops, input).map(e -> combiner.apply(base, e)) + splitter.apply(base).getSecond().decode(ops, input).map(e -> combiner.apply(base, e)).setLifecycle(Lifecycle.experimental()) ); } @@ -83,7 +120,7 @@ public RecordBuilder encode(final O input, final DynamicOps ops, final codec.encode(input, ops, prefix); final Pair> e = splitter.apply(input); e.getSecond().encode(e.getFirst(), ops, prefix); - return prefix; + return prefix.setLifecycle(Lifecycle.experimental()); } } @@ -123,7 +160,7 @@ public String toString() { } @Override - public Codec withDefault(final Consumer onError, final A value) { + public MapCodec withDefault(final Consumer onError, final A value) { return withDefault(DataFixUtils.consumerToFunction(onError), value); } @@ -148,7 +185,7 @@ public String toString() { } @Override - public Codec withDefault(final Consumer onError, final Supplier value) { + public MapCodec withDefault(final Consumer onError, final Supplier value) { return withDefault(DataFixUtils.consumerToFunction(onError), value); } diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index 01f62cfd..8d635991 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -50,7 +50,8 @@ public Stream> entries() { }; return decode(ops, map); } - return ops.getMap(input).flatMap(map -> decode(ops, map)); + // will use the lifecycle of decode + return ops.getMap(input).setLifecycle(Lifecycle.stable()).flatMap(map -> decode(ops, map)); } MapCompressor compressor(DynamicOps ops); @@ -103,6 +104,27 @@ public String toString() { }; } + @Override + default MapDecoder withLifecycle(final Lifecycle lifecycle) { + final MapDecoder self = this; + return new MapDecoder.Implementation() { + @Override + public Stream keys(final DynamicOps ops) { + return self.keys(ops); + } + + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return self.decode(ops, input).setLifecycle(lifecycle); + } + + @Override + public String toString() { + return self.toString(); + } + }; + } + abstract class Implementation implements MapDecoder { private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index c1b1da99..8ab18694 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -48,6 +48,27 @@ default DataResult encode(final A input, final DynamicOps ops, final T return encode(input, ops, compressedBuilder(ops)).build(prefix); } + @Override + default MapEncoder withLifecycle(final Lifecycle lifecycle) { + final MapEncoder self = this; + return new Implementation() { + @Override + public Stream keys(final DynamicOps ops) { + return self.keys(ops); + } + + @Override + public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { + return self.encode(input, ops, prefix).setLifecycle(lifecycle); + } + + @Override + public String toString() { + return self.toString(); + } + }; + } + abstract class Implementation implements MapEncoder { private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 41e8bb83..9b3e1e80 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -17,6 +17,8 @@ public interface RecordBuilder { RecordBuilder withErrorsFrom(final DataResult result); + RecordBuilder setLifecycle(Lifecycle lifecycle); + RecordBuilder mapError(Function onError); DataResult build(T prefix); @@ -116,6 +118,12 @@ public RecordBuilder withErrorsFrom(final DataResult result) { return this; } + @Override + public RecordBuilder setLifecycle(final Lifecycle lifecycle) { + builder = builder.setLifecycle(lifecycle); + return this; + } + @Override public RecordBuilder mapError(final Function onError) { builder = builder.mapError(onError); diff --git a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java index 387d0ac1..b1ba5eac 100644 --- a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java @@ -9,6 +9,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Lifecycle; import com.mojang.serialization.RecordBuilder; import java.util.List; @@ -30,7 +31,7 @@ public DataResult>, T>> decode(final DynamicOps ops, final ImmutableList.Builder> read = ImmutableList.builder(); final ImmutableMap.Builder failed = ImmutableMap.builder(); - final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE)); + final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE, Lifecycle.experimental())); map.accept((key, value) -> { final DataResult k = keyCodec.parse(ops, key); diff --git a/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java b/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java index 47d55a9a..6c0b9d4e 100644 --- a/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java +++ b/src/main/java/com/mojang/serialization/codecs/FieldDecoder.java @@ -11,7 +11,7 @@ import java.util.Objects; import java.util.stream.Stream; -public class FieldDecoder extends MapDecoder.Implementation { +public final class FieldDecoder extends MapDecoder.Implementation { protected final String name; private final Decoder elementCodec; diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index ee0259ba..dcbf2732 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -12,6 +12,7 @@ import com.mojang.serialization.Decoder; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Encoder; +import com.mojang.serialization.Lifecycle; import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapDecoder; import com.mojang.serialization.MapEncoder; @@ -56,6 +57,18 @@ public static RecordCodecBuilder point(final F instance) { return new RecordCodecBuilder<>(o -> instance, o -> Encoder.empty(), Decoder.unit(instance)); } + public static RecordCodecBuilder stable(final F instance) { + return point(instance, Lifecycle.stable()); + } + + public static RecordCodecBuilder deprecated(final F instance, final int since) { + return point(instance, Lifecycle.deprecated(since)); + } + + public static RecordCodecBuilder point(final F instance, final Lifecycle lifecycle) { + return new RecordCodecBuilder<>(o -> instance, o -> Encoder.empty().withLifecycle(lifecycle), Decoder.unit(instance).withLifecycle(lifecycle)); + } + public static MapCodec create(final Function, ? extends App, O>> builder) { return build(builder.apply(instance())); } @@ -112,6 +125,18 @@ public static final class Instance implements Applicative, Instance.Mu< private static final class Mu implements Applicative.Mu { } + public App, A> stable(final A a) { + return RecordCodecBuilder.stable(a); + } + + public App, A> deprecated(final A a, final int since) { + return RecordCodecBuilder.deprecated(a, since); + } + + public App, A> point(final A a, final Lifecycle lifecycle) { + return RecordCodecBuilder.point(a, lifecycle); + } + @Override public App, A> point(final A a) { return RecordCodecBuilder.point(a); From 96396bb340e02a7551f591c8f4e066932a9825fa Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Wed, 6 May 2020 12:54:50 +0200 Subject: [PATCH 64/96] Optional field with default value and different lifecycles helper --- .../java/com/mojang/serialization/Codec.java | 20 +++++++++++++ .../com/mojang/serialization/MapCodec.java | 6 ++++ .../com/mojang/serialization/MapDecoder.java | 21 ++++++++++++++ .../com/mojang/serialization/MapEncoder.java | 28 +++++++++++++++++++ 4 files changed, 75 insertions(+) diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index e4272ea4..27f2e07e 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -19,6 +19,7 @@ import java.nio.ByteBuffer; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; @@ -184,6 +185,25 @@ default MapCodec> optionalFieldOf(final String name) { return optionalField(name, this); } + default MapCodec optionalFieldOf(final String name, final A defaultValue) { + return optionalField(name, this).xmap( + o -> o.orElse(defaultValue), + a -> Objects.equals(a, defaultValue) ? Optional.empty() : Optional.of(a) + ); + } + + default MapCodec optionalFieldOf(final String name, final A defaultValue, final Lifecycle lifecycleOfDefault) { + return optionalFieldOf(name, Lifecycle.experimental(), defaultValue, lifecycleOfDefault); + } + + default MapCodec optionalFieldOf(final String name, final Lifecycle fieldLifecycle, final A defaultValue, final Lifecycle lifecycleOfDefault) { + // setting lifecycle to stable on the outside since it will be overriden by the passed parameters + return optionalField(name, this).stable().flatXmap( + o -> o.map(v-> DataResult.success(v, fieldLifecycle)).orElse(DataResult.success(defaultValue, lifecycleOfDefault)), + a -> Objects.equals(a, defaultValue) ? DataResult.success(Optional.empty(), lifecycleOfDefault) : DataResult.success(Optional.of(a), fieldLifecycle) + ); + } + interface ResultFunction { DataResult> apply(final DynamicOps ops, final T input, final DataResult> a); diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index c5ac4ba2..2299d6f8 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -82,10 +82,16 @@ public MapCodec deprecated(final int since) { return withLifecycle(Lifecycle.deprecated(since)); } + @Override public MapCodec xmap(final Function to, final Function from) { return MapCodec.of(comap(from), map(to), toString() + "[comapped]"); } + @Override + public MapCodec flatXmap(final Function> to, final Function> from) { + return Codec.of(flatComap(from), flatMap(to), toString() + "[flatXmapped]"); + } + public MapCodec dependent(final MapCodec initialInstance, final Function>> splitter, final BiFunction combiner) { return new Dependent(this, initialInstance, splitter, combiner); } diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index 8d635991..5a4aafdf 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -61,6 +61,27 @@ default DataResult> decode(final DynamicOps ops, final T input return compressedDecode(ops, input).map(r -> Pair.of(r, input)); } + @Override + default MapDecoder flatMap(final Function> function) { + final MapDecoder self = this; + return new Implementation() { + @Override + public Stream keys(final DynamicOps ops) { + return self.keys(ops); + } + + @Override + public DataResult decode(final DynamicOps ops, final MapLike input) { + return self.decode(ops, input).flatMap(b -> function.apply(b).map(Function.identity())); + } + + @Override + public String toString() { + return self.toString() + "[flatMapped]"; + } + }; + } + @Override default MapDecoder map(final Function function) { final MapDecoder self = this; diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index 8ab18694..caa333f0 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -43,6 +43,34 @@ public String toString() { }; } + @Override + default MapEncoder flatComap(final Function> function) { + final MapEncoder self = this; + return new MapEncoder.Implementation() { + @Override + public Stream keys(final DynamicOps ops) { + return self.keys(ops); + } + + @Override + public RecordBuilder encode(final B input, final DynamicOps ops, final RecordBuilder prefix) { + final DataResult aResult = function.apply(input); + final RecordBuilder builder = prefix.withErrorsFrom(aResult); + return aResult.map(r -> self.encode(r, ops, builder)).result().orElse(builder); + } + + @Override + public DataResult encode(final B input, final DynamicOps ops, final T prefix) { + return function.apply(input).flatMap(a -> self.encode(a, ops, prefix)); + } + + @Override + public String toString() { + return self.toString() + "[flatComapped]"; + } + }; + } + @Override default DataResult encode(final A input, final DynamicOps ops, final T prefix) { return encode(input, ops, compressedBuilder(ops)).build(prefix); From 21e277a6cff75f531964fd553884507b4633b265 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 7 May 2020 08:57:07 +0200 Subject: [PATCH 65/96] Marked more things stable --- src/main/java/com/mojang/serialization/DataResult.java | 6 ++++++ src/main/java/com/mojang/serialization/JsonOps.java | 8 ++++---- .../java/com/mojang/serialization/ListBuilder.java | 6 +++--- .../java/com/mojang/serialization/RecordBuilder.java | 10 +++++----- .../mojang/serialization/codecs/CompoundListCodec.java | 4 ++-- .../com/mojang/serialization/codecs/ListCodec.java | 7 ++++--- .../mojang/serialization/codecs/SimpleMapCodec.java | 8 +++++--- 7 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 1f5179ad..2fbdeedc 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -163,6 +163,12 @@ public DataResult apply2(final BiFunction function, final D return unbox(instance().apply2(function, this, second)); } + public DataResult apply2stable(final BiFunction function, final DataResult second) { + final Applicative instance = instance(); + final DataResult> f = unbox(instance.point(function)).setLifecycle(Lifecycle.stable()); + return unbox(instance.ap2(f, this, second)); + } + public DataResult apply3(final Function3 function, final DataResult second, final DataResult third) { return unbox(instance().apply3(function, this, second, third)); } diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 89981aad..f5a657e7 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -324,7 +324,7 @@ public ListBuilder listBuilder() { } private static final class ArrayBuilder implements ListBuilder { - private DataResult builder = DataResult.success(new JsonArray()); + private DataResult builder = DataResult.success(new JsonArray(), Lifecycle.stable()); @Override public DynamicOps ops() { @@ -342,7 +342,7 @@ public ListBuilder add(final JsonElement value) { @Override public ListBuilder add(final DataResult value) { - builder = builder.apply2((b, element) -> { + builder = builder.apply2stable((b, element) -> { b.add(element); return b; }, value); @@ -373,10 +373,10 @@ public DataResult build(final JsonElement prefix) { array.addAll(prefix.getAsJsonArray()); } array.addAll(b); - return DataResult.success(array); + return DataResult.success(array, Lifecycle.stable()); }); - builder = DataResult.success(new JsonArray()); + builder = DataResult.success(new JsonArray(), Lifecycle.stable()); return result; } } diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index 95082688..acc8f374 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -47,7 +47,7 @@ default ListBuilder addAll(final Iterable values, final Encoder enc final class Builder implements ListBuilder { private final DynamicOps ops; - private DataResult> builder = DataResult.success(ImmutableList.builder()); + private DataResult> builder = DataResult.success(ImmutableList.builder(), Lifecycle.stable()); public Builder(final DynamicOps ops) { this.ops = ops; @@ -66,7 +66,7 @@ public ListBuilder add(final T value) { @Override public ListBuilder add(final DataResult value) { - builder = builder.apply2(ImmutableList.Builder::add, value); + builder = builder.apply2stable(ImmutableList.Builder::add, value); return this; } @@ -85,7 +85,7 @@ public ListBuilder mapError(final Function onError) { @Override public DataResult build(final T prefix) { final DataResult result = builder.flatMap(b -> ops.mergeToList(prefix, b.build())); - builder = DataResult.success(ImmutableList.builder()); + builder = DataResult.success(ImmutableList.builder(), Lifecycle.stable()); return result; } } diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 9b3e1e80..e0a1bdc2 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -49,7 +49,7 @@ default RecordBuilder add(final String key, final E value, final Encoder< abstract class AbstractStringBuilder implements RecordBuilder { private final DynamicOps ops; - protected DataResult builder = DataResult.success(initBuilder()); + protected DataResult builder = DataResult.success(initBuilder(), Lifecycle.stable()); protected AbstractStringBuilder(final DynamicOps ops) { this.ops = ops; @@ -74,14 +74,14 @@ public RecordBuilder add(final String key, final T value) { @Override public RecordBuilder add(final String key, final DataResult value) { - builder = builder.apply2((b, v) -> append(key, v, b), value); + builder = builder.apply2stable((b, v) -> append(key, v, b), value); return this; } @Override public DataResult build(final T prefix) { final DataResult result = builder.flatMap(b -> build(b, prefix)); - builder = DataResult.success(initBuilder()); + builder = DataResult.success(initBuilder(), Lifecycle.stable()); return result; } @@ -151,13 +151,13 @@ public RecordBuilder add(final T key, final T value) { @Override public RecordBuilder add(final T key, final DataResult value) { - builder = builder.apply2((b, v) -> append(key, v, b), value); + builder = builder.apply2stable((b, v) -> append(key, v, b), value); return this; } @Override public RecordBuilder add(final DataResult key, final DataResult value) { - builder = builder.ap(key.apply2((k, v) -> b -> append(k, v, b), value)); + builder = builder.ap(key.apply2stable((k, v) -> b -> append(k, v, b), value)); return this; } } diff --git a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java index b1ba5eac..cba1ca34 100644 --- a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java @@ -37,11 +37,11 @@ public DataResult>, T>> decode(final DynamicOps ops, final DataResult k = keyCodec.parse(ops, key); final DataResult v = elementCodec.parse(ops, value); - final DataResult> readEntry = k.apply2(Pair::new, v); + final DataResult> readEntry = k.apply2stable(Pair::new, v); readEntry.error().ifPresent(e -> failed.put(key, value)); - result.set(result.get().apply2((u, e) -> { + result.set(result.get().apply2stable((u, e) -> { read.add(e); return u; }, readEntry)); diff --git a/src/main/java/com/mojang/serialization/codecs/ListCodec.java b/src/main/java/com/mojang/serialization/codecs/ListCodec.java index 5f6eff75..18c250e2 100644 --- a/src/main/java/com/mojang/serialization/codecs/ListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/ListCodec.java @@ -8,6 +8,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Lifecycle; import com.mojang.serialization.ListBuilder; import java.util.List; @@ -34,16 +35,16 @@ public DataResult encode(final List input, final DynamicOps ops, fi @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { - return ops.getList(input).flatMap(stream -> { + return ops.getList(input).setLifecycle(Lifecycle.stable()).flatMap(stream -> { final ImmutableList.Builder read = ImmutableList.builder(); final ImmutableList.Builder failed = ImmutableList.builder(); final AtomicReference> result = - new AtomicReference<>(DataResult.success(Unit.INSTANCE)); + new AtomicReference<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); stream.accept(t -> { final DataResult> element = elementCodec.decode(ops, t); element.error().ifPresent(e -> failed.add(t)); - result.set(result.get().apply2((r, v) -> { + result.set(result.get().apply2stable((r, v) -> { read.add(v.getFirst()); return r; }, element)); diff --git a/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java index 404d3b06..14e3bd8a 100644 --- a/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java @@ -10,6 +10,7 @@ import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Keyable; +import com.mojang.serialization.Lifecycle; import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapLike; import com.mojang.serialization.RecordBuilder; @@ -17,6 +18,7 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiFunction; import java.util.stream.Stream; public final class SimpleMapCodec extends MapCodec> { @@ -39,16 +41,16 @@ public Stream keys(final DynamicOps ops) { public DataResult> decode(final DynamicOps ops, final MapLike input) { final ImmutableMap.Builder read = ImmutableMap.builder(); final ImmutableList.Builder> failed = ImmutableList.builder(); - final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE)); + final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); input.entries().forEach(pair -> { final DataResult k = keyCodec.parse(ops, pair.getFirst()); final DataResult v = elementCodec.parse(ops, pair.getSecond()); - final DataResult> entry = k.apply2(Pair::of, v); + final DataResult> entry = k.apply2stable(Pair::of, v); entry.error().ifPresent(e -> failed.add(pair)); - result.set(result.get().apply2((u, p) -> { + result.set(result.get().apply2stable((u, p) -> { read.put(p.getFirst(), p.getSecond()); return u; }, entry)); From 85ccdf76cbe0469f9432da0ad8c599e5894b0ed7 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Thu, 7 May 2020 09:18:19 +0200 Subject: [PATCH 66/96] Added UnboundedMapCodec --- .../java/com/mojang/serialization/Codec.java | 5 ++ .../serialization/codecs/BaseMapCodec.java | 55 +++++++++++++++ .../serialization/codecs/SimpleMapCodec.java | 50 +++++--------- .../codecs/UnboundedMapCodec.java | 67 +++++++++++++++++++ 4 files changed, 144 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java create mode 100644 src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 27f2e07e..43795bb9 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -16,6 +16,7 @@ import com.mojang.serialization.codecs.PairMapCodec; import com.mojang.serialization.codecs.PrimitiveCodec; import com.mojang.serialization.codecs.SimpleMapCodec; +import com.mojang.serialization.codecs.UnboundedMapCodec; import java.nio.ByteBuffer; import java.util.List; @@ -148,6 +149,10 @@ static SimpleMapCodec simpleMap(final Codec keyCodec, final Code return new SimpleMapCodec<>(keyCodec, elementCodec, keys); } + static UnboundedMapCodec unboundedMap(final Codec keyCodec, final Codec elementCodec) { + return new UnboundedMapCodec<>(keyCodec, elementCodec); + } + static MapCodec> optionalField(final String name, final Codec elementCodec) { return new OptionalFieldCodec<>(name, elementCodec); } diff --git a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java new file mode 100644 index 00000000..696afb9b --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.util.Pair; +import com.mojang.datafixers.util.Unit; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Lifecycle; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +public interface BaseMapCodec extends Codec> { + + Codec keyCodec(); + + Codec elementCodec(); + + default DataResult> decode(final DynamicOps ops, final MapLike input) { + final ImmutableMap.Builder read = ImmutableMap.builder(); + final ImmutableList.Builder> failed = ImmutableList.builder(); + final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); + + input.entries().forEach(pair -> { + final DataResult k = keyCodec().parse(ops, pair.getFirst()); + final DataResult v = elementCodec().parse(ops, pair.getSecond()); + + final DataResult> entry = k.apply2stable(Pair::of, v); + entry.error().ifPresent(e -> failed.add(pair)); + + result.set(result.get().apply2stable((u, p) -> { + read.put(p.getFirst(), p.getSecond()); + return u; + }, entry)); + }); + + final Map elements = read.build(); + final T errors = ops.createMap(failed.build().stream()); + + return result.get().map(unit -> elements).setPartial(elements).mapError(e -> e + " missed input: " + errors); + } + + default RecordBuilder encode(final Map input, final DynamicOps ops, final RecordBuilder prefix) { + for (final Map.Entry entry : input.entrySet()) { + prefix.add(keyCodec().encodeStart(ops, entry.getKey()), elementCodec().encodeStart(ops, entry.getValue())); + } + return prefix; + } +} diff --git a/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java index 14e3bd8a..4f522dc4 100644 --- a/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java @@ -2,26 +2,22 @@ // Licensed under the MIT license. package com.mojang.serialization.codecs; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.mojang.datafixers.util.Pair; -import com.mojang.datafixers.util.Unit; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Keyable; -import com.mojang.serialization.Lifecycle; import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapLike; import com.mojang.serialization.RecordBuilder; import java.util.Map; import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BiFunction; import java.util.stream.Stream; -public final class SimpleMapCodec extends MapCodec> { +/** + * Key and value decoded independently, statically known set of keys + */ +public final class SimpleMapCodec extends MapCodec> implements BaseMapCodec { private final Codec keyCodec; private final Codec elementCodec; private final Keyable keys; @@ -33,41 +29,29 @@ public SimpleMapCodec(final Codec keyCodec, final Codec elementCodec, fina } @Override - public Stream keys(final DynamicOps ops) { - return keys.keys(ops); + public Codec keyCodec() { + return keyCodec; } @Override - public DataResult> decode(final DynamicOps ops, final MapLike input) { - final ImmutableMap.Builder read = ImmutableMap.builder(); - final ImmutableList.Builder> failed = ImmutableList.builder(); - final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); - - input.entries().forEach(pair -> { - final DataResult k = keyCodec.parse(ops, pair.getFirst()); - final DataResult v = elementCodec.parse(ops, pair.getSecond()); - - final DataResult> entry = k.apply2stable(Pair::of, v); - entry.error().ifPresent(e -> failed.add(pair)); + public Codec elementCodec() { + return elementCodec; + } - result.set(result.get().apply2stable((u, p) -> { - read.put(p.getFirst(), p.getSecond()); - return u; - }, entry)); - }); + @Override + public Stream keys(final DynamicOps ops) { + return keys.keys(ops); + } - final Map elements = read.build(); - final T errors = ops.createMap(failed.build().stream()); - return result.get().map(unit -> elements).setPartial(elements).mapError(e -> e + " missed input: " + errors); + @Override + public DataResult> decode(final DynamicOps ops, final MapLike input) { + return BaseMapCodec.super.decode(ops, input); } @Override public RecordBuilder encode(final Map input, final DynamicOps ops, final RecordBuilder prefix) { - for (final Map.Entry entry : input.entrySet()) { - prefix.add(keyCodec.encodeStart(ops, entry.getKey()), elementCodec.encodeStart(ops, entry.getValue())); - } - return prefix; + return BaseMapCodec.super.encode(input, ops, prefix); } @Override diff --git a/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java b/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java new file mode 100644 index 00000000..a40f0e19 --- /dev/null +++ b/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization.codecs; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Lifecycle; + +import java.util.Map; +import java.util.Objects; + +/** + * Key and value decoded independently, unknown set of keys + */ +public final class UnboundedMapCodec implements BaseMapCodec { + private final Codec keyCodec; + private final Codec elementCodec; + + public UnboundedMapCodec(final Codec keyCodec, final Codec elementCodec) { + this.keyCodec = keyCodec; + this.elementCodec = elementCodec; + } + + @Override + public Codec keyCodec() { + return keyCodec; + } + + @Override + public Codec elementCodec() { + return elementCodec; + } + + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + return ops.getMap(input).setLifecycle(Lifecycle.stable()).flatMap(map -> decode(ops, map)).map(r -> Pair.of(r, input)); + } + + @Override + public DataResult encode(final Map input, final DynamicOps ops, final T prefix) { + return encode(input, ops, ops.mapBuilder()).build(prefix); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final UnboundedMapCodec that = (UnboundedMapCodec) o; + return Objects.equals(keyCodec, that.keyCodec) && Objects.equals(elementCodec, that.elementCodec); + } + + @Override + public int hashCode() { + return Objects.hash(keyCodec, elementCodec); + } + + @Override + public String toString() { + return "UnboundedMapCodec[" + keyCodec + " -> " + elementCodec + ']'; + } +} From 2a675087107cf254c3d97bb976c8fb75e7c40410 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Fri, 8 May 2020 12:10:22 +0200 Subject: [PATCH 67/96] Fixed lifecycle addition bug --- src/main/java/com/mojang/serialization/Lifecycle.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/mojang/serialization/Lifecycle.java b/src/main/java/com/mojang/serialization/Lifecycle.java index 632f2ab1..8a12066d 100644 --- a/src/main/java/com/mojang/serialization/Lifecycle.java +++ b/src/main/java/com/mojang/serialization/Lifecycle.java @@ -53,6 +53,9 @@ public Lifecycle add(final Lifecycle other) { } return this; } + if (other instanceof Deprecated) { + return other; + } return STABLE; } } From 15d3282a0b95ab480dd8c5234abc1c03515416d4 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Fri, 8 May 2020 12:14:14 +0200 Subject: [PATCH 68/96] Slighly cleaner implementation of keys() in RecordCodecBuilder --- .../codecs/RecordCodecBuilder.java | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index dcbf2732..0749cbcc 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -225,7 +225,11 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final @Override public Stream keys(final DynamicOps ops) { - return Stream.concat(aEncoder.keys(ops), Stream.concat(bEncoder.keys(ops), fEncoder.keys(ops))); + return Stream.of( + fEncoder.keys(ops), + aEncoder.keys(ops), + bEncoder.keys(ops) + ).flatMap(Function.identity()); } @Override @@ -246,7 +250,11 @@ public DataResult decode(final DynamicOps ops, final MapLike input) @Override public Stream keys(final DynamicOps ops) { - return Stream.concat(fa.decoder.keys(ops), Stream.concat(fb.decoder.keys(ops), function.decoder.keys(ops))); + return Stream.of( + function.decoder.keys(ops), + fa.decoder.keys(ops), + fb.decoder.keys(ops) + ).flatMap(Function.identity()); } @Override @@ -291,10 +299,12 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final @Override public Stream keys(final DynamicOps ops) { - return Stream.concat( - Stream.concat(e1.keys(ops), e2.keys(ops)), - Stream.concat(e3.keys(ops), fEncoder.keys(ops)) - ); + return Stream.of( + fEncoder.keys(ops), + e1.keys(ops), + e2.keys(ops), + e3.keys(ops) + ).flatMap(Function.identity()); } @Override @@ -316,10 +326,12 @@ public DataResult decode(final DynamicOps ops, final MapLike input) @Override public Stream keys(final DynamicOps ops) { - return Stream.concat( - Stream.concat(f1.decoder.keys(ops), f2.decoder.keys(ops)), - Stream.concat(f3.decoder.keys(ops), function.decoder.keys(ops)) - ); + return Stream.of( + function.decoder.keys(ops), + f1.decoder.keys(ops), + f2.decoder.keys(ops), + f3.decoder.keys(ops) + ).flatMap(Function.identity()); } @Override @@ -369,13 +381,13 @@ public RecordBuilder encode(final R input, final DynamicOps ops, final @Override public Stream keys(final DynamicOps ops) { - return Stream.concat( - Stream.concat( - Stream.concat(e1.keys(ops), e2.keys(ops)), - Stream.concat(e3.keys(ops), e4.keys(ops)) - ), - fEncoder.keys(ops) - ); + return Stream.of( + fEncoder.keys(ops), + e1.keys(ops), + e2.keys(ops), + e3.keys(ops), + e4.keys(ops) + ).flatMap(Function.identity()); } @Override @@ -398,13 +410,13 @@ public DataResult decode(final DynamicOps ops, final MapLike input) @Override public Stream keys(final DynamicOps ops) { - return Stream.concat( - Stream.concat( - Stream.concat(f1.decoder.keys(ops), f2.decoder.keys(ops)), - Stream.concat(f3.decoder.keys(ops), f4.decoder.keys(ops)) - ), - function.decoder.keys(ops) - ); + return Stream.of( + function.decoder.keys(ops), + f1.decoder.keys(ops), + f2.decoder.keys(ops), + f3.decoder.keys(ops), + f4.decoder.keys(ops) + ).flatMap(Function.identity()); } @Override From d9def8e7612555ecb7b11826566ee24e2b859761 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 09:21:05 +0200 Subject: [PATCH 69/96] Split off generic products from Applicative, moved factories to Kind --- .../java/com/mojang/datafixers/Products.java | 781 ++++++++++++++++++ .../mojang/datafixers/kinds/Applicative.java | 704 ---------------- .../com/mojang/datafixers/kinds/Kind1.java | 66 ++ 3 files changed, 847 insertions(+), 704 deletions(-) create mode 100644 src/main/java/com/mojang/datafixers/Products.java diff --git a/src/main/java/com/mojang/datafixers/Products.java b/src/main/java/com/mojang/datafixers/Products.java new file mode 100644 index 00000000..ceba64cc --- /dev/null +++ b/src/main/java/com/mojang/datafixers/Products.java @@ -0,0 +1,781 @@ +package com.mojang.datafixers; + +import com.mojang.datafixers.kinds.App; +import com.mojang.datafixers.kinds.Applicative; +import com.mojang.datafixers.kinds.IdF; +import com.mojang.datafixers.kinds.K1; +import com.mojang.datafixers.util.Function10; +import com.mojang.datafixers.util.Function11; +import com.mojang.datafixers.util.Function12; +import com.mojang.datafixers.util.Function13; +import com.mojang.datafixers.util.Function14; +import com.mojang.datafixers.util.Function15; +import com.mojang.datafixers.util.Function16; +import com.mojang.datafixers.util.Function3; +import com.mojang.datafixers.util.Function4; +import com.mojang.datafixers.util.Function5; +import com.mojang.datafixers.util.Function6; +import com.mojang.datafixers.util.Function7; +import com.mojang.datafixers.util.Function8; +import com.mojang.datafixers.util.Function9; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface Products { + final class P1 { + private final App t1; + + public P1(final App t1) { + this.t1 = t1; + } + + public App t1() { + return t1; + } + + public P2 and(final App t2) { + return new P2<>(t1, t2); + } + + public P3 and(final P2 p) { + return new P3<>(t1, p.t1, p.t2); + } + + public P4 and(final P3 p) { + return new P4<>(t1, p.t1, p.t2, p.t3); + } + + public P5 and(final P4 p) { + return new P5<>(t1, p.t1, p.t2, p.t3, p.t4); + } + + public P6 and(final P5 p) { + return new P6<>(t1, p.t1, p.t2, p.t3, p.t4, p.t5); + } + + public P7 and(final P6 p) { + return new P7<>(t1, p.t1, p.t2, p.t3, p.t4, p.t5, p.t6); + } + + public P8 and(final P7 p) { + return new P8<>(t1, p.t1, p.t2, p.t3, p.t4, p.t5, p.t6, p.t7); + } + + public App apply(final Applicative instance, final Function function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap(function, t1); + } + } + + static P2 of(final T1 t1, final T2 t2) { + return new P2<>(IdF.create(t1), IdF.create(t2)); + } + + final class P2 { + private final App t1; + private final App t2; + + public P2(final App t1, final App t2) { + this.t1 = t1; + this.t2 = t2; + } + + public App t1() { + return t1; + } + + public App t2() { + return t2; + } + + public P3 and(final App t3) { + return new P3<>(t1, t2, t3); + } + + public P4 and(final P2 p) { + return new P4<>(t1, t2, p.t1, p.t2); + } + + public P5 and(final P3 p) { + return new P5<>(t1, t2, p.t1, p.t2, p.t3); + } + + public P6 and(final P4 p) { + return new P6<>(t1, t2, p.t1, p.t2, p.t3, p.t4); + } + + public P7 and(final P5 p) { + return new P7<>(t1, t2, p.t1, p.t2, p.t3, p.t4, p.t5); + } + + public P8 and(final P6 p) { + return new P8<>(t1, t2, p.t1, p.t2, p.t3, p.t4, p.t5, p.t6); + } + + public App apply(final Applicative instance, final BiFunction function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap2(function, t1, t2); + } + } + + final class P3 { + private final App t1; + private final App t2; + private final App t3; + + public P3(final App t1, final App t2, final App t3) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + } + + public App t1() { + return t1; + } + + public App t2() { + return t2; + } + + public App t3() { + return t3; + } + + public P4 and(final App t4) { + return new P4<>(t1, t2, t3, t4); + } + + public P5 and(final P2 p) { + return new P5<>(t1, t2, t3, p.t1, p.t2); + } + + public P6 and(final P3 p) { + return new P6<>(t1, t2, t3, p.t1, p.t2, p.t3); + } + + public P7 and(final P4 p) { + return new P7<>(t1, t2, t3, p.t1, p.t2, p.t3, p.t4); + } + + public P8 and(final P5 p) { + return new P8<>(t1, t2, t3, p.t1, p.t2, p.t3, p.t4, p.t5); + } + + public App apply(final Applicative instance, final Function3 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap3(function, t1, t2, t3); + } + } + + final class P4 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + + public P4(final App t1, final App t2, final App t3, final App t4) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + } + + public App t1() { + return t1; + } + + public App t2() { + return t2; + } + + public App t3() { + return t3; + } + + public App t4() { + return t4; + } + + public P5 and(final App t5) { + return new P5<>(t1, t2, t3, t4, t5); + } + + public P6 and(final P2 p) { + return new P6<>(t1, t2, t3, t4, p.t1, p.t2); + } + + public P7 and(final P3 p) { + return new P7<>(t1, t2, t3, t4, p.t1, p.t2, p.t3); + } + + public P8 and(final P4 p) { + return new P8<>(t1, t2, t3, t4, p.t1, p.t2, p.t3, p.t4); + } + + public App apply(final Applicative instance, final Function4 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap4(function, t1, t2, t3, t4); + } + } + + final class P5 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + + public P5(final App t1, final App t2, final App t3, final App t4, final App t5) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + } + + public App t1() { + return t1; + } + + public App t2() { + return t2; + } + + public App t3() { + return t3; + } + + public App t4() { + return t4; + } + + public App t5() { + return t5; + } + + public P6 and(final App t6) { + return new P6<>(t1, t2, t3, t4, t5, t6); + } + + public P7 and(final P2 p) { + return new P7<>(t1, t2, t3, t4, t5, p.t1, p.t2); + } + + public P8 and(final P3 p) { + return new P8<>(t1, t2, t3, t4, t5, p.t1, p.t2, p.t3); + } + + public App apply(final Applicative instance, final Function5 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap5(function, t1, t2, t3, t4, t5); + } + } + + final class P6 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + + public P6(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + } + + public App t1() { + return t1; + } + + public App t2() { + return t2; + } + + public App t3() { + return t3; + } + + public App t4() { + return t4; + } + + public App t5() { + return t5; + } + + public App t6() { + return t6; + } + + public P7 and(final App t7) { + return new P7<>(t1, t2, t3, t4, t5, t6, t7); + } + + public P8 and(final P2 p) { + return new P8<>(t1, t2, t3, t4, t5, t6, p.t1, p.t2); + } + + public App apply(final Applicative instance, final Function6 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap6(function, t1, t2, t3, t4, t5, t6); + } + } + + final class P7 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + + public P7(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + } + + public App t1() { + return t1; + } + + public App t2() { + return t2; + } + + public App t3() { + return t3; + } + + public App t4() { + return t4; + } + + public App t5() { + return t5; + } + + public App t6() { + return t6; + } + + public App t7() { + return t7; + } + + public P8 and(final App t8) { + return new P8<>(t1, t2, t3, t4, t5, t6, t7, t8); + } + + public App apply(final Applicative instance, final Function7 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap7(function, t1, t2, t3, t4, t5, t6, t7); + } + } + + final class P8 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + + public P8(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + } + + public App t1() { + return t1; + } + + public App t2() { + return t2; + } + + public App t3() { + return t3; + } + + public App t4() { + return t4; + } + + public App t5() { + return t5; + } + + public App t6() { + return t6; + } + + public App t7() { + return t7; + } + + public App t8() { + return t8; + } + + public App apply(final Applicative instance, final Function8 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap8(function, t1, t2, t3, t4, t5, t6, t7, t8); + } + } + + final class P9 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + + public P9(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + } + + public App apply(final Applicative instance, final Function9 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap9(function, t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + } + + final class P10 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + + public P10(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + } + + public App apply(final Applicative instance, final Function10 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap10(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + } + + final class P11 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + + public P11(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + } + + public App apply(final Applicative instance, final Function11 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap11(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + } + + final class P12 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + + public P12(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + } + + public App apply(final Applicative instance, final Function12 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap12(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + } + + final class P13 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + private final App t13; + + public P13(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + this.t13 = t13; + } + + public App apply(final Applicative instance, final Function13 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap13(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + } + + final class P14 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + private final App t13; + private final App t14; + + public P14(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + this.t13 = t13; + this.t14 = t14; + } + + public App apply(final Applicative instance, final Function14 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap14(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + } + + final class P15 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + private final App t13; + private final App t14; + private final App t15; + + public P15(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + this.t13 = t13; + this.t14 = t14; + this.t15 = t15; + } + + public App apply(final Applicative instance, final Function15 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap15(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + } + + final class P16 { + private final App t1; + private final App t2; + private final App t3; + private final App t4; + private final App t5; + private final App t6; + private final App t7; + private final App t8; + private final App t9; + private final App t10; + private final App t11; + private final App t12; + private final App t13; + private final App t14; + private final App t15; + private final App t16; + + public P16(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15, final App t16) { + this.t1 = t1; + this.t2 = t2; + this.t3 = t3; + this.t4 = t4; + this.t5 = t5; + this.t6 = t6; + this.t7 = t7; + this.t8 = t8; + this.t9 = t9; + this.t10 = t10; + this.t11 = t11; + this.t12 = t12; + this.t13 = t13; + this.t14 = t14; + this.t15 = t15; + this.t16 = t16; + } + + public App apply(final Applicative instance, final Function16 function) { + return apply(instance, instance.point(function)); + } + + public App apply(final Applicative instance, final App> function) { + return instance.ap16(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } + } +} diff --git a/src/main/java/com/mojang/datafixers/kinds/Applicative.java b/src/main/java/com/mojang/datafixers/kinds/Applicative.java index f5c5a712..3ed14fa3 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Applicative.java +++ b/src/main/java/com/mojang/datafixers/kinds/Applicative.java @@ -163,708 +163,4 @@ default App apply8(final Function8 App apply9(final Function9 func, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9) { return ap9(point(func), t1, t2, t3, t4, t5, t6, t7, t8, t9); } - - default P1 group(final App t1) { - return new P1<>(this, t1); - } - - default P2 group(final App t1, final App t2) { - return new P2<>(this, t1, t2); - } - - default P3 group(final App t1, final App t2, final App t3) { - return new P3<>(this, t1, t2, t3); - } - - default P4 group(final App t1, final App t2, final App t3, final App t4) { - return new P4<>(this, t1, t2, t3, t4); - } - - default P5 group(final App t1, final App t2, final App t3, final App t4, final App t5) { - return new P5<>(this, t1, t2, t3, t4, t5); - } - - default P6 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { - return new P6<>(this, t1, t2, t3, t4, t5, t6); - } - - default P7 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { - return new P7<>(this, t1, t2, t3, t4, t5, t6, t7); - } - - default P8 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { - return new P8<>(this, t1, t2, t3, t4, t5, t6, t7, t8); - } - - default P9 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9) { - return new P9<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9); - } - - default P10 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10) { - return new P10<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); - } - - default P11 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11) { - return new P11<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); - } - - default P12 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12) { - return new P12<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); - } - - default P13 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13) { - return new P13<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); - } - - default P14 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14) { - return new P14<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); - } - - default P15 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15) { - return new P15<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); - } - - default P16 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15, final App t16) { - return new P16<>(this, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); - } - - final class P1 { - private final Applicative instance; - private final App t1; - - private P1(final Applicative instance, final App t1) { - this.instance = instance; - this.t1 = t1; - } - - public P2 and(final App t2) { - return new P2<>(instance, t1, t2); - } - - public P3 and(final P2 p) { - return new P3<>(instance, t1, p.t1, p.t2); - } - - public P4 and(final P3 p) { - return new P4<>(instance, t1, p.t1, p.t2, p.t3); - } - - public P5 and(final P4 p) { - return new P5<>(instance, t1, p.t1, p.t2, p.t3, p.t4); - } - - public P6 and(final P5 p) { - return new P6<>(instance, t1, p.t1, p.t2, p.t3, p.t4, p.t5); - } - - public P7 and(final P6 p) { - return new P7<>(instance, t1, p.t1, p.t2, p.t3, p.t4, p.t5, p.t6); - } - - public P8 and(final P7 p) { - return new P8<>(instance, t1, p.t1, p.t2, p.t3, p.t4, p.t5, p.t6, p.t7); - } - - public App apply(final Function function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap(function, t1); - } - } - - final class P2 { - private final Applicative instance; - private final App t1; - private final App t2; - - private P2(final Applicative instance, final App t1, final App t2) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - } - - public P3 and(final App t3) { - return new P3<>(instance, t1, t2, t3); - } - - public P4 and(final P2 p) { - return new P4<>(instance, t1, t2, p.t1, p.t2); - } - - public P5 and(final P3 p) { - return new P5<>(instance, t1, t2, p.t1, p.t2, p.t3); - } - - public P6 and(final P4 p) { - return new P6<>(instance, t1, t2, p.t1, p.t2, p.t3, p.t4); - } - - public P7 and(final P5 p) { - return new P7<>(instance, t1, t2, p.t1, p.t2, p.t3, p.t4, p.t5); - } - - public P8 and(final P6 p) { - return new P8<>(instance, t1, t2, p.t1, p.t2, p.t3, p.t4, p.t5, p.t6); - } - - public App apply(final BiFunction function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap2(function, t1, t2); - } - } - - final class P3 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - - private P3(final Applicative instance, final App t1, final App t2, final App t3) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - } - - public P4 and(final App t4) { - return new P4<>(instance, t1, t2, t3, t4); - } - - public P5 and(final P2 p) { - return new P5<>(instance, t1, t2, t3, p.t1, p.t2); - } - - public P6 and(final P3 p) { - return new P6<>(instance, t1, t2, t3, p.t1, p.t2, p.t3); - } - - public P7 and(final P4 p) { - return new P7<>(instance, t1, t2, t3, p.t1, p.t2, p.t3, p.t4); - } - - public P8 and(final P5 p) { - return new P8<>(instance, t1, t2, t3, p.t1, p.t2, p.t3, p.t4, p.t5); - } - - public App apply(final Function3 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap3(function, t1, t2, t3); - } - } - - final class P4 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - - private P4(final Applicative instance, final App t1, final App t2, final App t3, final App t4) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - } - - public P5 and(final App t5) { - return new P5<>(instance, t1, t2, t3, t4, t5); - } - - public P6 and(final P2 p) { - return new P6<>(instance, t1, t2, t3, t4, p.t1, p.t2); - } - - public P7 and(final P3 p) { - return new P7<>(instance, t1, t2, t3, t4, p.t1, p.t2, p.t3); - } - - public P8 and(final P4 p) { - return new P8<>(instance, t1, t2, t3, t4, p.t1, p.t2, p.t3, p.t4); - } - - public App apply(final Function4 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap4(function, t1, t2, t3, t4); - } - } - - final class P5 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - - private P5(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - } - - public P6 and(final App t6) { - return new P6<>(instance, t1, t2, t3, t4, t5, t6); - } - - public P7 and(final P2 p) { - return new P7<>(instance, t1, t2, t3, t4, t5, p.t1, p.t2); - } - - public P8 and(final P3 p) { - return new P8<>(instance, t1, t2, t3, t4, t5, p.t1, p.t2, p.t3); - } - - public App apply(final Function5 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap5(function, t1, t2, t3, t4, t5); - } - } - - final class P6 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - - private P6(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - } - - public P7 and(final App t7) { - return new P7<>(instance, t1, t2, t3, t4, t5, t6, t7); - } - - public P8 and(final P2 p) { - return new P8<>(instance, t1, t2, t3, t4, t5, t6, p.t1, p.t2); - } - - public App apply(final Function6 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap6(function, t1, t2, t3, t4, t5, t6); - } - } - - final class P7 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - - private P7(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - } - - public P8 and(final App t8) { - return new P8<>(instance, t1, t2, t3, t4, t5, t6, t7, t8); - } - - public App apply(final Function7 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap7(function, t1, t2, t3, t4, t5, t6, t7); - } - } - - final class P8 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - private final App t8; - - private P8(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - this.t8 = t8; - } - - public App apply(final Function8 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap8(function, t1, t2, t3, t4, t5, t6, t7, t8); - } - } - - final class P9 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - private final App t8; - private final App t9; - - private P9(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - this.t8 = t8; - this.t9 = t9; - } - - public App apply(final Function9 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap9(function, t1, t2, t3, t4, t5, t6, t7, t8, t9); - } - } - - final class P10 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - private final App t8; - private final App t9; - private final App t10; - - private P10(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - this.t8 = t8; - this.t9 = t9; - this.t10 = t10; - } - - public App apply(final Function10 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap10(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); - } - } - - final class P11 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - private final App t8; - private final App t9; - private final App t10; - private final App t11; - - private P11(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - this.t8 = t8; - this.t9 = t9; - this.t10 = t10; - this.t11 = t11; - } - - public App apply(final Function11 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap11(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); - } - } - - final class P12 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - private final App t8; - private final App t9; - private final App t10; - private final App t11; - private final App t12; - - private P12(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - this.t8 = t8; - this.t9 = t9; - this.t10 = t10; - this.t11 = t11; - this.t12 = t12; - } - - public App apply(final Function12 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap12(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); - } - } - - final class P13 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - private final App t8; - private final App t9; - private final App t10; - private final App t11; - private final App t12; - private final App t13; - - private P13(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - this.t8 = t8; - this.t9 = t9; - this.t10 = t10; - this.t11 = t11; - this.t12 = t12; - this.t13 = t13; - } - - public App apply(final Function13 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap13(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); - } - } - - final class P14 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - private final App t8; - private final App t9; - private final App t10; - private final App t11; - private final App t12; - private final App t13; - private final App t14; - - private P14(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - this.t8 = t8; - this.t9 = t9; - this.t10 = t10; - this.t11 = t11; - this.t12 = t12; - this.t13 = t13; - this.t14 = t14; - } - - public App apply(final Function14 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap14(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); - } - } - - final class P15 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - private final App t8; - private final App t9; - private final App t10; - private final App t11; - private final App t12; - private final App t13; - private final App t14; - private final App t15; - - private P15(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - this.t8 = t8; - this.t9 = t9; - this.t10 = t10; - this.t11 = t11; - this.t12 = t12; - this.t13 = t13; - this.t14 = t14; - this.t15 = t15; - } - - public App apply(final Function15 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap15(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); - } - } - - final class P16 { - private final Applicative instance; - private final App t1; - private final App t2; - private final App t3; - private final App t4; - private final App t5; - private final App t6; - private final App t7; - private final App t8; - private final App t9; - private final App t10; - private final App t11; - private final App t12; - private final App t13; - private final App t14; - private final App t15; - private final App t16; - - private P16(final Applicative instance, final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15, final App t16) { - this.instance = instance; - this.t1 = t1; - this.t2 = t2; - this.t3 = t3; - this.t4 = t4; - this.t5 = t5; - this.t6 = t6; - this.t7 = t7; - this.t8 = t8; - this.t9 = t9; - this.t10 = t10; - this.t11 = t11; - this.t12 = t12; - this.t13 = t13; - this.t14 = t14; - this.t15 = t15; - this.t16 = t16; - } - - public App apply(final Function16 function) { - return apply(instance.point(function)); - } - - public App apply(final App> function) { - return instance.ap16(function, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); - } - } } diff --git a/src/main/java/com/mojang/datafixers/kinds/Kind1.java b/src/main/java/com/mojang/datafixers/kinds/Kind1.java index 1ecd910a..ec93205b 100644 --- a/src/main/java/com/mojang/datafixers/kinds/Kind1.java +++ b/src/main/java/com/mojang/datafixers/kinds/Kind1.java @@ -2,10 +2,76 @@ // Licensed under the MIT license. package com.mojang.datafixers.kinds; +import com.mojang.datafixers.Products; + public interface Kind1 extends App { static Kind1 unbox(final App proofBox) { return (Kind1) proofBox; } interface Mu extends K1 {} + + default Products.P1 group(final App t1) { + return new Products.P1<>(t1); + } + + default Products.P2 group(final App t1, final App t2) { + return new Products.P2<>(t1, t2); + } + + default Products.P3 group(final App t1, final App t2, final App t3) { + return new Products.P3<>(t1, t2, t3); + } + + default Products.P4 group(final App t1, final App t2, final App t3, final App t4) { + return new Products.P4<>(t1, t2, t3, t4); + } + + default Products.P5 group(final App t1, final App t2, final App t3, final App t4, final App t5) { + return new Products.P5<>(t1, t2, t3, t4, t5); + } + + default Products.P6 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6) { + return new Products.P6<>(t1, t2, t3, t4, t5, t6); + } + + default Products.P7 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7) { + return new Products.P7<>(t1, t2, t3, t4, t5, t6, t7); + } + + default Products.P8 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8) { + return new Products.P8<>(t1, t2, t3, t4, t5, t6, t7, t8); + } + + default Products.P9 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9) { + return new Products.P9<>(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + + default Products.P10 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10) { + return new Products.P10<>(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + + default Products.P11 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11) { + return new Products.P11<>(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + default Products.P12 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12) { + return new Products.P12<>(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); + } + + default Products.P13 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13) { + return new Products.P13<>(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); + } + + default Products.P14 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14) { + return new Products.P14<>(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); + } + + default Products.P15 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15) { + return new Products.P15<>(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); + } + + default Products.P16 group(final App t1, final App t2, final App t3, final App t4, final App t5, final App t6, final App t7, final App t8, final App t9, final App t10, final App t11, final App t12, final App t13, final App t14, final App t15, final App t16) { + return new Products.P16<>(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); + } } From 0a698556a5cd21a08cfb8d4703dd1306d2d98f55 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 9 May 2020 19:15:00 +0200 Subject: [PATCH 70/96] Made MapCodec not extend Codec anymore --- .../datafixers/types/constant/EmptyPart.java | 2 +- .../datafixers/types/templates/Tag.java | 2 +- .../types/templates/TaggedChoice.java | 4 +- .../java/com/mojang/serialization/Codec.java | 57 +++++++++++++------ .../com/mojang/serialization/Decoder.java | 5 -- .../com/mojang/serialization/Encoder.java | 5 -- .../com/mojang/serialization/JsonOps.java | 2 +- .../com/mojang/serialization/MapCodec.java | 55 ++++++++++++++---- .../com/mojang/serialization/MapDecoder.java | 21 ++++--- .../com/mojang/serialization/MapEncoder.java | 26 +++++---- .../serialization/codecs/BaseMapCodec.java | 2 +- .../codecs/KeyDispatchCodec.java | 10 ++-- .../codecs/RecordCodecBuilder.java | 6 +- .../codecs/UnboundedMapCodec.java | 2 +- 14 files changed, 128 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java index 997453fb..7b7740a3 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java @@ -33,6 +33,6 @@ public TypeTemplate buildTemplate() { @Override protected Codec buildCodec() { - return Codec.EMPTY; + return Codec.EMPTY.codec(); } } diff --git a/src/main/java/com/mojang/datafixers/types/templates/Tag.java b/src/main/java/com/mojang/datafixers/types/templates/Tag.java index e0589d03..cca93412 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/Tag.java +++ b/src/main/java/com/mojang/datafixers/types/templates/Tag.java @@ -170,7 +170,7 @@ public TypeTemplate buildTemplate() { @Override protected Codec buildCodec() { - return element.codec().fieldOf(name); + return element.codec().fieldOf(name).codec(); } @Override diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index c65d0e28..b9642c9c 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -188,13 +188,13 @@ public TypeTemplate buildTemplate() { @Override protected Codec> buildCodec() { - return new KeyDispatchCodec<>( + return new KeyDispatchCodec>( name, keyType.codec(), p -> DataResult.success(p.getFirst()), k -> getCodec(k).map(c -> c.map(v -> Pair.of(k, v))), this::encoder - ); + ).codec(); } private DataResult> getCodec(final K k) { diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 43795bb9..a81b680d 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -116,16 +116,10 @@ public String toString() { } static Codec> pair(final Codec first, final Codec second) { - if (first instanceof MapCodec && second instanceof MapCodec) { - return new PairMapCodec<>(((MapCodec) first), ((MapCodec) second)); - } return new PairCodec<>(first, second); } static Codec> either(final Codec first, final Codec second) { - if (first instanceof MapCodec && second instanceof MapCodec) { - return new EitherMapCodec<>(((MapCodec) first), ((MapCodec) second)); - } return new EitherCodec<>(first, second); } @@ -325,40 +319,69 @@ default Codec promotePartial(final Consumer onError) { return Codec.of(this, Decoder.super.promotePartial(onError)); } - static MapCodec unit(final A defaultValue) { + static Codec unit(final A defaultValue) { return unit(() -> defaultValue); } - static MapCodec unit(final Supplier defaultValue) { - return MapCodec.of(Encoder.empty(), Decoder.unit(defaultValue)); + static Codec unit(final Supplier defaultValue) { + return MapCodec.unit(defaultValue).codec(); } - default MapCodec dispatch(final Function type, final Function> codec) { + default Codec dispatch(final Function type, final Function> codec) { return dispatch("type", type, codec); } - default MapCodec dispatch(final String typeKey, final Function type, final Function> codec) { + default Codec dispatch(final String typeKey, final Function type, final Function> codec) { return partialDispatch(typeKey, type.andThen(DataResult::success), codec.andThen(DataResult::success)); } - default MapCodec dispatchStable(final Function type, final Function> codec) { + default Codec dispatchStable(final Function type, final Function> codec) { return dispatchStable("type", type, codec); } - default MapCodec dispatchStable(final String typeKey, final Function type, final Function> codec) { + default Codec dispatchStable(final String typeKey, final Function type, final Function> codec) { return partialDispatch(typeKey, e -> DataResult.success(type.apply(e), Lifecycle.stable()), a -> DataResult.success(codec.apply(a), Lifecycle.stable())); } - default MapCodec dispatchDeprecated(final int since, final Function type, final Function> codec) { + default Codec dispatchDeprecated(final int since, final Function type, final Function> codec) { return dispatchDeprecated(since, "type", type, codec); } - default MapCodec dispatchDeprecated(final int since, final String typeKey, final Function type, final Function> codec) { + default Codec dispatchDeprecated(final int since, final String typeKey, final Function type, final Function> codec) { final Lifecycle deprecated = Lifecycle.deprecated(since); return partialDispatch(typeKey, e -> DataResult.success(type.apply(e), deprecated), a -> DataResult.success(codec.apply(a), deprecated)); } - default MapCodec partialDispatch(final String typeKey, final Function> type, final Function>> codec) { + default Codec partialDispatch(final String typeKey, final Function> type, final Function>> codec) { + return new KeyDispatchCodec<>(typeKey, this, type, codec).codec(); + } + + default MapCodec dispatchMap(final Function type, final Function> codec) { + return dispatchMap("type", type, codec); + } + + default MapCodec dispatchMap(final String typeKey, final Function type, final Function> codec) { + return partialDispatchMap(typeKey, type.andThen(DataResult::success), codec.andThen(DataResult::success)); + } + + default MapCodec dispatchStableMap(final Function type, final Function> codec) { + return dispatchStableMap("type", type, codec); + } + + default MapCodec dispatchStableMap(final String typeKey, final Function type, final Function> codec) { + return partialDispatchMap(typeKey, e -> DataResult.success(type.apply(e), Lifecycle.stable()), a -> DataResult.success(codec.apply(a), Lifecycle.stable())); + } + + default MapCodec dispatchDeprecatedMap(final int since, final Function type, final Function> codec) { + return dispatchDeprecatedMap(since, "type", type, codec); + } + + default MapCodec dispatchDeprecatedMap(final int since, final String typeKey, final Function type, final Function> codec) { + final Lifecycle deprecated = Lifecycle.deprecated(since); + return partialDispatchMap(typeKey, e -> DataResult.success(type.apply(e), deprecated), a -> DataResult.success(codec.apply(a), deprecated)); + } + + default MapCodec partialDispatchMap(final String typeKey, final Function> type, final Function>> codec) { return new KeyDispatchCodec<>(typeKey, this, type, codec); } @@ -600,5 +623,5 @@ public String toString() { } }; - Codec EMPTY = Codec.of(Encoder.empty(), Decoder.unit(Unit.INSTANCE)); + MapCodec EMPTY = MapCodec.of(Encoder.empty(), Decoder.unit(Unit.INSTANCE)); } diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 13b1f4ac..274f4fe0 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -130,11 +130,6 @@ public Stream keys(final DynamicOps ops) { return Stream.empty(); } - @Override - public DataResult> decode(final DynamicOps ops, final T input) { - return DataResult.success(Pair.of(instance.get(), input)); - } - @Override public String toString() { return "UnitDecoder[" + instance.get() + "]"; diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index 9a747090..f1213426 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -89,11 +89,6 @@ public Stream keys(final DynamicOps ops) { return Stream.empty(); } - @Override - public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return DataResult.success(prefix); - } - @Override public String toString() { return "EmptyEncoder"; diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index f5a657e7..26d2c92f 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -45,7 +45,7 @@ public Codec getType(final JsonElement input) { return Codec.list(Codec.SAVING); } if (input instanceof JsonNull) { - return Codec.EMPTY; + return Codec.EMPTY.codec(); } final JsonPrimitive primitive = input.getAsJsonPrimitive(); if (primitive.isString()) { diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 2299d6f8..741cfe2b 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -12,7 +12,7 @@ import java.util.function.Supplier; import java.util.stream.Stream; -public abstract class MapCodec extends MapDecoder.Implementation implements MapEncoder, Codec { +public abstract class MapCodec extends MapDecoder.Implementation implements MapEncoder { public final RecordCodecBuilder forGetter(final Function getter) { return RecordCodecBuilder.of(getter, this); } @@ -45,6 +45,10 @@ public String toString() { }; } + public MapCodec fieldOf(final String name) { + return codec().fieldOf(name); + } + @Override public MapCodec withLifecycle(final Lifecycle lifecycle) { final MapCodec self = this; @@ -72,22 +76,49 @@ public String toString() { }; } - @Override + public static final class MapCodecCodec implements Codec { + private final MapCodec codec; + + public MapCodecCodec(final MapCodec codec) { + this.codec = codec; + } + + public MapCodec codec() { + return codec; + } + + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return codec.compressedDecode(ops, input).map(r -> Pair.of(r, input)); + } + + @Override + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return codec.encode(input, ops, codec.compressedBuilder(ops)).build(prefix); + } + + @Override + public String toString() { + return codec.toString(); + } + } + + public Codec codec() { + return new MapCodecCodec<>(this); + } + public MapCodec stable() { return withLifecycle(Lifecycle.stable()); } - @Override public MapCodec deprecated(final int since) { return withLifecycle(Lifecycle.deprecated(since)); } - @Override public MapCodec xmap(final Function to, final Function from) { return MapCodec.of(comap(from), map(to), toString() + "[comapped]"); } - @Override public MapCodec flatXmap(final Function> to, final Function> from) { return Codec.of(flatComap(from), flatMap(to), toString() + "[flatXmapped]"); } @@ -165,12 +196,10 @@ public String toString() { }; } - @Override public MapCodec withDefault(final Consumer onError, final A value) { return withDefault(DataFixUtils.consumerToFunction(onError), value); } - @Override public MapCodec withDefault(final Function onError, final A value) { return mapResult(new ResultFunction() { @Override @@ -190,12 +219,10 @@ public String toString() { }); } - @Override public MapCodec withDefault(final Consumer onError, final Supplier value) { return withDefault(DataFixUtils.consumerToFunction(onError), value); } - @Override public MapCodec withDefault(final Function onError, final Supplier value) { return mapResult(new ResultFunction() { @Override @@ -215,7 +242,6 @@ public String toString() { }); } - @Override public MapCodec withDefault(final A value) { return mapResult(new ResultFunction() { @Override @@ -235,7 +261,6 @@ public String toString() { }); } - @Override public MapCodec withDefault(final Supplier value) { return mapResult(new ResultFunction() { @Override @@ -254,4 +279,12 @@ public String toString() { } }); } + + static MapCodec unit(final A defaultValue) { + return unit(() -> defaultValue); + } + + static MapCodec unit(final Supplier defaultValue) { + return MapCodec.of(Encoder.empty(), Decoder.unit(defaultValue)); + } } diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index 5a4aafdf..bd508ed0 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -15,7 +15,7 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -public interface MapDecoder extends Decoder, Keyable { +public interface MapDecoder extends Keyable { DataResult decode(DynamicOps ops, MapLike input); default DataResult compressedDecode(final DynamicOps ops, final T input) { @@ -56,12 +56,21 @@ public Stream> entries() { MapCompressor compressor(DynamicOps ops); - @Override - default DataResult> decode(final DynamicOps ops, final T input) { - return compressedDecode(ops, input).map(r -> Pair.of(r, input)); + default Decoder decoder() { + final MapDecoder self = this; + return new Decoder() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return compressedDecode(ops, input).map(r -> Pair.of(r, input)); + } + + @Override + public String toString() { + return self.toString(); + } + }; } - @Override default MapDecoder flatMap(final Function> function) { final MapDecoder self = this; return new Implementation() { @@ -82,7 +91,6 @@ public String toString() { }; } - @Override default MapDecoder map(final Function function) { final MapDecoder self = this; return new Implementation() { @@ -125,7 +133,6 @@ public String toString() { }; } - @Override default MapDecoder withLifecycle(final Lifecycle lifecycle) { final MapDecoder self = this; return new MapDecoder.Implementation() { diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index caa333f0..476a22c3 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -10,7 +10,7 @@ import java.util.function.Function; import java.util.stream.Stream; -public interface MapEncoder extends Encoder, Keyable { +public interface MapEncoder extends Keyable { RecordBuilder encode(A input, DynamicOps ops, RecordBuilder prefix); default RecordBuilder compressedBuilder(final DynamicOps ops) { @@ -22,7 +22,6 @@ default RecordBuilder compressedBuilder(final DynamicOps ops) { MapCompressor compressor(final DynamicOps ops); - @Override default MapEncoder comap(final Function function) { final MapEncoder self = this; return new MapEncoder.Implementation() { @@ -43,7 +42,6 @@ public String toString() { }; } - @Override default MapEncoder flatComap(final Function> function) { final MapEncoder self = this; return new MapEncoder.Implementation() { @@ -59,11 +57,6 @@ public RecordBuilder encode(final B input, final DynamicOps ops, final return aResult.map(r -> self.encode(r, ops, builder)).result().orElse(builder); } - @Override - public DataResult encode(final B input, final DynamicOps ops, final T prefix) { - return function.apply(input).flatMap(a -> self.encode(a, ops, prefix)); - } - @Override public String toString() { return self.toString() + "[flatComapped]"; @@ -71,12 +64,21 @@ public String toString() { }; } - @Override - default DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return encode(input, ops, compressedBuilder(ops)).build(prefix); + default Encoder encoder() { + final MapEncoder self = this; + return new Encoder() { + @Override + public DataResult encode(final A input, final DynamicOps ops, final T prefix) { + return self.encode(input, ops, compressedBuilder(ops)).build(prefix); + } + + @Override + public String toString() { + return self.toString(); + } + }; } - @Override default MapEncoder withLifecycle(final Lifecycle lifecycle) { final MapEncoder self = this; return new Implementation() { diff --git a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java index 696afb9b..012748d0 100644 --- a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java @@ -16,7 +16,7 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -public interface BaseMapCodec extends Codec> { +public interface BaseMapCodec { Codec keyCodec(); diff --git a/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java b/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java index 731cfe6f..4c5d020f 100644 --- a/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java @@ -7,8 +7,6 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Encoder; import com.mojang.serialization.MapCodec; -import com.mojang.serialization.MapDecoder; -import com.mojang.serialization.MapEncoder; import com.mojang.serialization.MapLike; import com.mojang.serialization.RecordBuilder; @@ -55,8 +53,8 @@ public DataResult decode(final DynamicOps ops, final MapLike input) } return c.parse(ops, value).map(Function.identity()); } - if (c instanceof MapDecoder) { - return ((MapDecoder) c).decode(ops, input).map(Function.identity()); + if (c instanceof MapCodecCodec) { + return ((MapCodecCodec) c).codec().decode(ops, input).map(Function.identity()); } return c.decode(ops, ops.createMap(input.entries())).map(Pair::getFirst); }); @@ -77,8 +75,8 @@ public RecordBuilder encode(final V input, final DynamicOps ops, final .add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))) .add(valueKey, c.encodeStart(ops, input)); } - if (c instanceof MapEncoder) { - return ((MapEncoder) c).encode(input, ops, prefix) + if (c instanceof MapCodecCodec) { + return ((MapCodecCodec) c).codec().encode(input, ops, prefix) .add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))); } diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index 0749cbcc..dfc9a9e4 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -69,7 +69,11 @@ public static RecordCodecBuilder point(final F instance, final Life return new RecordCodecBuilder<>(o -> instance, o -> Encoder.empty().withLifecycle(lifecycle), Decoder.unit(instance).withLifecycle(lifecycle)); } - public static MapCodec create(final Function, ? extends App, O>> builder) { + public static Codec create(final Function, ? extends App, O>> builder) { + return build(builder.apply(instance())).codec(); + } + + public static MapCodec mapCodec(final Function, ? extends App, O>> builder) { return build(builder.apply(instance())); } diff --git a/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java b/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java index a40f0e19..d866175f 100644 --- a/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java @@ -14,7 +14,7 @@ /** * Key and value decoded independently, unknown set of keys */ -public final class UnboundedMapCodec implements BaseMapCodec { +public final class UnboundedMapCodec implements BaseMapCodec, Codec> { private final Codec keyCodec; private final Codec elementCodec; From c5117e093dd1dfa255a4a8043868c94533b7ae15 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 9 May 2020 20:01:44 +0200 Subject: [PATCH 71/96] Removed Serializable interface --- src/main/java/com/mojang/serialization/Codec.java | 4 ---- .../java/com/mojang/serialization/DynamicOps.java | 8 -------- .../java/com/mojang/serialization/Encoder.java | 14 -------------- .../java/com/mojang/serialization/ListBuilder.java | 13 ------------- .../com/mojang/serialization/RecordBuilder.java | 8 -------- .../com/mojang/serialization/Serializable.java | 11 ----------- 6 files changed, 58 deletions(-) delete mode 100644 src/main/java/com/mojang/serialization/Serializable.java diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index a81b680d..40fd6106 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -60,10 +60,6 @@ default Codec deprecated(final int since) { return withLifecycle(Lifecycle.deprecated(since)); } - static Codec of(final Decoder decoder) { - return of(Encoder.of(), decoder); - } - static Codec of(final Encoder encoder, final Decoder decoder) { return of(encoder, decoder, "Codec[" + encoder + " " + decoder + "]"); } diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index 86d00d95..b29b951f 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -231,14 +231,6 @@ default ListBuilder listBuilder() { return new ListBuilder.Builder<>(this); } - default DataResult list(final Iterable list) { - return list(list, empty(), empty()); - } - - default DataResult list(final Iterable list, final T prefix, final T elementPrefix) { - return list(list, prefix, e -> e.serialize(this, elementPrefix)); - } - default DataResult list(final Iterable list, final T prefix, final Encoder encoder) { final ListBuilder builder = listBuilder(); builder.addAll(list, encoder); diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index f1213426..b4809be1 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -63,20 +63,6 @@ public String toString() { }; } - static Encoder of() { - return new Encoder() { - @Override - public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return input.serialize(ops, prefix); - } - - @Override - public String toString() { - return "SerializableEncoder"; - } - }; - } - static MapEncoder empty() { return new MapEncoder.Implementation() { @Override diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index acc8f374..3fae7bc2 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -23,23 +23,10 @@ default DataResult build(final DataResult prefix) { return prefix.flatMap(this::build); } - default ListBuilder add(final Serializable value) { - return add(value, ops().empty()); - } - - default ListBuilder add(final Serializable value, final T elementPrefix) { - return add(value.serialize(ops(), elementPrefix)); - } - default ListBuilder add(final E value, final Encoder encoder) { return add(encoder.encodeStart(ops(), value)); } - default ListBuilder addAll(final Iterable values) { - values.forEach(this::add); - return this; - } - default ListBuilder addAll(final Iterable values, final Encoder encoder) { values.forEach(v -> encoder.encode(v, ops(), ops().empty())); return this; diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index e0a1bdc2..902edcf2 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -35,14 +35,6 @@ default RecordBuilder add(final String key, final DataResult value) { return add(ops().createString(key), value); } - default RecordBuilder add(final String key, final Serializable value) { - return add(key, value, ops().empty()); - } - - default RecordBuilder add(final String key, final Serializable value, final T elementPrefix) { - return add(key, value.serialize(ops(), elementPrefix)); - } - default RecordBuilder add(final String key, final E value, final Encoder encoder) { return add(key, encoder.encodeStart(ops(), value)); } diff --git a/src/main/java/com/mojang/serialization/Serializable.java b/src/main/java/com/mojang/serialization/Serializable.java deleted file mode 100644 index 4415e3c7..00000000 --- a/src/main/java/com/mojang/serialization/Serializable.java +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -package com.mojang.serialization; - -public interface Serializable { - DataResult serialize(final DynamicOps ops, final T prefix); - - default DataResult serializeStart(final DynamicOps ops) { - return serialize(ops, ops.empty()); - } -} From d5d4b3a2f84c582d9b249fa986a9e55e11d31a8a Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 11:36:09 +0200 Subject: [PATCH 72/96] Fixed duplicate key issue in KeyDispatchCodec --- .../mojang/serialization/codecs/KeyDispatchCodec.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java b/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java index 4c5d020f..504ee4c2 100644 --- a/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/KeyDispatchCodec.java @@ -80,10 +80,17 @@ public RecordBuilder encode(final V input, final DynamicOps ops, final .add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))); } - prefix.add(typeKey, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))); + final T typeString = ops.createString(typeKey); + final DataResult> element = c.encodeStart(ops, input).flatMap(ops::getMap); return element.map(map -> { - map.entries().forEach(pair -> prefix.add(pair.getFirst(), pair.getSecond())); + map.entries().forEach(pair -> { + if (pair.getFirst().equals(typeString)) { + prefix.add(typeString, type.apply(input).flatMap(t -> keyCodec.encodeStart(ops, t))); + } else { + prefix.add(pair.getFirst(), pair.getSecond()); + } + }); return prefix; }).result().orElseGet(() -> prefix.withErrorsFrom(element)); } From a7cc332c01e457f53e360c0c7253a7c9f8ce9c12 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 12:55:48 +0200 Subject: [PATCH 73/96] Do not create the new object in Lifecycle.add --- src/main/java/com/mojang/serialization/Lifecycle.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/mojang/serialization/Lifecycle.java b/src/main/java/com/mojang/serialization/Lifecycle.java index 8a12066d..e1dcce48 100644 --- a/src/main/java/com/mojang/serialization/Lifecycle.java +++ b/src/main/java/com/mojang/serialization/Lifecycle.java @@ -48,8 +48,8 @@ public Lifecycle add(final Lifecycle other) { return EXPERIMENTAL; } if (this instanceof Deprecated) { - if (other instanceof Deprecated) { - return new Deprecated(Math.min(((Deprecated) this).since, ((Deprecated) other).since)); + if (other instanceof Deprecated && ((Deprecated) other).since < ((Deprecated) this).since) { + return other; } return this; } From bea693c84fbe664d163fcae3b5d7351d285626ec Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 16:32:20 +0200 Subject: [PATCH 74/96] Renamed DynamicException to PartialResult --- .../com/mojang/serialization/DataResult.java | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 2fbdeedc..be1714c8 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -26,7 +26,7 @@ public static DataResult unbox(final App box) { return (DataResult) box; } - private final Either> result; + private final Either> result; private final Lifecycle lifecycle; public static DataResult success(final R result) { @@ -46,23 +46,23 @@ public static DataResult success(final R result, final Lifecycle experime } public static DataResult error(final String message, final R partialResult, final Lifecycle lifecycle) { - return new DataResult<>(Either.right(new DynamicException<>(message, Optional.of(partialResult))), lifecycle); + return new DataResult<>(Either.right(new PartialResult<>(message, Optional.of(partialResult))), lifecycle); } public static DataResult error(final String message, final Lifecycle lifecycle) { - return new DataResult<>(Either.right(new DynamicException<>(message, Optional.empty())), lifecycle); + return new DataResult<>(Either.right(new PartialResult<>(message, Optional.empty())), lifecycle); } - private static DataResult create(final Either> result, final Lifecycle lifecycle) { + private static DataResult create(final Either> result, final Lifecycle lifecycle) { return new DataResult<>(result, lifecycle); } - private DataResult(final Either> result, final Lifecycle lifecycle) { + private DataResult(final Either> result, final Lifecycle lifecycle) { this.result = result; this.lifecycle = lifecycle; } - public Either> get() { + public Either> get() { return result; } @@ -97,14 +97,14 @@ public R getOrThrow(final boolean allowPartial, final Consumer onError) ); } - public Optional> error() { + public Optional> error() { return result.right(); } public DataResult map(final Function function) { return create(result.mapBoth( function, - r -> new DynamicException<>(r.message, r.partialResult.map(function)) + r -> new PartialResult<>(r.message, r.partialResult.map(function)) ), lifecycle); } @@ -133,12 +133,12 @@ public DataResult flatMap(final Function { final DataResult second = function.apply(value); return create(Either.right(second.get().map( - l2 -> new DynamicException<>(r.message, Optional.of(l2)), - r2 -> new DynamicException<>(r.message + "; " + r2.message, r2.partialResult) + l2 -> new PartialResult<>(r.message, Optional.of(l2)), + r2 -> new PartialResult<>(r.message + "; " + r2.message, r2.partialResult) )), lifecycle.add(second.lifecycle)); }) .orElseGet( - () -> create(Either.right(new DynamicException<>(r.message, Optional.empty())), lifecycle) + () -> create(Either.right(new PartialResult<>(r.message, Optional.empty())), lifecycle) ) ); } @@ -147,11 +147,11 @@ public DataResult ap(final DataResult> functionResult) return create(result.map( arg -> functionResult.result.mapBoth( func -> func.apply(arg), - funcError -> new DynamicException<>(funcError.message, funcError.partialResult.map(f -> f.apply(arg))) + funcError -> new PartialResult<>(funcError.message, funcError.partialResult.map(f -> f.apply(arg))) ), argError -> Either.right(functionResult.result.map( - func -> new DynamicException<>(argError.message, argError.partialResult.map(func)), - funcError -> new DynamicException<>( + func -> new PartialResult<>(argError.message, argError.partialResult.map(func)), + funcError -> new PartialResult<>( argError.message + "; " + funcError.message, argError.partialResult.flatMap(a -> funcError.partialResult.map(f -> f.apply(a))) ) @@ -174,15 +174,15 @@ public DataResult apply3(final Function3 function, } public DataResult setPartial(final Supplier partial) { - return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial.get()))), lifecycle); + return create(result.mapRight(r -> new PartialResult<>(r.message, Optional.of(partial.get()))), lifecycle); } public DataResult setPartial(final R partial) { - return create(result.mapRight(r -> new DynamicException<>(r.message, Optional.of(partial))), lifecycle); + return create(result.mapRight(r -> new PartialResult<>(r.message, Optional.of(partial))), lifecycle); } public DataResult mapError(final Function function) { - return create(result.mapRight(r -> new DynamicException<>(function.apply(r.message), r.partialResult)), lifecycle); + return create(result.mapRight(r -> new PartialResult<>(function.apply(r.message), r.partialResult)), lifecycle); } public DataResult setLifecycle(final Lifecycle lifecycle) { @@ -219,11 +219,11 @@ public String toString() { return "DataResult[" + result + ']'; } - public static class DynamicException { + public static class PartialResult { private final String message; private final Optional partialResult; - public DynamicException(final String message, final Optional partialResult) { + public PartialResult(final String message, final Optional partialResult) { this.message = message; this.partialResult = partialResult; } @@ -232,16 +232,16 @@ public RuntimeException error() { return new RuntimeException(message); } - public DynamicException map(final Function function) { - return new DynamicException<>(message, partialResult.map(function)); + public PartialResult map(final Function function) { + return new PartialResult<>(message, partialResult.map(function)); } - public DynamicException flatMap(final Function> function) { + public PartialResult flatMap(final Function> function) { if (partialResult.isPresent()) { - final DynamicException result = function.apply(partialResult.get()); - return new DynamicException<>(message + "; " + result.message, result.partialResult); + final PartialResult result = function.apply(partialResult.get()); + return new PartialResult<>(message + "; " + result.message, result.partialResult); } - return new DynamicException<>(message, Optional.empty()); + return new PartialResult<>(message, Optional.empty()); } public String message() { @@ -256,7 +256,7 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - final DynamicException that = (DynamicException) o; + final PartialResult that = (PartialResult) o; return Objects.equals(message, that.message) && Objects.equals(partialResult, that.partialResult); } From 8628de3bd3e1d7249b2cdc2d208fe52463d0e81c Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 16:35:22 +0200 Subject: [PATCH 75/96] Made Deprecated class public --- src/main/java/com/mojang/serialization/Lifecycle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/Lifecycle.java b/src/main/java/com/mojang/serialization/Lifecycle.java index e1dcce48..7a044c38 100644 --- a/src/main/java/com/mojang/serialization/Lifecycle.java +++ b/src/main/java/com/mojang/serialization/Lifecycle.java @@ -19,7 +19,7 @@ public String toString() { private Lifecycle() { } - protected static final class Deprecated extends Lifecycle { + public static final class Deprecated extends Lifecycle { private final int since; public Deprecated(final int since) { From 07d6317e50775f1a06ae0d68197486c3a0e04635 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 16:44:44 +0200 Subject: [PATCH 76/96] Extracted message appending logic in DataResult --- src/main/java/com/mojang/serialization/DataResult.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index be1714c8..57b27b92 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -120,6 +120,10 @@ public DataResult promotePartial(final Consumer onError) { ); } + private static String appendMessages(final String first, final String second) { + return first + "; " + second; + } + /** * Applies the function to either full or partial result, in case of partial concatenates errors. */ @@ -134,7 +138,7 @@ public DataResult flatMap(final Function second = function.apply(value); return create(Either.right(second.get().map( l2 -> new PartialResult<>(r.message, Optional.of(l2)), - r2 -> new PartialResult<>(r.message + "; " + r2.message, r2.partialResult) + r2 -> new PartialResult<>(appendMessages(r.message, r2.message), r2.partialResult) )), lifecycle.add(second.lifecycle)); }) .orElseGet( @@ -152,7 +156,7 @@ public DataResult ap(final DataResult> functionResult) argError -> Either.right(functionResult.result.map( func -> new PartialResult<>(argError.message, argError.partialResult.map(func)), funcError -> new PartialResult<>( - argError.message + "; " + funcError.message, + appendMessages(argError.message, funcError.message), argError.partialResult.flatMap(a -> funcError.partialResult.map(f -> f.apply(a))) ) )) @@ -239,7 +243,7 @@ public PartialResult map(final Function functi public PartialResult flatMap(final Function> function) { if (partialResult.isPresent()) { final PartialResult result = function.apply(partialResult.get()); - return new PartialResult<>(message + "; " + result.message, result.partialResult); + return new PartialResult<>(appendMessages(message, result.message), result.partialResult); } return new PartialResult<>(message, Optional.empty()); } From d50e28aa24e810f5b978a158b18d9b832ba0debb Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 16:49:53 +0200 Subject: [PATCH 77/96] Function -> UnaryOperator --- src/main/java/com/mojang/datafixers/DataFixUtils.java | 4 ++-- src/main/java/com/mojang/serialization/Codec.java | 5 +++-- src/main/java/com/mojang/serialization/DataResult.java | 3 ++- src/main/java/com/mojang/serialization/JsonOps.java | 4 ++-- src/main/java/com/mojang/serialization/ListBuilder.java | 6 +++--- src/main/java/com/mojang/serialization/MapCodec.java | 5 +++-- src/main/java/com/mojang/serialization/RecordBuilder.java | 6 +++--- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/DataFixUtils.java b/src/main/java/com/mojang/datafixers/DataFixUtils.java index 83b3fb86..cf8959ae 100644 --- a/src/main/java/com/mojang/datafixers/DataFixUtils.java +++ b/src/main/java/com/mojang/datafixers/DataFixUtils.java @@ -5,8 +5,8 @@ import java.nio.ByteBuffer; import java.util.Optional; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.UnaryOperator; public class DataFixUtils { private DataFixUtils() { @@ -95,7 +95,7 @@ public static int getSubVersion(final int key) { return key % 10; } - public static Function consumerToFunction(final Consumer consumer) { + public static UnaryOperator consumerToFunction(final Consumer consumer) { return s -> { consumer.accept(s); return s; diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 40fd6106..6100d1a5 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -25,6 +25,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.LongStream; @@ -230,7 +231,7 @@ default Codec withDefault(final Consumer onError, final A value) { return withDefault(DataFixUtils.consumerToFunction(onError), value); } - default Codec withDefault(final Function onError, final A value) { + default Codec withDefault(final UnaryOperator onError, final A value) { return mapResult(new ResultFunction() { @Override public DataResult> apply(final DynamicOps ops, final T input, final DataResult> a) { @@ -253,7 +254,7 @@ default Codec withDefault(final Consumer onError, final Supplier withDefault(final Function onError, final Supplier value) { + default Codec withDefault(final UnaryOperator onError, final Supplier value) { return mapResult(new ResultFunction() { @Override public DataResult> apply(final DynamicOps ops, final T input, final DataResult> a) { diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 57b27b92..39ce0742 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -14,6 +14,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.UnaryOperator; /** * Represents either a successful operation, or a partial operation with an error message and a partial result (if available) @@ -185,7 +186,7 @@ public DataResult setPartial(final R partial) { return create(result.mapRight(r -> new PartialResult<>(r.message, Optional.of(partial))), lifecycle); } - public DataResult mapError(final Function function) { + public DataResult mapError(final UnaryOperator function) { return create(result.mapRight(r -> new PartialResult<>(function.apply(r.message), r.partialResult)), lifecycle); } diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 26d2c92f..6805a127 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -17,7 +17,7 @@ import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Function; +import java.util.function.UnaryOperator; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -356,7 +356,7 @@ public ListBuilder withErrorsFrom(final DataResult result) { } @Override - public ListBuilder mapError(final Function onError) { + public ListBuilder mapError(final UnaryOperator onError) { builder = builder.mapError(onError); return this; } diff --git a/src/main/java/com/mojang/serialization/ListBuilder.java b/src/main/java/com/mojang/serialization/ListBuilder.java index 3fae7bc2..c68ae76a 100644 --- a/src/main/java/com/mojang/serialization/ListBuilder.java +++ b/src/main/java/com/mojang/serialization/ListBuilder.java @@ -4,7 +4,7 @@ import com.google.common.collect.ImmutableList; -import java.util.function.Function; +import java.util.function.UnaryOperator; public interface ListBuilder { DynamicOps ops(); @@ -17,7 +17,7 @@ public interface ListBuilder { ListBuilder withErrorsFrom(final DataResult result); - ListBuilder mapError(Function onError); + ListBuilder mapError(UnaryOperator onError); default DataResult build(final DataResult prefix) { return prefix.flatMap(this::build); @@ -64,7 +64,7 @@ public ListBuilder withErrorsFrom(final DataResult result) { } @Override - public ListBuilder mapError(final Function onError) { + public ListBuilder mapError(final UnaryOperator onError) { builder = builder.mapError(onError); return this; } diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 741cfe2b..70e93262 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -10,6 +10,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.UnaryOperator; import java.util.stream.Stream; public abstract class MapCodec extends MapDecoder.Implementation implements MapEncoder { @@ -200,7 +201,7 @@ public MapCodec withDefault(final Consumer onError, final A value) { return withDefault(DataFixUtils.consumerToFunction(onError), value); } - public MapCodec withDefault(final Function onError, final A value) { + public MapCodec withDefault(final UnaryOperator onError, final A value) { return mapResult(new ResultFunction() { @Override public DataResult apply(final DynamicOps ops, final MapLike input, final DataResult a) { @@ -223,7 +224,7 @@ public MapCodec withDefault(final Consumer onError, final Supplier withDefault(final Function onError, final Supplier value) { + public MapCodec withDefault(final UnaryOperator onError, final Supplier value) { return mapResult(new ResultFunction() { @Override public DataResult apply(final DynamicOps ops, final MapLike input, final DataResult a) { diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 902edcf2..4e45bbc6 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -4,7 +4,7 @@ import com.google.common.collect.ImmutableMap; -import java.util.function.Function; +import java.util.function.UnaryOperator; public interface RecordBuilder { DynamicOps ops(); @@ -19,7 +19,7 @@ public interface RecordBuilder { RecordBuilder setLifecycle(Lifecycle lifecycle); - RecordBuilder mapError(Function onError); + RecordBuilder mapError(UnaryOperator onError); DataResult build(T prefix); @@ -117,7 +117,7 @@ public RecordBuilder setLifecycle(final Lifecycle lifecycle) { } @Override - public RecordBuilder mapError(final Function onError) { + public RecordBuilder mapError(final UnaryOperator onError) { builder = builder.mapError(onError); return this; } From e09880b6ece72aa2ed37d4f46391b0c71054dbf0 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 16:52:08 +0200 Subject: [PATCH 78/96] Removed unused method --- src/main/java/com/mojang/serialization/DataResult.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 39ce0742..2a42cc0a 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -233,10 +233,6 @@ public PartialResult(final String message, final Optional partialResult) { this.partialResult = partialResult; } - public RuntimeException error() { - return new RuntimeException(message); - } - public PartialResult map(final Function function) { return new PartialResult<>(message, partialResult.map(function)); } From ae2736175efd372a932bb58bc57dae8d2304bcf7 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 17:03:12 +0200 Subject: [PATCH 79/96] Removed useless stream collect --- .../mojang/serialization/MapCompressor.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/mojang/serialization/MapCompressor.java b/src/main/java/com/mojang/serialization/MapCompressor.java index fdafd004..9ba38e1e 100644 --- a/src/main/java/com/mojang/serialization/MapCompressor.java +++ b/src/main/java/com/mojang/serialization/MapCompressor.java @@ -7,8 +7,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; public final class MapCompressor { @@ -20,21 +18,22 @@ public final class MapCompressor { public MapCompressor(final DynamicOps ops, final Stream keyStream) { this.ops = ops; - final List keys = keyStream.distinct().collect(Collectors.toList()); compressString.defaultReturnValue(-1); - for (int i = 0; i < keys.size(); i++) { - final T key = keys.get(i); - compress.put(key, i); - final int finalI = i; + keyStream.forEach(key -> { + if (compress.containsKey(key)) { + return; + } + final int next = compress.size(); + compress.put(key, next); ops.getStringValue(key).result().ifPresent(k -> - compressString.put(k, finalI) + compressString.put(k, next) ); - decompress.put(i, key); - } + decompress.put(next, key); + }); - size = keys.size(); + size = compress.size(); } public T decompress(final int key) { From afb836962e8a7167b174b89e32204579c61fe283 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 17:07:42 +0200 Subject: [PATCH 80/96] List variable type --- src/main/java/com/mojang/serialization/MapEncoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index 476a22c3..cb606d4e 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -117,7 +117,7 @@ private CompressedRecordBuilder() { @Override protected List initBuilder() { - final ArrayList list = new ArrayList<>(compressor.size()); + final List list = new ArrayList<>(compressor.size()); for (int i = 0; i < compressor.size(); i++) { list.add(null); } From 061642ae2b4e913648a1a0539779892f819aa3c5 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 17:11:56 +0200 Subject: [PATCH 81/96] Saving -> Passthrough --- src/main/java/com/mojang/datafixers/DSL.java | 8 ++++---- .../{EmptyPartSaving.java => EmptyPartPassthrough.java} | 6 +++--- src/main/java/com/mojang/serialization/Codec.java | 4 ++-- src/main/java/com/mojang/serialization/Dynamic.java | 5 ++--- src/main/java/com/mojang/serialization/JsonOps.java | 4 ++-- 5 files changed, 13 insertions(+), 14 deletions(-) rename src/main/java/com/mojang/datafixers/types/constant/{EmptyPartSaving.java => EmptyPartPassthrough.java} (84%) diff --git a/src/main/java/com/mojang/datafixers/DSL.java b/src/main/java/com/mojang/datafixers/DSL.java index 53e8ce93..a1580c1b 100644 --- a/src/main/java/com/mojang/datafixers/DSL.java +++ b/src/main/java/com/mojang/datafixers/DSL.java @@ -7,7 +7,7 @@ import com.mojang.datafixers.types.Func; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.constant.EmptyPart; -import com.mojang.datafixers.types.constant.EmptyPartSaving; +import com.mojang.datafixers.types.constant.EmptyPartPassthrough; import com.mojang.datafixers.types.templates.Check; import com.mojang.datafixers.types.templates.CompoundList; import com.mojang.datafixers.types.templates.Const; @@ -84,11 +84,11 @@ static Type emptyPartType() { } static TypeTemplate remainder() { - return constType(Instances.NIL_SAVE); + return constType(Instances.EMPTY_PASSTHROUGH); } static Type> remainderType() { - return Instances.NIL_SAVE; + return Instances.EMPTY_PASSTHROUGH; } static TypeTemplate check(final String name, final int index, final TypeTemplate element) { @@ -443,7 +443,7 @@ final class Instances { private static final Type DOUBLE_TYPE = new Const.PrimitiveType<>(Codec.DOUBLE); private static final Type STRING_TYPE = new Const.PrimitiveType<>(Codec.STRING); private static final Type EMPTY_PART = new EmptyPart(); - private static final Type> NIL_SAVE = new EmptyPartSaving(); + private static final Type> EMPTY_PASSTHROUGH = new EmptyPartPassthrough(); private static final OpticFinder> REMAINDER_FINDER = remainderType().finder(); diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartPassthrough.java similarity index 84% rename from src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java rename to src/main/java/com/mojang/datafixers/types/constant/EmptyPartPassthrough.java index 399f62ca..f3b449a4 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartSaving.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartPassthrough.java @@ -10,10 +10,10 @@ import java.util.Optional; -public final class EmptyPartSaving extends com.mojang.datafixers.types.Type> { +public final class EmptyPartPassthrough extends com.mojang.datafixers.types.Type> { @Override public String toString() { - return "EmptyPartSaving"; + return "EmptyPartPassthrough"; } @Override @@ -33,6 +33,6 @@ public TypeTemplate buildTemplate() { @Override public Codec> buildCodec() { - return Codec.SAVING; + return Codec.PASSTHROUGH; } } diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index 6100d1a5..d6f2de39 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -586,7 +586,7 @@ public String toString() { } }; - Codec> SAVING = new Codec>() { + Codec> PASSTHROUGH = new Codec>() { @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { return DataResult.success(Pair.of(new Dynamic<>(ops, input), ops.empty())); @@ -616,7 +616,7 @@ public DataResult encode(final Dynamic input, final DynamicOps ops, @Override public String toString() { - return "saving"; + return "passthrough"; } }; diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index 7b036fd7..4bdf5ef0 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -10,7 +10,6 @@ import java.nio.ByteBuffer; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.LongStream; @@ -228,10 +227,10 @@ public static T convert(final DynamicOps inOps, final DynamicOps ou if (Objects.equals(type, Codec.list(Codec.LONG))) { return outOps.createLongList(inOps.getLongStream(input).result().orElse(LongStream.empty())); } - if (Objects.equals(type, Codec.list(Codec.SAVING))) { + if (Objects.equals(type, Codec.list(Codec.PASSTHROUGH))) { return outOps.createList(inOps.getStream(input).result().orElse(Stream.empty()).map(e -> convert(inOps, outOps, e))); } - if (Objects.equals(type, Codec.compoundList(Codec.SAVING, Codec.SAVING))) { + if (Objects.equals(type, Codec.compoundList(Codec.PASSTHROUGH, Codec.PASSTHROUGH))) { return outOps.createMap(inOps.getMapValues(input).result().orElse(Stream.empty()).map(e -> Pair.of(convert(inOps, outOps, e.getFirst()), convert(inOps, outOps, e.getSecond())) )); diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 6805a127..b5e81949 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -39,10 +39,10 @@ public JsonElement empty() { @Override public Codec getType(final JsonElement input) { if (input instanceof JsonObject) { - return Codec.compoundList(Codec.SAVING, Codec.SAVING); + return Codec.compoundList(Codec.PASSTHROUGH, Codec.PASSTHROUGH); } if (input instanceof JsonArray) { - return Codec.list(Codec.SAVING); + return Codec.list(Codec.PASSTHROUGH); } if (input instanceof JsonNull) { return Codec.EMPTY.codec(); From d4a1dba1a4da5210cc9f701b07e431cd59f06a5f Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 17:24:28 +0200 Subject: [PATCH 82/96] Replaced getType with ops-based dispatch --- .../com/mojang/serialization/Dynamic.java | 48 +------------------ .../com/mojang/serialization/DynamicOps.java | 13 ++++- .../com/mojang/serialization/JsonOps.java | 24 +++++----- 3 files changed, 26 insertions(+), 59 deletions(-) diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java index 4bdf5ef0..a75d3db0 100644 --- a/src/main/java/com/mojang/serialization/Dynamic.java +++ b/src/main/java/com/mojang/serialization/Dynamic.java @@ -190,51 +190,7 @@ public static T convert(final DynamicOps inOps, final DynamicOps ou if (Objects.equals(inOps, outOps)) { return (T) input; } - final Codec type = inOps.getType(input); - if (Objects.equals(type, Codec.EMPTY)) { - return outOps.empty(); - } - if (Objects.equals(type, Codec.BYTE)) { - return outOps.createByte(inOps.getNumberValue(input, 0).byteValue()); - } - if (Objects.equals(type, Codec.SHORT)) { - return outOps.createShort(inOps.getNumberValue(input, 0).shortValue()); - } - if (Objects.equals(type, Codec.INT)) { - return outOps.createInt(inOps.getNumberValue(input, 0).intValue()); - } - if (Objects.equals(type, Codec.LONG)) { - return outOps.createLong(inOps.getNumberValue(input, 0).longValue()); - } - if (Objects.equals(type, Codec.FLOAT)) { - return outOps.createFloat(inOps.getNumberValue(input, 0).floatValue()); - } - if (Objects.equals(type, Codec.DOUBLE)) { - return outOps.createDouble(inOps.getNumberValue(input, 0).doubleValue()); - } - if (Objects.equals(type, Codec.BOOL)) { - return outOps.createBoolean(inOps.getBooleanValue(input).result().orElse(false)); - } - if (Objects.equals(type, Codec.STRING)) { - return outOps.createString(inOps.getStringValue(input).result().orElse("")); - } - if (Objects.equals(type, Codec.list(Codec.BYTE))) { - return outOps.createByteList(inOps.getByteBuffer(input).result().orElse(ByteBuffer.wrap(new byte[0]))); - } - if (Objects.equals(type, Codec.list(Codec.INT))) { - return outOps.createIntList(inOps.getIntStream(input).result().orElse(IntStream.empty())); - } - if (Objects.equals(type, Codec.list(Codec.LONG))) { - return outOps.createLongList(inOps.getLongStream(input).result().orElse(LongStream.empty())); - } - if (Objects.equals(type, Codec.list(Codec.PASSTHROUGH))) { - return outOps.createList(inOps.getStream(input).result().orElse(Stream.empty()).map(e -> convert(inOps, outOps, e))); - } - if (Objects.equals(type, Codec.compoundList(Codec.PASSTHROUGH, Codec.PASSTHROUGH))) { - return outOps.createMap(inOps.getMapValues(input).result().orElse(Stream.empty()).map(e -> - Pair.of(convert(inOps, outOps, e.getFirst()), convert(inOps, outOps, e.getSecond())) - )); - } - throw new IllegalStateException("Could not convert value of type " + type); + + return inOps.convertTo(outOps, input); } } diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index b29b951f..165f9fa0 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -3,6 +3,7 @@ package com.mojang.serialization; import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonElement; import com.mojang.datafixers.util.Function3; import com.mojang.datafixers.util.Pair; @@ -31,7 +32,7 @@ default T emptyList() { return createList(Stream.empty()); } - Codec getType(final T input); + U convertTo(DynamicOps outOps, T input); DataResult getNumberValue(T input); @@ -272,4 +273,14 @@ default Function>> withDecoder(final Decoder dec default Function> withParser(final Decoder decoder) { return t -> decoder.parse(this, t); } + + default U convertList(final DynamicOps outOps, final T input) { + return outOps.createList(getStream(input).result().orElse(Stream.empty()).map(e -> convertTo(outOps, e))); + } + + default U convertMap(final DynamicOps outOps, final T input) { + return outOps.createMap(getMapValues(input).result().orElse(Stream.empty()).map(e -> + Pair.of(convertTo(outOps, e.getFirst()), convertTo(outOps, e.getSecond())) + )); + } } diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index b5e81949..46613cdc 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -37,42 +37,42 @@ public JsonElement empty() { } @Override - public Codec getType(final JsonElement input) { + public U convertTo(final DynamicOps outOps, final JsonElement input) { if (input instanceof JsonObject) { - return Codec.compoundList(Codec.PASSTHROUGH, Codec.PASSTHROUGH); + return convertMap(outOps, input); } if (input instanceof JsonArray) { - return Codec.list(Codec.PASSTHROUGH); + return convertList(outOps, input); } if (input instanceof JsonNull) { - return Codec.EMPTY.codec(); + return outOps.empty(); } final JsonPrimitive primitive = input.getAsJsonPrimitive(); if (primitive.isString()) { - return Codec.STRING; + return outOps.createString(primitive.getAsString()); } if (primitive.isBoolean()) { - return Codec.BOOL; + return outOps.createBoolean(primitive.getAsBoolean()); } final BigDecimal value = primitive.getAsBigDecimal(); try { final long l = value.longValueExact(); if ((byte) l == l) { - return Codec.BYTE; + return outOps.createByte((byte) l); } if ((short) l == l) { - return Codec.SHORT; + return outOps.createShort((short) l); } if ((int) l == l) { - return Codec.INT; + return outOps.createInt((int) l); } - return Codec.LONG; + return outOps.createLong(l); } catch (final ArithmeticException e) { final double d = value.doubleValue(); if ((float) d == d) { - return Codec.FLOAT; + return outOps.createFloat((float) d); } - return Codec.DOUBLE; + return outOps.createDouble(d); } } From 47bfac12b4f62b8a2c787e631726a79ef5183104 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 17:30:28 +0200 Subject: [PATCH 83/96] Fixed copypaste error --- src/main/java/com/mojang/serialization/MapCodec.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 70e93262..074d464e 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -117,7 +117,7 @@ public MapCodec deprecated(final int since) { } public MapCodec xmap(final Function to, final Function from) { - return MapCodec.of(comap(from), map(to), toString() + "[comapped]"); + return MapCodec.of(comap(from), map(to), toString() + "[xmapped]"); } public MapCodec flatXmap(final Function> to, final Function> from) { From 330d3ea4eaf5cfed4ecc5027466403961782174c Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 17:39:43 +0200 Subject: [PATCH 84/96] Extracted CompressorHolder from Map*.Implementation --- .../com/mojang/serialization/Compressable.java | 7 +++++++ .../mojang/serialization/CompressorHolder.java | 17 +++++++++++++++++ .../java/com/mojang/serialization/MapCodec.java | 2 +- .../com/mojang/serialization/MapDecoder.java | 11 +---------- .../com/mojang/serialization/MapEncoder.java | 12 +----------- 5 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/mojang/serialization/Compressable.java create mode 100644 src/main/java/com/mojang/serialization/CompressorHolder.java diff --git a/src/main/java/com/mojang/serialization/Compressable.java b/src/main/java/com/mojang/serialization/Compressable.java new file mode 100644 index 00000000..afc9f2d0 --- /dev/null +++ b/src/main/java/com/mojang/serialization/Compressable.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +public interface Compressable extends Keyable { + MapCompressor compressor(final DynamicOps ops); +} diff --git a/src/main/java/com/mojang/serialization/CompressorHolder.java b/src/main/java/com/mojang/serialization/CompressorHolder.java new file mode 100644 index 00000000..4debfc18 --- /dev/null +++ b/src/main/java/com/mojang/serialization/CompressorHolder.java @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package com.mojang.serialization; + +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; + +import java.util.Map; + +public abstract class CompressorHolder implements Compressable { + private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); + + @SuppressWarnings("unchecked") + @Override + public MapCompressor compressor(final DynamicOps ops) { + return (MapCompressor) compressors.computeIfAbsent(ops, k -> new MapCompressor<>(ops, keys(ops))); + } +} diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 074d464e..cf6e3b95 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -13,7 +13,7 @@ import java.util.function.UnaryOperator; import java.util.stream.Stream; -public abstract class MapCodec extends MapDecoder.Implementation implements MapEncoder { +public abstract class MapCodec extends CompressorHolder implements MapDecoder, MapEncoder { public final RecordCodecBuilder forGetter(final Function getter) { return RecordCodecBuilder.of(getter, this); } diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index bd508ed0..1ceaf2b4 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -3,12 +3,10 @@ package com.mojang.serialization; import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; @@ -153,13 +151,6 @@ public String toString() { }; } - abstract class Implementation implements MapDecoder { - private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); - - @SuppressWarnings("unchecked") - @Override - public MapCompressor compressor(final DynamicOps ops) { - return (MapCompressor) compressors.computeIfAbsent(ops, k -> new MapCompressor<>(ops, keys(ops))); - } + abstract class Implementation extends CompressorHolder implements MapDecoder { } } diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index cb606d4e..63910591 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -2,11 +2,8 @@ // Licensed under the MIT license. package com.mojang.serialization; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; - import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.function.Function; import java.util.stream.Stream; @@ -99,14 +96,7 @@ public String toString() { }; } - abstract class Implementation implements MapEncoder { - private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); - - @SuppressWarnings("unchecked") - @Override - public MapCompressor compressor(final DynamicOps ops) { - return (MapCompressor) compressors.computeIfAbsent(ops, k -> new MapCompressor<>(ops, keys(ops))); - } + abstract class Implementation extends CompressorHolder implements MapEncoder { } static RecordBuilder makeCompressedBuilder(final DynamicOps ops, final MapCompressor compressor) { From ca210512b189638ff572afb78f7acf23e78b7c77 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 17:44:04 +0200 Subject: [PATCH 85/96] Inlined redundant self constants --- .../java/com/mojang/serialization/Codec.java | 15 ++++----- .../com/mojang/serialization/Decoder.java | 20 +++++------- .../com/mojang/serialization/Encoder.java | 15 ++++----- .../com/mojang/serialization/MapCodec.java | 18 +++++------ .../com/mojang/serialization/MapDecoder.java | 31 ++++++++----------- .../com/mojang/serialization/MapEncoder.java | 26 +++++++--------- 6 files changed, 52 insertions(+), 73 deletions(-) diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index d6f2de39..a3591deb 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -34,21 +34,20 @@ public interface Codec extends Encoder, Decoder { @Override default Codec withLifecycle(final Lifecycle lifecycle) { - final Codec self = this; return new Codec() { @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return self.encode(input, ops, prefix).setLifecycle(lifecycle); + return Codec.this.encode(input, ops, prefix).setLifecycle(lifecycle); } @Override public DataResult> decode(final DynamicOps ops, final T input) { - return self.decode(ops, input).setLifecycle(lifecycle); + return Codec.this.decode(ops, input).setLifecycle(lifecycle); } @Override public String toString() { - return self.toString(); + return Codec.this.toString(); } }; } @@ -207,22 +206,20 @@ interface ResultFunction { } default Codec mapResult(final ResultFunction function) { - final Codec self = this; - return new Codec() { @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return function.coApply(ops, input, self.encode(input, ops, prefix)); + return function.coApply(ops, input, Codec.this.encode(input, ops, prefix)); } @Override public DataResult> decode(final DynamicOps ops, final T input) { - return function.apply(ops, input, self.decode(ops, input)); + return function.apply(ops, input, Codec.this.decode(ops, input)); } @Override public String toString() { - return self + "[mapResult " + function + "]"; + return Codec.this + "[mapResult " + function + "]"; } }; } diff --git a/src/main/java/com/mojang/serialization/Decoder.java b/src/main/java/com/mojang/serialization/Decoder.java index 274f4fe0..af768219 100644 --- a/src/main/java/com/mojang/serialization/Decoder.java +++ b/src/main/java/com/mojang/serialization/Decoder.java @@ -43,61 +43,57 @@ default MapDecoder fieldOf(final String name) { } default Decoder flatMap(final Function> function) { - final Decoder self = this; return new Decoder() { @Override public DataResult> decode(final DynamicOps ops, final T input) { - return self.decode(ops, input).flatMap(p -> function.apply(p.getFirst()).map(r -> Pair.of(r, p.getSecond()))); + return Decoder.this.decode(ops, input).flatMap(p -> function.apply(p.getFirst()).map(r -> Pair.of(r, p.getSecond()))); } @Override public String toString() { - return self.toString() + "[flatMapped]"; + return Decoder.this.toString() + "[flatMapped]"; } }; } default Decoder map(final Function function) { - final Decoder self = this; return new Decoder() { @Override public DataResult> decode(final DynamicOps ops, final T input) { - return self.decode(ops, input).map(p -> p.mapFirst(function)); + return Decoder.this.decode(ops, input).map(p -> p.mapFirst(function)); } @Override public String toString() { - return self.toString() + "[mapped]"; + return Decoder.this.toString() + "[mapped]"; } }; } default Decoder promotePartial(final Consumer onError) { - final Decoder self = this; return new Decoder() { @Override public DataResult> decode(final DynamicOps ops, final T input) { - return self.decode(ops, input).promotePartial(onError); + return Decoder.this.decode(ops, input).promotePartial(onError); } @Override public String toString() { - return self.toString() + "[promotePartial]"; + return Decoder.this.toString() + "[promotePartial]"; } }; } default Decoder withLifecycle(final Lifecycle lifecycle) { - final Decoder self = this; return new Decoder() { @Override public DataResult> decode(final DynamicOps ops, final T input) { - return self.decode(ops, input).setLifecycle(lifecycle); + return Decoder.this.decode(ops, input).setLifecycle(lifecycle); } @Override public String toString() { - return self.toString(); + return Decoder.this.toString(); } }; } diff --git a/src/main/java/com/mojang/serialization/Encoder.java b/src/main/java/com/mojang/serialization/Encoder.java index b4809be1..fc76059b 100644 --- a/src/main/java/com/mojang/serialization/Encoder.java +++ b/src/main/java/com/mojang/serialization/Encoder.java @@ -19,46 +19,43 @@ default MapEncoder fieldOf(final String name) { } default Encoder comap(final Function function) { - final Encoder self = this; return new Encoder() { @Override public DataResult encode(final B input, final DynamicOps ops, final T prefix) { - return self.encode(function.apply(input), ops, prefix); + return Encoder.this.encode(function.apply(input), ops, prefix); } @Override public String toString() { - return self.toString() + "[comapped]"; + return Encoder.this.toString() + "[comapped]"; } }; } default Encoder flatComap(final Function> function) { - final Encoder self = this; return new Encoder() { @Override public DataResult encode(final B input, final DynamicOps ops, final T prefix) { - return function.apply(input).flatMap(a -> self.encode(a, ops, prefix)); + return function.apply(input).flatMap(a -> Encoder.this.encode(a, ops, prefix)); } @Override public String toString() { - return self.toString() + "[flatComapped]"; + return Encoder.this.toString() + "[flatComapped]"; } }; } default Encoder withLifecycle(final Lifecycle lifecycle) { - final Encoder self = this; return new Encoder() { @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return self.encode(input, ops, prefix).setLifecycle(lifecycle); + return Encoder.this.encode(input, ops, prefix).setLifecycle(lifecycle); } @Override public String toString() { - return self.toString(); + return Encoder.this.toString(); } }; } diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index cf6e3b95..12bc6684 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -52,27 +52,26 @@ public MapCodec fieldOf(final String name) { @Override public MapCodec withLifecycle(final Lifecycle lifecycle) { - final MapCodec self = this; return new MapCodec() { @Override public Stream keys(final DynamicOps ops) { - return self.keys(ops); + return MapCodec.this.keys(ops); } @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - return self.decode(ops, input).setLifecycle(lifecycle); + return MapCodec.this.decode(ops, input).setLifecycle(lifecycle); } @Override public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { - return self.encode(input, ops, prefix).setLifecycle(lifecycle); + return MapCodec.this.encode(input, ops, prefix).setLifecycle(lifecycle); } @Override public String toString() { - return self.toString(); + return MapCodec.this.toString(); } }; } @@ -172,27 +171,26 @@ interface ResultFunction { } private MapCodec mapResult(final MapCodec.ResultFunction function) { - final MapCodec self = this; return new MapCodec() { @Override public Stream keys(final DynamicOps ops) { - return self.keys(ops); + return MapCodec.this.keys(ops); } @Override public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { - return function.coApply(ops, input, self.encode(input, ops, prefix)); + return function.coApply(ops, input, MapCodec.this.encode(input, ops, prefix)); } @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - return function.apply(ops, input, self.decode(ops, input)); + return function.apply(ops, input, MapCodec.this.decode(ops, input)); } @Override public String toString() { - return self + "[mapResult " + function + "]"; + return MapCodec.this + "[mapResult " + function + "]"; } }; } diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index 1ceaf2b4..f8a3e707 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -55,7 +55,6 @@ public Stream> entries() { MapCompressor compressor(DynamicOps ops); default Decoder decoder() { - final MapDecoder self = this; return new Decoder() { @Override public DataResult> decode(final DynamicOps ops, final T input) { @@ -64,89 +63,85 @@ public DataResult> decode(final DynamicOps ops, final T input) @Override public String toString() { - return self.toString(); + return MapDecoder.this.toString(); } }; } default MapDecoder flatMap(final Function> function) { - final MapDecoder self = this; return new Implementation() { @Override public Stream keys(final DynamicOps ops) { - return self.keys(ops); + return MapDecoder.this.keys(ops); } @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - return self.decode(ops, input).flatMap(b -> function.apply(b).map(Function.identity())); + return MapDecoder.this.decode(ops, input).flatMap(b -> function.apply(b).map(Function.identity())); } @Override public String toString() { - return self.toString() + "[flatMapped]"; + return MapDecoder.this.toString() + "[flatMapped]"; } }; } default MapDecoder map(final Function function) { - final MapDecoder self = this; return new Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - return self.decode(ops, input).map(function); + return MapDecoder.this.decode(ops, input).map(function); } @Override public Stream keys(final DynamicOps ops) { - return self.keys(ops); + return MapDecoder.this.keys(ops); } @Override public String toString() { - return self.toString() + "[mapped]"; + return MapDecoder.this.toString() + "[mapped]"; } }; } default MapDecoder ap(final MapDecoder> decoder) { - final MapDecoder self = this; return new Implementation() { @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - return self.decode(ops, input).flatMap(f -> + return MapDecoder.this.decode(ops, input).flatMap(f -> decoder.decode(ops, input).map(e -> e.apply(f)) ); } @Override public Stream keys(final DynamicOps ops) { - return Stream.concat(self.keys(ops), decoder.keys(ops)); + return Stream.concat(MapDecoder.this.keys(ops), decoder.keys(ops)); } @Override public String toString() { - return decoder.toString() + " * " + self.toString(); + return decoder.toString() + " * " + MapDecoder.this.toString(); } }; } default MapDecoder withLifecycle(final Lifecycle lifecycle) { - final MapDecoder self = this; return new MapDecoder.Implementation() { @Override public Stream keys(final DynamicOps ops) { - return self.keys(ops); + return MapDecoder.this.keys(ops); } @Override public DataResult decode(final DynamicOps ops, final MapLike input) { - return self.decode(ops, input).setLifecycle(lifecycle); + return MapDecoder.this.decode(ops, input).setLifecycle(lifecycle); } @Override public String toString() { - return self.toString(); + return MapDecoder.this.toString(); } }; } diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index 63910591..c03e8249 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -20,78 +20,74 @@ default RecordBuilder compressedBuilder(final DynamicOps ops) { MapCompressor compressor(final DynamicOps ops); default MapEncoder comap(final Function function) { - final MapEncoder self = this; return new MapEncoder.Implementation() { @Override public RecordBuilder encode(final B input, final DynamicOps ops, final RecordBuilder prefix) { - return self.encode(function.apply(input), ops, prefix); + return MapEncoder.this.encode(function.apply(input), ops, prefix); } @Override public Stream keys(final DynamicOps ops) { - return self.keys(ops); + return MapEncoder.this.keys(ops); } @Override public String toString() { - return self.toString() + "[comapped]"; + return MapEncoder.this.toString() + "[comapped]"; } }; } default MapEncoder flatComap(final Function> function) { - final MapEncoder self = this; return new MapEncoder.Implementation() { @Override public Stream keys(final DynamicOps ops) { - return self.keys(ops); + return MapEncoder.this.keys(ops); } @Override public RecordBuilder encode(final B input, final DynamicOps ops, final RecordBuilder prefix) { final DataResult aResult = function.apply(input); final RecordBuilder builder = prefix.withErrorsFrom(aResult); - return aResult.map(r -> self.encode(r, ops, builder)).result().orElse(builder); + return aResult.map(r -> MapEncoder.this.encode(r, ops, builder)).result().orElse(builder); } @Override public String toString() { - return self.toString() + "[flatComapped]"; + return MapEncoder.this.toString() + "[flatComapped]"; } }; } default Encoder encoder() { - final MapEncoder self = this; return new Encoder() { @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { - return self.encode(input, ops, compressedBuilder(ops)).build(prefix); + return MapEncoder.this.encode(input, ops, compressedBuilder(ops)).build(prefix); } @Override public String toString() { - return self.toString(); + return MapEncoder.this.toString(); } }; } default MapEncoder withLifecycle(final Lifecycle lifecycle) { - final MapEncoder self = this; return new Implementation() { @Override public Stream keys(final DynamicOps ops) { - return self.keys(ops); + return MapEncoder.this.keys(ops); } @Override public RecordBuilder encode(final A input, final DynamicOps ops, final RecordBuilder prefix) { - return self.encode(input, ops, prefix).setLifecycle(lifecycle); + return MapEncoder.this.encode(input, ops, prefix).setLifecycle(lifecycle); } @Override public String toString() { - return self.toString(); + return MapEncoder.this.toString(); } }; } From 5d34fe899306d456723469b6ee883153a9500eca Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Mon, 11 May 2020 17:58:29 +0200 Subject: [PATCH 86/96] MapCompressor -> KeyCompressor --- src/main/java/com/mojang/serialization/Compressable.java | 2 +- .../java/com/mojang/serialization/CompressorHolder.java | 6 +++--- .../{MapCompressor.java => KeyCompressor.java} | 4 ++-- src/main/java/com/mojang/serialization/MapDecoder.java | 4 ++-- src/main/java/com/mojang/serialization/MapEncoder.java | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) rename src/main/java/com/mojang/serialization/{MapCompressor.java => KeyCompressor.java} (93%) diff --git a/src/main/java/com/mojang/serialization/Compressable.java b/src/main/java/com/mojang/serialization/Compressable.java index afc9f2d0..433d12ae 100644 --- a/src/main/java/com/mojang/serialization/Compressable.java +++ b/src/main/java/com/mojang/serialization/Compressable.java @@ -3,5 +3,5 @@ package com.mojang.serialization; public interface Compressable extends Keyable { - MapCompressor compressor(final DynamicOps ops); + KeyCompressor compressor(final DynamicOps ops); } diff --git a/src/main/java/com/mojang/serialization/CompressorHolder.java b/src/main/java/com/mojang/serialization/CompressorHolder.java index 4debfc18..362e3f59 100644 --- a/src/main/java/com/mojang/serialization/CompressorHolder.java +++ b/src/main/java/com/mojang/serialization/CompressorHolder.java @@ -7,11 +7,11 @@ import java.util.Map; public abstract class CompressorHolder implements Compressable { - private final Map, MapCompressor> compressors = new Object2ObjectArrayMap<>(); + private final Map, KeyCompressor> compressors = new Object2ObjectArrayMap<>(); @SuppressWarnings("unchecked") @Override - public MapCompressor compressor(final DynamicOps ops) { - return (MapCompressor) compressors.computeIfAbsent(ops, k -> new MapCompressor<>(ops, keys(ops))); + public KeyCompressor compressor(final DynamicOps ops) { + return (KeyCompressor) compressors.computeIfAbsent(ops, k -> new KeyCompressor<>(ops, keys(ops))); } } diff --git a/src/main/java/com/mojang/serialization/MapCompressor.java b/src/main/java/com/mojang/serialization/KeyCompressor.java similarity index 93% rename from src/main/java/com/mojang/serialization/MapCompressor.java rename to src/main/java/com/mojang/serialization/KeyCompressor.java index 9ba38e1e..76422852 100644 --- a/src/main/java/com/mojang/serialization/MapCompressor.java +++ b/src/main/java/com/mojang/serialization/KeyCompressor.java @@ -9,14 +9,14 @@ import java.util.stream.Stream; -public final class MapCompressor { +public final class KeyCompressor { private final Int2ObjectMap decompress = new Int2ObjectArrayMap<>(); private final Object2IntMap compress = new Object2IntArrayMap<>(); private final Object2IntMap compressString = new Object2IntArrayMap<>(); private final int size; private final DynamicOps ops; - public MapCompressor(final DynamicOps ops, final Stream keyStream) { + public KeyCompressor(final DynamicOps ops, final Stream keyStream) { this.ops = ops; compressString.defaultReturnValue(-1); diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index f8a3e707..8a3ccae6 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -24,7 +24,7 @@ default DataResult compressedDecode(final DynamicOps ops, final T inpu return DataResult.error("Input is not a list"); } - final MapCompressor compressor = compressor(ops); + final KeyCompressor compressor = compressor(ops); final List entries = new ArrayList<>(); inputList.get().accept(entries::add); @@ -52,7 +52,7 @@ public Stream> entries() { return ops.getMap(input).setLifecycle(Lifecycle.stable()).flatMap(map -> decode(ops, map)); } - MapCompressor compressor(DynamicOps ops); + KeyCompressor compressor(DynamicOps ops); default Decoder decoder() { return new Decoder() { diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index c03e8249..f246da53 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -17,7 +17,7 @@ default RecordBuilder compressedBuilder(final DynamicOps ops) { return ops.mapBuilder(); } - MapCompressor compressor(final DynamicOps ops); + KeyCompressor compressor(final DynamicOps ops); default MapEncoder comap(final Function function) { return new MapEncoder.Implementation() { @@ -95,7 +95,7 @@ public String toString() { abstract class Implementation extends CompressorHolder implements MapEncoder { } - static RecordBuilder makeCompressedBuilder(final DynamicOps ops, final MapCompressor compressor) { + static RecordBuilder makeCompressedBuilder(final DynamicOps ops, final KeyCompressor compressor) { class CompressedRecordBuilder extends RecordBuilder.AbstractBuilder> { private CompressedRecordBuilder() { super(ops); From 99b04975ce7ab198751f537730a5f7e6c7fe1d3d Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 12 May 2020 09:24:15 +0200 Subject: [PATCH 87/96] Cleaned up RecordBuilder hierarchy --- .../com/mojang/serialization/MapEncoder.java | 8 +- .../mojang/serialization/RecordBuilder.java | 78 ++++++++++--------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index f246da53..efa70725 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -96,7 +96,7 @@ abstract class Implementation extends CompressorHolder implements MapEncoder< } static RecordBuilder makeCompressedBuilder(final DynamicOps ops, final KeyCompressor compressor) { - class CompressedRecordBuilder extends RecordBuilder.AbstractBuilder> { + class CompressedRecordBuilder extends RecordBuilder.AbstractUniversalBuilder> { private CompressedRecordBuilder() { super(ops); } @@ -116,12 +116,6 @@ protected List append(final T key, final T value, final List builder) { return builder; } - @Override - protected List append(final String key, final T value, final List builder) { - builder.set(compressor.compress(key), value); - return builder; - } - @Override protected DataResult build(final List builder, final T prefix) { return ops().mergeToList(prefix, builder); diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 4e45bbc6..defde958 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -39,11 +39,11 @@ default RecordBuilder add(final String key, final E value, final Encoder< return add(key, encoder.encodeStart(ops(), value)); } - abstract class AbstractStringBuilder implements RecordBuilder { + abstract class AbstractBuilder implements RecordBuilder { private final DynamicOps ops; protected DataResult builder = DataResult.success(initBuilder(), Lifecycle.stable()); - protected AbstractStringBuilder(final DynamicOps ops) { + protected AbstractBuilder(final DynamicOps ops) { this.ops = ops; } @@ -56,6 +56,39 @@ public DynamicOps ops() { protected abstract DataResult build(final R builder, final T prefix); + @Override + public DataResult build(final T prefix) { + final DataResult result = builder.flatMap(b -> build(b, prefix)); + builder = DataResult.success(initBuilder(), Lifecycle.stable()); + return result; + } + + @Override + public RecordBuilder withErrorsFrom(final DataResult result) { + builder = builder.flatMap(v -> result.map(r -> v)); + return this; + } + + @Override + public RecordBuilder setLifecycle(final Lifecycle lifecycle) { + builder = builder.setLifecycle(lifecycle); + return this; + } + + @Override + public RecordBuilder mapError(final UnaryOperator onError) { + builder = builder.mapError(onError); + return this; + } + } + + abstract class AbstractStringBuilder extends AbstractBuilder { + protected DataResult builder = DataResult.success(initBuilder(), Lifecycle.stable()); + + protected AbstractStringBuilder(final DynamicOps ops) { + super(ops); + } + protected abstract R append(String key, T value, R builder); @Override @@ -70,16 +103,9 @@ public RecordBuilder add(final String key, final DataResult value) { return this; } - @Override - public DataResult build(final T prefix) { - final DataResult result = builder.flatMap(b -> build(b, prefix)); - builder = DataResult.success(initBuilder(), Lifecycle.stable()); - return result; - } - @Override public RecordBuilder add(final T key, final T value) { - builder = ops.getStringValue(key).flatMap(k -> { + builder = ops().getStringValue(key).flatMap(k -> { add(k, value); return builder; }); @@ -88,7 +114,7 @@ public RecordBuilder add(final T key, final T value) { @Override public RecordBuilder add(final T key, final DataResult value) { - builder = ops.getStringValue(key).flatMap(k -> { + builder = ops().getStringValue(key).flatMap(k -> { add(k, value); return builder; }); @@ -97,44 +123,22 @@ public RecordBuilder add(final T key, final DataResult value) { @Override public RecordBuilder add(final DataResult key, final DataResult value) { - builder = key.flatMap(ops::getStringValue).flatMap(k -> { + builder = key.flatMap(ops()::getStringValue).flatMap(k -> { add(k, value); return builder; }); return this; } - @Override - public RecordBuilder withErrorsFrom(final DataResult result) { - builder = builder.flatMap(v -> result.map(r -> v)); - return this; - } - - @Override - public RecordBuilder setLifecycle(final Lifecycle lifecycle) { - builder = builder.setLifecycle(lifecycle); - return this; - } - - @Override - public RecordBuilder mapError(final UnaryOperator onError) { - builder = builder.mapError(onError); - return this; - } } - abstract class AbstractBuilder extends AbstractStringBuilder { - protected AbstractBuilder(final DynamicOps ops) { + abstract class AbstractUniversalBuilder extends AbstractBuilder { + protected AbstractUniversalBuilder(final DynamicOps ops) { super(ops); } protected abstract R append(T key, T value, R builder); - @Override - protected R append(final String key, final T value, final R builder) { - return append(ops().createString(key), value, builder); - } - @Override public RecordBuilder add(final T key, final T value) { builder = builder.map(b -> append(key, value, b)); @@ -154,7 +158,7 @@ public RecordBuilder add(final DataResult key, final DataResult value) } } - final class MapBuilder extends AbstractBuilder> { + final class MapBuilder extends AbstractUniversalBuilder> { public MapBuilder(final DynamicOps ops) { super(ops); } From 45a1715a05c0fe4873ad9183c0601d972b8a0331 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 12 May 2020 09:39:56 +0200 Subject: [PATCH 88/96] Use Stream.reduce in BaseMapCodec --- .../serialization/codecs/BaseMapCodec.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java index 012748d0..0cdeb8ba 100644 --- a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java @@ -14,7 +14,6 @@ import com.mojang.serialization.RecordBuilder; import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; public interface BaseMapCodec { @@ -25,25 +24,28 @@ public interface BaseMapCodec { default DataResult> decode(final DynamicOps ops, final MapLike input) { final ImmutableMap.Builder read = ImmutableMap.builder(); final ImmutableList.Builder> failed = ImmutableList.builder(); - final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); - input.entries().forEach(pair -> { - final DataResult k = keyCodec().parse(ops, pair.getFirst()); - final DataResult v = elementCodec().parse(ops, pair.getSecond()); + final DataResult result = input.entries().reduce( + DataResult.success(Unit.INSTANCE, Lifecycle.stable()), + (r, pair) -> { + final DataResult k = keyCodec().parse(ops, pair.getFirst()); + final DataResult v = elementCodec().parse(ops, pair.getSecond()); - final DataResult> entry = k.apply2stable(Pair::of, v); - entry.error().ifPresent(e -> failed.add(pair)); + final DataResult> entry = k.apply2stable(Pair::of, v); + entry.error().ifPresent(e -> failed.add(pair)); - result.set(result.get().apply2stable((u, p) -> { - read.put(p.getFirst(), p.getSecond()); - return u; - }, entry)); - }); + return r.apply2stable((u, p) -> { + read.put(p.getFirst(), p.getSecond()); + return u; + }, entry); + }, + (r1, r2) -> r1.apply2stable((u1, u2) -> u1, r2) + ); final Map elements = read.build(); final T errors = ops.createMap(failed.build().stream()); - return result.get().map(unit -> elements).setPartial(elements).mapError(e -> e + " missed input: " + errors); + return result.map(unit -> elements).setPartial(elements).mapError(e -> e + " missed input: " + errors); } default RecordBuilder encode(final Map input, final DynamicOps ops, final RecordBuilder prefix) { From 5fdd9841950b2606a6ff6b183e6396ce12f45279 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 12 May 2020 10:59:46 +0200 Subject: [PATCH 89/96] AtomicReference -> MutableObject --- .../java/com/mojang/datafixers/types/Type.java | 15 ++++++++------- .../com/mojang/serialization/DynamicLike.java | 9 +++++---- .../com/mojang/serialization/DynamicOps.java | 17 +++++++++-------- .../serialization/codecs/CompoundListCodec.java | 9 +++++---- .../mojang/serialization/codecs/ListCodec.java | 11 ++++++----- 5 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/types/Type.java b/src/main/java/com/mojang/datafixers/types/Type.java index a988ed54..263ae34e 100644 --- a/src/main/java/com/mojang/datafixers/types/Type.java +++ b/src/main/java/com/mojang/datafixers/types/Type.java @@ -5,9 +5,6 @@ import com.google.common.collect.Maps; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.Dynamic; import com.mojang.datafixers.FieldFinder; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.OpticFinder; @@ -25,7 +22,11 @@ import com.mojang.datafixers.types.templates.TypeTemplate; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; +import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.tuple.Triple; import javax.annotation.Nullable; @@ -33,7 +34,6 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; public abstract class Type implements App { private static final Map, TypeRewriteRule, PointFreeRule>, CompletableFuture>>> PENDING_REWRITE_CACHE = Maps.newConcurrentMap(); @@ -177,15 +177,16 @@ private DataResult capWrite(final DynamicOps ops, final Type exp if (rewrite != null) { return (Optional>) rewrite; } - final AtomicReference>>> ref = new AtomicReference<>(); + // TODO: AtomicReference.getPlain/setPlain in java9+ + final MutableObject>>> ref = new MutableObject<>(); final CompletableFuture>> pending = PENDING_REWRITE_CACHE.computeIfAbsent(key, k -> { final CompletableFuture>> value = new CompletableFuture<>(); - ref.set(value); + ref.setValue(value); return value; }); - if (ref.get() != null) { + if (ref.getValue() != null) { Optional> result = rule.rewrite(this).flatMap(r -> r.view().rewrite(fRule).map(view -> RewriteResult.create(view, r.recData()))); REWRITE_CACHE.put(key, result); pending.complete(result); diff --git a/src/main/java/com/mojang/serialization/DynamicLike.java b/src/main/java/com/mojang/serialization/DynamicLike.java index 3adc5b7a..768cc53b 100644 --- a/src/main/java/com/mojang/serialization/DynamicLike.java +++ b/src/main/java/com/mojang/serialization/DynamicLike.java @@ -8,11 +8,11 @@ import com.mojang.datafixers.kinds.ListBox; import com.mojang.datafixers.util.Function3; import com.mojang.datafixers.util.Pair; +import org.apache.commons.lang3.mutable.MutableObject; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -89,9 +89,10 @@ public DataResult>> readMap(final Decoder keyDecoder, public DataResult readMap(final DataResult empty, final Function3, Dynamic, DataResult> combiner) { return asMapOpt().flatMap(stream -> { - final AtomicReference> result = new AtomicReference<>(empty); - stream.forEach(p -> result.set(result.get().flatMap(r -> combiner.apply(r, p.getFirst(), p.getSecond())))); - return result.get(); + // TODO: AtomicReference.getPlain/setPlain in java9+ + final MutableObject> result = new MutableObject<>(empty); + stream.forEach(p -> result.setValue(result.getValue().flatMap(r -> combiner.apply(r, p.getFirst(), p.getSecond())))); + return result.getValue(); }); } diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index 165f9fa0..be316292 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -3,16 +3,15 @@ package com.mojang.serialization; import com.google.common.collect.ImmutableMap; -import com.google.gson.JsonElement; import com.mojang.datafixers.util.Function3; import com.mojang.datafixers.util.Pair; +import org.apache.commons.lang3.mutable.MutableObject; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; @@ -102,12 +101,13 @@ default DataResult mergeToMap(final T map, final Map values) { } default DataResult mergeToMap(final T map, final MapLike values) { - final AtomicReference> result = new AtomicReference<>(DataResult.success(map)); + // TODO: AtomicReference.getPlain/setPlain in java9+ + final MutableObject> result = new MutableObject<>(DataResult.success(map)); values.entries().forEach(entry -> - result.set(result.get().flatMap(r -> mergeToMap(r, entry.getFirst(), entry.getSecond()))) + result.setValue(result.getValue().flatMap(r -> mergeToMap(r, entry.getFirst(), entry.getSecond()))) ); - return result.get(); + return result.getValue(); } /** @@ -256,9 +256,10 @@ default DataResult map(final Map map, final T prefix, final Func default DataResult readMap(final T input, final DataResult empty, final Function3> combiner) { return getMapValues(input).flatMap(stream -> { - final AtomicReference> result = new AtomicReference<>(empty); - stream.forEach(p -> result.set(result.get().flatMap(r -> combiner.apply(r, p.getFirst(), p.getSecond())))); - return result.get(); + // TODO: AtomicReference.getPlain/setPlain in java9+ + final MutableObject> result = new MutableObject<>(empty); + stream.forEach(p -> result.setValue(result.getValue().flatMap(r -> combiner.apply(r, p.getFirst(), p.getSecond())))); + return result.getValue(); }); } diff --git a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java index cba1ca34..17731489 100644 --- a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java @@ -11,10 +11,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Lifecycle; import com.mojang.serialization.RecordBuilder; +import org.apache.commons.lang3.mutable.MutableObject; import java.util.List; import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; public final class CompoundListCodec implements Codec>> { private final Codec keyCodec; @@ -31,7 +31,8 @@ public DataResult>, T>> decode(final DynamicOps ops, final ImmutableList.Builder> read = ImmutableList.builder(); final ImmutableMap.Builder failed = ImmutableMap.builder(); - final AtomicReference> result = new AtomicReference<>(DataResult.success(Unit.INSTANCE, Lifecycle.experimental())); + // TODO: AtomicReference.getPlain/setPlain in java9+ + final MutableObject> result = new MutableObject<>(DataResult.success(Unit.INSTANCE, Lifecycle.experimental())); map.accept((key, value) -> { final DataResult k = keyCodec.parse(ops, key); @@ -41,7 +42,7 @@ public DataResult>, T>> decode(final DynamicOps ops, readEntry.error().ifPresent(e -> failed.put(key, value)); - result.set(result.get().apply2stable((u, e) -> { + result.setValue(result.getValue().apply2stable((u, e) -> { read.add(e); return u; }, readEntry)); @@ -52,7 +53,7 @@ public DataResult>, T>> decode(final DynamicOps ops, final Pair>, T> pair = Pair.of(elements, errors); - return result.get().map(unit -> pair).setPartial(pair); + return result.getValue().map(unit -> pair).setPartial(pair); }); } diff --git a/src/main/java/com/mojang/serialization/codecs/ListCodec.java b/src/main/java/com/mojang/serialization/codecs/ListCodec.java index 18c250e2..46e20477 100644 --- a/src/main/java/com/mojang/serialization/codecs/ListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/ListCodec.java @@ -10,10 +10,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Lifecycle; import com.mojang.serialization.ListBuilder; +import org.apache.commons.lang3.mutable.MutableObject; import java.util.List; import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; public final class ListCodec implements Codec> { private final Codec elementCodec; @@ -38,13 +38,14 @@ public DataResult, T>> decode(final DynamicOps ops, final T return ops.getList(input).setLifecycle(Lifecycle.stable()).flatMap(stream -> { final ImmutableList.Builder read = ImmutableList.builder(); final ImmutableList.Builder failed = ImmutableList.builder(); - final AtomicReference> result = - new AtomicReference<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); + // TODO: AtomicReference.getPlain/setPlain in java9+ + final MutableObject> result = + new MutableObject<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); stream.accept(t -> { final DataResult> element = elementCodec.decode(ops, t); element.error().ifPresent(e -> failed.add(t)); - result.set(result.get().apply2stable((r, v) -> { + result.setValue(result.getValue().apply2stable((r, v) -> { read.add(v.getFirst()); return r; }, element)); @@ -55,7 +56,7 @@ public DataResult, T>> decode(final DynamicOps ops, final T final Pair, T> pair = Pair.of(elements, errors); - return result.get().map(unit -> pair).setPartial(pair); + return result.getValue().map(unit -> pair).setPartial(pair); }); } From 56fdd77509061f80080e536f14f0829a871d8abf Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 12 May 2020 15:44:56 +0200 Subject: [PATCH 90/96] Fixed extraneous field --- src/main/java/com/mojang/serialization/RecordBuilder.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index defde958..37a9e4cf 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -83,8 +83,6 @@ public RecordBuilder mapError(final UnaryOperator onError) { } abstract class AbstractStringBuilder extends AbstractBuilder { - protected DataResult builder = DataResult.success(initBuilder(), Lifecycle.stable()); - protected AbstractStringBuilder(final DynamicOps ops) { super(ops); } From d6122437466ffd37e01c395d789fea51dbf6efc4 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 12 May 2020 16:52:26 +0200 Subject: [PATCH 91/96] Added roundrip codec test --- build.gradle | 1 + .../com/mojang/serialization/DataResult.java | 4 + .../mojang/serialization/RoundtripTest.java | 284 ++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 src/test/java/com/mojang/serialization/RoundtripTest.java diff --git a/build.gradle b/build.gradle index 9c7b9e55..5260b33a 100644 --- a/build.gradle +++ b/build.gradle @@ -39,6 +39,7 @@ dependencies { compile 'com.google.guava:guava:21.0' compile 'org.apache.commons:commons-lang3:3.5' compile 'it.unimi.dsi:fastutil:7.1.0' + testCompile 'junit:junit-dep:4.10' } task sourcesJar(type: Jar) { diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 2a42cc0a..5d0485ff 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -54,6 +54,10 @@ public static DataResult error(final String message, final Lifecycle life return new DataResult<>(Either.right(new PartialResult<>(message, Optional.empty())), lifecycle); } + public static Function> partialGet(final Function partialGet, final Supplier errorPrefix) { + return name -> Optional.ofNullable(partialGet.apply(name)).map(DataResult::success).orElseGet(() -> error(errorPrefix.get() + name)); + } + private static DataResult create(final Either> result, final Lifecycle lifecycle) { return new DataResult<>(result, lifecycle); } diff --git a/src/test/java/com/mojang/serialization/RoundtripTest.java b/src/test/java/com/mojang/serialization/RoundtripTest.java new file mode 100644 index 00000000..6b529d16 --- /dev/null +++ b/src/test/java/com/mojang/serialization/RoundtripTest.java @@ -0,0 +1,284 @@ +package com.mojang.serialization; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.junit.Assert.assertEquals; + +public class RoundtripTest { + // Constructors, equals and hashcode are auto-generated + // TODO: switch to records in java 14+ + + private enum Day { + TUESDAY("tuesday", TuesdayData.CODEC), + WEDNESDAY("wednesday", WednesdayData.CODEC), + SUNDAY("sunday", SundayData.CODEC), + ; + + private static final Map BY_NAME = Arrays.stream(values()).collect(Collectors.toMap(v -> v.name, Function.identity())); + public static final Codec CODEC = Codec.STRING.comapFlatMap(DataResult.partialGet(BY_NAME::get, () -> "unknown day"), d -> d.name); + + private final String name; + private final Codec codec; + + Day(final String name, final Codec codec) { + this.name = name; + this.codec = codec.fieldOf("data").codec(); + } + + public Codec codec() { + return codec; + } + } + + interface DayData { + Codec CODEC = Day.CODEC.dispatch(DayData::type, Day::codec); + Day type(); + } + + private static final class TuesdayData implements DayData { + public static final Codec CODEC = Codec.INT.xmap(TuesdayData::new, d -> d.x); + + private final int x; + + private TuesdayData(final int x) { + this.x = x; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final TuesdayData that = (TuesdayData) o; + return x == that.x; + } + + @Override + public int hashCode() { + return Objects.hash(x); + } + + @Override + public Day type() { + return Day.TUESDAY; + } + } + + private static final class WednesdayData implements DayData { + public static final Codec CODEC = Codec.STRING.xmap(WednesdayData::new, d -> d.y); + + private final String y; + + private WednesdayData(final String y) { + this.y = y; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final WednesdayData that = (WednesdayData) o; + return Objects.equals(y, that.y); + } + + @Override + public int hashCode() { + return Objects.hash(y); + } + + @Override + public Day type() { + return Day.WEDNESDAY; + } + } + + private static final class SundayData implements DayData { + public static final Codec CODEC = Codec.FLOAT.xmap(SundayData::new, d -> d.z); + + private final float z; + + private SundayData(final float z) { + this.z = z; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final SundayData that = (SundayData) o; + return Float.compare(that.z, z) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(z); + } + + @Override + public Day type() { + return Day.SUNDAY; + } + } + + private static final class TestData { + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + Codec.FLOAT.fieldOf("a").forGetter(d -> d.a), + Codec.DOUBLE.fieldOf("b").forGetter(d -> d.b), + Codec.BYTE.fieldOf("c").forGetter(d -> d.c), + Codec.SHORT.fieldOf("d").forGetter(d -> d.d), + Codec.INT.fieldOf("e").forGetter(d -> d.e), + Codec.LONG.fieldOf("f").forGetter(d -> d.f), + Codec.BOOL.fieldOf("g").forGetter(d -> d.g), + Codec.STRING.fieldOf("h").forGetter(d -> d.h), + Codec.STRING.listOf().fieldOf("i").forGetter(d -> d.i), + Codec.unboundedMap(Codec.STRING, Codec.STRING).fieldOf("j").forGetter(d -> d.j), + Codec.compoundList(Codec.STRING, Codec.STRING).fieldOf("k").forGetter(d -> d.k), + DayData.CODEC.fieldOf("day_data").forGetter(d -> d.dayData) + ).apply(i, TestData::new)); + + private final float a; + private final double b; + private final byte c; + private final short d; + private final int e; + private final long f; + private final boolean g; + private final String h; + private final List i; + private final Map j; + private final List> k; + + private final DayData dayData; + + private TestData(final float a, final double b, final byte c, final short d, final int e, final long f, final boolean g, final String h, final List i, final Map j, final List> k, final DayData dayData) { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + this.e = e; + this.f = f; + this.g = g; + this.h = h; + this.i = i; + this.j = j; + this.k = k; + this.dayData = dayData; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final TestData testData = (TestData) o; + return Float.compare(testData.a, a) == 0 && + Double.compare(testData.b, b) == 0 && + c == testData.c && + d == testData.d && + e == testData.e && + f == testData.f && + g == testData.g && + h.equals(testData.h) && + i.equals(testData.i) && + j.equals(testData.j) && + k.equals(testData.k) && + dayData.equals(testData.dayData); + } + + @Override + public int hashCode() { + return Objects.hash(a, b, c, d, e, f, g, h, i, j, k, dayData); + } + } + + private static TestData makeRandomTestData() { + final Random random = new Random(4); + return new TestData( + random.nextFloat(), + random.nextDouble(), + (byte) random.nextInt(), + (short) random.nextInt(), + random.nextInt(), + random.nextLong(), + random.nextBoolean(), + Float.toString(random.nextFloat()), + IntStream.range(0, random.nextInt(100)) + .mapToObj(i -> Float.toString(random.nextFloat())) + .collect(Collectors.toList()), + IntStream.range(0, random.nextInt(100)) + .boxed() + .collect(Collectors.toMap( + i -> Float.toString(random.nextFloat()), + i -> Float.toString(random.nextFloat())) + ), + IntStream.range(0, random.nextInt(100)) + .mapToObj(i -> Pair.of(Float.toString(random.nextFloat()), Float.toString(random.nextFloat()))) + .collect(Collectors.toList() + ), + new WednesdayData("meetings lol")); + } + + private void testWriteRead(final DynamicOps ops) { + final TestData data = makeRandomTestData(); + + final DataResult encoded = TestData.CODEC.encodeStart(ops, data); + final DataResult decoded = encoded.flatMap(r -> TestData.CODEC.parse(ops, r)); + + assertEquals("read(write(x)) == x", DataResult.success(data), decoded); + } + + private void testReadWrite(final DynamicOps ops) { + final TestData data = makeRandomTestData(); + + final DataResult encoded = TestData.CODEC.encodeStart(ops, data); + final DataResult decoded = encoded.flatMap(r -> TestData.CODEC.parse(ops, r)); + final DataResult reEncoded = decoded.flatMap(r -> TestData.CODEC.encodeStart(ops, r)); + + assertEquals("write(read(x)) == x", encoded, reEncoded); + } + + @Test + public void testWriteReadNormal() { + testWriteRead(JsonOps.INSTANCE); + } + + @Test + public void testReadWriteNormal() { + testReadWrite(JsonOps.INSTANCE); + } + + @Test + public void testWriteReadCompressed() { + testWriteRead(JsonOps.COMPRESSED); + } + + @Test + public void testReadWriteCompressed() { + testReadWrite(JsonOps.COMPRESSED); + } +} \ No newline at end of file From ce9ec60cb2e793e3fae2153a2fc1de6b4ac6c9db Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 12 May 2020 16:54:26 +0200 Subject: [PATCH 92/96] Reordered primitive codec definitions --- .../java/com/mojang/serialization/Codec.java | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index a3591deb..fb99a570 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -379,60 +379,78 @@ default MapCodec partialDispatchMap(final String typeKey, final Function< return new KeyDispatchCodec<>(typeKey, this, type, codec); } - PrimitiveCodec FLOAT = new PrimitiveCodec() { + PrimitiveCodec BOOL = new PrimitiveCodec() { @Override - public DataResult read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { + return ops + .getBooleanValue(input); + } + + @Override + public T write(final DynamicOps ops, final Boolean value) { + return ops.createBoolean(value); + } + + @Override + public String toString() { + return "Bool"; + } + }; + + PrimitiveCodec BYTE = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(Number::floatValue); + .map(Number::byteValue); } @Override - public T write(final DynamicOps ops, final Float value) { - return ops.createFloat(value); + public T write(final DynamicOps ops, final Byte value) { + return ops.createByte(value); } @Override public String toString() { - return "Float"; + return "Byte"; } }; - PrimitiveCodec INT = new PrimitiveCodec() { + PrimitiveCodec SHORT = new PrimitiveCodec() { @Override - public DataResult read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(Number::intValue); + .map(Number::shortValue); } @Override - public T write(final DynamicOps ops, final Integer value) { - return ops.createInt(value); + public T write(final DynamicOps ops, final Short value) { + return ops.createShort(value); } @Override public String toString() { - return "Int"; + return "Short"; } }; - PrimitiveCodec BYTE = new PrimitiveCodec() { + PrimitiveCodec INT = new PrimitiveCodec() { @Override - public DataResult read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(Number::byteValue); + .map(Number::intValue); } @Override - public T write(final DynamicOps ops, final Byte value) { - return ops.createByte(value); + public T write(final DynamicOps ops, final Integer value) { + return ops.createInt(value); } @Override public String toString() { - return "Byte"; + return "Int"; } }; @@ -455,40 +473,41 @@ public String toString() { } }; - PrimitiveCodec BOOL = new PrimitiveCodec() { + PrimitiveCodec FLOAT = new PrimitiveCodec() { @Override - public DataResult read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops - .getBooleanValue(input); + .getNumberValue(input) + .map(Number::floatValue); } @Override - public T write(final DynamicOps ops, final Boolean value) { - return ops.createBoolean(value); + public T write(final DynamicOps ops, final Float value) { + return ops.createFloat(value); } @Override public String toString() { - return "Bool"; + return "Float"; } }; - PrimitiveCodec SHORT = new PrimitiveCodec() { + PrimitiveCodec DOUBLE = new PrimitiveCodec() { @Override - public DataResult read(final DynamicOps ops, final T input) { + public DataResult read(final DynamicOps ops, final T input) { return ops .getNumberValue(input) - .map(Number::shortValue); + .map(Number::doubleValue); } @Override - public T write(final DynamicOps ops, final Short value) { - return ops.createShort(value); + public T write(final DynamicOps ops, final Double value) { + return ops.createDouble(value); } @Override public String toString() { - return "Short"; + return "Double"; } }; @@ -510,25 +529,6 @@ public String toString() { } }; - PrimitiveCodec DOUBLE = new PrimitiveCodec() { - @Override - public DataResult read(final DynamicOps ops, final T input) { - return ops - .getNumberValue(input) - .map(Number::doubleValue); - } - - @Override - public T write(final DynamicOps ops, final Double value) { - return ops.createDouble(value); - } - - @Override - public String toString() { - return "Double"; - } - }; - PrimitiveCodec BYTE_BUFFER = new PrimitiveCodec() { @Override public DataResult read(final DynamicOps ops, final T input) { From dab00f1731101234bbff9033198961923ec27035 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 12 May 2020 16:58:44 +0200 Subject: [PATCH 93/96] ImmutableList.Builder -> Stream.Builder --- src/main/java/com/mojang/serialization/codecs/ListCodec.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/mojang/serialization/codecs/ListCodec.java b/src/main/java/com/mojang/serialization/codecs/ListCodec.java index 46e20477..e8d24bb1 100644 --- a/src/main/java/com/mojang/serialization/codecs/ListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/ListCodec.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.Objects; +import java.util.stream.Stream; public final class ListCodec implements Codec> { private final Codec elementCodec; @@ -37,7 +38,7 @@ public DataResult encode(final List input, final DynamicOps ops, fi public DataResult, T>> decode(final DynamicOps ops, final T input) { return ops.getList(input).setLifecycle(Lifecycle.stable()).flatMap(stream -> { final ImmutableList.Builder read = ImmutableList.builder(); - final ImmutableList.Builder failed = ImmutableList.builder(); + final Stream.Builder failed = Stream.builder(); // TODO: AtomicReference.getPlain/setPlain in java9+ final MutableObject> result = new MutableObject<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); @@ -52,7 +53,7 @@ public DataResult, T>> decode(final DynamicOps ops, final T }); final ImmutableList elements = read.build(); - final T errors = ops.createList(failed.build().stream()); + final T errors = ops.createList(failed.build()); final Pair, T> pair = Pair.of(elements, errors); From aef28535e54a81daef3158d86f9fffc845bea912 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 12 May 2020 17:00:49 +0200 Subject: [PATCH 94/96] Small cleanup of byte buffer stream creation --- src/main/java/com/mojang/serialization/DynamicOps.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/mojang/serialization/DynamicOps.java b/src/main/java/com/mojang/serialization/DynamicOps.java index be316292..a0ffdc0f 100644 --- a/src/main/java/com/mojang/serialization/DynamicOps.java +++ b/src/main/java/com/mojang/serialization/DynamicOps.java @@ -165,8 +165,7 @@ default DataResult getByteBuffer(final T input) { } default T createByteList(final ByteBuffer input) { - final int[] i = {0}; - return createList(Stream.generate(() -> createByte(input.get(i[0]++))).limit(input.capacity())); + return createList(IntStream.range(0, input.capacity()).mapToObj(i -> createByte(input.get(i)))); } default DataResult getIntStream(final T input) { From a1f4543562d8848eaf7d4e0a7b9d4cfd70b9a298 Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Tue, 12 May 2020 17:04:24 +0200 Subject: [PATCH 95/96] Fixed implementation of keys in EitherMapCodec --- .../java/com/mojang/serialization/codecs/EitherMapCodec.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/codecs/EitherMapCodec.java b/src/main/java/com/mojang/serialization/codecs/EitherMapCodec.java index a149a5d4..da2a0298 100644 --- a/src/main/java/com/mojang/serialization/codecs/EitherMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/EitherMapCodec.java @@ -62,6 +62,6 @@ public String toString() { @Override public Stream keys(final DynamicOps ops) { - return null; + return Stream.concat(first.keys(ops), second.keys(ops)); } } From 4b409835c3311e17d29e7803e748c8e303f3f635 Mon Sep 17 00:00:00 2001 From: Erik Broes Date: Tue, 12 May 2020 16:01:49 +0200 Subject: [PATCH 96/96] Style/import stuff. --- .../java/com/mojang/datafixers/DataFix.java | 3 +- .../com/mojang/datafixers/DataFixerUpper.java | 7 ++--- .../com/mojang/datafixers/FieldFinder.java | 4 +-- .../com/mojang/datafixers/FunctionType.java | 3 +- .../mojang/datafixers/NamedChoiceFinder.java | 2 +- .../com/mojang/datafixers/OpticFinder.java | 2 +- .../java/com/mojang/datafixers/Typed.java | 10 +++--- .../com/mojang/datafixers/TypedOptic.java | 11 ++++--- src/main/java/com/mojang/datafixers/View.java | 2 +- .../mojang/datafixers/functions/Apply.java | 2 +- .../com/mojang/datafixers/functions/Comp.java | 2 +- .../com/mojang/datafixers/functions/Fold.java | 2 +- .../datafixers/functions/Functions.java | 2 +- .../com/mojang/datafixers/functions/Id.java | 2 +- .../com/mojang/datafixers/functions/In.java | 2 +- .../com/mojang/datafixers/functions/Out.java | 2 +- .../datafixers/functions/PointFree.java | 2 +- .../datafixers/functions/PointFreeRule.java | 4 +-- .../com/mojang/datafixers/optics/Affine.java | 4 +-- .../com/mojang/datafixers/optics/Forget.java | 4 +-- .../com/mojang/datafixers/optics/ForgetE.java | 4 +-- .../mojang/datafixers/optics/ForgetOpt.java | 4 +-- .../com/mojang/datafixers/optics/Lens.java | 2 +- .../com/mojang/datafixers/optics/Optic.java | 1 - .../com/mojang/datafixers/optics/Optics.java | 16 +++++----- .../com/mojang/datafixers/optics/Prism.java | 2 +- .../mojang/datafixers/optics/ReForget.java | 4 +-- .../mojang/datafixers/optics/ReForgetC.java | 4 +-- .../mojang/datafixers/optics/ReForgetE.java | 2 +- .../mojang/datafixers/optics/ReForgetEP.java | 4 +-- .../mojang/datafixers/optics/ReForgetP.java | 4 +-- .../optics/profunctors/Cartesian.java | 2 +- .../optics/profunctors/Cocartesian.java | 2 +- .../optics/profunctors/Monoidal.java | 2 +- .../optics/profunctors/ReCartesian.java | 2 +- .../optics/profunctors/ReCocartesian.java | 2 +- .../optics/profunctors/TraversalP.java | 8 ++--- .../com/mojang/datafixers/types/Func.java | 4 +-- .../com/mojang/datafixers/types/Type.java | 2 +- .../datafixers/types/constant/EmptyPart.java | 3 +- .../types/constant/EmptyPartPassthrough.java | 3 +- .../types/templates/CompoundList.java | 1 - .../datafixers/types/templates/List.java | 1 - .../types/templates/TaggedChoice.java | 31 +++++++++---------- .../types/templates/TypeTemplate.java | 2 +- .../com/mojang/datafixers/util/Either.java | 6 ++-- .../java/com/mojang/serialization/Codec.java | 8 ++--- .../com/mojang/serialization/DataResult.java | 12 ++++--- .../com/mojang/serialization/Decoder.java | 2 +- .../com/mojang/serialization/DynamicLike.java | 6 ++-- .../com/mojang/serialization/JsonOps.java | 6 ++-- .../com/mojang/serialization/MapCodec.java | 6 ++-- .../com/mojang/serialization/MapDecoder.java | 2 +- .../com/mojang/serialization/MapEncoder.java | 4 +-- .../mojang/serialization/RecordBuilder.java | 1 - .../serialization/codecs/BaseMapCodec.java | 1 - .../codecs/CompoundListCodec.java | 1 - .../codecs/KeyDispatchCodec.java | 1 - .../serialization/codecs/ListCodec.java | 3 +- .../codecs/RecordCodecBuilder.java | 13 +++----- .../serialization/codecs/SimpleMapCodec.java | 1 - .../codecs/UnboundedMapCodec.java | 2 +- 62 files changed, 121 insertions(+), 138 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/DataFix.java b/src/main/java/com/mojang/datafixers/DataFix.java index 6bb9bc13..c0cc99fc 100644 --- a/src/main/java/com/mojang/datafixers/DataFix.java +++ b/src/main/java/com/mojang/datafixers/DataFix.java @@ -3,11 +3,10 @@ package com.mojang.datafixers; import com.mojang.datafixers.schemas.Schema; +import com.mojang.datafixers.types.Type; import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.Type; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/com/mojang/datafixers/DataFixerUpper.java b/src/main/java/com/mojang/datafixers/DataFixerUpper.java index 62912d06..b8570111 100644 --- a/src/main/java/com/mojang/datafixers/DataFixerUpper.java +++ b/src/main/java/com/mojang/datafixers/DataFixerUpper.java @@ -4,6 +4,9 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import com.mojang.datafixers.functions.PointFreeRule; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.datafixers.types.Type; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap; @@ -11,14 +14,10 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import com.mojang.datafixers.functions.PointFreeRule; -import com.mojang.datafixers.schemas.Schema; -import com.mojang.datafixers.types.Type; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.List; -import java.util.Optional; /* * Optimizing functions diff --git a/src/main/java/com/mojang/datafixers/FieldFinder.java b/src/main/java/com/mojang/datafixers/FieldFinder.java index 91e0dcdd..a20a9ded 100644 --- a/src/main/java/com/mojang/datafixers/FieldFinder.java +++ b/src/main/java/com/mojang/datafixers/FieldFinder.java @@ -2,8 +2,6 @@ // Licensed under the MIT license. package com.mojang.datafixers; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.optics.Adapter; import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.Proj1; @@ -12,6 +10,8 @@ import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.templates.Tag; import com.mojang.datafixers.types.templates.TaggedChoice; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import javax.annotation.Nullable; import java.util.Objects; diff --git a/src/main/java/com/mojang/datafixers/FunctionType.java b/src/main/java/com/mojang/datafixers/FunctionType.java index ec1572db..364943e6 100644 --- a/src/main/java/com/mojang/datafixers/FunctionType.java +++ b/src/main/java/com/mojang/datafixers/FunctionType.java @@ -10,7 +10,6 @@ import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.kinds.Representable; -import com.mojang.datafixers.optics.Optic; import com.mojang.datafixers.optics.Optics; import com.mojang.datafixers.optics.Procompose; import com.mojang.datafixers.optics.Wander; @@ -69,7 +68,7 @@ enum Instance implements TraversalP, MonoidProfunctor TYPE_TOKEN = new TypeToken() {}; + public static final TypeToken TYPE_TOKEN = new TypeToken() {}; } @Override diff --git a/src/main/java/com/mojang/datafixers/NamedChoiceFinder.java b/src/main/java/com/mojang/datafixers/NamedChoiceFinder.java index 095829d3..22d9c311 100644 --- a/src/main/java/com/mojang/datafixers/NamedChoiceFinder.java +++ b/src/main/java/com/mojang/datafixers/NamedChoiceFinder.java @@ -2,10 +2,10 @@ // Licensed under the MIT license. package com.mojang.datafixers; -import com.mojang.datafixers.util.Either; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.templates.Tag; import com.mojang.datafixers.types.templates.TaggedChoice; +import com.mojang.datafixers.util.Either; import java.util.Objects; diff --git a/src/main/java/com/mojang/datafixers/OpticFinder.java b/src/main/java/com/mojang/datafixers/OpticFinder.java index cc4ada75..82cfcab5 100644 --- a/src/main/java/com/mojang/datafixers/OpticFinder.java +++ b/src/main/java/com/mojang/datafixers/OpticFinder.java @@ -2,8 +2,8 @@ // Licensed under the MIT license. package com.mojang.datafixers; -import com.mojang.datafixers.util.Either; import com.mojang.datafixers.types.Type; +import com.mojang.datafixers.util.Either; import javax.annotation.Nullable; diff --git a/src/main/java/com/mojang/datafixers/Typed.java b/src/main/java/com/mojang/datafixers/Typed.java index 75bf9622..55c55beb 100644 --- a/src/main/java/com/mojang/datafixers/Typed.java +++ b/src/main/java/com/mojang/datafixers/Typed.java @@ -4,8 +4,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.kinds.Const; import com.mojang.datafixers.kinds.IdF; import com.mojang.datafixers.kinds.Monoid; @@ -17,11 +15,13 @@ import com.mojang.datafixers.optics.ReForgetC; import com.mojang.datafixers.optics.Traversal; import com.mojang.datafixers.optics.profunctors.TraversalP; +import com.mojang.datafixers.types.Type; +import com.mojang.datafixers.types.templates.RecursivePoint; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; -import com.mojang.datafixers.types.Type; -import com.mojang.datafixers.types.templates.RecursivePoint; import java.util.List; import java.util.Optional; @@ -167,7 +167,7 @@ private Typed updateCap(final TypedOptic field, fin public List> getAllTyped(final OpticFinder optic) { final TypedOptic field = optic.findType(type, optic.type(), false).orThrow(); - return getAll(field).stream().map(ft -> new Typed(optic.type(), ops, ft)).collect(Collectors.toList()); + return getAll(field).stream().map(ft -> new Typed<>(optic.type(), ops, ft)).collect(Collectors.toList()); } public List getAll(final TypedOptic field) { diff --git a/src/main/java/com/mojang/datafixers/TypedOptic.java b/src/main/java/com/mojang/datafixers/TypedOptic.java index 375a4137..10c55657 100644 --- a/src/main/java/com/mojang/datafixers/TypedOptic.java +++ b/src/main/java/com/mojang/datafixers/TypedOptic.java @@ -5,8 +5,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K1; @@ -25,8 +23,11 @@ import com.mojang.datafixers.optics.profunctors.TraversalP; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.templates.TaggedChoice; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -167,7 +168,7 @@ public static TypedOptic, Either, G, G2> inj2(fin ); } - public static TypedOptic>, java.util.List>, K, K2> compoundListKeys(final Type aType, final Type bType, final Type valueType) { + public static TypedOptic>, List>, K, K2> compoundListKeys(final Type aType, final Type bType, final Type valueType) { return new TypedOptic<>( TraversalP.Mu.TYPE_TOKEN, DSL.compoundList(aType, valueType), @@ -178,7 +179,7 @@ public static TypedOptic>, java.util.List

TypedOptic>, java.util.List>, V, V2> compoundListElements(final Type keyType, final Type aType, final Type bType) { + public static TypedOptic>, List>, V, V2> compoundListElements(final Type keyType, final Type aType, final Type bType) { return new TypedOptic<>( TraversalP.Mu.TYPE_TOKEN, DSL.compoundList(keyType, aType), @@ -189,7 +190,7 @@ public static TypedOptic>, java.util.List

extends Profunctor { static

Cartesian unbox(final App proofBox) { diff --git a/src/main/java/com/mojang/datafixers/optics/profunctors/Cocartesian.java b/src/main/java/com/mojang/datafixers/optics/profunctors/Cocartesian.java index 2135dc18..4d1da3d7 100644 --- a/src/main/java/com/mojang/datafixers/optics/profunctors/Cocartesian.java +++ b/src/main/java/com/mojang/datafixers/optics/profunctors/Cocartesian.java @@ -3,12 +3,12 @@ package com.mojang.datafixers.optics.profunctors; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.CocartesianLike; import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.kinds.K2; +import com.mojang.datafixers.util.Either; public interface Cocartesian

extends Profunctor { static

Cocartesian unbox(final App proofBox) { diff --git a/src/main/java/com/mojang/datafixers/optics/profunctors/Monoidal.java b/src/main/java/com/mojang/datafixers/optics/profunctors/Monoidal.java index 99d70179..1f991043 100644 --- a/src/main/java/com/mojang/datafixers/optics/profunctors/Monoidal.java +++ b/src/main/java/com/mojang/datafixers/optics/profunctors/Monoidal.java @@ -2,10 +2,10 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics.profunctors; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; +import com.mojang.datafixers.util.Pair; import java.util.function.Supplier; diff --git a/src/main/java/com/mojang/datafixers/optics/profunctors/ReCartesian.java b/src/main/java/com/mojang/datafixers/optics/profunctors/ReCartesian.java index ef9704b2..995372db 100644 --- a/src/main/java/com/mojang/datafixers/optics/profunctors/ReCartesian.java +++ b/src/main/java/com/mojang/datafixers/optics/profunctors/ReCartesian.java @@ -2,10 +2,10 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics.profunctors; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; +import com.mojang.datafixers.util.Pair; public interface ReCartesian

extends Profunctor { static

ReCartesian unbox(final App proofBox) { diff --git a/src/main/java/com/mojang/datafixers/optics/profunctors/ReCocartesian.java b/src/main/java/com/mojang/datafixers/optics/profunctors/ReCocartesian.java index fa144123..8b6d86fa 100644 --- a/src/main/java/com/mojang/datafixers/optics/profunctors/ReCocartesian.java +++ b/src/main/java/com/mojang/datafixers/optics/profunctors/ReCocartesian.java @@ -2,10 +2,10 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics.profunctors; -import com.mojang.datafixers.util.Either; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; +import com.mojang.datafixers.util.Either; public interface ReCocartesian

extends Profunctor { static

ReCocartesian unbox(final App proofBox) { diff --git a/src/main/java/com/mojang/datafixers/optics/profunctors/TraversalP.java b/src/main/java/com/mojang/datafixers/optics/profunctors/TraversalP.java index 3f3daee9..2dd262c1 100644 --- a/src/main/java/com/mojang/datafixers/optics/profunctors/TraversalP.java +++ b/src/main/java/com/mojang/datafixers/optics/profunctors/TraversalP.java @@ -3,8 +3,6 @@ package com.mojang.datafixers.optics.profunctors; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; @@ -13,6 +11,8 @@ import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.kinds.Traversable; import com.mojang.datafixers.optics.Wander; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; public interface TraversalP

extends AffineP/*, Monoidal*/ { static

TraversalP unbox(final App proofBox) { @@ -54,12 +54,12 @@ public FunctionType, App>> wander(final Ap @Override default App2, Pair> first(final App2 input) { - return dimap(traverse(new Pair.Instance(), input), box -> box, Pair::unbox); + return dimap(traverse(new Pair.Instance<>(), input), box -> box, Pair::unbox); } @Override default App2, Either> left(final App2 input) { - return dimap(traverse(new Either.Instance(), input), box -> box, Either::unbox); + return dimap(traverse(new Either.Instance<>(), input), box -> box, Either::unbox); } default FunctorProfunctor> toFP3() { diff --git a/src/main/java/com/mojang/datafixers/types/Func.java b/src/main/java/com/mojang/datafixers/types/Func.java index 07c2a3f5..c7089409 100644 --- a/src/main/java/com/mojang/datafixers/types/Func.java +++ b/src/main/java/com/mojang/datafixers/types/Func.java @@ -39,10 +39,10 @@ public String toString() { @Override public boolean equals(final Object obj, final boolean ignoreRecursionPoints, final boolean checkIndex) { - if (!(obj instanceof com.mojang.datafixers.types.Func)) { + if (!(obj instanceof Func)) { return false; } - final com.mojang.datafixers.types.Func that = (com.mojang.datafixers.types.Func) obj; + final Func that = (Func) obj; return first.equals(that.first, ignoreRecursionPoints, checkIndex) && second.equals(that.second, ignoreRecursionPoints, checkIndex); } diff --git a/src/main/java/com/mojang/datafixers/types/Type.java b/src/main/java/com/mojang/datafixers/types/Type.java index 263ae34e..4592da3c 100644 --- a/src/main/java/com/mojang/datafixers/types/Type.java +++ b/src/main/java/com/mojang/datafixers/types/Type.java @@ -113,7 +113,7 @@ public Optional> findCheckedType(final int index) { } public final DataResult>> read(final Dynamic input) { - return codec().decode(input.getOps(), input.getValue()).map(v -> v.mapSecond(t -> new Dynamic(input.getOps(), t))); + return codec().decode(input.getOps(), input.getValue()).map(v -> v.mapSecond(t -> new Dynamic<>(input.getOps(), t))); } public final Codec codec() { diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java index 7b7740a3..0c12f6e3 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPart.java @@ -3,6 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.DSL; +import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.templates.TypeTemplate; import com.mojang.datafixers.util.Unit; import com.mojang.serialization.Codec; @@ -10,7 +11,7 @@ import java.util.Optional; -public final class EmptyPart extends com.mojang.datafixers.types.Type { +public final class EmptyPart extends Type { @Override public String toString() { return "EmptyPart"; diff --git a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartPassthrough.java b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartPassthrough.java index f3b449a4..2bfadf11 100644 --- a/src/main/java/com/mojang/datafixers/types/constant/EmptyPartPassthrough.java +++ b/src/main/java/com/mojang/datafixers/types/constant/EmptyPartPassthrough.java @@ -3,6 +3,7 @@ package com.mojang.datafixers.types.constant; import com.mojang.datafixers.DSL; +import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.templates.TypeTemplate; import com.mojang.serialization.Codec; import com.mojang.serialization.Dynamic; @@ -10,7 +11,7 @@ import java.util.Optional; -public final class EmptyPartPassthrough extends com.mojang.datafixers.types.Type> { +public final class EmptyPartPassthrough extends Type> { @Override public String toString() { return "EmptyPartPassthrough"; diff --git a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java index 182ccad9..a67d421d 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java +++ b/src/main/java/com/mojang/datafixers/types/templates/CompoundList.java @@ -24,7 +24,6 @@ import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.codecs.CompoundListCodec; import javax.annotation.Nullable; import java.util.List; diff --git a/src/main/java/com/mojang/datafixers/types/templates/List.java b/src/main/java/com/mojang/datafixers/types/templates/List.java index d99a4d37..984d852d 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/List.java +++ b/src/main/java/com/mojang/datafixers/types/templates/List.java @@ -21,7 +21,6 @@ import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.codecs.ListCodec; import javax.annotation.Nullable; import java.util.Objects; diff --git a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java index b9642c9c..5dc77c28 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TaggedChoice.java @@ -132,15 +132,13 @@ public TaggedChoiceType(final String name, final Type keyType, final Map, ?> all(final TypeRewriteRule rule, final boolean recurse, final boolean checkIndex) { - final Map> results = types.entrySet().stream().map( - e -> rule.rewrite(e.getValue()).map(v -> Pair.of(e.getKey(), v)) - ).filter( - e -> e.isPresent() && !Objects.equals(e.get().getSecond().view().function(), Functions.id()) - ).map( - Optional::get - ).collect( - Pair.toMap() - ); + final Map> results = types.entrySet().stream() + .map(e -> rule.rewrite(e.getValue()).map(v -> Pair.of(e.getKey(), v))) + .filter(e -> e.isPresent() && !Objects.equals(e.get().getSecond().view().function(), Functions.id())) + .map(Optional::get) + .collect(Pair.toMap()) + ; + if (results.isEmpty()) { return RewriteResult.nop(this); } else if (results.size() == 1) { @@ -220,13 +218,12 @@ public Optional> findFieldTypeOpt(final String name) { @Override public Either, ?, FT, FR>, FieldNotFoundException> findTypeInChildren(final Type type, final Type resultType, final TypeMatcher matcher, final boolean recurse) { - final Map> optics = types.entrySet().stream().map( - e -> Pair.of(e.getKey(), e.getValue().findType(type, resultType, matcher, recurse)) - ).filter( - e -> e.getSecond().left().isPresent() - ).map( - e -> e.mapSecond(o -> o.left().get()) - ).collect(Pair.toMap()); + final Map> optics = types.entrySet().stream() + .map(e -> Pair.of(e.getKey(), e.getValue().findType(type, resultType, matcher, recurse))) + .filter(e -> e.getSecond().left().isPresent()) + .map(e -> e.mapSecond(o -> o.left().get())) + .collect(Pair.toMap()) + ; if (optics.isEmpty()) { return Either.right(new FieldNotFoundException("Not found in any choices")); @@ -360,7 +357,7 @@ public boolean equals(final Object obj, final boolean ignoreRecursionPoints, fin if (this == obj) { return true; } - if (!(obj instanceof TaggedChoice.TaggedChoiceType)) { + if (!(obj instanceof TaggedChoiceType)) { return false; } final TaggedChoiceType other = (TaggedChoiceType) obj; diff --git a/src/main/java/com/mojang/datafixers/types/templates/TypeTemplate.java b/src/main/java/com/mojang/datafixers/types/templates/TypeTemplate.java index 61671c5a..38236e98 100644 --- a/src/main/java/com/mojang/datafixers/types/templates/TypeTemplate.java +++ b/src/main/java/com/mojang/datafixers/types/templates/TypeTemplate.java @@ -2,12 +2,12 @@ // Licensed under the MIT license. package com.mojang.datafixers.types.templates; -import com.mojang.datafixers.util.Either; import com.mojang.datafixers.DSL; import com.mojang.datafixers.FamilyOptic; import com.mojang.datafixers.RewriteResult; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.TypeFamily; +import com.mojang.datafixers.util.Either; import javax.annotation.Nullable; import java.util.function.IntFunction; diff --git a/src/main/java/com/mojang/datafixers/util/Either.java b/src/main/java/com/mojang/datafixers/util/Either.java index 612c3539..a90adac7 100644 --- a/src/main/java/com/mojang/datafixers/util/Either.java +++ b/src/main/java/com/mojang/datafixers/util/Either.java @@ -15,8 +15,7 @@ import java.util.function.Function; public abstract class Either implements App, L> { - public static final class Mu implements K1 { - } + public static final class Mu implements K1 {} public static Either unbox(final App, L> box) { return (Either) box; @@ -193,8 +192,7 @@ public Either flatMap(final Function> function) { } public static final class Instance implements Applicative, Instance.Mu>, Traversable, Instance.Mu>, CocartesianLike, R2, Instance.Mu> { - public static final class Mu implements Applicative.Mu, Traversable.Mu, CocartesianLike.Mu { - } + public static final class Mu implements Applicative.Mu, Traversable.Mu, CocartesianLike.Mu {} @Override public App, R> map(final Function func, final App, T> ts) { diff --git a/src/main/java/com/mojang/serialization/Codec.java b/src/main/java/com/mojang/serialization/Codec.java index fb99a570..e7f5d46f 100644 --- a/src/main/java/com/mojang/serialization/Codec.java +++ b/src/main/java/com/mojang/serialization/Codec.java @@ -194,7 +194,7 @@ default MapCodec optionalFieldOf(final String name, final A defaultValue, fin default MapCodec optionalFieldOf(final String name, final Lifecycle fieldLifecycle, final A defaultValue, final Lifecycle lifecycleOfDefault) { // setting lifecycle to stable on the outside since it will be overriden by the passed parameters return optionalField(name, this).stable().flatXmap( - o -> o.map(v-> DataResult.success(v, fieldLifecycle)).orElse(DataResult.success(defaultValue, lifecycleOfDefault)), + o -> o.map(v -> DataResult.success(v, fieldLifecycle)).orElse(DataResult.success(defaultValue, lifecycleOfDefault)), a -> Objects.equals(a, defaultValue) ? DataResult.success(Optional.empty(), lifecycleOfDefault) : DataResult.success(Optional.of(a), fieldLifecycle) ); } @@ -533,7 +533,7 @@ public String toString() { @Override public DataResult read(final DynamicOps ops, final T input) { return ops - .getByteBuffer(input); + .getByteBuffer(input); } @Override @@ -551,7 +551,7 @@ public String toString() { @Override public DataResult read(final DynamicOps ops, final T input) { return ops - .getIntStream(input); + .getIntStream(input); } @Override @@ -569,7 +569,7 @@ public String toString() { @Override public DataResult read(final DynamicOps ops, final T input) { return ops - .getLongStream(input); + .getLongStream(input); } @Override diff --git a/src/main/java/com/mojang/serialization/DataResult.java b/src/main/java/com/mojang/serialization/DataResult.java index 5d0485ff..27513522 100644 --- a/src/main/java/com/mojang/serialization/DataResult.java +++ b/src/main/java/com/mojang/serialization/DataResult.java @@ -23,7 +23,7 @@ public class DataResult implements App { public static final class Mu implements K1 {} - public static DataResult unbox(final App box) { + public static DataResult unbox(final App box) { return (DataResult) box; } @@ -276,7 +276,7 @@ public String toString() { } } - public enum Instance implements Applicative { + public enum Instance implements Applicative { INSTANCE; public static final class Mu implements Applicative.Mu {} @@ -310,7 +310,8 @@ public App ap2(final App(Either.left(fr.result.left().get().apply( ra.result.left().get(), rb.result.left().get() @@ -331,7 +332,8 @@ public App ap3(final App(Either.left(fr.result.left().get().apply( dr1.result.left().get(), dr2.result.left().get(), @@ -342,4 +344,4 @@ public App ap3(final App DataResult parse(final DynamicOps ops, final T input) { return decode(ops, input).map(Pair::getFirst); } - default DataResult> decode(final Dynamic input) { + default DataResult> decode(final Dynamic input) { return decode(input.getOps(), input.getValue()); } diff --git a/src/main/java/com/mojang/serialization/DynamicLike.java b/src/main/java/com/mojang/serialization/DynamicLike.java index 768cc53b..1ef30b43 100644 --- a/src/main/java/com/mojang/serialization/DynamicLike.java +++ b/src/main/java/com/mojang/serialization/DynamicLike.java @@ -53,7 +53,7 @@ public DataResult> asMapOpt(final Function, K> keyDe return asMapOpt().map(map -> { final ImmutableMap.Builder builder = ImmutableMap.builder(); map.forEach(entry -> - builder.put(keyDeserializer.apply(entry.getFirst()), valueDeserializer.apply(entry.getSecond())) + builder.put(keyDeserializer.apply(entry.getFirst()), valueDeserializer.apply(entry.getSecond())) ); return builder.build(); }); @@ -65,8 +65,8 @@ public DataResult read(final Decoder decoder) { public DataResult> readList(final Decoder decoder) { return asStreamOpt() - .map(s -> s.map(d -> d.read(decoder)).collect(Collectors.>toList())) - .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); + .map(s -> s.map(d -> d.read(decoder)).collect(Collectors.>toList())) + .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); } public DataResult> readList(final Function, ? extends DataResult> decoder) { diff --git a/src/main/java/com/mojang/serialization/JsonOps.java b/src/main/java/com/mojang/serialization/JsonOps.java index 46613cdc..d4f42a41 100644 --- a/src/main/java/com/mojang/serialization/JsonOps.java +++ b/src/main/java/com/mojang/serialization/JsonOps.java @@ -142,9 +142,9 @@ public DataResult mergeToList(final JsonElement list, final JsonEle } final JsonArray result = new JsonArray(); - if (list != empty()) { - result.addAll(list.getAsJsonArray()); - } + if (list != empty()) { + result.addAll(list.getAsJsonArray()); + } result.add(value); return DataResult.success(result); } diff --git a/src/main/java/com/mojang/serialization/MapCodec.java b/src/main/java/com/mojang/serialization/MapCodec.java index 12bc6684..738149f7 100644 --- a/src/main/java/com/mojang/serialization/MapCodec.java +++ b/src/main/java/com/mojang/serialization/MapCodec.java @@ -52,7 +52,6 @@ public MapCodec fieldOf(final String name) { @Override public MapCodec withLifecycle(final Lifecycle lifecycle) { - return new MapCodec() { @Override public Stream keys(final DynamicOps ops) { @@ -124,7 +123,7 @@ public MapCodec flatXmap(final Function MapCodec dependent(final MapCodec initialInstance, final Function>> splitter, final BiFunction combiner) { - return new Dependent(this, initialInstance, splitter, combiner); + return new Dependent<>(this, initialInstance, splitter, combiner); } private static class Dependent extends MapCodec { @@ -170,8 +169,7 @@ interface ResultFunction { RecordBuilder coApply(final DynamicOps ops, final A input, final RecordBuilder t); } - private MapCodec mapResult(final MapCodec.ResultFunction function) { - + private MapCodec mapResult(final ResultFunction function) { return new MapCodec() { @Override public Stream keys(final DynamicOps ops) { diff --git a/src/main/java/com/mojang/serialization/MapDecoder.java b/src/main/java/com/mojang/serialization/MapDecoder.java index 8a3ccae6..1c20bcd0 100644 --- a/src/main/java/com/mojang/serialization/MapDecoder.java +++ b/src/main/java/com/mojang/serialization/MapDecoder.java @@ -128,7 +128,7 @@ public String toString() { } default MapDecoder withLifecycle(final Lifecycle lifecycle) { - return new MapDecoder.Implementation() { + return new Implementation() { @Override public Stream keys(final DynamicOps ops) { return MapDecoder.this.keys(ops); diff --git a/src/main/java/com/mojang/serialization/MapEncoder.java b/src/main/java/com/mojang/serialization/MapEncoder.java index efa70725..45dbb9ff 100644 --- a/src/main/java/com/mojang/serialization/MapEncoder.java +++ b/src/main/java/com/mojang/serialization/MapEncoder.java @@ -20,7 +20,7 @@ default RecordBuilder compressedBuilder(final DynamicOps ops) { KeyCompressor compressor(final DynamicOps ops); default MapEncoder comap(final Function function) { - return new MapEncoder.Implementation() { + return new Implementation() { @Override public RecordBuilder encode(final B input, final DynamicOps ops, final RecordBuilder prefix) { return MapEncoder.this.encode(function.apply(input), ops, prefix); @@ -39,7 +39,7 @@ public String toString() { } default MapEncoder flatComap(final Function> function) { - return new MapEncoder.Implementation() { + return new Implementation() { @Override public Stream keys(final DynamicOps ops) { return MapEncoder.this.keys(ops); diff --git a/src/main/java/com/mojang/serialization/RecordBuilder.java b/src/main/java/com/mojang/serialization/RecordBuilder.java index 37a9e4cf..7a2baa65 100644 --- a/src/main/java/com/mojang/serialization/RecordBuilder.java +++ b/src/main/java/com/mojang/serialization/RecordBuilder.java @@ -127,7 +127,6 @@ public RecordBuilder add(final DataResult key, final DataResult value) }); return this; } - } abstract class AbstractUniversalBuilder extends AbstractBuilder { diff --git a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java index 0cdeb8ba..883617c9 100644 --- a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java @@ -16,7 +16,6 @@ import java.util.Map; public interface BaseMapCodec { - Codec keyCodec(); Codec elementCodec(); diff --git a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java index 17731489..883c61ac 100644 --- a/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/CompoundListCodec.java @@ -68,7 +68,6 @@ public DataResult encode(final List> input, final DynamicOps DataResult, T>> decode(final DynamicOps ops, final T final ImmutableList.Builder read = ImmutableList.builder(); final Stream.Builder failed = Stream.builder(); // TODO: AtomicReference.getPlain/setPlain in java9+ - final MutableObject> result = - new MutableObject<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); + final MutableObject> result = new MutableObject<>(DataResult.success(Unit.INSTANCE, Lifecycle.stable())); stream.accept(t -> { final DataResult> element = elementCodec.decode(ops, t); diff --git a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java index dfc9a9e4..72cb7812 100644 --- a/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java +++ b/src/main/java/com/mojang/serialization/codecs/RecordCodecBuilder.java @@ -24,8 +24,7 @@ import java.util.stream.Stream; public final class RecordCodecBuilder implements App, F> { - public static final class Mu implements K1 { - } + public static final class Mu implements K1 {} public static RecordCodecBuilder unbox(final App, F> box) { return ((RecordCodecBuilder) box); @@ -69,11 +68,11 @@ public static RecordCodecBuilder point(final F instance, final Life return new RecordCodecBuilder<>(o -> instance, o -> Encoder.empty().withLifecycle(lifecycle), Decoder.unit(instance).withLifecycle(lifecycle)); } - public static Codec create(final Function, ? extends App, O>> builder) { + public static Codec create(final Function, ? extends App, O>> builder) { return build(builder.apply(instance())).codec(); } - public static MapCodec mapCodec(final Function, ? extends App, O>> builder) { + public static MapCodec mapCodec(final Function, ? extends App, O>> builder) { return build(builder.apply(instance())); } @@ -100,7 +99,7 @@ public String toString() { ); } - public static MapCodec build(final App, O> builderBox) { + public static MapCodec build(final App, O> builderBox) { final RecordCodecBuilder builder = unbox(builderBox); return new MapCodec() { @Override @@ -126,8 +125,7 @@ public String toString() { } public static final class Instance implements Applicative, Instance.Mu> { - private static final class Mu implements Applicative.Mu { - } + private static final class Mu implements Applicative.Mu {} public App, A> stable(final A a) { return RecordCodecBuilder.stable(a); @@ -460,4 +458,3 @@ public String toString() { } } } - diff --git a/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java index 4f522dc4..a916751f 100644 --- a/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/SimpleMapCodec.java @@ -43,7 +43,6 @@ public Stream keys(final DynamicOps ops) { return keys.keys(ops); } - @Override public DataResult> decode(final DynamicOps ops, final MapLike input) { return BaseMapCodec.super.decode(ops, input); diff --git a/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java b/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java index d866175f..0e7cf972 100644 --- a/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/UnboundedMapCodec.java @@ -39,7 +39,7 @@ public DataResult, T>> decode(final DynamicOps ops, final } @Override - public DataResult encode(final Map input, final DynamicOps ops, final T prefix) { + public DataResult encode(final Map input, final DynamicOps ops, final T prefix) { return encode(input, ops, ops.mapBuilder()).build(prefix); }

TypedOptic, java.util.List, A, B> list(final Type aType, final Type bType) { + public static TypedOptic, List, A, B> list(final Type aType, final Type bType) { return new TypedOptic<>( TraversalP.Mu.TYPE_TOKEN, DSL.list(aType), diff --git a/src/main/java/com/mojang/datafixers/View.java b/src/main/java/com/mojang/datafixers/View.java index 1ff3d483..4139dc99 100644 --- a/src/main/java/com/mojang/datafixers/View.java +++ b/src/main/java/com/mojang/datafixers/View.java @@ -7,8 +7,8 @@ import com.mojang.datafixers.functions.PointFreeRule; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/functions/Apply.java b/src/main/java/com/mojang/datafixers/functions/Apply.java index 189fa987..32c55622 100644 --- a/src/main/java/com/mojang/datafixers/functions/Apply.java +++ b/src/main/java/com/mojang/datafixers/functions/Apply.java @@ -3,8 +3,8 @@ package com.mojang.datafixers.functions; import com.mojang.datafixers.DSL; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/functions/Comp.java b/src/main/java/com/mojang/datafixers/functions/Comp.java index d3d88776..a7a0ba66 100644 --- a/src/main/java/com/mojang/datafixers/functions/Comp.java +++ b/src/main/java/com/mojang/datafixers/functions/Comp.java @@ -3,9 +3,9 @@ package com.mojang.datafixers.functions; import com.mojang.datafixers.DSL; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Func; import com.mojang.datafixers.types.Type; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/com/mojang/datafixers/functions/Fold.java b/src/main/java/com/mojang/datafixers/functions/Fold.java index 419e4639..54f1afd4 100644 --- a/src/main/java/com/mojang/datafixers/functions/Fold.java +++ b/src/main/java/com/mojang/datafixers/functions/Fold.java @@ -5,11 +5,11 @@ import com.google.common.collect.Maps; import com.mojang.datafixers.RewriteResult; import com.mojang.datafixers.View; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.families.Algebra; import com.mojang.datafixers.types.families.RecursiveTypeFamily; import com.mojang.datafixers.types.templates.RecursivePoint; import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DynamicOps; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/mojang/datafixers/functions/Functions.java b/src/main/java/com/mojang/datafixers/functions/Functions.java index a113353b..6a5e4023 100644 --- a/src/main/java/com/mojang/datafixers/functions/Functions.java +++ b/src/main/java/com/mojang/datafixers/functions/Functions.java @@ -5,10 +5,10 @@ import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.RewriteResult; import com.mojang.datafixers.optics.Optic; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.types.families.Algebra; import com.mojang.datafixers.types.templates.RecursivePoint; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/functions/Id.java b/src/main/java/com/mojang/datafixers/functions/Id.java index c27cb2c6..141134a2 100644 --- a/src/main/java/com/mojang/datafixers/functions/Id.java +++ b/src/main/java/com/mojang/datafixers/functions/Id.java @@ -12,7 +12,7 @@ public Id() { @Override public boolean equals(final Object obj) { - return obj instanceof com.mojang.datafixers.functions.Id; + return obj instanceof Id; } @Override diff --git a/src/main/java/com/mojang/datafixers/functions/In.java b/src/main/java/com/mojang/datafixers/functions/In.java index 9479d787..8a530338 100644 --- a/src/main/java/com/mojang/datafixers/functions/In.java +++ b/src/main/java/com/mojang/datafixers/functions/In.java @@ -2,8 +2,8 @@ // Licensed under the MIT license. package com.mojang.datafixers.functions; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.RecursivePoint; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/functions/Out.java b/src/main/java/com/mojang/datafixers/functions/Out.java index 84367060..735a6d99 100644 --- a/src/main/java/com/mojang/datafixers/functions/Out.java +++ b/src/main/java/com/mojang/datafixers/functions/Out.java @@ -2,8 +2,8 @@ // Licensed under the MIT license. package com.mojang.datafixers.functions; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.templates.RecursivePoint; +import com.mojang.serialization.DynamicOps; import java.util.Objects; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/functions/PointFree.java b/src/main/java/com/mojang/datafixers/functions/PointFree.java index cf080f1d..f7593e3b 100644 --- a/src/main/java/com/mojang/datafixers/functions/PointFree.java +++ b/src/main/java/com/mojang/datafixers/functions/PointFree.java @@ -2,8 +2,8 @@ // Licensed under the MIT license. package com.mojang.datafixers.functions; -import com.mojang.serialization.DynamicOps; import com.mojang.datafixers.types.Type; +import com.mojang.serialization.DynamicOps; import org.apache.commons.lang3.StringUtils; import javax.annotation.Nullable; diff --git a/src/main/java/com/mojang/datafixers/functions/PointFreeRule.java b/src/main/java/com/mojang/datafixers/functions/PointFreeRule.java index cf5afb88..eaee52d2 100644 --- a/src/main/java/com/mojang/datafixers/functions/PointFreeRule.java +++ b/src/main/java/com/mojang/datafixers/functions/PointFreeRule.java @@ -4,8 +4,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.RewriteResult; @@ -20,6 +18,8 @@ import com.mojang.datafixers.types.families.Algebra; import com.mojang.datafixers.types.families.ListAlgebra; import com.mojang.datafixers.types.families.RecursiveTypeFamily; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import org.apache.commons.lang3.ObjectUtils; import java.util.BitSet; diff --git a/src/main/java/com/mojang/datafixers/optics/Affine.java b/src/main/java/com/mojang/datafixers/optics/Affine.java index 284353be..9f7e4fee 100644 --- a/src/main/java/com/mojang/datafixers/optics/Affine.java +++ b/src/main/java/com/mojang/datafixers/optics/Affine.java @@ -2,8 +2,6 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; @@ -11,6 +9,8 @@ import com.mojang.datafixers.optics.profunctors.AffineP; import com.mojang.datafixers.optics.profunctors.Cartesian; import com.mojang.datafixers.optics.profunctors.Cocartesian; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/Forget.java b/src/main/java/com/mojang/datafixers/optics/Forget.java index c60c479d..84a3735c 100644 --- a/src/main/java/com/mojang/datafixers/optics/Forget.java +++ b/src/main/java/com/mojang/datafixers/optics/Forget.java @@ -2,14 +2,14 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.Cartesian; import com.mojang.datafixers.optics.profunctors.ReCocartesian; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/ForgetE.java b/src/main/java/com/mojang/datafixers/optics/ForgetE.java index 3ff22051..274d030a 100644 --- a/src/main/java/com/mojang/datafixers/optics/ForgetE.java +++ b/src/main/java/com/mojang/datafixers/optics/ForgetE.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.AffineP; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/ForgetOpt.java b/src/main/java/com/mojang/datafixers/optics/ForgetOpt.java index 4b82829e..074d687e 100644 --- a/src/main/java/com/mojang/datafixers/optics/ForgetOpt.java +++ b/src/main/java/com/mojang/datafixers/optics/ForgetOpt.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.AffineP; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.Optional; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/Lens.java b/src/main/java/com/mojang/datafixers/optics/Lens.java index 52c2e575..f8b068e6 100644 --- a/src/main/java/com/mojang/datafixers/optics/Lens.java +++ b/src/main/java/com/mojang/datafixers/optics/Lens.java @@ -2,12 +2,12 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.Cartesian; +import com.mojang.datafixers.util.Pair; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/Optic.java b/src/main/java/com/mojang/datafixers/optics/Optic.java index e2574f91..077fb157 100644 --- a/src/main/java/com/mojang/datafixers/optics/Optic.java +++ b/src/main/java/com/mojang/datafixers/optics/Optic.java @@ -3,7 +3,6 @@ package com.mojang.datafixers.optics; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K1; diff --git a/src/main/java/com/mojang/datafixers/optics/Optics.java b/src/main/java/com/mojang/datafixers/optics/Optics.java index 76553b43..4bf469df 100644 --- a/src/main/java/com/mojang/datafixers/optics/Optics.java +++ b/src/main/java/com/mojang/datafixers/optics/Optics.java @@ -2,8 +2,6 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; @@ -15,6 +13,8 @@ import com.mojang.datafixers.optics.profunctors.GetterP; import com.mojang.datafixers.optics.profunctors.Profunctor; import com.mojang.datafixers.optics.profunctors.TraversalP; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.Optional; import java.util.function.BiFunction; @@ -23,32 +23,32 @@ public abstract class Optics { public static Adapter toAdapter(final Optic optic) { - final Function, A, B>, App2, S, T>> eval = optic.eval(new Adapter.Instance()); + final Function, A, B>, App2, S, T>> eval = optic.eval(new Adapter.Instance<>()); return Adapter.unbox(eval.apply(adapter(Function.identity(), Function.identity()))); } public static Lens toLens(final Optic optic) { - final Function, A, B>, App2, S, T>> eval = optic.eval(new Lens.Instance()); + final Function, A, B>, App2, S, T>> eval = optic.eval(new Lens.Instance<>()); return Lens.unbox(eval.apply(lens(Function.identity(), (b, a) -> b))); } public static Prism toPrism(final Optic optic) { - final Function, A, B>, App2, S, T>> eval = optic.eval(new Prism.Instance()); + final Function, A, B>, App2, S, T>> eval = optic.eval(new Prism.Instance<>()); return Prism.unbox(eval.apply(prism(Either::right, Function.identity()))); } public static Affine toAffine(final Optic optic) { - final Function, A, B>, App2, S, T>> eval = optic.eval(new Affine.Instance()); + final Function, A, B>, App2, S, T>> eval = optic.eval(new Affine.Instance<>()); return Affine.unbox(eval.apply(affine(Either::right, (b, a) -> b))); } public static Getter toGetter(final Optic optic) { - final Function, A, B>, App2, S, T>> eval = optic.eval(new Getter.Instance()); + final Function, A, B>, App2, S, T>> eval = optic.eval(new Getter.Instance<>()); return Getter.unbox(eval.apply(getter(Function.identity()))); } public static Traversal toTraversal(final Optic optic) { - final Function, A, B>, App2, S, T>> eval = optic.eval(new Traversal.Instance()); + final Function, A, B>, App2, S, T>> eval = optic.eval(new Traversal.Instance<>()); return Traversal.unbox(eval.apply(new Traversal() { @Override public FunctionType> wander(final Applicative applicative, final FunctionType> input) { diff --git a/src/main/java/com/mojang/datafixers/optics/Prism.java b/src/main/java/com/mojang/datafixers/optics/Prism.java index dead8ed0..330842ad 100644 --- a/src/main/java/com/mojang/datafixers/optics/Prism.java +++ b/src/main/java/com/mojang/datafixers/optics/Prism.java @@ -2,12 +2,12 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.Cocartesian; +import com.mojang.datafixers.util.Either; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/ReForget.java b/src/main/java/com/mojang/datafixers/optics/ReForget.java index 72329eda..ab5f4da2 100644 --- a/src/main/java/com/mojang/datafixers/optics/ReForget.java +++ b/src/main/java/com/mojang/datafixers/optics/ReForget.java @@ -2,14 +2,14 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.Cocartesian; import com.mojang.datafixers.optics.profunctors.ReCartesian; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/ReForgetC.java b/src/main/java/com/mojang/datafixers/optics/ReForgetC.java index 47e984e0..5a8858da 100644 --- a/src/main/java/com/mojang/datafixers/optics/ReForgetC.java +++ b/src/main/java/com/mojang/datafixers/optics/ReForgetC.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.AffineP; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.function.BiFunction; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/ReForgetE.java b/src/main/java/com/mojang/datafixers/optics/ReForgetE.java index c5a43287..aec5f989 100644 --- a/src/main/java/com/mojang/datafixers/optics/ReForgetE.java +++ b/src/main/java/com/mojang/datafixers/optics/ReForgetE.java @@ -2,12 +2,12 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.Cocartesian; +import com.mojang.datafixers.util.Either; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/ReForgetEP.java b/src/main/java/com/mojang/datafixers/optics/ReForgetEP.java index 04db8915..01b2c82f 100644 --- a/src/main/java/com/mojang/datafixers/optics/ReForgetEP.java +++ b/src/main/java/com/mojang/datafixers/optics/ReForgetEP.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.AffineP; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/ReForgetP.java b/src/main/java/com/mojang/datafixers/optics/ReForgetP.java index a47410e4..367631a5 100644 --- a/src/main/java/com/mojang/datafixers/optics/ReForgetP.java +++ b/src/main/java/com/mojang/datafixers/optics/ReForgetP.java @@ -2,13 +2,13 @@ // Licensed under the MIT license. package com.mojang.datafixers.optics; -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.FunctionType; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.K2; import com.mojang.datafixers.optics.profunctors.AffineP; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; import java.util.function.Function; diff --git a/src/main/java/com/mojang/datafixers/optics/profunctors/Cartesian.java b/src/main/java/com/mojang/datafixers/optics/profunctors/Cartesian.java index e6fd1dc4..37404b77 100644 --- a/src/main/java/com/mojang/datafixers/optics/profunctors/Cartesian.java +++ b/src/main/java/com/mojang/datafixers/optics/profunctors/Cartesian.java @@ -3,12 +3,12 @@ package com.mojang.datafixers.optics.profunctors; import com.google.common.reflect.TypeToken; -import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.App2; import com.mojang.datafixers.kinds.CartesianLike; import com.mojang.datafixers.kinds.K1; import com.mojang.datafixers.kinds.K2; +import com.mojang.datafixers.util.Pair; public interface Cartesian