junobuild_shared/ic/
call.rs

1use candid::{CandidType, Deserialize};
2use ic_cdk::call::{CallFailed, Response};
3
4/// Extension trait for decoding Candid responses from inter-canister calls.
5///
6/// This trait provides a convenient method to decode the response of an inter-canister call
7/// into a Rust type, combining error handling for both call failures and decoding failures.
8pub trait DecodeCandid {
9    /// Decodes the response as a Candid type.
10    ///
11    /// This method handles both the call result and Candid decoding in a single step,
12    /// converting any errors into descriptive string messages.
13    ///
14    /// # Type Parameters
15    /// * `T` - The type to decode the response into. Must implement `CandidType` and `Deserialize`.
16    ///
17    /// # Returns
18    /// * `Ok(T)` - The successfully decoded response.
19    /// * `Err(String)` - An error message describing either the call failure or decoding failure.
20    ///
21    /// # Examples
22    ///
23    /// ```rust,no_run
24    /// # use ic_cdk::call::Call;
25    /// # use candid::Principal;
26    /// # async fn example() -> Result<u32, String> {
27    /// # let canister_id = Principal::anonymous();
28    /// let result: u32 = Call::bounded_wait(canister_id, "get_value")
29    ///     .await
30    ///     .decode_candid()?;
31    /// # Ok(result)
32    /// # }
33    /// ```
34    fn decode_candid<T>(self) -> Result<T, String>
35    where
36        T: CandidType + for<'de> Deserialize<'de>;
37}
38
39impl DecodeCandid for Result<Response, CallFailed> {
40    fn decode_candid<T>(self) -> Result<T, String>
41    where
42        T: CandidType + for<'de> Deserialize<'de>,
43    {
44        self.map_err(|e| format!("Call failed: {:?}", e))?
45            .candid::<T>()
46            .map_err(|e| format!("Decoding failed: {:?}", e))
47    }
48}