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

org.atnos.eff.FutureInterpretation.scala Maven / Gradle / Ivy

The newest version!
package org.atnos.eff

import cats._
import org.atnos.eff.concurrent.Scheduler
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.concurrent.Promise

trait FutureInterpretation extends FutureTypes {

  def runAsyncOn[R, A](executorServices: ExecutorServices)(e: Eff[R, A])(implicit m: Member.Aux[TimedFuture, R, NoFx]): Future[A] =
    runAsync(e)(executorServices.scheduler, executorServices.executionContext, m)

  def runAsync[R, A](e: Eff[R, A])(implicit scheduler: Scheduler, exc: ExecutionContext, m: Member.Aux[TimedFuture, R, NoFx]): Future[A] =
    Eff.detachA(Eff.effInto[R, Fx1[TimedFuture], A](e))(TimedFuture.MonadTimedFuture, TimedFuture.ApplicativeTimedFuture).runNow(scheduler, exc)

  def runSequentialOn[R, A](executorServices: ExecutorServices)(e: Eff[R, A])(implicit m: Member.Aux[TimedFuture, R, NoFx]): Future[A] =
    runSequential(e)(executorServices.scheduler, executorServices.executionContext, m)

  def runSequential[R, A](e: Eff[R, A])(implicit scheduler: Scheduler, exc: ExecutionContext, m: Member.Aux[TimedFuture, R, NoFx]): Future[A] =
    Eff.detach(Eff.effInto[R, Fx1[TimedFuture], A](e)).runNow(scheduler, exc)

  final def futureAttempt[R, A](e: Eff[R, A])(implicit future: TimedFuture /= R): Eff[R, Throwable Either A] =
    interpret.interceptNatM[R, TimedFuture, Either[Throwable, *], A](
      e,
      new (TimedFuture ~> ({ type l[a] = TimedFuture[Either[Throwable, a]] })#l) {
        override def apply[X](fa: TimedFuture[X]): TimedFuture[Throwable Either X] = attempt(fa)
      }
    )

  final def attempt[A](a: TimedFuture[A]): TimedFuture[Throwable Either A] = {
    TimedFuture[Throwable Either A](callback = (scheduler, ec) => {
      val prom = Promise[Throwable Either A]()
      a.runNow(scheduler, ec)
        .onComplete { t =>
          prom.success(t.toEither)
        }(ec)
      prom.future
    })
  }

  final def memoize[A](key: AnyRef, cache: Cache, future: TimedFuture[A]): TimedFuture[A] =
    TimedFuture { (scheduler, ec) =>
      val prom = Promise[A]()
      cache
        .get[A](key)
        .fold {
          prom.completeWith(
            future
              .runNow(scheduler, ec)
              .map { v =>
                val _ = cache.put(key, v); v
              }(ec)
          )
        } { v => prom.success(v) }
      prom.future
    }

  /**
    * Memoize future values using a cache
    *
    * if this method is called with the same key the previous value will be returned
    */
  final def futureMemo[R, A](key: AnyRef, cache: Cache, e: Eff[R, A])(implicit future: TimedFuture /= R): Eff[R, A] =
    interpret.interceptNat[R, TimedFuture, A](e)(
      new (TimedFuture ~> TimedFuture) {
        override def apply[X](fa: TimedFuture[X]): TimedFuture[X] = memoize(key, cache, fa)
      }
    )

  /**
    * Memoize Future values using a memoization effect
    *
    * if this method is called with the same key the previous value will be returned
    */
  final def futureMemoized[R, A](key: AnyRef, e: Eff[R, A])(implicit future: TimedFuture /= R, m: Memoized |= R): Eff[R, A] =
    MemoEffect.getCache[R].flatMap(cache => futureMemo(key, cache, e))

}

object FutureInterpretation extends FutureInterpretation




© 2015 - 2024 Weber Informatics LLC | Privacy Policy