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

net.cassite.f.For Maven / Gradle / Ivy

The newest version!
package net.cassite.f;

import io.vertx.core.Future;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

public class For {
    private For() {
    }

    public static  ForEach each(@NotNull Iterable it) {
        if (it == null)
            throw new NullPointerException();
        return new ForEach<>(it.iterator(), true);
    }


    public static  ForEach each(@NotNull T[] tArr) {
        if (tArr == null)
            throw new NullPointerException();
        return new ForEach<>(Arrays.stream(tArr).iterator(), true);
    }

    public static  ForEach each(@NotNull Iterator ite) {
        if (ite == null)
            throw new NullPointerException();
        return new ForEach<>(ite, true);
    }

    static  ForEach eachThrowBreak(Iterable it) {
        return new ForEach<>(it.iterator(), false);
    }

    private interface ClearLoop {
        void clear();
    }

    private static  Future handleLoopFunc(MList results, T t, Function> func, ClearLoop clearLoop, boolean handleBreak) {
        Future fu;
        try {
            fu = func.apply(t);
        } catch (Break b) {
            if (!handleBreak) {
                throw b;
            }
            if (b.ins != null)
                //noinspection unchecked
                results.add((R) b.ins);
            clearLoop.clear();
            return F.unit();
        }
        Future rFu = Future.future();
        fu.setHandler(res -> {
            if (res.failed()) {
                clearLoop.clear();
                if (handleBreak && res.cause() instanceof Break) {
                    Break b = (Break) res.cause();
                    if (b.ins != null)
                        //noinspection unchecked
                        results.add((R) b.ins);
                    rFu.complete();
                } else {
                    rFu.fail(res.cause());
                }
                return;
            }
            R r = res.result();
            if (r != null)
                results.add(r);
            rFu.complete();
        });
        return rFu;
    }

    public static class ForEach {
        private final Iterator ite;
        private final boolean handleBreak;

        ForEach(Iterator ite, boolean handleBreak) {
            this.ite = ite;
            this.handleBreak = handleBreak;
        }

        public  Monad> yield(@NotNull Function> func) {
            if (func == null)
                throw new NullPointerException();
            MList results = MList.modifiable();
            return Monad.transform(handle(results, func).map(v -> results.immutable()));
        }

        private  Future handle(MList results, Function> func) {
            if (!ite.hasNext())
                return F.unit();
            T t = ite.next();
            return handleLoopFunc(results, t, func, () -> {
                while (ite.hasNext()) ite.next();
            }, handleBreak).compose(v -> handle(results, func));
        }
    }

    public static  ForLoop init(@Nullable I initVal) {
        return new ForLoop<>(initVal);
    }

    public static class ForLoopCtx {
        @Nullable
        public I i;
    }

    public static class ForLoop {
        private ForLoopCtx ctx = new ForLoopCtx<>();

        ForLoop(I i) {
            ctx.i = i;
        }

        public WithCondition cond(@NotNull Function, Future> condition) {
            if (condition == null)
                throw new NullPointerException();
            return new WithCondition(condition);
        }

        public WithCondition condSync(@NotNull Predicate> condition) {
            if (condition == null)
                throw new NullPointerException();
            return new WithCondition(ctx -> F.unit(condition.test(ctx)));
        }

        public class WithCondition {
            private final Function, Future> condition;

            WithCondition(Function, Future> condition) {
                this.condition = condition;
            }

            public WithIncr incr(@NotNull Function, Future> incrFunc) {
                if (incrFunc == null)
                    throw new NullPointerException();
                return new WithIncr(incrFunc);
            }

            public WithIncr incrSync(@NotNull Consumer> incrFunc) {
                if (incrFunc == null)
                    throw new NullPointerException();
                return incr(ctx -> {
                    incrFunc.accept(ctx);
                    return F.unit();
                });
            }

            public class WithIncr {
                private final Function, Future> incr;

                WithIncr(Function, Future> incr) {
                    this.incr = incr;
                }

                public  Monad> yield(@NotNull Function, Future> func) {
                    if (func == null)
                        throw new NullPointerException();
                    MList results = MList.modifiable();
                    return Monad.transform(handle(new boolean[]{true}, results, func).map(v -> results.immutable()));
                }

                private  Future handle(boolean[] doContinue, MList results, Function, Future> func) {
                    return condition.apply(ctx).compose(b -> {
                        if (!b) return F.unit();
                        if (!doContinue[0]) return F.unit();
                        return handleLoopFunc(results, ctx, func, () -> doContinue[0] = false, true)
                            .compose(v -> incr.apply(ctx))
                            .compose(v -> handle(doContinue, results, func));
                    });
                }
            }
        }
    }
}