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}