Package yalp.libs

Source Code of yalp.libs.F$Promise

package yalp.libs;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;

import yalp.exceptions.UnexpectedException;

public class F {

    public static class Promise<V> implements Future<V>, F.Action<V> {

        final CountDownLatch taskLock = new CountDownLatch(1);
        boolean cancelled = false;

        public boolean cancel(boolean mayInterruptIfRunning) {
            return false;
        }

        public boolean isCancelled() {
            return false;
        }

        public boolean isDone() {
            return invoked;
        }

        public V getOrNull() {
            return result;
        }

        public V get() throws InterruptedException, ExecutionException {
            taskLock.await();
            if (exception != null) {
                // The result of the promise is an exception - throw it
                throw new ExecutionException(exception);
            }
            return result;
        }

        public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            taskLock.await(timeout, unit);
            if (exception != null) {
                // The result of the promise is an exception - throw it
                throw new ExecutionException(exception);
            }
            return result;
        }

        List<F.Action<Promise<V>>> callbacks = new ArrayList<F.Action<Promise<V>>>();
        boolean invoked = false;
        V result = null;
        Throwable exception = null;

        public void invoke(V result) {
            invokeWithResultOrException(result, null);
        }

        public void invokeWithException(Throwable t) {
            invokeWithResultOrException(null, t);
        }

        protected void invokeWithResultOrException(V result, Throwable t) {
            synchronized (this) {
                if (!invoked) {
                    invoked = true;
                    this.result = result;
                    this.exception = t;
                    taskLock.countDown();
                } else {
                    return;
                }
            }
            for (F.Action<Promise<V>> callback : callbacks) {
                callback.invoke(this);
            }
        }

        public void onRedeem(F.Action<Promise<V>> callback) {
            synchronized (this) {
                if (!invoked) {
                    callbacks.add(callback);
                }
            }
            if (invoked) {
                callback.invoke(this);
            }
        }

        public static <T> Promise<List<T>> waitAll(final Promise<T>... promises) {
            return waitAll(Arrays.asList(promises));
        }

