All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.spongepowered.api.data.DataHolder Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
 * This file is part of SpongeAPI, licensed under the MIT License (MIT).
 *
 * Copyright (c) SpongePowered 
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.spongepowered.api.data;

import org.spongepowered.api.data.value.CollectionValue;
import org.spongepowered.api.data.value.MapValue;
import org.spongepowered.api.data.value.MergeFunction;
import org.spongepowered.api.data.value.Value;
import org.spongepowered.api.data.value.ValueContainer;
import org.spongepowered.api.util.annotation.DoNotStore;

import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * A data holder object allows the access of additional data on the object
 * that is not simply expressed by its basic type.
 */
@DoNotStore
public interface DataHolder extends ValueContainer {

    /**
     * Represents a data holder that allows its data to be modified.
     */
    interface Mutable extends DataHolder {

        /**
         * Applies a transformation on the provided {@link Value} such that
         * the return value of {@link Function#apply(Object)} will become the end
         * resulting value set into this {@link Mutable}. It is not
         * necessary that the input is actually present, in which case the
         * {@link Key}ed data is compatible, but not necessarily present. Writing
         * a {@link Function} to properly handle the potential for a null input
         * is required for this method to execute without exception.
         *
         * @param key The key linked to
         * @param function The function to manipulate the value
         * @param  The type of value
         * @return The end resulting value
         */
        default  DataTransactionResult transform(Key> key, Function function) {
            if (this.supports(key)) {
                return this.get(key)
                    .map(function)
                    .map(value -> this.offer(key, value))
                    .orElseGet(DataTransactionResult::failNoData);
            }
            return DataTransactionResult.failNoData();
        }

        /**
         * Applies a transformation on the provided {@link Value} such that
         * the return value of {@link Function#apply(Object)} will become the end
         * resulting value set into this {@link Mutable}. It is not
         * necessary that the input is actually present, in which case the
         * {@link Key}ed data is compatible, but not necessarily present. Writing
         * a {@link Function} to properly handle the potential for a null input
         * is required for this method to execute without exception.
         *
         * @param key The key linked to
         * @param function The function to manipulate the value
         * @param  The type of value
         * @return The end resulting value
         */
        default  DataTransactionResult transform(Supplier>> key, Function function) {
            return this.transform(key.get(), function);
        }

        /**
         * Offers the given {@code value} as defined by the provided {@link Key}
         * such that a {@link DataTransactionResult} is returned for any
         * successful, rejected, and replaced {@link Value}s from this
         * {@link Mutable}.
         *
         * @param key The key to the value to set
         * @param value The value to set
         * @param  The type of value
         * @return The transaction result
         */
         DataTransactionResult offer(Key> key, E value);

        /**
         * Offers the given {@code value} as defined by the provided {@link Key}
         * such that a {@link DataTransactionResult} is returned for any
         * successful, rejected, and replaced {@link Value}s from this
         * {@link Mutable}.
         *
         * @param key The key to the value to set
         * @param value The value to set
         * @param  The type of value
         * @return The transaction result
         */
        default  DataTransactionResult offer(Supplier>> key, E value) {
            return this.offer(key.get(), value);
        }

        /**
         * Offers the given {@code value} as defined by the provided {@link Key}
         * such that a {@link DataTransactionResult} is returned for any
         * successful, rejected, and replaced {@link Value}s from this
         * {@link Mutable}.
         *
         * @param key The key to the value to set
         * @param value The value to set
         * @param  The type of value
         * @return The transaction result
         */
        default  DataTransactionResult offer(Supplier>> key, Supplier value) {
            return this.offer(key.get(), value.get());
        }

        /**
         * Offers the given {@link Value} as defined by the provided
         * {@link Key} such that a {@link DataTransactionResult} is returned for
         * any successful, rejected, and replaced {@link Value}s from this
         * {@link Mutable}.
         *
         * @param value The value to set
         * @return The transaction result
         */
        DataTransactionResult offer(Value value);

         DataTransactionResult offerSingle(Key> key, E element);

        default  DataTransactionResult offerSingle(Supplier>> key, E element) {
            return this.offerSingle(key.get(), element);
        }

         DataTransactionResult offerSingle(Key> key, K valueKey, V value);

        default  DataTransactionResult offerSingle(Supplier>> key, K valueKey, V value) {
            return this.offerSingle(key.get(), valueKey, value);
        }

         DataTransactionResult offerAll(Key> key, Map map);

        default  DataTransactionResult offerAll(Supplier>> key, Map map) {
            return this.offerAll(key.get(), map);
        }

        DataTransactionResult offerAll(MapValue value);

        DataTransactionResult offerAll(CollectionValue value);

         DataTransactionResult offerAll(Key> key, Collection elements);

