// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. package com.mojang.serialization; 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; public interface Decoder<A> { <T> DataResult<Pair<A, T>> decode(final DynamicOps<T> ops, final T input); // TODO: rename to read after Type.read is no more default <T> DataResult<A> parse(final DynamicOps<T> ops, final T input) { return decode(ops, input).map(Pair::getFirst); } default <T> DataResult<Pair<A, T>> decode(final Dynamic<T> input) { return decode(input.getOps(), input.getValue()); } default <T> DataResult<A> parse(final Dynamic<T> input) { return decode(input).map(Pair::getFirst); } default Terminal<A> terminal() { return this::parse; } default Boxed<A> boxed() { return this::decode; } default Simple<A> simple() { return this::parse; } default MapDecoder<A> fieldOf(final String name) { return new FieldDecoder<>(name, this); } default <B> Decoder<B> flatMap(final Function<? super A, ? extends DataResult<? extends B>> function) { return new Decoder<B>() { @Override public <T> DataResult<Pair<B, T>> decode(final DynamicOps<T> ops, final T input) { return Decoder.this.decode(ops, input).flatMap(p -> function.apply(p.getFirst()).map(r -> Pair.of(r, p.getSecond()))); } @Override public String toString() { return Decoder.this.toString() + "[flatMapped]"; } }; } default <B> Decoder<B> map(final Function<? super A, ? extends B> function) { return new Decoder<B>() { @Override public <T> DataResult<Pair<B, T>> decode(final DynamicOps<T> ops, final T input) { return Decoder.this.decode(ops, input).map(p -> p.mapFirst(function)); } @Override public String toString() { return Decoder.this.toString() + "[mapped]"; } }; } default Decoder<A> promotePartial(final Consumer<String> onError) { return new Decoder<A>() { @Override public <T> DataResult<Pair<A, T>> decode(final DynamicOps<T> ops, final T input) { return Decoder.this.decode(ops, input).promotePartial(onError); } @Override public String toString() { return Decoder.this.toString() + "[promotePartial]"; } }; } default Decoder<A> withLifecycle(final Lifecycle lifecycle) { return new Decoder<A>() { @Override public <T> DataResult<Pair<A, T>> decode(final DynamicOps<T> ops, final T input) { return Decoder.this.decode(ops, input).setLifecycle(lifecycle); } @Override public String toString() { return Decoder.this.toString(); } }; } static <A> Decoder<A> ofTerminal(final Terminal<? extends A> terminal) { return terminal.decoder().map(Function.identity()); } static <A> Decoder<A> ofBoxed(final Boxed<? extends A> boxed) { return boxed.decoder().map(Function.identity()); } static <A> Decoder<A> ofSimple(final Simple<? extends A> simple) { return simple.decoder().map(Function.identity()); } static <A> MapDecoder<A> unit(final A instance) { return unit(() -> instance); } static <A> MapDecoder<A> unit(final Supplier<A> instance) { return new MapDecoder.Implementation<A>() { @Override public <T> DataResult<A> decode(final DynamicOps<T> ops, final MapLike<T> input) { return DataResult.success(instance.get()); } @Override public <T> Stream<T> keys(final DynamicOps<T> ops) { return Stream.empty(); } @Override public String toString() { return "UnitDecoder[" + instance.get() + "]"; } }; } static <A> Decoder<A> error(final String error) { return new Decoder<A>() { @Override public <T> DataResult<Pair<A, T>> decode(final DynamicOps<T> ops, final T input) { return DataResult.error(error); } @Override public String toString() { return "ErrorDecoder[" + error + ']'; } }; } interface Terminal<A> { <T> DataResult<A> decode(final DynamicOps<T> ops, final T input); default Decoder<A> decoder() { return new Decoder<A>() { @Override public <T> DataResult<Pair<A, T>> decode(final DynamicOps<T> 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<A> { <T> DataResult<Pair<A, T>> decode(final Dynamic<T> input); default Decoder<A> decoder() { return new Decoder<A>() { @Override public <T> DataResult<Pair<A, T>> decode(final DynamicOps<T> ops, final T input) { return Boxed.this.decode(new Dynamic<>(ops, input)); } @Override public String toString() { return "BoxedDecoder[" + Boxed.this + "]"; } }; } } interface Simple<A> { <T> DataResult<A> decode(final Dynamic<T> input); default Decoder<A> decoder() { return new Decoder<A>() { @Override public <T> DataResult<Pair<A, T>> decode(final DynamicOps<T> 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 + "]"; } }; } } }