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
91pub struct CallResult {
93 inner: WorkflowCallResult,
94}
95
96impl CallResult {
97 pub fn candid<R>(&self) -> Result<R, Error>
99 where
100 R: CandidType + DeserializeOwned,
101 {
102 self.inner.candid().map_err(Error::from)
103 }
104
105 pub fn candid_tuple<R>(&self) -> Result<R, Error>
107 where
108 R: for<'de> ArgumentDecoder<'de>,
109 {
110 self.inner.candid_tuple().map_err(Error::from)
111 }
112}
113
114#[cfg(test)]
119mod tests {
120 use super::*;
121 use crate::ops::runtime::metrics::inter_canister_call::{
122 InterCanisterCallMetricKey, InterCanisterCallMetrics,
123 };
124 use std::collections::HashMap;
125
126 #[test]
127 fn public_builder_routes_through_instrumented_call_authority() {
128 InterCanisterCallMetrics::reset();
129 let target = Principal::from_slice(&[7; 29]);
130
131 let _builder = Call::bounded_wait(target, "example")
132 .with_arg(42_u64)
133 .expect("encode one argument")
134 .with_cycles(1_000);
135
136 let counts: HashMap<_, _> = InterCanisterCallMetrics::snapshot()
137 .entries
138 .into_iter()
139 .collect();
140 assert_eq!(
141 counts.get(&InterCanisterCallMetricKey {
142 target,
143 method: "example".to_string(),
144 }),
145 Some(&1)
146 );
147 }
148}