Repository: tauri-apps/tauri
File: crates/tauri/src/ipc/mod.rs (Rust)

Code before:
  }

  /// Reply to the invoke promise with an async task.
  pub fn respond_async<T, F>(self, task: F)
  where
    T: IpcResponse,
    F: Future<Output = Result<T, InvokeError>> + Send + 'static,
  {
    crate::async_runtime::spawn(async move {
      Self::return_task(
        self.webview,
        self.responder,
        task,
        self.cmd,
        self.callback,
        self.error,
      )
      .await;
    });
  }

  /// Reply to the invoke promise with an async task which is already serialized.
  pub fn respond_async_serialized(
    self,
    task: Pin<Box<dyn Future<Output = Result<InvokeResponseBody, InvokeError>> + Send + 'static>>,
  ) {
    crate::async_runtime::spawn(async move {
      let response = match task.await {
        Ok(ok) => InvokeResponse::Ok(ok),
        Err(err) => InvokeResponse::Err(err),
      };
      Self::return_result(
        self.webview,
        self.responder,
        response,
        self.cmd,
        self.callback,
        self.error,
      )
    });
  }

  /// Reply to the invoke promise with a serializable value.
  pub fn respond<T: IpcResponse>(self, value: Result<T, InvokeError>) {
    Self::return_result(
      self.webview,
      self.responder,
      value.into(),
      self.cmd,
      self.callback,
      self.error,

Review comment (bug):
Considering that `respond_async_serialized` is a `pub` API, isn't this a BREAKING CHANGE?

> maybe we could enable this for the debug build and still use the old static dispatch one for the release build?

In my opinion, having different signatures in debug and release modes would be confusing.

---

Not sure if I am correctly: if we only pass in `Box::pin(...) as Pin<Box<dyn ...>>`, then only a single template instantiation of `respond_async_serialized<Pin<Box<dyn ...>>>` will occur, which is effectively the same as changing the signature to `Pin<Box<dyn ...>>`, right?

Code after:
  pub fn respond_async<T, F>(self, task: F)
  where
    T: IpcResponse,
    F: Future<Output = Result<T, InvokeError>> + Send + 'static,
  {
    crate::async_runtime::spawn(async move {
      Self::return_task(
        self.webview,
        self.responder,
        task,
        self.cmd,
        self.callback,
        self.error,
      )
      .await;
    });
  }

  /// Reply to the invoke promise with an async task which is already serialized.
  pub fn respond_async_serialized<F>(self, task: F)
  where
    F: Future<Output = Result<InvokeResponseBody, InvokeError>> + Send + 'static,
  {
    // Dynamic dispatch the call in dev for a faster compile time
    // TODO: Revisit this and see if we can do this for the release build as well if the performace hit is not a problem
    #[cfg(debug_assertions)]
    {
      self.respond_async_serialized_dyn(Box::pin(task))
    }
    #[cfg(not(debug_assertions))]
    {
      self.respond_async_serialized_inner(task)
    }
  }

  /// Dynamic dispatch the [`Self::respond_async_serialized`] call
  #[cfg(debug_assertions)]
  fn respond_async_serialized_dyn(
    self,
    task: std::pin::Pin<
      Box<dyn Future<Output = Result<InvokeResponseBody, InvokeError>> + Send + 'static>,
    >,
  ) {
    self.respond_async_serialized_inner(task)
  }

  /// Reply to the invoke promise with an async task which is already serialized.
  fn respond_async_serialized_inner<F>(self, task: F)
  where
    F: Future<Output = Result<InvokeResponseBody, InvokeError>> + Send + 'static,
  {