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

com.avsystem.commons.macros.misc.DelegationMacros.scala Maven / Gradle / Ivy

There is a newer version: 2.22.0
Show newest version
package com.avsystem.commons
package macros.misc

import com.avsystem.commons.macros.AbstractMacroCommons

import scala.reflect.macros.blackbox

class DelegationMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {

  import c.universe._

  final def DelegationCls: Tree = tq"$MiscPkg.Delegation"

  def delegate[A: WeakTypeTag, B: WeakTypeTag](source: Tree): Tree = instrument {
    val targetTpe = weakTypeOf[B]

    val targetSymbol = targetTpe.dealias.typeSymbol
    if (!targetSymbol.isClass && !targetSymbol.asClass.isAbstract) {
      abort(s"$targetTpe is not a trait or abstract class")
    }

    val wrappedName = c.freshName(TermName("w"))

    val methodDelegations = targetTpe.members.iterator
      .filter(m => m.isAbstract)
      .flatMap { m =>
        if (m.isPublic && m.isMethod && !m.asTerm.isSetter) {
          val ms = m.asMethod
          val name = m.name.toTermName
          val mtpe = m.typeSignatureIn(targetTpe)
          val typeNames = mtpe.typeParams.map(_.name.toTypeName)
          val typeDefs = mtpe.typeParams.map(typeSymbolToTypeDef(_))
          val paramNames =
            mtpe.paramLists.map(_.map(p => if (isRepeated(p)) q"${p.name.toTermName}: _*" else q"${p.name.toTermName}"))
          val paramLists = mtpe.paramLists.map(_.map(paramSymbolToValDef))
          val resultTpeTree = treeForType(mtpe.finalResultType)

          val result = if (ms.isGetter)
            q"val $name: $resultTpeTree = $wrappedName.$name"
          else
            q"def $name[..$typeDefs](...$paramLists): $resultTpeTree = $wrappedName.$name[..$typeNames](...$paramNames)"

          Some(result)
        } else {
          error(s"Can't delegate ${m.name} - only public defs and vals can be delegated")
          None
        }
      }.toList

    q"""
      val $wrappedName = $source
      new $targetTpe {
        ..$methodDelegations
      }
     """
  }

  def materializeDelegation[A: WeakTypeTag, B: WeakTypeTag]: Tree = instrument {
    val targetTpe = weakTypeOf[B]
    val sourceTpe = weakTypeOf[A]

    q"""
      new $DelegationCls[$sourceTpe, $targetTpe] {
        def delegate(source: $sourceTpe): $targetTpe = ${delegate[A, B](q"source")}
      }
     """
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy