Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kernelize Start\Fire #682

Merged
merged 4 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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] {
Odomontois marked this conversation as resolved.
Show resolved Hide resolved
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])
}
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 }]
}
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
}
)
}