1use core::fmt;
4
5use crate::{
6 __rt::marker::ErasableGeneric, JsCast, JsError, JsGeneric, JsValue, convert::UpcastFrom,
7};
8use wry_bindgen_macro::wasm_bindgen;
9
10pub trait Promising {
12 type Resolution;
13}
14
15#[wasm_bindgen(wasm_bindgen = crate)]
16extern "C" {
17 #[wasm_bindgen(is_type_of = JsValue::is_undefined, typescript_type = "undefined", no_upcast)]
22 #[derive(Clone, PartialEq)]
23 pub type Undefined;
24}
25
26impl Undefined {
27 pub const UNDEFINED: Undefined = Self {
29 obj: JsValue::UNDEFINED,
30 };
31}
32
33impl Eq for Undefined {}
34
35impl Default for Undefined {
36 fn default() -> Self {
37 Self::UNDEFINED
38 }
39}
40
41impl fmt::Debug for Undefined {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 f.write_str("undefined")
44 }
45}
46
47impl fmt::Display for Undefined {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 f.write_str("undefined")
50 }
51}
52
53#[wasm_bindgen(wasm_bindgen = crate)]
54extern "C" {
55 #[wasm_bindgen(is_type_of = JsValue::is_null, typescript_type = "null", no_upcast)]
60 #[derive(Clone, PartialEq)]
61 pub type Null;
62}
63
64impl Null {
65 pub const NULL: Null = Self { obj: JsValue::NULL };
67}
68
69impl Eq for Null {}
70
71impl Default for Null {
72 fn default() -> Self {
73 Self::NULL
74 }
75}
76
77impl fmt::Debug for Null {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 f.write_str("null")
80 }
81}
82
83impl fmt::Display for Null {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 f.write_str("null")
86 }
87}
88
89impl UpcastFrom<Undefined> for Undefined {}
90impl UpcastFrom<()> for Undefined {}
91impl UpcastFrom<Undefined> for () {}
92impl UpcastFrom<Undefined> for JsValue {}
93impl UpcastFrom<Null> for Null {}
94impl UpcastFrom<Null> for JsValue {}
95impl UpcastFrom<()> for JsValue {}
96impl UpcastFrom<()> for () {}
97
98#[wasm_bindgen(wasm_bindgen = crate)]
99extern "C" {
100 #[wasm_bindgen(typescript_type = "any", no_upcast)]
113 #[derive(Clone, PartialEq)]
114 pub type JsOption<T = JsValue>;
115}
116
117impl<T: JsGeneric> JsOption<T> {
118 #[inline]
119 pub fn new() -> Self {
120 Undefined::UNDEFINED.unchecked_into()
121 }
122
123 #[inline]
124 pub fn wrap(val: T) -> Self {
125 val.unchecked_into()
126 }
127
128 #[inline]
129 pub fn from_option(opt: Option<T>) -> Self {
130 match opt {
131 Some(value) => Self::wrap(value),
132 None => Self::new(),
133 }
134 }
135
136 #[inline]
137 pub fn is_empty(&self) -> bool {
138 AsRef::<JsValue>::as_ref(self).is_null_or_undefined()
139 }
140
141 #[inline]
142 pub fn as_option(&self) -> Option<T> {
143 if self.is_empty() {
144 None
145 } else {
146 Some(T::unchecked_from_js(AsRef::<JsValue>::as_ref(self).clone()))
147 }
148 }
149
150 #[inline]
151 pub fn into_option(self) -> Option<T> {
152 if self.is_empty() {
153 None
154 } else {
155 Some(self.unchecked_into())
156 }
157 }
158
159 #[inline]
160 pub fn unwrap(self) -> T {
161 self.expect("called `JsOption::unwrap()` on an empty value")
162 }
163
164 #[inline]
165 pub fn expect(self, msg: &str) -> T {
166 match self.into_option() {
167 Some(value) => value,
168 None => panic!("{}", msg),
169 }
170 }
171
172 #[inline]
173 pub fn unwrap_or_default(self) -> T
174 where
175 T: Default,
176 {
177 self.into_option().unwrap_or_default()
178 }
179
180 #[inline]
181 pub fn unwrap_or_else<F>(self, f: F) -> T
182 where
183 F: FnOnce() -> T,
184 {
185 self.into_option().unwrap_or_else(f)
186 }
187}
188
189impl<T: JsGeneric> Default for JsOption<T> {
190 fn default() -> Self {
191 Self::new()
192 }
193}
194
195impl<T: JsGeneric + fmt::Debug> fmt::Debug for JsOption<T> {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 write!(f, "{}?(", core::any::type_name::<T>())?;
198 match self.as_option() {
199 Some(value) => write!(f, "{value:?}")?,
200 None => f.write_str("null")?,
201 }
202 f.write_str(")")
203 }
204}
205
206impl<T: JsGeneric + fmt::Display> fmt::Display for JsOption<T> {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 write!(f, "{}?(", core::any::type_name::<T>())?;
209 match self.as_option() {
210 Some(value) => write!(f, "{value}")?,
211 None => f.write_str("null")?,
212 }
213 f.write_str(")")
214 }
215}
216
217impl UpcastFrom<JsValue> for JsOption<JsValue> {}
218impl<T> UpcastFrom<Undefined> for JsOption<T> {}
219impl<T> UpcastFrom<Null> for JsOption<T> {}
220impl<T> UpcastFrom<()> for JsOption<T> {}
221impl<T> UpcastFrom<JsOption<T>> for JsValue {}
222impl<T, U> UpcastFrom<JsOption<U>> for JsOption<T> where T: UpcastFrom<U> {}
223
224impl Promising for JsValue {
225 type Resolution = JsValue;
226}
227
228impl Promising for () {
229 type Resolution = Undefined;
230}
231
232macro_rules! promising_self {
233 ($($ty:ty),* $(,)?) => {
234 $(
235 impl Promising for $ty {
236 type Resolution = $ty;
237 }
238 )*
239 };
240 }
241
242promising_self!(
243 bool, char, f32, f64, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, JsError
244);
245
246impl Promising for alloc::string::String {
247 type Resolution = alloc::string::String;
248}
249
250impl<T: Promising> Promising for alloc::vec::Vec<T> {
251 type Resolution = alloc::vec::Vec<T::Resolution>;
252}
253
254impl<T: Promising> Promising for Option<T> {
255 type Resolution = Option<T::Resolution>;
256}
257
258impl<T: ErasableGeneric + Promising, E: ErasableGeneric> Promising for Result<T, E> {
259 type Resolution = Result<T::Resolution, E>;
260}