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 #[must_use]
179 pub fn with_arg<A>(self, arg: A) -> Self
180 where
181 A: CandidType,
182 {
183 Self {
184 inner: self.inner.with_arg(arg),
185 }
186 }
187
188 #[must_use]
189 pub fn with_args<A>(self, args: A) -> Self
190 where
191 A: ArgumentEncoder,
192 {
193 Self {
194 inner: self.inner.with_args(args),
195 }
196 }
197
198 pub fn try_with_arg<A>(self, arg: A) -> Result<Self, Error>
199 where
200 A: CandidType,
201 {
202 Ok(Self {
203 inner: self.inner.try_with_arg(arg).map_err(Error::from)?,
204 })
205 }
206
207 pub fn try_with_args<A>(self, args: A) -> Result<Self, Error>
208 where
209 A: ArgumentEncoder,
210 {
211 Ok(Self {
212 inner: self.inner.try_with_args(args).map_err(Error::from)?,
213 })
214 }
215
216 #[must_use]
219 pub fn with_cycles(self, cycles: u128) -> Self {
220 Self {
221 inner: self.inner.with_cycles(cycles),
222 }
223 }
224
225 #[must_use]
228 pub fn with_intent(self, intent: IntentReservation) -> Self {
229 Self {
230 inner: self.inner.with_intent(intent.into_spec()),
231 }
232 }
233
234 pub async fn execute(self) -> Result<CallResult, Error> {
237 Ok(CallResult {
238 inner: self.inner.execute().await.map_err(Error::from)?,
239 })
240 }
241}
242
243pub struct CallResult {
255 inner: WorkflowCallResult,
256}
257
258impl CallResult {
259 pub fn candid<R>(&self) -> Result<R, Error>
260 where
261 R: CandidType + DeserializeOwned,
262 {
263 self.inner.candid().map_err(Error::from)
264 }
265
266 pub fn candid_tuple<R>(&self) -> Result<R, Error>
267 where
268 R: for<'de> ArgumentDecoder<'de>,
269 {
270 self.inner.candid_tuple().map_err(Error::from)
271 }
272}