        default  DataTransactionResult offerAll(Supplier>> key, Collection elements) {
            return this.offerAll(key.get(), elements);
        }

         DataTransactionResult removeSingle(Key> key, E element);

        default  DataTransactionResult removeSingle(Supplier>> key, E element) {
            return this.removeSingle(key.get(), element);
        }

         DataTransactionResult removeKey(Key> key, K mapKey);

        default  DataTransactionResult removeKey(Supplier>> key, K mapKey) {
            return this.removeKey(key.get(), mapKey);
        }

        DataTransactionResult removeAll(CollectionValue value);

         DataTransactionResult removeAll(Key> key, Collection elements);

        default  DataTransactionResult removeAll(Supplier>> key, Collection elements) {
            return this.removeAll(key.get(), elements);
        }

        DataTransactionResult removeAll(MapValue value);

         DataTransactionResult removeAll(Key> key, Map map);

        default  DataTransactionResult removeAll(Supplier>> key, Map map) {
            return this.removeAll(key.get(), map);
        }

        /**
         * Offers the given {@code value} as defined by the provided {@link Key}
         * such that a {@link DataTransactionResult} is returned for any
         * successful {@link Value}s from this {@link Mutable}.
         * Intentionally, however, this differs from {@link #offer(Key, Object)}
         * as it will intentionally throw an exception if the result was a failure.
         *
         * @param key The key to the value to set
         * @param value The value to set
         * @param  The type of value
         * @return The transaction result
         * @throws IllegalArgumentException If the result is a failure likely due to
         *     incompatibility
         */
         DataTransactionResult tryOffer(Key> key, E value);

        /**
         * Offers the given {@code value} as defined by the provided {@link Key}
         * such that a {@link DataTransactionResult} is returned for any
         * successful {@link Value}s from this {@link Mutable}.
         * Intentionally, however, this differs from {@link #offer(Key, Object)}
         * as it will intentionally throw an exception if the result was a failure.
         *
         * @param key The key to the value to set
         * @param value The value to set
         * @param  The type of value
         * @return The transaction result
         * @throws IllegalArgumentException If the result is a failure likely due to
         *     incompatibility
         */
        default  DataTransactionResult tryOffer(Supplier>> key, E value) {
            return this.tryOffer(key.get(), value);
        }

        /**
         * Offers the given {@code value} as defined by the provided {@link Key}
         * such that a {@link DataTransactionResult} is returned for any
         * successful {@link Value}s from this {@link Mutable}.
         * Intentionally, however, this differs from {@link #offer(Key, Object)}
         * as it will intentionally throw an exception if the result was a failure.
         *
         * @param value The value to set
         * @param  The type of value
         * @return The transaction result
         * @throws IllegalArgumentException If the result is a failure likely due to
         *     incompatibility
         */
        default  DataTransactionResult tryOffer(Value value) throws IllegalArgumentException {
            final DataTransactionResult result = this.offer(value.key(), value.get());
            if (!result.isSuccessful()) {
                throw new IllegalArgumentException("Failed offer transaction!");
            }
            return result;
        }

        /**
         * Attempts to remove the provided {@link Value}. All values that were
         * successfully removed will be provided in
         * {@link DataTransactionResult#replacedData()}. If the data can not be
         * removed, the result will be an expected
         * {@link DataTransactionResult.Type#FAILURE}.
         *
         * @param value The value to remove
         * @return The transaction result
         */
        default DataTransactionResult remove(Value value) {
            return this.remove(value.key());
        }

        /**
         * Attempts to remove the data associated with the provided {@link Key}.
         * All values that were successfully removed will be provided in
         * {@link DataTransactionResult#replacedData()}. If the data can not be
         * removed, the result will be an expected
         * {@link DataTransactionResult.Type#FAILURE}.
         *
         * @param key The key of the data
         * @return The transaction result
         */
        DataTransactionResult remove(Key key);

        /**
         * Attempts to remove the data associated with the provided {@link Key}.
         * All values that were successfully removed will be provided in
         * {@link DataTransactionResult#replacedData()}. If the data can not be
         * removed, the result will be an expected
         * {@link DataTransactionResult.Type#FAILURE}.
         *
         * @param key The key of the data
         * @return The transaction result
         */
        default DataTransactionResult remove(Supplier> key) {
            return this.remove(key.get());
        }

        /**
         * Attempts to "revert" a {@link DataTransactionResult} such that any
         * of the {@link DataTransactionResult#replacedData()} are offered
         * back, and any {@link DataTransactionResult#successfulData()} are
         * removed if they were not the same types as any exising in the
         * replaced values.
         *
         * @param result The result to undo
         * @return The result of the undo
         */
        DataTransactionResult undo(DataTransactionResult result);

