Repository: ktorio/ktor
File: ktor-server/ktor-server-plugins/ktor-server-di/common/src/io/ktor/server/plugins/di/DependencyRegistry.kt (Kotlin)

Code before:
    internal val requirements = mutableMapOf<DependencyKey, Throwable>()
    private val resolver: Lazy<DependencyResolver> = lazy {
        resolution.resolve(provider, external, reflection)
    }

    override fun <T> set(key: DependencyKey, value: DependencyResolver.() -> T) {
        if (resolver.isInitialized()) throw OutOfOrderDependencyException(key)
        provider.set(key, value)
    }

    override fun contains(key: DependencyKey): Boolean =
        resolver.value.contains(key)

    override fun <T> get(key: DependencyKey): T =
        resolver.value.get(key)

    override fun <T> getOrPut(key: DependencyKey, defaultValue: () -> T): T =
        resolver.value.getOrPut(key, defaultValue)

    /**
     * Indicates that the given dependency is required.
     *
     * This is ensured after `validate()` is called.
     */
    public fun require(key: DependencyKey) {
        requirements += key to DependencyInjectionException()
    }

    /**
     * Get the dependency from the map for the key represented by the type (and optionally, with the given name).
     */
    public inline fun <reified T> resolve(key: String? = null): T =
        get(dependencyKey<T>(key))

    /**
     * Provides a delegated property for accessing a dependency from a [DependencyRegistry].
     * This operator function allows property delegation, ensuring the required dependency is
     * registered and retrievable through the registry.
     *
     * Example usage:
     * ```
     * val repository: Repository<Message> by dependencies
     * ```
     *
     * @param thisRef The receiver to which the property is being delegated. This parameter
     * is not used in the actual implementation.
     * @param prop The property for which the delegate is being requested.
     * @return A [ReadOnlyProperty] that provides access to the resolved dependency of type [T].
     * @throws DependencyInjectionException If the dependency required by [prop] is not resolvable
     * during access.
     */

Review comment (refactor):
What if we introduce a new internal class `DependencyDeclarationSource : Throwable` and change the type of `requirements` to `mutableMapOf<DependencyKey, DependencyDeclarationSource>()`? The functions extracting external trace could be moved into it then.

Code after:
    internal val requirements = mutableMapOf<DependencyKey, DependencyReference>()
    private val resolver: Lazy<DependencyResolver> = lazy {
        resolution.resolve(provider, external, reflection)
    }

    override fun <T> set(key: DependencyKey, value: DependencyResolver.() -> T) {
        if (resolver.isInitialized()) throw OutOfOrderDependencyException(key)
        provider.set(key, value)
    }

    override fun contains(key: DependencyKey): Boolean =
        resolver.value.contains(key)

    override fun <T> get(key: DependencyKey): T =
        resolver.value.get(key)

    override fun <T> getOrPut(key: DependencyKey, defaultValue: () -> T): T =
        resolver.value.getOrPut(key, defaultValue)

    /**
     * Indicates that the given dependency is required.
     *
     * The DI plugin enforces this at startup.
     */
    public fun require(key: DependencyKey) {
        requirements += key to DependencyReference()
    }

    /**
     * Get the dependency from the map for the key represented by the type (and optionally, with the given name).
     */
    public inline fun <reified T> resolve(key: String? = null): T =
        get(DependencyKey<T>(key))

    /**
     * Provides a delegated property for accessing a dependency from a [DependencyRegistry].
     * This operator function allows property delegation, ensuring the required dependency is
     * registered and retrievable through the registry.
     *
     * Example usage:
     * ```
     * val repository: Repository<Message> by dependencies
     * ```
     *
     * @param thisRef The receiver to which the property is being delegated. This parameter
     * is not used in the actual implementation.
     * @param prop The property for which the delegate is being requested.
     * @return A [ReadOnlyProperty] that provides access to the resolved dependency of type [T].
     * @throws DependencyInjectionException If the dependency required by [prop] is not resolvable
     * during access.
     */