commonMain.org.kodein.di.bindings.set.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.DIBuilderImpl
import org.kodein.type.TypeToken
/**
* Base class for binding set.
*
* @param C The context type of all bindings in the set.
* @param A The argument type of all bindings in the set.
* @param T The provided type of all bindings in the set.
*/
public abstract class BaseMultiBinding : DIBinding> {
internal abstract val set: MutableSet>
override fun factoryName(): String = "bindingSet"
}
private class SetBindingDI(private val _base: BindingDI) : BindingDI by _base {
override fun overriddenFactory() = throw IllegalStateException("Cannot access overrides in a Set binding")
override fun overriddenFactoryOrNull() = throw IllegalStateException("Cannot access overrides in a Set binding")
}
/**
* Binding that holds multiple factory bindings (e.g. with argument) in a set.
*
* @param C The context type of all bindings in the set.
* @param A The argument type of all bindings in the set.
* @param T The provided type of all bindings in the set.
*/
public class ArgSetBinding(override val contextType: TypeToken, override val argType: TypeToken, private val _elementType: TypeToken, override val createdType: TypeToken>) : BaseMultiBinding() {
override val set = LinkedHashSet>()
override fun getFactory(key: DI.Key>, di: BindingDI): (A) -> Set {
var lateInitFactories: List<(A) -> T>? = null
return { arg ->
val factories = lateInitFactories ?: run {
val subKey = DI.Key(key.contextType, key.argType, _elementType, key.tag)
set.map { it.getFactory(subKey, SetBindingDI(di)) }
}.also { lateInitFactories = it }
factories.asSequence().map { it.invoke(arg) } .toSet()
}
}
override val copier: DIBinding.Copier> = DIBinding.Copier { builder ->
ArgSetBinding(contextType, argType, _elementType, createdType).also {
it.set.addAll(set.map { it.copier?.copy(builder) ?: it })
}
}
}
/**
* Binding that holds multiple factory bindings (e.g. with argument) in a set.
*
* @param C The context type of all bindings in the set.
* @param T The provided type of all bindings in the set.
*/
public class SetBinding(override val contextType: TypeToken, private val _elementType: TypeToken, override val createdType: TypeToken>) : NoArgDIBinding>, BaseMultiBinding() {
@Suppress("UNCHECKED_CAST")
override val set = LinkedHashSet>()
override fun getFactory(key: DI.Key>, di: BindingDI): (Unit) -> Set {
var lateInitProviders: List<(Unit) -> T>? = null
return { _ ->
val providers = lateInitProviders ?: run {
val subKey = DI.Key(key.contextType, TypeToken.Unit, _elementType, key.tag)
val subDI = SetBindingDI(di)
set.map { it.getFactory(subKey, subDI) }
}.also { lateInitProviders = it }
providers.asSequence().map { it.invoke(Unit) }.toSet()
}
}
override val copier: DIBinding.Copier> = DIBinding.Copier { builder ->
SetBinding(contextType, _elementType, createdType).also {
it.set.addAll(set.map { it.copier?.copy(builder) ?: it })
}
}
}
/**
* Second part of the `bind().inSet() with binding` syntax.
*
* @param T The type of the binding in the set.
*/
public class TypeBinderInSet internal constructor(private val _binder: DI.Builder.TypeBinder, private val _colTypeToken: TypeToken) {
/**
* Second part of the `bind().inSet() with binding` syntax.
*
* @param C The context type of the binding.
* @param binding The binding to add in the set.
*/
@Suppress("UNCHECKED_CAST")
public infix fun with(binding: DIBinding) {
_binder as DIBuilderImpl.TypeBinder
val setKey = DI.Key(binding.contextType, binding.argType, _colTypeToken, _binder.tag)
val setBinding = _binder.containerBuilder.bindingsMap[setKey]?.first() ?: throw IllegalStateException("No set binding to $setKey")
setBinding.binding as? BaseMultiBinding ?: throw IllegalStateException("$setKey is associated to a ${setBinding.binding.factoryName()} while it should be associated with bindingSet")
(setBinding.binding.set as MutableSet>).add(binding)
}
}
/**
* Allows to bind in an existing set binding (rather than directly as a new binding).
*
* First part of the `bind().inSet() with binding` syntax.
*
* @param T The provided type of all bindings in the set.
* @param setTypeToken The type of the bound set.
*/
@Suppress("FunctionName")
public fun DI.Builder.TypeBinder.InSet(setTypeToken: TypeToken>): TypeBinderInSet> = TypeBinderInSet(this, setTypeToken)
© 2015 - 2024 Weber Informatics LLC | Privacy Policy