diff --git a/concurrent/src/main/scala/tofu/concurrent/impl/FocusedRef.scala b/concurrent/src/main/scala/tofu/concurrent/impl/FocusedRef.scala index 778e2e442..db878a445 100644 --- a/concurrent/src/main/scala/tofu/concurrent/impl/FocusedRef.scala +++ b/concurrent/src/main/scala/tofu/concurrent/impl/FocusedRef.scala @@ -12,8 +12,8 @@ final case class FocusedRef[F[_]: Functor, A, B](ref: Ref[F, A], focus: Contains focus.set(a, next) -> res } - def get: F[B] = ref.get.map(focus.extract) - def set(b: B): F[Unit] = ref.update(a => focus.set(a, b)) + def get: F[B] = ref.get.map(focus.extract) + def set(b: B): F[Unit] = ref.update(a => focus.set(a, b)) def update(f: B => B): F[Unit] = ref.update(focus.update(_, f)) def modify[X](f: B => (B, X)): F[X] = ref.modify(focusedMod(f)) diff --git a/logging/structured/src/main/scala/tofu/logging/Logging.scala b/logging/structured/src/main/scala/tofu/logging/Logging.scala index 97e909b7e..3acf2d15f 100644 --- a/logging/structured/src/main/scala/tofu/logging/Logging.scala +++ b/logging/structured/src/main/scala/tofu/logging/Logging.scala @@ -108,10 +108,6 @@ object Logging { def combine(x: Logging[F], y: Logging[F]): Logging[F] = Logging.combine(x, y) } - implicit val loggingEmbed: Embed[Logging] = new Embed[Logging] { - def embed[F[_]: FlatMap](ft: F[Logging[F]]): Logging[F] = new EmbedLogging[F](ft) - } - /** log level enumeration */ sealed trait Level diff --git a/logging/structured/src/main/scala/tofu/logging/Logs.scala b/logging/structured/src/main/scala/tofu/logging/Logs.scala index 62dad24c5..1940bbacf 100644 --- a/logging/structured/src/main/scala/tofu/logging/Logs.scala +++ b/logging/structured/src/main/scala/tofu/logging/Logs.scala @@ -1,14 +1,18 @@ package tofu.logging import Logging.loggerForService +import cats.data.Tuple2K import cats.effect.Sync import cats.kernel.Monoid -import cats.{Applicative, Apply, FlatMap, Functor} +import cats.tagless.{ApplyK, FunctorK} +import cats.tagless.syntax.functorK._ +import cats.{Applicative, Apply, FlatMap, Functor, ~>} import impl.{ContextSyncLoggingImpl, SyncLogging} import org.slf4j.LoggerFactory import tofu.higherKind -import tofu.higherKind.RepresentableK +import tofu.higherKind.{Function2K, MonoidalK, Point, RepresentableK} import tofu.syntax.monadic._ +import tofu.syntax.monoidalK._ import scala.reflect.ClassTag @@ -21,14 +25,17 @@ trait Logs[+I[_], F[_]] extends LogsVOps[I, F] { final def service[Svc: ClassTag]: I[ServiceLogging[F, Svc]] = forService[Svc].asInstanceOf[I[ServiceLogging[F, Svc]]] } -object Logs { +object Logs extends LogsInstances0 { def apply[I[_], F[_]](implicit logs: Logs[I, F]): Logs[I, F] = logs - private[this] val logsRepresentableAny: RepresentableK[Logs[*[_], Any]] = + private[this] val logs1RepresentableAny: RepresentableK[Logs[*[_], Any]] = higherKind.derived.genRepresentableK[Logs[*[_], Any]] - implicit def logsRepresentable[Y[_]]: RepresentableK[Logs[*[_], Y]] = - logsRepresentableAny.asInstanceOf[RepresentableK[Logs[*[_], Y]]] + implicit def logs1Representable[Y[_]]: RepresentableK[Logs[*[_], Y]] = + logs1RepresentableAny.asInstanceOf[RepresentableK[Logs[*[_], Y]]] + + implicit def logs2MonoidalK[Y[_]](implicit Y: Applicative[Y]): MonoidalK[Logs[Y, *[_]]] = + new Logs2MonoidalK[Y] { def I: Applicative[Y] = Y } def provide[I[_], F[_]] = new Provide[I, F] def provideM[I[_], F[_]] = new ProvideM[I, F] @@ -73,3 +80,44 @@ object Logs { logs.forService[X].flatMap(f) } } + +private[logging] trait LogsInstances0 extends LogsInstances1 { + implicit def logs2ApplyK[Y[_]](implicit Y: Apply[Y]): ApplyK[Logs[Y, *[_]]] = + new Logs2ApplyK[Y] { def I: Apply[Y] = Y } +} + +private[logging] trait LogsInstances1 { + implicit def logs2FunctorK[Y[_]](implicit Y: Functor[Y]): FunctorK[Logs[Y, *[_]]] = + new Logs2FunctorK[Y] { def I: Functor[Y] = Y } +} + +trait Logs2FunctorK[Y[_]] extends FunctorK[Logs[Y, *[_]]] { + implicit def I: Functor[Y] + + def mapK[F[_], G[_]](af: Logs[Y, F])(fk: F ~> G): Logs[Y, G] = new Logs[Y, G] { + def forService[Svc: ClassTag]: Y[Logging[G]] = af.forService[Svc].map(_.mapK(fk)) + def byName(name: String): Y[Logging[G]] = af.byName(name).map(_.mapK(fk)) + } +} + +trait Logs2ApplyK[Y[_]] extends Logs2FunctorK[Y] with ApplyK[Logs[Y, *[_]]] { + implicit def I: Apply[Y] + + def zipWith2K[F[_], G[_], H[_]](af: Logs[Y, F], ag: Logs[Y, G])(f2: Function2K[F, G, H]): Logs[Y, H] = + new Logs[Y, H] { + def forService[Svc: ClassTag]: Y[Logging[H]] = (af.forService[Svc], ag.forService[Svc]).mapN(_.zipWithK(_)(f2)) + def byName(name: String): Y[Logging[H]] = (af.byName(name), ag.byName(name)).mapN(_.zipWithK(_)(f2)) + } + + def productK[F[_], G[_]](af: Logs[Y, F], ag: Logs[Y, G]): Logs[Y, Tuple2K[F, G, *]] = + zipWith2K(af, ag)(Function2K((f, g) => Tuple2K(f, g))) +} + +trait Logs2MonoidalK[Y[_]] extends Logs2ApplyK[Y] with MonoidalK[Logs[Y, *[_]]] { + implicit def I: Applicative[Y] + + def pureK[F[_]](p: Point[F]): Logs[Y, F] = new Logs[Y, F] { + def forService[Svc: ClassTag]: Y[Logging[F]] = p.pureK[Logging].pure[Y] + def byName(name: String): Y[Logging[F]] = p.pureK[Logging].pure[Y] + } +}