canic_core/api/call/
mod.rs1use crate::{
8 dto::error::Error,
9 workflow::ic::call::{
10 CallBuilder as WorkflowCallBuilder, CallResult as WorkflowCallResult, CallWorkflow,
11 },
12};
13use candid::{
14 CandidType, Principal,
15 utils::{ArgumentDecoder, ArgumentEncoder},
16};
17use serde::de::DeserializeOwned;
18use std::borrow::Cow;
19
20pub struct Call;
22
23impl Call {
24 #[must_use]
26 pub fn bounded_wait(canister_id: impl Into<Principal>, method: &str) -> CallBuilder<'static> {
27 CallBuilder {
28 inner: CallWorkflow::bounded_wait(canister_id, method),
29 }
30 }
31
32 #[must_use]
34 pub fn unbounded_wait(canister_id: impl Into<Principal>, method: &str) -> CallBuilder<'static> {
35 CallBuilder {
36 inner: CallWorkflow::unbounded_wait(canister_id, method),
37 }
38 }
39}
40
41pub struct CallBuilder<'a> {
43 inner: WorkflowCallBuilder<'a>,
44}
45
46impl CallBuilder<'_> {
47 pub fn with_arg<A>(self, arg: A) -> Result<Self, Error>
49 where
50 A: CandidType,
51 {
52 Ok(Self {
53 inner: self.inner.with_arg(arg).map_err(Error::from)?,
54 })
55 }
56
57 pub fn with_args<A>(self, args: A) -> Result<Self, Error>
59 where
60 A: ArgumentEncoder,
61 {
62 Ok(Self {
63 inner: self.inner.with_args(args).map_err(Error::from)?,
64 })
65 }
66
67 #[must_use]
69 pub fn with_raw_args<'b>(self, args: impl Into<Cow<'b, [u8]>>) -> CallBuilder<'b> {
70 CallBuilder {
71 inner: self.inner.with_raw_args(args),
72 }
73 }
74
75 #[must_use]
77 pub fn with_cycles(self, cycles: u128) -> Self {
78 Self {
79 inner: self.inner.with_cycles(cycles),
80 }
81 }
82
83 pub async fn execute(self) -> Result<CallResult, Error> {
85 Ok(CallResult {
86 inner: self.inner.execute().await.map_err(Error::from)?,
87 })
88 }
89
90 pub async fn execute_candid<R>(self) -> Result<R, Error>
92 where
93 R: CandidType + DeserializeOwned,
94 {
95 self.execute().await?.candid()
96 }
97
98 pub async fn execute_candid_tuple<R>(self) -> Result<R, Error>
100 where
101 R: for<'de> ArgumentDecoder<'de>,
102 {
103 self.execute().await?.candid_tuple()
104 }
105}
106
107pub struct CallResult {
109 inner: WorkflowCallResult,
110}
111
112impl CallResult {
113 pub fn candid<R>(&self) -> Result<R, Error>
115 where
116 R: CandidType + DeserializeOwned,
117 {
118 self.inner.candid().map_err(Error::from)
119 }
120
121 pub fn candid_tuple<R>(&self) -> Result<R, Error>
123 where
124 R: for<'de> ArgumentDecoder<'de>,
125 {
126 self.inner.candid_tuple().map_err(Error::from)
127 }
128}
129
130#[cfg(test)]
135mod tests {
136 use super::*;
137 use crate::ops::runtime::metrics::inter_canister_call::{
138 InterCanisterCallMetricKey, InterCanisterCallMetrics,
139 };
140 use std::collections::HashMap;
141
142 #[test]
143 fn public_builder_routes_through_instrumented_call_authority() {
144 InterCanisterCallMetrics::reset();
145 let target = Principal::from_slice(&[7; 29]);
146
147 let _builder = Call::bounded_wait(target, "example")
148 .with_arg(42_u64)
149 .expect("encode one argument")
150 .with_cycles(1_000);
151
152 let counts: HashMap<_, _> = InterCanisterCallMetrics::snapshot()
153 .entries
154 .into_iter()
155 .collect();
156 assert_eq!(
157 counts.get(&InterCanisterCallMetricKey {
158 target,
159 method: "example".to_string(),
160 }),
161 Some(&1)
162 );
163 }
164}