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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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>>>>;

/// A possible error value when dealing with stable memory.
pub struct StableMemoryError();

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>(&self, data: T);

    /// Return the data that does not implement [`Default`].
    fn get_maybe<T: 'static>(&self) -> Option<&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>>;

    /// Execute a future without blocking the current call.
    fn spawn<F: 'static + std::future::Future<Output = ()>>(&mut self, future: F);

    /// Returns the current size of the stable memory in WebAssembly pages.
    /// (One WebAssembly page is 64KiB)
    fn stable_size(&self) -> u32;

    /// Tries to grow the memory by new_pages many pages containing zeroes.
    /// This system call traps if the previous size of the memory exceeds 2^32 bytes.
    /// Errors if the new size of the memory exceeds 2^32 bytes or growing is unsuccessful.
    /// Otherwise, it grows the memory and returns the previous size of the memory in pages.
    fn stable_grow(&self, new_pages: u32) -> Result<u32, StableMemoryError>;

    /// Writes data to the stable memory location specified by an offset.
    fn stable_write(&self, offset: u32, buf: &[u8]);

    /// Reads data from the stable memory location specified by an offset.
    fn stable_read(&self, offset: u32, buf: &mut [u8]);
}