tauri_api/
rpc.rs

1use serde::Serialize;
2use serde_json::Value as JsonValue;
3use std::fmt::Display;
4
5/// Formats a function name and argument to be evaluated as callback.
6///
7/// # Examples
8/// ```
9/// use tauri_api::rpc::format_callback;
10/// // callback with a string argument
11/// let cb = format_callback("callback-function-name", "the string response");
12/// assert!(cb.contains(r#"window["callback-function-name"]("the string response")"#));
13/// ```
14///
15/// ```
16/// use tauri_api::rpc::format_callback;
17/// use serde::Serialize;
18/// // callback with JSON argument
19/// #[derive(Serialize)]
20/// struct MyResponse {
21///   value: String
22/// }
23/// let cb = format_callback("callback-function-name", serde_json::to_value(&MyResponse {
24///   value: "some value".to_string()
25/// }).expect("failed to serialize"));
26/// assert!(cb.contains(r#"window["callback-function-name"]({"value":"some value"})"#));
27/// ```
28pub fn format_callback<T: Into<JsonValue>, S: AsRef<str> + Display>(
29  function_name: S,
30  arg: T,
31) -> String {
32  format!(
33    r#"
34      if (window["{fn}"]) {{
35        window["{fn}"]({arg})
36      }} else {{
37        console.warn("[TAURI] Couldn't find callback id {fn} in window. This happens when the app is reloaded while Rust is running an asynchronous operation.")
38      }}
39    "#,
40    fn = function_name,
41    arg = arg.into().to_string()
42  )
43}
44
45/// Formats a Result type to its Promise response.
46/// Useful for Promises handling.
47/// If the Result `is_ok()`, the callback will be the `success_callback` function name and the argument will be the Ok value.
48/// If the Result `is_err()`, the callback will be the `error_callback` function name and the argument will be the Err value.
49///
50/// * `result` the Result to check
51/// * `success_callback` the function name of the Ok callback. Usually the `resolve` of the JS Promise.
52/// * `error_callback` the function name of the Err callback. Usually the `reject` of the JS Promise.
53///
54/// Note that the callback strings are automatically generated by the `promisified` helper.
55///
56/// # Examples
57/// ```
58/// use tauri_api::rpc::format_callback_result;
59/// let res: Result<u8, &str> = Ok(5);
60/// let cb = format_callback_result(res, "success_cb".to_string(), "error_cb".to_string()).expect("failed to format");
61/// assert!(cb.contains(r#"window["success_cb"](5)"#));
62///
63/// let res: Result<&str, &str> = Err("error message here");
64/// let cb = format_callback_result(res, "success_cb".to_string(), "error_cb".to_string()).expect("failed to format");
65/// assert!(cb.contains(r#"window["error_cb"]("error message here")"#));
66/// ```
67pub fn format_callback_result<T: Serialize, E: Serialize>(
68  result: Result<T, E>,
69  success_callback: String,
70  error_callback: String,
71) -> crate::Result<String> {
72  let rpc = match result {
73    Ok(res) => format_callback(success_callback, serde_json::to_value(res)?),
74    Err(err) => format_callback(error_callback, serde_json::to_value(err)?),
75  };
76  Ok(rpc)
77}
78
79#[cfg(test)]
80mod test {
81  use crate::rpc::*;
82  use quickcheck_macros::quickcheck;
83
84  // check abritrary strings in the format callback function
85  #[quickcheck]
86  fn qc_formating(f: String, a: String) -> bool {
87    // can not accept empty strings
88    if f != "" && a != "" {
89      // call format callback
90      let fc = format_callback(f.clone(), a.clone());
91      fc.contains(&format!(
92        r#"window["{}"]({})"#,
93        f,
94        serde_json::Value::String(a),
95      ))
96    } else {
97      true
98    }
99  }
100
101  // check arbitrary strings in format_callback_result
102  #[quickcheck]
103  fn qc_format_res(result: Result<String, String>, c: String, ec: String) -> bool {
104    let resp = format_callback_result(result.clone(), c.clone(), ec.clone())
105      .expect("failed to format callback result");
106    let (function, value) = match result {
107      Ok(v) => (c, v),
108      Err(e) => (ec, e),
109    };
110
111    resp.contains(&format!(
112      r#"window["{}"]({})"#,
113      function,
114      serde_json::Value::String(value),
115    ))
116  }
117}