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

org.pkl.thirdparty.paguro.oneOf.OneOf4 Maven / Gradle / Ivy

Go to download

Shaded fat Jar for pkl-config-java, a Java config library based on the Pkl config language.

There is a newer version: 0.27.1
Show newest version
package org.pkl.thirdparty.paguro.oneOf;

import org.pkl.thirdparty.jetbrains.annotations.NotNull;
import org.pkl.thirdparty.paguro.collections.ImList;
import org.pkl.thirdparty.paguro.function.Fn1;
import org.pkl.thirdparty.paguro.type.RuntimeTypes;

import java.util.Objects;

import static org.pkl.thirdparty.paguro.type.RuntimeTypes.union2Str;

/** Holds one of 4 types of value. See {@link OneOf2} for a full description. */
public abstract class OneOf4 {
    protected final @NotNull Object item;
    private final int sel;
    @SuppressWarnings("rawtypes")
    private final @NotNull ImList types;

    /**
     * Protected constructor for subclassing.
     *
     * @param o the item
     * @param aClass class 0
     * @param bClass class 1
     * @param cClass class 2
     * @param dClass class 3
     * @param index 0 means this represents an A, 1 a B, 2 a C, and 3 a D.
     */
    protected OneOf4(
            @NotNull Object o,
            @NotNull Class aClass,
            @NotNull Class bClass,
            @NotNull Class cClass,
            @NotNull Class dClass,
            int index
    ) {
        types = RuntimeTypes.registerClasses(aClass, bClass, cClass, dClass);
        sel = index;
        item = o;
        if (index < 0) {
            throw new IllegalArgumentException("Selected item index must be 0-3");
        } else if (index > 3) {
            throw new IllegalArgumentException("Selected item index must be 0-3");
        }
        if (!types.get(index).isInstance(o)) {
            throw new ClassCastException("You specified index " + index + ", indicating a(n) " +
                                         types.get(index).getCanonicalName() + "," +
                                         " but passed a " + o.getClass().getCanonicalName());
        }
    }

    /**
     * Languages that have union types built in have a match statement that works like this method.
     * Exactly one of these functions will be executed - determined by which type of item this object holds.
     * @param fa applied iff this stores the first type.
     * @param fb applied iff this stores the second type.
     * @param fc applied iff this stores the third type.
     * @param fd applied iff this stores the fourth type.
     * @return the return value of whichever function is executed.
     */
    // We only store one item and its type is erased, so we have to cast it at runtime.
    // If sel is managed correctly, this ensures that cast is accurate.
    @SuppressWarnings("unchecked")
    public  R match(
            @NotNull Fn1 fa,
            @NotNull Fn1 fb,
            @NotNull Fn1 fc,
            @NotNull Fn1 fd
    ) {
        if (sel == 0) {
            return fa.apply((A) item);
        } else if (sel == 1) {
            return fb.apply((B) item);
        } else if (sel == 2) {
            return fc.apply((C) item);
        } else {
            return fd.apply((D) item);
        }
    }

    public int hashCode() {
        // Simplest way to make the two items different.
        return Objects.hashCode(item) + sel;
    }

    @Override public boolean equals(Object other) {
        if (this == other) { return true; }
        if (!(other instanceof OneOf4)) { return false; }

        @SuppressWarnings("rawtypes")
        OneOf4 that = (OneOf4) other;
        return (sel == that.sel) &&
               Objects.equals(item, that.item);
    }

    @Override
    public @NotNull String toString() { return union2Str(item, types); }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy