All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.me.jason5lee.defer.DeferScope.kt Maven / Gradle / Ivy

package me.jason5lee.defer

/**
 * A defer scope. It is not thread-safe.
 */
public class DeferScope @PublishedApi internal constructor() {
    private var defers: ArrayList<() -> Unit>? = ArrayList()

    /**
     * Add a deferred task.
     *
     * @throws DeferScopeClosedException if out of scope or cancelled.
     */
    public fun defer(task: () -> Unit) {
        (defers ?: throw DeferScopeClosedException("DeferScope")).add(task)
    }

    /**
     * Add a deferred task which operates [this].
     *
     * @return [this]
     * @throws DeferScopeClosedException if out of scope or cancelled.
     */
    public inline fun  T.defer(crossinline task: T.() -> Unit): T {
        [email protected] { task() }
        return this
    }

    /**
     * Cancel all deferred tasks.
     */
    public fun cancelDeferred() {
        defers = null
    }

    @PublishedApi
    internal fun runDeferred() {
        val defers = this.defers ?: return
        var exception: Throwable? = null
        for (i in (defers.size - 1) downTo 0) {
            try {
                defers[i]()
            } catch (e: Throwable) {
                if (exception == null) {
                    exception = e
                } else {
                    exception.addSuppressed(e)
                }
            }
        }
        this.defers = null
        if (exception != null) throw exception
    }

    @PublishedApi
    internal fun runDeferred(exception: Throwable): Nothing {
        this.defers?.let { defers ->
            for (i in (defers.size - 1) downTo 0) {
                try {
                    defers[i]()
                } catch (e: Throwable) {
                    exception.addSuppressed(e)
                }
            }
        }
        this.defers = null

        throw exception
    }
}

/**
 * Creates a defer scope. Within this scope, you can use `defer` to add deferred tasks.
 * When exiting the defer scope, these tasks are executed in reverse order of their addition.
 */
public inline fun  deferScope(block: DeferScope.() -> R): R {
    val scope = DeferScope()
    val result = try {
        block(scope)
    } catch (e: Throwable) {
        scope.runDeferred(e)
    }
    scope.runDeferred()
    return result
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy