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

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

Go to download

Fat Jar containing pkl-cli, pkl-codegen-java, pkl-codegen-kotlin, pkl-config-java, pkl-core, pkl-doc, and their shaded third-party dependencies.

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 3 types of value. See {@link OneOf2} for a full description. */
public class OneOf3 {
    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 index 0 means this represents an A, 1 a B, and 2 a C.
     */
    protected OneOf3(
            @NotNull Object o,
            @NotNull Class aClass,
            @NotNull Class bClass,
            @NotNull Class cClass,
            int index
    ) {
        types = RuntimeTypes.registerClasses(aClass, bClass, cClass);
        sel = index;
        item = o;
        if (index < 0) {
            throw new IllegalArgumentException("Selected item index must be 0-2");
        } else if (index > 2) {
            throw new IllegalArgumentException("Selected item index must be 0-2");
        }
        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.
     * @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
    ) {
        if (sel == 0) {
            return fa.apply((A) item);
        } else if (sel == 1) {
            return fb.apply((B) item);
        } else {
            return fc.apply((C) 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 OneOf3)) { return false; }

        @SuppressWarnings("rawtypes")
        OneOf3 that = (OneOf3) 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