1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use std::future::Future;
use std::pin::Pin;

use ic_cdk::api::call::CallResult;
use ic_cdk::export::candid::utils::{ArgumentDecoder, ArgumentEncoder};
use ic_cdk::export::candid::{decode_args, encode_args};
use ic_cdk::export::{candid, Principal};

pub type CallResponse<T> = Pin<Box<dyn Future<Output = CallResult<T>>>>;

pub trait Context {
    /// Trap the code.
    fn trap(&self, message: &str) -> !;

    /// Print a message.
    fn print<S: std::convert::AsRef<str>>(&self, s: S);

    /// ID of the current canister.
    fn id(&self) -> Principal;

    /// The time in nanoseconds.
    fn time(&self) -> u64;

    /// The balance of the canister.
    fn balance(&self) -> u64;

    /// The caller who has invoked this method on the canister.
    fn caller(&self) -> Principal;

    /// Return the number of available cycles that is sent by the caller.
    fn msg_cycles_available(&self) -> u64;

    /// Accept the given amount of cycles, returns the actual amount of accepted cycles.
    fn msg_cycles_accept(&self, amount: u64) -> u64;

    /// Return the cycles that were sent back by the canister that was just called.
    /// This method should only be called right after an inter-canister call.
    fn msg_cycles_refunded(&self) -> u64;

    /// Store the given data to the storage.
    fn store<T: 'static + Default>(&self, data: T);

    /// Return the data associated with the given type. If the data is not present the default
    /// value of the type is returned.
    #[inline]
    fn get<T: 'static + Default>(&self) -> &T {
        self.get_mut()
    }

    /// Return a mutable reference to the given data type, if the data is not present the default
    /// value of the type is constructed and stored. The changes made to the data during updates
    /// is preserved.
    fn get_mut<T: 'static + Default>(&self) -> &mut T;

    /// Remove the data associated with the given data type.
    fn delete<T: 'static + Default>(&self) -> bool;

    /// Store the given data to the stable storage.
    fn stable_store<T>(&self, data: T) -> Result<(), candid::Error>
    where
        T: ArgumentEncoder;

    /// Restore the data from the stable storage. If the data is not already stored the None value
    /// is returned.
    fn stable_restore<T>(&self) -> Result<T, String>
    where
        T: for<'de> ArgumentDecoder<'de>;

    /// Perform a call.
    fn call_raw<S: Into<String>>(
        &'static self,
        id: Principal,
        method: S,
        args_raw: Vec<u8>,
        cycles: u64,
    ) -> CallResponse<Vec<u8>>;

    /// Perform the call and return the response.
    #[inline(always)]
    fn call<T: ArgumentEncoder, R: for<'a> ArgumentDecoder<'a>, S: Into<String>>(
        &'static self,
        id: Principal,
        method: S,
        args: T,
    ) -> CallResponse<R> {
        self.call_with_payment(id, method, args, 0)
    }

    #[inline(always)]
    fn call_with_payment<T: ArgumentEncoder, R: for<'a> ArgumentDecoder<'a>, S: Into<String>>(
        &'static self,
        id: Principal,
        method: S,
        args: T,
        cycles: u64,
    ) -> CallResponse<R> {
        let args_raw = encode_args(args).expect("Failed to encode arguments.");
        let method = method.into();
        Box::pin(async move {
            let bytes = self.call_raw(id, method, args_raw, cycles).await?;
            decode_args(&bytes).map_err(|err| panic!("{:?}", err))
        })
    }

    /// Set the certified data of the canister, this method traps if data.len > 32.
    fn set_certified_data(&self, data: &[u8]);

    /// Returns the data certificate authenticating certified_data set by this canister.
    fn data_certificate(&self) -> Option<Vec<u8>>;
}