Skip to main content

ic_cdk/
api.rs

1//! System API bindings.
2//!
3//! This module provides Rust ergonomic bindings to the system APIs.
4//!
5//! Some APIs require more advanced handling and are organized into separate modules:
6//! * For the inter-canister calls API, see the [`call`](mod@crate::call) module.
7//! * For the stable memory management API, see the .
8//!   * The basic bindings are provided in this module including [`stable_size`], [`stable_grow`], [`stable_read`] and [`stable_write`].
9//!   * The [`stable`](crate::stable) module provides more advanced functionalities, e.g. support for `std::io` traits.
10//!
11//! APIs that are only available for `wasm32` are not included.
12//! As a result, system APIs with a numeric postfix (indicating the data bit width) are bound to names without the postfix.
13//! For example, `ic0::msg_cycles_available128` is bound to [`msg_cycles_available`], while `ic0::msg_cycles_available` has no binding.
14//!
15//! Functions that provide bindings for a single system API method share the same name as the system API.
16//! For example, `ic0::msg_reject_code` is bound to [`msg_reject_code`].
17//!
18//! Functions that wrap multiple system API methods are named using the common prefix of the wrapped methods.
19//! For example, [`msg_arg_data`] wraps both `ic0::msg_arg_data_size` and `ic0::msg_arg_data_copy`.
20
21use candid::Principal;
22use std::{convert::TryFrom, num::NonZeroU64};
23
24/// Gets the message argument data.
25pub fn msg_arg_data() -> Vec<u8> {
26    let len = ic0::msg_arg_data_size();
27    let mut buf = vec![0u8; len];
28    ic0::msg_arg_data_copy(&mut buf, 0);
29    buf
30}
31
32/// Gets the identity of the caller, which may be a canister id or a user id.
33///
34/// During canister installation or upgrade, this is the id of the user or canister requesting the installation or upgrade.
35/// During a system task (heartbeat or global timer), this is the id of the management canister.
36pub fn msg_caller() -> Principal {
37    let len = ic0::msg_caller_size();
38    let mut buf = vec![0u8; len];
39    ic0::msg_caller_copy(&mut buf, 0);
40    // Trust that the system always returns a valid principal.
41    Principal::try_from(&buf).unwrap()
42}
43
44/// Gets auxiliary data about the caller as provided by the canister with which the caller's identity is associated.
45///
46/// This only returns non-empty data if the caller is a self-authenticating principal authenticated
47/// by canister signatures (e.g. Internet Identity). Returns empty bytes when the caller is another canister.
48///
49/// The data is guaranteed to be signed by the canister returned from [`msg_caller_info_signer`],
50/// so the signer should be checked before trusting the payload.
51///
52/// ```rust,no_run
53/// use ic_cdk::api::{msg_caller_info_data, msg_caller_info_signer};
54///
55/// if msg_caller_info_signer().is_some() {
56///     let data = msg_caller_info_data();
57///     // Decode per the signer's documented format (e.g. identity attributes).
58/// }
59/// ```
60pub fn msg_caller_info_data() -> Vec<u8> {
61    let len = ic0::msg_caller_info_data_size();
62    let mut buf = vec![0u8; len];
63    ic0::msg_caller_info_data_copy(&mut buf, 0);
64    buf
65}
66
67/// Gets the canister ID of the canister that provided the caller's canister signature.
68///
69/// Returns `None` if the caller is not a self-authenticating principal authenticated by canister
70/// signatures (e.g. when the caller is another canister or no sender info was provided).
71///
72/// ```rust,no_run
73/// use ic_cdk::api::msg_caller_info_signer;
74/// use candid::Principal;
75///
76/// let trusted_issuer = Principal::from_text("rdmx6-jaaaa-aaaaa-aaadq-cai").unwrap();
77/// if msg_caller_info_signer() == Some(trusted_issuer) {
78///     // Caller's identity was attested by the trusted issuer (e.g. Internet Identity).
79/// }
80/// ```
81pub fn msg_caller_info_signer() -> Option<Principal> {
82    let len = ic0::msg_caller_info_signer_size();
83    if len == 0 {
84        return None;
85    }
86    let mut buf = vec![0u8; len];
87    ic0::msg_caller_info_signer_copy(&mut buf, 0);
88    // Trust that the system always returns a valid principal when non-empty.
89    Some(Principal::try_from(&buf).expect("msg_caller_info_signer must be a valid principal"))
90}
91
92/// Returns the reject code, if the current function is invoked as a reject callback.
93pub fn msg_reject_code() -> u32 {
94    ic0::msg_reject_code()
95}
96
97/// Gets the reject message.
98///
99/// This function can only be called in the reject callback.
100///
101/// Traps if:
102/// - There is no reject message (i.e. if `reject_code` is 0).
103/// - The message is not valid UTF-8.
104pub fn msg_reject_msg() -> String {
105    let len = ic0::msg_reject_msg_size();
106    let mut buf = vec![0u8; len];
107    ic0::msg_reject_msg_copy(&mut buf, 0);
108    String::from_utf8(buf).expect("reject message is not valid UTF-8")
109}
110
111/// Gets the deadline, in nanoseconds since 1970-01-01, after which the caller might stop waiting for a response.
112///
113/// For calls to update methods with best-effort responses and their callbacks,
114/// the deadline is computed based on the time the call was made,
115/// and the `timeout_seconds` parameter provided by the caller.
116/// In such cases, the deadline value will be converted to `NonZeroU64` and wrapped in `Some`.
117/// To get the deadline value as a `u64`, call `get()` on the `NonZeroU64` value.
118///
119/// ```rust,no_run
120/// use ic_cdk::api::msg_deadline;
121/// if let Some(deadline) = msg_deadline() {
122///     let deadline_value : u64 = deadline.get();
123/// }
124/// ```
125///
126/// For other calls (ingress messages and all calls to query and composite query methods,
127/// including calls in replicated mode), a `None` is returned.
128/// Please note that the raw `msg_deadline` system API returns 0 in such cases.
129/// This function is a wrapper around the raw system API that provides more semantic information through the return type.
130pub fn msg_deadline() -> Option<NonZeroU64> {
131    let nano_seconds = ic0::msg_deadline();
132    match nano_seconds {
133        0 => None,
134        _ => Some(NonZeroU64::new(nano_seconds).unwrap()),
135    }
136}
137
138/// Replies to the sender with the data.
139pub fn msg_reply<T: AsRef<[u8]>>(data: T) {
140    let buf = data.as_ref();
141    if !buf.is_empty() {
142        ic0::msg_reply_data_append(buf);
143    }
144    ic0::msg_reply();
145}
146
147/// Rejects the call with a diagnostic message.
148pub fn msg_reject<T: AsRef<str>>(message: T) {
149    let message = message.as_ref();
150    ic0::msg_reject(message.as_bytes());
151}
152
153/// Gets the number of cycles transferred by the caller of the current call, still available in this message.
154pub fn msg_cycles_available() -> u128 {
155    ic0::msg_cycles_available128()
156}
157
158/// Gets the amount of cycles that came back with the response as a refund
159///
160/// This function can only be used in a callback handler (reply or reject).
161/// The refund has already been added to the canister balance automatically.
162pub fn msg_cycles_refunded() -> u128 {
163    ic0::msg_cycles_refunded128()
164}
165
166/// Moves cycles from the call to the canister balance.
167///
168/// The actual amount moved will be returned.
169pub fn msg_cycles_accept(max_amount: u128) -> u128 {
170    ic0::msg_cycles_accept128(max_amount)
171}
172
173/// Burns cycles from the canister.
174///
175/// Returns the amount of cycles that were actually burned.
176pub fn cycles_burn(amount: u128) -> u128 {
177    ic0::cycles_burn128(amount)
178}
179
180/// Gets canister's own identity.
181pub fn canister_self() -> Principal {
182    let len = ic0::canister_self_size();
183    let mut buf = vec![0u8; len];
184    ic0::canister_self_copy(&mut buf, 0);
185    // Trust that the system always returns a valid principal.
186    Principal::try_from(&buf).unwrap()
187}
188
189/// Gets the current cycle balance of the canister.
190pub fn canister_cycle_balance() -> u128 {
191    ic0::canister_cycle_balance128()
192}
193
194/// Gets the current amount of cycles that is available for spending in calls and execution.
195pub fn canister_liquid_cycle_balance() -> u128 {
196    ic0::canister_liquid_cycle_balance128()
197}
198
199/// Gets the status of the canister.
200///
201/// The status is one of the following:
202/// - 1: Running
203/// - 2: Stopping
204/// - 3: Stopped
205pub fn canister_status() -> CanisterStatusCode {
206    ic0::canister_status().into()
207}
208
209/// The status of a canister.
210///
211/// See [Canister status](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-canister-status).
212#[derive(Debug, PartialEq, Eq, Clone, Copy)]
213#[repr(u32)]
214pub enum CanisterStatusCode {
215    /// Running.
216    Running = 1,
217    /// Stopping.
218    Stopping = 2,
219    /// Stopped.
220    Stopped = 3,
221    /// A status code that is not recognized by this library.
222    Unrecognized(u32),
223}
224
225impl From<u32> for CanisterStatusCode {
226    fn from(value: u32) -> Self {
227        match value {
228            1 => Self::Running,
229            2 => Self::Stopping,
230            3 => Self::Stopped,
231            _ => Self::Unrecognized(value),
232        }
233    }
234}
235
236impl From<CanisterStatusCode> for u32 {
237    fn from(value: CanisterStatusCode) -> Self {
238        match value {
239            CanisterStatusCode::Running => 1,
240            CanisterStatusCode::Stopping => 2,
241            CanisterStatusCode::Stopped => 3,
242            CanisterStatusCode::Unrecognized(value) => value,
243        }
244    }
245}
246
247impl PartialEq<u32> for CanisterStatusCode {
248    fn eq(&self, other: &u32) -> bool {
249        let self_as_u32: u32 = (*self).into();
250        self_as_u32 == *other
251    }
252}
253
254/// Gets the canister version.
255///
256/// See [Canister version](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-canister-version).
257pub fn canister_version() -> u64 {
258    ic0::canister_version()
259}
260
261/// Gets the ID of the subnet on which the canister is running.
262pub fn subnet_self() -> Principal {
263    let len = ic0::subnet_self_size();
264    let mut buf = vec![0u8; len];
265    ic0::subnet_self_copy(&mut buf, 0);
266    // Trust that the system always returns a valid principal.
267    Principal::try_from(&buf).unwrap()
268}
269
270/// Gets the number of nodes on the subnet on which the canister is running.
271pub fn subnet_self_node_count() -> u32 {
272    ic0::subnet_self_node_count()
273}
274
275/// Gets the name of the method to be inspected.
276///
277/// This function is only available in the `canister_inspect_message` context.
278///
279/// Traps if the method name is not valid UTF-8.
280pub fn msg_method_name() -> String {
281    let len = ic0::msg_method_name_size();
282    let mut buf = vec![0u8; len];
283    ic0::msg_method_name_copy(&mut buf, 0);
284    String::from_utf8(buf).expect("msg_method_name is not valid UTF-8")
285}
286
287/// Accepts the message in `canister_inspect_message`.
288///
289/// This function is only available in the `canister_inspect_message` context.
290/// This function traps if invoked twice.
291pub fn accept_message() {
292    ic0::accept_message();
293}
294
295/// Gets the current size of the stable memory (in WebAssembly pages).
296///
297/// One WebAssembly page is 64KiB.
298pub fn stable_size() -> u64 {
299    ic0::stable64_size()
300}
301
302/// Attempts to grow the stable memory by `new_pages` many pages containing zeroes.
303///
304/// One WebAssembly page is 64KiB.
305///
306/// If successful, returns the previous size of the memory (in pages).
307/// Otherwise, returns `u64::MAX`.
308pub fn stable_grow(new_pages: u64) -> u64 {
309    ic0::stable64_grow(new_pages)
310}
311
312/// Writes data to the stable memory location specified by an offset.
313///
314/// # Warning
315/// This will panic if `offset + buf.len()` exceeds the current size of stable memory.
316/// Call [`stable_grow`] to request more stable memory if needed.
317pub fn stable_write(offset: u64, buf: &[u8]) {
318    ic0::stable64_write(buf, offset);
319}
320
321/// Reads data from the stable memory location specified by an offset.
322///
323/// # Warning
324/// This will panic if `offset + buf.len()` exceeds the current size of stable memory.
325pub fn stable_read(offset: u64, buf: &mut [u8]) {
326    ic0::stable64_read(buf, offset);
327}
328
329/// Gets the public key (a DER-encoded BLS key) of the root key of this instance of the Internet Computer Protocol.
330///
331/// # Note
332///
333/// This traps in non-replicated mode.
334pub fn root_key() -> Vec<u8> {
335    let len = ic0::root_key_size();
336    let mut buf = vec![0u8; len];
337    ic0::root_key_copy(&mut buf, 0);
338    buf
339}
340
341/// Sets the certified data of this canister.
342///
343/// Canisters can store up to 32 bytes of data that is certified by
344/// the system on a regular basis.  One can call [`data_certificate`]
345/// function from a query call to get a certificate authenticating the
346/// value set by calling this function.
347///
348/// This function can only be called from the following contexts:
349/// - `canister_init`, `canister_pre_upgrade` and `canister_post_upgrade`
350///   hooks.
351/// - `canister_update` calls.
352/// - reply or reject callbacks.
353///
354/// # Panics
355///
356/// - This function traps if `data.len() > 32`.
357/// - This function traps if it's called from an illegal context
358///   (e.g., from a query call).
359pub fn certified_data_set<T: AsRef<[u8]>>(data: T) {
360    let buf = data.as_ref();
361    ic0::certified_data_set(buf);
362}
363
364/// When called from a query call, returns the data certificate authenticating
365/// certified data set by this canister.
366///
367/// Returns `None` if called not from a query call.
368pub fn data_certificate() -> Option<Vec<u8>> {
369    if ic0::data_certificate_present() == 0 {
370        return None;
371    }
372    let n = ic0::data_certificate_size();
373    let mut buf = vec![0u8; n];
374    ic0::data_certificate_copy(&mut buf, 0);
375    Some(buf)
376}
377
378/// Gets current timestamp, in nanoseconds since the epoch (1970-01-01)
379pub fn time() -> u64 {
380    ic0::time()
381}
382
383/// Sets global timer.
384///
385/// The canister can set a global timer to make the system
386/// schedule a call to the exported `canister_global_timer`
387/// Wasm method after the specified time.
388/// The time must be provided as nanoseconds since 1970-01-01.
389///
390/// The function returns the previous value of the timer.
391/// If no timer is set before invoking the function, then the function returns zero.
392///
393/// Passing zero as an argument to the function deactivates the timer and thus
394/// prevents the system from scheduling calls to the canister's `canister_global_timer` Wasm method.
395pub fn global_timer_set(timestamp: u64) -> u64 {
396    ic0::global_timer_set(timestamp)
397}
398
399/// Gets the value of specified performance counter.
400///
401/// See [`PerformanceCounterType`] for available counter types.
402#[inline]
403pub fn performance_counter(counter_type: impl Into<PerformanceCounterType>) -> u64 {
404    let counter_type: u32 = counter_type.into().into();
405    ic0::performance_counter(counter_type)
406}
407
408/// The type of performance counter.
409#[derive(Debug, PartialEq, Eq, Clone, Copy)]
410#[repr(u32)]
411pub enum PerformanceCounterType {
412    /// Current execution instruction counter.
413    ///
414    /// The number of WebAssembly instructions the canister has executed
415    /// since the beginning of the current Message execution.
416    InstructionCounter,
417    /// Call context instruction counter
418    ///
419    /// The number of WebAssembly instructions the canister has executed
420    /// within the call context of the current Message execution
421    /// since Call context creation.
422    /// The counter monotonically increases across all message executions
423    /// in the call context until the corresponding call context is removed.
424    CallContextInstructionCounter,
425    /// A performance counter type that is not recognized by this library.
426    Unrecognized(u32),
427}
428
429impl From<u32> for PerformanceCounterType {
430    fn from(value: u32) -> Self {
431        match value {
432            0 => Self::InstructionCounter,
433            1 => Self::CallContextInstructionCounter,
434            _ => Self::Unrecognized(value),
435        }
436    }
437}
438
439impl From<PerformanceCounterType> for u32 {
440    fn from(value: PerformanceCounterType) -> Self {
441        match value {
442            PerformanceCounterType::InstructionCounter => 0,
443            PerformanceCounterType::CallContextInstructionCounter => 1,
444            PerformanceCounterType::Unrecognized(value) => value,
445        }
446    }
447}
448
449impl PartialEq<u32> for PerformanceCounterType {
450    fn eq(&self, other: &u32) -> bool {
451        let self_as_u32: u32 = (*self).into();
452        self_as_u32 == *other
453    }
454}
455
456/// Returns the number of instructions that the canister executed since the last [entry
457/// point](https://internetcomputer.org/docs/current/references/ic-interface-spec/#entry-points).
458#[inline]
459pub fn instruction_counter() -> u64 {
460    performance_counter(0)
461}
462
463/// Returns the number of WebAssembly instructions the canister has executed
464/// within the call context of the current Message execution since
465/// Call context creation.
466///
467/// The counter monotonically increases across all message executions
468/// in the call context until the corresponding call context is removed.
469#[inline]
470pub fn call_context_instruction_counter() -> u64 {
471    performance_counter(1)
472}
473
474/// Determines if a Principal is a controller of the canister.
475pub fn is_controller(principal: &Principal) -> bool {
476    let slice = principal.as_slice();
477    match ic0::is_controller(slice) {
478        0 => false,
479        1 => true,
480        n => panic!("unexpected return value from is_controller: {n}"),
481    }
482}
483
484/// Checks if in replicated execution.
485///
486/// The canister can check whether it is currently running in replicated or non replicated execution.
487pub fn in_replicated_execution() -> bool {
488    match ic0::in_replicated_execution() {
489        0 => false,
490        1 => true,
491        n => panic!("unexpected return value from in_replicated_execution: {n}"),
492    }
493}
494
495/// Gets the amount of cycles that a canister needs to be above the freezing threshold in order to successfully make an inter-canister call.
496pub fn cost_call(method_name_size: u64, payload_size: u64) -> u128 {
497    ic0::cost_call(method_name_size, payload_size)
498}
499
500/// Gets the cycle cost of the Management canister method [`create_canister`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-create_canister).
501pub fn cost_create_canister() -> u128 {
502    ic0::cost_create_canister()
503}
504
505/// Gets the cycle cost of the Management canister method [`http_request`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-http_request).
506pub fn cost_http_request(request_size: u64, max_res_bytes: u64) -> u128 {
507    ic0::cost_http_request(request_size, max_res_bytes)
508}
509
510/// Gets the cycle cost of a canister HTTPS outcall priced with pricing version `2`.
511///
512/// This prices both [`http_request`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-http_request)
513/// with `pricing_version` set to `2` and
514/// [`flexible_http_request`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-flexible_http_request),
515/// which is always priced this way.
516///
517/// `params` must be the Candid encoding of the parameter record documented for
518/// [`ic0.cost_http_request_v2`](https://internetcomputer.org/docs/references/ic-interface-spec#system-api-cycle-cost).
519/// This function traps if it is not.
520///
521/// Prefer the typed wrappers in the `ic-cdk-management-canister` crate, which build and encode
522/// the record for you.
523pub fn cost_http_request_v2(params: &[u8]) -> u128 {
524    ic0::cost_http_request_v2(params)
525}
526
527/// The error type for [`cost_sign_with_ecdsa`] and [`cost_sign_with_schnorr`].
528#[derive(thiserror::Error, Debug, Clone)]
529pub enum SignCostError {
530    /// The ECDSA/vetKD curve or Schnorr algorithm is invalid.
531    #[error("invalid curve or algorithm")]
532    InvalidCurveOrAlgorithm,
533
534    /// The key name is invalid for the provided curve or algorithm.
535    #[error("invalid key name")]
536    InvalidKeyName,
537    /// Unrecognized error.
538    ///
539    /// This error is returned when the System API returns an unrecognized error code.
540    /// Please report to ic-cdk maintainers.
541    #[error("unrecognized error: {0}")]
542    UnrecognizedError(u32),
543}
544
545/// Helper function to handle the result of a signature cost function.
546fn sign_cost_result(dst: u128, code: u32) -> Result<u128, SignCostError> {
547    match code {
548        0 => Ok(dst),
549        1 => Err(SignCostError::InvalidCurveOrAlgorithm),
550        2 => Err(SignCostError::InvalidKeyName),
551        _ => Err(SignCostError::UnrecognizedError(code)),
552    }
553}
554
555/// Gets the cycle cost of the Management canister method [`sign_with_ecdsa`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-sign_with_ecdsa).
556///
557/// # Errors
558///
559/// This function will return an error if the `key_name` or the `ecdsa_curve` is invalid.
560/// The error type [`SignCostError`] provides more information about the reason of the error.
561pub fn cost_sign_with_ecdsa<T: AsRef<str>>(
562    key_name: T,
563    ecdsa_curve: u32,
564) -> Result<u128, SignCostError> {
565    let key_name = key_name.as_ref();
566    let (cost, code) = ic0::cost_sign_with_ecdsa(key_name, ecdsa_curve);
567    sign_cost_result(cost, code)
568}
569
570/// Gets the cycle cost of the Management canister method [`sign_with_schnorr`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-sign_with_schnorr).
571///
572/// # Errors
573///
574/// This function will return an error if the `key_name` or the `algorithm` is invalid.
575/// The error type [`SignCostError`] provides more information about the reason of the error.
576pub fn cost_sign_with_schnorr<T: AsRef<str>>(
577    key_name: T,
578    algorithm: u32,
579) -> Result<u128, SignCostError> {
580    let key_name = key_name.as_ref();
581    let (dst, code) = ic0::cost_sign_with_schnorr(key_name, algorithm);
582    sign_cost_result(dst, code)
583}
584
585/// Gets the cycle cost of the Management canister method [`vetkd_derive_key`](https://github.com/dfinity/portal/pull/3763).
586///
587/// Later, the description will be available in [the interface spec](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-vetkd_derive_key).
588///
589/// # Errors
590///
591/// This function will return an error if the `key_name` or the `vetkd_curve` is invalid.
592/// The error type [`SignCostError`] provides more information about the reason of the error.
593pub fn cost_vetkd_derive_key<T: AsRef<str>>(
594    key_name: T,
595    vetkd_curve: u32,
596) -> Result<u128, SignCostError> {
597    let key_name = key_name.as_ref();
598    let (cost, code) = ic0::cost_vetkd_derive_key(key_name, vetkd_curve);
599    sign_cost_result(cost, code)
600}
601
602/// Gets the number of environment variables available in the canister.
603pub fn env_var_count() -> usize {
604    ic0::env_var_count()
605}
606
607/// Gets the size of the name of the environment variable at the given index.
608///
609/// # Panics
610///
611/// This function traps if:
612/// - The index is out of bounds (>= than value provided by [`env_var_count`])
613/// - The name is not valid UTF-8.
614pub fn env_var_name(index: usize) -> String {
615    let len = ic0::env_var_name_size(index);
616    let mut buf = vec![0u8; len];
617    ic0::env_var_name_copy(index, &mut buf, 0);
618    String::from_utf8(buf).expect("env_var_name is not valid UTF-8")
619}
620
621/// Checks if the environment variable with the given name exists.
622///
623/// # Panics
624///
625/// This function traps if the length of `name` exceeds `MAX_ENV_VAR_NAME_LENGTH`.
626pub fn env_var_name_exists<T: AsRef<str>>(name: T) -> bool {
627    match ic0::env_var_name_exists(name.as_ref()) {
628        0 => false,
629        1 => true,
630        n => panic!("unexpected return value from env_var_name_exists: {n}"),
631    }
632}
633
634/// Gets the value of the environment variable with the given name.
635///
636/// It's recommended to use [`env_var_name_exists`] to check if the variable exists before calling this function.
637///
638/// # Panics
639///
640/// This function traps if:
641/// - The length of `name` exceeds `MAX_ENV_VAR_NAME_LENGTH`.
642/// - The name does not match any existing environment variable.
643/// - The value is not valid UTF-8.
644pub fn env_var_value<T: AsRef<str>>(name: T) -> String {
645    let name = name.as_ref();
646    let len = ic0::env_var_value_size(name);
647    let mut buf = vec![0u8; len];
648    ic0::env_var_value_copy(name, &mut buf, 0);
649    String::from_utf8(buf).expect("env_var_value is not valid UTF-8")
650}
651
652/// Emits textual trace messages.
653///
654/// On the "real" network, these do not do anything.
655///
656/// When executing in an environment that supports debugging, this copies out the data
657/// and logs, prints or stores it in an environment-appropriate way.
658pub fn debug_print<T: AsRef<str>>(data: T) {
659    let buf = data.as_ref();
660    ic0::debug_print(buf.as_bytes());
661}
662
663/// Traps with the given message.
664///
665/// The environment may copy out the data and log, print or store it in an environment-appropriate way,
666/// or include it in system-generated reject messages where appropriate.
667pub fn trap<T: AsRef<str>>(data: T) -> ! {
668    let buf = data.as_ref();
669    ic0::trap(buf.as_bytes());
670}