// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. package com.mojang.serialization; 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 org.apache.commons.lang3.mutable.MutableObject; import java.nio.ByteBuffer; 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.LongStream; import java.util.stream.Stream; @SuppressWarnings("unused") public abstract class DynamicLike<T> { protected final DynamicOps<T> ops; public DynamicLike(final DynamicOps<T> ops) { this.ops = ops; } public DynamicOps<T> getOps() { return ops; } public abstract DataResult<Number> asNumber(); public abstract DataResult<String> asString(); public abstract DataResult<Stream<Dynamic<T>>> asStreamOpt(); public abstract DataResult<Stream<Pair<Dynamic<T>, Dynamic<T>>>> asMapOpt(); public abstract DataResult<ByteBuffer> asByteBufferOpt(); public abstract DataResult<IntStream> asIntStreamOpt(); public abstract DataResult<LongStream> asLongStreamOpt(); public abstract OptionalDynamic<T> get(String key); public abstract DataResult<T> getGeneric(T key); public abstract DataResult<T> getElement(String key); public abstract DataResult<T> getElementGeneric(T key); public abstract <A> DataResult<Pair<A, T>> decode(final Decoder<? extends A> decoder); public <U> DataResult<List<U>> asListOpt(final Function<Dynamic<T>, U> deserializer) { return asStreamOpt().map(stream -> stream.map(deserializer).collect(Collectors.toList())); } public <K, V> DataResult<Map<K, V>> asMapOpt(final Function<Dynamic<T>, K> keyDeserializer, final Function<Dynamic<T>, V> valueDeserializer) { return asMapOpt().map(map -> { final ImmutableMap.Builder<K, V> builder = ImmutableMap.builder(); map.forEach(entry -> builder.put(keyDeserializer.apply(entry.getFirst()), valueDeserializer.apply(entry.getSecond())) ); return builder.build(); }); } public <A> DataResult<A> read(final Decoder<? extends A> decoder) { return decode(decoder).map(Pair::getFirst); } public <E> DataResult<List<E>> readList(final Decoder<E> decoder) { return asStreamOpt() .map(s -> s.map(d -> d.read(decoder)).collect(Collectors.<App<DataResult.Mu, E>>toList())) .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); } public <E> DataResult<List<E>> readList(final Function<? super Dynamic<?>, ? extends DataResult<? extends E>> decoder) { return asStreamOpt() .map(s -> s.map(decoder).map(r -> r.map(e -> (E) e)).collect(Collectors.<App<DataResult.Mu, E>>toList())) .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); } public <K, V> DataResult<List<Pair<K, V>>> readMap(final Decoder<K> keyDecoder, final Decoder<V> 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.<App<DataResult.Mu, Pair<K, V>>>toList())) .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); } public <K, V> DataResult<List<Pair<K, V>>> readMap(final Decoder<K> keyDecoder, final Function<K, Decoder<V>> 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.<App<DataResult.Mu, Pair<K, V>>>toList())) .flatMap(l -> DataResult.unbox(ListBox.flip(DataResult.instance(), l))); } public <R> DataResult<R> readMap(final DataResult<R> empty, final Function3<R, Dynamic<T>, Dynamic<T>, DataResult<R>> combiner) { return asMapOpt().flatMap(stream -> { // TODO: AtomicReference.getPlain/setPlain in java9+ final MutableObject<DataResult<R>> result = new MutableObject<>(empty); stream.forEach(p -> result.setValue(result.getValue().flatMap(r -> combiner.apply(r, p.getFirst(), p.getSecond())))); return result.getValue(); }); } public Number asNumber(final Number defaultValue) { return asNumber().result().orElse(defaultValue); } public int asInt(final int defaultValue) { return asNumber(defaultValue).intValue(); } public long asLong(final long defaultValue) { return asNumber(defaultValue).longValue(); } public float asFloat(final float defaultValue) { return asNumber(defaultValue).floatValue(); } public double asDouble(final double defaultValue) { return asNumber(defaultValue).doubleValue(); } public byte asByte(final byte defaultValue) { return asNumber(defaultValue).byteValue(); } public short asShort(final short defaultValue) { return asNumber(defaultValue).shortValue(); } public boolean asBoolean(final boolean defaultValue) { return asNumber(defaultValue ? 1 : 0).intValue() != 0; } public String asString(final String defaultValue) { return asString().result().orElse(defaultValue); } public Stream<Dynamic<T>> asStream() { return asStreamOpt().result().orElseGet(Stream::empty); } public ByteBuffer asByteBuffer() { return asByteBufferOpt().result().orElseGet(() -> ByteBuffer.wrap(new byte[0])); } public IntStream asIntStream() { return asIntStreamOpt().result().orElseGet(IntStream::empty); } public LongStream asLongStream() { return asLongStreamOpt().result().orElseGet(LongStream::empty); } public <U> List<U> asList(final Function<Dynamic<T>, U> deserializer) { return asListOpt(deserializer).result().orElseGet(ImmutableList::of); } public <K, V> Map<K, V> asMap(final Function<Dynamic<T>, K> keyDeserializer, final Function<Dynamic<T>, V> valueDeserializer) { return asMapOpt(keyDeserializer, valueDeserializer).result().orElseGet(ImmutableMap::of); } public T getElement(final String key, final T defaultValue) { return getElement(key).result().orElse(defaultValue); } public T getElementGeneric(final T key, final T defaultValue) { return getElementGeneric(key).result().orElse(defaultValue); } public Dynamic<T> emptyList() { return new Dynamic<>(ops, ops.emptyList()); } public Dynamic<T> emptyMap() { return new Dynamic<>(ops, ops.emptyMap()); } public Dynamic<T> createNumeric(final Number i) { return new Dynamic<>(ops, ops.createNumeric(i)); } public Dynamic<T> createByte(final byte value) { return new Dynamic<>(ops, ops.createByte(value)); } public Dynamic<T> createShort(final short value) { return new Dynamic<>(ops, ops.createShort(value)); } public Dynamic<T> createInt(final int value) { return new Dynamic<>(ops, ops.createInt(value)); } public Dynamic<T> createLong(final long value) { return new Dynamic<>(ops, ops.createLong(value)); } public Dynamic<T> createFloat(final float value) { return new Dynamic<>(ops, ops.createFloat(value)); } public Dynamic<T> createDouble(final double value) { return new Dynamic<>(ops, ops.createDouble(value)); } public Dynamic<T> createBoolean(final boolean value) { return new Dynamic<>(ops, ops.createBoolean(value)); } public Dynamic<T> createString(final String value) { return new Dynamic<>(ops, ops.createString(value)); } public Dynamic<T> createList(final Stream<? extends Dynamic<?>> input) { return new Dynamic<>(ops, ops.createList(input.map(element -> element.cast(ops)))); } public Dynamic<T> createMap(final Map<? extends Dynamic<?>, ? extends Dynamic<?>> map) { final ImmutableMap.Builder<T, T> builder = ImmutableMap.builder(); for (final Map.Entry<? extends Dynamic<?>, ? extends Dynamic<?>> entry : map.entrySet()) { builder.put(entry.getKey().cast(ops), entry.getValue().cast(ops)); } return new Dynamic<>(ops, ops.createMap(builder.build())); } public Dynamic<?> createByteList(final ByteBuffer input) { return new Dynamic<>(ops, ops.createByteList(input)); } public Dynamic<?> createIntList(final IntStream input) { return new Dynamic<>(ops, ops.createIntList(input)); } public Dynamic<?> createLongList(final LongStream input) { return new Dynamic<>(ops, ops.createLongList(input)); } }