// ///|
// /// JavaScript Promise[T]
// /// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise
// #external
// pub type Promise[T]
// ///|
// pub fn[T] Promise::to_any(self : Promise[T]) -> @core.Any = "%identity"
// ///|
// /// JS: new Promise((resolve, reject) => { ... })
// /// Create a Promise from an async executor function with resolve/reject callbacks.
// /// ```moonbit no-check
// /// let p : Promise[Int] = Promise::new(async fn(resolve, _reject) {
// /// let result = some_async_operation()
// /// resolve(result)
// /// })
// /// ```
// pub fn[A] Promise::new(
// f : async ((A) -> Unit, (Error) -> Unit) -> Unit,
// ) -> Promise[A] {
// ffi_new_promise(fn(resolve, reject) {
// @core.run_async(fn() {
// f(a => a |> identity |> resolve, e => e |> identity |> reject) catch {
// e => e |> identity |> reject
// }
// })
// })
// |> identity
// }
// ///|
// /// Convert an async function to a Promise.
// /// ```moonbit no-check
// /// let p : Promise[Int] = Promise::from_async(async fn() {
// /// let result = some_async_operation()
// /// result
// /// })
// /// ```
// pub fn[A] Promise::from_async(f : async () -> A) -> Promise[A] noraise {
// let { promise, resolve, reject } = Promise::withResolvers()
// @core.run_async(fn() {
// try f() |> resolve catch {
// e => reject(e)
// }
// })
// promise
// }
// ///|
// /// js: Promise.resolve(value)
// /// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
// pub fn[A] Promise::resolve(x : A) -> Self[A] {
// ffi_promise_resolve(identity(x)) |> identity
// }
// ///|
// /// js: Promise.reject(error)
// /// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
// pub fn Promise::reject(x : @core.Any) -> Self[@core.Any] {
// ffi_promise_reject(identity(x)) |> identity
// }
// ///|
// pub fn[A, B] Promise::then(
// self : Self[A],
// resolve : (A) -> Self[B] raise,
// ) -> Promise[B] {
// ffi_promise_then(self.to_any() |> identity, a => (a
// |> identity
// |> resolve
// |> identity) catch {
// e => e |> identity |> ffi_promise_reject |> identity
// })
// |> identity
// }
// ///|
// pub fn[A, B] Promise::catch_(
// self : Self[A],
// f : (Error) -> Promise[B],
// ) -> Promise[B] {
// self.to_any()._call("catch", [@core.any(from_fn1(f))]).cast()
// }
// ///|
// /// JS: promise.finally(() => { ... })
// pub fn[A] Promise::finally_(self : Self[A], f : () -> Unit) -> Self[A] {
// self.to_any()._call("finally", [@core.any(from_fn0(f))]).cast()
// }
// ///|
// /// JS: await promise
// /// Waits for the Promise to be resolved or rejected.
// pub async fn[T] Promise::wait(self : Self[T]) -> T {
// @core.suspend((ok, err) => self
// .to_any()
// ._call("then", [@core.any(from_fn1(ok))])
// ._call("catch", [@core.any(from_fn1(err))])
// |> ignore)
// }
// ///|
// /// JS: Promise.all(promises)
// /// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
// /// ```moonbit no-check
// /// let results = Promise::all([
// /// Promise::from_async(async fn() { fetch_user() }),
// /// Promise::from_async(async fn() { fetch_posts() }),
// /// ]).wait()
// /// ```
// pub fn[A] Promise::all(promises : Array[Promise[A]]) -> Promise[Array[A]] {
// ffi_promise_all(promises |> identity) |> identity
// }
// ///|
// /// JS: Promise.race(promises)
// /// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
// /// ```moonbit no-check
// /// let first = Promise::race([
// /// Promise::from_async(async fn() {
// /// sleep(100)
// /// "slow"
// /// }),
// /// Promise::from_async(async fn() {
// /// sleep(10)
// /// "fast"
// /// }),
// /// ]).wait() // "fast"
// /// ```
// pub fn[T] Promise::race(promises : Array[Promise[T]]) -> Promise[T] {
// ffi_promise_race(promises |> identity) |> identity
// }
// ///|
// /// JS: Promise.any(promises)
// /// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/any
// /// ```moonbit no-check
// /// let first_success = Promise::any([
// /// Promise::from_async(async fn() { fetch_from_mirror1() }),
// /// Promise::from_async(async fn() { fetch_from_mirror2() }),
// /// ]).wait()
// /// ```
// pub fn[T] Promise::any(promises : Array[Promise[T]]) -> Promise[T] {
// ffi_promise_any(promises |> identity) |> identity
// }
// ///|
// /// Result type for Promise.allSettled
// pub(all) struct SettledResult[T] {
// status : String // "fulfilled" | "rejected"
// value : T?
// reason : Nullable[@core.Any]
// }
// ///|
// pub fn[T] SettledResult::to_any(self : SettledResult[T]) -> @core.Any = "%identity"
// ///|
// /// JS: Promise.allSettled(promises)
// /// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
// /// ```moonbit no-check
// /// let results = Promise::allSettled([
// /// Promise::from_async(async fn() { 1 }),
// /// Promise::from_async(async fn() { fail("error") }),
// /// ]).wait()
// /// // results[0].status == "fulfilled", results[0].value == Some(1)
// /// // results[1].status == "rejected", results[1].reason != null
// /// ```
// pub fn[A] Promise::allSettled(
// promises : Array[Promise[A]],
// ) -> Promise[Array[SettledResult[A]]] {
// ffi_promise_all(promises |> identity) |> identity
// }
///|
/// JS: Promise.withResolvers()
/// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/withPromiseResolvers
pub(all) struct PromiseResolvers[T] {
promise : Promise[T]
resolve : (T) -> Unit
reject : (Error) -> Unit
}
///|
/// JS: Promise.withResolvers()
/// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/withPromiseResolvers
// pub fn[T] Promise::withResolvers() -> PromiseResolvers[T] {
// ffi_promise_with_resolvers() |> identity
// }
///|
/// JS: resolvers.resolve(value)
pub fn[T] PromiseResolvers::resolve(self : Self[T], value : T) -> Unit {
(self.resolve)(value)
}
///|
/// JS: resolvers.reject(error)
pub fn[T] PromiseResolvers::reject(self : Self[T], error : Error) -> Unit {
(self.reject)(error)
}
///|
pub fn[R] promisify0(f : async () -> R) -> () -> Promise[R] noraise {
() => {
let { promise, resolve, reject } = Promise::withResolvers()
@core.run_async(async fn() noraise {
try f() |> resolve catch {
e => reject(e)
}
})
promise
}
}
///|
/// Moonbit Async Function to JS Promise Function
pub fn[A, R] promisify1(f : async (A) -> R) -> (A) -> Promise[R] noraise {
a => {
let { promise, resolve, reject } = Promise::withResolvers()
@core.run_async(async fn() noraise {
try f(a) |> resolve catch {
e => reject(e)
}
})
promise
}
}
///|
/// Moonbit Async Function to JS Promise Function
pub fn[A, B, R] promisify2(
f : async (A, B) -> R,
) -> (A, B) -> Promise[R] noraise {
(a, b) => {
let { promise, resolve, reject } = Promise::withResolvers()
@core.run_async(async fn() noraise {
try f(a, b) |> resolve catch {
e => reject(e)
}
})
promise
}
}
///|
/// Moonbit Async Function to JS Promise Function
pub fn[A, B, C, R] promisify3(
f : async (A, B, C) -> R,
) -> (A, B, C) -> Promise[R] noraise {
(a, b, c) => {
let { promise, resolve, reject } = Promise::withResolvers()
@core.run_async(async fn() noraise {
try f(a, b, c) |> resolve catch {
e => reject(e)
}
})
promise
}
}
// ///|
// /// Sleep for given milliseconds
// extern "js" fn ffi_sleep(ms : Int) -> Promise[Unit] =
// #| (ms) => new Promise((resolve) => setTimeout(resolve, ms))
// ///|
// pub async fn sleep(ms : Int) -> Unit noraise {
// ffi_sleep(ms).wait() catch {
// _ => panic()
// }
// }
// ///|
// /// Async dispose (Symbol.asyncDispose)
// /// Usage: defer value |> dispose_async
// pub async fn dispose_async(value : @core.Any) -> Unit {
// let dispose_fn : @core.Any = value._get(
// @symbol.Symbol::asyncDispose() |> identity,
// )
// let promise : Promise[Unit] = @core.Any::_invoke(dispose_fn, []) |> identity
// promise.wait()
// }