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

commonMain.jetbrains.datalore.base.async.Asyncs.kt Maven / Gradle / Ivy

There is a newer version: 4.5.3-alpha1
Show newest version
/*
 * Copyright (c) 2019. JetBrains s.r.o.
 * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
 */

package jetbrains.datalore.base.async

import jetbrains.datalore.base.function.Consumer
import jetbrains.datalore.base.function.Runnable
import jetbrains.datalore.base.function.Supplier
import jetbrains.datalore.base.function.Value
import jetbrains.datalore.base.registration.Registration

object Asyncs {
    fun isFinished(async: Async<*>): Boolean {
        val finished = Value(false)
        async.onResult(
                { finished.set(true) },
                { finished.set(true) }
        ).remove()
        return finished.get()
    }

    fun  constant(value: ValueT): Async {
        return object : Async {
            override fun onSuccess(successHandler: Consumer): Registration {
                successHandler(value)
                return Registration.EMPTY
            }

            override fun onResult(successHandler: Consumer, failureHandler: Consumer): Registration {
                return onSuccess(successHandler)
            }

            override fun onFailure(failureHandler: Consumer): Registration {
                return Registration.EMPTY
            }

            override fun  map(success: (ValueT) -> ResultT): Async {
                val result: ResultT
                try {
                    result = success(value)
                } catch (t: Throwable) {
                    return failure(t)
                }

                //return cannot be moved to try block to avoid catching possible errors from Asyncs.constant call
                return constant(result)
            }

            override fun  flatMap(success: (ValueT) -> Async?): Async {
                val result: Async?
                try {
                    result = success(value)
                } catch (t: Throwable) {
                    return failure(t)
                }

                //return cannot be moved to try block to avoid catching possible errors from Asyncs.constant call
                return if (result == null) {
                    constant(null)
                } else {
                    @Suppress("UNCHECKED_CAST")
                    result as Async
                }
            }
        }
    }

    fun  failure(t: Throwable): Async {
        return object : Async {
            override fun onSuccess(successHandler: Consumer): Registration {
                return Registration.EMPTY
            }

            override fun onResult(successHandler: Consumer, failureHandler: Consumer): Registration {
                return onFailure(failureHandler)
            }

            override fun onFailure(failureHandler: Consumer): Registration {
                failureHandler(t)
                return Registration.EMPTY
            }

            override fun  map(success: (ValueT) -> ResultT): Async {
                return failure(t)
            }

            override fun  flatMap(success: (ValueT) -> Async?): Async {
                return failure(t)
            }
        }
    }

    fun voidAsync(): Async {
        return constant(Unit)
    }

    fun  toUnit(async: Async): Async {
        return map(async, {}, ThreadSafeAsync())
    }

    internal fun  map(
            async: Async,
            f: (SourceT) -> TargetT,
            resultAsync: ResolvableAsync):
            Async {

        async.onResult(
                { value ->
                    val result: TargetT
                    try {
                        result = f(value)
                    } catch (e: Exception) {
                        resultAsync.failure(e)
                        return@onResult
                    }

                    resultAsync.success(result)
                },
                { value -> resultAsync.failure(value) })
        return resultAsync
    }

    internal fun  select(
            async: Async,
            f: (SourceT) -> Async?,
            resultAsync: ResolvableAsync):
            Async {

        async.onResult(
                { value ->
                    val async1: Async?
                    try {
                        async1 = f(value)
                    } catch (e: Exception) {
                        resultAsync.failure(e)
                        return@onResult
                    }

                    if (async1 == null) {
                        resultAsync.success(null)
                    } else {
                        delegate(async1, resultAsync)
                    }
                },
                { value -> resultAsync.failure(value) })
        return resultAsync
    }

    fun  seq(first: Async, second: Async): Async {
        return select(first, { second }, ThreadSafeAsync())
    }

    fun onAnyResult(async: Async<*>, r: Runnable): Registration {
        return async.onResult({ r.run() }, { r.run() })
    }

    fun  untilSuccess(s: Supplier>): Async {
        val result = SimpleAsync()
        val async: Async
        val successConsumer: Consumer = { value -> result.success(value) }
        try {
            async = s.get()
        } catch (ignore: Exception) {
            untilSuccess(s).onSuccess(successConsumer)
            return result
        }

        async.onResult(successConsumer, { untilSuccess(s).onSuccess(successConsumer) })
        return result
    }

    internal fun  delegate(from: Async, to: AsyncResolver): Registration {
        return from.onResult({ value -> to.success(value) }, { value -> to.failure(value) })
    }

    fun  pair(first: Async, second: Async): Async> {
        val res = SimpleAsync>()
        val proxy = SimpleAsync()
        val firstPaired = PairedAsync(first)
        val secondPaired = PairedAsync(second)
        proxy.onResult(
                {
                    if (firstPaired.mySucceeded && secondPaired.mySucceeded) {
                        @Suppress("UNCHECKED_CAST")
                        res.success(Pair(
                                firstPaired.myItem as FirstT,
                                secondPaired.myItem as SecondT))
                    } else {
                        res.failure(Throwable("internal error in pair async"))
                    }
                },
                { throwable ->
                    res.failure(throwable)
                })
        firstPaired.pair(secondPaired, proxy)
        secondPaired.pair(firstPaired, proxy)
        return res
    }

    private class PairedAsync(private val myAsync: Async) {

        internal var myItem: ItemT? = null
        internal var mySucceeded: Boolean = false
        private var myReg: Registration? = null

        internal fun  pair(anotherInfo: PairedAsync, async: SimpleAsync) {
            if (async.hasSucceeded() || async.hasFailed()) {
                return
            }
            myReg = myAsync.onResult(
                    { item ->
                        myItem = item
                        mySucceeded = true
                        if (anotherInfo.mySucceeded) {
                            async.success(Unit)
                        }
                    },
                    { failure ->
                        //reg == null can happen in case if myAsync fails instantly
                        if (anotherInfo.myReg != null) {
                            anotherInfo.myReg!!.remove()
                        }
                        async.failure(failure)
                    })
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy