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 f651b1b
Show file tree
Hide file tree
Showing 9 changed files with 888 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@ package org.kodein.di.android

import android.accounts.AccountManager
import android.annotation.SuppressLint
import android.app.Activity
import android.app.ActivityManager
import android.app.AlarmManager
import android.app.Application
import android.app.Dialog
import android.app.DownloadManager
import android.app.Fragment
import android.app.admin.DevicePolicyManager
import android.app.job.JobScheduler
import android.app.usage.NetworkStatsManager
import android.app.usage.UsageStatsManager
import android.appwidget.AppWidgetManager
import android.content.AbstractThreadedSyncAdapter
import android.content.Context
import android.content.Loader
import android.content.pm.LauncherApps
import android.content.pm.ShortcutManager
import android.hardware.SensorManager
Expand Down Expand Up @@ -40,8 +50,12 @@ import android.view.inputmethod.InputMethodManager
import android.view.textservice.TextServicesManager
import org.kodein.di.DI
import org.kodein.di.bind
import org.kodein.di.bindings.Factory
import org.kodein.di.bindings.Provider
import org.kodein.di.bindings.SimpleContextTranslator
import org.kodein.type.TypeToken
import org.kodein.type.generic
import kotlin.coroutines.jvm.internal.CompletedContinuation.context

val androidCoreContextTranslators = DI.Module(name = "\u2063androidCoreContextTranslators") {
RegisterContextTranslator(SimpleContextTranslator<Fragment, Activity>(generic(), generic()) { it.activity })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ package org.kodein.di.jxinject
import org.kodein.di.*
import org.kodein.di.bindings.*
import org.kodein.di.jxinject.internal.JxInjectorContainer
import org.kodein.type.TypeToken
import org.kodein.type.erased
import javax.inject.Named

/**
* Module that must be imported in order to use [JxInjector].
*/
public val jxInjectorModule: DI.Module = DI.Module("JX Injector") {
Bind(binding = SetBinding<Any, JxInjectorContainer.Qualifier>(TypeToken.Any, erased(), erasedSet()))
bindSet<JxInjectorContainer.Qualifier>()
jxQualifier(Named::class.java) { it.value }

bind<JxInjectorContainer>() with Singleton(NoScope(), erased(), false, erased()) { JxInjectorContainer(Instance(erasedSet())) }
Expand All @@ -30,7 +29,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))
InBindSet(type = erased<JxInjectorContainer.Qualifier>()) {
add { InstanceBinding(erased(), JxInjectorContainer.Qualifier(cls, tagProvider as (Annotation) -> Any)) }
}
}

/**
Expand All @@ -40,7 +41,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
2 changes: 1 addition & 1 deletion kodein-di/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ kodein {

common {
main.dependencies {
api("org.kodein.type:kaverit:2.2.1-kotlin-1.7.20-RC")
api("org.kodein.type:kaverit:2.2.1")
}
test.dependencies {
implementation(project(":test-utils"))
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 f651b1b

Please sign in to comment.