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