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

com.github.tonivade.purefun.concurrent.Par 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.concurrent;

import com.github.tonivade.purefun.CheckedRunnable;
import com.github.tonivade.purefun.Consumer1;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Function2;
import com.github.tonivade.purefun.HigherKind;
import com.github.tonivade.purefun.Matcher1;
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.data.Sequence;

import java.time.Duration;
import java.util.concurrent.Executor;

import static com.github.tonivade.purefun.Function1.identity;
import static com.github.tonivade.purefun.Function2.second;
import static com.github.tonivade.purefun.data.ImmutableList.empty;

@HigherKind
@FunctionalInterface
public interface Par {

  Future apply(Executor executor);

  default Promise run(Executor executor) {
    return apply(executor).toPromise();
  }

  default  Par map(Function1 mapper) {
    return executor -> apply(executor).map(mapper);
  }

  default  Par flatMap(Function1> mapper) {
    return executor -> apply(executor).flatMap(value -> mapper.apply(value).apply(executor));
  }

  default  Par andThen(Par next) {
    return map2(this, next, second());
  }

  default  Par ap(Par> apply) {
    return apply.flatMap(this::map);
  }

  default Par filter(Matcher1 matcher) {
    return executor -> apply(executor).filter(matcher);
  }

  default Par filterNot(Matcher1 matcher) {
    return executor -> apply(executor).filterNot(matcher);
  }

  default Par recover(Function1 recover) {
    return fold(recover, identity());
  }

  default  Par recoverWith(Class type, Function1 mapper) {
    return executor -> apply(executor).recoverWith(type, mapper);
  }

  default  Par fold(Function1 failureMapper, Function1 successmapper) {
    return executor -> apply(executor).fold(failureMapper, successmapper);
  }

  static  Par success(T value) {
    return executor -> Future.success(executor, value);
  }

  static  Par failure(Throwable error) {
    return executor -> Future.failure(executor, error);
  }

  static  Par task(Producer producer) {
    return executor -> Future.async(executor, producer);
  }

  static  Par defer(Producer> producer) {
    return executor -> Future.defer(executor, () -> producer.get().apply(executor));
  }

  static Par run(CheckedRunnable runnable) {
    return executor -> Future.exec(executor, runnable);
  }

  static Par sleep(Duration delay) {
    return executor -> Future.sleep(executor, delay);
  }

  static  Par bracket(Par acquire, Function1> use, Consumer1 release) {
    return executor -> Future.bracket(acquire.apply(executor), a -> use.apply(a).apply(executor), release);
  }

  static  Par map2(Par parA, Par parB, Function2 mapper) {
    return parB.ap(parA.map(mapper.curried()));
  }

  static  Par> tuple(Par parA, Par parB) {
    return map2(parA, parB, Tuple::of);
  }

  static  Par> traverse(Sequence> sequence) {
    return sequence.foldLeft(success(empty()), (parA, parB) -> map2(parA, parB, Sequence::append));
  }

  static Par sequence(Sequence> sequence) {
    return sequence.fold(unit(), Par::andThen).andThen(unit());
  }

  static Par unit() {
    return success(Unit.unit());
  }
}