quickjs_rusty/value/
promise.rs1use std::ops::Deref;
2
3use libquickjs_ng_sys as q;
4
5use crate::utils::ensure_no_excpetion;
6use crate::{Context, ExecutionError, JsFunction, ValueError};
7
8use super::OwnedJsValue;
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct OwnedJsPromise {
12 value: OwnedJsValue,
13}
14
15impl OwnedJsPromise {
16 pub fn try_from_value(value: OwnedJsValue) -> Result<Self, ValueError> {
17 if !value.is_promise() {
18 Err(ValueError::Internal("Expected an promise".into()))
19 } else {
20 Ok(Self { value })
21 }
22 }
23
24 pub fn into_value(self) -> OwnedJsValue {
25 self.value
26 }
27
28 pub fn state(&self) -> PromiseState {
29 let state = unsafe { q::JS_PromiseState(self.value.context(), self.value.value) };
30 match state {
31 q::JSPromiseStateEnum_JS_PROMISE_PENDING => PromiseState::Pending,
32 q::JSPromiseStateEnum_JS_PROMISE_FULFILLED => PromiseState::Fulfilled,
33 q::JSPromiseStateEnum_JS_PROMISE_REJECTED => PromiseState::Rejected,
34 _ => unreachable!(),
35 }
36 }
37
38 pub fn result(&self) -> OwnedJsValue {
41 let result = unsafe { q::JS_PromiseResult(self.value.context(), self.value.value) };
42 OwnedJsValue::new(self.value.context(), result)
43 }
44
45 pub fn then(&self, on_fulfilled: &OwnedJsValue) -> Result<OwnedJsPromise, ExecutionError> {
46 let new_promise = unsafe {
47 q::JS_Ext_PromiseThen(self.value.context(), self.value.value, on_fulfilled.value)
48 };
49
50 let new_promise = OwnedJsValue::new(self.value.context(), new_promise);
51
52 ensure_no_excpetion(self.value.context())?;
53
54 Ok(OwnedJsPromise::try_from_value(new_promise)?)
55 }
56
57 pub fn then2(
58 &self,
59 on_fulfilled: &OwnedJsValue,
60 on_rejected: &OwnedJsValue,
61 ) -> Result<OwnedJsPromise, ExecutionError> {
62 let new_promise = unsafe {
63 q::JS_Ext_PromiseThen2(
64 self.value.context(),
65 self.value.value,
66 on_fulfilled.value,
67 on_rejected.value,
68 )
69 };
70
71 let new_promise = OwnedJsValue::new(self.value.context(), new_promise);
72
73 ensure_no_excpetion(self.value.context())?;
74
75 Ok(OwnedJsPromise::try_from_value(new_promise)?)
76 }
77
78 pub fn catch(&self, on_rejected: &OwnedJsValue) -> Result<OwnedJsPromise, ExecutionError> {
79 let new_promise = unsafe {
80 q::JS_Ext_PromiseCatch(self.value.context(), self.value.value, on_rejected.value)
81 };
82
83 let new_promise = OwnedJsValue::new(self.value.context(), new_promise);
84
85 ensure_no_excpetion(self.value.context())?;
86
87 Ok(OwnedJsPromise::try_from_value(new_promise)?)
88 }
89
90 pub fn finally(&self, on_finally: &OwnedJsValue) -> Result<OwnedJsPromise, ExecutionError> {
91 let new_promise = unsafe {
92 q::JS_Ext_PromiseFinally(self.value.context(), self.value.value, on_finally.value)
93 };
94
95 let new_promise = OwnedJsValue::new(self.value.context(), new_promise);
96
97 ensure_no_excpetion(self.value.context())?;
98
99 Ok(OwnedJsPromise::try_from_value(new_promise)?)
100 }
101
102 pub fn resolve(
103 context: &Context,
104 value: &OwnedJsValue,
105 ) -> Result<OwnedJsPromise, ExecutionError> {
106 let promise = unsafe { q::JS_Ext_PromiseResolve(context.context, value.value) };
107 let promise = OwnedJsValue::new(context.context, promise);
108
109 ensure_no_excpetion(context.context)?;
110
111 Ok(OwnedJsPromise::try_from_value(promise)?)
112 }
113
114 pub fn reject(
115 context: &Context,
116 value: &OwnedJsValue,
117 ) -> Result<OwnedJsPromise, ExecutionError> {
118 let promise = unsafe { q::JS_Ext_PromiseReject(context.context, value.value) };
119 let promise = OwnedJsValue::new(context.context, promise);
120
121 ensure_no_excpetion(context.context)?;
122
123 Ok(OwnedJsPromise::try_from_value(promise)?)
124 }
125
126 pub fn all(
127 context: &Context,
128 values: impl IntoIterator<Item = OwnedJsPromise>,
129 ) -> Result<OwnedJsPromise, ExecutionError> {
130 let iterable: OwnedJsValue =
131 (context.context, values.into_iter().collect::<Vec<_>>()).into();
132
133 let promise = unsafe { q::JS_Ext_PromiseAll(context.context, iterable.value) };
134 let promise = OwnedJsValue::new(context.context, promise);
135
136 ensure_no_excpetion(context.context)?;
137
138 Ok(OwnedJsPromise::try_from_value(promise)?)
139 }
140
141 pub fn all_settled(
142 context: &Context,
143 values: impl IntoIterator<Item = OwnedJsPromise>,
144 ) -> Result<OwnedJsPromise, ExecutionError> {
145 let iterable: OwnedJsValue =
146 (context.context, values.into_iter().collect::<Vec<_>>()).into();
147
148 let promise = unsafe { q::JS_Ext_PromiseAllSettled(context.context, iterable.value) };
149 let promise = OwnedJsValue::new(context.context, promise);
150
151 ensure_no_excpetion(context.context)?;
152
153 Ok(OwnedJsPromise::try_from_value(promise)?)
154 }
155
156 pub fn race(
157 context: &Context,
158 values: impl IntoIterator<Item = OwnedJsPromise>,
159 ) -> Result<OwnedJsPromise, ExecutionError> {
160 let iterable: OwnedJsValue =
161 (context.context, values.into_iter().collect::<Vec<_>>()).into();
162
163 let promise = unsafe { q::JS_Ext_PromiseRace(context.context, iterable.value) };
164 let promise = OwnedJsValue::new(context.context, promise);
165
166 ensure_no_excpetion(context.context)?;
167
168 Ok(OwnedJsPromise::try_from_value(promise)?)
169 }
170
171 pub fn any(
172 context: &Context,
173 values: impl IntoIterator<Item = OwnedJsPromise>,
174 ) -> Result<OwnedJsPromise, ExecutionError> {
175 let iterable: OwnedJsValue =
176 (context.context, values.into_iter().collect::<Vec<_>>()).into();
177
178 let promise = unsafe { q::JS_Ext_PromiseAny(context.context, iterable.value) };
179 let promise = OwnedJsValue::new(context.context, promise);
180
181 ensure_no_excpetion(context.context)?;
182
183 Ok(OwnedJsPromise::try_from_value(promise)?)
184 }
185
186 pub fn with_resolvers(
187 context: &Context,
188 ) -> Result<(OwnedJsPromise, JsFunction, JsFunction), ExecutionError> {
189 let obj = unsafe { q::JS_Ext_PromiseWithResolvers(context.context) };
190 let obj = OwnedJsValue::new(context.context, obj);
191
192 ensure_no_excpetion(context.context)?;
193
194 let obj = obj.try_into_object()?;
195
196 let promise = obj.property("promise")?.unwrap().try_into_promise()?;
198 let resolve = obj.property("resolve")?.unwrap().try_into_function()?;
199 let reject = obj.property("reject")?.unwrap().try_into_function()?;
200
201 Ok((promise, resolve, reject))
202 }
203}
204
205impl Deref for OwnedJsPromise {
206 type Target = OwnedJsValue;
207
208 fn deref(&self) -> &Self::Target {
209 &self.value
210 }
211}
212
213#[derive(Debug, Clone, Copy)]
214pub enum PromiseState {
215 Pending,
216 Fulfilled,
217 Rejected,
218}