1#[cfg(not(target_family = "wasm"))]
2thread_local!(static HANDLER: std::cell::RefCell<Option<Box<dyn Ic0CallHandler>>> = std::cell::RefCell::new(None));
3
4#[cfg(not(target_family = "wasm"))]
10pub fn register_handler<H: Ic0CallHandler + 'static>(handler: H) {
11 HANDLER.with(|c| {
12 let _ = c.borrow_mut().insert(Box::new(handler));
13 });
14}
15
16macro_rules! _ic0_module_ret {
17 ( ( $_: ident : $t: ty ) ) => {
18 $t
19 };
20 ( ( $_i1: ident : $t1: ty , $_i2: ident : $t2: ty) ) => {
21 ($t1, $t2)
22 };
23 ( ( $t: ty ) ) => {
24 $t
25 };
26 ( $t: ty ) => {
27 $t
28 };
29}
30
31macro_rules! ic0_module {
32 ( $( ic0. $name: ident : ( $( $argname: ident : $argtype: ty ),* ) -> $rettype: tt ; )+ ) => {
33 #[allow(improper_ctypes)]
34 #[cfg(target_family = "wasm")]
35 #[link(wasm_import_module = "ic0")]
36 extern "C" {
37 $(pub fn $name($( $argname: $argtype, )*) -> _ic0_module_ret!($rettype) ;)*
38 }
39
40 #[cfg(not(target_family = "wasm"))]
42 pub trait Ic0CallHandler {
43 $(
44 fn $name(&mut self, $($argname: $argtype,)*) -> _ic0_module_ret!($rettype);
45 )*
46 }
47
48 #[cfg(not(target_family = "wasm"))]
51 pub mod runtime {
52 use futures::executor::block_on;
53 use super::Ic0CallHandler;
54
55 #[derive(Debug)]
57 pub enum Response {
58 None,
59 Isize(isize),
60 I32(i32),
61 I64(i64),
62 Trap(String),
63 }
64
65 impl From<()> for Response {
66 #[inline(always)]
67 fn from(_: ()) -> Self {
68 Response::None
69 }
70 }
71
72 impl Into<()> for Response {
73 #[inline(always)]
74 fn into(self) -> () {
75 match self {
76 Response::None => (),
77 Response::Trap(m) => panic!("Canister trapped: {}", m),
78 _ => panic!("unexpected type cast."),
79 }
80 }
81 }
82
83 impl From<isize> for Response {
84 #[inline(always)]
85 fn from(n: isize) -> Self {
86 Response::Isize(n)
87 }
88 }
89
90 impl Into<isize> for Response {
91 #[inline(always)]
92 fn into(self) -> isize {
93 match self {
94 Response::Isize(n) => n,
95 Response::Trap(m) => panic!("Canister trapped: {}", m),
96 _ => panic!("unexpected type cast."),
97 }
98 }
99 }
100
101 impl From<i32> for Response {
102 #[inline(always)]
103 fn from(n: i32) -> Self {
104 Response::I32(n)
105 }
106 }
107
108 impl Into<i32> for Response {
109 #[inline(always)]
110 fn into(self) -> i32 {
111 match self {
112 Response::I32(n) => n,
113 Response::Trap(m) => panic!("Canister trapped: {}", m),
114 _ => panic!("unexpected type cast."),
115 }
116 }
117 }
118
119 impl From<i64> for Response {
120 #[inline(always)]
121 fn from(n: i64) -> Self {
122 Response::I64(n)
123 }
124 }
125
126 impl Into<i64> for Response {
127 #[inline(always)]
128 fn into(self) -> i64 {
129 match self {
130 Response::I64(n) => n,
131 Response::Trap(m) => panic!("Canister trapped: {}", m),
132 _ => panic!("unexpected type cast."),
133 }
134 }
135 }
136
137 impl From<String> for Response {
138 #[inline(always)]
139 fn from(m: String) -> Self {
140 Response::Trap(m)
141 }
142 }
143
144 pub trait Ic0CallHandlerProxy {
146 $(
147 fn $name(&mut self, $($argname: $argtype,)*) -> Result<_ic0_module_ret!($rettype), String>;
148 )*
149 }
150
151 #[derive(Debug)]
153 #[allow(non_camel_case_types)]
154 pub enum Request {
155 $(
156 $name {
157 $($argname: $argtype,)*
158 },
159 )*
160 }
161
162 impl Request {
163 #[inline(always)]
165 pub fn proxy<H: Ic0CallHandlerProxy>(self, handler: &mut H) -> Response {
166 match self {
167 $(
168 Request::$name { $($argname,)* } => handler.$name($($argname,)*)
169 .map(Response::from)
170 .unwrap_or_else(Response::from),
171 )*
172 }
173 }
174 }
175
176 pub struct RuntimeHandle {
179 rx: tokio::sync::mpsc::Receiver<Response>,
180 tx: tokio::sync::mpsc::Sender<Request>,
181 }
182
183 impl RuntimeHandle {
184 pub fn new(
185 rx: tokio::sync::mpsc::Receiver<Response>,
186 tx: tokio::sync::mpsc::Sender<Request>,
187 ) -> Self {
188 Self {
189 rx,
190 tx
191 }
192 }
193 }
194
195 impl Ic0CallHandler for RuntimeHandle {
196 $(
197 fn $name(&mut self, $($argname: $argtype,)*) -> _ic0_module_ret!($rettype) {
198 block_on(async {
199 self.tx
200 .send(Request::$name {$($argname,)*})
201 .await
202 .expect("ic-kit-runtime: Failed to send message from canister thread.");
203 self.rx.recv().await.expect("Channel closed").into()
204 })
205 }
206 )*
207 }
208 }
209
210 $(
211 #[cfg(not(target_family = "wasm"))]
212 pub unsafe fn $name($( $argname: $argtype, )*) -> _ic0_module_ret!($rettype) {
213 HANDLER.with(|handler| {
214 std::cell::RefMut::map(handler.borrow_mut(), |h| {
215 h.as_mut().expect("No handler set for current thread.")
216 })
217 .$name($( $argname, )*)
218 })
219 }
220 )*
221 };
222}
223
224ic0_module! {
242 ic0.msg_arg_data_size : () -> isize; ic0.msg_arg_data_copy : (dst : isize, offset : isize, size : isize) -> (); ic0.msg_caller_size : () -> isize; ic0.msg_caller_copy : (dst : isize, offset: isize, size : isize) -> (); ic0.msg_reject_code : () -> i32; ic0.msg_reject_msg_size : () -> isize; ic0.msg_reject_msg_copy : (dst : isize, offset : isize, size : isize) -> (); ic0.msg_reply_data_append : (src : isize, size : isize) -> (); ic0.msg_reply : () -> (); ic0.msg_reject : (src : isize, size : isize) -> (); ic0.msg_cycles_available : () -> i64; ic0.msg_cycles_available128 : (dst : isize) -> (); ic0.msg_cycles_refunded : () -> i64; ic0.msg_cycles_refunded128 : (dst : isize) -> (); ic0.msg_cycles_accept : (max_amount : i64) -> (amount : i64); ic0.msg_cycles_accept128 : (max_amount_high : i64, max_amount_low: i64, dst : isize)
260 -> (); ic0.canister_self_size : () -> isize; ic0.canister_self_copy : (dst : isize, offset : isize, size : isize) -> (); ic0.canister_cycle_balance : () -> i64; ic0.canister_cycle_balance128 : (dst : isize) -> (); ic0.canister_status : () -> i32; ic0.msg_method_name_size : () -> isize; ic0.msg_method_name_copy : (dst : isize, offset : isize, size : isize) -> (); ic0.accept_message : () -> (); ic0.call_new : ( callee_src : isize,
274 callee_size : isize,
275 name_src : isize,
276 name_size : isize,
277 reply_fun : isize,
278 reply_env : isize,
279 reject_fun : isize,
280 reject_env : isize
281 ) -> ();
282 ic0.call_on_cleanup : (fun : isize, env : isize) -> (); ic0.call_data_append : (src : isize, size : isize) -> (); ic0.call_cycles_add : (amount : i64) -> (); ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); ic0.call_perform : () -> ( err_code : i32 ); ic0.stable_size : () -> (page_count : i32); ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); ic0.stable_write : (offset : i32, src : isize, size : isize) -> (); ic0.stable_read : (dst : isize, offset : i32, size : isize) -> (); ic0.stable64_size : () -> (page_count : i64); ic0.stable64_grow : (new_pages : i64) -> (old_page_count : i64); ic0.stable64_write : (offset : i64, src : i64, size : i64) -> (); ic0.stable64_read : (dst : i64, offset : i64, size : i64) -> (); ic0.certified_data_set : (src: isize, size: isize) -> (); ic0.data_certificate_present : () -> i32; ic0.data_certificate_size : () -> isize; ic0.data_certificate_copy : (dst: isize, offset: isize, size: isize) -> (); ic0.time : () -> (timestamp : i64); ic0.performance_counter : (counter_type : i32) -> (counter : i64); ic0.debug_print : (src : isize, size : isize) -> (); ic0.trap : (src : isize, size : isize) -> (); }