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