///|
type Promise[T]
///|
pub impl[T : IsAny] IsAny for Promise[T]
///|
pub impl[T : IsValue] IsValue for Promise[T]
///|
pub fn[A] Promise::resolve(x : A) -> Self[A] {
Promise::new(x)
}
///|
pub fn[A] Promise::reject(error : Error) -> Self[A] {
ffi_promise_reject(identity(error)) |> identity
}
///|
pub fn[A, B] Promise::then(
x : Self[A],
resolve : (A) -> Self[B] raise,
reject? : (Error) -> Self[B],
) -> Self[B] {
x.bind(resolve, reject?)
}
///|
pub fn[A, B] Promise::catch_(x : Self[A], f : (Error) -> Self[B]) -> Self[B] {
ffi_promise_catch(identity(x), identity(f)) |> identity
}
///|
#callsite(autofill(loc))
pub fn[A] Promise::new(x : A, loc~ : SourceLoc) -> Self[A] {
(if ffi_is_promise(identity(x)) {
ffi_promise_reject(InvalidNestedPromise(loc))
} else {
ffi_promise_resolve(identity(x))
})
|> identity
}
///|
#callsite(autofill(loc))
pub fn[A, B] Promise::map(
x : Self[A],
resolve : (A) -> B raise,
loc~ : SourceLoc,
) -> Self[B] {
let x = identity(x)
fn f(a) {
try resolve(identity(a)) catch {
e => ffi_promise_reject(e)
} noraise {
b if ffi_is_promise(identity(b)) =>
identity(ffi_promise_reject(InvalidNestedPromise(loc)))
b => identity(b)
}
}
let reject : (Any) -> Any = identity((undefined() : Optional[Unit]))
ffi_promise_then(x, f, reject) |> identity
}
///|
pub fn[A, B] Promise::bind(
x : Self[A],
resolve : (A) -> Self[B] raise,
reject? : (Error) -> Self[B],
) -> Self[B] {
ffi_promise_then(
identity(x),
fn(a) {
identity(resolve(identity(a))) catch {
e => identity(ffi_promise_reject(e))
}
},
identity(reject),
)
|> identity
}
///|
pub async fn[A] Promise::wait(x : Self[A]) -> A {
suspend(fn(ok, err) {
ffi_promise_then(identity(x), identity(ok), identity(err))
})
}
///|
pub fn try_launch(f : async () -> Unit) -> Unit noraise {
run(() => f() catch { e => println(e.to_string()) })
}
///|
pub fn launch(f : async () -> Unit noraise) -> Unit noraise {
run(f)
}
///|
fn run(f : async () -> Unit noraise) -> Unit noraise = "%async.run"
///|
async fn[T, E : Error] suspend(
f : ((T) -> Unit, (E) -> Unit) -> Unit,
) -> T raise E = "%async.suspend"
///|
extern "js" fn ffi_promise_resolve(x : Any) -> Any = "(x) => Promise.resolve(x)"
///|
extern "js" fn ffi_promise_reject(e : Error) -> Any = "(x) => Promise.reject(x)"
///|
extern "js" fn ffi_promise_then(x : Any, ok : (Any) -> Any, err : (Any) -> Any) = "(x,f,g) => x.then(f,g)"
///|
extern "js" fn ffi_promise_catch(x : Any, err : (Error) -> Any) = "(x,f) => x.catch(f)"
///|
extern "js" fn ffi_is_promise(x : Any) -> Bool = "(a) => MoonBit.Promise.is_promise(a)"
///|
// extern "js" fn ffi_promise_handle_thrown_error(
// promise : Any,
// j2m : (String, Any, Any) -> Any raise,
// ) -> Any raise = "(a,b) => MoonBit.Promise.handle_thrown(a,b)"
///|
// extern "js" fn ffi_not_promise_or_throw(promise : Any, loc~ : SourceLoc) -> Any = "(a,b) => MoonBit.Promise.not_promise_or_throw(a,b)"