canic_core/api/ic/
call.rs1use crate::{
21 cdk::{
22 candid::CandidType,
23 types::{BoundedString128, Principal},
24 },
25 dto::error::Error,
26 workflow::ic::call::{
27 CallBuilder as WorkflowCallBuilder, CallResult as WorkflowCallResult, CallWorkflow,
28 IntentSpec as WorkflowIntentSpec,
29 },
30};
31use candid::utils::{ArgumentDecoder, ArgumentEncoder};
32use serde::de::DeserializeOwned;
33
34pub struct Call;
46
47impl Call {
48 #[must_use]
49 pub fn bounded_wait(canister_id: impl Into<Principal>, method: &str) -> CallBuilder {
50 CallBuilder {
51 inner: CallWorkflow::bounded_wait(canister_id, method),
52 }
53 }
54
55 #[must_use]
56 pub fn unbounded_wait(canister_id: impl Into<Principal>, method: &str) -> CallBuilder {
57 CallBuilder {
58 inner: CallWorkflow::unbounded_wait(canister_id, method),
59 }
60 }
61}
62
63pub struct IntentKey(BoundedString128);
78
79impl IntentKey {
80 pub fn try_new(value: impl Into<String>) -> Result<Self, Error> {
81 BoundedString128::try_new(value)
82 .map(Self)
83 .map_err(Error::invalid)
84 }
85
86 #[must_use]
87 pub fn as_str(&self) -> &str {
88 self.0.as_str()
89 }
90
91 #[must_use]
92 pub fn into_inner(self) -> BoundedString128 {
93 self.0
94 }
95}
96
97impl AsRef<str> for IntentKey {
98 fn as_ref(&self) -> &str {
99 self.0.as_str()
100 }
101}
102
103impl From<IntentKey> for BoundedString128 {
104 fn from(key: IntentKey) -> Self {
105 key.0
106 }
107}
108
109pub struct IntentReservation {
128 key: IntentKey,
129 quantity: u64,
130 ttl_secs: Option<u64>,
131 max_in_flight: Option<u64>,
132}
133
134impl IntentReservation {
135 #[must_use]
136 pub const fn new(key: IntentKey, quantity: u64) -> Self {
137 Self {
138 key,
139 quantity,
140 ttl_secs: None,
141 max_in_flight: None,
142 }
143 }
144
145 #[must_use]
146 pub const fn with_ttl_secs(mut self, ttl_secs: u64) -> Self {
147 self.ttl_secs = Some(ttl_secs);
148 self
149 }
150
151 #[must_use]
152 pub const fn with_max_in_flight(mut self, max_in_flight: u64) -> Self {
153 self.max_in_flight = Some(max_in_flight);
154 self
155 }
156
157 pub(crate) fn into_spec(self) -> WorkflowIntentSpec {
158 WorkflowIntentSpec::new(
159 self.key.into(),
160 self.quantity,
161 self.ttl_secs,
162 self.max_in_flight,
163 )
164 }
165}
166
167pub struct CallBuilder {
172 inner: WorkflowCallBuilder,
173}
174
175impl CallBuilder {
176 pub fn with_arg<A>(self, arg: A) -> Result<Self, Error>
180 where
181 A: CandidType,
182 {
183 Ok(Self {
184 inner: self.inner.with_arg(arg).map_err(Error::from)?,
185 })
186 }
187
188 pub fn with_args<A>(self, args: A) -> Result<Self, Error>
190 where
191 A: ArgumentEncoder,
192 {
193 Ok(Self {
194 inner: self.inner.with_args(args).map_err(Error::from)?,
195 })
196 }
197
198 #[must_use]
200 pub fn with_raw_args(self, args: Vec<u8>) -> Self {
201 Self {
202 inner: self.inner.with_raw_args(args),
203 }
204 }
205
206 #[must_use]
209 pub fn with_cycles(self, cycles: u128) -> Self {
210 Self {
211 inner: self.inner.with_cycles(cycles),
212 }
213 }
214
215 #[must_use]
218 pub fn with_intent(self, intent: IntentReservation) -> Self {
219 Self {
220 inner: self.inner.with_intent(intent.into_spec()),
221 }
222 }
223
224 pub async fn execute(self) -> Result<CallResult, Error> {
227 Ok(CallResult {
228 inner: self.inner.execute().await.map_err(Error::from)?,
229 })
230 }
231}
232
233pub struct CallResult {
245 inner: WorkflowCallResult,
246}
247
248impl CallResult {
249 pub fn candid<R>(&self) -> Result<R, Error>
250 where
251 R: CandidType + DeserializeOwned,
252 {
253 self.inner.candid().map_err(Error::from)
254 }
255
256 pub fn candid_tuple<R>(&self) -> Result<R, Error>
257 where
258 R: for<'de> ArgumentDecoder<'de>,
259 {
260 self.inner.candid_tuple().map_err(Error::from)
261 }
262}