ContinuationUtils.kt

package org.knio.core.utils

import java.nio.channels.CompletionHandler
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

private val DEFAULT_ON_FAIL: (Throwable) -> Nothing = { throw it }

internal typealias CompletionBlock<T, R> = (T) -> R

/**
 * A CompletionHandler implementation that resumes a Continuation with the result or exception.
 *
 * @param T The type of the result.
 * @param R The type of the continuation result.
 * @property onComplete The block to execute on completion.
 * @property onFail The block to execute on failure.
 */
private class ContinuationCompletionHandler<T, R>(
    val onComplete: CompletionBlock<T, R>,
    val onFail: (Throwable) -> R
): CompletionHandler<T, Continuation<R>> {

    /**
     * Called when the operation completes successfully.
     *
     * @param result The result of the operation.
     * @param attachment The continuation to resume.
     */
    override fun completed(result: T, attachment: Continuation<R>) {
        try {
            attachment.resume(onComplete(result))
        } catch (e: Throwable) {
            attachment.resumeWithException(e)
        }
    }

    /**
     * Called when the operation fails.
     *
     * @param exc The exception that caused the failure.
     * @param attachment The continuation to resume with the exception.
     */
    override fun failed(exc: Throwable, attachment: Continuation<R>) {
        try {
            attachment.resume(onFail(exc))
        } catch (e: Throwable) {
            attachment.resumeWithException(e)
        }
    }
}

/**
 * Creates a CompletionHandler that resumes a Continuation with the result or exception.
 *
 * @param R The type of the continuation result.
 * @param onFail The block to execute on failure.
 * @return A CompletionHandler that resumes a Continuation.
 */
internal fun <R> fromResult(onFail: (Throwable) -> R = DEFAULT_ON_FAIL): CompletionHandler<R, Continuation<R>> {
    return ContinuationCompletionHandler({ it }, onFail = onFail)
}

/**
 * Converts a result to a CompletionHandler that resumes a Continuation.
 *
 * @param T The type of the result.
 * @param R The type of the continuation result.
 * @param onFail The block to execute on failure.
 * @return A CompletionHandler that resumes a Continuation.
 */
internal fun <T,R> R.asCompletionHandler(onFail: (Throwable) -> R = DEFAULT_ON_FAIL): CompletionHandler<T, Continuation<R>> {
    return ContinuationCompletionHandler({ this }, onFail = onFail)
}

/**
 * Converts a CompletionBlock to a CompletionHandler that resumes a Continuation.
 *
 * @param T The type of the result.
 * @param R The type of the continuation result.
 * @param onFail The block to execute on failure.
 * @return A CompletionHandler that resumes a Continuation.
 */
internal fun <T, R> CompletionBlock<T, R>.asCompletionHandler(onFail: (Throwable) -> R = DEFAULT_ON_FAIL): CompletionHandler<T, Continuation<R>> {
    return ContinuationCompletionHandler(this, onFail = onFail)
}