Skip to content

Commit

Permalink
implement new set binding API (#384)
Browse files Browse the repository at this point in the history
  • Loading branch information
romainbsl committed Nov 14, 2022
1 parent 996440a commit bd38323
Show file tree
Hide file tree
Showing 7 changed files with 872 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ public val DirectDI.jx: JxInjector get() = JxInjector(this, Instance(erased(), n
/** @suppress */
@Suppress("UNCHECKED_CAST")
public fun <T: Annotation> DI.Builder.jxQualifier(cls: Class<T>, tagProvider: (T) -> Any) {
Bind(erased<JxInjectorContainer.Qualifier>()).InSet(erasedSet()) with InstanceBinding(erased(), JxInjectorContainer.Qualifier(cls, tagProvider as (Annotation) -> Any))
BindInSet(type = erased<JxInjectorContainer.Qualifier>()) {
add { InstanceBinding(erased(), JxInjectorContainer.Qualifier(cls, tagProvider as (Annotation) -> Any)) }
}
}

/**
Expand All @@ -40,7 +42,8 @@ public fun <T: Annotation> DI.Builder.jxQualifier(cls: Class<T>, tagProvider: (T
* @receiver DI Builder.
* @param tagProvider A function that transforms an annotation of type `T` into a tag.
*/
internal inline fun <reified T: Annotation> DI.Builder.jxQualifier(noinline tagProvider: (T) -> Any) = jxQualifier(T::class.java, tagProvider)
internal inline fun <reified T : Annotation> DI.Builder.jxQualifier(noinline tagProvider: (T) -> Any) =
jxQualifier(T::class.java, tagProvider)

/**
* Utility function that eases the retrieval of a [JxInjector].
Expand Down
112 changes: 112 additions & 0 deletions kodein-di/src/commonMain/kotlin/org/kodein/di/DI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,46 @@ public interface DI : DIAware {
public fun <T: Any> With(valueType: TypeToken<out T>, value: T)
}

/**
* Manage multiple bindings in a [Set]
*/
public interface SetBinder<T : Any> {
/**
* Add a binding in the [Set] of type [T]
*
* @param createBinding The builder that should add binding in the set.
*/
public fun add(createBinding: () -> DIBinding<*, *, out T>)
/**
* Add a binding in the [Set] of type [T], and also in the DI container
*
* @param tag The tag to bind.
* @param overrides Whether this bind **must** or **must not** override an existing binding.
* @param createBinding The builder that should add binding in the set.
*/
public fun bind(tag: Any? = null, overrides: Boolean? = null, createBinding: () -> DIBinding<*, *, out T>)
}

/**
* Manage multiple bindings, with type argument, in a [Set]
*/
public interface ArgSetBinder<A: Any, T : Any> {
/**
* Add a binding in the [Set] of type [T]
*
* @param createBinding The builder that should add binding in the set.
*/
public fun add(createBinding: () -> DIBinding<*, in A, out T>)
/**
* Add a binding in the [Set] of type [T], and also in the DI container
*
* @param tag The tag to bind.
* @param overrides Whether this bind **must** or **must not** override an existing binding.
* @param createBinding The builder that should add binding in the set.
*/
public fun bind(tag: Any? = null, overrides: Boolean? = null, createBinding: () -> DIBinding<*, in A, out T>)
}

/**
* Attaches the binding of a given type with a given tag.
*
Expand All @@ -286,19 +326,91 @@ public interface DI : DIAware {
*/
public fun <T : Any> Bind(tag: Any? = null, overrides: Boolean? = null, binding: DIBinding<*, *, T>)

/**
* Creates a Set binding of a given type with a given tag and attaches multiple bindings to it.
*
* @param T The type of value to bind.
* @param tag The tag to bind.
* @param overrides Whether this bind **must** or **must not** override an existing binding.
*/
public fun <T : Any> BindInSet(
tag: Any? = null,
overrides: Boolean? = null,
type: TypeToken<out T>,
creator: SetBinder<T>.() -> Unit
)

/**
* Attaches multiple bindings in a Set binding of a given type with a given tag.
*
* @param T The type of value to bind.
* @param tag The tag to bind.
* @param overrides Whether this bind **must** or **must not** override an existing binding.
*/
public fun <T : Any> InBindSet(
tag: Any? = null,
overrides: Boolean? = null,
type: TypeToken<out T>,
creator: SetBinder<T>.() -> Unit
)

/**
* Creates a Set binding of a given type with a given tag and attaches multiple bindings to it.
*
* @param T The type of value to bind.
* @param tag The tag to bind.
* @param overrides Whether this bind **must** or **must not** override an existing binding.
*/
public fun <A: Any, T : Any> BindInArgSet(
tag: Any? = null,
overrides: Boolean? = null,
argType: TypeToken<in A>,
type: TypeToken<out T>,
creator: ArgSetBinder<A, T>.() -> Unit
)

/**
* Attaches multiple bindings in a Set binding of a given type with a given tag.
*
* @param T The type of value to bind.
* @param tag The tag to bind.
* @param overrides Whether this bind **must** or **must not** override an existing binding.
*/
public fun <A: Any, T : Any> InBindArgSet(
tag: Any? = null,
overrides: Boolean? = null,
argType: TypeToken<in A>,
type: TypeToken<out T>,
creator: ArgSetBinder<A, T>.() -> Unit
)

/**
* Attaches the binding of a given type with a given tag.
*
* @param T The type of value to bind.
* @param tag The tag to bind.
* @param overrides Whether this bind **must** or **must not** override an existing binding.
*/
@Deprecated("Use AddBindInSet instead.", ReplaceWith("AddBindInSet"))
public fun <T : Any> BindSet(
tag: Any? = null,
overrides: Boolean? = null,
binding: DIBinding<*, *, T>,
)

/**
* Attaches multiple bindings in a Set binding of a given type with a given tag.
*
* @param T The type of value to bind.
* @param tag The tag to bind.
* @param overrides Whether this bind **must** or **must not** override an existing binding.
*/
public fun <T : Any> AddBindInSet(
tag: Any? = null,
overrides: Boolean? = null,
binding: DIBinding<*, *, T>,
)

/**
* Starts the binding of a given type with a given tag.
*
Expand Down
81 changes: 70 additions & 11 deletions kodein-di/src/commonMain/kotlin/org/kodein/di/SetBindings.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@file:Suppress("unused", "UNCHECKED_CAST")
@file:Suppress("unused", "unchecked_cast", "deprecation")

package org.kodein.di

Expand All @@ -23,17 +23,48 @@ import org.kodein.type.generic
public inline fun <reified T : Any> DI.Builder.bindSet(tag: Any? = null, overrides: Boolean? = null): Unit = Bind(
tag = tag,
overrides = overrides,
binding = SetBinding(TypeToken.Any, generic<T>(), erasedComp(Set::class, generic<T>()) as TypeToken<Set<T>>)
binding = SetBinding(
contextType = TypeToken.Any,
_elementType = generic<T>(),
createdType = erasedComp(Set::class, generic<T>()) as TypeToken<Set<T>>
)
)

/**
* Creates a set and add multiple bindings to it.
*
* T generics will be erased!
*
* @param T The created type.
* @param creator The builder that should add binding in the set.
*/
public inline fun <reified T : Any> DI.Builder.bindSet(
tag: Any? = null,
overrides: Boolean? = null,
noinline creator: DI.Builder.SetBinder<T>.() -> Unit
): Unit = BindInSet(tag = tag, overrides = overrides, type = generic(), creator = creator)

/**
* Add multiple bindings in an existing set
*
* T generics will be erased!
*
* @param T The binding type of the targeted set.
* @param creator The builder that should add binding in the set.
*/
public inline fun <reified T : Any> DI.Builder.inBindSet(
tag: Any? = null,
overrides: Boolean? = null,
noinline creator: DI.Builder.SetBinder<T>.() -> Unit
): Unit = InBindSet(tag = tag, overrides = overrides, type = generic(), creator = creator)

/**
* Creates a set: multiple bindings can be added in this set.
*
* T generics will be erased!
*
* @param A The argument type.
* @param T The created type.
* @return A set binding ready to be bound.
*/
@Suppress("RemoveExplicitTypeArguments")
public inline fun <reified A : Any, reified T : Any> DI.Builder.bindArgSet(
Expand All @@ -43,22 +74,38 @@ public inline fun <reified A : Any, reified T : Any> DI.Builder.bindArgSet(
tag = tag,
overrides = overrides,
binding = ArgSetBinding(
TypeToken.Any,
generic<A>(),
generic<T>(),
erasedComp(Set::class, generic<T>()) as TypeToken<Set<T>>
contextType = TypeToken.Any,
argType = generic<A>(),
_elementType = generic<T>(),
createdType = erasedComp(Set::class, generic<T>()) as TypeToken<Set<T>>
)
)

/**
* Creates a set and add multiple bindings to it.
*
* T generics will be erased!
*
* @param A The argument type.
* @param T The created type.
* @param creator The builder that should add binding in the set.
*/
public inline fun <reified A : Any, reified T : Any> DI.Builder.bindArgSet(
tag: Any? = null,
overrides: Boolean? = null,
noinline creator: DI.Builder.ArgSetBinder<A, T>.() -> Unit
): Unit = BindInArgSet(tag = tag, overrides = overrides, argType = generic(), type = generic(), creator = creator)

/**
* Defines that the binding will be saved in a set binding.
*
* T generics will be erased!
*
* @param T The type of the binding.
*/
@Deprecated("Use addInBindSet instead")
public inline fun <reified T : Any> DI.Builder.TypeBinder<T>.inSet(): TypeBinderInSet<T, Set<T>> =
InSet(erasedComp(Set::class, generic<T>()) as TypeToken<Set<T>>)
InSet(setTypeToken = erasedComp(Set::class, generic<T>()) as TypeToken<Set<T>>)

/**
* Defines that the binding will be saved in a set binding.
Expand All @@ -67,10 +114,22 @@ public inline fun <reified T : Any> DI.Builder.TypeBinder<T>.inSet(): TypeBinder
*
* @param T The type of the binding.
*/
@Deprecated("Use addInBindSet instead", ReplaceWith("addInBindSet"))
public inline fun <reified T : Any> DI.Builder.inSet(
tag: Any? = null,
overrides: Boolean? = null,
creator: () -> DIBinding<*, *, T>
): Unit {
BindSet(tag = tag, overrides = overrides, creator())
}
): Unit = BindSet(tag = tag, overrides = overrides, creator())

/**
* Defines that the binding will be saved in a set binding.
*
* T generics will be erased!
*
* @param T The type of the binding.
*/
public inline fun <reified T : Any> DI.Builder.addInBindSet(
tag: Any? = null,
overrides: Boolean? = null,
creator: () -> DIBinding<*, *, T>
): Unit = AddBindInSet(tag = tag, overrides = overrides, binding = creator())
5 changes: 3 additions & 2 deletions kodein-di/src/commonMain/kotlin/org/kodein/di/bindings/set.kt
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public class SetBinding<C : Any, T : Any>(
override val createdType: TypeToken<out Set<T>>
) : NoArgDIBinding<C, Set<T>>, BaseMultiBinding<C, Unit, T>() {

@Suppress("UNCHECKED_CAST")
override val set = LinkedHashSet<DIBinding<C, Unit, T>>()

override fun getFactory(key: DI.Key<C, Unit, Set<T>>, di: BindingDI<C>): (Unit) -> Set<T> {
Expand All @@ -96,6 +95,7 @@ public class SetBinding<C : Any, T : Any>(
*
* @param T The type of the binding in the set.
*/
@Deprecated("TypeBinderInSet must be replaced by the use of bindSet / inBindSet / addInBindSet builders.")
public class TypeBinderInSet<in T : Any, S : Any> internal constructor(
private val _binder: DI.Builder.TypeBinder<T>,
private val _colTypeToken: TypeToken<S>
Expand Down Expand Up @@ -129,6 +129,7 @@ public class TypeBinderInSet<in T : Any, S : Any> internal constructor(
* @param T The provided type of all bindings in the set.
* @param setTypeToken The type of the bound set.
*/
@Suppress("FunctionName")
@Suppress("FunctionName", "deprecation")
@Deprecated("InSet must be replaced by the use of bindSet / inBindSet / addInBindSet builders.")
public fun <T : Any> DI.Builder.TypeBinder<T>.InSet(setTypeToken: TypeToken<Set<T>>): TypeBinderInSet<T, Set<T>> =
TypeBinderInSet(this, setTypeToken)
Loading

0 comments on commit bd38323

Please sign in to comment.