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

com.github.tonivade.purefun.instances.FutureInstances Maven / Gradle / Ivy

/*
 * Copyright (c) 2018-2020, Antonio Gabriel Muñoz Conejo 
 * Distributed under the terms of the MIT License
 */
package com.github.tonivade.purefun.instances;

import static com.github.tonivade.purefun.Function1.identity;
import static com.github.tonivade.purefun.Precondition.checkNonNull;
import static com.github.tonivade.purefun.concurrent.FutureOf.toFuture;

import java.time.Duration;
import java.util.concurrent.Executor;
import com.github.tonivade.purefun.Consumer1;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Producer;
import com.github.tonivade.purefun.Tuple;
import com.github.tonivade.purefun.Tuple2;
import com.github.tonivade.purefun.Unit;
import com.github.tonivade.purefun.concurrent.Future;
import com.github.tonivade.purefun.concurrent.FutureOf;
import com.github.tonivade.purefun.concurrent.Future_;
import com.github.tonivade.purefun.concurrent.Promise;
import com.github.tonivade.purefun.type.Either;
import com.github.tonivade.purefun.type.Try;
import com.github.tonivade.purefun.typeclasses.Applicative;
import com.github.tonivade.purefun.typeclasses.Async;
import com.github.tonivade.purefun.typeclasses.Bracket;
import com.github.tonivade.purefun.typeclasses.Concurrent;
import com.github.tonivade.purefun.typeclasses.Defer;
import com.github.tonivade.purefun.typeclasses.Fiber;
import com.github.tonivade.purefun.typeclasses.Functor;
import com.github.tonivade.purefun.typeclasses.Monad;
import com.github.tonivade.purefun.typeclasses.MonadDefer;
import com.github.tonivade.purefun.typeclasses.MonadError;
import com.github.tonivade.purefun.typeclasses.MonadThrow;

public interface FutureInstances {

  static Functor functor() {
    return FutureFunctor.INSTANCE;
  }

  static Applicative applicative() {
    return applicative(Future.DEFAULT_EXECUTOR);
  }

  static Applicative applicative(Executor executor) {
    return FutureApplicative.instance(checkNonNull(executor));
  }

  static Monad monad() {
    return monad(Future.DEFAULT_EXECUTOR);
  }

  static Monad monad(Executor executor) {
    return FutureMonad.instance(checkNonNull(executor));
  }

  static MonadError monadError() {
    return monadError(Future.DEFAULT_EXECUTOR);
  }

  static MonadError monadError(Executor executor) {
    return FutureMonadThrow.instance(checkNonNull(executor));
  }

  static MonadDefer monadDefer() {
    return monadDefer(Future.DEFAULT_EXECUTOR);
  }

  static MonadDefer monadDefer(Executor executor) {
    return FutureMonadDefer.instance(checkNonNull(executor));
  }

  static Async async() {
    return async(Future.DEFAULT_EXECUTOR);
  }

  static Async async(Executor executor) {
    return FutureAsync.instance(checkNonNull(executor));
  }

  static Concurrent concurrent() {
    return concurrent(Future.DEFAULT_EXECUTOR);
  }

  static Concurrent concurrent(Executor executor) {
    return FutureConcurrent.instance(checkNonNull(executor));
  }
}

interface FutureFunctor extends Functor {

  FutureFunctor INSTANCE = new FutureFunctor() {};

  @Override
  default  Kind map(Kind value, Function1 mapper) {
    return value.fix(toFuture()).map(mapper);
  }
}

interface ExecutorHolder {
  Executor executor();
}

interface FuturePure extends Applicative, ExecutorHolder {

  @Override
  default  Kind pure(T value) {
    return Future.success(executor(), value);
  }
}

interface FutureApplicative extends FuturePure {

  static FutureApplicative instance(Executor executor) {
    return () -> executor;
  }

  @Override
  default  Kind ap(Kind value, 
      Kind> apply) {
    return value.fix(FutureOf::narrowK).ap(apply.fix(FutureOf::narrowK));
  }
}

interface FutureMonad extends FuturePure, Monad {

  static FutureMonad instance(Executor executor) {
    return () -> executor;
  }

  @Override
  default  Kind flatMap(Kind value,
      Function1> map) {
    return value.fix(toFuture()).flatMap(map.andThen(FutureOf::narrowK));
  }

  /**
   * XXX In order to create real parallel computations, we need to override ap to use the
   * applicative version of the ap method
   */
  @Override
  default  Kind ap(Kind value, 
      Kind> apply) {
    return FutureInstances.applicative().ap(value, apply);
  }
}

interface FutureMonadThrow extends FutureMonad, MonadThrow {

  static FutureMonadThrow instance(Executor executor) {
    return () -> executor;
  }

  @Override
  default  Kind raiseError(Throwable error) {
    return Future.failure(executor(), error);
  }

  @Override
  default  Kind handleErrorWith(
      Kind value,
      Function1> handler) {
    return value.fix(toFuture()).fold(handler.andThen(FutureOf::narrowK),
                                      success -> Future.success(executor(), success)).flatMap(identity());
  }
}

interface FutureDefer extends Defer, ExecutorHolder {

  @Override
  default  Kind defer(Producer> defer) {
    return Future.defer(executor(), defer.map(FutureOf::narrowK)::get);
  }
}

interface FutureBracket extends Bracket, ExecutorHolder {

  @Override
  default  Kind bracket(Kind acquire, 
      Function1> use, Consumer1 release) {
    return Future.bracket(executor(), acquire.fix(toFuture()), use.andThen(FutureOf::narrowK), release);
  }
}

interface FutureMonadDefer extends MonadDefer, FutureMonadThrow, FutureDefer, FutureBracket {

  static FutureMonadDefer instance(Executor executor) {
    return () -> executor;
  }

  @Override
  default Kind sleep(Duration duration) {
    return Future.sleep(executor(), duration);
  }
}

interface FutureAsync extends Async, FutureMonadDefer {

  static FutureAsync instance(Executor executor) {
    return () -> executor;
  }
  
  @Override
  default  Kind asyncF(
      Function1>, Kind> consumer) {
    return Future.asyncF(executor(), consumer.andThen(FutureOf::narrowK));
  }
}

interface FutureConcurrent extends Concurrent, FutureAsync {

  static FutureConcurrent instance(Executor executor) {
    return () -> executor;
  }

  @Override
  default  Future> fork(Kind value) {
    return Future.later(executor(), () -> fiber(executor(), value.fix(toFuture())));
  }
  
  @Override
  default  Future>, Tuple2, B>>> racePair(
      Kind fa, Kind fb) {
    
    Kind>, Tuple2, B>>> async = 
        async(consumer -> {
          Fiber fiberA = fiber(executor(), fa);
          Fiber fiberB = fiber(executor(), fb);
          
          Promise>, Tuple2, B>>> promise = Promise.make();
          promise.onComplete(consumer);
          
          fa.fix(toFuture()).onSuccess(a -> promise.tryComplete(Try.success(Either.left(Tuple.of(a, fiberB)))));
          fb.fix(toFuture()).onSuccess(b -> promise.tryComplete(Try.success(Either.right(Tuple.of(fiberA, b)))));

          fa.fix(toFuture()).onFailure(
              error1 -> fb.fix(toFuture()).onFailure(
                  error2 -> promise.tryComplete(Try.failure("failed: " + error1 + " " + error2))));
        });
    
    return async.fix(toFuture());
  }
  
  static  Fiber fiber(Executor executor, Kind future) {
    return Fiber.of(() -> future, () -> Future.exec(executor, () -> future.fix(toFuture()).cancel(true)));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy