Skip to content

Commit 2fce5df

Browse files
committed
components can ask for implicit ComponentInfo
1 parent 345128e commit 2fce5df

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed

commons-core/src/main/scala/com/avsystem/commons/di/Component.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ case class ComponentInfo(
2525
object ComponentInfo {
2626
def apply(namePrefix: String, sourceInfo: SourceInfo): ComponentInfo =
2727
new ComponentInfo(namePrefix + sourceInfo.enclosingSymbols.head, sourceInfo.filePath, sourceInfo.fileName, sourceInfo.line)
28+
29+
@compileTimeOnly("implicit ComponentInfo is only available inside code passed to component/singleton macro")
30+
implicit def info: ComponentInfo = sys.error("stub")
2831
}
2932

3033
/**
@@ -212,7 +215,7 @@ trait Components extends ComponentsLowPrio {
212215
*/
213216
protected[this] def asyncSingleton[T](definition: ExecutionContext => Future[T])(implicit sourceInfo: SourceInfo): Component[T] = macro ComponentMacros.asyncSingleton[T]
214217

215-
private[this] val singletonsCache = new ConcurrentHashMap[ComponentInfo, AtomicReference[Future[_]]]
218+
private[this] lazy val singletonsCache = new ConcurrentHashMap[ComponentInfo, AtomicReference[Future[_]]]
216219

217220
protected[this] def cached[T](component: Component[T], freshInfo: ComponentInfo): Component[T] = {
218221
val cacheStorage = singletonsCache
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.avsystem.commons
2+
package di
3+
4+
import scala.concurrent.Await
5+
import scala.concurrent.duration.Duration
6+
7+
abstract class BaseComponent(implicit info: ComponentInfo) {
8+
println(s"$info init")
9+
}
10+
11+
class SubDao(implicit info: ComponentInfo) extends BaseComponent
12+
class SubService(dao: SubDao)(implicit info: ComponentInfo) extends BaseComponent
13+
14+
class SubSystem extends Components {
15+
override protected def componentNamePrefix: String = "sub."
16+
17+
private val dao: Component[SubDao] =
18+
component(new SubDao)
19+
20+
val service: Component[SubService] =
21+
component(new SubService(dao.ref))
22+
}
23+
24+
class Service(subService: SubService)(implicit info: ComponentInfo) extends BaseComponent
25+
26+
class System(subSystem: SubSystem) extends Components {
27+
val service: Component[Service] =
28+
component(new Service(subSystem.service.ref))
29+
}
30+
31+
object ComponentComposition {
32+
def main(args: Array[String]): Unit = {
33+
val subSystem = new SubSystem
34+
val system = new System(subSystem)
35+
36+
import ExecutionContext.Implicits.global
37+
Await.result(system.service.init, Duration.Inf)
38+
}
39+
}

commons-macros/src/main/scala/com/avsystem/commons/macros/di/ComponentMacros.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class ComponentMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {
1717
lazy val ComponentTpe: Type = getType(tq"$ComponentCls[_]")
1818
lazy val ComponentRefSym: Symbol = ComponentTpe.member(TermName("ref"))
1919
lazy val InjectSym: Symbol = getType(tq"$DiPkg.Components").member(TermName("inject"))
20+
lazy val ComponentInfoSym: Symbol = getType(tq"$DiPkg.ComponentInfo.type").member(TermName("info"))
2021

2122
object ComponentRef {
2223
def unapply(tree: Tree): Option[Tree] = tree match {
@@ -30,6 +31,7 @@ class ComponentMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {
3031

3132
private def mkComponent(tpe: Type, sourceInfo: Tree, definition: Tree, singleton: Boolean, async: Boolean): Tree = {
3233
val depArrayName = c.freshName(TermName("deps"))
34+
val infoName = c.freshName(TermName("info"))
3335
val depsBuf = new ListBuffer[Tree]
3436

3537
def validateDependency(tree: Tree): Tree = {
@@ -54,6 +56,8 @@ class ComponentMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {
5456
depsBuf += validateDependency(component)
5557
val depTpe = component.tpe.baseType(ComponentTpe.typeSymbol).typeArgs.head
5658
q"$depArrayName(${depsBuf.size - 1}).asInstanceOf[$depTpe]"
59+
case t if t.symbol == ComponentInfoSym =>
60+
q"$infoName"
5761
case _ =>
5862
super.transform(tree)
5963
}
@@ -75,13 +79,15 @@ class ComponentMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {
7579

7680
val result =
7781
q"""
82+
val $infoName = ${c.prefix}.componentInfo($sourceInfo)
7883
new $DiPkg.Component[$tpe](
79-
${c.prefix}.componentInfo($sourceInfo),
84+
$infoName,
8085
$ScalaPkg.IndexedSeq(..${depsBuf.result()}),
8186
($depArrayName: $ScalaPkg.IndexedSeq[$ScalaPkg.Any]) => $asyncDefinition
8287
)
8388
"""
8489

90+
//TODO: can I avoid recreating ComponentInfo?
8591
if (singleton)
8692
q"${c.prefix}.cached($result, ${c.prefix}.componentInfo($sourceInfo))"
8793
else

0 commit comments

Comments
 (0)