ic_kit/
ic.rs

1use crate::candid::utils::{ArgumentDecoder, ArgumentEncoder};
2pub use crate::stable::*;
3use crate::{candid, CallResponse, Context, Principal, StableMemoryError};
4
5#[inline(always)]
6fn get_context() -> &'static mut impl Context {
7    #[cfg(not(target_family = "wasm"))]
8    return crate::inject::get_context();
9    #[cfg(target_family = "wasm")]
10    return crate::wasm::IcContext::context();
11}
12
13/// Trap the code.
14#[inline(always)]
15pub fn trap(message: &str) -> ! {
16    get_context().trap(message)
17}
18
19/// Print a message.
20#[inline(always)]
21pub fn print<S: AsRef<str>>(s: S) {
22    get_context().print(s)
23}
24
25/// ID of the current canister.
26#[inline(always)]
27pub fn id() -> Principal {
28    get_context().id()
29}
30
31/// The time in nanoseconds.
32#[inline(always)]
33pub fn time() -> u64 {
34    get_context().time()
35}
36
37/// The balance of the canister.
38#[inline(always)]
39pub fn balance() -> u64 {
40    get_context().balance()
41}
42
43/// The caller who has invoked this method on the canister.
44#[inline(always)]
45pub fn caller() -> Principal {
46    get_context().caller()
47}
48
49/// Return the number of available cycles that is sent by the caller.
50#[inline(always)]
51pub fn msg_cycles_available() -> u64 {
52    get_context().msg_cycles_available()
53}
54
55/// Accept the given amount of cycles, returns the actual amount of accepted cycles.
56#[inline(always)]
57pub fn msg_cycles_accept(amount: u64) -> u64 {
58    get_context().msg_cycles_accept(amount)
59}
60
61/// Return the cycles that were sent back by the canister that was just called.
62/// This method should only be called right after an inter-canister call.
63#[inline(always)]
64pub fn msg_cycles_refunded() -> u64 {
65    get_context().msg_cycles_refunded()
66}
67
68/// Store the given data to the stable storage.
69#[inline(always)]
70pub fn stable_store<T>(data: T) -> Result<(), candid::Error>
71where
72    T: ArgumentEncoder,
73{
74    get_context().stable_store(data)
75}
76
77/// Restore the data from the stable storage. If the data is not already stored the None value
78/// is returned.
79#[inline(always)]
80pub fn stable_restore<T>() -> Result<T, String>
81where
82    T: for<'de> ArgumentDecoder<'de>,
83{
84    get_context().stable_restore()
85}
86
87/// Perform a call.
88#[inline(always)]
89pub fn call_raw<S: Into<String>>(
90    id: Principal,
91    method: S,
92    args_raw: Vec<u8>,
93    cycles: u64,
94) -> CallResponse<Vec<u8>> {
95    get_context().call_raw(id, method, args_raw, cycles)
96}
97
98/// Perform the call and return the response.
99#[inline(always)]
100pub fn call<T: ArgumentEncoder, R: for<'a> ArgumentDecoder<'a>, S: Into<String>>(
101    id: Principal,
102    method: S,
103    args: T,
104) -> CallResponse<R> {
105    get_context().call_with_payment(id, method, args, 0)
106}
107
108#[inline(always)]
109pub fn call_with_payment<T: ArgumentEncoder, R: for<'a> ArgumentDecoder<'a>, S: Into<String>>(
110    id: Principal,
111    method: S,
112    args: T,
113    cycles: u64,
114) -> CallResponse<R> {
115    get_context().call_with_payment(id, method, args, cycles)
116}
117
118/// Set the certified data of the canister, this method traps if data.len > 32.
119#[inline(always)]
120pub fn set_certified_data(data: &[u8]) {
121    get_context().set_certified_data(data)
122}
123
124/// Returns the data certificate authenticating certified_data set by this canister.
125#[inline(always)]
126pub fn data_certificate() -> Option<Vec<u8>> {
127    get_context().data_certificate()
128}
129
130/// Execute a future without blocking the current call.
131#[inline(always)]
132pub fn spawn<F: 'static + std::future::Future<Output = ()>>(future: F) {
133    get_context().spawn(future)
134}
135
136/// Returns the current size of the stable memory in WebAssembly pages.
137/// (One WebAssembly page is 64KiB)
138#[inline(always)]
139pub fn stable_size() -> u32 {
140    get_context().stable_size()
141}
142
143/// Tries to grow the memory by new_pages many pages containing zeroes.
144/// This system call traps if the previous size of the memory exceeds 2^32 bytes.
145/// Errors if the new size of the memory exceeds 2^32 bytes or growing is unsuccessful.
146/// Otherwise, it grows the memory and returns the previous size of the memory in pages.
147#[inline(always)]
148pub fn stable_grow(new_pages: u32) -> Result<u32, StableMemoryError> {
149    get_context().stable_grow(new_pages)
150}
151
152/// Writes data to the stable memory location specified by an offset.
153#[inline(always)]
154pub fn stable_write(offset: u32, buf: &[u8]) {
155    get_context().stable_write(offset, buf)
156}
157
158/// Reads data from the stable memory location specified by an offset.
159#[inline(always)]
160pub fn stable_read(offset: u32, buf: &mut [u8]) {
161    get_context().stable_read(offset, buf)
162}
163
164/// Returns a copy of the stable memory.
165///
166/// This will map the whole memory (even if not all of it has been written to), we don't recommend
167/// using such a method as this is an expensive read of the entire stable storage to the heap.
168///
169/// Only use it with caution.
170pub fn stable_bytes() -> Vec<u8> {
171    let size = (stable_size() as usize) << 16;
172    let mut vec = Vec::with_capacity(size);
173    unsafe {
174        vec.set_len(size);
175    }
176
177    stable_read(0, vec.as_mut_slice());
178
179    vec
180}
181
182/// Pass an immutable reference to the value associated with the given type to the closure.
183///
184/// If no value is currently associated to the type `T`, this method will insert the default
185/// value in its place before invoking the callback. Use `maybe_with` if you don't want the
186/// default value to be inserted or if your type does not implement the [`Default`] trait.
187///
188/// This is a safe replacement for the previously known `ic_kit::ic::get` API, and you can use it
189/// instead of `lazy_static` or `local_thread`.
190///
191/// # Example
192///
193/// ```
194/// use ic_kit::*;
195///
196/// #[derive(Default)]
197/// struct Counter {
198///     count: u64
199/// }
200///
201/// impl Counter {
202///     fn get(&self) -> u64 {
203///         *self.count
204///     }
205/// }
206///
207/// MockContext::new()
208///     .with_data(Counter { count: 17 })
209///     .inject();
210///
211/// assert_eq!(ic::with(Counter::get), 17);
212/// ```
213pub fn with<T: 'static + Default, U, F: FnOnce(&T) -> U>(callback: F) -> U {
214    get_context().with(callback)
215}
216
217/// Like [`with`], but does not initialize the data with the default value and simply returns None,
218/// if there is no value associated with the type.
219pub fn maybe_with<T: 'static, U, F: FnOnce(&T) -> U>(callback: F) -> Option<U> {
220    get_context().maybe_with(callback)
221}
222
223/// Pass a mutable reference to the value associated with the given type to the closure.
224///
225/// If no value is currently associated to the type `T`, this method will insert the default
226/// value in its place before invoking the callback. Use `maybe_with_mut` if you don't want the
227/// default value to be inserted or if your type does not implement the [`Default`] trait.
228///
229/// This is a safe replacement for the previously known `ic_kit::ic::get` API, and you can use it
230/// instead of `lazy_static` or `local_thread`.
231///
232/// # Example
233///
234/// ```
235/// use ic_kit::*;
236///
237/// #[derive(Default)]
238/// struct Counter {
239///     count: u64
240/// }
241///
242/// impl Counter {
243///     fn increment(&mut self) -> u64 {
244///         self.count += 1;
245///         *self.count
246///     }
247/// }
248///
249/// MockContext::new()
250///     .with_data(Counter { count: 17 })
251///     .inject();
252///
253/// assert_eq!(ic::with_mut(Counter::increment), 18);
254/// ```
255pub fn with_mut<T: 'static + Default, U, F: FnOnce(&mut T) -> U>(callback: F) -> U {
256    get_context().with_mut(callback)
257}
258
259/// Like [`with_mut`], but does not initialize the data with the default value and simply returns
260/// None, if there is no value associated with the type.
261pub fn maybe_with_mut<T: 'static, U, F: FnOnce(&mut T) -> U>(callback: F) -> Option<U> {
262    get_context().maybe_with_mut(callback)
263}
264
265/// Remove the current value associated with the type and return it.
266pub fn take<T: 'static>() -> Option<T> {
267    get_context().take::<T>()
268}
269
270/// Swaps the value associated with type `T` with the given value, returns the old one.
271pub fn swap<T: 'static>(value: T) -> Option<T> {
272    get_context().swap(value)
273}
274
275/// Store the given data to the storage.
276#[inline(always)]
277#[deprecated(
278    since = "0.4.8",
279    note = "Unsafe memory methods are deprecated, use the safer ic_kit::ic::swap method."
280)]
281pub fn store<T: 'static>(data: T) {
282    get_context().store(data)
283}
284
285/// Return the data that does not implement [`Default`].
286#[inline(always)]
287#[deprecated(
288    since = "0.4.8",
289    note = "Unsafe memory methods are deprecated, use the safer ic_kit::ic::maybe_with method."
290)]
291pub fn get_maybe<T: 'static>() -> Option<&'static T> {
292    get_context().get_maybe()
293}
294
295/// Return the data associated with the given type. If the data is not present the default
296/// value of the type is returned.
297#[inline(always)]
298#[deprecated(
299    since = "0.4.8",
300    note = "Unsafe memory methods are deprecated, use the safer ic_kit::ic::with method."
301)]
302pub fn get<T: 'static + Default>() -> &'static T {
303    get_context().get_mut()
304}
305
306/// Return a mutable reference to the given data type, if the data is not present the default
307/// value of the type is constructed and stored. The changes made to the data during updates
308/// is preserved.
309#[inline(always)]
310#[deprecated(
311    since = "0.4.8",
312    note = "Unsafe memory methods are deprecated, use the safer ic_kit::ic::with method."
313)]
314pub fn get_mut<T: 'static + Default>() -> &'static mut T {
315    get_context().get_mut()
316}
317
318/// Remove the data associated with the given data type.
319#[inline(always)]
320#[deprecated(
321    since = "0.4.8",
322    note = "Unsafe memory methods are deprecated, use the safer ic_kit::ic::take method."
323)]
324pub fn delete<T: 'static + Default>() -> bool {
325    get_context().delete::<T>()
326}