        public static <T> Promise<List<T>> waitAll(final Collection<Promise<T>> promises) {
            final CountDownLatch waitAllLock = new CountDownLatch(promises.size());
            final Promise<List<T>> result = new Promise<List<T>>() {

                @Override
                public boolean cancel(boolean mayInterruptIfRunning) {
                    boolean r = true;
                    for (Promise<T> f : promises) {
                        r = r & f.cancel(mayInterruptIfRunning);
                    }
                    return r;
                }

                @Override
                public boolean isCancelled() {
                    boolean r = true;
                    for (Promise<T> f : promises) {
                        r = r & f.isCancelled();
                    }
                    return r;
                }

                @Override
                public boolean isDone() {
                    boolean r = true;
                    for (Promise<T> f : promises) {
                        r = r & f.isDone();
                    }
                    return r;
                }

                @Override
                public List<T> get() throws InterruptedException, ExecutionException {
                    waitAllLock.await();
                    List<T> r = new ArrayList<T>();
                    for (Promise<T> f : promises) {
                        r.add(f.get());
                    }
                    return r;
                }

                @Override
                public List<T> get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
                    waitAllLock.await(timeout, unit);
                    return get();
                }
            };
            final F.Action<Promise<T>> action = new F.Action<Promise<T>>() {

                public void invoke(Promise<T> completed) {
                    waitAllLock.countDown();
                    if (waitAllLock.getCount() == 0) {
                        try {
                            result.invoke(result.get());
                        } catch (Exception e) {
                            throw new UnexpectedException(e);
                        }
                    }
                }
            };
            for (Promise<T> f : promises) {
                f.onRedeem(action);
            }
            return result;
        }

        public static <A, B> Promise<F.Tuple<A, B>> wait2(Promise<A> tA, Promise<B> tB) {
            final Promise<F.Tuple<A, B>> result = new Promise<F.Tuple<A, B>>();
            final Promise<List<Object>> t = waitAll(new Promise[]{tA, tB});
            t.onRedeem(new F.Action<Promise<List<Object>>>() {

                public void invoke(Promise<List<Object>> completed) {
                    List<Object> values = completed.getOrNull();
                    result.invoke(new F.Tuple((A) values.get(0), (B) values.get(1)));
                }
            });
            return result;
        }

        public static <A, B, C> Promise<F.T3<A, B, C>> wait3(Promise<A> tA, Promise<B> tB, Promise<C> tC) {
            final Promise<F.T3<A, B, C>> result = new Promise<F.T3<A, B, C>>();
            final Promise<List<Object>> t = waitAll(new Promise[]{tA, tB, tC});
            t.onRedeem(new F.Action<Promise<List<Object>>>() {

                public void invoke(Promise<List<Object>> completed) {
                    List<Object> values = completed.getOrNull();
                    result.invoke(new F.T3((A) values.get(0), (B) values.get(1), (C) values.get(2)));
                }
            });
            return result;
        }

        public static <A, B, C, D> Promise<F.T4<A, B, C, D>> wait4(Promise<A> tA, Promise<B> tB, Promise<C> tC, Promise<D> tD) {
            final Promise<F.T4<A, B, C, D>> result = new Promise<F.T4<A, B, C, D>>();
            final Promise<List<Object>> t = waitAll(new Promise[]{tA, tB, tC, tD});
            t.onRedeem(new F.Action<Promise<List<Object>>>() {

                public void invoke(Promise<List<Object>> completed) {
                    List<Object> values = completed.getOrNull();
                    result.invoke(new F.T4((A) values.get(0), (B) values.get(1), (C) values.get(2), (D) values.get(3)));
                }
            });
            return result;
        }

        public static <A, B, C, D, E> Promise<F.T5<A, B, C, D, E>> wait5(Promise<A> tA, Promise<B> tB, Promise<C> tC, Promise<D> tD, Promise<E> tE) {
            final Promise<F.T5<A, B, C, D, E>> result = new Promise<F.T5<A, B, C, D, E>>();
            final Promise<List<Object>> t = waitAll(new Promise[]{tA, tB, tC, tD, tE});
            t.onRedeem(new F.Action<Promise<List<Object>>>() {

                public void invoke(Promise<List<Object>> completed) {
                    List<Object> values = completed.getOrNull();
                    result.invoke(new F.T5((A) values.get(0), (B) values.get(1), (C) values.get(2), (D) values.get(3), (E) values.get(4)));
                }
            });
            return result;
        }

        private static Promise<F.Tuple<Integer, Promise<Object>>> waitEitherInternal(final Promise<?>... futures) {
            final Promise<F.Tuple<Integer, Promise<Object>>> result = new Promise<F.Tuple<Integer, Promise<Object>>>();
            for (int i = 0; i < futures.length; i++) {
                final int index = i + 1;
                ((Promise<Object>) futures[i]).onRedeem(new F.Action<Promise<Object>>() {

                    public void invoke(Promise<Object> completed) {
                        result.invoke(new F.Tuple(index, completed));
                    }
                });
            }
            return result;
        }

        public static <A, B> Promise<F.Either<A, B>> waitEither(final Promise<A> tA, final Promise<B> tB) {
            final Promise<F.Either<A, B>> result = new Promise<F.Either<A, B>>();
            final Promise<F.Tuple<Integer, Promise<Object>>> t = waitEitherInternal(tA, tB);

            t.onRedeem(new F.Action<Promise<F.Tuple<Integer, Promise<Object>>>>() {

                public void invoke(Promise<F.Tuple<Integer, Promise<Object>>> completed) {
                    F.Tuple<Integer, Promise<Object>> value = completed.getOrNull();
                    switch (value._1) {
                        case 1:
                            result.invoke(F.Either.<A, B>_1((A) value._2.getOrNull()));
                            break;
                        case 2:
                            result.invoke(F.Either.<A, B>_2((B) value._2.getOrNull()));
                            break;
                    }

                }
            });

            return result;
        }

        public static <A, B, C> Promise<F.E3<A, B, C>> waitEither(final Promise<A> tA, final Promise<B> tB, final Promise<C> tC) {
            final Promise<F.E3<A, B, C>> result = new Promise<F.E3<A, B, C>>();
            final Promise<F.Tuple<Integer, Promise<Object>>> t = waitEitherInternal(tA, tB, tC);

            t.onRedeem(new F.Action<Promise<F.Tuple<Integer, Promise<Object>>>>() {

                public void invoke(Promise<F.Tuple<Integer, Promise<Object>>> completed) {
                    F.Tuple<Integer, Promise<Object>> value = completed.getOrNull();
                    switch (value._1) {
                        case 1:
                            result.invoke(F.E3.<A, B, C>_1((A) value._2.getOrNull()));
                            break;
                        case 2:
                            result.invoke(F.E3.<A, B, C>_2((B) value._2.getOrNull()));
                            break;
                        case 3:
                            result.invoke(F.E3.<A, B, C>_3((C) value._2.getOrNull()));
                            break;
                    }

                }
            });

            return result;
        }

        public static <A, B, C, D> Promise<F.E4<A, B, C, D>> waitEither(final Promise<A> tA, final Promise<B> tB, final Promise<C> tC, final Promise<D> tD) {
            final Promise<F.E4<A, B, C, D>> result = new Promise<F.E4<A, B, C, D>>();
            final Promise<F.Tuple<Integer, Promise<Object>>> t = waitEitherInternal(tA, tB, tC, tD);

            t.onRedeem(new F.Action<Promise<F.Tuple<Integer, Promise<Object>>>>() {

                public void invoke(Promise<F.Tuple<Integer, Promise<Object>>> completed) {
                    F.Tuple<Integer, Promise<Object>> value = completed.getOrNull();
                    switch (value._1) {
                        case 1:
                            result.invoke(F.E4.<A, B, C, D>_1((A) value._2.getOrNull()));
                            break;
                        case 2:
                            result.invoke(F.E4.<A, B, C, D>_2((B) value._2.getOrNull()));
                            break;
                        case 3:
                            result.invoke(F.E4.<A, B, C, D>_3((C) value._2.getOrNull()));
                            break;
                        case 4:
                            result.invoke(F.E4.<A, B, C, D>_4((D) value._2.getOrNull()));
                            break;
                    }

                }
            });

            return result;
        }

        public static <A, B, C, D, E> Promise<F.E5<A, B, C, D, E>> waitEither(final Promise<A> tA, final Promise<B> tB, final Promise<C> tC, final Promise<D> tD, final Promise<E> tE) {
            final Promise<F.E5<A, B, C, D, E>> result = new Promise<F.E5<A, B, C, D, E>>();
            final Promise<F.Tuple<Integer, Promise<Object>>> t = waitEitherInternal(tA, tB, tC, tD, tE);

            t.onRedeem(new F.Action<Promise<F.Tuple<Integer, Promise<Object>>>>() {

                public void invoke(Promise<F.Tuple<Integer, Promise<Object>>> completed) {
                    F.Tuple<Integer, Promise<Object>> value = completed.getOrNull();
                    switch (value._1) {
                        case 1:
                            result.invoke(F.E5.<A, B, C, D, E>_1((A) value._2.getOrNull()));
                            break;
                        case 2:
                            result.invoke(F.E5.<A, B, C, D, E>_2((B) value._2.getOrNull()));
                            break;
                        case 3:
                            result.invoke(F.E5.<A, B, C, D, E>_3((C) value._2.getOrNull()));
                            break;
                        case 4:
                            result.invoke(F.E5.<A, B, C, D, E>_4((D) value._2.getOrNull()));
                            break;
                        case 5:
                            result.invoke(F.E5.<A, B, C, D, E>_5((E) value._2.getOrNull()));
                            break;

                    }

                }
            });

            return result;
        }

        public static <T> Promise<T> waitAny(final Promise<T>... futures) {
            final Promise<T> result = new Promise<T>();

            final F.Action<Promise<T>> action = new F.Action<Promise<T>>() {

                public void invoke(Promise<T> completed) {
                    synchronized (this) {
                        if (result.isDone()) {
                            return;
                        }
                    }
                    result.invoke(completed.getOrNull());
                }
            };

            for (Promise<T> f : futures) {
                f.onRedeem(action);
            }

            return result;
        }
    }

    public static class Timeout extends Promise<Timeout> {

        static Timer timer = new Timer("F.Timeout", true);
        final public String token;
        final public long delay;

        public Timeout(String delay) {
            this(Time.parseDuration(delay) * 1000);
        }

        public Timeout(String token, String delay) {
            this(token, Time.parseDuration(delay) * 1000);
        }

        public Timeout(long delay) {
            this("timeout", delay);
        }

        public Timeout(String token, long delay) {
            this.delay = delay;
            this.token = token;
            final Timeout timeout = this;
            timer.schedule(new TimerTask() {

                @Override
                public void run() {
                    timeout.invoke(timeout);
                }
            }, delay);
        }

        @Override
        public String toString() {
            return "Timeout(" + delay + ")";
        }

    }

    public static Timeout Timeout(String delay) {
        return new Timeout(delay);
    }

    public static Timeout Timeout(String token, String delay) {
        return new Timeout(token, delay);
    }

    public static Timeout Timeout(long delay) {
        return new Timeout(delay);
    }

    public static Timeout Timeout(String token, long delay) {
        return new Timeout(token, delay);
    }

    public static class EventStream<T> {

        final int bufferSize;
        final ConcurrentLinkedQueue<T> events = new ConcurrentLinkedQueue<T>();
        final List<Promise<T>> waiting = Collections.synchronizedList(new ArrayList<Promise<T>>());

        public EventStream() {
            this.bufferSize = 100;
        }

        public EventStream(int maxBufferSize) {
            this.bufferSize = maxBufferSize;
        }

        public synchronized Promise<T> nextEvent() {
            if (events.isEmpty()) {
                LazyTask task = new LazyTask();
                waiting.add(task);
                return task;
            }
            return new LazyTask(events.peek());
        }

        public synchronized void publish(T event) {
            if (events.size() > bufferSize) {
                events.poll();
            }
            events.offer(event);
            notifyNewEvent();
        }

        void notifyNewEvent() {
            T value = events.peek();
            for (Promise<T> task : waiting) {
                task.invoke(value);
            }
            waiting.clear();
        }

        class LazyTask extends Promise<T> {

            public LazyTask() {
            }

            public LazyTask(T value) {
                invoke(value);
            }

            @Override
            public T get() throws InterruptedException, ExecutionException {
                T value = super.get();
                markAsRead(value);
                return value;
            }

            @Override
            public T getOrNull() {
                T value = super.getOrNull();
                markAsRead(value);
                return value;
            }

            private void markAsRead(T value) {
                if (value != null) {
                    events.remove(value);
                }
            }
        }
    }

    public static class IndexedEvent<M> {

        private static final AtomicLong idGenerator = new AtomicLong(1);
        final public M data;
        final public Long id;

        public IndexedEvent(M data) {
            this.data = data;
            this.id = idGenerator.getAndIncrement();
        }

        @Override
        public String toString() {
            return "Event(id: " + id + ", " + data + ")";
        }

        public static void resetIdGenerator() {
            idGenerator.set(1);
        }
    }

    public static class ArchivedEventStream<T> {

        final int archiveSize;
        final ConcurrentLinkedQueue<IndexedEvent<T>> events = new ConcurrentLinkedQueue<IndexedEvent<T>>();
        final List<FilterTask<T>> waiting = Collections.synchronizedList(new ArrayList<FilterTask<T>>());
        final List<EventStream<T>> pipedStreams = new ArrayList<EventStream<T>>();

        public ArchivedEventStream(int archiveSize) {
            this.archiveSize = archiveSize;
        }

        public synchronized EventStream<T> eventStream() {
            final EventStream<T> stream = new EventStream<T>(archiveSize);
            for (IndexedEvent<T> event : events) {
                stream.publish(event.data);
            }
            pipedStreams.add(stream);
            return stream;
        }

        public synchronized Promise<List<IndexedEvent<T>>> nextEvents(long lastEventSeen) {
            FilterTask<T> filter = new FilterTask<T>(lastEventSeen);
            waiting.add(filter);
            notifyNewEvent();
            return filter;
        }

        public synchronized List<IndexedEvent> availableEvents(long lastEventSeen) {
            List<IndexedEvent> result = new ArrayList<IndexedEvent>();
            for (IndexedEvent event : events) {
                if (event.id > lastEventSeen) {
                    result.add(event);
                }
            }
            return result;
        }

        public List<T> archive() {
            List<T> result = new ArrayList<T>();
            for (IndexedEvent<T> event : events) {
                result.add(event.data);
            }
            return result;
        }

        public synchronized void publish(T event) {
            if (events.size() >= archiveSize) {
                events.poll();
            }
            events.offer(new IndexedEvent(event));
            notifyNewEvent();
            for (EventStream<T> eventStream : pipedStreams) {
                eventStream.publish(event);
            }
        }

        void notifyNewEvent() {
            for (ListIterator<FilterTask<T>> it = waiting.listIterator(); it.hasNext(); ) {
                FilterTask<T> filter = it.next();
                for (IndexedEvent<T> event : events) {
                    filter.propose(event);
                }
                if (filter.trigger()) {
                    it.remove();
                }
            }
        }

        static class FilterTask<K> extends Promise<List<IndexedEvent<K>>> {

            final Long lastEventSeen;
            final List<IndexedEvent<K>> newEvents = new ArrayList<IndexedEvent<K>>();

            public FilterTask(Long lastEventSeen) {
                this.lastEventSeen = lastEventSeen;
            }

            public void propose(IndexedEvent<K> event) {
                if (event.id > lastEventSeen) {
                    newEvents.add(event);
                }
            }

            public boolean trigger() {
                if (newEvents.isEmpty()) {
                    return false;
                }
                invoke(newEvents);
                return true;
            }
        }
    }

    public static interface Action0 {

        void invoke();
    }

    public static interface Action<T> {

        void invoke(T result);
    }

    public static abstract class Option<T> implements Iterable<T> {

        public abstract boolean isDefined();

        public abstract T get();

        public static <T> None<T> None() {
            return (None<T>) (Object) None;
        }

        public static <T> Some<T> Some(T value) {
            return new Some<T>(value);
        }
    }

    public static <A> Some<A> Some(A a) {
        return new Some(a);
    }

    public static class None<T> extends Option<T> {

        @Override
        public boolean isDefined() {
            return false;
        }

        @Override
        public T get() {
            throw new IllegalStateException("No value");
        }

        public Iterator<T> iterator() {
            return Collections.<T>emptyList().iterator();
        }

        @Override
        public String toString() {
            return "None";
        }
    }

    public static None<Object> None = new None<Object>();

    public static class Some<T> extends Option<T> {

        final T value;

        public Some(T value) {
            this.value = value;
        }

        @Override
        public boolean isDefined() {
            return true;
        }

        @Override
        public T get() {
            return value;
        }

        public Iterator<T> iterator() {
            return Collections.singletonList(value).iterator();
        }

        @Override
        public String toString() {
            return "Some(" + value + ")";
        }
    }

    public static class Either<A, B> {

        final public Option<A> _1;
        final public Option<B> _2;

        private Either(Option<A> _1, Option<B> _2) {
            this._1 = _1;
            this._2 = _2;
        }

        public static <A, B> Either<A, B> _1(A value) {
            return new Either(Some(value), None);
        }

        public static <A, B> Either<A, B> _2(B value) {
            return new Either(None, Some(value));
        }

        @Override
        public String toString() {
            return "E2(_1: " + _1 + ", _2: " + _2 + ")";
        }
    }

    public static class E2<A, B> extends Either<A, B> {

        private E2(Option<A> _1, Option<B> _2) {
            super(_1, _2);
        }
    }

    public static class E3<A, B, C> {

        final public Option<A> _1;
        final public Option<B> _2;
        final public Option<C> _3;

        private E3(Option<A> _1, Option<B> _2, Option<C> _3) {
            this._1 = _1;
            this._2 = _2;
            this._3 = _3;
        }

        public static <A, B, C> E3<A, B, C> _1(A value) {
            return new E3(Some(value), None, None);
        }

        public static <A, B, C> E3<A, B, C> _2(B value) {
            return new E3(None, Some(value), None);
        }

        public static <A, B, C> E3<A, B, C> _3(C value) {
            return new E3(None, None, Some(value));
        }

        @Override
        public String toString() {
            return "E3(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ")";
        }
    }

    public static class E4<A, B, C, D> {

        final public Option<A> _1;
        final public Option<B> _2;
        final public Option<C> _3;
        final public Option<D> _4;

        private E4(Option<A> _1, Option<B> _2, Option<C> _3, Option<D> _4) {
            this._1 = _1;
            this._2 = _2;
            this._3 = _3;
            this._4 = _4;
        }

        public static <A, B, C, D> E4<A, B, C, D> _1(A value) {
            return new E4(Option.Some(value), None, None, None);
        }

        public static <A, B, C, D> E4<A, B, C, D> _2(B value) {
            return new E4(None, Some(value), None, None);
        }

        public static <A, B, C, D> E4<A, B, C, D> _3(C value) {
            return new E4(None, None, Some(value), None);
        }

        public static <A, B, C, D> E4<A, B, C, D> _4(D value) {
            return new E4(None, None, None, Some(value));
        }

        @Override
        public String toString() {
            return "E4(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ", _4:" + _4 + ")";
        }
    }

    public static class E5<A, B, C, D, E> {

        final public Option<A> _1;
        final public Option<B> _2;
        final public Option<C> _3;
        final public Option<D> _4;
        final public Option<E> _5;

        private E5(Option<A> _1, Option<B> _2, Option<C> _3, Option<D> _4, Option<E> _5) {
            this._1 = _1;
            this._2 = _2;
            this._3 = _3;
            this._4 = _4;
            this._5 = _5;
        }

        public static <A, B, C, D, E> E5<A, B, C, D, E> _1(A value) {
            return new E5(Option.Some(value), None, None, None, None);
        }

        public static <A, B, C, D, E> E5<A, B, C, D, E> _2(B value) {
            return new E5(None, Option.Some(value), None, None, None);
        }

        public static <A, B, C, D, E> E5<A, B, C, D, E> _3(C value) {
            return new E5(None, None, Option.Some(value), None, None);
        }

        public static <A, B, C, D, E> E5<A, B, C, D, E> _4(D value) {
            return new E5(None, None, None, Option.Some(value), None);
        }

        public static <A, B, C, D, E> E5<A, B, C, D, E> _5(E value) {
            return new E5(None, None, None, None, Option.Some(value));
        }

        @Override
        public String toString() {
            return "E5(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ", _4:" + _4 + ", _5:" + _5 + ")";
        }
    }

    public static class Tuple<A, B> {

        final public A _1;
        final public B _2;

        public Tuple(A _1, B _2) {
            this._1 = _1;
            this._2 = _2;
        }

        @Override
        public String toString() {
            return "T2(_1: " + _1 + ", _2: " + _2 + ")";
        }
    }

    public static <A, B> Tuple<A, B> Tuple(A a, B b) {
        return new Tuple(a, b);
    }

    public static class T2<A, B> extends Tuple<A, B> {

        public T2(A _1, B _2) {
            super(_1, _2);
        }
    }

    public static <A, B> T2<A, B> T2(A a, B b) {
        return new T2(a, b);
    }

    public static class T3<A, B, C> {

        final public A _1;
        final public B _2;
        final public C _3;

        public T3(A _1, B _2, C _3) {
            this._1 = _1;
            this._2 = _2;
            this._3 = _3;
        }

        @Override
        public String toString() {
            return "T3(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ")";
        }
    }

    public static <A, B, C> T3<A, B, C> T3(A a, B b, C c) {
        return new T3(a, b, c);
    }

    public static class T4<A, B, C, D> {

        final public A _1;
        final public B _2;
        final public C _3;
        final public D _4;

        public T4(A _1, B _2, C _3, D _4) {
            this._1 = _1;
            this._2 = _2;
            this._3 = _3;
            this._4 = _4;
        }

        @Override
        public String toString() {
            return "T4(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ", _4:" + _4 + ")";
        }
    }

    public static <A, B, C, D> T4<A, B, C, D> T4(A a, B b, C c, D d) {
        return new T4<A, B, C, D>(a, b, c, d);
    }

    public static class T5<A, B, C, D, E> {

        final public A _1;
        final public B _2;
        final public C _3;
        final public D _4;
        final public E _5;

        public T5(A _1, B _2, C _3, D _4, E _5) {
            this._1 = _1;
            this._2 = _2;
            this._3 = _3;
            this._4 = _4;
            this._5 = _5;
        }

        @Override
        public String toString() {
            return "T5(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ", _4:" + _4 + ", _5:" + _5 + ")";
        }
    }

    public static <A, B, C, D, E> T5<A, B, C, D, E> T5(A a, B b, C c, D d, E e) {
        return new T5<A, B, C, D, E>(a, b, c, d, e);
    }

    public static abstract class Matcher<T, R> {

        public abstract Option<R> match(T o);

        public Option<R> match(Option<T> o) {
            if (o.isDefined()) {
                return match(o.get());
            }
            return Option.None();
        }

        public <NR> Matcher<T, NR> and(final Matcher<R, NR> nextMatcher) {
            final Matcher<T, R> firstMatcher = this;
            return new Matcher<T, NR>() {

                @Override
                public Option<NR> match(T o) {
                    for (R r : firstMatcher.match(o)) {
                        return nextMatcher.match(r);
                    }
                    return Option.None();
                }
            };
        }

        public static Matcher<Object, String> String = new Matcher<Object, String>() {

            @Override
            public Option<String> match(Object o) {
                if (o instanceof String) {
                    return Option.Some((String) o);
                }
                return Option.None();
            }
        };

        public static <K> Matcher<Object, K> ClassOf(final Class<K> clazz) {
            return new Matcher<Object, K>() {

                @Override
                public Option<K> match(Object o) {
                    if (o instanceof Option && ((Option) o).isDefined()) {
                        o = ((Option) o).get();
                    }
                    if (clazz.isInstance(o)) {
                        return Option.Some((K) o);
                    }
                    return Option.None();
                }
            };
        }

        public static Matcher<String, String> StartsWith(final String prefix) {
            return new Matcher<String, String>() {

                @Override
                public Option<String> match(String o) {
                    if (o.startsWith(prefix)) {
                        return Option.Some(o);
                    }
                    return Option.None();
                }
            };
        }

        public static Matcher<String, String> Re(final String pattern) {
            return new Matcher<String, String>() {

                @Override
                public Option<String> match(String o) {
                    if (o.matches(pattern)) {
                        return Option.Some(o);
                    }
                    return Option.None();
                }
            };
        }

        public static <X> Matcher<X, X> Equals(final X other) {
            return new Matcher<X, X>() {

                @Override
                public Option<X> match(X o) {
                    if (o.equals(other)) {
                        return Option.Some(o);
                    }
                    return Option.None();
                }
            };
        }
    }
}
TOP

Related Classes of yalp.libs.F$Promise

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.