commonMain.org.kodein.di.DIAware.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
@file:Suppress("FunctionName", "DEPRECATION")
package org.kodein.di
import org.kodein.di.internal.DirectDIImpl
import org.kodein.type.TypeToken
/**
* Defines a context and its type to be used by Di
*/
public interface DIContext {
/**
* The type of the context, used to lookup corresponding bindings.
*/
public val type: TypeToken
/**
* The context itself.
*/
public val value: C
/**
* Defines a context and its type to be used by DI
*/
public data class Value(override val type: TypeToken, override val value: C) : DIContext
/**
* Defines a context and its type to be used by DI
*/
public class Lazy(override val type: TypeToken, public val getValue: () -> C) : DIContext {
override val value: C by lazy(getValue)
}
public companion object {
public operator fun invoke(type: TypeToken, value: C): DIContext = Value(type, value)
public operator fun invoke(type: TypeToken, getValue: () -> C): DIContext =
Lazy(type, getValue)
}
}
@Suppress("UNCHECKED_CAST")
internal inline val DIContext<*>.anyType get() = type as TypeToken
private object Contexes {
val AnyDIContext = DIContext(TypeToken.Any, Any())
}
/**
* Default DI context, means no context.
*/
internal val AnyDIContext: DIContext get() = Contexes.AnyDIContext
/**
* Any class that extends this interface can use DI "seamlessly".
*/
public interface DIAware {
/**
* A DI Aware class must be within reach of a [DI] object.
*/
public val di: DI
/**
* A DI Aware class can define a context that is for all retrieval by overriding this property.
*
* Note that even if you override this property, all bindings that do not use a Context or are not scoped will still work!
*/
public val diContext: DIContext<*> get() = AnyDIContext
/**
* Trigger to use that define when the retrieval will be done.
*
* By default, retrieval happens on first property access.
* However, you can use a [DITrigger] to force retrieval at a given time of your choice.
*/
public val diTrigger: DITrigger? get() = null
}
/**
* Gets a factory of [T] for the given argument type, return type and tag.
*
* @param A The type of argument the returned factory takes.
* @param T The type of object to retrieve with the returned factory.
* @param argType The type of argument the returned factory takes.
* @param type The type of object to retrieve with the returned factory.
* @param tag The bound tag, if any.
* @return A factory of [T].
* @throws DI.NotFoundException If no factory was found.
* @throws DI.DependencyLoopException When calling the factory, if the value construction triggered a dependency loop.
*/
public fun DIAware.Factory(
argType: TypeToken,
type: TypeToken,
tag: Any? = null,
): LazyDelegate<(A) -> T> = DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.factory(DI.Key(ctx.anyType, argType, type, tag), ctx.value)
}
/**
* Gets a factory of [T] for the given argument type, return type and tag, or null if none is found.
*
* @param A The type of argument the returned factory takes.
* @param T The type of object to retrieve with the returned factory.
* @param argType The type of argument the returned factory takes.
* @param type The type of object to retrieve with the returned factory.
* @param tag The bound tag, if any.
* @return A factory of [T], or null if no factory was found.
* @throws DI.DependencyLoopException When calling the factory, if the value construction triggered a dependency loop.
*/
public fun DIAware.FactoryOrNull(
argType: TypeToken,
type: TypeToken,
tag: Any? = null,
): LazyDelegate<((A) -> T)?> = DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.factoryOrNull(DI.Key(ctx.anyType, argType, type, tag), ctx.value)
}
/**
* Gets a provider of [T] for the given type and tag.
*
* @param T The type of object to retrieve with the returned provider.
* @param type The type of object to retrieve with the returned provider.
* @param tag The bound tag, if any.
* @return A provider of [T].
* @throws DI.NotFoundException If no provider was found.
* @throws DI.DependencyLoopException When calling the provider, if the value construction triggered a dependency loop.
*/
public fun DIAware.Provider(type: TypeToken, tag: Any? = null): LazyDelegate<() -> T> =
DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.provider(DI.Key(ctx.anyType, TypeToken.Unit, type, tag), ctx.value)
}
/**
* Gets a provider of [T] for the given type and tag, curried from a factory that takes an argument [A].
*
* @param A The type of argument the curried factory takes.
* @param T The type of object to retrieve with the returned provider.
* @param argType The type of argument the curried factory takes.
* @param type The type of object to retrieve with the returned provider.
* @param tag The bound tag, if any.
* @param arg A function that returns the argument that will be given to the factory when curried.
* @return A provider of [T].
* @throws DI.NotFoundException If no provider was found.
* @throws DI.DependencyLoopException When calling the provider, if the value construction triggered a dependency loop.
*/
public fun DIAware.Provider(
argType: TypeToken,
type: TypeToken,
tag: Any? = null,
arg: () -> A,
): DIProperty<() -> T> = DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.factory(DI.Key(ctx.anyType, argType, type, tag),
ctx.value).toProvider(arg)
}
/**
* Gets a provider of [T] for the given type and tag, or null if none is found.
*
* @param T The type of object to retrieve with the returned provider.
* @param type The type of object to retrieve with the returned provider.
* @param tag The bound tag, if any.
* @return A provider of [T], or null if no provider was found.
* @throws DI.DependencyLoopException When calling the provider, if the value construction triggered a dependency loop.
*/
public fun DIAware.ProviderOrNull(type: TypeToken, tag: Any? = null): LazyDelegate<(() -> T)?> =
DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.providerOrNull(DI.Key(ctx.anyType,
TypeToken.Unit,
type,
tag), ctx.value)
}
/**
* Gets a provider of [T] for the given type and tag, curried from a factory that takes an argument [A], or null if none is found.
*
* @param A The type of argument the curried factory takes.
* @param T The type of object to retrieve with the returned provider.
* @param argType The type of argument the curried factory takes.
* @param type The type of object to retrieve with the returned provider.
* @param tag The bound tag, if any.
* @param arg A function that returns the argument that will be given to the factory when curried.
* @return A provider of [T], or null if no factory was found.
* @throws DI.DependencyLoopException When calling the provider, if the value construction triggered a dependency loop.
*/
public fun DIAware.ProviderOrNull(
argType: TypeToken,
type: TypeToken,
tag: Any? = null,
arg: () -> A,
): LazyDelegate<(() -> T)?> = DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.factoryOrNull(DI.Key(ctx.anyType, argType, type, tag),
ctx.value)?.toProvider(arg)
}
/**
* Gets an instance of [T] for the given type and tag.
*
* @param T The type of object to retrieve.
* @param type The type of object to retrieve.
* @param tag The bound tag, if any.
* @return An instance of [T].
* @throws DI.NotFoundException If no provider was found.
* @throws DI.DependencyLoopException If the value construction triggered a dependency loop.
*/
public fun DIAware.Instance(type: TypeToken, tag: Any? = null): LazyDelegate =
DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.provider(DI.Key(ctx.anyType, TypeToken.Unit, type, tag),
ctx.value).invoke()
}
/**
* Gets an instance of [T] for the given type and tag, curried from a factory that takes an argument [A].
*
* @param A The type of argument the curried factory takes.
* @param T The type of object to retrieve.
* @param argType The type of argument the curried factory takes.
* @param type The type of object to retrieve.
* @param tag The bound tag, if any.
* @param arg A function that returns the argument that will be given to the factory when curried.
* @return An instance of [T].
* @throws DI.NotFoundException If no provider was found.
* @throws DI.DependencyLoopException If the value construction triggered a dependency loop.
*/
public fun DIAware.Instance(
argType: TypeToken,
type: TypeToken,
tag: Any? = null,
arg: () -> A,
): LazyDelegate = DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.factory(DI.Key(ctx.anyType, argType, type, tag),
ctx.value).invoke(arg())
}
/**
* Gets an instance of [T] for the given type and tag, or null if none is found.
*
* @param type The type of object to retrieve.
* @param tag The bound tag, if any.
* @return An instance of [T], or null if no provider was found.
* @throws DI.DependencyLoopException If the value construction triggered a dependency loop.
*/
public fun DIAware.InstanceOrNull(type: TypeToken, tag: Any? = null): LazyDelegate =
DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.providerOrNull(DI.Key(ctx.anyType,
TypeToken.Unit,
type,
tag), ctx.value)?.invoke()
}
/**
* Gets an instance of [T] for the given type and tag, curried from a factory that takes an argument [A], or null if none is found.
*
* @param A The type of argument the curried factory takes.
* @param T The type of object to retrieve.
* @param type The type of object to retrieve.
* @param tag The bound tag, if any.
* @param arg A function that returns the argument that will be given to the factory when curried.
* @return An instance of [T], or null if no factory was found.
* @throws DI.DependencyLoopException If the value construction triggered a dependency loop.
*/
public fun DIAware.InstanceOrNull(
argType: TypeToken,
type: TypeToken,
tag: Any? = null,
arg: () -> A,
): LazyDelegate = DIProperty(diTrigger, diContext) { ctx, _ ->
di.container.factoryOrNull(DI.Key(ctx.anyType, argType, type, tag),
ctx.value)?.invoke(arg())
}
/**
* Return a direct [DirectDI] instance, with its receiver and context set to this DIAware receiver and context.
*/
public val DIAware.direct: DirectDI get() = DirectDIImpl(di.container, diContext)
private class DIWrapper(
private val _base: DI,
override val diContext: DIContext<*>,
override val diTrigger: DITrigger? = null,
) : DI {
constructor(
base: DIAware,
diContext: DIContext<*> = base.diContext,
trigger: DITrigger? = base.diTrigger,
) : this(base.di, diContext, trigger)
override val di: DI get() = this
override val container: DIContainer get() = _base.container
}
/**
* Allows to create a new DI object with a context and/or a trigger set.
*
* @param context The new context of the new DI.
* @param trigger The new trigger of the new DI.
* @return A DI object that uses the same container as this one, but with its context and/or trigger changed.
*/
public fun DIAware.On(context: DIContext<*> = this.diContext, trigger: DITrigger? = this.diTrigger): DI =
DIWrapper(this, diContext = context, trigger = trigger)
/**
* Allows to create a new instance of an unbound object with the same API as when bounding one.
*
* @param T The type of object to create.
* @param creator A function that do create the object.
*/
public fun DIAware.newInstance(creator: DirectDI.() -> T): LazyDelegate =
DIProperty(diTrigger, diContext) { ctx, _ -> di.direct.On(ctx).run(creator) }
© 2015 - 2024 Weber Informatics LLC | Privacy Policy