Skip to content

Instantly share code, notes, and snippets.

Created October 17, 2021 21:20
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
Scala programmer discovers DI
import izumi.reflect.Tag
import shapeless.tag
import shapeless.tag._
import zio._
import zio.magic._
import scala.language.implicitConversions
import BillingClient._
import NotificatorClient._
object Main extends CustomApp {
type Env = BillingClient with NotificatorClient
val layers = ZLayer.fromMagic[Env](,
// tag layer by target service
// replace type to tagged one in the ZLayer's input[GrpcConfig, BillingClient.Service, Has[Grpc]],[GrpcConfig, NotificatorClient.Service, Has[Grpc]]
// ZLAYER SYNTAX ===============
class ZLayerExtensionsRequireTagged[RIn, E, ROut](
private val layer: ZLayer[RIn, E, ROut]
) {
def requireTagged[A: Tag, T: Tag, RIn1: Tag](implicit
ev: RIn1 with Has[A] =:= RIn,
union: Has.Union[RIn1, Has[A]]
): ZLayer[Has[A @@ T] with RIn1, E, ROut] =
ZLayer.environment[Has[A @@ T]].flatMap { tagged =>
(ZLayer.environment[RIn1] ++ ZLayer.succeed(untag(tagged.get))).map(ev) >>>
class ZLayerExtensionsTagged[-RIn, +E, ROut](
private val layer: ZLayer[RIn, E, Has[ROut]]
) extends AnyVal {
def tagged[LayerTag: Tag](implicit
ROut: Tag[ROut]
): ZLayer[RIn, E, Has[ROut @@ LayerTag]] = => Has(tag[LayerTag](out.get)))
trait ZLayerSyntax {
implicit def zLayerSyntax[RIn, E, ROut: Tag](
layer: ZLayer[RIn, E, Has[ROut]]
): ZLayerExtensionsTagged[RIn, E, ROut] =
new ZLayerExtensionsTagged(layer)
implicit def zLayerSyntax1[RIn, E, ROut](
layer: ZLayer[RIn, E, ROut]
): ZLayerExtensionsRequireTagged[RIn, E, ROut] =
new ZLayerExtensionsRequireTagged(layer)
trait CustomApp extends ZLayerSyntax
case class GrpcConfig(name: String)
object GrpcConfig {
def load(name: String) = ZLayer.succeed(GrpcConfig(name))
case class Grpc()
object Grpc {
val live = ZLayer.succeed(Grpc())
object BillingClient {
type BillingClient = Has[Service]
trait Service {}
case class BillingClientLive(config: GrpcConfig, grpc: Grpc) extends BillingClient.Service
object BillingClientLive {
val live: URLayer[Has[GrpcConfig] with Has[Grpc], BillingClient] =
(BillingClientLive(_, _)).toLayer
object NotificatorClient {
type NotificatorClient = Has[Service]
trait Service {}
case class NotificatorClientLive(config: GrpcConfig, grpc: Grpc) extends NotificatorClient.Service
object NotificatorClientLive {
val live: URLayer[Has[GrpcConfig] with Has[Grpc], NotificatorClient] =
(NotificatorClientLive(_, _)).toLayer
// UTILS =======================
def untag[A, B](x: A @@ B): A = x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment