ic_cdk/api/
call.rs

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