1use crate::{
11 Runtime,
12 ipc::{InvokeBody, InvokeError, InvokeMessage},
13};
14use serde::{
15 Deserialize, Deserializer,
16 de::{Error, Visitor},
17};
18
19use tauri_utils::acl::resolved::ResolvedCommand;
20
21pub struct CommandItem<'a, R: Runtime> {
23 pub plugin: Option<&'static str>,
25
26 pub name: &'static str,
28
29 pub key: &'static str,
31
32 pub message: &'a InvokeMessage<R>,
34
35 pub acl: &'a Option<Vec<ResolvedCommand>>,
37}
38
39pub trait CommandArg<'de, R: Runtime>: Sized {
67 fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError>;
71}
72
73impl<'de, D: Deserialize<'de>, R: Runtime> CommandArg<'de, R> for D {
75 fn from_command(command: CommandItem<'de, R>) -> Result<D, InvokeError> {
76 let name = command.name;
77 let arg = command.key;
78 #[cfg(feature = "tracing")]
79 let _span = tracing::trace_span!("ipc::request::deserialize_arg", arg = arg).entered();
80 Self::deserialize(command).map_err(|e| crate::Error::InvalidArgs(name, arg, e).into())
81 }
82}
83
84macro_rules! pass {
88 ($fn:ident, $($arg:ident: $argt:ty),+) => {
89 fn $fn<V: Visitor<'de>>(self, $($arg: $argt),*) -> Result<V::Value, Self::Error> {
90 self.deserialize_json()?.$fn($($arg),*)
91 }
92 }
93}
94
95impl<'a, R: Runtime> CommandItem<'a, R> {
96 fn deserialize_json(self) -> serde_json::Result<&'a serde_json::Value> {
97 if self.key.is_empty() {
98 return Err(serde_json::Error::custom(format!(
99 "command {} has an argument with no name with a non-optional value",
100 self.name
101 )));
102 }
103
104 match &self.message.payload {
105 InvokeBody::Raw(_body) => Err(serde_json::Error::custom(format!(
106 "command {} expected a value for key {} but the IPC call used a bytes payload",
107 self.name, self.key
108 ))),
109 InvokeBody::Json(v) => match v.get(self.key) {
110 Some(value) => Ok(value),
111 None => Err(serde_json::Error::custom(format!(
112 "command {} missing required key {}",
113 self.name, self.key
114 ))),
115 },
116 }
117 }
118}
119
120impl<'de, R: Runtime> Deserializer<'de> for CommandItem<'de, R> {
126 type Error = serde_json::Error;
127
128 pass!(deserialize_any, visitor: V);
129 pass!(deserialize_bool, visitor: V);
130 pass!(deserialize_i8, visitor: V);
131 pass!(deserialize_i16, visitor: V);
132 pass!(deserialize_i32, visitor: V);
133 pass!(deserialize_i64, visitor: V);
134 pass!(deserialize_u8, visitor: V);
135 pass!(deserialize_u16, visitor: V);
136 pass!(deserialize_u32, visitor: V);
137 pass!(deserialize_u64, visitor: V);
138 pass!(deserialize_f32, visitor: V);
139 pass!(deserialize_f64, visitor: V);
140 pass!(deserialize_char, visitor: V);
141 pass!(deserialize_str, visitor: V);
142 pass!(deserialize_string, visitor: V);
143 pass!(deserialize_bytes, visitor: V);
144 pass!(deserialize_byte_buf, visitor: V);
145
146 fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
147 match &self.message.payload {
148 InvokeBody::Raw(_body) => Err(serde_json::Error::custom(format!(
149 "command {} expected a value for key {} but the IPC call used a bytes payload",
150 self.name, self.key
151 ))),
152 InvokeBody::Json(v) => match v.get(self.key) {
153 Some(value) => value.deserialize_option(visitor),
154 None => visitor.visit_none(),
155 },
156 }
157 }
158
159 pass!(deserialize_unit, visitor: V);
160 pass!(deserialize_unit_struct, name: &'static str, visitor: V);
161 pass!(deserialize_newtype_struct, name: &'static str, visitor: V);
162 pass!(deserialize_seq, visitor: V);
163 pass!(deserialize_tuple, len: usize, visitor: V);
164
165 pass!(
166 deserialize_tuple_struct,
167 name: &'static str,
168 len: usize,
169 visitor: V
170 );
171
172 pass!(deserialize_map, visitor: V);
173
174 pass!(
175 deserialize_struct,
176 name: &'static str,
177 fields: &'static [&'static str],
178 visitor: V
179 );
180
181 pass!(
182 deserialize_enum,
183 name: &'static str,
184 fields: &'static [&'static str],
185 visitor: V
186 );
187
188 pass!(deserialize_identifier, visitor: V);
189 pass!(deserialize_ignored_any, visitor: V);
190}
191
192#[doc(hidden)]
196pub mod private {
197 use crate::{
198 Runtime,
199 ipc::{InvokeError, InvokeResolver, InvokeResponseBody, IpcResponse},
200 };
201 use std::future::Future;
202 #[cfg(feature = "tracing")]
203 pub use tracing;
204
205 pub struct ResponseTag;
208
209 pub trait ResponseKind {
210 #[inline(always)]
211 fn blocking_kind(&self) -> ResponseTag {
212 ResponseTag
213 }
214
215 #[inline(always)]
216 fn async_kind(&self) -> ResponseTag {
217 ResponseTag
218 }
219 }
220
221 impl<T: IpcResponse> ResponseKind for &T {}
222
223 impl ResponseTag {
224 #[inline(always)]
225 pub fn block<R, T>(self, value: T, resolver: InvokeResolver<R>)
226 where
227 R: Runtime,
228 T: IpcResponse,
229 {
230 resolver.respond(Ok(value))
231 }
232
233 #[inline(always)]
234 pub async fn future<T>(self, value: T) -> Result<InvokeResponseBody, InvokeError>
235 where
236 T: IpcResponse,
237 {
238 Ok(value.body()?)
239 }
240 }
241
242 pub struct ResultTag;
245
246 pub trait ResultKind {
247 #[inline(always)]
248 fn blocking_kind(&self) -> ResultTag {
249 ResultTag
250 }
251
252 #[inline(always)]
253 fn async_kind(&self) -> ResultTag {
254 ResultTag
255 }
256 }
257
258 impl<T: IpcResponse, E: Into<InvokeError>> ResultKind for Result<T, E> {}
259
260 impl ResultTag {
261 #[inline(always)]
262 pub fn block<R, T, E>(self, value: Result<T, E>, resolver: InvokeResolver<R>)
263 where
264 R: Runtime,
265 T: IpcResponse,
266 E: Into<InvokeError>,
267 {
268 resolver.respond(value.map_err(Into::into))
269 }
270
271 #[inline(always)]
272 pub async fn future<T, E>(self, value: Result<T, E>) -> Result<InvokeResponseBody, InvokeError>
273 where
274 T: IpcResponse,
275 E: Into<InvokeError>,
276 {
277 Ok(value.map_err(Into::into)?.body()?)
278 }
279 }
280
281 pub struct FutureTag;
284
285 pub trait FutureKind {
286 #[inline(always)]
287 fn async_kind(&self) -> FutureTag {
288 FutureTag
289 }
290 }
291 impl<T: IpcResponse, F: Future<Output = T>> FutureKind for &F {}
292
293 impl FutureTag {
294 #[inline(always)]
295 pub async fn future<T, F>(self, value: F) -> Result<InvokeResponseBody, InvokeError>
296 where
297 T: IpcResponse,
298 F: Future<Output = T> + Send + 'static,
299 {
300 Ok(value.await.body()?)
301 }
302 }
303
304 pub struct ResultFutureTag;
307
308 pub trait ResultFutureKind {
309 #[inline(always)]
310 fn async_kind(&self) -> ResultFutureTag {
311 ResultFutureTag
312 }
313 }
314
315 impl<T: IpcResponse, E: Into<InvokeError>, F: Future<Output = Result<T, E>>> ResultFutureKind
316 for F
317 {
318 }
319
320 impl ResultFutureTag {
321 #[inline(always)]
322 pub async fn future<T, E, F>(self, value: F) -> Result<InvokeResponseBody, InvokeError>
323 where
324 T: IpcResponse,
325 E: Into<InvokeError>,
326 F: Future<Output = Result<T, E>> + Send,
327 {
328 let response = value.await.map_err(Into::into)?;
329 Ok(response.body()?)
330 }
331 }
332}