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

wvlet.airframe.AirframeMacros.scala Maven / Gradle / Ivy

There is a newer version: 0.21
Show newest version
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package wvlet.airframe

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
import scala.reflect.macros.{blackbox => sm}

private[wvlet] object AirframeMacros {

  private[airframe] class BindHelper[C <: Context](val c: C) {

    import c.universe._

    def shouldGenerateTrait(t: c.Type): Boolean = {
      val a = t.typeSymbol

      // Find the public default constructor that has no arguments
      val hasPublicDefaultConstructor = t.members
                                        .find(_.isConstructor)
                                        .map(_.asMethod).exists { m =>
        m.isPublic && m.paramLists.size == 1 && m.paramLists(0).size == 0
      }

      val hasAbstractMethods = t.members.exists(x =>
        x.isMethod && x.isAbstract && !x.isAbstractOverride
      )

      val isTaggedType = t.typeSymbol.fullName.startsWith("wvlet.surface.tag.")

      val shouldInstantiateTrait = if (!a.isStatic) {
        // = Non static type
        // If X is non static type (= local class or trait),
        // we need to instantiate it first in order to populate its $outer variables
        true
      }
      else if (a.isAbstract) {
        // = Abstract type
        // We cannot build abstract type X that has abstract methods, so bind[X].to[ConcreteType]
        // needs to be found in the design

        // If there is no abstract methods, it might be a trait without any method
        !hasAbstractMethods
      }
      else {
        // We cannot instantiate any trait or class without the default constructor
        // So binding needs to be found in the Design.
        hasPublicDefaultConstructor
      }

      // Tagged type binding should be found in Design
      !isTaggedType && shouldInstantiateTrait
    }

    def bind(session: c.Tree, t: c.Type): c.Tree = {
      q"""{
            val session = ${session}
            ${newBinder(t)}(session)
          }"""
    }

    def bindSingleton(session: c.Tree, t: c.Type): c.Tree = {
      q"""{
            val session = ${session}
            ${newSingletonBinder(t)}(session)
          }"""
    }

    def findSession: c.Tree = {
      q"""wvlet.airframe.Session.findSession(this)"""
    }


    def newBinder(t: c.Type): c.Tree = {
      if (shouldGenerateTrait(t)) {
        q"""{
             session : wvlet.airframe.Session =>
             session.getOrElseUpdate(${surfaceOf(t)},
              (new $t with wvlet.airframe.SessionHolder { def __current_session = session}).asInstanceOf[$t]
             )
            }"""
      }
      else {
        q"""{ session : wvlet.airframe.Session => session.get[$t](${surfaceOf(t)}) }"""
      }
    }

    def newSingletonBinder(t: c.Type): c.Tree = {
      if (shouldGenerateTrait(t)) {
        q"""{
             session : wvlet.airframe.Session =>
             session.getOrElseUpdateSingleton[$t](${surfaceOf(t)},
              (new $t with wvlet.airframe.SessionHolder { def __current_session = session}).asInstanceOf[$t]
             )
            }"""
      }
      else {
        q"""{ session : wvlet.airframe.Session => session.getSingleton[$t](${surfaceOf(t)}) }"""
      }
    }

    def registorFactory(t:c.Type) : c.Tree = {
      if(shouldGenerateTrait(t)) {
        q""" {
           val s = ${surfaceOf(t)}
           wvlet.airframe.factoryCache.getOrElseUpdate(s,
             { session: wvlet.airframe.Session => (new $t with wvlet.airframe.SessionHolder { def __current_session = session }).asInstanceOf[Any] }
           )
           s
         }
        """
      }
      else {
        q"""{${surfaceOf(t)}}"""
      }
    }

    def withFactoryRegistration(t: c.Type, body: c.Tree) : c.Tree = {
      q"""
        ${registorFactory(t)}
        ${body}
        """
    }

    def surfaceOf(t: c.Type): c.Tree = {
      q"wvlet.surface.Surface.of[$t]"
    }

    def provider1Binding[D1:c.WeakTypeTag](factory:c.Tree, singleton:Boolean, eager:Boolean) : c.Tree = {
      val ev1 = implicitly[c.WeakTypeTag[D1]].tpe
      q"""{
           val self = ${c.prefix.tree}
           val d1 = ${registorFactory(ev1)}
           import wvlet.airframe.Binder._
           self.design.addBinding(ProviderBinding(DependencyFactory(self.from, Seq(d1), ${factory}), ${singleton}, ${eager}))
        }
        """
    }

    def provider2Binding[D1:c.WeakTypeTag, D2:c.WeakTypeTag](factory:c.Tree, singleton:Boolean, eager:Boolean) : c.Tree = {
      val ev1 = implicitly[c.WeakTypeTag[D1]].tpe
      val ev2 = implicitly[c.WeakTypeTag[D2]].tpe
      q"""{
           val self = ${c.prefix.tree}
           val d1 = ${registorFactory(ev1)}
           val d2 = ${registorFactory(ev2)}
           import wvlet.airframe.Binder._
           self.design.addBinding(ProviderBinding(DependencyFactory(self.from, Seq(d1, d2), ${factory}), ${singleton}, ${eager}))
        }
        """
    }

    def provider3Binding[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag](factory:c.Tree, singleton:Boolean, eager:Boolean) : c.Tree = {
      val ev1 = implicitly[c.WeakTypeTag[D1]].tpe
      val ev2 = implicitly[c.WeakTypeTag[D2]].tpe
      val ev3 = implicitly[c.WeakTypeTag[D3]].tpe
      q"""{
           val self = ${c.prefix.tree}
           val d1 = ${registorFactory(ev1)}
           val d2 = ${registorFactory(ev2)}
           val d3 = ${registorFactory(ev3)}
           import wvlet.airframe.Binder._
           self.design.addBinding(ProviderBinding(DependencyFactory(self.from, Seq(d1, d2, d3), ${factory}), ${singleton}, ${eager}))
        }
        """
    }

    def provider4Binding[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag, D4:c.WeakTypeTag](factory:c.Tree, singleton:Boolean, eager:Boolean) : c.Tree = {
      val ev1 = implicitly[c.WeakTypeTag[D1]].tpe
      val ev2 = implicitly[c.WeakTypeTag[D2]].tpe
      val ev3 = implicitly[c.WeakTypeTag[D3]].tpe
      val ev4 = implicitly[c.WeakTypeTag[D4]].tpe
      q"""{
           val self = ${c.prefix.tree}
           val d1 = ${registorFactory(ev1)}
           val d2 = ${registorFactory(ev2)}
           val d3 = ${registorFactory(ev3)}
           val d4 = ${registorFactory(ev4)}
           import wvlet.airframe.Binder._
           self.design.addBinding(ProviderBinding(DependencyFactory(self.from, Seq(d1, d2, d3, d4), ${factory}), ${singleton}, ${eager}))
        }
        """
    }

    def provider5Binding[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag, D4:c.WeakTypeTag, D5:c.WeakTypeTag](factory:c.Tree, singleton:Boolean, eager:Boolean) : c.Tree = {
      val ev1 = implicitly[c.WeakTypeTag[D1]].tpe
      val ev2 = implicitly[c.WeakTypeTag[D2]].tpe
      val ev3 = implicitly[c.WeakTypeTag[D3]].tpe
      val ev4 = implicitly[c.WeakTypeTag[D4]].tpe
      val ev5 = implicitly[c.WeakTypeTag[D5]].tpe
      q"""{
           val self = ${c.prefix.tree}
           val d1 = ${registorFactory(ev1)}
           val d2 = ${registorFactory(ev2)}
           val d3 = ${registorFactory(ev3)}
           val d4 = ${registorFactory(ev4)}
           val d5 = ${registorFactory(ev5)}
           import wvlet.airframe.Binder._
           self.design.addBinding(ProviderBinding(DependencyFactory(self.from, Seq(d1, d2, d3, d4, d5), ${factory}), ${singleton}, ${eager}))
        }
        """
    }

    def fullTypeNameOf(typeEv: c.Type): String = {
      typeEv match {
        case TypeRef(prefix, typeSymbol, args) =>
          if (args.isEmpty) {
            typeSymbol.fullName
          }
          else {
            val typeArgs = args.map(fullTypeNameOf(_)).mkString(",")
            s"${typeSymbol.fullName}[${typeArgs}]"
          }
        case other =>
          typeEv.typeSymbol.fullName
      }
    }
  }

  def designBindImpl[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val h = new BindHelper[c.type](c)
    h.withFactoryRegistration(t,
      q"""${c.prefix}
         .bind(${h.surfaceOf(t)})
         .asInstanceOf[wvlet.airframe.Binder[$t]]"""
    )
  }

  def designRemoveImpl[A:c.WeakTypeTag](c: sm.Context) : c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val h = new BindHelper[c.type](c)
    q"""{
         val target = ${h.surfaceOf(t)}
         new wvlet.airframe.Design(${c.prefix}.binding.filterNot(_.from == target))
        }
     """
  }

  def binderToImpl[B: c.WeakTypeTag](c: sm.Context) : c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[B]].tpe
    val h = new BindHelper[c.type](c)
    val core = q""" {
      val self = ${c.prefix.tree}
      val to = ${h.surfaceOf(t)}
      self.design.addBinding(wvlet.airframe.Binder.ClassBinding(self.from, to))
    }"""
    h.withFactoryRegistration(t, core)
  }

  def binderToSingletonOfImpl[B: c.WeakTypeTag](c: sm.Context) : c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[B]].tpe
    val h = new BindHelper[c.type](c)
    val core = q""" {
      val self = ${c.prefix.tree}
      val to = ${h.surfaceOf(t)}
      if(self.from == to) {
         wvlet.log.Logger("wvlet.airframe.Binder").warn("Binding to the same type is not allowed: " + to.toString)
         throw new wvlet.airframe.AirframeException.CYCLIC_DEPENDENCY(Set(to))
      }
      self.design.addBinding(wvlet.airframe.Binder.SingletonBinding(self.from, to, false))
    }"""
    h.withFactoryRegistration(t, core)
  }

  def binderToEagerSingletonOfImpl[B: c.WeakTypeTag](c: sm.Context) : c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[B]].tpe
    val h = new BindHelper[c.type](c)
    val core = q""" {
      val self = ${c.prefix.tree}
      val to = ${h.surfaceOf(t)}
      if(self.from == to) {
         wvlet.log.Logger("wvlet.airframe.Binder").warn("Binding to the same type is not allowed: " + to.toString)
         throw new wvlet.airframe.AirframeException.CYCLIC_DEPENDENCY(Set(to))
      }
      self.design.addBinding(wvlet.airframe.Binder.SingletonBinding(self.from, to, true))
    }"""
    h.withFactoryRegistration(t, core)
  }

  def bindToProvider1[D1:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider1Binding[D1](factory, false, false)
  }

  def bindToProvider2[D1:c.WeakTypeTag, D2:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider2Binding[D1,D2](factory, false, false)
  }

  def bindToProvider3[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider3Binding[D1,D2,D3](factory, false, false)
  }

  def bindToProvider4[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag, D4:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider4Binding[D1,D2,D3,D4](factory, false, false)
  }

  def bindToProvider5[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag, D4:c.WeakTypeTag, D5:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider5Binding[D1,D2,D3,D4,D5](factory, false, false)
  }

  def bindToSingletonProvider1[D1:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider1Binding[D1](factory, true, false)
  }

  def bindToSingletonProvider2[D1:c.WeakTypeTag, D2:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider2Binding[D1,D2](factory, true, false)
  }

  def bindToSingletonProvider3[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider3Binding[D1,D2,D3](factory, true, false)
  }

  def bindToSingletonProvider4[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag, D4:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider4Binding[D1,D2,D3,D4](factory, true, false)
  }

  def bindToSingletonProvider5[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag, D4:c.WeakTypeTag, D5:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider5Binding[D1,D2,D3,D4,D5](factory, true, false)
  }

  def bindToEagerSingletonProvider1[D1:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider1Binding[D1](factory, true, true)
  }

  def bindToEagerSingletonProvider2[D1:c.WeakTypeTag, D2:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider2Binding[D1,D2](factory, true, true)
  }

  def bindToEagerSingletonProvider3[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag](c:sm.Context)(factory:c.Tree): c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider3Binding[D1,D2,D3](factory, true, true)
  }

  def bindToEagerSingletonProvider4[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag, D4:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider4Binding[D1,D2,D3,D4](factory, true, true)
  }

  def bindToEagerSingletonProvider5[D1:c.WeakTypeTag, D2:c.WeakTypeTag, D3:c.WeakTypeTag, D4:c.WeakTypeTag, D5:c.WeakTypeTag](c:sm.Context)(factory:c.Tree) : c.Tree = {
    val h = new BindHelper[c.type](c)
    h.provider5Binding[D1,D2,D3,D4,D5](factory, true, true)
  }

  /**
    * Used when Session location is known
    *
    * @param c
    * @tparam A
    * @return
    */
  def buildImpl[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[A]].tpe
    new BindHelper[c.type](c).bind(c.prefix.tree, t)
  }

  def addLifeCycle[A:c.WeakTypeTag](c: sm.Context): c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val h = new BindHelper[c.type](c)
    q"""{
         val session = ${h.findSession}
         new wvlet.airframe.LifeCycleBinder(${c.prefix}.dep, ${h.surfaceOf(t)}, session)
        }
      """
  }

  def addInitLifeCycle[A:c.WeakTypeTag](c: sm.Context)(body: c.Tree): c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val h = new BindHelper[c.type](c)
    q"""{
         val session = ${h.findSession}
         new wvlet.airframe.LifeCycleBinder(${c.prefix}.dep, ${h.surfaceOf(t)}, session)(init=${body})
        }
      """
  }

  def addStartLifeCycle[A:c.WeakTypeTag](c: sm.Context)(body: c.Tree): c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val h = new BindHelper[c.type](c)
    q"""{
         val session = ${h.findSession}
         new wvlet.airframe.LifeCycleBinder(${c.prefix}.dep, ${h.surfaceOf(t)}, session)(start=${body})
        }
      """
  }


  def addShutdownLifeCycle[A:c.WeakTypeTag](c: sm.Context)(body: c.Tree): c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val h = new BindHelper[c.type](c)
    q"""{
         val session = ${h.findSession}
         new wvlet.airframe.LifeCycleBinder(${c.prefix}.dep, ${h.surfaceOf(t)}, session)(shutdown=${body})
        }
      """
  }

  def bindImpl[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val h = new BindHelper[c.type](c)
    h.bind(h.findSession, t)
  }

  def bind0Impl[A: c.WeakTypeTag](c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val h = new BindHelper[c.type](c)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdate(${h.surfaceOf(t)}, $factory)
        }
      """
  }

  def bind1Impl[A: c.WeakTypeTag, D1: c.WeakTypeTag](c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val dep1 = h.newBinder(d1)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdate(${h.surfaceOf(t)}, $factory($dep1(session)))
        }
      """
  }

  def bind2Impl[A: c.WeakTypeTag, D1: c.WeakTypeTag, D2: c.WeakTypeTag]
  (c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val d2 = implicitly[c.WeakTypeTag[D2]].tpe
    val dep1 = h.newBinder(d1)
    val dep2 = h.newBinder(d2)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdate(${h.surfaceOf(t)}, $factory($dep1(session), $dep2(session)))
        }
      """
  }

  def bind3Impl[A: c.WeakTypeTag, D1: c.WeakTypeTag, D2: c.WeakTypeTag, D3: c.WeakTypeTag]
  (c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val d2 = implicitly[c.WeakTypeTag[D2]].tpe
    val d3 = implicitly[c.WeakTypeTag[D3]].tpe
    val dep1 = h.newBinder(d1)
    val dep2 = h.newBinder(d2)
    val dep3 = h.newBinder(d3)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdate(${h.surfaceOf(t)}, $factory($dep1(session),$dep2(session),$dep3(session)))
        }
      """
  }

  def bind4Impl[A: c.WeakTypeTag, D1: c.WeakTypeTag, D2: c.WeakTypeTag, D3: c.WeakTypeTag, D4: c.WeakTypeTag]
  (c: sm.Context)(factory: c.Tree) : c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val d2 = implicitly[c.WeakTypeTag[D2]].tpe
    val d3 = implicitly[c.WeakTypeTag[D3]].tpe
    val d4 = implicitly[c.WeakTypeTag[D4]].tpe
    val dep1 = h.newBinder(d1)
    val dep2 = h.newBinder(d2)
    val dep3 = h.newBinder(d3)
    val dep4 = h.newBinder(d4)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdate(${h.surfaceOf(t)},
           $factory($dep1(session),$dep2(session),$dep3(session),$dep4(session))
         )
        }
      """
  }

  def bind5Impl[A: c.WeakTypeTag, D1: c.WeakTypeTag, D2: c.WeakTypeTag, D3: c.WeakTypeTag, D4: c.WeakTypeTag, D5: c.WeakTypeTag]
  (c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val d2 = implicitly[c.WeakTypeTag[D2]].tpe
    val d3 = implicitly[c.WeakTypeTag[D3]].tpe
    val d4 = implicitly[c.WeakTypeTag[D4]].tpe
    val d5 = implicitly[c.WeakTypeTag[D5]].tpe
    val dep1 = h.newBinder(d1)
    val dep2 = h.newBinder(d2)
    val dep3 = h.newBinder(d3)
    val dep4 = h.newBinder(d4)
    val dep5 = h.newBinder(d5)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdate(${h.surfaceOf(t)},
           $factory($dep1(session),$dep2(session),$dep3(session),$dep4(session),$dep5(session))
         )
        }
      """
  }

  def bindSingletonImpl[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    h.bindSingleton(h.findSession, t)
  }

  def bind0SingletonImpl[A: c.WeakTypeTag](c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val h = new BindHelper[c.type](c)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdateSingleton(${h.surfaceOf(t)}, $factory)
        }
      """
  }

  def bind1SingletonImpl[A: c.WeakTypeTag, D1: c.WeakTypeTag]
  (c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val dep1 = h.newBinder(d1)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdateSingleton(${h.surfaceOf(t)}, $factory($dep1(session)))
        }
      """
  }

  def bind2SingletonImpl[A: c.WeakTypeTag, D1: c.WeakTypeTag, D2: c.WeakTypeTag]
  (c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val d2 = implicitly[c.WeakTypeTag[D2]].tpe
    val dep1 = h.newBinder(d1)
    val dep2 = h.newBinder(d2)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdateSingleton(${h.surfaceOf(t)}, $factory($dep1(session), $dep2(session)))
        }
      """
  }

  def bind3SingletonImpl[A: c.WeakTypeTag, D1: c.WeakTypeTag, D2: c.WeakTypeTag, D3: c.WeakTypeTag]
  (c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val d2 = implicitly[c.WeakTypeTag[D2]].tpe
    val d3 = implicitly[c.WeakTypeTag[D3]].tpe
    val dep1 = h.newBinder(d1)
    val dep2 = h.newBinder(d2)
    val dep3 = h.newBinder(d3)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdateSingleton(${h.surfaceOf(t)}, $factory($dep1(session),$dep2(session),$dep3(session)))
        }
      """
  }

  def bind4SingletonImpl[A: c.WeakTypeTag, D1: c.WeakTypeTag, D2: c.WeakTypeTag,
  D3: c.WeakTypeTag, D4: c.WeakTypeTag]
  (c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val d2 = implicitly[c.WeakTypeTag[D2]].tpe
    val d3 = implicitly[c.WeakTypeTag[D3]].tpe
    val d4 = implicitly[c.WeakTypeTag[D4]].tpe
    val dep1 = h.newBinder(d1)
    val dep2 = h.newBinder(d2)
    val dep3 = h.newBinder(d3)
    val dep4 = h.newBinder(d4)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdateSingleton(${h.surfaceOf(t)},
           $factory($dep1(session),$dep2(session),$dep3(session),$dep4(session))
         )
        }
      """
  }

  def bind5SingletonImpl[A: c.WeakTypeTag, D1: c.WeakTypeTag, D2: c.WeakTypeTag,
  D3: c.WeakTypeTag, D4: c.WeakTypeTag, D5: c.WeakTypeTag]
  (c: sm.Context)(factory: c.Tree): c.Tree = {
    import c.universe._
    val h = new BindHelper[c.type](c)
    val t = implicitly[c.WeakTypeTag[A]].tpe
    val d1 = implicitly[c.WeakTypeTag[D1]].tpe
    val d2 = implicitly[c.WeakTypeTag[D2]].tpe
    val d3 = implicitly[c.WeakTypeTag[D3]].tpe
    val d4 = implicitly[c.WeakTypeTag[D4]].tpe
    val d5 = implicitly[c.WeakTypeTag[D5]].tpe
    val dep1 = h.newBinder(d1)
    val dep2 = h.newBinder(d2)
    val dep3 = h.newBinder(d3)
    val dep4 = h.newBinder(d4)
    val dep5 = h.newBinder(d5)
    q"""{
         val session = ${h.findSession}
         session.getOrElseUpdateSingleton(${h.surfaceOf(t)},
           $factory($dep1(session),$dep2(session),$dep3(session),$dep4(session),$dep5(session))
         )
        }
      """
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy