1use {
2 crate::{error::Error, ext},
3 js_sys::{ArrayBuffer, JsString, Uint8Array},
4 std::{
5 pin::Pin,
6 task::{Context, Poll},
7 },
8 wasm_bindgen::prelude::*,
9 wasm_bindgen_futures::JsFuture,
10};
11
12pub(crate) mod api {
13 use super::*;
14
15 #[inline]
36 pub fn invoke<C>(cmd: C) -> Invoke<C::Js>
37 where
38 C: ToStringValue,
39 {
40 let cmd = cmd.to_string_value();
41 let args = JsValue::UNDEFINED;
42 let opts = Options::empty();
43 Invoke { cmd, args, opts }
44 }
45}
46
47pub struct Invoke<C, A = JsValue> {
48 cmd: C,
49 args: A,
50 opts: Options,
51}
52
53impl<C, A> Invoke<C, A> {
54 #[cfg_attr(feature = "serde", doc = "```")]
64 #[cfg_attr(not(feature = "serde"), doc = "```ignore")]
65 #[inline]
86 pub fn with_args<T>(self, args: T) -> Invoke<C, T::JsValue>
87 where
88 T: ToArgs,
89 {
90 let cmd = self.cmd;
91 let args = args.to_args();
92 let opts = self.opts;
93 Invoke { cmd, args, opts }
94 }
95
96 #[cfg_attr(feature = "serde", doc = "```")]
103 #[cfg_attr(not(feature = "serde"), doc = "```ignore")]
104 #[inline]
118 pub fn with_options(self, opts: Options) -> Self {
119 Self { opts, ..self }
120 }
121}
122
123pub struct InvokeFuture(JsFuture);
124
125impl InvokeFuture {
126 #[inline]
127 pub fn into_future(self) -> JsFuture {
128 self.0
129 }
130}
131
132impl Future for InvokeFuture {
133 type Output = Result<JsValue, Error>;
134
135 #[inline]
136 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
137 let me = self.get_mut();
138 Pin::new(&mut me.0).poll(cx).map_err(Error)
139 }
140}
141
142impl<C, A> IntoFuture for Invoke<C, A>
143where
144 C: AsRef<JsValue>,
145 A: AsRef<JsValue>,
146{
147 type Output = Result<JsValue, Error>;
148 type IntoFuture = InvokeFuture;
149
150 #[inline]
151 fn into_future(self) -> Self::IntoFuture {
152 let promise = ext::invoke(self.cmd.as_ref(), self.args.as_ref(), self.opts);
153 InvokeFuture(JsFuture::from(promise))
154 }
155}
156
157pub trait ToStringValue {
158 type Js: AsRef<JsValue>;
159 fn to_string_value(self) -> Self::Js;
160}
161
162impl ToStringValue for JsString {
163 type Js = JsValue;
164
165 #[inline]
166 fn to_string_value(self) -> Self::Js {
167 JsValue::from(self)
168 }
169}
170
171impl<'str> ToStringValue for &'str JsString {
172 type Js = &'str JsValue;
173
174 #[inline]
175 fn to_string_value(self) -> Self::Js {
176 self
177 }
178}
179
180impl ToStringValue for String {
181 type Js = JsValue;
182
183 #[inline]
184 fn to_string_value(self) -> Self::Js {
185 (&self).to_string_value()
186 }
187}
188
189impl ToStringValue for &String {
190 type Js = JsValue;
191
192 #[inline]
193 fn to_string_value(self) -> Self::Js {
194 JsValue::from(self)
195 }
196}
197
198impl ToStringValue for &str {
199 type Js = JsValue;
200
201 #[inline]
202 fn to_string_value(self) -> Self::Js {
203 JsValue::from(self)
204 }
205}
206
207pub trait ToArgs {
208 type JsValue: AsRef<JsValue>;
209 fn to_args(self) -> Self::JsValue;
210}
211
212impl ToArgs for ArrayBuffer {
213 type JsValue = JsValue;
214
215 #[inline]
216 fn to_args(self) -> Self::JsValue {
217 JsValue::from(self)
218 }
219}
220
221impl<'arr> ToArgs for &'arr ArrayBuffer {
222 type JsValue = &'arr JsValue;
223
224 #[inline]
225 fn to_args(self) -> Self::JsValue {
226 self
227 }
228}
229
230impl ToArgs for Uint8Array {
231 type JsValue = JsValue;
232
233 #[inline]
234 fn to_args(self) -> Self::JsValue {
235 JsValue::from(self)
236 }
237}
238
239impl<'arr> ToArgs for &'arr Uint8Array {
240 type JsValue = &'arr JsValue;
241
242 #[inline]
243 fn to_args(self) -> Self::JsValue {
244 self
245 }
246}
247
248impl ToArgs for &[u8] {
249 type JsValue = JsValue;
250
251 #[inline]
252 fn to_args(self) -> Self::JsValue {
253 Uint8Array::from(self).to_args()
254 }
255}
256
257impl<const N: usize> ToArgs for &[u8; N] {
258 type JsValue = JsValue;
259
260 #[inline]
261 fn to_args(self) -> Self::JsValue {
262 self.as_slice().to_args()
263 }
264}
265
266#[wasm_bindgen]
267pub struct Options {
268 pub(crate) headers: JsValue,
269}
270
271impl Options {
272 pub(crate) const fn empty() -> Self {
273 let headers = JsValue::UNDEFINED;
274 Self { headers }
275 }
276}
277
278#[wasm_bindgen]
279impl Options {
280 #[inline]
281 #[wasm_bindgen(getter)]
282 pub fn headers(self) -> JsValue {
283 self.headers
284 }
285}
286
287pub trait ToHeaders {
288 fn to_headers(self) -> Result<JsValue, JsValue>;
289
290 #[inline]
291 fn to_options(self) -> Result<Options, Error>
292 where
293 Self: Sized,
294 {
295 let headers = self.to_headers().map_err(Error)?;
296 Ok(Options { headers })
297 }
298}