        /**
         * Performs an absolute copy of all {@link org.spongepowered.api.data.value.Value.Mutable}s and
         * {@link ValueContainer}s to this {@link Mutable} such that
         * any overlapping {@link org.spongepowered.api.data.value.Value.Mutable}s are offered for replacement. The
         * result is provided as a {@link DataTransactionResult}.
         *
         * @param that The other {@link Mutable} to copy values from
         * @return The transaction result
         */
        default DataTransactionResult copyFrom(ValueContainer that) {
            return this.copyFrom(that, MergeFunction.REPLACEMENT_PREFERRED);
        }

        /**
         * Performs an absolute copy of all {@link org.spongepowered.api.data.value.Value.Mutable}s and
         * {@link ValueContainer}s to this {@link Mutable} such that
         * any overlapping {@link org.spongepowered.api.data.value.Value.Mutable}s are offered for replacement. The
         * result is provided as a {@link DataTransactionResult}.
         *
         * @param that The other {@link Mutable} to copy values from
         * @param function The function to resolve merge conflicts
         * @return The transaction result
         */
        DataTransactionResult copyFrom(ValueContainer that, MergeFunction function);
    }

    /**
     * Represents a {@link DataHolder} that is immutable and can be transformed
     * into other immutable data holders.
     */
    interface Immutable> extends DataHolder {

        /**
         * Applies a transformation on the provided {@link Value} such that
         * the return value of {@link Function#apply(Object)} will become the end
         * resulting value set into the newly created {@link Immutable}.
         *
         * @param key The key linked to
         * @param function The function to manipulate the value
         * @param  The type of value
         * @return The newly created immutable value store
         */
         Optional transform(Key> key, Function function);

        /**
         * Applies a transformation on the provided {@link Value} such that
         * the return value of {@link Function#apply(Object)} will become the end
         * resulting value set into the newly created {@link Immutable}.
         *
         * @param key The key linked to
         * @param function The function to manipulate the value
         * @param  The type of value
         * @return The newly created immutable value store
         */
        default  Optional transform(Supplier>> key, Function function) {
            return this.transform(key.get(), function);
        }

        /**
         * Creates a new {@link Immutable} with the provided
         * value by {@link Key}. If the key is supported by this value store,
         * the returned value store will be present.
         *
         * @param key The key to the value to set
         * @param value The value to set
         * @param  The type of value
         * @return The new immutable value store
         */
         Optional with(Key> key, E value);

        /**
         * Creates a new {@link Immutable} with the provided
         * value by {@link Key}. If the key is supported by this value store,
         * the returned value store will be present.
         *
         * @param key The key to the value to set
         * @param value The value to set
         * @param  The type of value
         * @return The new immutable value store
         */
        default  Optional with(Supplier>> key, E value) {
            return this.with(key.get(), value);
        }

        /**
         * Offers the given {@code value} as defined by the provided {@link Key}
         * such that if the {@link Key} is supported, a new
         * {@link Immutable} is created.
         *
         * @param value The value to set
         * @return The new immutable value store
         */
        Optional with(Value value);

        /**
         * Creates a new {@link Immutable} without the key of the provided
         * {@link Value}. If the key is supported by this value store,
         * the returned value store will be present.
         *
         * @param value The value
         * @return The new immutable value store
         */
        default Optional without(Value value) {
            return this.without(value.key());
        }

        /**
         * Creates a new {@link Immutable} without the provided {@link Key}. If the
         * key is supported by this value store, the returned value store will
         * be present.
         *
         * @param key The key to remove
         * @return The new immutable value store
         */
        Optional without(Key key);

        /**
         * Creates a new {@link Immutable} without the provided {@link Key}. If the
         * key is supported by this value store, the returned value store will
         * be present.
         *
         * @param key The key to remove
         * @return The new immutable value store
         */
        default Optional without(Supplier> key) {
            return this.without(key.get());
        }

        /**
         * Attempts to merge the {@link org.spongepowered.api.data.value.Value.Immutable}s from this
         * {@link Immutable} and the given {@link Immutable} to
         * produce a new instance of the merged result.
         *
         * @param that The other immutable value store to gather values from
         * @return The new immutable value store instance
         */
        default I mergeWith(I that) {
            return this.mergeWith(that, MergeFunction.REPLACEMENT_PREFERRED);
        }

        /**
         * Attempts to merge the {@link org.spongepowered.api.data.value.Value.Immutable}s from this
         * {@link Immutable} and the given {@link Immutable} to
         * produce a new instance of the merged result. Any overlapping
         * {@link ValueContainer}s are merged through the {@link MergeFunction}.
         *
         * @param that The other immutable value store to gather values from
         * @param function The function to resolve merge conflicts
         * @return The new immutable value store instance
         */
        I mergeWith(I that, MergeFunction function);
    }
}