Repository: ktorio/ktor
File: ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClientConfig.kt (Kotlin)

Code before:
     * If the plugin is already installed, the configuration block will be applied to the existing configuration class.
     *
     * Learn more from [Plugins](https://ktor.io/docs/http-client-plugins.html).
     *
     * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.client.HttpClientConfig.install)
     */
    public fun <TBuilder : Any, TPlugin : Any> install(
        plugin: HttpClientPlugin<TBuilder, TPlugin>,
        configure: TBuilder.() -> Unit = {}
    ) {
        val previousConfigBlock = pluginConfigurations[plugin.key]
        pluginConfigurations[plugin.key] = {
            previousConfigBlock?.invoke(this)

            @Suppress("UNCHECKED_CAST")
            (this as TBuilder).configure()
        }

        installPlugin(plugin)
    }

    /**
     * Installs the specified [plugin] and optionally configures it using the [configure] block.
     * If the plugin is already installed, the configuration block will override the existing configuration class.
     */
    internal fun <TBuilder : Any, TPlugin : Any> installAndOverride(
        plugin: HttpClientPlugin<TBuilder, TPlugin>,
        configure: TBuilder.() -> Unit = {}
    ) {
        pluginConfigurations[plugin.key] = {
            @Suppress("UNCHECKED_CAST")
            (this as TBuilder).configure()
        }

        installPlugin(plugin)
    }

    private fun <TBuilder : Any, TPlugin : Any> installPlugin(plugin: HttpClientPlugin<TBuilder, TPlugin>) {
        if (plugins.containsKey(plugin.key)) return

        plugins[plugin.key] = { scope ->
            val attributes = scope.attributes.computeIfAbsent(PLUGIN_INSTALLED_LIST) { Attributes(concurrent = true) }
            val config = scope.config.pluginConfigurations[plugin.key]!!
            val pluginData = plugin.prepare(config)

            plugin.install(pluginData, scope)
            attributes.put(plugin.key, pluginData)
        }
    }

    /**

Review comment (suggestion):
Maybe `installOrReplace()`?  This could be public as well, since there's some other uses.

Code after:
     * If the plugin is already installed, the configuration block will be applied to the existing configuration class.
     *
     * Learn more from [Plugins](https://ktor.io/docs/http-client-plugins.html).
     *
     * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.client.HttpClientConfig.install)
     */
    public fun <TBuilder : Any, TPlugin : Any> install(
        plugin: HttpClientPlugin<TBuilder, TPlugin>,
        configure: TBuilder.() -> Unit = {}
    ) {
        val previousConfigBlock = pluginConfigurations[plugin.key]
        pluginConfigurations[plugin.key] = {
            previousConfigBlock?.invoke(this)

            @Suppress("UNCHECKED_CAST")
            (this as TBuilder).configure()
        }

        installPlugin(plugin)
    }

    /**
     * Installs the specified [plugin] and optionally configures it using the [configure] block.
     * If the plugin is already installed, the configuration block will replace the existing configuration class.
     *
     * ```kotlin
     * val client = HttpClient {
     *     installOrReplace(ContentNegotiation) {
     *         // configuration block
     *         json()
     *     }
     * }
     * ```
     *
     * Learn more from [Plugins](https://ktor.io/docs/http-client-plugins.html).
     *
     * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.client.HttpClientConfig.installOrReplace)
     */
    public fun <TBuilder : Any, TPlugin : Any> installOrReplace(
        plugin: HttpClientPlugin<TBuilder, TPlugin>,
        configure: TBuilder.() -> Unit = {}
    ) {
        pluginConfigurations[plugin.key] = {
            @Suppress("UNCHECKED_CAST")
            (this as TBuilder).configure()
        }

        installPlugin(plugin)
    }

    private fun <TBuilder : Any, TPlugin : Any> installPlugin(plugin: HttpClientPlugin<TBuilder, TPlugin>) {