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

com.github.morinb.func.Either Maven / Gradle / Ivy

There is a newer version: 1.8
Show newest version
/*
 * Copyright 2024 Baptiste MORIN
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.morinb.func;


import java.io.Serializable;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;

/**
 * An interface representing either a left or a right value.
 *
 * @param  The type of the left value
 * @param  The type of the right value
 */
public sealed interface Either
        extends Value, Serializable
        permits Either.Left, Either.Right
{


    /**
     * Returns a new instance of Right with the specified value.
     *
     * @param    the type of the left value
     * @param    the type of the right value
     * @param value the value for the right side of the instance
     * @return a new instance of Right with the specified value
     */
    static  Right right(final R value)
    {
        return new Right<>(value);
    }

    /**
     * Returns a new instance of Left with the specified value.
     *
     * @param    the type of the left value
     * @param    the type of the right value
     * @param value the value for the left side of the instance
     * @return a new instance of Left with the specified value
     */
    static  Left left(final L value)
    {
        return new Left<>(value);
    }

    /**
     * Performs a no-operation and returns a new Either object with a Right value of null.
     *
     * @param  The type of the Left value in the Either object.
     * @param  The type of the Right value in the Either object.
     * @return A new Either object with a Right value of null.
     */
    static  Either noop()
    {
        return new Right<>(null);
    }

    /**
     * Creates an empty Either object.
     *
     * @param  The type of the left value.
     * @param  The type of the right value.
     * @return An empty Either object of type Either<L, R>.
     */
    static  Either empty()
    {
        return new Left<>(null);
    }

    /**
     * Zips or accumulates the values from multiple Either instances. If all input Either instances are Right,
     * the transform function is applied to the values and the result is wrapped in a Right. If any of the input
     * Either instances are Left, the Left values are accumulated into a NonEmptyList and returned.
     *
     * @param        the type of the Left value
     * @param        the type of the Right value for Either a
     * @param        the type of the Right value for Either b
     * @param        the type of the result value
     * @param a         the Either for value a
     * @param b         the Either for value b
     * @param transform the function to apply to the values if all Either instances are Right
     * @return an Either containing the accumulated Left values or the result of applying the transform function
     */
    static  Either, Z> zipOrAccumulate(
            final Either a,
            final Either b,
            final Function2 transform
    )
    {
        return zipOrAccumulate(
                a, b, Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb));
    }

    /**
     * Zips or accumulates the values from multiple Either instances. If all input Either instances are Right,
     * the transform function is applied to the values and the result is wrapped in a Right. If any of the input
     * Either instances are Left, the Left values are accumulated into a NonEmptyList and returned.
     *
     * @param        the type of the Left value
     * @param        the type of the Right value for Either a
     * @param        the type of the Right value for Either b
     * @param        the type of the Right value for Either c
     * @param        the type of the result value
     * @param a         the Either for value a
     * @param b         the Either for value b
     * @param c         the Either for value c
     * @param transform the function to apply to the values if all Either instances are Right
     * @return an Either containing the accumulated Left values or the result of applying the transform function
     */
    static  Either, Z> zipOrAccumulate(
            final Either a,
            final Either b,
            final Either c,
            final Function3 transform
    )
    {
        return zipOrAccumulate(
                a, b, c, Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc));
    }

    /**
     * Zips or accumulates the values from multiple Either instances. If all input Either instances are Right,
     * the transform function is applied to the values and the result is wrapped in a Right. If any of the input
     * Either instances are Left, the Left values are accumulated into a NonEmptyList and returned.
     *
     * @param        the type of the Left value
     * @param        the type of the Right value for Either a
     * @param        the type of the Right value for Either b
     * @param        the type of the Right value for Either c
     * @param        the type of the Right value for Either d
     * @param        the type of the result value
     * @param a         the Either for value a
     * @param b         the Either for value b
     * @param c         the Either for value c
     * @param d         the Either for value d
     * @param transform the function to apply to the values if all Either instances are Right
     * @return an Either containing the accumulated Left values or the result of applying the transform function
     */
    static  Either, Z> zipOrAccumulate(
            final Either a,
            final Either b,
            final Either c,
            final Either d,
            final Function4 transform
    )
    {
        return zipOrAccumulate(
                a, b, c, d, Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd));
    }

    /**
     * Zips or accumulates the values from multiple Either instances. If all input Either instances are Right,
     * the transform function is applied to the values and the result is wrapped in a Right. If any of the input
     * Either instances are Left, the Left values are accumulated into a NonEmptyList and returned.
     *
     * @param        the type of the Left value
     * @param        the type of the Right value for Either a
     * @param        the type of the Right value for Either b
     * @param        the type of the Right value for Either c
     * @param        the type of the Right value for Either d
     * @param        the type of the Right value for Either e
     * @param        the type of the result value
     * @param a         the Either for value a
     * @param b         the Either for value b
     * @param c         the Either for value c
     * @param d         the Either for value d
     * @param e         the Either for value e
     * @param transform the function to apply to the values if all Either instances are Right
     * @return an Either containing the accumulated Left values or the result of applying the transform function
     */
    static  Either, Z> zipOrAccumulate(
            final Either a,
            final Either b,
            final Either c,
            final Either d,
            final Either e,
            final Function5 transform
    )
    {
        return zipOrAccumulate(
                a, b, c, d, e, Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee));
    }

    /**
     * Zips or accumulates the values from multiple Either instances. If all input Either instances are Right,
     * the transform function is applied to the values and the result is wrapped in a Right. If any of the input
     * Either instances are Left, the Left values are accumulated into a NonEmptyList and returned.
     *
     * @param        the type of the Left value
     * @param        the type of the Right value for Either a
     * @param        the type of the Right value for Either b
     * @param        the type of the Right value for Either c
     * @param        the type of the Right value for Either d
     * @param        the type of the Right value for Either e
     * @param        the type of the Right value for Either f
     * @param        the type of the result value
     * @param a         the Either for value a
     * @param b         the Either for value b
     * @param c         the Either for value c
     * @param d         the Either for value d
     * @param e         the Either for value e
     * @param f         the Either for value f
     * @param transform the function to apply to the values if all Either instances are Right
     * @return an Either containing the accumulated Left values or the result of applying the transform function
     */
    static  Either, Z> zipOrAccumulate(
            final Either a,
            final Either b,
            final Either c,
            final Either d,
            final Either e,
            final Either f,
            final Function6 transform
    )
    {
        return zipOrAccumulate(
                a, b, c, d, e, f, Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee, ff));
    }

    /**
     * Zips or accumulates the values from multiple Either instances. If all input Either instances are Right,
     * the transform function is applied to the values and the result is wrapped in a Right. If any of the input
     * Either instances are Left, the Left values are accumulated into a NonEmptyList and returned.
     *
     * @param        the type of the Left value
     * @param        the type of the Right value for Either a
     * @param        the type of the Right value for Either b
     * @param        the type of the Right value for Either c
     * @param        the type of the Right value for Either d
     * @param        the type of the Right value for Either e
     * @param        the type of the Right value for Either f
     * @param        the type of the Right value for Either g
     * @param        the type of the result value
     * @param a         the Either for value a
     * @param b         the Either for value b
     * @param c         the Either for value c
     * @param d         the Either for value d
     * @param e         the Either for value e
     * @param f         the Either for value f
     * @param g         the Either for value g
     * @param transform the function to apply to the values if all Either instances are Right
     * @return an Either containing the accumulated Left values or the result of applying the transform function
     */
    @SuppressWarnings("squid:S107")
    static  Either, Z> zipOrAccumulate(
            final Either a,
            final Either b,
            final Either c,
            final Either d,
            final Either e,
            final Either f,
            final Either g,
            final Function7 transform
    )
    {
        return zipOrAccumulate(
                a, b, c, d, e, f, g, Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee, ff, gg));
    }

    /**
     * Zips or accumulates the values from multiple Either instances. If all input Either instances are Right,
     * the transform function is applied to the values and the result is wrapped in a Right. If any of the input
     * Either instances are Left, the Left values are accumulated into a NonEmptyList and returned.
     *
     * @param        the type of the Left value
     * @param        the type of the Right value for Either a
     * @param        the type of the Right value for Either b
     * @param        the type of the Right value for Either c
     * @param        the type of the Right value for Either d
     * @param        the type of the Right value for Either e
     * @param        the type of the Right value for Either f
     * @param        the type of the Right value for Either g
     * @param        the type of the Right value for Either h
     * @param        the type of the result value
     * @param a         the Either for value a
     * @param b         the Either for value b
     * @param c         the Either for value c
     * @param d         the Either for value d
     * @param e         the Either for value e
     * @param f         the Either for value f
     * @param g         the Either for value g
     * @param h         the Either for value h
     * @param transform the function to apply to the values if all Either instances are Right
     * @return an Either containing the accumulated Left values or the result of applying the transform function
     */
    @SuppressWarnings("squid:S107")
    static  Either, Z> zipOrAccumulate(
            final Either a,
            final Either b,
            final Either c,
            final Either d,
            final Either e,
            final Either f,
            final Either g,
            final Either h,
            final Function8 transform
    )
    {
        return zipOrAccumulate(
                a, b, c, d, e, f, g, h, Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee, ff, gg, hh));
    }

    /**
     * Zips or accumulates the values from multiple Either instances. If all input Either instances are Right,
     * the transform function is applied to the values and the result is wrapped in a Right. If any of the input
     * Either instances are Left, the Left values are accumulated into a NonEmptyList and returned.
     *
     * @param        the type of the Left value
     * @param        the type of the Right value for Either a
     * @param        the type of the Right value for Either b
     * @param        the type of the Right value for Either c
     * @param        the type of the Right value for Either d
     * @param        the type of the Right value for Either e
     * @param        the type of the Right value for Either f
     * @param        the type of the Right value for Either g
     * @param        the type of the Right value for Either h
     * @param        the type of the Right value for Either i
     * @param        the type of the result value
     * @param a         the Either for value a
     * @param b         the Either for value b
     * @param c         the Either for value c
     * @param d         the Either for value d
     * @param e         the Either for value e
     * @param f         the Either for value f
     * @param g         the Either for value g
     * @param h         the Either for value h
     * @param i         the Either for value i
     * @param transform the function to apply to the values if all Either instances are Right
     * @return an Either containing the accumulated Left values or the result of applying the transform function
     */
    @SuppressWarnings("squid:S107")
    static  Either, Z> zipOrAccumulate(
            final Either a,
            final Either b,
            final Either c,
            final Either d,
            final Either e,
            final Either f,
            final Either g,
            final Either h,
            final Either i,
            final Function9 transform
    )
    {
        return zipOrAccumulate(
                a, b, c, d, e, f, g, h, i, Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee, ff, gg, hh, ii));
    }

    /**
     * Zips or accumulates the values from multiple Either instances. If all input Either instances are Right,
     * the transform function is applied to the values and the result is wrapped in a Right. If any of the input
     * Either instances are Left, the Left values are accumulated into a NonEmptyList and returned.
     *
     * @param        the type of the Left value
     * @param        the type of the Right value for Either a
     * @param        the type of the Right value for Either b
     * @param        the type of the Right value for Either c
     * @param        the type of the Right value for Either d
     * @param        the type of the Right value for Either e
     * @param        the type of the Right value for Either f
     * @param        the type of the Right value for Either g
     * @param        the type of the Right value for Either h
     * @param        the type of the Right value for Either i
     * @param        the type of the Right value for Either j
     * @param        the type of the result value
     * @param a         the Either for value a
     * @param b         the Either for value b
     * @param c         the Either for value c
     * @param d         the Either for value d
     * @param e         the Either for value e
     * @param f         the Either for value f
     * @param g         the Either for value g
     * @param h         the Either for value h
     * @param i         the Either for value i
     * @param j         the Either for value j
     * @param transform the function to apply to the values if all Either instances are Right
     * @return an Either containing the accumulated Left values or the result of applying the transform function
     */
    @SuppressWarnings({"squid:S107"})
    static  Either, Z> zipOrAccumulate(
            final Either a,
            final Either b,
            final Either c,
            final Either d,
            final Either e,
            final Either f,
            final Either g,
            final Either h,
            final Either i,
            final Either j,
            final Function10 transform
    )
    {
        final var eithers = FList.of(a, b, c, d, e, f, g, h, i, j);

        final var errors = eithers
                .filter(Either::isLeft)
                .map(Either::getLeft);

        if (errors.isEmpty())
        {
            return right(transform.apply(a.get(), b.get(), c.get(), d.get(), e.get(), f.get(), g.get(), h.get(), i.get(), j.get()));
        }
        else
        {
            return left(NonEmptyList.of(errors));
        }
    }

    /**
     * Combines or accumulates multiple Either into a single Either.
     * If all the input Either are Right, then
     * the transform function is applied to their Right values and the result is returned as a Right. If any of the
     * input Either are Left, then the Left values are accumulated and returned as a NonEmptyList of errors.
     *
     * @param        The type of the error value in the input Either and the resulting NonEmptyList of errors.
     * @param        The type of the Right value in the first input Either.
     * @param        The type of the Right value in the second input Either.
     * @param        The type of the result when transforming the Right values with the given transform function.
     * @param a         The first input Either.
     * @param b         The second input Either.
     * @param transform The function to transform the Right values of the input Either into a result of type Z.
     * @return Either - Either containing the accumulated errors as a NonEmptyList or the transformed right value as a Right.
     */

    static  Either, Z> zipOrAccumulateNel(
            final Either, A> a,
            final Either, B> b,
            final Function2 transform
    )
    {
        return zipOrAccumulateNel(
                a, b, Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb));
    }

    /**
     * Combines or accumulates multiple Either into a single Either.
     * If all the input Either are Right, then
     * the transform function is applied to their Right values and the result is returned as a Right. If any of the
     * input Either are Left, then the Left values are accumulated and returned as a NonEmptyList of errors.
     *
     * @param        The type of the error value in the input Either and the resulting NonEmptyList of errors.
     * @param        The type of the Right value in the first input Either.
     * @param        The type of the Right value in the second input Either.
     * @param        The type of the Right value in the third input Either.
     * @param        The type of the result when transforming the Right values with the given transform function.
     * @param a         The first input Either.
     * @param b         The second input Either.
     * @param c         The third input Either.
     * @param transform The function to transform the Right values of the input Either into a result of type Z.
     * @return Either - Either containing the accumulated errors as a NonEmptyList or the transformed right value as a Right.
     */

    static  Either, Z> zipOrAccumulateNel(
            final Either, A> a,
            final Either, B> b,
            final Either, C> c,
            final Function3 transform
    )
    {
        return zipOrAccumulateNel(
                a, b, c, Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc));
    }

    /**
     * Combines or accumulates multiple Either into a single Either.
     * If all the input Either are Right, then
     * the transform function is applied to their Right values and the result is returned as a Right. If any of the
     * input Either are Left, then the Left values are accumulated and returned as a NonEmptyList of errors.
     *
     * @param        The type of the error value in the input Either and the resulting NonEmptyList of errors.
     * @param        The type of the Right value in the first input Either.
     * @param        The type of the Right value in the second input Either.
     * @param        The type of the Right value in the third input Either.
     * @param        The type of the Right value in the fourth input Either.
     * @param        The type of the result when transforming the Right values with the given transform function.
     * @param a         The first input Either.
     * @param b         The second input Either.
     * @param c         The third input Either.
     * @param d         The fourth input Either.
     * @param transform The function to transform the Right values of the input Either into a result of type Z.
     * @return Either - Either containing the accumulated errors as a NonEmptyList or the transformed right value as a Right.
     */


    static  Either, Z> zipOrAccumulateNel(
            final Either, A> a,
            final Either, B> b,
            final Either, C> c,
            final Either, D> d,
            final Function4 transform
    )
    {
        return zipOrAccumulateNel(
                a, b, c, d, Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd));
    }

    /**
     * Combines or accumulates multiple Either into a single Either.
     * If all the input Either are Right, then
     * the transform function is applied to their Right values and the result is returned as a Right. If any of the
     * input Either are Left, then the Left values are accumulated and returned as a NonEmptyList of errors.
     *
     * @param        The type of the error value in the input Either and the resulting NonEmptyList of errors.
     * @param        The type of the Right value in the first input Either.
     * @param        The type of the Right value in the second input Either.
     * @param        The type of the Right value in the third input Either.
     * @param        The type of the Right value in the fourth input Either.
     * @param        The type of the Right value in the fifth input Either.
     * @param        The type of the result when transforming the Right values with the given transform function.
     * @param a         The first input Either.
     * @param b         The second input Either.
     * @param c         The third input Either.
     * @param d         The fourth input Either.
     * @param e         The fifth input Either.
     * @param transform The function to transform the Right values of the input Either into a result of type Z.
     * @return Either - Either containing the accumulated errors as a NonEmptyList or the transformed right value as a Right.
     */

    static  Either, Z> zipOrAccumulateNel(
            final Either, A> a,
            final Either, B> b,
            final Either, C> c,
            final Either, D> d,
            final Either, E> e,
            final Function5 transform
    )
    {
        return zipOrAccumulateNel(
                a, b, c, d, e, Either.noop(), Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee));
    }

    /**
     * Combines or accumulates multiple Either into a single Either.
     * If all the input Either are Right, then
     * the transform function is applied to their Right values and the result is returned as a Right. If any of the
     * input Either are Left, then the Left values are accumulated and returned as a NonEmptyList of errors.
     *
     * @param        The type of the error value in the input Either and the resulting NonEmptyList of errors.
     * @param        The type of the Right value in the first input Either.
     * @param        The type of the Right value in the second input Either.
     * @param        The type of the Right value in the third input Either.
     * @param        The type of the Right value in the fourth input Either.
     * @param        The type of the Right value in the fifth input Either.
     * @param        The type of the Right value in the sixth input Either.
     * @param        The type of the result when transforming the Right values with the given transform function.
     * @param a         The first input Either.
     * @param b         The second input Either.
     * @param c         The third input Either.
     * @param d         The fourth input Either.
     * @param e         The fifth input Either.
     * @param f         The sixth input Either.
     * @param transform The function to transform the Right values of the input Either into a result of type Z.
     * @return Either - Either containing the accumulated errors as a NonEmptyList or the transformed right value as a Right.
     */

    static  Either, Z> zipOrAccumulateNel(
            final Either, A> a,
            final Either, B> b,
            final Either, C> c,
            final Either, D> d,
            final Either, E> e,
            final Either, F> f,
            final Function6 transform
    )
    {
        return zipOrAccumulateNel(
                a, b, c, d, e, f, Either.noop(), Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee, ff));
    }

    /**
     * Combines or accumulates multiple Either into a single Either.
     * If all the input Either are Right, then
     * the transform function is applied to their Right values and the result is returned as a Right. If any of the
     * input Either are Left, then the Left values are accumulated and returned as a NonEmptyList of errors.
     *
     * @param        The type of the error value in the input Either and the resulting NonEmptyList of errors.
     * @param        The type of the Right value in the first input Either.
     * @param        The type of the Right value in the second input Either.
     * @param        The type of the Right value in the third input Either.
     * @param        The type of the Right value in the fourth input Either.
     * @param        The type of the Right value in the fifth input Either.
     * @param        The type of the Right value in the sixth input Either.
     * @param        The type of the Right value in the seventh input Either.
     * @param        The type of the result when transforming the Right values with the given transform function.
     * @param a         The first input Either.
     * @param b         The second input Either.
     * @param c         The third input Either.
     * @param d         The fourth input Either.
     * @param e         The fifth input Either.
     * @param f         The sixth input Either.
     * @param g         The seventh input Either.
     * @param transform The function to transform the Right values of the input Either into a result of type Z.
     * @return Either - Either containing the accumulated errors as a NonEmptyList or the transformed right value as a Right.
     */

    @SuppressWarnings("squid:S107")
    static  Either, Z> zipOrAccumulateNel(
            final Either, A> a,
            final Either, B> b,
            final Either, C> c,
            final Either, D> d,
            final Either, E> e,
            final Either, F> f,
            final Either, G> g,
            final Function7 transform
    )
    {
        return zipOrAccumulateNel(
                a, b, c, d, e, f, g, Either.noop(), Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee, ff, gg));
    }

    /**
     * Combines or accumulates multiple Either into a single Either.
     * If all the input Either are Right, then
     * the transform function is applied to their Right values and the result is returned as a Right. If any of the
     * input Either are Left, then the Left values are accumulated and returned as a NonEmptyList of errors.
     *
     * @param        The type of the error value in the input Either and the resulting NonEmptyList of errors.
     * @param        The type of the Right value in the first input Either.
     * @param        The type of the Right value in the second input Either.
     * @param        The type of the Right value in the third input Either.
     * @param        The type of the Right value in the fourth input Either.
     * @param        The type of the Right value in the fifth input Either.
     * @param        The type of the Right value in the sixth input Either.
     * @param        The type of the Right value in the seventh input Either.
     * @param        The type of the Right value in the eighth input Either.
     * @param        The type of the result when transforming the Right values with the given transform function.
     * @param a         The first input Either.
     * @param b         The second input Either.
     * @param c         The third input Either.
     * @param d         The fourth input Either.
     * @param e         The fifth input Either.
     * @param f         The sixth input Either.
     * @param g         The seventh input Either.
     * @param h         The eighth input Either.
     * @param transform The function to transform the Right values of the input Either into a result of type Z.
     * @return Either - Either containing the accumulated errors as a NonEmptyList or the transformed right value as a Right.
     */

    @SuppressWarnings("squid:S107")
    static  Either, Z> zipOrAccumulateNel(
            final Either, A> a,
            final Either, B> b,
            final Either, C> c,
            final Either, D> d,
            final Either, E> e,
            final Either, F> f,
            final Either, G> g,
            final Either, H> h,
            final Function8 transform
    )
    {
        return zipOrAccumulateNel(
                a, b, c, d, e, f, g, h, Either.noop(), Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee, ff, gg, hh));
    }

    /**
     * Combines or accumulates multiple Either into a single Either.
     * If all the input Either are Right, then
     * the transform function is applied to their Right values and the result is returned as a Right. If any of the
     * input Either are Left, then the Left values are accumulated and returned as a NonEmptyList of errors.
     *
     * @param        The type of the error value in the input Either and the resulting NonEmptyList of errors.
     * @param        The type of the Right value in the first input Either.
     * @param        The type of the Right value in the second input Either.
     * @param        The type of the Right value in the third input Either.
     * @param        The type of the Right value in the fourth input Either.
     * @param        The type of the Right value in the fifth input Either.
     * @param        The type of the Right value in the sixth input Either.
     * @param        The type of the Right value in the seventh input Either.
     * @param        The type of the Right value in the eighth input Either.
     * @param        The type of the Right value in the ninth input Either.
     * @param        The type of the result when transforming the Right values with the given transform function.
     * @param a         The first input Either.
     * @param b         The second input Either.
     * @param c         The third input Either.
     * @param d         The fourth input Either.
     * @param e         The fifth input Either.
     * @param f         The sixth input Either.
     * @param g         The seventh input Either.
     * @param h         The eighth input Either.
     * @param i         The ninth input Either.
     * @param transform The function to transform the Right values of the input Either into a result of type Z.
     * @return Either - Either containing the accumulated errors as a NonEmptyList or the transformed right value as a Right.
     */
    @SuppressWarnings("squid:S107")
    static  Either, Z> zipOrAccumulateNel(
            final Either, A> a,
            final Either, B> b,
            final Either, C> c,
            final Either, D> d,
            final Either, E> e,
            final Either, F> f,
            final Either, G> g,
            final Either, H> h,
            final Either, I> i,
            final Function9 transform
    )
    {
        return zipOrAccumulateNel(
                a, b, c, d, e, f, g, h, i, Either.noop(),
                (aa, bb, cc, dd, ee, ff, gg, hh, ii, jj) -> transform.apply(aa, bb, cc, dd, ee, ff, gg, hh, ii));
    }

    /**
     * Combines or accumulates multiple Either into a single Either.
     * If all the input Either are Right, then
     * the transform function is applied to their Right values and the result is returned as a Right. If any of the
     * input Either are Left, then the Left values are accumulated and returned as a NonEmptyList of errors.
     *
     * @param        The type of the error value in the input Either and the resulting NonEmptyList of errors.
     * @param        The type of the Right value in the first input Either.
     * @param        The type of the Right value in the second input Either.
     * @param        The type of the Right value in the third input Either.
     * @param        The type of the Right value in the fourth input Either.
     * @param        The type of the Right value in the fifth input Either.
     * @param        The type of the Right value in the sixth input Either.
     * @param        The type of the Right value in the seventh input Either.
     * @param        The type of the Right value in the eighth input Either.
     * @param        The type of the Right value in the ninth input Either.
     * @param        The type of the Right value in the tenth input Either.
     * @param        The type of the result when transforming the Right values with the given transform function.
     * @param a         The first input Either.
     * @param b         The second input Either.
     * @param c         The third input Either.
     * @param d         The fourth input Either.
     * @param e         The fifth input Either.
     * @param f         The sixth input Either.
     * @param g         The seventh input Either.
     * @param h         The eighth input Either.
     * @param i         The ninth input Either.
     * @param j         The tenth input Either.
     * @param transform The function to transform the Right values of the input Either into a result of type Z.
     * @return Either - Either containing the accumulated errors as a NonEmptyList or the transformed right value as a Right.
     */
    @SuppressWarnings("squid:S107")
    static  Either, Z> zipOrAccumulateNel(
            final Either, A> a,
            final Either, B> b,
            final Either, C> c,
            final Either, D> d,
            final Either, E> e,
            final Either, F> f,
            final Either, G> g,
            final Either, H> h,
            final Either, I> i,
            final Either, J> j,
            final Function10 transform
    )
    {
        final var eithers = FList.of(a, b, c, d, e, f, g, h, i, j);

        final var errors = eithers
                .filter(Either::isLeft)
                .map(Either::getLeft)
                .flatMap(NonEmptyList::toFList);

        if (errors.isEmpty())
        {
            return right(transform.apply(a.get(), b.get(), c.get(), d.get(), e.get(), f.get(), g.get(), h.get(), i.get(), j.get()));
        }
        else
        {
            return left(NonEmptyList.of(errors));
        }
    }

    /**
     * Checks if the instance is of the Left type.
     *
     * @return true if the instance is of the Left type, false otherwise.
     */
    boolean isLeft();

    /**
     * Checks if the instance is of the Right type.
     *
     * @return true if the instance is of the Right type, false otherwise.
     */
    boolean isRight();

    /**
     * Retrieves the value of the left side of the Either instance.
     *
     * @return The value of the left side.
     */
    L getLeft();

    /**
     * Returns the value if it is present, or throws an exception if it is empty.
     *
     * @param exceptionMapper the function that maps the left value to an exception to be thrown
     * @param              the type of exception to be thrown
     * @return the value if it is present
     * @throws X                    if the value is empty
     * @throws NullPointerException if exceptionMapper is null
     */
    default  R getOrElseThrow(final Function1 exceptionMapper) throws X
    {
        Objects.requireNonNull(exceptionMapper, "exceptionMapper is null");
        if (isEmpty())
        {
            throw exceptionMapper.apply(getLeft());
        }
        return get();
    }

    @Override
    default boolean isEmpty()
    {
        return isLeft();
    }

    @Override
    default Iterator iterator()
    {
        if (isRight())
        {
            return new Iterator<>()
            {
                boolean hasNext = true;

                @Override
                public boolean hasNext()
                {
                    return hasNext;
                }

                @Override
                public R next()
                {
                    if (!hasNext)
                    {
                        throw new NoSuchElementException();
                    }
                    hasNext = false;
                    return get();
                }
            };
        }
        else
        {
            return new Iterator<>()
            {
                @Override
                public boolean hasNext()
                {
                    return false;
                }

                @Override
                public R next()
                {
                    throw new NoSuchElementException();
                }

            };
        }

    }

    /**
     * Performs the specified action on the value of the Right side of this Either, if it exists.
     *
     * @param action the action to be performed on the value of the Right side
     * @return this Either
     */
    default Either peek(final Consumer action)
    {
        Objects.requireNonNull(action, "action is null");
        if (isRight())
        {
            action.accept(get());
        }
        return this;
    }

    /**
     * Performs the specified action on the left value of this Either, if it is present.
     *
     * @param action the action to be performed on the left value, must not be null
     * @return this Either
     */
    default Either peekLeft(final Consumer action)
    {
        Objects.requireNonNull(action, "action is null");
        if (isLeft())
        {
            action.accept(getLeft());
        }
        return this;
    }

    /**
     * Maps the value of the Either if it is a right value, using the provided mapper function.
     *
     * @param     The type of the mapped value.
     * @param mapper The function to apply to the value if it is a right value.
     * @return A new Either containing the mapped value, or the same Either if it is a left value.
     */
    @SuppressWarnings("unchecked")
    default  Either map(final Function1 mapper)
    {
        if (isRight())
        {
            return right(mapper.apply(get()));
        }
        else
        {
            return (Either) this;
        }
    }

    /**
     * This method applies the given mapper function to the left value of this Either object and returns a new Either object with the result.
     *
     * @param mapper the function to apply to the left value
     * @param     the type of the result of the function
     * @return a new Either object with the result of applying the mapper function to the left value
     */
    @SuppressWarnings("unchecked")
    default  Either mapLeft(final Function1 mapper)
    {
        Objects.requireNonNull(mapper, "mapper is null");
        if (isLeft())
        {
            return left(mapper.apply(getLeft()));
        }
        else
        {
            return (Either) this;
        }
    }

    /**
     * Applies the specified mappers to the values of the Either,
     * returning a new Either instance with the transformed values.
     *
     * @param leftMapper  the mapper function to apply to the left value
     * @param rightMapper the mapper function to apply to the right value
     * @param          the type of the left value of the Either
     * @param          the type of the right value of the Either
     * @return a new Either instance with the transformed values
     */
    default  Either bimap(final Function1 leftMapper, final Function1 rightMapper)
    {
        Objects.requireNonNull(leftMapper, "leftMapper is null");
        Objects.requireNonNull(rightMapper, "rightMapper is null");
        if (isLeft())
        {
            return left(leftMapper.apply(getLeft()));
        }
        else
        {
            return right(rightMapper.apply(get()));
        }
    }

    /**
     * Applies the given leftMapper function on the left value if this either is in the left state,
     * or applies the given rightMapper function on the right value if this either is in the right state.
     * Returns the result of the function application.
     *
     * @param leftMapper  the function to be applied on the left value if this either is in the left state
     * @param rightMapper the function to be applied on the right value if this either is in the right state
     * @param          the type of the result of the function application
     * @return the result of the function application
     * @throws NullPointerException if leftMapper is null or rightMapper is null
     */
    default  U fold(final Function1 leftMapper, final Function1 rightMapper)
    {
        Objects.requireNonNull(leftMapper, "leftMapper is null");
        Objects.requireNonNull(rightMapper, "rightMapper is null");
        if (isRight())
        {
            return rightMapper.apply(get());
        }
        else
        {
            return leftMapper.apply(getLeft());
        }
    }

    /**
     * Represents the left side of an {@link Either}.
     * An instance of Left stores a value of type L on the left side.
     *
     * @param  the type of the value stored on the left side
     * @param  the type of the value stored on the right side
     */
    final class Left implements Either
    {

        /**
         * Represents the value stored in an instance of Left.
         * 

* This value is final and cannot be modified once initialized. */ private final L value; /** * Constructs a new instance of Left with the specified value. * * @param value the value for the left side of the instance */ public Left(final L value) { this.value = value; } /** * Determines if the object is from the left side. * * @return {@code true} if the object is from the left side, * {@code false} otherwise. */ @Override public boolean isLeft() { return true; } /** * Checks if the current object represents the right side of an Either object. * * @return {@code false} since this object represents the left side of an Either object */ @Override public boolean isRight() { return false; } /** * Retrieves the value contained in an instance of Left. * * @return the value contained in the Left instance. * @throws NoSuchElementException if called on an instance of Left. */ @Override public R get() { throw new NoSuchElementException("Calling get on a Left"); } /** * Retrieves the left value of this object. * * @return the left value */ @Override public L getLeft() { return value; } @Override public boolean equals(final Object obj) { return (obj == this) || (obj instanceof Either.Left && Objects.equals(value, ((Left) obj).value)); } @Override public int hashCode() { return Objects.hashCode(value); } @Override public String toString() { if (getLeft() == null) { return "Left(null)"; } return "Left(" + getLeft() + ")"; } } /** * Represents a Right value in the Either type. * * @param the type of the Left value * @param the type of the Right value */ final class Right implements Either { /** * Value stored in an instance of the Right class. */ private final R value; /** * Constructs a new Right instance with the specified value. * * @param value the value for the right side of the instance */ public Right(final R value) { this.value = value; } /** * Determines if the given object is positioned at the left. * * @return {@code true} if the object is at the left, {@code false} otherwise. */ @Override public boolean isLeft() { return false; } /** * Returns a boolean value indicating whether this instance represents a right value. * * @return true if this instance represents a right value, false otherwise. */ @Override public boolean isRight() { return true; } /** * Returns the value of the Right type object. * * @return the value of the Right type object */ @Override public R get() { return value; } /** * Retrieves the left value of this Either instance. * * @return the left value of this Either instance. * @throws NoSuchElementException if this is a Right instance. */ @Override public L getLeft() { throw new NoSuchElementException("Calling getLeft on a Right"); } @Override public boolean equals(final Object obj) { return (obj == this) || (obj instanceof Right && Objects.equals(value, ((Right) obj).value)); } @Override public int hashCode() { return Objects.hashCode(value); } @Override public String toString() { if (get() == null) { return "Right(null)"; } return "Right(" + get() + ")"; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy