ic_cdk/api/
call.rs

1//! APIs to make and manage calls in the canister.
2use crate::api::trap;
3use candid::utils::{decode_args_with_config_debug, ArgumentDecoder, ArgumentEncoder};
4use candid::{
5    decode_args, encode_args, write_args, CandidType, DecoderConfig, Deserialize, Principal,
6};
7use serde::ser::Error;
8use std::future::Future;
9use std::marker::PhantomData;
10use std::pin::Pin;
11use std::sync::atomic::Ordering;
12use std::sync::{Arc, RwLock, Weak};
13use std::task::{Context, Poll, Waker};
14
15/// Rejection code from calling another canister.
16///
17/// These can be obtained either using `reject_code()` or `reject_result()`.
18#[allow(missing_docs)]
19#[repr(i32)]
20#[derive(CandidType, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord)]
21pub enum RejectionCode {
22    NoError = 0,
23
24    SysFatal = 1,
25    SysTransient = 2,
26    DestinationInvalid = 3,
27    CanisterReject = 4,
28    CanisterError = 5,
29
30    Unknown,
31}
32
33impl From<i32> for RejectionCode {
34    fn from(code: i32) -> Self {
35        match code {
36            0 => RejectionCode::NoError,
37            1 => RejectionCode::SysFatal,
38            2 => RejectionCode::SysTransient,
39            3 => RejectionCode::DestinationInvalid,
40            4 => RejectionCode::CanisterReject,
41            5 => RejectionCode::CanisterError,
42            _ => RejectionCode::Unknown,
43        }
44    }
45}
46
47impl From<u32> for RejectionCode {
48    fn from(code: u32) -> Self {
49        RejectionCode::from(code as i32)
50    }
51}
52
53/// The result of a Call.
54///
55/// Errors on the IC have two components; a Code and a message associated with it.
56pub type CallResult<R> = Result<R, (RejectionCode, String)>;
57
58// Internal state for the Future when sending a call.
59struct CallFutureState<T: AsRef<[u8]>> {
60    result: Option<CallResult<Vec<u8>>>,
61    waker: Option<Waker>,
62    id: Principal,
63    method: String,
64    arg: T,
65    payment: u128,
66}
67
68struct CallFuture<T: AsRef<[u8]>> {
69    state: Arc<RwLock<CallFutureState<T>>>,
70}
71
72impl<T: AsRef<[u8]>> Future for CallFuture<T> {
73    type Output = CallResult<Vec<u8>>;
74
75    fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
76        let self_ref = Pin::into_inner(self);
77        let mut state = self_ref.state.write().unwrap();
78
79        if let Some(result) = state.result.take() {
80            Poll::Ready(result)
81        } else {
82            if state.waker.is_none() {
83                let callee = state.id.as_slice();
84                let method = &state.method;
85                let args = state.arg.as_ref();
86                let payment = state.payment;
87                let state_ptr = Weak::into_raw(Arc::downgrade(&self_ref.state));
88                // SAFETY:
89                // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new.
90                // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new.
91                // `callback` is a function with signature (env : i32) -> () and therefore can be called as both reply and reject fn for ic0.call_new.
92                // `state_ptr` is a pointer created via Weak::into_raw, and can therefore be passed as the userdata for `callback`.
93                // `args`, being a &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_data_append.
94                // `cleanup` is a function with signature (env : i32) -> () and therefore can be called as a cleanup fn for ic0.call_on_cleanup.
95                // `state_ptr` is a pointer created via Weak::into_raw, and can therefore be passed as the userdata for `cleanup`.
96                // ic0.call_perform is always safe to call.
97                // callback and cleanup are safe to parameterize with T because:
98                // - if the future is dropped before the callback is called, there will be no more strong references and the weak reference will fail to upgrade
99                // - if the future is *not* dropped before the callback is called, the compiler will mandate that any data borrowed by T is still alive
100                let err_code = unsafe {
101                    ic0::call_new(
102                        callee.as_ptr() as i32,
103                        callee.len() as i32,
104                        method.as_ptr() as i32,
105                        method.len() as i32,
106                        callback::<T> as usize as i32,
107                        state_ptr as i32,
108                        callback::<T> as usize as i32,
109                        state_ptr as i32,
110                    );
111
112                    ic0::call_data_append(args.as_ptr() as i32, args.len() as i32);
113                    add_payment(payment);
114                    ic0::call_on_cleanup(cleanup::<T> as usize as i32, state_ptr as i32);
115                    ic0::call_perform()
116                };
117
118                // 0 is a special error code meaning call succeeded.
119                if err_code != 0 {
120                    let result = Err((
121                        RejectionCode::from(err_code),
122                        "Couldn't send message".to_string(),
123                    ));
124                    state.result = Some(result.clone());
125                    return Poll::Ready(result);
126                }
127            }
128            state.waker = Some(context.waker().clone());
129            Poll::Pending
130        }
131    }
132}
133
134/// The callback from IC dereferences the future from a raw pointer, assigns the
135/// result and calls the waker. We cannot use a closure here because we pass raw
136/// pointers to the System and back.
137///
138/// # Safety
139///
140/// This function must only be passed to the IC with a pointer from Weak::into_raw as userdata.
141unsafe extern "C" fn callback<T: AsRef<[u8]>>(state_ptr: *const RwLock<CallFutureState<T>>) {
142    // SAFETY: This function is only ever called by the IC, and we only ever pass a Weak as userdata.
143    let state = unsafe { Weak::from_raw(state_ptr) };
144    if let Some(state) = state.upgrade() {
145        // Make sure to un-borrow_mut the state.
146        {
147            state.write().unwrap().result = Some(match reject_code() {
148                RejectionCode::NoError => Ok(arg_data_raw()),
149                n => Err((n, reject_message())),
150            });
151        }
152        let w = state.write().unwrap().waker.take();
153        if let Some(waker) = w {
154            // This is all to protect this little guy here which will call the poll() which
155            // borrow_mut() the state as well. So we need to be careful to not double-borrow_mut.
156            waker.wake()
157        }
158    }
159}
160
161/// This function is called when [callback] was just called with the same parameter, and trapped.
162/// We can't guarantee internal consistency at this point, but we can at least e.g. drop mutex guards.
163/// Waker is a very opaque API, so the best we can do is set a global flag and proceed normally.
164///
165/// # Safety
166///
167/// This function must only be passed to the IC with a pointer from Weak::into_raw as userdata.
168unsafe extern "C" fn cleanup<T: AsRef<[u8]>>(state_ptr: *const RwLock<CallFutureState<T>>) {
169    // SAFETY: This function is only ever called by the IC, and we only ever pass a Weak as userdata.
170    let state = unsafe { Weak::from_raw(state_ptr) };
171    if let Some(state) = state.upgrade() {
172        // We set the call result, even though it won't be read on the
173        // default executor, because we can't guarantee it was called on
174        // our executor. However, we are not allowed to inspect
175        // reject_code() inside of a cleanup callback, so always set the
176        // result to a reject.
177        //
178        // Borrowing does not trap - the rollback from the
179        // previous trap ensures that the RwLock can be borrowed again.
180        state.write().unwrap().result = Some(Err((RejectionCode::NoError, "cleanup".to_string())));
181        let w = state.write().unwrap().waker.take();
182        if let Some(waker) = w {
183            // Flag that we do not want to actually wake the task - we
184            // want to drop it *without* executing it.
185            ic_cdk_executor::CLEANUP.store(true, Ordering::Relaxed);
186            waker.wake();
187            ic_cdk_executor::CLEANUP.store(false, Ordering::Relaxed);
188        }
189    }
190}
191
192fn add_payment(payment: u128) {
193    if payment == 0 {
194        return;
195    }
196    let high = (payment >> 64) as u64;
197    let low = (payment & u64::MAX as u128) as u64;
198    // SAFETY: ic0.call_cycles_add128 is always safe to call.
199    unsafe {
200        ic0::call_cycles_add128(high as i64, low as i64);
201    }
202}
203
204/// Sends a one-way message with `payment` cycles attached to it that invokes `method` with
205/// arguments `args` on the principal identified by `id`, ignoring the reply.
206///
207/// Returns `Ok(())` if the message was successfully enqueued, otherwise returns a reject code.
208///
209/// # Notes
210///
211///   * The caller has no way of checking whether the destination processed the notification.
212///     The system can drop the notification if the destination does not have resources to
213///     process the message (for example, if it's out of cycles or queue slots).
214///
215///   * The callee cannot tell whether the call is one-way or not.
216///     The callee must produce replies for all incoming messages.
217///
218///   * It is safe to upgrade a canister without stopping it first if it sends out *only*
219///     one-way messages.
220///
221///   * If the payment is non-zero and the system fails to deliver the notification, the behaviour
222///     is unspecified: the funds can be either reimbursed or consumed irrevocably by the IC depending
223///     on the underlying implementation of one-way calls.
224pub fn notify_with_payment128<T: ArgumentEncoder>(
225    id: Principal,
226    method: &str,
227    args: T,
228    payment: u128,
229) -> Result<(), RejectionCode> {
230    let args_raw = encode_args(args).expect("failed to encode arguments");
231    notify_raw(id, method, &args_raw, payment)
232}
233
234/// Like [notify_with_payment128], but sets the payment to zero.
235pub fn notify<T: ArgumentEncoder>(
236    id: Principal,
237    method: &str,
238    args: T,
239) -> Result<(), RejectionCode> {
240    notify_with_payment128(id, method, args, 0)
241}
242
243/// Like [notify], but sends the argument as raw bytes, skipping Candid serialization.
244pub fn notify_raw(
245    id: Principal,
246    method: &str,
247    args_raw: &[u8],
248    payment: u128,
249) -> Result<(), RejectionCode> {
250    let callee = id.as_slice();
251    // We set all callbacks to -1, which is guaranteed to be invalid callback index.
252    // The system will still deliver the reply, but it will trap immediately because the callback
253    // is not a valid function. See
254    // https://www.joachim-breitner.de/blog/789-Zero-downtime_upgrades_of_Internet_Computer_canisters#one-way-calls
255    // for more context.
256
257    // SAFETY:
258    // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new.
259    // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new.
260    // -1, i.e. usize::MAX, is a function pointer the wasm module cannot possibly contain, and therefore can be passed as both reply and reject fn for ic0.call_new.
261    // Since the callback function will never be called, any value can be passed as its context parameter, and therefore -1 can be passed for those values.
262    // `args`, being a &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_data_append.
263    // ic0.call_perform is always safe to call.
264    let err_code = unsafe {
265        ic0::call_new(
266            callee.as_ptr() as i32,
267            callee.len() as i32,
268            method.as_ptr() as i32,
269            method.len() as i32,
270            /* reply_fun = */ -1,
271            /* reply_env = */ -1,
272            /* reject_fun = */ -1,
273            /* reject_env = */ -1,
274        );
275        add_payment(payment);
276        ic0::call_data_append(args_raw.as_ptr() as i32, args_raw.len() as i32);
277        ic0::call_perform()
278    };
279    match err_code {
280        0 => Ok(()),
281        c => Err(RejectionCode::from(c)),
282    }
283}
284
285/// Performs an asynchronous call to another canister and pay cycles at the same time.
286///
287/// Treats arguments and returns as raw bytes. No data serialization and deserialization is performed.
288///
289/// # Example
290///
291/// It can be called:
292///
293/// ```rust
294/// # use ic_cdk::api::call::call_raw;
295/// # fn callee_canister() -> candid::Principal { unimplemented!() }
296/// async fn call_add_user() -> Vec<u8>{
297///     call_raw(callee_canister(), "add_user", b"abcd", 1_000_000u64).await.unwrap()
298/// }
299/// ```
300pub fn call_raw<'a, T: AsRef<[u8]> + Send + Sync + 'a>(
301    id: Principal,
302    method: &str,
303    args_raw: T,
304    payment: u64,
305) -> impl Future<Output = CallResult<Vec<u8>>> + Send + Sync + 'a {
306    call_raw_internal(id, method, args_raw, payment.into())
307}
308
309/// Performs an asynchronous call to another canister and pay cycles (in `u128`) at the same time.
310///
311/// Treats arguments and returns as raw bytes. No data serialization and deserialization is performed.
312/// # Example
313///
314/// It can be called:
315///
316/// ```rust
317/// # use ic_cdk::api::call::call_raw128;
318/// # fn callee_canister() -> candid::Principal { unimplemented!() }
319/// async fn call_add_user() -> Vec<u8>{
320///     call_raw128(callee_canister(), "add_user", b"abcd", 1_000_000u128).await.unwrap()
321/// }
322/// ```
323pub fn call_raw128<'a, T: AsRef<[u8]> + Send + Sync + 'a>(
324    id: Principal,
325    method: &str,
326    args_raw: T,
327    payment: u128,
328) -> impl Future<Output = CallResult<Vec<u8>>> + Send + Sync + 'a {
329    call_raw_internal(id, method, args_raw, payment)
330}
331
332fn call_raw_internal<'a, T: AsRef<[u8]> + Send + Sync + 'a>(
333    id: Principal,
334    method: &str,
335    args_raw: T,
336    payment: u128,
337) -> impl Future<Output = CallResult<Vec<u8>>> + Send + Sync + 'a {
338    let state = Arc::new(RwLock::new(CallFutureState {
339        result: None,
340        waker: None,
341        id,
342        method: method.to_string(),
343        arg: args_raw,
344        payment,
345    }));
346    CallFuture { state }
347}
348
349fn decoder_error_to_reject<T>(err: candid::error::Error) -> (RejectionCode, String) {
350    (
351        RejectionCode::CanisterError,
352        format!(
353            "failed to decode canister response as {}: {}",
354            std::any::type_name::<T>(),
355            err
356        ),
357    )
358}
359
360/// Performs an asynchronous call to another canister.
361///
362/// # Example
363///
364/// Assuming that the callee canister has following interface:
365///
366/// ```text
367/// service : {
368///     add_user: (name: text) -> (nat64);
369/// }
370/// ```
371///
372/// It can be called:
373///
374/// ```rust
375/// # use ic_cdk::api::call::call;
376/// # fn callee_canister() -> candid::Principal { unimplemented!() }
377/// async fn call_add_user() -> u64 {
378///     let (user_id,) = call(callee_canister(), "add_user", ("Alice".to_string(),)).await.unwrap();
379///     user_id
380/// }
381/// ```
382///
383/// # Note
384///
385/// * Both argument and return types are tuples even if it has only one value, e.g `(user_id,)`, `("Alice".to_string(),)`.
386/// * The type annotation on return type is required. Or the return type can be inferred from the context.
387/// * The asynchronous call must be awaited in order for the inter-canister call to be made.
388/// * If the reply payload is not a valid encoding of the expected type `T`, the call results in [RejectionCode::CanisterError] error.
389pub fn call<T: ArgumentEncoder, R: for<'a> ArgumentDecoder<'a>>(
390    id: Principal,
391    method: &str,
392    args: T,
393) -> impl Future<Output = CallResult<R>> + Send + Sync {
394    let args_raw = encode_args(args).expect("Failed to encode arguments.");
395    let fut = call_raw(id, method, args_raw, 0);
396    async {
397        let bytes = fut.await?;
398        decode_args(&bytes).map_err(decoder_error_to_reject::<R>)
399    }
400}
401
402/// Performs an asynchronous call to another canister and pay cycles at the same time.
403///
404/// # Example
405///
406/// Assuming that the callee canister has following interface:
407///
408/// ```text
409/// service : {
410///     add_user: (name: text) -> (nat64);
411/// }
412/// ```
413///
414/// It can be called:
415///
416/// ```rust
417/// # use ic_cdk::api::call::call_with_payment;
418/// # fn callee_canister() -> candid::Principal { unimplemented!() }
419/// async fn call_add_user() -> u64 {
420///     let (user_id,) = call_with_payment(callee_canister(), "add_user", ("Alice".to_string(),), 1_000_000u64).await.unwrap();
421///     user_id
422/// }
423/// ```
424///
425/// # Note
426///
427/// * Both argument and return types are tuples even if it has only one value, e.g `(user_id,)`, `("Alice".to_string(),)`.
428/// * The type annotation on return type is required. Or the return type can be inferred from the context.
429/// * The asynchronous call must be awaited in order for the inter-canister call to be made.
430/// * If the reply payload is not a valid encoding of the expected type `T`, the call results in [RejectionCode::CanisterError] error.
431pub fn call_with_payment<T: ArgumentEncoder, R: for<'a> ArgumentDecoder<'a>>(
432    id: Principal,
433    method: &str,
434    args: T,
435    cycles: u64,
436) -> impl Future<Output = CallResult<R>> + Send + Sync {
437    let args_raw = encode_args(args).expect("Failed to encode arguments.");
438    let fut = call_raw(id, method, args_raw, cycles);
439    async {
440        let bytes = fut.await?;
441        decode_args(&bytes).map_err(decoder_error_to_reject::<R>)
442    }
443}
444
445/// Performs an asynchronous call to another canister and pay cycles (in `u128`) at the same time.
446///
447/// # Example
448///
449/// Assuming that the callee canister has following interface:
450///
451/// ```text
452/// service : {
453///     add_user: (name: text) -> (nat64);
454/// }
455/// ```
456///
457/// It can be called:
458///
459/// ```rust
460/// # use ic_cdk::api::call::call_with_payment128;
461/// # fn callee_canister() -> candid::Principal { unimplemented!() }
462/// async fn call_add_user() -> u64 {
463///     let (user_id,) = call_with_payment128(callee_canister(), "add_user", ("Alice".to_string(),), 1_000_000u128).await.unwrap();
464///     user_id
465/// }
466/// ```
467///
468/// # Note
469///
470/// * Both argument and return types are tuples even if it has only one value, e.g `(user_id,)`, `("Alice".to_string(),)`.
471/// * The type annotation on return type is required. Or the return type can be inferred from the context.
472/// * The asynchronous call must be awaited in order for the inter-canister call to be made.
473/// * If the reply payload is not a valid encoding of the expected type `T`, the call results in [RejectionCode::CanisterError] error.
474pub fn call_with_payment128<T: ArgumentEncoder, R: for<'a> ArgumentDecoder<'a>>(
475    id: Principal,
476    method: &str,
477    args: T,
478    cycles: u128,
479) -> impl Future<Output = CallResult<R>> + Send + Sync {
480    let args_raw = encode_args(args).expect("Failed to encode arguments.");
481    let fut = call_raw128(id, method, args_raw, cycles);
482    async {
483        let bytes = fut.await?;
484        decode_args(&bytes).map_err(decoder_error_to_reject::<R>)
485    }
486}
487
488/// Performs an asynchronous call to another canister and pay cycles (in `u128`).
489/// It also allows setting a quota for decoding the return values.
490/// The decoding quota is strongly recommended when calling third-party or untrusted canisters.
491///
492/// # Example
493///
494/// Assuming that the callee canister has following interface:
495///
496/// ```text
497/// service : {
498///     add_user: (name: text) -> (nat64);
499/// }
500/// ```
501///
502/// It can be called:
503///
504/// ```rust
505/// # use ic_cdk::api::call::{call_with_config, ArgDecoderConfig};
506/// # fn callee_canister() -> candid::Principal { unimplemented!() }
507/// async fn call_add_user() -> u64 {
508///     let config = ArgDecoderConfig {
509///         // The function only returns a nat64, to accomodate future upgrades, we set a larger decoding_quota.
510///         decoding_quota: Some(10_000),
511///         // To accomodate future upgrades, reserve some skipping_quota.
512///         skipping_quota: Some(100),
513///         // Enable debug mode to print decoding instructions and cost to the replica log.
514///         debug: true,
515///     };
516///     let (user_id,) = call_with_config(callee_canister(), "add_user", ("Alice".to_string(),), 1_000_000u128, &config).await.unwrap();
517///     user_id
518/// }
519/// ```
520pub fn call_with_config<'b, T: ArgumentEncoder, R: for<'a> ArgumentDecoder<'a>>(
521    id: Principal,
522    method: &'b str,
523    args: T,
524    cycles: u128,
525    arg_config: &'b ArgDecoderConfig,
526) -> impl Future<Output = CallResult<R>> + Send + Sync + 'b {
527    let args_raw = encode_args(args).expect("Failed to encode arguments.");
528    let fut = call_raw128(id, method, args_raw, cycles);
529    async move {
530        let bytes = fut.await?;
531        let config = arg_config.to_candid_config();
532        let pre_cycles = if arg_config.debug {
533            Some(crate::api::performance_counter(0))
534        } else {
535            None
536        };
537        match decode_args_with_config_debug(&bytes, &config) {
538            Err(e) => Err(decoder_error_to_reject::<R>(e)),
539            Ok((r, cost)) => {
540                if arg_config.debug {
541                    print_decoding_debug_info(&format!("{method} return"), &cost, pre_cycles);
542                }
543                Ok(r)
544            }
545        }
546    }
547}
548
549fn print_decoding_debug_info(title: &str, cost: &DecoderConfig, pre_cycles: Option<u64>) {
550    use crate::api::{performance_counter, print};
551    let pre_cycles = pre_cycles.unwrap_or(0);
552    let instrs = performance_counter(0) - pre_cycles;
553    print(format!("[Debug] {title} decoding instructions: {instrs}"));
554    if let Some(n) = cost.decoding_quota {
555        print(format!("[Debug] {title} decoding cost: {n}"));
556    }
557    if let Some(n) = cost.skipping_quota {
558        print(format!("[Debug] {title} skipping cost: {n}"));
559    }
560}
561
562/// Returns a result that maps over the call
563///
564/// It will be Ok(T) if the call succeeded (with T being the arg_data),
565/// and [reject_message()] if it failed.
566pub fn result<T: for<'a> ArgumentDecoder<'a>>() -> Result<T, String> {
567    match reject_code() {
568        RejectionCode::NoError => {
569            decode_args(&arg_data_raw()).map_err(|e| format!("Failed to decode arguments: {}", e))
570        }
571        _ => Err(reject_message()),
572    }
573}
574
575/// Returns the rejection code for the call.
576pub fn reject_code() -> RejectionCode {
577    // SAFETY: ic0.msg_reject_code is always safe to call.
578    let code = unsafe { ic0::msg_reject_code() };
579    RejectionCode::from(code)
580}
581
582/// Returns the rejection message.
583pub fn reject_message() -> String {
584    // SAFETY: ic0.msg_reject_msg_size is always safe to call.
585    let len: u32 = unsafe { ic0::msg_reject_msg_size() as u32 };
586    let mut bytes = vec![0u8; len as usize];
587    // SAFETY: `bytes`, being mutable and allocated to `len` bytes, is safe to pass to ic0.msg_reject_msg_copy with no offset
588    unsafe {
589        ic0::msg_reject_msg_copy(bytes.as_mut_ptr() as i32, 0, len as i32);
590    }
591    String::from_utf8_lossy(&bytes).into_owned()
592}
593
594/// Rejects the current call with the message.
595pub fn reject(message: &str) {
596    let err_message = message.as_bytes();
597    // SAFETY: `err_message`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.msg_reject.
598    unsafe {
599        ic0::msg_reject(err_message.as_ptr() as i32, err_message.len() as i32);
600    }
601}
602
603/// An io::Write for message replies.
604#[derive(Debug, Copy, Clone)]
605pub struct CallReplyWriter;
606
607impl std::io::Write for CallReplyWriter {
608    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
609        // SAFETY: buf, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.msg_reply_data_append.
610        unsafe {
611            ic0::msg_reply_data_append(buf.as_ptr() as i32, buf.len() as i32);
612        }
613        Ok(buf.len())
614    }
615
616    fn flush(&mut self) -> std::io::Result<()> {
617        Ok(())
618    }
619}
620
621/// Replies to the current call with a candid argument.
622pub fn reply<T: ArgumentEncoder>(reply: T) {
623    write_args(&mut CallReplyWriter, reply).expect("Could not encode reply.");
624    // SAFETY: ic0.msg_reply is always safe to call.
625    unsafe {
626        ic0::msg_reply();
627    }
628}
629
630/// Returns the amount of cycles that were transferred by the caller
631/// of the current call, and is still available in this message.
632pub fn msg_cycles_available() -> u64 {
633    // SAFETY: ic0.msg_cycles_available is always safe to call.
634    unsafe { ic0::msg_cycles_available() as u64 }
635}
636
637/// Returns the amount of cycles that were transferred by the caller
638/// of the current call, and is still available in this message.
639pub fn msg_cycles_available128() -> u128 {
640    let mut recv = 0u128;
641    // SAFETY: recv is writable and sixteen bytes wide, and therefore is safe to pass to ic0.msg_cycles_available128
642    unsafe {
643        ic0::msg_cycles_available128(&mut recv as *mut u128 as i32);
644    }
645    recv
646}
647
648/// Returns the amount of cycles that came back with the response as a refund.
649///
650/// The refund has already been added to the canister balance automatically.
651pub fn msg_cycles_refunded() -> u64 {
652    // SAFETY: ic0.msg_cycles_refunded is always safe to call
653    unsafe { ic0::msg_cycles_refunded() as u64 }
654}
655
656/// Returns the amount of cycles that came back with the response as a refund.
657///
658/// The refund has already been added to the canister balance automatically.
659pub fn msg_cycles_refunded128() -> u128 {
660    let mut recv = 0u128;
661    // SAFETY: recv is writable and sixteen bytes wide, and therefore is safe to pass to ic0.msg_cycles_refunded128
662    unsafe {
663        ic0::msg_cycles_refunded128(&mut recv as *mut u128 as i32);
664    }
665    recv
666}
667
668/// Moves cycles from the call to the canister balance.
669///
670/// The actual amount moved will be returned.
671pub fn msg_cycles_accept(max_amount: u64) -> u64 {
672    // SAFETY: ic0.msg_cycles_accept is always safe to call.
673    unsafe { ic0::msg_cycles_accept(max_amount as i64) as u64 }
674}
675
676/// Moves cycles from the call to the canister balance.
677///
678/// The actual amount moved will be returned.
679pub fn msg_cycles_accept128(max_amount: u128) -> u128 {
680    let high = (max_amount >> 64) as u64;
681    let low = (max_amount & u64::MAX as u128) as u64;
682    let mut recv = 0u128;
683    // SAFETY: `recv` is writable and sixteen bytes wide, and therefore safe to pass to ic0.msg_cycles_accept128
684    unsafe {
685        ic0::msg_cycles_accept128(high as i64, low as i64, &mut recv as *mut u128 as i32);
686    }
687    recv
688}
689
690/// Returns the argument data as bytes.
691pub fn arg_data_raw() -> Vec<u8> {
692    // SAFETY: ic0.msg_arg_data_size is always safe to call.
693    let len: usize = unsafe { ic0::msg_arg_data_size() as usize };
694    let mut bytes = Vec::with_capacity(len);
695    // SAFETY:
696    // `bytes`, being mutable and allocated to `len` bytes, is safe to pass to ic0.msg_arg_data_copy with no offset
697    // ic0.msg_arg_data_copy writes to all of `bytes[0..len]`, so `set_len` is safe to call with the new len.
698    unsafe {
699        ic0::msg_arg_data_copy(bytes.as_mut_ptr() as i32, 0, len as i32);
700        bytes.set_len(len);
701    }
702    bytes
703}
704
705/// Gets the len of the raw-argument-data-bytes.
706pub fn arg_data_raw_size() -> usize {
707    // SAFETY: ic0.msg_arg_data_size is always safe to call.
708    unsafe { ic0::msg_arg_data_size() as usize }
709}
710
711/// Replies with the bytes passed
712pub fn reply_raw(buf: &[u8]) {
713    if !buf.is_empty() {
714        // SAFETY: `buf`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.msg_reject.
715        unsafe { ic0::msg_reply_data_append(buf.as_ptr() as i32, buf.len() as i32) }
716    };
717    // SAFETY: ic0.msg_reply is always safe to call.
718    unsafe { ic0::msg_reply() };
719}
720
721#[derive(Debug)]
722/// Config to control the behavior of decoding canister endpoint arguments.
723pub struct ArgDecoderConfig {
724    /// Limit the total amount of work the deserializer can perform. See [docs on the Candid library](https://docs.rs/candid/latest/candid/de/struct.DecoderConfig.html#method.set_decoding_quota) to understand the cost model.
725    pub decoding_quota: Option<usize>,
726    /// Limit the total amount of work for skipping unneeded data on the wire. See [docs on the Candid library](https://docs.rs/candid/latest/candid/de/struct.DecoderConfig.html#method.set_skipping_quota) to understand the skipping cost.
727    pub skipping_quota: Option<usize>,
728    /// When set to true, print instruction count and the decoding/skipping cost to the replica log.
729    pub debug: bool,
730}
731impl ArgDecoderConfig {
732    fn to_candid_config(&self) -> DecoderConfig {
733        let mut config = DecoderConfig::new();
734        if let Some(n) = self.decoding_quota {
735            config.set_decoding_quota(n);
736        }
737        if let Some(n) = self.skipping_quota {
738            config.set_skipping_quota(n);
739        }
740        if self.debug {
741            config.set_full_error_message(true);
742        }
743        config
744    }
745}
746impl Default for ArgDecoderConfig {
747    fn default() -> Self {
748        Self {
749            decoding_quota: None,
750            skipping_quota: Some(10_000),
751            debug: false,
752        }
753    }
754}
755
756/// Returns the argument data in the current call. Traps if the data cannot be
757/// decoded.
758pub fn arg_data<R: for<'a> ArgumentDecoder<'a>>(arg_config: ArgDecoderConfig) -> R {
759    let bytes = arg_data_raw();
760
761    let config = arg_config.to_candid_config();
762    let res = decode_args_with_config_debug(&bytes, &config);
763    match res {
764        Err(e) => trap(&format!("failed to decode call arguments: {:?}", e)),
765        Ok((r, cost)) => {
766            if arg_config.debug {
767                print_decoding_debug_info("Argument", &cost, None);
768            }
769            r
770        }
771    }
772}
773
774/// Accepts the ingress message.
775pub fn accept_message() {
776    // SAFETY: ic0.accept_message is always safe to call.
777    unsafe {
778        ic0::accept_message();
779    }
780}
781
782/// Returns the name of current canister method.
783pub fn method_name() -> String {
784    // SAFETY: ic0.msg_method_name_size is always safe to call.
785    let len: u32 = unsafe { ic0::msg_method_name_size() as u32 };
786    let mut bytes = vec![0u8; len as usize];
787    // SAFETY: `bytes` is writable and allocated to `len` bytes, and therefore can be safely passed to ic0.msg_method_name_copy
788    unsafe {
789        ic0::msg_method_name_copy(bytes.as_mut_ptr() as i32, 0, len as i32);
790    }
791    String::from_utf8_lossy(&bytes).into_owned()
792}
793
794/// Gets the value of specified performance counter
795///
796/// See [`crate::api::performance_counter`].
797#[deprecated(
798    since = "0.11.3",
799    note = "This method conceptually doesn't belong to this module. Please use `ic_cdk::api::performance_counter` instead."
800)]
801pub fn performance_counter(counter_type: u32) -> u64 {
802    // SAFETY: ic0.performance_counter is always safe to call.
803    unsafe { ic0::performance_counter(counter_type as i32) as u64 }
804}
805
806/// Pretends to have the Candid type `T`, but unconditionally errors
807/// when serialized.
808///
809/// Usable, but not required, as metadata when using `#[query(manual_reply = true)]`,
810/// so an accurate Candid file can still be generated.
811#[derive(Debug, Copy, Clone, Default)]
812pub struct ManualReply<T: ?Sized>(PhantomData<T>);
813
814impl<T: ?Sized> ManualReply<T> {
815    /// Constructs a new `ManualReply`.
816    #[allow(clippy::self_named_constructors)]
817    pub const fn empty() -> Self {
818        Self(PhantomData)
819    }
820    /// Replies with the given value and returns a new `ManualReply`,
821    /// for a useful reply-then-return shortcut.
822    pub fn all<U>(value: U) -> Self
823    where
824        U: ArgumentEncoder,
825    {
826        reply(value);
827        Self::empty()
828    }
829    /// Replies with a one-element tuple around the given value and returns
830    /// a new `ManualReply`, for a useful reply-then-return shortcut.
831    pub fn one<U>(value: U) -> Self
832    where
833        U: CandidType,
834    {
835        reply((value,));
836        Self::empty()
837    }
838
839    /// Rejects the call with the specified message and returns a new
840    /// `ManualReply`, for a useful reply-then-return shortcut.
841    pub fn reject(message: impl AsRef<str>) -> Self {
842        reject(message.as_ref());
843        Self::empty()
844    }
845}
846
847impl<T> CandidType for ManualReply<T>
848where
849    T: CandidType + ?Sized,
850{
851    fn _ty() -> candid::types::Type {
852        T::_ty()
853    }
854    /// Unconditionally errors.
855    fn idl_serialize<S>(&self, _: S) -> Result<(), S::Error>
856    where
857        S: candid::types::Serializer,
858    {
859        Err(S::Error::custom("`Empty` cannot be serialized"))
860    }
861}
862
863/// Tells you whether the current async fn is being canceled due to a trap/panic.
864///
865/// If a function traps/panics, then the canister state is rewound to the beginning of the function.
866/// However, due to the way async works, the beginning of the function as the IC understands it is actually
867/// the most recent `await` from an inter-canister-call. This means that part of the function will have executed,
868/// and part of it won't.
869///
870/// When this happens the CDK will cancel the task, causing destructors to be run. If you need any functions to be run
871/// no matter what happens, they should happen in a destructor; the [`scopeguard`](https://docs.rs/scopeguard) crate
872/// provides a convenient wrapper for this. In a destructor, `is_recovering_from_trap` serves the same purpose as
873/// [std::thread::panicking] - it tells you whether the destructor is executing *because* of a trap,
874/// as opposed to just because the scope was exited, so you could e.g. implement mutex poisoning.
875pub fn is_recovering_from_trap() -> bool {
876    ic_cdk_executor::CLEANUP.load(Ordering::Relaxed)
877}