use candid::Principal;
use std::{convert::TryFrom, num::NonZeroU64};
pub fn msg_arg_data() -> Vec<u8> {
let len = ic0::msg_arg_data_size();
let mut buf = vec![0u8; len];
ic0::msg_arg_data_copy(&mut buf, 0);
buf
}
pub fn msg_caller() -> Principal {
let len = ic0::msg_caller_size();
let mut buf = vec![0u8; len];
ic0::msg_caller_copy(&mut buf, 0);
Principal::try_from(&buf).unwrap()
}
pub fn msg_caller_info_data() -> Vec<u8> {
let len = ic0::msg_caller_info_data_size();
let mut buf = vec![0u8; len];
ic0::msg_caller_info_data_copy(&mut buf, 0);
buf
}
pub fn msg_caller_info_signer() -> Option<Principal> {
let len = ic0::msg_caller_info_signer_size();
if len == 0 {
return None;
}
let mut buf = vec![0u8; len];
ic0::msg_caller_info_signer_copy(&mut buf, 0);
Some(Principal::try_from(&buf).expect("msg_caller_info_signer must be a valid principal"))
}
pub fn msg_reject_code() -> u32 {
ic0::msg_reject_code()
}
pub fn msg_reject_msg() -> String {
let len = ic0::msg_reject_msg_size();
let mut buf = vec![0u8; len];
ic0::msg_reject_msg_copy(&mut buf, 0);
String::from_utf8(buf).expect("reject message is not valid UTF-8")
}
pub fn msg_deadline() -> Option<NonZeroU64> {
let nano_seconds = ic0::msg_deadline();
match nano_seconds {
0 => None,
_ => Some(NonZeroU64::new(nano_seconds).unwrap()),
}
}
pub fn msg_reply<T: AsRef<[u8]>>(data: T) {
let buf = data.as_ref();
if !buf.is_empty() {
ic0::msg_reply_data_append(buf);
}
ic0::msg_reply();
}
pub fn msg_reject<T: AsRef<str>>(message: T) {
let message = message.as_ref();
ic0::msg_reject(message.as_bytes());
}
pub fn msg_cycles_available() -> u128 {
ic0::msg_cycles_available128()
}
pub fn msg_cycles_refunded() -> u128 {
ic0::msg_cycles_refunded128()
}
pub fn msg_cycles_accept(max_amount: u128) -> u128 {
ic0::msg_cycles_accept128(max_amount)
}
pub fn cycles_burn(amount: u128) -> u128 {
ic0::cycles_burn128(amount)
}
pub fn canister_self() -> Principal {
let len = ic0::canister_self_size();
let mut buf = vec![0u8; len];
ic0::canister_self_copy(&mut buf, 0);
Principal::try_from(&buf).unwrap()
}
pub fn canister_cycle_balance() -> u128 {
ic0::canister_cycle_balance128()
}
pub fn canister_liquid_cycle_balance() -> u128 {
ic0::canister_liquid_cycle_balance128()
}
pub fn canister_status() -> CanisterStatusCode {
ic0::canister_status().into()
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum CanisterStatusCode {
Running = 1,
Stopping = 2,
Stopped = 3,
Unrecognized(u32),
}
impl From<u32> for CanisterStatusCode {
fn from(value: u32) -> Self {
match value {
1 => Self::Running,
2 => Self::Stopping,
3 => Self::Stopped,
_ => Self::Unrecognized(value),
}
}
}
impl From<CanisterStatusCode> for u32 {
fn from(value: CanisterStatusCode) -> Self {
match value {
CanisterStatusCode::Running => 1,
CanisterStatusCode::Stopping => 2,
CanisterStatusCode::Stopped => 3,
CanisterStatusCode::Unrecognized(value) => value,
}
}
}
impl PartialEq<u32> for CanisterStatusCode {
fn eq(&self, other: &u32) -> bool {
let self_as_u32: u32 = (*self).into();
self_as_u32 == *other
}
}
pub fn canister_version() -> u64 {
ic0::canister_version()
}
pub fn subnet_self() -> Principal {
let len = ic0::subnet_self_size();
let mut buf = vec![0u8; len];
ic0::subnet_self_copy(&mut buf, 0);
Principal::try_from(&buf).unwrap()
}
pub fn msg_method_name() -> String {
let len = ic0::msg_method_name_size();
let mut buf = vec![0u8; len];
ic0::msg_method_name_copy(&mut buf, 0);
String::from_utf8(buf).expect("msg_method_name is not valid UTF-8")
}
pub fn accept_message() {
ic0::accept_message();
}
pub fn stable_size() -> u64 {
ic0::stable64_size()
}
pub fn stable_grow(new_pages: u64) -> u64 {
ic0::stable64_grow(new_pages)
}
pub fn stable_write(offset: u64, buf: &[u8]) {
ic0::stable64_write(buf, offset);
}
pub fn stable_read(offset: u64, buf: &mut [u8]) {
ic0::stable64_read(buf, offset);
}
pub fn root_key() -> Vec<u8> {
let len = ic0::root_key_size();
let mut buf = vec![0u8; len];
ic0::root_key_copy(&mut buf, 0);
buf
}
pub fn certified_data_set<T: AsRef<[u8]>>(data: T) {
let buf = data.as_ref();
ic0::certified_data_set(buf);
}
pub fn data_certificate() -> Option<Vec<u8>> {
if ic0::data_certificate_present() == 0 {
return None;
}
let n = ic0::data_certificate_size();
let mut buf = vec![0u8; n];
ic0::data_certificate_copy(&mut buf, 0);
Some(buf)
}
pub fn time() -> u64 {
ic0::time()
}
pub fn global_timer_set(timestamp: u64) -> u64 {
ic0::global_timer_set(timestamp)
}
#[inline]
pub fn performance_counter(counter_type: impl Into<PerformanceCounterType>) -> u64 {
let counter_type: u32 = counter_type.into().into();
ic0::performance_counter(counter_type)
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum PerformanceCounterType {
InstructionCounter,
CallContextInstructionCounter,
Unrecognized(u32),
}
impl From<u32> for PerformanceCounterType {
fn from(value: u32) -> Self {
match value {
0 => Self::InstructionCounter,
1 => Self::CallContextInstructionCounter,
_ => Self::Unrecognized(value),
}
}
}
impl From<PerformanceCounterType> for u32 {
fn from(value: PerformanceCounterType) -> Self {
match value {
PerformanceCounterType::InstructionCounter => 0,
PerformanceCounterType::CallContextInstructionCounter => 1,
PerformanceCounterType::Unrecognized(value) => value,
}
}
}
impl PartialEq<u32> for PerformanceCounterType {
fn eq(&self, other: &u32) -> bool {
let self_as_u32: u32 = (*self).into();
self_as_u32 == *other
}
}
#[inline]
pub fn instruction_counter() -> u64 {
performance_counter(0)
}
#[inline]
pub fn call_context_instruction_counter() -> u64 {
performance_counter(1)
}
pub fn is_controller(principal: &Principal) -> bool {
let slice = principal.as_slice();
match ic0::is_controller(slice) {
0 => false,
1 => true,
n => panic!("unexpected return value from is_controller: {n}"),
}
}
pub fn in_replicated_execution() -> bool {
match ic0::in_replicated_execution() {
0 => false,
1 => true,
n => panic!("unexpected return value from in_replicated_execution: {n}"),
}
}
pub fn cost_call(method_name_size: u64, payload_size: u64) -> u128 {
ic0::cost_call(method_name_size, payload_size)
}
pub fn cost_create_canister() -> u128 {
ic0::cost_create_canister()
}
pub fn cost_http_request(request_size: u64, max_res_bytes: u64) -> u128 {
ic0::cost_http_request(request_size, max_res_bytes)
}
#[derive(thiserror::Error, Debug, Clone)]
pub enum SignCostError {
#[error("invalid curve or algorithm")]
InvalidCurveOrAlgorithm,
#[error("invalid key name")]
InvalidKeyName,
#[error("unrecognized error: {0}")]
UnrecognizedError(u32),
}
fn sign_cost_result(dst: u128, code: u32) -> Result<u128, SignCostError> {
match code {
0 => Ok(dst),
1 => Err(SignCostError::InvalidCurveOrAlgorithm),
2 => Err(SignCostError::InvalidKeyName),
_ => Err(SignCostError::UnrecognizedError(code)),
}
}
pub fn cost_sign_with_ecdsa<T: AsRef<str>>(
key_name: T,
ecdsa_curve: u32,
) -> Result<u128, SignCostError> {
let key_name = key_name.as_ref();
let (cost, code) = ic0::cost_sign_with_ecdsa(key_name, ecdsa_curve);
sign_cost_result(cost, code)
}
pub fn cost_sign_with_schnorr<T: AsRef<str>>(
key_name: T,
algorithm: u32,
) -> Result<u128, SignCostError> {
let key_name = key_name.as_ref();
let (dst, code) = ic0::cost_sign_with_schnorr(key_name, algorithm);
sign_cost_result(dst, code)
}
pub fn cost_vetkd_derive_key<T: AsRef<str>>(
key_name: T,
vetkd_curve: u32,
) -> Result<u128, SignCostError> {
let key_name = key_name.as_ref();
let (cost, code) = ic0::cost_vetkd_derive_key(key_name, vetkd_curve);
sign_cost_result(cost, code)
}
pub fn env_var_count() -> usize {
ic0::env_var_count()
}
pub fn env_var_name(index: usize) -> String {
let len = ic0::env_var_name_size(index);
let mut buf = vec![0u8; len];
ic0::env_var_name_copy(index, &mut buf, 0);
String::from_utf8(buf).expect("env_var_name is not valid UTF-8")
}
pub fn env_var_name_exists<T: AsRef<str>>(name: T) -> bool {
match ic0::env_var_name_exists(name.as_ref()) {
0 => false,
1 => true,
n => panic!("unexpected return value from env_var_name_exists: {n}"),
}
}
pub fn env_var_value<T: AsRef<str>>(name: T) -> String {
let name = name.as_ref();
let len = ic0::env_var_value_size(name);
let mut buf = vec![0u8; len];
ic0::env_var_value_copy(name, &mut buf, 0);
String::from_utf8(buf).expect("env_var_value is not valid UTF-8")
}
pub fn debug_print<T: AsRef<str>>(data: T) {
let buf = data.as_ref();
ic0::debug_print(buf.as_bytes());
}
pub fn trap<T: AsRef<str>>(data: T) -> ! {
let buf = data.as_ref();
ic0::trap(buf.as_bytes());
}