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

com.jtransc.async.promise.kt Maven / Gradle / Ivy

package com.jtransc.async

import java.util.*

class Promise(var parent: Promise<*>?) {
	private var resolved: Boolean = false
	private var resolvedValue: T? = null
	private var resolvedException: Throwable? = null
	private val callbacks = LinkedList<(T) -> Any>()
	private val failcallbacks = LinkedList<(Throwable) -> Any>()


	private constructor(parent: Promise<*>?, value: Throwable) : this(null) {
		resolved = true
		resolvedException = value
	}

	class Deferred {
		val promise: Promise = Promise(null)

		fun resolve(value: T) {
			this.promise.resolve(value)
		}

		fun progress(value: Double) {
			this.promise.progress(value)
		}

		fun reject(value: Throwable) {
			this.promise.reject(value);
		}
	}

	companion object {
		fun  invoke(callback: (resolve: (value: T) -> Unit, reject: (error: Throwable) -> Unit) -> Unit): Promise {
			val deferred = Deferred()
			callback({ deferred.resolve(it) }, { deferred.reject(it) })
			return deferred.promise
		}

		fun  create(callback: (resolve: (value: T) -> Unit, reject: (error: Throwable) -> Unit) -> Unit): Promise {
			val deferred = Deferred()
			callback({ deferred.resolve(it) }, { deferred.reject(it) })
			return deferred.promise
		}

		fun  sequence(vararg promises: () -> Promise): Promise> {
			return sequence(promises.toList())
		}

		fun  sequence(promises: Iterable<() -> Promise>): Promise> {
			val items = promises.toCollection(LinkedList())
			if (items.size == 0) return Promise.resolved(listOf())
			val out = ArrayList(items.size)
			val deferred = Deferred>()
			fun step() {
				if (items.isEmpty()) {
					deferred.resolve(out)
				} else {
					val promiseGenerator = items.removeFirst()
					val promise = promiseGenerator()
					promise.then {
						out.add(it)
						step()
					}.fail {
						deferred.reject(it)
					}
				}
			}
			EventLoop.queue { step() }
			return deferred.promise
		}

		fun chain(): Promise = resolved(Unit)

		@Deprecated("Use resolved", ReplaceWith("this.resolved(Unit)"))
		fun resolve() = Promise.resolved(Unit)

		fun  resolved(value: T): Promise {
			val deferred = Deferred()
			deferred.resolve(value)
			return deferred.promise
		}

		fun  rejected(value: Throwable): Promise {
			return Promise(null, value);
		}

		fun  all(vararg promises: Promise): Promise> {
			return all(promises.toList())
		}

		fun  all(promises: Iterable>): Promise> {
			val promiseList = promises.toList()
			var count = 0
			val total = promiseList.size

			val out = arrayListOf()
			val deferred = Deferred>()
			for (n in 0..total - 1) out.add(null)

			fun checkDone() {
				if (count >= total) {
					deferred.resolve(out.map { it!! })
				}
			}

			promiseList.indices.forEach {
				val index = it
				val promise = promiseList[index]
				promise.then {
					out[index] = it
					count++
					checkDone()
				}
			}

			checkDone()

			return deferred.promise
		}

		/*
		fun create(callback: (resolve: (value:T) -> Unit, reject:(exception:Throwable) -> Unit) -> Unit):Promise {
			val deferred = Deferred()
			return deferred.promise
		}
		*/
		fun  forever(): Promise {
			return Deferred().promise
		}

		fun  any(vararg promises: Promise): Promise {
			val deferred = Promise.Deferred()
			for (promise in promises) {
				promise.then { deferred.resolve(it) }.fail { deferred.reject(it) }
			}
			return deferred.promise
		}
	}

	internal fun resolve(value: T) {
		if (resolved) return;
		resolved = true
		resolvedValue = value
		parent = null
		flush();
	}

	internal fun reject(value: Throwable) {
		if (resolved) return;
		resolved = true
		resolvedException = value
		parent = null

		// @TODO: Check why this fails!
		if (failcallbacks.isEmpty() && callbacks.isEmpty()) {
			println("Promise.reject(): Not capturated: $value")
			throw value
		}

		flush();
	}

	internal fun progress(value: Double) {

	}

	private fun flush() {
		if (!resolved || (callbacks.isEmpty() && failcallbacks.isEmpty())) return

		val resolvedValue = this.resolvedValue
		if (resolvedValue != null) {
			while (callbacks.isNotEmpty()) {
				val callback = callbacks.removeAt(0);
				EventLoop.queue({
					callback(resolvedValue)
				})
			}
		} else if (resolvedException != null) {
			while (failcallbacks.isNotEmpty()) {
				val failcallback = failcallbacks.removeAt(0);
				EventLoop.queue({
					failcallback(resolvedException!!)
				})
			}
		}
	}

	fun cancel() {
		parent?.cancel()
		parent = null
		cancelledHandlers.dispatch()
	}

	private var cancelledHandlers = Signal()

	fun cancelled(handler: () -> Unit): Promise {
		cancelledHandlers.once { handler() }
		return this;
	}

	fun  pipe(callback: (value: T) -> Promise): Promise {
		try {
			val out = Promise(this)
			this.failcallbacks.add {
				out.reject(it)
			}
			this.callbacks.add({
				callback(it)
					.then { out.resolve(it) }
					.fail { out.fail { it } }
			})
			return out
		} finally {
			flush()
		}
	}

	fun  then(callback: (value: T) -> T2): Promise {
		try {
			val out = Promise(this)
			this.failcallbacks.add {
				out.reject(it)
			}
			this.callbacks.add {
				try {
					out.resolve(callback(it))
				} catch (t: Throwable) {
					println("then catch:$t")
					t.printStackTrace()
					out.reject(t)
				}
			}
			return out
		} finally {
			flush()
		}
	}

	fun  fail(failcallback: (throwable: Throwable) -> T2): Promise {
		try {
			val out = Promise(this)
			this.failcallbacks.add {
				try {
					out.resolve(failcallback(it))
				} catch (t: Throwable) {
					println("fail catch:$t")
					t.printStackTrace()
					out.reject(t)
				}
			}
			return out
		} finally {
			flush()
		}
	}

	fun timeout(time: Int): Promise {
		return Promise.create { resolve, reject ->
			//EventLoop.setTimeout(time) { reject(TimeoutException()) }

			this.then { resolve(it) }.fail { reject(it) }
		}
	}

	fun always(callback: () -> Unit): Promise {
		then { callback() }.fail { callback() }
		return this
	}
}

val  Promise.unit: Promise get() = then { Unit }

fun  Promise.syncWait(maxMs:Int = Integer.MAX_VALUE): T {
	var completed = false
	var value: T? = null
	var exception: Throwable? = null
	this.then {
		value = it
		completed = true
	}.fail {
		exception = it
		completed = true
	}
	val start = System.currentTimeMillis()
	while (!completed) {
		val current = System.currentTimeMillis()
		val elapsed = current - start
		if (elapsed >= maxMs) throw RuntimeException("Waiting too much!")
		EventLoop.executeStep()
		Thread.sleep(1)
	}
	if (exception != null) throw exception!!
	return value!!
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy