Skip to content

Commit

Permalink
Kernelize Start\Fire (#682)
Browse files Browse the repository at this point in the history
* Kernelize Start\Fire

* Abstract over exit in Fibers

* Fix Fibers signature

* fix and move syntax
  • Loading branch information
Odomontois committed Jul 2, 2021
1 parent 58c7f70 commit 3ea4ed7
Show file tree
Hide file tree
Showing 16 changed files with 166 additions and 83 deletions.
42 changes: 0 additions & 42 deletions core/src/main/scala/tofu/Fire.scala

This file was deleted.

5 changes: 5 additions & 0 deletions core/src/main/scala/tofu/Start.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package tofu

import tofu.internal.EffectComp

object Start extends EffectComp[Start]
4 changes: 4 additions & 0 deletions core/src/main/scala/tofu/package.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import cats.effect.Bracket
import cats.effect.Fiber
import cats.data.Ior
import tofu.kernel.KernelTypes
import cats.Id

package object tofu extends KernelTypes {

Expand All @@ -15,4 +17,6 @@ package object tofu extends KernelTypes {

type Calculates[F[_]] = Scoped[Scoped.Calculation, F]
type CalcExec[F[_]] = ScopedExecute[Scoped.Calculation, F]

type Start[F[_]] = Fibers[F, Id, Fiber[F, *]]
}
1 change: 1 addition & 0 deletions core/src/test/scala/tofu/GuaranteeSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tofu

import scala.annotation.nowarn
import tofu.interop.CE2Kernel.CEExit
import tofu.internal.carriers.FinallyCarrier

object GuaranteeSuite {

Expand Down
30 changes: 30 additions & 0 deletions core/src/test/scala/tofu/StartSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package tofu

import cats.effect.Concurrent
import scala.annotation.nowarn
import cats.effect.IO
import cats.effect.ContextShift
import tofu.syntax.start._
import tofu.syntax.monadic._

@nowarn("msg=parameter")
object StartSuite {
def summonInstancesForConcurrent[F[_]: Concurrent] = {
Fire[F]
Start[F]
Race[F]
}

def summonInstancesForIO(implicit cs: ContextShift[IO]) = {
Fire[IO]
Start[IO]
Race[IO]
}

def testStartSyntaxCheck[A, B, F[_]: Concurrent](fa: F[A], fb: F[B]): F[(A, B)] = {
fa.racePair(fb).flatMap {
case Left((a, eb)) => eb.join.tupleLeft(a)
case Right((ea, b)) => ea.join.tupleRight(b)
}
}
}
2 changes: 1 addition & 1 deletion kernel/src/main/scala/tofu/Context.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import cats.Monad
import tofu.kernel.types._
import cats.arrow.FunctionK
import tofu.syntax.monadic._
import tofu.lift.UnliftEffect
import tofu.internal.carriers.UnliftEffect

/** Declares that [[F]] can provide value of type Ctx
*
Expand Down
31 changes: 31 additions & 0 deletions kernel/src/main/scala/tofu/Fire.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package tofu

import scala.util.Either
import tofu.internal.{EffectComp, Effect3Comp}
import tofu.internal.carriers.FibersCarrier

trait Fire[F[_]] {
def fireAndForget[A](fa: F[A]): F[Unit]
}

object Fire extends EffectComp[Fire] {
final implicit def byCarrier[F[_], Ex[_], Fib[_]](implicit
carrier: FibersCarrier.Aux[F, Ex, Fib]
): Fibers[F, Ex, Fib] = carrier.content
}

trait Race[F[_]] extends Fire[F] {
def race[A, B](fa: F[A], fb: F[B]): F[Either[A, B]]
def never[A]: F[A]
}

object Race extends EffectComp[Race] {
def never[F[_], A](implicit race: Race[F]): F[A] = race.never
}

trait Fibers[F[_], Exit[_], Fib[_]] extends Race[F] {
def start[A](fa: F[A]): F[Fib[A]]
def racePair[A, B](fa: F[A], fb: F[B]): F[Either[(Exit[A], Fib[B]), (Fib[A], Exit[B])]]
}

object Fibers extends Effect3Comp[Fibers]
23 changes: 4 additions & 19 deletions kernel/src/main/scala/tofu/Guarantee.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package tofu

import tofu.internal.WBInterop
import cats.MonadError
import scala.annotation.unused
import tofu.internal.{EffectComp, Effect2Comp}
import tofu.internal.carriers.FinallyCarrier

/** Bracket-like typeclass allowing to understand if operation was succeed
* @tparam F effect process
Expand All @@ -17,15 +18,14 @@ trait Guarantee[F[_]] {
def bracket[A, B, C](init: F[A])(action: A => F[B])(release: (A, Boolean) => F[C]): F[B]
}

object Guarantee{
object Guarantee extends EffectComp[Guarantee] {
final implicit def fromBracket[F[_], E, Exit[_]](implicit
@unused ev1: MonadError[F, E],
carrier: FinallyCarrier.Aux[F, E, Exit]
): Finally[F, Exit] =
carrier.content
}


/** Bracket-like typeclass allowing to match exit of the process
* @tparam F effect process
* @tparam Exit structure, describing process exit like `ExitCase` or `Exit`
Expand All @@ -40,19 +40,4 @@ trait Finally[F[_], Exit[_]] extends Guarantee[F] {
def finallyCase[A, B, C](init: F[A])(action: A => F[B])(release: (A, Exit[B]) => F[C]): F[B]
}

abstract class FinallyCarrier[F[_], E] {
type Exit[_]
val content: Finally[F, Exit]
}

object FinallyCarrier {
type Aux[F[_], E, Ex[_]] = FinallyCarrier[F, E] { type Exit[a] = Ex[a] }
def apply[F[_], E, Ex[_]](fin: Finally[F, Ex]) = new FinallyCarrier[F, E] {
type Exit[a] = Ex[a]
val content = fin
}


final implicit def fromBracket[F[_], E, Exit[_]]: Aux[F, E, Exit] =
macro WBInterop.delegate1[F, E, { val `tofu.interop.CE2Kernel.finallyFromBracket`: Unit }]
}
object Finally extends Effect2Comp[Finally]
8 changes: 8 additions & 0 deletions kernel/src/main/scala/tofu/internal/DataEffectComp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ trait EffectComp[TC[_[_]]] {
@inline final def apply[F[_]](implicit instance: TC[F]): TC[F] = instance
}

trait Effect2Comp[TC[f[_], g[_]]] {
@inline final def apply[F[_], G[_]](implicit instance: TC[F, G]): TC[F, G] = instance
}

trait Effect3Comp[TC[f[_], g[_], h[_]]] {
@inline final def apply[F[_], G[_], H[_]](implicit instance: TC[F, G, H]): TC[F, G, H] = instance
}

trait DataComp[TC[_]] {
@inline final def apply[A](implicit instance: TC[A]): TC[A] = instance
}
1 change: 1 addition & 0 deletions kernel/src/main/scala/tofu/internal/Interop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ class Interop(val c: blackbox.Context) {
class WBInterop(override val c: whitebox.Context) extends Interop(c) {
import c.universe._
import c.{WeakTypeTag => WTT}
def delegate0[F[_]: WTTU, N: WTT]: Tree = delegateTree[N](tc[F])
def delegate1[F[_]: WTTU, A: WTT, N: WTT]: Tree = delegateTree[N](tc[F], t[A])
}
21 changes: 21 additions & 0 deletions kernel/src/main/scala/tofu/internal/carriers/FibersCarrier.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package tofu.internal.carriers
import tofu.Fibers
import tofu.internal.WBInterop

abstract class FibersCarrier[F[_]] {
type Fib[_]
type Exit[_]
val content: Fibers[F, Exit, Fib]
}

object FibersCarrier {
type Aux[F[_], Ex[_], Fb[_]] = FibersCarrier[F] { type Exit[a] = Ex[a]; type Fib[a] = Fb[a]; }
def apply[F[_], Ex[_], Fb[_]](fin: Fibers[F, Ex, Fb]) = new FibersCarrier[F] {
type Fib[a] = Fb[a]
type Exit[a] = Ex[a]
val content = fin
}

final implicit def startFromConcurrent[F[_], Exit[_], Fiber[_]]: Aux[F, Exit, Fiber] =
macro WBInterop.delegate0[F, { val `tofu.interop.CE2Kernel.startFromConcurrent`: Unit }]
}
20 changes: 20 additions & 0 deletions kernel/src/main/scala/tofu/internal/carriers/FinallyCarrier.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package tofu.internal.carriers

import tofu.Finally
import tofu.internal.WBInterop

abstract class FinallyCarrier[F[_], E] {
type Exit[_]
val content: Finally[F, Exit]
}

object FinallyCarrier {
type Aux[F[_], E, Ex[_]] = FinallyCarrier[F, E] { type Exit[a] = Ex[a] }
def apply[F[_], E, Ex[_]](fin: Finally[F, Ex]) = new FinallyCarrier[F, E] {
type Exit[a] = Ex[a]
val content = fin
}

final implicit def fromBracket[F[_], E, Exit[_]]: Aux[F, E, Exit] =
macro WBInterop.delegate1[F, E, { val `tofu.interop.CE2Kernel.finallyFromBracket`: Unit }]
}
14 changes: 14 additions & 0 deletions kernel/src/main/scala/tofu/internal/carriers/UnliftEffect.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package tofu.internal.carriers

import tofu.internal.Interop
import tofu.lift.Unlift

// This is purely workaround for scala 2.12
// Which denies to unfold a macro (and recieve a type error)
// before checking an implicit for eligibility
class UnliftEffect[F[_], G[_]](val value: Unlift[F, G]) extends AnyVal

object UnliftEffect {
final implicit def unliftIOEffect[F[_], G[_]]: UnliftEffect[F, G] =
macro Interop.delegate[UnliftEffect[F, G], G, { val `tofu.interop.CE2Kernel.unliftEffect`: Unit }]
}
9 changes: 0 additions & 9 deletions kernel/src/main/scala/tofu/lift/Unlift.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import cats.{Applicative, FlatMap, Functor, Monad, ~>}
import syntax.funk._
import tofu.optics.Contains
import tofu.syntax.monadic._
import tofu.internal.Interop
import kernel.types._

trait Lift[F[_], G[_]] {
Expand Down Expand Up @@ -103,12 +102,4 @@ object Unlift {
}
}

// This is purely workaround for scala 2.12
// Which denies to unfold a macro (and recieve a type error)
// before checking an implicit for eligibility
class UnliftEffect[F[_], G[_]](val value: Unlift[F, G]) extends AnyVal

object UnliftEffect {
final implicit def unliftIOEffect[F[_], G[_]]: UnliftEffect[F, G] =
macro Interop.delegate[UnliftEffect[F, G], G, { val `tofu.interop.CE2Kernel.unliftEffect`: Unit }]
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package tofu.syntax

import tofu.{Fire, Race, Start}
import cats.effect.Fiber
import tofu.{Fire, Race, Fibers}

object fire {
final implicit class FireOps[F[_], A](private val fa: F[A]) extends AnyVal {
Expand All @@ -15,8 +14,10 @@ object race {
}
object start {
final implicit class StartOps[F[_], A](private val fa: F[A]) extends AnyVal {
def start(implicit F: Start[F]): F[Fiber[F, A]] = F.start(fa)
def racePair[F1[x] >: F[x], B](fb: F1[B])(implicit F: Start[F1]): F1[Either[(A, Fiber[F1, B]), (Fiber[F1, A], B)]] =
F.racePair(fa, fb)
def start[Exit[_], Fib[_]](implicit F: Fibers[F, Exit, Fib]): F[Fib[A]] = F.start(fa)
def racePair[F1[x] >: F[x], B, Exit[_], Fib[_]](fb: F1[B])(implicit
F: Fibers[F1, Exit, Fib]
): F1[Either[(Exit[A], Fib[B]), (Fib[A], Exit[B])]] =
F.racePair[A, B](fa, fb)
}
}
27 changes: 20 additions & 7 deletions kernelCE2Interop/src/main/scala/tofu/interop/CE2Kernel.scala
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
package tofu.interop
package tofu
package interop
import tofu.lift.Unlift

import cats.effect.Sync
import tofu.Delay
import cats.effect.Effect
import cats.effect.IO
import tofu.syntax.monadic._
import cats.~>
import tofu.lift.UnliftEffect
import cats.{~>, Id}
import cats.effect.Concurrent
import cats.effect.Timer
import cats.effect.Fiber
import scala.concurrent.duration.FiniteDuration
import tofu.Timeout
import tofu.internal.NonTofu
import tofu.compat.unused
import cats.effect.Bracket
import tofu.Finally
import cats.effect.ExitCase
import tofu.FinallyCarrier
import tofu.internal.carriers._

object CE2Kernel {
// 2.12 sometimes gets mad on Const partial alias during implicit search
Expand Down Expand Up @@ -50,11 +49,25 @@ object CE2Kernel {
F.bracketCase(init)(action) { case (a, exit) =>
F.void(release(a, exit))
}
def bracket[A, B, C](init: F[A])(action: A => F[B])(release: (A, Boolean) => F[C]): F[B] =
def bracket[A, B, C](init: F[A])(action: A => F[B])(release: (A, Boolean) => F[C]): F[B] =
F.bracketCase(init)(action) {
case (a, ExitCase.Completed) => F.void(release(a, true))
case (a, _) => F.void(release(a, false))
}
}
)

final implicit def startFromConcurrent[F[_]](implicit
F: Concurrent[F],
@unused _nonTofu: NonTofu[F]
): FibersCarrier.Aux[F, Id, Fiber[F, *]] =
FibersCarrier[F, Id, Fiber[F, *]](
new Fibers[F, Id, Fiber[F, *]] {
def start[A](fa: F[A]): F[Fiber[F, A]] = F.start(fa)
def fireAndForget[A](fa: F[A]): F[Unit] = F.void(start(fa))
def racePair[A, B](fa: F[A], fb: F[B]): F[Either[(A, Fiber[F, B]), (Fiber[F, A], B)]] = F.racePair(fa, fb)
def race[A, B](fa: F[A], fb: F[B]): F[Either[A, B]] = F.race(fa, fb)
def never[A]: F[A] = F.never
}
)
}

0 comments on commit 3ea4ed7

Please sign in to comment.