commonMain.org.kodein.di.bindings.standardBindings.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kodein-di-js Show documentation
Show all versions of kodein-di-js Show documentation
KODEIN Dependency Injection Core
package org.kodein.di.bindings
import org.kodein.di.*
import org.kodein.di.internal.BindingDIImpl
import org.kodein.di.internal.synchronizedIfNull
import org.kodein.type.TypeToken
import org.kodein.type.erasedOf
/**
* Concrete factory: each time an instance is needed, the function creator function will be called.
*
* @param A The argument type.
* @param T The created type.
* @param argType The type of the argument used by this factory.
* @param createdType The type of objects created by this factory.
* @property creator The function that will be called each time an instance is requested. Should create a new instance.
*/
public class Factory(override val contextType: TypeToken, override val argType: TypeToken, override val createdType: TypeToken, private val creator: BindingDI.(A) -> T) : DIBinding {
override fun factoryName(): String = "factory"
override fun getFactory(key: DI.Key, di: BindingDI): (A) -> T = { arg -> this.creator(di, arg) }
}
private data class ScopeKey(val scopeId: Any, val arg: A)
/**
* Concrete multiton: will create one and only one instance for each argument.
* Will create the instance on first time a given argument is used and will subsequently always return the same instance for the same argument.
*
* @param T The created type.
* @property argType The type of the argument used for each value can there be a new instance.
* @property createdType The type of the created object, *used for debug print only*.
* @property creator The function that will be called the first time an instance is requested. Guaranteed to be called only once per argument. Should create a new instance.
*/
public class Multiton(override val scope: Scope, override val contextType: TypeToken, private val explicitContext: Boolean, override val argType: TypeToken, override val createdType: TypeToken, refMaker: RefMaker? = null, public val sync: Boolean = true, private val creator: BindingDI.(A) -> T) : DIBinding {
private val _refMaker = refMaker ?: SingletonReference
private val _scopeId = Any()
private fun factoryName(params: List) = buildString {
append("multiton")
if (params.isNotEmpty())
append(params.joinToString(prefix = "(", separator = ", ", postfix = ")"))
}
override fun factoryName(): String {
val params = ArrayList(2)
if (_refMaker != SingletonReference)
params.add("ref = ${erasedOf(_refMaker).simpleDispString()}")
return factoryName(params)
}
override fun factoryFullName(): String {
val params = ArrayList(2)
if (_refMaker != SingletonReference)
params.add("ref = ${erasedOf(_refMaker).qualifiedDispString()}")
return factoryName(params)
}
override fun getFactory(key: DI.Key, di: BindingDI): (A) -> T {
var lateInitRegistry: ScopeRegistry? = null
val bindingDi = if (explicitContext) di else di.onErasedContext()
return { arg ->
val registry = lateInitRegistry ?: scope.getRegistry(bindingDi.context).also { lateInitRegistry = it }
@Suppress("UNCHECKED_CAST")
registry.getOrCreate(ScopeKey(_scopeId, arg), sync) { _refMaker.make { bindingDi.creator(arg) } } as T
}
}
override val copier: DIBinding.Copier = DIBinding.Copier { Multiton(scope, contextType, explicitContext, argType, createdType, _refMaker, sync, creator) }
}
/**
* Concrete provider: each time an instance is needed, the function [creator] function will be called.
*
* A provider is like a [Factory], but without argument.
*
* @param T The created type.
* @param createdType The type of objects created by this provider, *used for debug print only*.
* @property creator The function that will be called each time an instance is requested. Should create a new instance.
*/
public class Provider(override val contextType: TypeToken, override val createdType: TypeToken, public val creator: NoArgBindingDI.() -> T) : NoArgDIBinding {
override fun factoryName(): String = "provider"
/**
* @see [DIBinding.getFactory]
*/
override fun getFactory(key: DI.Key, di: BindingDI): (Unit) -> T = { _ -> NoArgBindingDIWrap(di).creator() }
}
/**
* Singleton Binding: will create an instance on first request and will subsequently always return the same instance.
*
* @param T The created type.
* @param createdType The type of the created object, *used for debug print only*.
* @param creator The function that will be called the first time an instance is requested. Guaranteed to be called only once. Should create a new instance.
*/
public class Singleton(override val scope: Scope, override val contextType: TypeToken, private val explicitContext: Boolean, override val createdType: TypeToken, refMaker: RefMaker? = null, public val sync: Boolean = true, public val creator: NoArgBindingDI.() -> T) : NoArgDIBinding {
@Suppress("UNCHECKED_CAST")
private val _refMaker = refMaker ?: SingletonReference
private val _scopeKey = ScopeKey(Any(), Unit)
private fun factoryName(params: List) = buildString {
append("singleton")
if (params.isNotEmpty())
append(params.joinToString(prefix = "(", separator = ", ", postfix = ")"))
}
override fun factoryName(): String {
val params = ArrayList(2)
if (_refMaker != SingletonReference)
params.add("ref = ${erasedOf(_refMaker).simpleDispString()}")
return factoryName(params)
}
override fun factoryFullName(): String {
val params = ArrayList(2)
if (_refMaker != SingletonReference)
params.add("ref = ${erasedOf(_refMaker).qualifiedDispString()}")
return factoryName(params)
}
/**
* @see [DIBinding.getFactory]
*/
override fun getFactory(key: DI.Key, di: BindingDI): (Unit) -> T {
var lateInitRegistry: ScopeRegistry? = null
@Suppress("UNCHECKED_CAST")
val bindingDi = if (explicitContext) di else di.onErasedContext()
return { _ ->
val registry = lateInitRegistry ?: scope.getRegistry(bindingDi.context).also { lateInitRegistry = it }
@Suppress("UNCHECKED_CAST")
registry.getOrCreate(_scopeKey, sync) { _refMaker.make { NoArgBindingDIWrap(bindingDi).creator() } } as T
}
}
override val copier: DIBinding.Copier = DIBinding.Copier { Singleton(scope, contextType, explicitContext, createdType, _refMaker, sync, creator) }
}
/**
* Concrete eager singleton: will create an instance as soon as di is ready (all bindings are set) and will always return this instance.
*
* @param T The created type.
* @param createdType The type of the created object.
* @param creator The function that will be called as soon as DI is ready. Guaranteed to be called only once. Should create a new instance.
*/
public class EagerSingleton(builder: DIContainer.Builder, override val createdType: TypeToken, public val creator: NoArgBindingDI.() -> T) : NoArgDIBinding {
override val contextType: TypeToken = TypeToken.Any
@Volatile private var _instance: T? = null
private val _lock = Any()
private fun getFactory(di: BindingDI): (Unit) -> T {
return { _ ->
synchronizedIfNull(
lock = _lock,
predicate = this@EagerSingleton::_instance,
ifNotNull = { it },
ifNull = {
NoArgBindingDIWrap(di).creator().also { _instance = it }
}
)
}
}
/**
* @see [DIBinding.getFactory]
*/
override fun getFactory(key: DI.Key, di: BindingDI): (Unit) -> T = getFactory(di)
override fun factoryName(): String = "eagerSingleton"
init {
val key = DI.Key(TypeToken.Any, TypeToken.Unit, createdType, null)
builder.onReady { getFactory(BindingDIImpl(this, key, 0)).invoke(Unit) }
}
override val copier: DIBinding.Copier = DIBinding.Copier { builder -> EagerSingleton(builder, createdType, creator) }
}
/**
* Concrete instance provider: will always return the given instance.
*
* @param T The type of the instance.
* @param createdType The type of the object, *used for debug print only*.
* @property instance The object that will always be returned.
*/
public class InstanceBinding(override val createdType: TypeToken, public val instance: T) : NoArgDIBinding {
override fun factoryName(): String = "instance"
override val contextType: TypeToken = TypeToken.Any
/**
* @see [DIBinding.getFactory]
*/
override fun getFactory(key: DI.Key, di: BindingDI): (Unit) -> T = { _ -> this.instance }
override val description: String get() = "${factoryName()} ( ${createdType.simpleDispString()} )"
override val fullDescription: String get() = "${factoryFullName()} ( ${createdType.qualifiedDispString()} )"
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy