diff --git a/Cargo.lock b/Cargo.lock index da69ef87ec..fc0942e947 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,27 +205,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "canister" -version = "0.0.0" -dependencies = [ - "anyhow", - "candid", - "candid_parser", - "ic-cdk 0.12.2", - "ic-cdk-macros 0.8.4", - "ic-cdk-timers", - "ic-stable-structures", - "ic-wasi-polyfill", - "open_value_sharing", - "serde", - "serde_json", - "sha2", - "slotmap", - "wasmedge_quickjs", - "wasmi", -] - [[package]] name = "cc" version = "1.1.15" @@ -482,6 +461,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "experimental_canister_template" +version = "0.0.0" +dependencies = [ + "anyhow", + "candid", + "candid_parser", + "ic-cdk 0.12.2", + "ic-cdk-macros 0.8.4", + "ic-cdk-timers", + "ic-stable-structures", + "ic-wasi-polyfill", + "open_value_sharing", + "serde", + "serde_json", + "sha2", + "slotmap", + "wasmedge_quickjs", + "wasmi", +] + [[package]] name = "fastrand" version = "2.1.1" @@ -1331,6 +1331,33 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rquickjs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cbd33e0b668aea0ab238b9164523aca929096f9f40834700d71d91dd4888882" +dependencies = [ + "rquickjs-core", +] + +[[package]] +name = "rquickjs-core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9129d69b7b8f7ee8ad1da5b12c7f4a8a8acd45f2e6dd9cb2ee1bc5a1f2fa3d" +dependencies = [ + "rquickjs-sys", +] + +[[package]] +name = "rquickjs-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6f2288d8e7fbb5130f62cf720451641e99d55f6fde9db86aa2914ecb553fd2" +dependencies = [ + "cc", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1571,6 +1598,23 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "stable_canister_template" +version = "0.0.0" +dependencies = [ + "candid", + "candid_parser", + "ic-cdk 0.12.2", + "ic-cdk-macros 0.8.4", + "ic-cdk-timers", + "ic-stable-structures", + "ic-wasi-polyfill", + "rquickjs", + "serde", + "serde_json", + "slotmap", +] + [[package]] name = "stacker" version = "0.1.17" diff --git a/Cargo.toml b/Cargo.toml index 4b99d1b359..b8f7ad4851 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,6 @@ [workspace] -members = ["src/build/rust/canister", "src/build/rust/open_value_sharing"] +members = [ + "src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template", + "src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing", + "src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template", +] diff --git a/canister_templates/experimental.wasm b/canister_templates/experimental.wasm index 6cd05e68dc..f9b832b541 100644 Binary files a/canister_templates/experimental.wasm and b/canister_templates/experimental.wasm differ diff --git a/canister_templates/stable.wasm b/canister_templates/stable.wasm index be367f9efb..eda45c789f 100644 Binary files a/canister_templates/stable.wasm and b/canister_templates/stable.wasm differ diff --git a/src/build/experimental/commands/compile/get_context.ts b/src/build/experimental/commands/compile/get_context.ts index 8017a50b8f..5f247bf502 100644 --- a/src/build/experimental/commands/compile/get_context.ts +++ b/src/build/experimental/commands/compile/get_context.ts @@ -32,6 +32,7 @@ export async function getContext( consumer, managementDid, recordBenchmarks: + process.env.npm_lifecycle_event === 'pre_tests' || process.env.npm_lifecycle_event === 'pretest' || process.env.npm_lifecycle_event === 'test' ? process.env.AZLE_RECORD_BENCHMARKS !== 'false' diff --git a/src/build/experimental/commands/compile/wasm_binary/compile.ts b/src/build/experimental/commands/compile/wasm_binary/compile.ts index cf847797d5..f4b66ff208 100644 --- a/src/build/experimental/commands/compile/wasm_binary/compile.ts +++ b/src/build/experimental/commands/compile/wasm_binary/compile.ts @@ -13,7 +13,7 @@ export function compile( ); execSyncPretty( - `wasi2ic target/wasm32-wasi/release/canister.wasm ${wasmDest}`, + `wasi2ic target/wasm32-wasi/release/experimental_canister_template.wasm ${wasmDest}`, ioType ); } diff --git a/src/build/rust/canister/Cargo.toml b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/Cargo.toml similarity index 94% rename from src/build/rust/canister/Cargo.toml rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/Cargo.toml index 7ba918b185..d4d0ae8117 100644 --- a/src/build/rust/canister/Cargo.toml +++ b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "canister" +name = "experimental_canister_template" version = "0.0.0" edition = "2018" diff --git a/src/build/rust/canister/src/autoreload.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/autoreload.rs similarity index 100% rename from src/build/rust/canister/src/autoreload.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/autoreload.rs diff --git a/src/build/rust/canister/src/benchmarking.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/benchmarking.rs similarity index 96% rename from src/build/rust/canister/src/benchmarking.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/benchmarking.rs index f6883676fd..8ec47e2944 100644 --- a/src/build/rust/canister/src/benchmarking.rs +++ b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/benchmarking.rs @@ -1,5 +1,4 @@ use std::cell::RefCell; -use std::collections::BTreeMap; use candid::CandidType; use wasmedge_quickjs::{AsObject, Context}; diff --git a/src/build/rust/canister/src/candid.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/candid.rs similarity index 98% rename from src/build/rust/canister/src/candid.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/candid.rs index f66d941ec2..ba21eed769 100644 --- a/src/build/rust/canister/src/candid.rs +++ b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/candid.rs @@ -37,7 +37,7 @@ pub fn get_candid_and_method_meta_pointer() -> *mut std::os::raw::c_char { // TODO what do we do if there is an error in here? context.eval_global_str("globalThis.exports = {};".to_string()); context.eval_global_str(format!("globalThis._azleExperimental = {EXPERIMENTAL};")); - context.eval_module_str(std::str::from_utf8(&js).unwrap().to_string(), "azle_main"); + context.eval_module_str(std::str::from_utf8(&js).unwrap().to_string(), "main"); run_event_loop(context); diff --git a/src/build/rust/canister/src/chunk.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/chunk.rs similarity index 100% rename from src/build/rust/canister/src/chunk.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/chunk.rs diff --git a/src/build/rust/canister/src/execute_method_js.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/execute_method_js.rs similarity index 99% rename from src/build/rust/canister/src/execute_method_js.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/execute_method_js.rs index 52ca50d757..2dcf6cc81a 100644 --- a/src/build/rust/canister/src/execute_method_js.rs +++ b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/execute_method_js.rs @@ -14,6 +14,7 @@ pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data: i32) { runtime.run_with_context(|context| { let global = context.get_global(); let callbacks = global.get("_azleCallbacks"); + let method_callback = callbacks.get(&function_name).unwrap(); let candid_args = if pass_arg_data { diff --git a/src/build/rust/canister/src/guards.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/guards.rs similarity index 100% rename from src/build/rust/canister/src/guards.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/guards.rs diff --git a/src/build/rust/canister/src/ic/accept_message.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/accept_message.rs similarity index 100% rename from src/build/rust/canister/src/ic/accept_message.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/accept_message.rs diff --git a/src/build/rust/canister/src/ic/arg_data_raw.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/arg_data_raw.rs similarity index 100% rename from src/build/rust/canister/src/ic/arg_data_raw.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/arg_data_raw.rs diff --git a/src/build/rust/canister/src/ic/call_raw.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/call_raw.rs similarity index 100% rename from src/build/rust/canister/src/ic/call_raw.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/call_raw.rs diff --git a/src/build/rust/canister/src/ic/caller.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/caller.rs similarity index 100% rename from src/build/rust/canister/src/ic/caller.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/caller.rs diff --git a/src/build/rust/canister/src/ic/candid_compiler.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/candid_compiler.rs similarity index 100% rename from src/build/rust/canister/src/ic/candid_compiler.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/candid_compiler.rs diff --git a/src/build/rust/canister/src/ic/candid_decode.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/candid_decode.rs similarity index 100% rename from src/build/rust/canister/src/ic/candid_decode.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/candid_decode.rs diff --git a/src/build/rust/canister/src/ic/candid_encode.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/candid_encode.rs similarity index 100% rename from src/build/rust/canister/src/ic/candid_encode.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/candid_encode.rs diff --git a/src/build/rust/canister/src/ic/canister_balance.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/canister_balance.rs similarity index 100% rename from src/build/rust/canister/src/ic/canister_balance.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/canister_balance.rs diff --git a/src/build/rust/canister/src/ic/canister_version.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/canister_version.rs similarity index 100% rename from src/build/rust/canister/src/ic/canister_version.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/canister_version.rs diff --git a/src/build/rust/canister/src/ic/clear_timer.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/clear_timer.rs similarity index 100% rename from src/build/rust/canister/src/ic/clear_timer.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/clear_timer.rs diff --git a/src/build/rust/canister/src/ic/cycles_burn.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/cycles_burn.rs similarity index 100% rename from src/build/rust/canister/src/ic/cycles_burn.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/cycles_burn.rs diff --git a/src/build/rust/canister/src/ic/data_certificate.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/data_certificate.rs similarity index 100% rename from src/build/rust/canister/src/ic/data_certificate.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/data_certificate.rs diff --git a/src/build/rust/canister/src/ic/id.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/id.rs similarity index 100% rename from src/build/rust/canister/src/ic/id.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/id.rs diff --git a/src/build/rust/canister/src/ic/instruction_counter.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/instruction_counter.rs similarity index 100% rename from src/build/rust/canister/src/ic/instruction_counter.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/instruction_counter.rs diff --git a/src/build/rust/canister/src/ic/is_controller.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/is_controller.rs similarity index 100% rename from src/build/rust/canister/src/ic/is_controller.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/is_controller.rs diff --git a/src/build/rust/canister/src/ic/method_name.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/method_name.rs similarity index 100% rename from src/build/rust/canister/src/ic/method_name.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/method_name.rs diff --git a/src/build/rust/canister/src/ic/mod.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/mod.rs similarity index 99% rename from src/build/rust/canister/src/ic/mod.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/mod.rs index 2005ab8029..086a4f4f68 100644 --- a/src/build/rust/canister/src/ic/mod.rs +++ b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/mod.rs @@ -312,5 +312,5 @@ pub fn register(context: &mut wasmedge_quickjs::Context) { context.new_function::("").into(), ); - context.get_global().set("_azleIc", ic.into()); + context.get_global().set("_azleIcExperimental", ic.into()); } diff --git a/src/build/rust/canister/src/ic/msg_cycles_accept.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/msg_cycles_accept.rs similarity index 100% rename from src/build/rust/canister/src/ic/msg_cycles_accept.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/msg_cycles_accept.rs diff --git a/src/build/rust/canister/src/ic/msg_cycles_available.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/msg_cycles_available.rs similarity index 100% rename from src/build/rust/canister/src/ic/msg_cycles_available.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/msg_cycles_available.rs diff --git a/src/build/rust/canister/src/ic/msg_cycles_refunded.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/msg_cycles_refunded.rs similarity index 100% rename from src/build/rust/canister/src/ic/msg_cycles_refunded.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/msg_cycles_refunded.rs diff --git a/src/build/rust/canister/src/ic/notify_raw.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/notify_raw.rs similarity index 100% rename from src/build/rust/canister/src/ic/notify_raw.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/notify_raw.rs diff --git a/src/build/rust/canister/src/ic/performance_counter.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/performance_counter.rs similarity index 100% rename from src/build/rust/canister/src/ic/performance_counter.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/performance_counter.rs diff --git a/src/build/rust/canister/src/ic/print.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/print.rs similarity index 100% rename from src/build/rust/canister/src/ic/print.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/print.rs diff --git a/src/build/rust/canister/src/ic/reject.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/reject.rs similarity index 100% rename from src/build/rust/canister/src/ic/reject.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/reject.rs diff --git a/src/build/rust/canister/src/ic/reject_code.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/reject_code.rs similarity index 100% rename from src/build/rust/canister/src/ic/reject_code.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/reject_code.rs diff --git a/src/build/rust/canister/src/ic/reject_message.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/reject_message.rs similarity index 100% rename from src/build/rust/canister/src/ic/reject_message.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/reject_message.rs diff --git a/src/build/rust/canister/src/ic/reply_raw.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/reply_raw.rs similarity index 100% rename from src/build/rust/canister/src/ic/reply_raw.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/reply_raw.rs diff --git a/src/build/rust/canister/src/ic/set_certified_data.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/set_certified_data.rs similarity index 100% rename from src/build/rust/canister/src/ic/set_certified_data.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/set_certified_data.rs diff --git a/src/build/rust/canister/src/ic/set_timer.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/set_timer.rs similarity index 100% rename from src/build/rust/canister/src/ic/set_timer.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/set_timer.rs diff --git a/src/build/rust/canister/src/ic/set_timer_interval.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/set_timer_interval.rs similarity index 100% rename from src/build/rust/canister/src/ic/set_timer_interval.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/set_timer_interval.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_contains_key.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_contains_key.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_contains_key.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_contains_key.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_get.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_get.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_get.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_get.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_init.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_init.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_init.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_init.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_insert.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_insert.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_insert.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_insert.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_is_empty.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_is_empty.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_is_empty.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_is_empty.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_items.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_items.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_items.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_items.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_keys.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_keys.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_keys.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_keys.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_len.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_len.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_len.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_len.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_remove.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_remove.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_remove.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_remove.rs diff --git a/src/build/rust/canister/src/ic/stable_b_tree_map_values.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_values.rs similarity index 100% rename from src/build/rust/canister/src/ic/stable_b_tree_map_values.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/stable_b_tree_map_values.rs diff --git a/src/build/rust/canister/src/ic/time.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/time.rs similarity index 100% rename from src/build/rust/canister/src/ic/time.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/time.rs diff --git a/src/build/rust/canister/src/ic/trap.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/trap.rs similarity index 100% rename from src/build/rust/canister/src/ic/trap.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/ic/trap.rs diff --git a/src/build/rust/canister/src/init_and_post_upgrade.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/init_and_post_upgrade.rs similarity index 97% rename from src/build/rust/canister/src/init_and_post_upgrade.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/init_and_post_upgrade.rs index 374b5a4116..aec3c5526a 100644 --- a/src/build/rust/canister/src/init_and_post_upgrade.rs +++ b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/init_and_post_upgrade.rs @@ -126,11 +126,11 @@ pub fn initialize_js(js: &str, init: bool, function_index: i32, pass_arg_data: i context.eval_global_str(format!( "globalThis._azleRecordBenchmarks = {record_benchmarks};" )); - context.eval_module_str(js.to_string(), "azle_main"); + context.eval_module_str(js.to_string(), "main"); run_event_loop(context); - // let temp = context.eval_module_str(std::str::from_utf8(MAIN_JS).unwrap().to_string(), "azle_main"); + // let temp = context.eval_module_str(std::str::from_utf8(MAIN_JS).unwrap().to_string(), "main"); // match &temp { // wasmedge_quickjs::JsValue::Exception(js_exception) => { diff --git a/src/build/rust/canister/src/lib.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/lib.rs similarity index 100% rename from src/build/rust/canister/src/lib.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/lib.rs diff --git a/src/build/rust/canister/src/stable_b_tree_map.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/stable_b_tree_map.rs similarity index 100% rename from src/build/rust/canister/src/stable_b_tree_map.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/stable_b_tree_map.rs diff --git a/src/build/rust/canister/src/upload_file/bytes_to_human_readable.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/bytes_to_human_readable.rs similarity index 100% rename from src/build/rust/canister/src/upload_file/bytes_to_human_readable.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/bytes_to_human_readable.rs diff --git a/src/build/rust/canister/src/upload_file/file_info.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/file_info.rs similarity index 100% rename from src/build/rust/canister/src/upload_file/file_info.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/file_info.rs diff --git a/src/build/rust/canister/src/upload_file/hash.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/hash.rs similarity index 100% rename from src/build/rust/canister/src/upload_file/hash.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/hash.rs diff --git a/src/build/rust/canister/src/upload_file/mod.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/mod.rs similarity index 100% rename from src/build/rust/canister/src/upload_file/mod.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/mod.rs diff --git a/src/build/rust/canister/src/upload_file/reset.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/reset.rs similarity index 100% rename from src/build/rust/canister/src/upload_file/reset.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/reset.rs diff --git a/src/build/rust/canister/src/upload_file/upload_file_chunk.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/upload_file_chunk.rs similarity index 100% rename from src/build/rust/canister/src/upload_file/upload_file_chunk.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/upload_file/upload_file_chunk.rs diff --git a/src/build/rust/canister/src/wasm_binary_manipulation.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/wasm_binary_manipulation.rs similarity index 100% rename from src/build/rust/canister/src/wasm_binary_manipulation.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/wasm_binary_manipulation.rs diff --git a/src/build/rust/canister/src/web_assembly/instantiate.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/web_assembly/instantiate.rs similarity index 100% rename from src/build/rust/canister/src/web_assembly/instantiate.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/web_assembly/instantiate.rs diff --git a/src/build/rust/canister/src/web_assembly/mod.rs b/src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/web_assembly/mod.rs similarity index 100% rename from src/build/rust/canister/src/web_assembly/mod.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/experimental_canister_template/src/web_assembly/mod.rs diff --git a/src/build/rust/open_value_sharing/Cargo.toml b/src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/Cargo.toml similarity index 100% rename from src/build/rust/open_value_sharing/Cargo.toml rename to src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/Cargo.toml diff --git a/src/build/rust/open_value_sharing/src/lib.rs b/src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/lib.rs similarity index 100% rename from src/build/rust/open_value_sharing/src/lib.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/lib.rs diff --git a/src/build/rust/open_value_sharing/src/platforms/icp/assets/cycles.rs b/src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/platforms/icp/assets/cycles.rs similarity index 100% rename from src/build/rust/open_value_sharing/src/platforms/icp/assets/cycles.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/platforms/icp/assets/cycles.rs diff --git a/src/build/rust/open_value_sharing/src/platforms/icp/assets/mod.rs b/src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/platforms/icp/assets/mod.rs similarity index 100% rename from src/build/rust/open_value_sharing/src/platforms/icp/assets/mod.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/platforms/icp/assets/mod.rs diff --git a/src/build/rust/open_value_sharing/src/platforms/icp/mod.rs b/src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/platforms/icp/mod.rs similarity index 100% rename from src/build/rust/open_value_sharing/src/platforms/icp/mod.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/platforms/icp/mod.rs diff --git a/src/build/rust/open_value_sharing/src/platforms/mod.rs b/src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/platforms/mod.rs similarity index 100% rename from src/build/rust/open_value_sharing/src/platforms/mod.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/platforms/mod.rs diff --git a/src/build/rust/open_value_sharing/src/query_methods.rs b/src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/query_methods.rs similarity index 100% rename from src/build/rust/open_value_sharing/src/query_methods.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/query_methods.rs diff --git a/src/build/rust/open_value_sharing/src/test/mod.rs b/src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/test/mod.rs similarity index 100% rename from src/build/rust/open_value_sharing/src/test/mod.rs rename to src/build/experimental/commands/compile/wasm_binary/rust/open_value_sharing/src/test/mod.rs diff --git a/src/build/experimental/commands/template.ts b/src/build/experimental/commands/template.ts index 5d773fb3e9..0ed65f7492 100644 --- a/src/build/experimental/commands/template.ts +++ b/src/build/experimental/commands/template.ts @@ -14,8 +14,12 @@ export async function runCommand(ioType: IOType): Promise { AZLE_PACKAGE_PATH, 'src', 'build', + 'experimental', + 'commands', + 'compile', + 'wasm_binary', 'rust', - 'canister', + 'experimental_canister_template', 'Cargo.toml' ), EXPERIMENTAL_STATIC_CANISTER_TEMPLATE_PATH, diff --git a/src/build/stable/commands/compile/get_context.ts b/src/build/stable/commands/compile/get_context.ts index 5b1a64e1db..76ee81f431 100644 --- a/src/build/stable/commands/compile/get_context.ts +++ b/src/build/stable/commands/compile/get_context.ts @@ -28,6 +28,7 @@ export function getContext( const wasmData: WasmData = { envVars, recordBenchmarks: + process.env.npm_lifecycle_event === 'pre_tests' || process.env.npm_lifecycle_event === 'pretest' || process.env.npm_lifecycle_event === 'test' ? process.env.AZLE_RECORD_BENCHMARKS !== 'false' diff --git a/src/build/stable/commands/compile/wasm_binary/compile.ts b/src/build/stable/commands/compile/wasm_binary/compile.ts index 4213ffe421..3599832d52 100644 --- a/src/build/stable/commands/compile/wasm_binary/compile.ts +++ b/src/build/stable/commands/compile/wasm_binary/compile.ts @@ -13,7 +13,7 @@ export function compile( ); execSyncPretty( - `wasi2ic target/wasm32-wasi/release/canister.wasm ${wasmDest}`, + `wasi2ic target/wasm32-wasi/release/stable_canister_template.wasm ${wasmDest}`, ioType ); } diff --git a/src/build/stable/commands/compile/wasm_binary/generate_cargo_toml_files.ts b/src/build/stable/commands/compile/wasm_binary/generate_cargo_toml_files.ts deleted file mode 100644 index 9f09be3ae2..0000000000 --- a/src/build/stable/commands/compile/wasm_binary/generate_cargo_toml_files.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function generateWorkspaceCargoToml(): string { - return ` - # This code is automatically generated by Azle - - [workspace] - members = [ - "canister", - "open_value_sharing" - ] - - [profile.release] - opt-level = 'z' - `; -} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/Cargo.toml b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/Cargo.toml new file mode 100644 index 0000000000..b6b1445ac2 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "stable_canister_template" +version = "0.0.0" +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +candid = "0.10.2" +candid_parser = "0.1.2" +ic-cdk = "0.12.2" +ic-cdk-macros = "0.8.4" +ic-cdk-timers = "0.6.0" +ic-stable-structures = "0.6.5" +ic-wasi-polyfill = "0.6.1" +rquickjs = { version = "0.6.2", features = ["array-buffer"] } +serde = "1.0.202" +serde_json = "1.0.107" +slotmap = "=1.0.6" diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/benchmarking.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/benchmarking.rs new file mode 100644 index 0000000000..e9e04839c1 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/benchmarking.rs @@ -0,0 +1,38 @@ +use std::{cell::RefCell, error::Error}; + +use candid::CandidType; + +use crate::quickjs_with_ctx; + +#[derive(CandidType, Debug, Clone)] +pub struct BenchmarkEntry { + pub method_name: String, + pub instructions: u64, + pub timestamp: u64, +} + +thread_local! { + pub static BENCHMARKS_REF_CELL: RefCell> = RefCell::new(Vec::new()); +} + +pub fn record_benchmark(function_name: &str, instructions: u64) -> Result<(), Box> { + quickjs_with_ctx(|ctx| { + let timestamp = ic_cdk::api::time(); + + let method_names: rquickjs::Object = + ctx.clone().globals().get("_azleCanisterMethodNames")?; + + let method_name: String = method_names.get(function_name)?; + + BENCHMARKS_REF_CELL.with(|benchmarks_ref_cell| { + let mut benchmarks = benchmarks_ref_cell.borrow_mut(); + benchmarks.push(BenchmarkEntry { + method_name, + instructions, + timestamp, + }); + }); + + Ok(()) + }) +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs new file mode 100644 index 0000000000..1be5a877c0 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs @@ -0,0 +1,66 @@ +use crate::{ + ic, quickjs_with_ctx, wasm_binary_manipulation::get_js_code, CONTEXT_REF_CELL, MODULE_NAME, +}; + +// TODO we might not need any of these panic hooks + +// Heavily inspired by https://stackoverflow.com/a/47676844 +#[no_mangle] +pub fn get_candid_and_method_meta_pointer() -> *mut std::os::raw::c_char { + std::panic::set_hook(Box::new(|panic_info| { + let msg = match panic_info.payload().downcast_ref::<&str>() { + Some(s) => *s, + None => "Unknown panic message", + }; + let location = if let Some(location) = panic_info.location() { + format!(" at {}:{}", location.file(), location.line()) + } else { + " (unknown location)".to_string() + }; + + let message = &format!("Panic occurred: {}{}", msg, location); + + ic_cdk::println!("{}", message); + })); + + let runtime = rquickjs::Runtime::new().unwrap(); + let context = rquickjs::Context::full(&runtime).unwrap(); + + CONTEXT_REF_CELL.with(|context_ref_cell| { + *context_ref_cell.borrow_mut() = Some(context); + }); + + quickjs_with_ctx(|ctx| { + ctx.clone() + .globals() + .set("_azleNodeWasmEnvironment", true) + .unwrap(); + + ic::register(ctx.clone()); + + ctx.clone() + .globals() + .set("exports", rquickjs::Object::new(ctx.clone()).unwrap()) + .unwrap(); + + ctx.clone() + .globals() + .set("_azleExperimental", false) + .unwrap(); + + let js = get_js_code(); + + // TODO is there a better name for this main module? + // TODO this returns a promise...make sure we handle it appropriately + rquickjs::Module::evaluate(ctx.clone(), MODULE_NAME, js).unwrap(); + + let get_candid_and_method_meta: rquickjs::Function = + ctx.globals().get("_azleGetCandidAndMethodMeta").unwrap(); + + let candid_and_method_meta: String = get_candid_and_method_meta.call(()).unwrap(); + + let c_string = std::ffi::CString::new(candid_and_method_meta).unwrap(); + + c_string.into_raw() + }) +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/chunk.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/chunk.rs new file mode 100644 index 0000000000..78e9f70558 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/chunk.rs @@ -0,0 +1,7 @@ +#[allow(unused)] +pub async fn chunk() { + let id = ic_cdk::id(); + let method = "_azle_chunk"; + let args_raw = [68, 73, 68, 76, 0, 0]; // '()' pre encoded + let _ = ic_cdk::api::call::call_raw128(id, method, args_raw, 0).await; +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs new file mode 100644 index 0000000000..444c9c540a --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs @@ -0,0 +1,35 @@ +use crate::{benchmarking::record_benchmark, quickjs_with_ctx, WASM_DATA_REF_CELL}; + +#[no_mangle] +#[allow(unused)] +pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data: i32) { + let function_name = &function_index.to_string(); + let pass_arg_data = if pass_arg_data == 1 { true } else { false }; + + quickjs_with_ctx(|ctx| { + let callbacks: rquickjs::Object = ctx.clone().globals().get("_azleCallbacks").unwrap(); + + let method_callback: rquickjs::Function = callbacks.get(function_name).unwrap(); + + let candid_args = if pass_arg_data { + ic_cdk::api::call::arg_data_raw() + } else { + vec![] + }; + + method_callback + .call::<_, rquickjs::Undefined>((candid_args,)) + .unwrap(); + }); + + if WASM_DATA_REF_CELL.with(|wasm_data_ref_cell| { + wasm_data_ref_cell + .borrow() + .as_ref() + .unwrap() + .record_benchmarks + }) { + let instructions = ic_cdk::api::performance_counter(1); + record_benchmark(&function_name, instructions); + } +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/guards.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/guards.rs new file mode 100644 index 0000000000..a6993b3005 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/guards.rs @@ -0,0 +1,9 @@ +#[allow(unused)] +pub fn guard_against_non_controllers() -> Result<(), String> { + if ic_cdk::api::is_controller(&ic_cdk::api::caller()) { + return Ok(()); + } + return Err( + "Not Authorized: only controllers of this canister may call this method".to_string(), + ); +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs new file mode 100644 index 0000000000..be743b1e03 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || { + ic_cdk::api::call::accept_message(); + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs new file mode 100644 index 0000000000..18648c2133 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function, TypedArray}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context.clone(), move || { + TypedArray::::new(context.clone(), ic_cdk::api::call::arg_data_raw()) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs new file mode 100644 index 0000000000..a15cb91428 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs @@ -0,0 +1,95 @@ +use crate::quickjs_with_ctx; +use rquickjs::{Ctx, Exception, Function, IntoJs, TypedArray}; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new( + ctx, + |promise_id: String, + canister_id_bytes: TypedArray, + method: String, + args_raw: TypedArray, + payment_string: String| { + let canister_id = candid::Principal::from_slice(canister_id_bytes.as_ref()); + let args_raw = args_raw.as_bytes().unwrap().to_vec(); + let payment: u128 = payment_string.parse().unwrap(); + + ic_cdk::spawn(async move { + let call_result = + ic_cdk::api::call::call_raw128(canister_id, &method, args_raw, payment).await; + + quickjs_with_ctx(move |ctx| { + resolve_or_reject(ctx.clone(), &call_result, &promise_id); + }); + }); + + rquickjs::Undefined + }, + ) + .unwrap() +} + +fn resolve_or_reject<'a>( + ctx: Ctx<'a>, + call_result: &Result, (ic_cdk::api::call::RejectionCode, String)>, + promise_id: &str, +) { + let (should_resolve, js_value) = prepare_js_value(ctx.clone(), &call_result); + let callback = get_callback(ctx.clone(), &promise_id, should_resolve); + + callback + .call::<_, rquickjs::Undefined>((js_value,)) + .unwrap(); +} + +fn prepare_js_value<'a>( + ctx: Ctx<'a>, + call_result: &Result, (ic_cdk::api::call::RejectionCode, String)>, +) -> (bool, rquickjs::Value<'a>) { + match call_result { + Ok(candid_bytes) => { + let candid_bytes_js_value = TypedArray::::new(ctx.clone(), candid_bytes.clone()) + .into_js(&ctx) + .unwrap(); + + (true, candid_bytes_js_value) + } + Err(err) => { + let err_js_value = Exception::from_message( + ctx.clone(), + &format!("Rejection code {}, {}", (err.0 as i32).to_string(), err.1), + ) + .into_js(&ctx) + .unwrap(); + + (false, err_js_value) + } + } +} + +fn get_callback<'a>( + ctx: Ctx<'a>, + promise_id: &str, + should_resolve: bool, +) -> rquickjs::Function<'a> { + let global_object = get_resolve_or_reject_global_object(ctx.clone(), should_resolve); + let callback_name = get_resolve_or_reject_callback_name(&promise_id, should_resolve); + + global_object.get(callback_name).unwrap() +} + +fn get_resolve_or_reject_global_object(ctx: Ctx, should_resolve: bool) -> rquickjs::Object { + let global = ctx.globals(); + if should_resolve { + global.get("_azleResolveIds").unwrap() + } else { + global.get("_azleRejectIds").unwrap() + } +} + +fn get_resolve_or_reject_callback_name(promise_id: &str, should_resolve: bool) -> String { + if should_resolve { + format!("_resolve_{promise_id}") + } else { + format!("_reject_{promise_id}") + } +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs new file mode 100644 index 0000000000..a58cad407b --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function, TypedArray}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context.clone(), move || { + TypedArray::::new(context.clone(), ic_cdk::api::caller().as_slice()) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_compiler.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_compiler.rs new file mode 100644 index 0000000000..2fec0196bb --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_compiler.rs @@ -0,0 +1,11 @@ +use rquickjs::{Ctx, Function}; +use std::path::Path; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |candid_path: String| { + let (env, actor) = candid_parser::pretty_check_file(Path::new(&candid_path)).unwrap(); + + candid_parser::bindings::javascript::compile(&env, &actor) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_decode.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_decode.rs new file mode 100644 index 0000000000..e573fbb21a --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_decode.rs @@ -0,0 +1,12 @@ +use rquickjs::{Ctx, Function, TypedArray}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |candid_encoded: TypedArray| { + let candid_bytes = candid_encoded.as_ref(); + let candid_args: candid::IDLArgs = candid::IDLArgs::from_bytes(candid_bytes).unwrap(); + let candid_string = candid_args.to_string(); + + candid_string + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_encode.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_encode.rs new file mode 100644 index 0000000000..8f293ec22d --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_encode.rs @@ -0,0 +1,11 @@ +use rquickjs::{Ctx, Function, TypedArray}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context.clone(), move |candid_string: String| { + let candid_args = candid_parser::parse_idl_args(&candid_string).unwrap(); + let candid_encoded = candid_args.to_bytes().unwrap(); + + TypedArray::::new(context.clone(), candid_encoded) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_balance.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_balance.rs new file mode 100644 index 0000000000..5f3c6fc85b --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_balance.rs @@ -0,0 +1,5 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || ic_cdk::api::canister_balance128().to_string()).unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_version.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_version.rs new file mode 100644 index 0000000000..adac460569 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_version.rs @@ -0,0 +1,5 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || ic_cdk::api::canister_version()).unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/clear_timer.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/clear_timer.rs new file mode 100644 index 0000000000..1d53f6d3e9 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/clear_timer.rs @@ -0,0 +1,10 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new(ctx, |timer_id: String| { + ic_cdk_timers::clear_timer(ic_cdk_timers::TimerId::from(slotmap::KeyData::from_ffi( + timer_id.parse().unwrap(), + ))); + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/cycles_burn.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/cycles_burn.rs new file mode 100644 index 0000000000..e92965c240 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/cycles_burn.rs @@ -0,0 +1,10 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |amount_string: String| { + let amount: u128 = amount_string.parse().unwrap(); + + ic_cdk::api::cycles_burn(amount).to_string() + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/data_certificate.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/data_certificate.rs new file mode 100644 index 0000000000..cb76330ad7 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/data_certificate.rs @@ -0,0 +1,17 @@ +use rquickjs::{Ctx, Function, IntoJs, TypedArray}; + +pub fn get_function(context: Ctx) -> Function { + Function::new( + context.clone(), + move || match ic_cdk::api::data_certificate() { + Some(data_certificate_vec_u8) => { + TypedArray::::new(context.clone(), data_certificate_vec_u8) + .unwrap() + .into_js(&context) + .unwrap() + } + None => rquickjs::Undefined.into_js(&context).unwrap(), + }, + ) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/id.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/id.rs new file mode 100644 index 0000000000..a97d966c03 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/id.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function, TypedArray}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context.clone(), move || { + TypedArray::::new(context.clone(), ic_cdk::id().as_slice()) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/instruction_counter.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/instruction_counter.rs new file mode 100644 index 0000000000..0053a016a0 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/instruction_counter.rs @@ -0,0 +1,5 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || ic_cdk::api::instruction_counter()).unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/is_controller.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/is_controller.rs new file mode 100644 index 0000000000..5a08676eca --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/is_controller.rs @@ -0,0 +1,10 @@ +use rquickjs::{Ctx, Function, TypedArray}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |principal_bytes: TypedArray| { + let principal = candid::Principal::from_slice(principal_bytes.as_ref()); + + ic_cdk::api::is_controller(&principal) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/method_name.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/method_name.rs new file mode 100644 index 0000000000..b1ccc04776 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/method_name.rs @@ -0,0 +1,5 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || ic_cdk::api::call::method_name()).unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs new file mode 100644 index 0000000000..e1fdf03216 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs @@ -0,0 +1,237 @@ +mod accept_message; +mod arg_data_raw; +mod call_raw; +mod caller; +mod candid_compiler; +mod candid_decode; +mod candid_encode; +mod canister_balance; +mod canister_version; +mod clear_timer; +mod cycles_burn; +mod data_certificate; +mod id; +mod instruction_counter; +mod is_controller; +mod method_name; +mod msg_cycles_accept; +mod msg_cycles_available; +mod msg_cycles_refunded; +mod notify_raw; +mod performance_counter; +mod print; +mod reject; +mod reject_code; +mod reject_message; +mod reply_raw; +mod set_certified_data; +mod set_timer; +mod set_timer_interval; +mod stable_b_tree_map_contains_key; +mod stable_b_tree_map_get; +mod stable_b_tree_map_init; +mod stable_b_tree_map_insert; +mod stable_b_tree_map_is_empty; +mod stable_b_tree_map_items; +mod stable_b_tree_map_keys; +mod stable_b_tree_map_len; +mod stable_b_tree_map_remove; +mod stable_b_tree_map_values; +mod time; +mod trap; + +#[allow(unused)] +pub fn register(context: rquickjs::Ctx) { + let ic = rquickjs::Object::new(context.clone()).unwrap(); + + ic.set( + "acceptMessage", + accept_message::get_function(context.clone()), + ) + .unwrap(); + + ic.set("argDataRaw", arg_data_raw::get_function(context.clone())) + .unwrap(); + + ic.set("callRaw", call_raw::get_function(context.clone())) + .unwrap(); + + ic.set("caller", caller::get_function(context.clone())) + .unwrap(); + + ic.set( + "candidCompiler", + candid_compiler::get_function(context.clone()), + ) + .unwrap(); + + ic.set("candidDecode", candid_decode::get_function(context.clone())) + .unwrap(); + + ic.set("candidEncode", candid_encode::get_function(context.clone())) + .unwrap(); + + ic.set( + "canisterBalance", + canister_balance::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "canisterVersion", + canister_version::get_function(context.clone()), + ) + .unwrap(); + + ic.set("clearTimer", clear_timer::get_function(context.clone())) + .unwrap(); + + ic.set("cyclesBurn", cycles_burn::get_function(context.clone())) + .unwrap(); + + ic.set( + "dataCertificate", + data_certificate::get_function(context.clone()), + ) + .unwrap(); + + ic.set("id", id::get_function(context.clone())).unwrap(); + + ic.set( + "instructionCounter", + instruction_counter::get_function(context.clone()), + ) + .unwrap(); + + ic.set("isController", is_controller::get_function(context.clone())) + .unwrap(); + + ic.set("methodName", method_name::get_function(context.clone())) + .unwrap(); + + ic.set( + "msgCyclesAccept", + msg_cycles_accept::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "msgCyclesAvailable", + msg_cycles_available::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "msgCyclesRefunded", + msg_cycles_refunded::get_function(context.clone()), + ) + .unwrap(); + + ic.set("notifyRaw", notify_raw::get_function(context.clone())) + .unwrap(); + + ic.set( + "performanceCounter", + performance_counter::get_function(context.clone()), + ) + .unwrap(); + + ic.set("print", print::get_function(context.clone())) + .unwrap(); + + ic.set("reject", reject::get_function(context.clone())) + .unwrap(); + + ic.set("rejectCode", reject_code::get_function(context.clone())) + .unwrap(); + + ic.set( + "rejectMessage", + reject_message::get_function(context.clone()), + ) + .unwrap(); + + ic.set("replyRaw", reply_raw::get_function(context.clone())) + .unwrap(); + + ic.set( + "setCertifiedData", + set_certified_data::get_function(context.clone()), + ) + .unwrap(); + + ic.set("setTimer", set_timer::get_function(context.clone())) + .unwrap(); + + ic.set( + "setTimerInterval", + set_timer_interval::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapContainsKey", + stable_b_tree_map_contains_key::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapGet", + stable_b_tree_map_get::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapInit", + stable_b_tree_map_init::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapInsert", + stable_b_tree_map_insert::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapIsEmpty", + stable_b_tree_map_is_empty::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapItems", + stable_b_tree_map_items::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapKeys", + stable_b_tree_map_keys::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapLen", + stable_b_tree_map_len::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapRemove", + stable_b_tree_map_remove::get_function(context.clone()), + ) + .unwrap(); + + ic.set( + "stableBTreeMapValues", + stable_b_tree_map_values::get_function(context.clone()), + ) + .unwrap(); + + ic.set("time", time::get_function(context.clone())).unwrap(); + + ic.set("trap", trap::get_function(context.clone())).unwrap(); + + context.clone().globals().set("_azleIcStable", ic).unwrap(); +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_accept.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_accept.rs new file mode 100644 index 0000000000..95bfe3b268 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_accept.rs @@ -0,0 +1,10 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |max_amount_string: String| { + let max_amount: u128 = max_amount_string.parse().unwrap(); + + ic_cdk::api::call::msg_cycles_accept128(max_amount).to_string() + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_available.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_available.rs new file mode 100644 index 0000000000..eaba647961 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_available.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || { + ic_cdk::api::call::msg_cycles_available128().to_string() + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_refunded.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_refunded.rs new file mode 100644 index 0000000000..1eaeaa9194 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_refunded.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || { + ic_cdk::api::call::msg_cycles_refunded128().to_string() + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/notify_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/notify_raw.rs new file mode 100644 index 0000000000..b05ea92c99 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/notify_raw.rs @@ -0,0 +1,34 @@ +use rquickjs::{Ctx, Function, IntoJs, TypedArray}; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new( + ctx.clone(), + move |canister_id_bytes: TypedArray, + method: String, + args_raw: TypedArray, + payment_string: String| { + let canister_id = candid::Principal::from_slice(canister_id_bytes.as_ref()); + let args_raw = args_raw.as_bytes().unwrap().to_vec(); + let payment: u128 = payment_string.parse().unwrap(); + + let notify_result = + ic_cdk::api::call::notify_raw(canister_id, &method, &args_raw, payment); + + match notify_result { + Ok(_) => rquickjs::Undefined.into_js(&ctx).unwrap(), + Err(err) => { + let err_string = format!( + "Rejection code {rejection_code}", + rejection_code = (err as i32).to_string() + ); + let err_js_value = rquickjs::Exception::from_message(ctx.clone(), &err_string) + .into_js(&ctx) + .unwrap(); + + err_js_value + } + } + }, + ) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/performance_counter.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/performance_counter.rs new file mode 100644 index 0000000000..b7af20f182 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/performance_counter.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |counter_type: u32| { + ic_cdk::api::performance_counter(counter_type) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/print.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/print.rs new file mode 100644 index 0000000000..f35d190399 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/print.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> rquickjs::Function { + Function::new(context, |message: String| { + ic_cdk::print(message); + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject.rs new file mode 100644 index 0000000000..a43452c82a --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |message: String| { + ic_cdk::api::call::reject(&message); + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_code.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_code.rs new file mode 100644 index 0000000000..0ceb9b6d22 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_code.rs @@ -0,0 +1,20 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || { + let reject_code = ic_cdk::api::call::reject_code(); + + let reject_code_number = match reject_code { + ic_cdk::api::call::RejectionCode::NoError => 0, + ic_cdk::api::call::RejectionCode::SysFatal => 1, + ic_cdk::api::call::RejectionCode::SysTransient => 2, + ic_cdk::api::call::RejectionCode::DestinationInvalid => 3, + ic_cdk::api::call::RejectionCode::CanisterReject => 4, + ic_cdk::api::call::RejectionCode::CanisterError => 5, + ic_cdk::api::call::RejectionCode::Unknown => 6, + }; + + reject_code_number + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_message.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_message.rs new file mode 100644 index 0000000000..5fa76ffa33 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_message.rs @@ -0,0 +1,5 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || ic_cdk::api::call::reject_message()).unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reply_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reply_raw.rs new file mode 100644 index 0000000000..4ef5b4295d --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reply_raw.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> rquickjs::Function { + Function::new(context, |bytes: rquickjs::TypedArray| { + ic_cdk::api::call::reply_raw(bytes.as_ref()); + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_certified_data.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_certified_data.rs new file mode 100644 index 0000000000..94a4fb1c67 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_certified_data.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |bytes: rquickjs::TypedArray| { + ic_cdk::api::set_certified_data(bytes.as_ref()); + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs new file mode 100644 index 0000000000..f675303c43 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs @@ -0,0 +1,33 @@ +use rquickjs::{Ctx, Function}; +use slotmap::Key; + +use crate::quickjs_with_ctx; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new(ctx, |delay: String, callback_id: String| { + let delay: u64 = delay.parse().unwrap(); + let delay_duration = core::time::Duration::new(delay, 0); + + let closure = move || { + quickjs_with_ctx(|ctx| { + let global = ctx.globals(); + let timer_callbacks = global + .get::<_, rquickjs::Object>("_azleTimerCallbacks") + .unwrap(); + let timer_callback: Function = timer_callbacks.get(callback_id.as_str()).unwrap(); + + let result = timer_callback.call::<_, rquickjs::Value>(()).unwrap(); + + if result.is_exception() { + panic!("Timer callback threw an exception"); + } + }); + }; + + let timer_id: ic_cdk_timers::TimerId = ic_cdk_timers::set_timer(delay_duration, closure); + let timer_id_u64: u64 = timer_id.data().as_ffi(); + + timer_id_u64 + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs new file mode 100644 index 0000000000..f79a5cf391 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs @@ -0,0 +1,34 @@ +use rquickjs::{Ctx, Function}; +use slotmap::Key; + +use crate::quickjs_with_ctx; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new(ctx, |interval: String, callback_id: String| { + let interval: u64 = interval.parse().unwrap(); + let interval_duration = core::time::Duration::new(interval, 0); + + let closure = move || { + quickjs_with_ctx(|ctx| { + let global = ctx.globals(); + let timer_callbacks = global + .get::<_, rquickjs::Object>("_azleTimerCallbacks") + .unwrap(); + let timer_callback: Function = timer_callbacks.get(callback_id.as_str()).unwrap(); + + let result = timer_callback.call::<_, rquickjs::Value>(()).unwrap(); + + if result.is_exception() { + panic!("Timer interval callback threw an exception"); + } + }); + }; + + let timer_id: ic_cdk_timers::TimerId = + ic_cdk_timers::set_timer_interval(interval_duration, closure); + let timer_id_u64: u64 = timer_id.data().as_ffi(); + + timer_id_u64 + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_contains_key.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_contains_key.rs new file mode 100644 index 0000000000..47e307ad83 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_contains_key.rs @@ -0,0 +1,17 @@ +use rquickjs::{Ctx, Function, TypedArray}; + +use crate::stable_b_tree_map::{AzleStableBTreeMapKey, STABLE_B_TREE_MAPS}; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new(ctx, |memory_id: u8, key_typed_array: TypedArray| { + let key_slice: &[u8] = key_typed_array.as_ref(); + let key: Vec = key_slice.to_vec(); + + STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let stable_b_tree_maps = stable_b_tree_maps.borrow(); + + stable_b_tree_maps[&memory_id].contains_key(&AzleStableBTreeMapKey { bytes: key }) + }) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_get.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_get.rs new file mode 100644 index 0000000000..7a554532f8 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_get.rs @@ -0,0 +1,21 @@ +use rquickjs::{Ctx, Function, TypedArray}; + +use crate::stable_b_tree_map::{ + AzleStableBTreeMapKey, AzleStableBTreeMapValue, STABLE_B_TREE_MAPS, +}; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new(ctx, |memory_id: u8, key_typed_array: TypedArray| { + let key_slice: &[u8] = key_typed_array.as_ref(); + let key: Vec = key_slice.to_vec(); + + STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let stable_b_tree_maps = stable_b_tree_maps.borrow(); + + stable_b_tree_maps[&memory_id] + .get(&AzleStableBTreeMapKey { bytes: key }) + .map(|value: AzleStableBTreeMapValue| value.bytes.clone()) + }) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_init.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_init.rs new file mode 100644 index 0000000000..30fbbf81d2 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_init.rs @@ -0,0 +1,20 @@ +use ic_stable_structures::{memory_manager::MemoryId, StableBTreeMap}; +use rquickjs::{Ctx, Function}; + +use crate::{stable_b_tree_map::STABLE_B_TREE_MAPS, MEMORY_MANAGER_REF_CELL}; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new(ctx, |memory_id: u8| { + STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let mut stable_b_tree_maps = stable_b_tree_maps.borrow_mut(); + + stable_b_tree_maps.insert( + memory_id, + StableBTreeMap::init( + MEMORY_MANAGER_REF_CELL.with(|m| m.borrow().get(MemoryId::new(memory_id))), + ), + ); + }); + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_insert.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_insert.rs new file mode 100644 index 0000000000..79953414f4 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_insert.rs @@ -0,0 +1,30 @@ +use rquickjs::{Ctx, Function, TypedArray}; + +use crate::stable_b_tree_map::{ + AzleStableBTreeMapKey, AzleStableBTreeMapValue, STABLE_B_TREE_MAPS, +}; + +pub fn get_function(context: Ctx) -> Function { + Function::new( + context, + |memory_id: u8, key_typed_array: TypedArray, value_typed_array: TypedArray| { + let key_slice: &[u8] = key_typed_array.as_ref(); + let key: Vec = key_slice.to_vec(); + + let value_slice: &[u8] = value_typed_array.as_ref(); + let value: Vec = value_slice.to_vec(); + + let value_option = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let mut stable_b_tree_maps = stable_b_tree_maps.borrow_mut(); + + stable_b_tree_maps.get_mut(&memory_id).unwrap().insert( + AzleStableBTreeMapKey { bytes: key }, + AzleStableBTreeMapValue { bytes: value }, + ) + }); + + value_option.map(|value| value.bytes) + }, + ) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_is_empty.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_is_empty.rs new file mode 100644 index 0000000000..9cef1f804a --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_is_empty.rs @@ -0,0 +1,13 @@ +use rquickjs::{Ctx, Function}; + +use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new(ctx, |memory_id: u8| { + STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let stable_b_tree_maps = stable_b_tree_maps.borrow(); + stable_b_tree_maps.get(&memory_id).unwrap().is_empty() + }) + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_items.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_items.rs new file mode 100644 index 0000000000..e0a284d577 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_items.rs @@ -0,0 +1,31 @@ +use std::convert::TryInto; + +use rquickjs::{Array, Ctx, FromIteratorJs, Function}; + +use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new( + ctx.clone(), + move |memory_id: u8, start_index: u64, length: i64| { + let items: Vec>> = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let stable_b_tree_maps = stable_b_tree_maps.borrow(); + let stable_b_tree_map = &stable_b_tree_maps[&memory_id]; + + stable_b_tree_map + .iter() + .skip(start_index.try_into().unwrap()) + .take(if length == -1 { + stable_b_tree_map.len().try_into().unwrap() + } else { + length.try_into().unwrap() + }) + .map(|(key, value)| vec![key.bytes, value.bytes]) + .collect() + }); + + Array::from_iter_js(&ctx, items.into_iter()) + }, + ) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_keys.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_keys.rs new file mode 100644 index 0000000000..a584f9899e --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_keys.rs @@ -0,0 +1,31 @@ +use std::convert::TryInto; + +use rquickjs::{Array, Ctx, FromIteratorJs, Function}; + +use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new( + ctx.clone(), + move |memory_id: u8, start_index: u64, length: i64| { + let keys: Vec> = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let stable_b_tree_maps = stable_b_tree_maps.borrow(); + let stable_b_tree_map = &stable_b_tree_maps[&memory_id]; + + stable_b_tree_map + .iter() + .skip(start_index.try_into().unwrap()) + .take(if length == -1 { + stable_b_tree_map.len().try_into().unwrap() + } else { + length.try_into().unwrap() + }) + .map(|(key, _)| key.bytes) + .collect() + }); + + Array::from_iter_js(&ctx, keys.into_iter()) + }, + ) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_len.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_len.rs new file mode 100644 index 0000000000..ecd41dfeca --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_len.rs @@ -0,0 +1,15 @@ +use rquickjs::{Ctx, Function}; + +use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |memory_id: u8| { + let len = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let stable_b_tree_maps = stable_b_tree_maps.borrow(); + stable_b_tree_maps[&memory_id].len() + }); + + len.to_string() + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_remove.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_remove.rs new file mode 100644 index 0000000000..536d361dbc --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_remove.rs @@ -0,0 +1,31 @@ +use rquickjs::{Ctx, Function, IntoJs, TypedArray}; + +use crate::stable_b_tree_map::{AzleStableBTreeMapKey, STABLE_B_TREE_MAPS}; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new( + ctx.clone(), + move |memory_id: u8, key_typed_array: TypedArray| { + let key_slice: &[u8] = key_typed_array.as_ref(); + let key: Vec = key_slice.to_vec(); + + let value_option = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let mut stable_b_tree_maps = stable_b_tree_maps.borrow_mut(); + + stable_b_tree_maps + .get_mut(&memory_id) + .unwrap() + .remove(&AzleStableBTreeMapKey { bytes: key }) + }); + + match value_option { + Some(value) => TypedArray::::new(ctx.clone(), value.bytes.as_slice()) + .unwrap() + .into_js(&ctx) + .unwrap(), + None => rquickjs::Undefined.into_js(&ctx).unwrap(), + } + }, + ) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_values.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_values.rs new file mode 100644 index 0000000000..89ad549ad0 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_values.rs @@ -0,0 +1,31 @@ +use std::convert::TryInto; + +use rquickjs::{Array, Ctx, FromIteratorJs, Function}; + +use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; + +pub fn get_function(ctx: Ctx) -> Function { + Function::new( + ctx.clone(), + move |memory_id: u8, start_index: u64, length: i64| { + let values: Vec> = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let stable_b_tree_maps = stable_b_tree_maps.borrow(); + let stable_b_tree_map = &stable_b_tree_maps[&memory_id]; + + stable_b_tree_map + .iter() + .skip(start_index.try_into().unwrap()) + .take(if length == -1 { + stable_b_tree_map.len().try_into().unwrap() + } else { + length.try_into().unwrap() + }) + .map(|(_, value)| value.bytes) + .collect() + }); + + Array::from_iter_js(&ctx, values.into_iter()) + }, + ) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/time.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/time.rs new file mode 100644 index 0000000000..43a150f23c --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/time.rs @@ -0,0 +1,5 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, || ic_cdk::api::time()).unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/trap.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/trap.rs new file mode 100644 index 0000000000..572aa5719f --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/trap.rs @@ -0,0 +1,8 @@ +use rquickjs::{Ctx, Function}; + +pub fn get_function(context: Ctx) -> Function { + Function::new(context, |message: String| { + ic_cdk::api::trap(&message); + }) + .unwrap() +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs new file mode 100644 index 0000000000..5c27679e0c --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs @@ -0,0 +1,115 @@ +use ic_stable_structures::memory_manager::MemoryId; + +use crate::{ + execute_method_js::execute_method_js, + ic, quickjs_with_ctx, + wasm_binary_manipulation::{get_js_code, get_wasm_data}, + CONTEXT_REF_CELL, MEMORY_MANAGER_REF_CELL, MODULE_NAME, WASM_DATA_REF_CELL, +}; + +#[inline(never)] +#[no_mangle] +pub extern "C" fn init(function_index: i32, pass_arg_data: i32) { + // Without something like this the init and post_upgrade functions + // seem to be optimized into the same function in the Wasm binary + // This causes problems during Wasm binary manipulation + format!("prevent init and post_upgrade optimization"); + + initialize(true, function_index, pass_arg_data); +} + +#[inline(never)] +#[no_mangle] +pub extern "C" fn post_upgrade(function_index: i32, pass_arg_data: i32) { + initialize(false, function_index, pass_arg_data); +} + +fn initialize(init: bool, function_index: i32, pass_arg_data: i32) { + let wasm_data = get_wasm_data(); + + WASM_DATA_REF_CELL.with(|wasm_data_ref_cell| { + *wasm_data_ref_cell.borrow_mut() = Some(wasm_data.clone()); + }); + + let env_vars: Vec<(&str, &str)> = wasm_data + .env_vars + .iter() + .map(|(key, value)| (key.as_str(), value.as_str())) + .collect(); + + let polyfill_memory = + MEMORY_MANAGER_REF_CELL.with(|manager| manager.borrow().get(MemoryId::new(254))); + ic_wasi_polyfill::init_with_memory(&[], &env_vars, polyfill_memory); + + let js = get_js_code(); + + initialize_js( + std::str::from_utf8(&js).unwrap(), + init, + function_index, + pass_arg_data, + ); +} + +// TODO do we need all these clonse? +// TODO do not forget to deal with the event loop everywhere +pub fn initialize_js(js: &str, init: bool, function_index: i32, pass_arg_data: i32) { + let runtime = rquickjs::Runtime::new().unwrap(); + let context = rquickjs::Context::full(&runtime).unwrap(); + + CONTEXT_REF_CELL.with(|context_ref_cell| { + *context_ref_cell.borrow_mut() = Some(context); + }); + + quickjs_with_ctx(|ctx| { + ctx.clone() + .globals() + .set("_azleNodeWasmEnvironment", false) + .unwrap(); + + ic::register(ctx.clone()); + + let env = rquickjs::Object::new(ctx.clone()).unwrap(); + + for (key, value) in std::env::vars() { + env.set(key, value).unwrap(); + } + + let process = rquickjs::Object::new(ctx.clone()).unwrap(); + + process.set("env", env).unwrap(); + + ctx.clone().globals().set("process", process).unwrap(); + + ctx.clone() + .globals() + .set("exports", rquickjs::Object::new(ctx.clone()).unwrap()) + .unwrap(); + + ctx.clone() + .globals() + .set("_azleExperimental", false) + .unwrap(); + + // TODO is there a better name for this main module? + // TODO this returns a promise...make sure we handle it appropriately + rquickjs::Module::evaluate(ctx.clone(), MODULE_NAME, js).unwrap(); + }); + + // TODO is it possible to just put this all in the same quickjs_with_ctx? + if function_index != -1 { + execute_method_js(function_index, pass_arg_data); + } + + // _azleInitCalled and _azlePostUpgradeCalled refer to Azle's own init/post_upgrade methods being called + // these variables do not indicate if the developer's own init/post_upgrade methods were called + quickjs_with_ctx(|ctx| { + let assignment = if init { + "globalThis._azleInitCalled = true;" + } else { + "globalThis._azlePostUpgradeCalled = true;" + }; + + ctx.eval::<(), _>(assignment).unwrap(); + }); +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs new file mode 100644 index 0000000000..f801ba0101 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs @@ -0,0 +1,46 @@ +// TODO the plan is to integrate rquickjs for stable +// TODO and at that time create two crates +// TODO we should place each crate at src/build/stable/commands/compile/rust +// TODO and src/build/experimental/commands/compile/rust respectively + +use std::cell::RefCell; + +// #[allow(unused)] +use ic_stable_structures::{ + memory_manager::{MemoryManager, VirtualMemory}, + DefaultMemoryImpl, +}; + +mod benchmarking; +mod candid; +mod chunk; +mod execute_method_js; +mod guards; +mod ic; +mod init_and_post_upgrade; +mod quickjs_with_ctx; +mod stable_b_tree_map; +mod wasm_binary_manipulation; + +use guards::guard_against_non_controllers; +pub use quickjs_with_ctx::quickjs_with_ctx; + +const MODULE_NAME: &str = "main"; + +#[allow(unused)] +type Memory = VirtualMemory; + +thread_local! { + static CONTEXT_REF_CELL: RefCell> = RefCell::new(None); + pub static MEMORY_MANAGER_REF_CELL: RefCell> = RefCell::new(MemoryManager::init(DefaultMemoryImpl::default())); + static WASM_DATA_REF_CELL: RefCell> = RefCell::new(None); +} + +#[ic_cdk_macros::update] +pub fn _azle_chunk() {} + +#[ic_cdk_macros::query(guard = guard_against_non_controllers)] +pub fn _azle_get_benchmarks() -> Vec { + benchmarking::BENCHMARKS_REF_CELL + .with(|benchmarks_ref_cell| benchmarks_ref_cell.borrow().clone()) +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs new file mode 100644 index 0000000000..9f5c999062 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs @@ -0,0 +1,30 @@ +use crate::CONTEXT_REF_CELL; +use rquickjs::Ctx; + +pub fn quickjs_with_ctx(callback: F) -> R +where + F: FnOnce(Ctx) -> R, +{ + CONTEXT_REF_CELL.with(|context_ref_cell| { + let context_ref = context_ref_cell.borrow(); + let context = context_ref.as_ref().unwrap(); + + context.with(|ctx| { + let result = callback(ctx.clone()); + + run_event_loop(ctx); + + result + }) + }) +} + +fn run_event_loop(ctx: rquickjs::Ctx) { + loop { + let result = ctx.execute_pending_job(); + + if result == false { + break; + } + } +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/stable_b_tree_map.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/stable_b_tree_map.rs new file mode 100644 index 0000000000..705b045999 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/stable_b_tree_map.rs @@ -0,0 +1,50 @@ +use std::{cell::RefCell, collections::BTreeMap}; + +use ic_stable_structures::{storable::Bound, StableBTreeMap, Storable}; + +use crate::Memory; + +#[allow(unused)] +type AzleStableBTreeMap = StableBTreeMap; + +thread_local! { + pub static STABLE_B_TREE_MAPS: RefCell> = RefCell::new(BTreeMap::new()); +} + +#[derive(Ord, PartialOrd, Eq, PartialEq, Clone)] +pub struct AzleStableBTreeMapKey { + pub bytes: Vec, +} + +impl Storable for AzleStableBTreeMapKey { + fn to_bytes(&self) -> std::borrow::Cow<[u8]> { + std::borrow::Cow::Borrowed(&self.bytes) + } + + fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self { + AzleStableBTreeMapKey { + bytes: bytes.to_vec(), + } + } + + const BOUND: Bound = Bound::Unbounded; +} + +#[derive(Ord, PartialOrd, Eq, PartialEq, Clone)] +pub struct AzleStableBTreeMapValue { + pub bytes: Vec, +} + +impl Storable for AzleStableBTreeMapValue { + fn to_bytes(&self) -> std::borrow::Cow<[u8]> { + std::borrow::Cow::Borrowed(&self.bytes) + } + + fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self { + AzleStableBTreeMapValue { + bytes: bytes.to_vec(), + } + } + + const BOUND: Bound = Bound::Unbounded; +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs new file mode 100644 index 0000000000..158db8a844 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs @@ -0,0 +1,59 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct WasmData { + #[serde(rename = "envVars")] + pub env_vars: Vec<(String, String)>, + #[serde(rename = "recordBenchmarks")] + pub record_benchmarks: bool, +} + +#[inline(never)] +#[no_mangle] +extern "C" fn init_js_passive_data(js_vec_location: i32) -> usize { + "123_456_789".parse::().unwrap() + js_vec_location as usize // TODO must be like this for weird optimization reasons +} + +// TODO seems we need to do this to stop the compiler from hard-coding the result of this function where it is called +// TODO hopefully there's a less hacky way to do this +#[inline(never)] +#[no_mangle] +extern "C" fn js_passive_data_size() -> usize { + "123_456_789".parse().unwrap() +} + +// TODO waiting on license inspired from https://github.com/adambratschikaye/wasm-inject-data/blob/main/src/static_wasm.rs +pub fn get_js_code() -> Vec { + let size = js_passive_data_size(); + let mut js_vec = vec![243; size]; + let js_vec_location = js_vec.as_mut_ptr() as i32; + + init_js_passive_data(js_vec_location); + + js_vec +} + +#[inline(never)] +#[no_mangle] +extern "C" fn init_wasm_data_passive_data(wasm_data_vec_location: i32) -> usize { + "123_456_789".parse::().unwrap() + wasm_data_vec_location as usize // TODO must be like this for weird optimization reasons +} + +// TODO seems we need to do this to stop the compiler from hard-coding the result of this function where it is called +// TODO hopefully there's a less hacky way to do this +#[inline(never)] +#[no_mangle] +extern "C" fn wasm_data_passive_data_size() -> usize { + "123_456_789".parse().unwrap() +} + +// TODO waiting on license inspired from https://github.com/adambratschikaye/wasm-inject-data/blob/main/src/static_wasm.rs +pub fn get_wasm_data() -> WasmData { + let size = wasm_data_passive_data_size(); + let mut wasm_data_vec = vec![243; size]; + let wasm_data_vec_location = wasm_data_vec.as_mut_ptr() as i32; + + init_wasm_data_passive_data(wasm_data_vec_location); + + serde_json::from_str(std::str::from_utf8(&wasm_data_vec).unwrap()).unwrap() +} diff --git a/src/build/stable/commands/template.ts b/src/build/stable/commands/template.ts index c782711231..9072e2478e 100644 --- a/src/build/stable/commands/template.ts +++ b/src/build/stable/commands/template.ts @@ -16,8 +16,12 @@ export async function runCommand(ioType: IOType): Promise { AZLE_PACKAGE_PATH, 'src', 'build', + 'stable', + 'commands', + 'compile', + 'wasm_binary', 'rust', - 'canister', + 'stable_canister_template', 'Cargo.toml' ), STABLE_STATIC_CANISTER_TEMPLATE_PATH, diff --git a/src/lib/experimental/canister_methods/execute_method.ts b/src/lib/experimental/canister_methods/execute_method.ts index 73bd2796ac..ca0b28ad2d 100644 --- a/src/lib/experimental/canister_methods/execute_method.ts +++ b/src/lib/experimental/canister_methods/execute_method.ts @@ -1,9 +1,9 @@ import '../experimental'; -import { handleUncaughtError } from '../../stable/error'; import { CandidType } from '../candid/candid_type'; import { decode } from '../candid/serde/decode'; import { encode } from '../candid/serde/encode'; +import { handleUncaughtError } from '../error'; import { ic } from '../ic'; import { CanisterMethodInfo } from './types/canister_method_info'; diff --git a/src/lib/experimental/error.ts b/src/lib/experimental/error.ts new file mode 100644 index 0000000000..3030d03540 --- /dev/null +++ b/src/lib/experimental/error.ts @@ -0,0 +1,10 @@ +// import { trap } from './ic_apis/trap'; // TODO why does this break bitcoin_psbt examples? https://github.com/demergent-labs/azle/issues/2003 +import { trap } from './ic/trap'; + +export function handleUncaughtError(rawError: any): never { + const error = rawError instanceof Error ? rawError : new Error(rawError); + + const azleError = `Uncaught ${error.name}: ${error.message}${error.stack}`; + + trap(azleError); +} diff --git a/src/lib/experimental/globals.ts b/src/lib/experimental/globals.ts index bf4661a95e..937838a511 100644 --- a/src/lib/experimental/globals.ts +++ b/src/lib/experimental/globals.ts @@ -1,4 +1,5 @@ import './experimental'; +import '../stable/globals'; // We import this to remove type errors having to do with the stable and experimental globals import { Buffer } from 'buffer'; import * as process from 'process'; @@ -9,8 +10,6 @@ import { v4 } from 'uuid'; import { azleFetch } from './fetch'; declare global { - // eslint-disable-next-line no-var - var _azleWebAssembly: any; // eslint-disable-next-line no-var var _azleOutgoingHttpOptionsSubnetSize: number | undefined; // eslint-disable-next-line no-var @@ -21,10 +20,15 @@ declare global { var _azleOutgoingHttpOptionsTransformMethodName: string | undefined; // eslint-disable-next-line no-var var _azleOutgoingHttpOptionsTransformContext: Uint8Array | undefined; + // eslint-disable-next-line no-var + var _azleWebAssembly: any; } globalThis._azleInsideCanister = - globalThis._azleIc === undefined ? false : true; + globalThis._azleIcExperimental === undefined && + globalThis._azleIcStable === undefined + ? false + : true; if (globalThis._azleInsideCanister === true) { // Even though these are set in stable/globals diff --git a/src/lib/experimental/ic/accept_message.ts b/src/lib/experimental/ic/accept_message.ts index 361a703dd9..917ebbf2d6 100644 --- a/src/lib/experimental/ic/accept_message.ts +++ b/src/lib/experimental/ic/accept_message.ts @@ -9,5 +9,9 @@ import { inspectMessage } from '../canister_methods/methods/inspect_message'; // * {@link inspectMessage} context will cause the canister to trap. */ export function acceptMessage(): Void { - return globalThis._azleIc ? globalThis._azleIc.acceptMessage() : undefined; + if (globalThis._azleIcExperimental === undefined) { + return undefined; + } + + return globalThis._azleIcExperimental.acceptMessage(); } diff --git a/src/lib/experimental/ic/arg_data_raw.ts b/src/lib/experimental/ic/arg_data_raw.ts index 7e453d2b46..fa0f1d7e56 100644 --- a/src/lib/experimental/ic/arg_data_raw.ts +++ b/src/lib/experimental/ic/arg_data_raw.ts @@ -7,7 +7,9 @@ import { blob } from '../candid/types/constructed/blob'; * @returns the argument data */ export function argDataRaw(): blob { - return new Uint8Array( - globalThis._azleIc ? globalThis._azleIc.argDataRaw() : [] - ); + if (globalThis._azleIcExperimental === undefined) { + return new Uint8Array(); + } + + return new Uint8Array(globalThis._azleIcExperimental.argDataRaw()); } diff --git a/src/lib/stable/ic_apis/azle_ic.ts b/src/lib/experimental/ic/azle_ic_experimental.ts similarity index 98% rename from src/lib/stable/ic_apis/azle_ic.ts rename to src/lib/experimental/ic/azle_ic_experimental.ts index 19c857c792..089296e4bd 100644 --- a/src/lib/stable/ic_apis/azle_ic.ts +++ b/src/lib/experimental/ic/azle_ic_experimental.ts @@ -2,7 +2,7 @@ * The interface for our rust methods it slightly different than the interface * we expose to the users. This is the interface for the rust functions. */ -export type AzleIc = { +export type AzleIcExperimental = { argDataRaw: () => ArrayBuffer; callRaw: ( promiseId: string, diff --git a/src/lib/experimental/ic/call.ts b/src/lib/experimental/ic/call.ts index 16c977d3ba..d160404aac 100644 --- a/src/lib/experimental/ic/call.ts +++ b/src/lib/experimental/ic/call.ts @@ -22,7 +22,7 @@ export function call any>( cycles?: nat; } ): ReturnTypeOf { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return undefined as any; } diff --git a/src/lib/experimental/ic/call_raw.ts b/src/lib/experimental/ic/call_raw.ts index f7108aca99..e716e1d882 100644 --- a/src/lib/experimental/ic/call_raw.ts +++ b/src/lib/experimental/ic/call_raw.ts @@ -23,13 +23,13 @@ export function callRaw( argsRaw: blob, payment: nat ): Promise { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return Promise.resolve(new Uint8Array()); } // TODO this should use a Result remember return new Promise((resolve, reject) => { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return new Uint8Array(); } @@ -62,7 +62,7 @@ export function callRaw( // TODO consider finally, what if deletion goes wrong try { - globalThis._azleIc.callRaw( + globalThis._azleIcExperimental.callRaw( promiseId, canisterIdBytes, method, diff --git a/src/lib/experimental/ic/caller.ts b/src/lib/experimental/ic/caller.ts index 19ba47ba7d..73e1005f64 100644 --- a/src/lib/experimental/ic/caller.ts +++ b/src/lib/experimental/ic/caller.ts @@ -7,10 +7,10 @@ import { Principal } from '../candid/types/reference/principal'; * @returns the caller of the current call */ export function caller(): Principal { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return Principal.fromHex('04'); } - const callerBytes = globalThis._azleIc.caller(); + const callerBytes = globalThis._azleIcExperimental.caller(); return Principal.fromUint8Array(new Uint8Array(callerBytes)); } diff --git a/src/lib/experimental/ic/candid_compiler.ts b/src/lib/experimental/ic/candid_compiler.ts index 05d0f4734c..8aa47f0e28 100644 --- a/src/lib/experimental/ic/candid_compiler.ts +++ b/src/lib/experimental/ic/candid_compiler.ts @@ -8,9 +8,9 @@ import { text } from '../candid/types/primitive/text'; * @returns the IDL string */ export function candidCompiler(candidPath: text): string { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return ''; } - return globalThis._azleIc.candidCompiler(candidPath); + return globalThis._azleIcExperimental.candidCompiler(candidPath); } diff --git a/src/lib/experimental/ic/candid_decode.ts b/src/lib/experimental/ic/candid_decode.ts index fd94735524..9a759591d2 100644 --- a/src/lib/experimental/ic/candid_decode.ts +++ b/src/lib/experimental/ic/candid_decode.ts @@ -9,9 +9,9 @@ import { text } from '../candid/types/primitive/text'; * @returns the Candid string */ export function candidDecode(candidEncoded: blob): text { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return ''; } - return globalThis._azleIc.candidDecode(candidEncoded.buffer); + return globalThis._azleIcExperimental.candidDecode(candidEncoded.buffer); } diff --git a/src/lib/experimental/ic/candid_encode.ts b/src/lib/experimental/ic/candid_encode.ts index 0efdfbba1e..7839434843 100644 --- a/src/lib/experimental/ic/candid_encode.ts +++ b/src/lib/experimental/ic/candid_encode.ts @@ -9,7 +9,11 @@ import { text } from '../candid/types/primitive/text'; * @returns the candid value as bytes */ export function candidEncode(candidString: text): blob { + if (globalThis._azleIcExperimental === undefined) { + return new Uint8Array(); + } + return new Uint8Array( - globalThis._azleIc ? globalThis._azleIc.candidEncode(candidString) : [] + globalThis._azleIcExperimental.candidEncode(candidString) ); } diff --git a/src/lib/experimental/ic/canister_balance.ts b/src/lib/experimental/ic/canister_balance.ts index 12d1a963e9..b27ab4de09 100644 --- a/src/lib/experimental/ic/canister_balance.ts +++ b/src/lib/experimental/ic/canister_balance.ts @@ -7,9 +7,9 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the number of cycles in the canister */ export function canisterBalance(): nat64 { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } - return BigInt(globalThis._azleIc.canisterBalance()); + return BigInt(globalThis._azleIcExperimental.canisterBalance()); } diff --git a/src/lib/experimental/ic/canister_version.ts b/src/lib/experimental/ic/canister_version.ts index 35950c193e..d309cb0885 100644 --- a/src/lib/experimental/ic/canister_version.ts +++ b/src/lib/experimental/ic/canister_version.ts @@ -8,9 +8,9 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the version number */ export function canisterVersion(): nat64 { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } - return BigInt(globalThis._azleIc.canisterVersion()); + return BigInt(globalThis._azleIcExperimental.canisterVersion()); } diff --git a/src/lib/experimental/ic/chunk.ts b/src/lib/experimental/ic/chunk.ts index 6860bbdf39..507a6d9aba 100644 --- a/src/lib/experimental/ic/chunk.ts +++ b/src/lib/experimental/ic/chunk.ts @@ -3,7 +3,7 @@ import '../experimental'; import { ic } from './'; export async function chunk(): Promise { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return undefined; } diff --git a/src/lib/experimental/ic/clear_timer.ts b/src/lib/experimental/ic/clear_timer.ts index e0251ae0b5..0d2198256b 100644 --- a/src/lib/experimental/ic/clear_timer.ts +++ b/src/lib/experimental/ic/clear_timer.ts @@ -7,11 +7,11 @@ import { Void } from '../candid/types/primitive/void'; * @param id The ID of the timer to be cancelled. */ export function clearTimer(timerId: bigint): Void { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return undefined; } - globalThis._azleIc.clearTimer(timerId.toString()); + globalThis._azleIcExperimental.clearTimer(timerId.toString()); const timerCallbackId = globalThis._azleIcTimers[timerId.toString()]; diff --git a/src/lib/experimental/ic/data_certificate.ts b/src/lib/experimental/ic/data_certificate.ts index 77a02d7658..d2235b1102 100644 --- a/src/lib/experimental/ic/data_certificate.ts +++ b/src/lib/experimental/ic/data_certificate.ts @@ -10,11 +10,11 @@ import { None, Opt, Some } from '../candid/types/constructed/opt'; * @returns the data certificate or None */ export function dataCertificate(): Opt { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return None; } - const rawRustValue = globalThis._azleIc.dataCertificate(); + const rawRustValue = globalThis._azleIcExperimental.dataCertificate(); return rawRustValue === undefined ? None diff --git a/src/lib/experimental/ic/id.ts b/src/lib/experimental/ic/id.ts index 426a5f4333..f63be1f617 100644 --- a/src/lib/experimental/ic/id.ts +++ b/src/lib/experimental/ic/id.ts @@ -7,11 +7,11 @@ import { Principal } from '../candid/types/reference/principal'; * @returns the canister id */ export function id(): Principal { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return Principal.fromHex('04'); } // TODO consider bytes instead of string, just like with caller - const idString = globalThis._azleIc.id(); + const idString = globalThis._azleIcExperimental.id(); return Principal.fromText(idString); } diff --git a/src/lib/experimental/ic/instruction_counter.ts b/src/lib/experimental/ic/instruction_counter.ts index 57ae63c289..57fb154948 100644 --- a/src/lib/experimental/ic/instruction_counter.ts +++ b/src/lib/experimental/ic/instruction_counter.ts @@ -11,9 +11,9 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the number of instructions */ export function instructionCounter(): nat64 { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } - return BigInt(globalThis._azleIc.instructionCounter()); + return BigInt(globalThis._azleIcExperimental.instructionCounter()); } diff --git a/src/lib/experimental/ic/is_controller.ts b/src/lib/experimental/ic/is_controller.ts index f010a4f8d9..9680266df8 100644 --- a/src/lib/experimental/ic/is_controller.ts +++ b/src/lib/experimental/ic/is_controller.ts @@ -5,9 +5,11 @@ import { Principal } from '../candid/types/reference/principal'; /** Determine if a {@link Principal} is a controller of the canister. */ export function isController(principal: Principal): bool { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return false; } - return globalThis._azleIc.isController(principal.toUint8Array().buffer); + return globalThis._azleIcExperimental.isController( + principal.toUint8Array().buffer + ); } diff --git a/src/lib/experimental/ic/method_name.ts b/src/lib/experimental/ic/method_name.ts index 9fb7e5d873..172cb68818 100644 --- a/src/lib/experimental/ic/method_name.ts +++ b/src/lib/experimental/ic/method_name.ts @@ -7,5 +7,9 @@ import { text } from '../candid/types/primitive/text'; * @returns the current canister method */ export function methodName(): text { - return globalThis._azleIc ? globalThis._azleIc.methodName() : ''; + if (globalThis._azleIcExperimental === undefined) { + return ''; + } + + return globalThis._azleIcExperimental.methodName(); } diff --git a/src/lib/experimental/ic/msg_cycles_accept.ts b/src/lib/experimental/ic/msg_cycles_accept.ts index 68b6bb5b83..2ca031cc91 100644 --- a/src/lib/experimental/ic/msg_cycles_accept.ts +++ b/src/lib/experimental/ic/msg_cycles_accept.ts @@ -8,13 +8,12 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the actual amount moved */ export function msgCyclesAccept(maxAmount: nat64): nat64 { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } - const msgCyclesAcceptAmountMovedString = globalThis._azleIc.msgCyclesAccept( - maxAmount.toString() - ); + const msgCyclesAcceptAmountMovedString = + globalThis._azleIcExperimental.msgCyclesAccept(maxAmount.toString()); return BigInt(msgCyclesAcceptAmountMovedString); } diff --git a/src/lib/experimental/ic/msg_cycles_available.ts b/src/lib/experimental/ic/msg_cycles_available.ts index 338c882f1e..5b1b7cea11 100644 --- a/src/lib/experimental/ic/msg_cycles_available.ts +++ b/src/lib/experimental/ic/msg_cycles_available.ts @@ -8,12 +8,12 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the amount of cycles */ export function msgCyclesAvailable(): nat64 { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } const msgCyclesAvailableAmountString = - globalThis._azleIc.msgCyclesAvailable(); + globalThis._azleIcExperimental.msgCyclesAvailable(); return BigInt(msgCyclesAvailableAmountString); } diff --git a/src/lib/experimental/ic/msg_cycles_refunded.ts b/src/lib/experimental/ic/msg_cycles_refunded.ts index 8de30a1cdd..7eb091649e 100644 --- a/src/lib/experimental/ic/msg_cycles_refunded.ts +++ b/src/lib/experimental/ic/msg_cycles_refunded.ts @@ -8,12 +8,12 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the amount of cycles */ export function msgCyclesRefunded(): nat64 { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } const msgCyclesRefundedAmountString = - globalThis._azleIc.msgCyclesRefunded(); + globalThis._azleIcExperimental.msgCyclesRefunded(); return BigInt(msgCyclesRefundedAmountString); } diff --git a/src/lib/experimental/ic/notify.ts b/src/lib/experimental/ic/notify.ts index af668ad8e2..70365b0036 100644 --- a/src/lib/experimental/ic/notify.ts +++ b/src/lib/experimental/ic/notify.ts @@ -41,7 +41,7 @@ export function notify any>( cycles?: nat; } ): Void { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return undefined; } diff --git a/src/lib/experimental/ic/notify_raw.ts b/src/lib/experimental/ic/notify_raw.ts index a731ad01b2..a7394ee622 100644 --- a/src/lib/experimental/ic/notify_raw.ts +++ b/src/lib/experimental/ic/notify_raw.ts @@ -20,7 +20,7 @@ export function notifyRaw( argsRaw: blob, payment: nat ): Void { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return undefined; } @@ -28,7 +28,7 @@ export function notifyRaw( const argsRawBuffer = argsRaw.buffer; const paymentString = payment.toString(); - return globalThis._azleIc.notifyRaw( + return globalThis._azleIcExperimental.notifyRaw( canisterIdBytes, method, argsRawBuffer, diff --git a/src/lib/experimental/ic/performance_counter.ts b/src/lib/experimental/ic/performance_counter.ts index 2645b8ed6a..868da6e82d 100644 --- a/src/lib/experimental/ic/performance_counter.ts +++ b/src/lib/experimental/ic/performance_counter.ts @@ -13,11 +13,13 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the performance counter metric */ export function performanceCounter(counterType: nat32): nat64 { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } return BigInt( - globalThis._azleIc.performanceCounter(counterType.toString()) + globalThis._azleIcExperimental.performanceCounter( + counterType.toString() + ) ); } diff --git a/src/lib/experimental/ic/print.ts b/src/lib/experimental/ic/print.ts index 56d4c0cda8..89cd7e55f3 100644 --- a/src/lib/experimental/ic/print.ts +++ b/src/lib/experimental/ic/print.ts @@ -7,5 +7,9 @@ import { Void } from '../candid/types/primitive/void'; * @param args the message to print */ export function print(...args: any): Void { - return globalThis._azleIc ? globalThis._azleIc.print(...args) : undefined; + if (globalThis._azleIcExperimental === undefined) { + return undefined; + } + + globalThis._azleIcExperimental.print(...args); } diff --git a/src/lib/experimental/ic/reject.ts b/src/lib/experimental/ic/reject.ts index 93be1250c9..d1054a4038 100644 --- a/src/lib/experimental/ic/reject.ts +++ b/src/lib/experimental/ic/reject.ts @@ -8,5 +8,9 @@ import { Void } from '../candid/types/primitive/void'; * @param message the rejection message */ export function reject(message: text): Void { - return globalThis._azleIc ? globalThis._azleIc.reject(message) : undefined; + if (globalThis._azleIcExperimental === undefined) { + return undefined; + } + + globalThis._azleIcExperimental.reject(message); } diff --git a/src/lib/experimental/ic/reject_code.ts b/src/lib/experimental/ic/reject_code.ts index d17eeb2e11..9fd7575dd5 100644 --- a/src/lib/experimental/ic/reject_code.ts +++ b/src/lib/experimental/ic/reject_code.ts @@ -8,11 +8,13 @@ import { RejectionCode } from '../system_types'; * @returns the rejection code */ export function rejectCode(): RejectionCode { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return { Unknown: null }; } - const rejectCodeNumber = Number(globalThis._azleIc.rejectCode()); + const rejectCodeNumber = Number( + globalThis._azleIcExperimental.rejectCode() + ); switch (rejectCodeNumber) { case 0: diff --git a/src/lib/experimental/ic/reject_message.ts b/src/lib/experimental/ic/reject_message.ts index e3c822647e..5b455dfc73 100644 --- a/src/lib/experimental/ic/reject_message.ts +++ b/src/lib/experimental/ic/reject_message.ts @@ -14,5 +14,9 @@ import { ic } from '../ic'; // Used for links in comments * @returns the rejection message */ export function rejectMessage(): text { - return globalThis._azleIc ? globalThis._azleIc.rejectMessage() : ''; + if (globalThis._azleIcExperimental === undefined) { + return ''; + } + + return globalThis._azleIcExperimental.rejectMessage(); } diff --git a/src/lib/experimental/ic/reply.ts b/src/lib/experimental/ic/reply.ts index d5895ed91a..636dff6c88 100644 --- a/src/lib/experimental/ic/reply.ts +++ b/src/lib/experimental/ic/reply.ts @@ -33,14 +33,16 @@ type ReplyInput = * ``` */ export function reply(input: ReplyInput): Void { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return undefined; } if ('raw' in input) { - return globalThis._azleIc.replyRaw(input.raw.buffer); + return globalThis._azleIcExperimental.replyRaw(input.raw.buffer); } else { const { candidType: type, data } = input; - return globalThis._azleIc.replyRaw(encode(type, data).buffer); + return globalThis._azleIcExperimental.replyRaw( + encode(type, data).buffer + ); } } diff --git a/src/lib/experimental/ic/set_certified_data.ts b/src/lib/experimental/ic/set_certified_data.ts index 4a0913f772..536933a53c 100644 --- a/src/lib/experimental/ic/set_certified_data.ts +++ b/src/lib/experimental/ic/set_certified_data.ts @@ -26,9 +26,9 @@ import { Void } from '../candid/types/primitive/void'; * @returns */ export function setCertifiedData(data: blob): Void { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return undefined; } - return globalThis._azleIc.setCertifiedData(data.buffer); + return globalThis._azleIcExperimental.setCertifiedData(data.buffer); } diff --git a/src/lib/experimental/ic/set_timer.ts b/src/lib/experimental/ic/set_timer.ts index a0535e44e4..00434645f1 100644 --- a/src/lib/experimental/ic/set_timer.ts +++ b/src/lib/experimental/ic/set_timer.ts @@ -15,13 +15,13 @@ export function setTimer( delay: bigint, callback: () => void | Promise ): bigint { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } const timerCallbackId = `_timer_${v4()}`; - const timerId = globalThis._azleIc.setTimer( + const timerId = globalThis._azleIcExperimental.setTimer( delay.toString(), timerCallbackId ); diff --git a/src/lib/experimental/ic/set_timer_interval.ts b/src/lib/experimental/ic/set_timer_interval.ts index 8e6fe633dc..0031b3712b 100644 --- a/src/lib/experimental/ic/set_timer_interval.ts +++ b/src/lib/experimental/ic/set_timer_interval.ts @@ -15,13 +15,13 @@ export function setTimerInterval( interval: bigint, callback: () => void | Promise ): bigint { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } const timerCallbackId = `_interval_timer_${v4()}`; - const timerId = globalThis._azleIc.setTimerInterval( + const timerId = globalThis._azleIcExperimental.setTimerInterval( interval.toString(), timerCallbackId ); diff --git a/src/lib/experimental/ic/time.ts b/src/lib/experimental/ic/time.ts index 1bbad14f94..488ca0506f 100644 --- a/src/lib/experimental/ic/time.ts +++ b/src/lib/experimental/ic/time.ts @@ -7,9 +7,9 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the current timestamp */ export function time(): nat64 { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { return 0n; } - return BigInt(globalThis._azleIc.time()); + return BigInt(globalThis._azleIcExperimental.time()); } diff --git a/src/lib/experimental/ic/trap.ts b/src/lib/experimental/ic/trap.ts index 4e46c8c370..5af6ff6318 100644 --- a/src/lib/experimental/ic/trap.ts +++ b/src/lib/experimental/ic/trap.ts @@ -9,9 +9,9 @@ import { text } from '../candid/types/primitive/text'; * @param message the rejection message */ export function trap(message: text): empty { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcExperimental === undefined) { throw new Error(); } - return globalThis._azleIc.trap(message); + return globalThis._azleIcExperimental.trap(message); } diff --git a/src/lib/experimental/index.ts b/src/lib/experimental/index.ts index 946f08e6dd..e3b4519563 100644 --- a/src/lib/experimental/index.ts +++ b/src/lib/experimental/index.ts @@ -3,12 +3,12 @@ import './globals'; import '../../../type_tests'; export * from '../stable/json'; -export * from '../stable/stable_structures/stable_b_tree_map'; export * from '../stable/stable_structures/stable_json'; export * from './candid'; export * from './canister_methods'; export { serialize } from './fetch'; export * from './ic'; export * from './server'; +export * from './stable_structures/stable_b_tree_map'; export * from './system_types'; export * from './threshold_wallet'; diff --git a/src/lib/experimental/stable_structures/stable_b_tree_map.ts b/src/lib/experimental/stable_structures/stable_b_tree_map.ts new file mode 100644 index 0000000000..f21300ef52 --- /dev/null +++ b/src/lib/experimental/stable_structures/stable_b_tree_map.ts @@ -0,0 +1,237 @@ +import { stableJson } from '../../stable/stable_structures/stable_json'; + +export interface Serializable { + toBytes: (data: any) => Uint8Array; + fromBytes: (bytes: Uint8Array) => any; +} + +// TODO make this function's return type explicit https://github.com/demergent-labs/azle/issues/1860 +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export function StableBTreeMap( + memoryIdNumber: number, + keySerializable: Serializable = stableJson, + valueSerializable: Serializable = stableJson +) { + const memoryId = memoryIdNumber.toString(); + + if ( + globalThis._azleIcExperimental !== undefined && + globalThis._azleNodeWasmEnvironment !== true + ) { + globalThis._azleIcExperimental.stableBTreeMapInit(memoryId); + } + + isSerializable(keySerializable); + isSerializable(valueSerializable); + + return { + /** + * Checks if the given key exists in the map. + * @param key the key to check. + * @returns `true` if the key exists in the map, `false` otherwise. + */ + containsKey(key: Key): boolean { + if (globalThis._azleIcExperimental === undefined) { + return undefined as any; + } + + const encodedKey = keySerializable.toBytes(key).buffer; + + return globalThis._azleIcExperimental.stableBTreeMapContainsKey( + memoryId, + encodedKey + ); + }, + /** + * Retrieves the value stored at the provided key. + * @param key the location from which to retrieve. + * @returns the value associated with the given key, if it exists. + */ + get(key: Key): Value | null { + if (globalThis._azleIcExperimental === undefined) { + return undefined as any; + } + + const encodedKey = keySerializable.toBytes(key).buffer; + + const encodedResult = + globalThis._azleIcExperimental.stableBTreeMapGet( + memoryId, + encodedKey + ); + + if (encodedResult === undefined) { + return null; + } else { + return valueSerializable.fromBytes( + new Uint8Array(encodedResult) + ); + } + }, + /** + * Inserts a value into the map at the provided key. + * @param key the location at which to insert. + * @param value the value to insert. + * @returns the previous value of the key, if present. + */ + insert(key: Key, value: Value): Value | null { + if (globalThis._azleIcExperimental === undefined) { + return undefined as any; + } + + const encodedKey = keySerializable.toBytes(key).buffer; + const encodedValue = valueSerializable.toBytes(value).buffer; + + const encodedResult = + globalThis._azleIcExperimental.stableBTreeMapInsert( + memoryId, + encodedKey, + encodedValue + ); + + if (encodedResult === undefined) { + return null; + } else { + return valueSerializable.fromBytes( + new Uint8Array(encodedResult) + ); + } + }, + /** + * Checks if the map is empty. + * @returns `true` if the map contains no elements, `false` otherwise. + */ + isEmpty(): boolean { + if (globalThis._azleIcExperimental === undefined) { + return undefined as any; + } + + return globalThis._azleIcExperimental.stableBTreeMapIsEmpty( + memoryId + ); + }, + /** + * Retrieves the items in the map in sorted order. + * @param startIndex the starting index to begin retrieval + * @param length the number of items to retrieve + * @returns tuples representing key/value pairs. + */ + items(startIndex?: number, length?: number): [Key, Value][] { + if (globalThis._azleIcExperimental === undefined) { + return undefined as any; + } + + const encodedItems = + globalThis._azleIcExperimental.stableBTreeMapItems( + memoryId, + startIndex?.toString() ?? '0', + length?.toString() ?? 'NOT_SET' + ); + + // TODO too much copying + return encodedItems.map(([encodedKey, encodedValue]) => { + return [ + keySerializable.fromBytes(new Uint8Array(encodedKey)), + valueSerializable.fromBytes(new Uint8Array(encodedValue)) + ]; + }); + }, + /** + * The keys for each element in the map in sorted order. + * @param startIndex the starting index to begin retrieval + * @param length the number of keys to retrieve + * @returns they keys in the map. + */ + keys(startIndex?: number, length?: number): Key[] { + if (globalThis._azleIcExperimental === undefined) { + return undefined as any; + } + + const encodedKeys = + globalThis._azleIcExperimental.stableBTreeMapKeys( + memoryId, + startIndex?.toString() ?? '0', + length?.toString() ?? 'NOT_SET' + ); + + // TODO too much copying + return encodedKeys.map((encodedKey) => { + return keySerializable.fromBytes(new Uint8Array(encodedKey)); + }); + }, + /** + * Checks to see how many elements are in the map. + * @returns the number of elements in the map. + */ + len(): bigint { + if (globalThis._azleIcExperimental === undefined) { + return undefined as any; + } + + return BigInt( + globalThis._azleIcExperimental.stableBTreeMapLen(memoryId) + ); + }, + /** + * Removes a key from the map. + * @param key the location from which to remove. + * @returns the previous value at the key if it exists, `null` otherwise. + */ + remove(key: Key): Value | null { + if (globalThis._azleIcExperimental === undefined) { + return undefined as any; + } + + const encodedKey = keySerializable.toBytes(key).buffer; + + const encodedValue = + globalThis._azleIcExperimental.stableBTreeMapRemove( + memoryId, + encodedKey + ); + + if (encodedValue === undefined) { + return null; + } else { + return valueSerializable.fromBytes( + new Uint8Array(encodedValue) + ); + } + }, + /** + * The values in the map in sorted order. + * @param startIndex the starting index to begin retrieval + * @param length the number of values to retrieve + * @returns the values in the map. + */ + values(startIndex?: number, length?: number): Value[] { + if (globalThis._azleIcExperimental === undefined) { + return undefined as any; + } + + const encodedValues = + globalThis._azleIcExperimental.stableBTreeMapValues( + memoryId, + startIndex?.toString() ?? '0', + length?.toString() ?? 'NOT_SET' + ); + + // TODO too much copying + return encodedValues.map((encodedValue) => { + return valueSerializable.fromBytes( + new Uint8Array(encodedValue) + ); + }); + } + }; +} + +function isSerializable(obj: any): asserts obj is Serializable { + if (obj.toBytes === undefined) { + throw new Error(`value must have a toBytes method`); + } + + if (obj.fromBytes === undefined) { + throw new Error(`value must have a fromBytes method`); + } +} diff --git a/src/lib/stable/globals.ts b/src/lib/stable/globals.ts index 72b45c8951..23ba0ba67c 100644 --- a/src/lib/stable/globals.ts +++ b/src/lib/stable/globals.ts @@ -2,9 +2,10 @@ import { IDL } from '@dfinity/candid'; import { TextDecoder, TextEncoder } from 'text-encoding'; import { MethodMeta } from '../../build/stable/utils/types'; +import { AzleIcExperimental } from '../experimental/ic/azle_ic_experimental'; import { jsonReplacer } from '../stable/stable_structures/stable_json'; import { print } from './ic_apis'; -import { AzleIc } from './ic_apis/azle_ic'; +import { AzleIcStable } from './ic_apis/azle_ic_stable'; type Callbacks = { [key: string]: (...args: any) => any; @@ -24,7 +25,9 @@ declare global { // eslint-disable-next-line no-var var _azleExperimental: boolean; // eslint-disable-next-line no-var - var _azleIc: AzleIc; + var _azleIcExperimental: AzleIcExperimental; + // eslint-disable-next-line no-var + var _azleIcStable: AzleIcStable; // eslint-disable-next-line no-var var _azleIcTimers: { [key: string]: string }; // eslint-disable-next-line no-var @@ -44,13 +47,16 @@ declare global { // eslint-disable-next-line no-var var _azleRejectIds: { [key: string]: (err: any) => void }; // eslint-disable-next-line no-var - var _azleResolveIds: { [key: string]: (buf: ArrayBuffer) => void }; + var _azleResolveIds: { [key: string]: (buf: Uint8Array) => void }; // eslint-disable-next-line no-var var _azleTimerCallbacks: { [key: string]: () => void }; } globalThis._azleInsideCanister = - globalThis._azleIc === undefined ? false : true; + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ? false + : true; // TODO do we need to disable setTimeout, setInterval, etc? // TODO do we need to disable any other wasmedge-quickjs globals diff --git a/src/lib/stable/ic_apis/accept_message.ts b/src/lib/stable/ic_apis/accept_message.ts index ba8042c384..6616f1fb11 100644 --- a/src/lib/stable/ic_apis/accept_message.ts +++ b/src/lib/stable/ic_apis/accept_message.ts @@ -6,5 +6,17 @@ import { inspectMessage } from '../canister_methods/inspect_message'; // Used fo * {@link inspectMessage} context will cause the canister to trap. */ export function acceptMessage(): void { - return globalThis._azleIc ? globalThis._azleIc.acceptMessage() : undefined; + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return; + } + + if (globalThis._azleIcExperimental !== undefined) { + globalThis._azleIcExperimental.acceptMessage(); + return; + } + + globalThis._azleIcStable.acceptMessage(); } diff --git a/src/lib/stable/ic_apis/arg_data_raw.ts b/src/lib/stable/ic_apis/arg_data_raw.ts index d27984e631..78d1932e72 100644 --- a/src/lib/stable/ic_apis/arg_data_raw.ts +++ b/src/lib/stable/ic_apis/arg_data_raw.ts @@ -3,7 +3,16 @@ * @returns the argument data */ export function argDataRaw(): Uint8Array { - return new Uint8Array( - globalThis._azleIc ? globalThis._azleIc.argDataRaw() : [] - ); + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return new Uint8Array(); + } + + if (globalThis._azleIcExperimental !== undefined) { + return new Uint8Array(globalThis._azleIcExperimental.argDataRaw()); + } + + return globalThis._azleIcStable.argDataRaw(); } diff --git a/src/lib/stable/ic_apis/azle_ic_stable.ts b/src/lib/stable/ic_apis/azle_ic_stable.ts new file mode 100644 index 0000000000..fde62fc137 --- /dev/null +++ b/src/lib/stable/ic_apis/azle_ic_stable.ts @@ -0,0 +1,92 @@ +/** + * The interface for our rust methods it slightly different than the interface + * we expose to the users. This is the interface for the rust functions. + */ +export type AzleIcStable = { + argDataRaw: () => Uint8Array; + callRaw: ( + promiseId: string, + canisterIdBytes: Uint8Array, + method: string, + argsRaw: Uint8Array, + paymentString: string + ) => void; + caller: () => Uint8Array; + candidCompiler: (candidPath: string) => string; + candidDecode: (candidBytes: Uint8Array) => string; + candidEncode: (candidString: string) => Uint8Array; + canisterBalance: () => string; + canisterVersion: () => bigint; + clearTimer: (timerId: string) => void; + cyclesBurn: (amountString: string) => string; + dataCertificate: () => Uint8Array | undefined; + id: () => Uint8Array; + instructionCounter: () => bigint; + isController: (principalBytes: Uint8Array) => boolean; + msgCyclesAccept: (maxAmountString: string) => string; + msgCyclesAvailable: () => string; + msgCyclesRefunded: () => string; + notifyRaw: ( + canisterIdBytes: Uint8Array, + method: string, + argsRawBuffer: Uint8Array, + paymentString: string + ) => void; + performanceCounter: (counterType: number) => bigint; + rejectCode: () => number; + replyRaw: (bytes: Uint8Array) => void; + setCertifiedData: (dataBytes: Uint8Array) => void; + setTimer: (delay: string, timerCallbackId: string) => bigint; + setTimerInterval: (interval: string, timerCallbackId: string) => bigint; + time: () => bigint; + // These calls aren't intercepted by our IC object, they go right to the + // rust version and come out. Since they don't need to be intercepted I am + // assuming that their types are the same as the types declared by our + // interceptor. + acceptMessage: () => void; + methodName: () => string; + print: (...args: any) => void; + reject: (message: string) => void; + rejectMessage: () => string; + trap: (message: string) => never; + // These calls are intercepted by our IC object and redirected to their + // corresponding raw version. The rust version is never called, we don't + // have enough info about types to do so + call: () => never; + notify: () => never; + reply: () => never; + // Stable B Tree Map Functions + stableBTreeMapInit: (memoryId: number) => void; + stableBTreeMapContainsKey: ( + memoryId: number, + encodedKey: Uint8Array + ) => boolean; + stableBTreeMapGet: ( + memoryId: number, + encodedKey: Uint8Array + ) => Uint8Array | undefined; + stableBTreeMapInsert: ( + memoryId: number, + encodedKey: Uint8Array, + encodedValue: Uint8Array + ) => Uint8Array | undefined; + stableBTreeMapIsEmpty: (memoryId: number) => boolean; + // TODO should these indexes and lengths be bigints for future proofing? + stableBTreeMapItems: ( + memoryId: number, + startIndex: number, + length: number + ) => [Uint8Array, Uint8Array][]; + stableBTreeMapKeys: ( + memoryId: number, + startIndex: number, + length: number + ) => Uint8Array[]; + stableBTreeMapLen: (memoryId: number) => bigint; + stableBTreeMapRemove(memoryId: number, encodedKey: Uint8Array): Uint8Array; + stableBTreeMapValues: ( + memoryId: number, + startIndex: number, + length: number + ) => Uint8Array[]; +}; diff --git a/src/lib/stable/ic_apis/call.ts b/src/lib/stable/ic_apis/call.ts index 4d7c0213bb..cf728b7ad7 100644 --- a/src/lib/stable/ic_apis/call.ts +++ b/src/lib/stable/ic_apis/call.ts @@ -15,7 +15,10 @@ export async function call( ): Promise { // TODO this should use a Result remember return new Promise((resolve, reject) => { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return undefined; } @@ -30,10 +33,10 @@ export async function call( // TODO for example, we can keep the time with these // TODO if they are over a certain amount old we can delete them globalThis._azleResolveIds[globalResolveId] = ( - result: ArrayBuffer + result: Uint8Array ): void => { if (raw !== undefined) { - resolve(new Uint8Array(result) as Return); + resolve(result as Return); } else { const idlType = returnTypeIdl === undefined ? [] : [returnTypeIdl]; @@ -59,22 +62,32 @@ export async function call( typeof canisterId === 'string' ? Principal.fromText(canisterId) : canisterId; - const canisterIdBytes = canisterIdPrincipal.toUint8Array().buffer; - const argsRawBuffer = + const canisterIdBytes = canisterIdPrincipal.toUint8Array(); + const argsRaw = raw === undefined - ? new Uint8Array(IDL.encode(paramIdlTypes, args)).buffer - : raw.buffer; + ? new Uint8Array(IDL.encode(paramIdlTypes, args)) + : raw; const paymentString = payment.toString(); // TODO consider finally, what if deletion goes wrong try { - globalThis._azleIc.callRaw( - promiseId, - canisterIdBytes, - method, - argsRawBuffer, - paymentString - ); + if (globalThis._azleIcExperimental !== undefined) { + globalThis._azleIcExperimental.callRaw( + promiseId, + canisterIdBytes.buffer, + method, + argsRaw.buffer, + paymentString + ); + } else { + globalThis._azleIcStable.callRaw( + promiseId, + canisterIdBytes, + method, + argsRaw, + paymentString + ); + } } catch (error) { delete globalThis._azleResolveIds[globalResolveId]; delete globalThis._azleRejectIds[globalRejectId]; diff --git a/src/lib/stable/ic_apis/caller.ts b/src/lib/stable/ic_apis/caller.ts index df8b43cab5..4856b74b44 100644 --- a/src/lib/stable/ic_apis/caller.ts +++ b/src/lib/stable/ic_apis/caller.ts @@ -5,10 +5,18 @@ import { Principal } from '@dfinity/principal'; * @returns the principal of the caller of the current call */ export function caller(): Principal { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return Principal.fromHex('04'); } - const callerBytes = globalThis._azleIc.caller(); - return Principal.fromUint8Array(new Uint8Array(callerBytes)); + if (globalThis._azleIcExperimental !== undefined) { + return Principal.fromUint8Array( + new Uint8Array(globalThis._azleIcExperimental.caller()) + ); + } + + return Principal.fromUint8Array(globalThis._azleIcStable.caller()); } diff --git a/src/lib/stable/ic_apis/candid_compiler.ts b/src/lib/stable/ic_apis/candid_compiler.ts index 623bfee08d..4084043ddb 100644 --- a/src/lib/stable/ic_apis/candid_compiler.ts +++ b/src/lib/stable/ic_apis/candid_compiler.ts @@ -1,12 +1,19 @@ /** * Converts a Candid string into its corresponding IDL as a string - * @param candidString a valid Candid string + * @param candidPath a valid Candid file path * @returns the IDL string */ export function candidCompiler(candidPath: string): string { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return ''; } - return globalThis._azleIc.candidCompiler(candidPath); + if (globalThis._azleIcExperimental !== undefined) { + return globalThis._azleIcExperimental.candidCompiler(candidPath); + } + + return globalThis._azleIcStable.candidCompiler(candidPath); } diff --git a/src/lib/stable/ic_apis/candid_decode.ts b/src/lib/stable/ic_apis/candid_decode.ts index 59f5d9f150..564ac156a1 100644 --- a/src/lib/stable/ic_apis/candid_decode.ts +++ b/src/lib/stable/ic_apis/candid_decode.ts @@ -4,9 +4,18 @@ * @returns the Candid string */ export function candidDecode(candidEncoded: Uint8Array): string { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return ''; } - return globalThis._azleIc.candidDecode(candidEncoded.buffer); + if (globalThis._azleIcExperimental !== undefined) { + return globalThis._azleIcExperimental.candidDecode( + candidEncoded.buffer + ); + } + + return globalThis._azleIcStable.candidDecode(candidEncoded); } diff --git a/src/lib/stable/ic_apis/candid_encode.ts b/src/lib/stable/ic_apis/candid_encode.ts index 2d514df12c..794429b661 100644 --- a/src/lib/stable/ic_apis/candid_encode.ts +++ b/src/lib/stable/ic_apis/candid_encode.ts @@ -4,7 +4,18 @@ * @returns the candid value as bytes */ export function candidEncode(candidString: string): Uint8Array { - return new Uint8Array( - globalThis._azleIc ? globalThis._azleIc.candidEncode(candidString) : [] - ); + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return new Uint8Array(); + } + + if (globalThis._azleIcExperimental !== undefined) { + return new Uint8Array( + globalThis._azleIcExperimental.candidEncode(candidString) + ); + } + + return globalThis._azleIcStable.candidEncode(candidString); } diff --git a/src/lib/stable/ic_apis/canister_balance.ts b/src/lib/stable/ic_apis/canister_balance.ts index 80e1fd7dcd..3344aa26a2 100644 --- a/src/lib/stable/ic_apis/canister_balance.ts +++ b/src/lib/stable/ic_apis/canister_balance.ts @@ -3,9 +3,16 @@ * @returns the number of cycles in the canister */ export function canisterBalance(): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } - return BigInt(globalThis._azleIc.canisterBalance()); + if (globalThis._azleIcExperimental !== undefined) { + return BigInt(globalThis._azleIcExperimental.canisterBalance()); + } + + return BigInt(globalThis._azleIcStable.canisterBalance()); } diff --git a/src/lib/stable/ic_apis/canister_version.ts b/src/lib/stable/ic_apis/canister_version.ts index f8f968a467..bdfe158ffc 100644 --- a/src/lib/stable/ic_apis/canister_version.ts +++ b/src/lib/stable/ic_apis/canister_version.ts @@ -4,9 +4,16 @@ * @returns the version number */ export function canisterVersion(): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } - return BigInt(globalThis._azleIc.canisterVersion()); + if (globalThis._azleIcExperimental !== undefined) { + return BigInt(globalThis._azleIcExperimental.canisterVersion()); + } + + return globalThis._azleIcStable.canisterVersion(); } diff --git a/src/lib/stable/ic_apis/chunk.ts b/src/lib/stable/ic_apis/chunk.ts index 383e2a7a56..c6edff6b37 100644 --- a/src/lib/stable/ic_apis/chunk.ts +++ b/src/lib/stable/ic_apis/chunk.ts @@ -14,7 +14,10 @@ import { id } from './id'; * - heartbeats ([T](https://internetcomputer.org/docs/current/references/ic-interface-spec#system-api-imports)) */ export async function chunk(): Promise { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return undefined; } diff --git a/src/lib/stable/ic_apis/clear_timer.ts b/src/lib/stable/ic_apis/clear_timer.ts index de53b2000b..522e2a6639 100644 --- a/src/lib/stable/ic_apis/clear_timer.ts +++ b/src/lib/stable/ic_apis/clear_timer.ts @@ -1,13 +1,20 @@ /** * Cancels an existing timer. Does nothing if the timer has already been canceled. - * @param id The ID of the timer to be cancelled. + * @param timerId The ID of the timer to be cancelled. */ export function clearTimer(timerId: bigint): void { - if (globalThis._azleIc === undefined) { - return undefined; + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return; } - globalThis._azleIc.clearTimer(timerId.toString()); + if (globalThis._azleIcExperimental !== undefined) { + globalThis._azleIcExperimental.clearTimer(timerId.toString()); + } else { + globalThis._azleIcStable.clearTimer(timerId.toString()); + } const timerCallbackId = globalThis._azleIcTimers[timerId.toString()]; diff --git a/src/lib/stable/ic_apis/cycles_burn.ts b/src/lib/stable/ic_apis/cycles_burn.ts index 4d034feb40..5b3b46a6e6 100644 --- a/src/lib/stable/ic_apis/cycles_burn.ts +++ b/src/lib/stable/ic_apis/cycles_burn.ts @@ -1,11 +1,21 @@ /** * Burns cycles from the canister - * @returns the amount of cycles that were actually burned + * @param amount The amount of cycles to burn + * @returns The amount of cycles that were actually burned */ export function cyclesBurn(amount: bigint): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } - return BigInt(globalThis._azleIc.cyclesBurn(amount.toString())); + if (globalThis._azleIcExperimental !== undefined) { + return BigInt( + globalThis._azleIcExperimental.cyclesBurn(amount.toString()) + ); + } + + return BigInt(globalThis._azleIcStable.cyclesBurn(amount.toString())); } diff --git a/src/lib/stable/ic_apis/data_certificate.ts b/src/lib/stable/ic_apis/data_certificate.ts index 5c8133f7f9..3e349be617 100644 --- a/src/lib/stable/ic_apis/data_certificate.ts +++ b/src/lib/stable/ic_apis/data_certificate.ts @@ -4,12 +4,23 @@ * `None`. * @returns the data certificate or None */ -export function dataCertificate(): [Uint8Array] | [] { - if (globalThis._azleIc === undefined) { - return []; +export function dataCertificate(): Uint8Array | undefined { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined; } - const rawRustValue = globalThis._azleIc.dataCertificate(); + if (globalThis._azleIcExperimental !== undefined) { + const result = globalThis._azleIcExperimental.dataCertificate(); - return rawRustValue === undefined ? [] : [new Uint8Array(rawRustValue)]; + if (result === undefined) { + return undefined; + } + + return new Uint8Array(result); + } + + return globalThis._azleIcStable.dataCertificate(); } diff --git a/src/lib/stable/ic_apis/id.ts b/src/lib/stable/ic_apis/id.ts index c3a2113554..468aabad77 100644 --- a/src/lib/stable/ic_apis/id.ts +++ b/src/lib/stable/ic_apis/id.ts @@ -5,11 +5,16 @@ import { Principal } from '@dfinity/principal'; * @returns the canister's id as a principal */ export function id(): Principal { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return Principal.fromHex('04'); } - // TODO consider bytes instead of string, just like with caller - const idString = globalThis._azleIc.id(); - return Principal.fromText(idString); + if (globalThis._azleIcExperimental !== undefined) { + return Principal.fromText(globalThis._azleIcExperimental.id()); + } + + return Principal.fromUint8Array(globalThis._azleIcStable.id()); } diff --git a/src/lib/stable/ic_apis/instruction_counter.ts b/src/lib/stable/ic_apis/instruction_counter.ts index a183d6b488..562c6fe825 100644 --- a/src/lib/stable/ic_apis/instruction_counter.ts +++ b/src/lib/stable/ic_apis/instruction_counter.ts @@ -7,9 +7,16 @@ * @returns the number of instructions */ export function instructionCounter(): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } - return BigInt(globalThis._azleIc.instructionCounter()); + if (globalThis._azleIcExperimental !== undefined) { + return BigInt(globalThis._azleIcExperimental.instructionCounter()); + } + + return globalThis._azleIcStable.instructionCounter(); } diff --git a/src/lib/stable/ic_apis/is_controller.ts b/src/lib/stable/ic_apis/is_controller.ts index 509c29f43c..7ba789988e 100644 --- a/src/lib/stable/ic_apis/is_controller.ts +++ b/src/lib/stable/ic_apis/is_controller.ts @@ -1,10 +1,23 @@ import { Principal } from '@dfinity/principal'; -/** Determine if a {@link Principal} is a controller of the canister. */ +/** + * Determine if a {@link Principal} is a controller of the canister. + * @param principal The Principal to check + * @returns true if the Principal is a controller, false otherwise + */ export function isController(principal: Principal): boolean { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return false; } - return globalThis._azleIc.isController(principal.toUint8Array().buffer); + if (globalThis._azleIcExperimental !== undefined) { + return globalThis._azleIcExperimental.isController( + principal.toUint8Array().buffer + ); + } + + return globalThis._azleIcStable.isController(principal.toUint8Array()); } diff --git a/src/lib/stable/ic_apis/method_name.ts b/src/lib/stable/ic_apis/method_name.ts index 4a9b9f206d..7c4f09b68e 100644 --- a/src/lib/stable/ic_apis/method_name.ts +++ b/src/lib/stable/ic_apis/method_name.ts @@ -1,7 +1,18 @@ /** - * Returns the name of the current canister methods - * @returns the current canister method + * Returns the name of the current canister method + * @returns the current canister method name */ export function methodName(): string { - return globalThis._azleIc ? globalThis._azleIc.methodName() : ''; + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return ''; + } + + if (globalThis._azleIcExperimental !== undefined) { + return globalThis._azleIcExperimental.methodName(); + } + + return globalThis._azleIcStable.methodName(); } diff --git a/src/lib/stable/ic_apis/msg_cycles_accept.ts b/src/lib/stable/ic_apis/msg_cycles_accept.ts index 1b1be65179..64ec041628 100644 --- a/src/lib/stable/ic_apis/msg_cycles_accept.ts +++ b/src/lib/stable/ic_apis/msg_cycles_accept.ts @@ -4,13 +4,20 @@ * @returns the actual amount moved */ export function msgCyclesAccept(maxAmount: bigint): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } - const msgCyclesAcceptAmountMovedString = globalThis._azleIc.msgCyclesAccept( - maxAmount.toString() - ); + if (globalThis._azleIcExperimental !== undefined) { + return BigInt( + globalThis._azleIcExperimental.msgCyclesAccept(maxAmount.toString()) + ); + } - return BigInt(msgCyclesAcceptAmountMovedString); + return BigInt( + globalThis._azleIcStable.msgCyclesAccept(maxAmount.toString()) + ); } diff --git a/src/lib/stable/ic_apis/msg_cycles_available.ts b/src/lib/stable/ic_apis/msg_cycles_available.ts index c006c93b24..79c1617f8a 100644 --- a/src/lib/stable/ic_apis/msg_cycles_available.ts +++ b/src/lib/stable/ic_apis/msg_cycles_available.ts @@ -4,12 +4,16 @@ * @returns the amount of cycles */ export function msgCyclesAvailable(): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } - const msgCyclesAvailableAmountString = - globalThis._azleIc.msgCyclesAvailable(); + if (globalThis._azleIcExperimental !== undefined) { + return BigInt(globalThis._azleIcExperimental.msgCyclesAvailable()); + } - return BigInt(msgCyclesAvailableAmountString); + return BigInt(globalThis._azleIcStable.msgCyclesAvailable()); } diff --git a/src/lib/stable/ic_apis/msg_cycles_refunded.ts b/src/lib/stable/ic_apis/msg_cycles_refunded.ts index f7efc3567a..234075efa8 100644 --- a/src/lib/stable/ic_apis/msg_cycles_refunded.ts +++ b/src/lib/stable/ic_apis/msg_cycles_refunded.ts @@ -4,12 +4,16 @@ * @returns the amount of cycles */ export function msgCyclesRefunded(): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } - const msgCyclesRefundedAmountString = - globalThis._azleIc.msgCyclesRefunded(); + if (globalThis._azleIcExperimental !== undefined) { + return BigInt(globalThis._azleIcExperimental.msgCyclesRefunded()); + } - return BigInt(msgCyclesRefundedAmountString); + return BigInt(globalThis._azleIcStable.msgCyclesRefunded()); } diff --git a/src/lib/stable/ic_apis/notify.ts b/src/lib/stable/ic_apis/notify.ts index 6167474d12..59e681588b 100644 --- a/src/lib/stable/ic_apis/notify.ts +++ b/src/lib/stable/ic_apis/notify.ts @@ -3,11 +3,10 @@ import { Principal } from '@dfinity/principal'; /** * Performs a cross-canister call without awaiting the result - * @param canisterId - * @param method - * @param argsRaw - * @param payment - * @returns + * @param canisterId The ID of the canister to notify + * @param method The method to call on the canister + * @param options Optional parameters for the call + * @returns void */ export function notify( canisterId: Principal | string, @@ -19,7 +18,10 @@ export function notify( raw?: Uint8Array; } ): void { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return undefined; } @@ -32,17 +34,26 @@ export function notify( typeof canisterId === 'string' ? Principal.fromText(canisterId) : canisterId; - const canisterIdBytes = canisterIdPrincipal.toUint8Array().buffer; - const argsRawBuffer = + const canisterIdBytes = canisterIdPrincipal.toUint8Array(); + const argsRaw = raw === undefined - ? new Uint8Array(IDL.encode(paramIdlTypes, args)).buffer - : raw.buffer; + ? new Uint8Array(IDL.encode(paramIdlTypes, args)) + : raw; const paymentString = payment.toString(); - return globalThis._azleIc.notifyRaw( + if (globalThis._azleIcExperimental !== undefined) { + return globalThis._azleIcExperimental.notifyRaw( + canisterIdBytes.buffer, + method, + argsRaw.buffer, + paymentString + ); + } + + return globalThis._azleIcStable.notifyRaw( canisterIdBytes, method, - argsRawBuffer, + argsRaw, paymentString ); } diff --git a/src/lib/stable/ic_apis/performance_counter.ts b/src/lib/stable/ic_apis/performance_counter.ts index 0e8553be3d..970ff6e72c 100644 --- a/src/lib/stable/ic_apis/performance_counter.ts +++ b/src/lib/stable/ic_apis/performance_counter.ts @@ -8,11 +8,20 @@ * @returns the performance counter metric */ export function performanceCounter(counterType: number): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } - return BigInt( - globalThis._azleIc.performanceCounter(counterType.toString()) - ); + if (globalThis._azleIcExperimental !== undefined) { + return BigInt( + globalThis._azleIcExperimental.performanceCounter( + counterType.toString() + ) + ); + } + + return globalThis._azleIcStable.performanceCounter(counterType); } diff --git a/src/lib/stable/ic_apis/print.ts b/src/lib/stable/ic_apis/print.ts index c6e956fbe1..f89de2c1d2 100644 --- a/src/lib/stable/ic_apis/print.ts +++ b/src/lib/stable/ic_apis/print.ts @@ -2,6 +2,18 @@ * Prints the given message * @param args the message to print */ -export function print(...args: any): void { - return globalThis._azleIc ? globalThis._azleIc.print(...args) : undefined; +export function print(...args: any[]): void { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return; + } + + if (globalThis._azleIcExperimental !== undefined) { + globalThis._azleIcExperimental.print(...args); + return; + } + + globalThis._azleIcStable.print(...args); } diff --git a/src/lib/stable/ic_apis/reject.ts b/src/lib/stable/ic_apis/reject.ts index 072354d06d..88abceb3c3 100644 --- a/src/lib/stable/ic_apis/reject.ts +++ b/src/lib/stable/ic_apis/reject.ts @@ -3,5 +3,17 @@ * @param message the rejection message */ export function reject(message: string): void { - return globalThis._azleIc ? globalThis._azleIc.reject(message) : undefined; + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return; + } + + if (globalThis._azleIcExperimental !== undefined) { + globalThis._azleIcExperimental.reject(message); + return; + } + + globalThis._azleIcStable.reject(message); } diff --git a/src/lib/stable/ic_apis/reject_code.ts b/src/lib/stable/ic_apis/reject_code.ts index 5a9d514cfc..5f87861165 100644 --- a/src/lib/stable/ic_apis/reject_code.ts +++ b/src/lib/stable/ic_apis/reject_code.ts @@ -1,54 +1,44 @@ type RejectionCode = - | { - NoError: null; - } - | { - SysFatal: null; - } - | { - SysTransient: null; - } - | { - DestinationInvalid: null; - } - | { - CanisterReject: null; - } - | { - CanisterError: null; - } - | { - Unknown: null; - }; + | { NoError: null } + | { SysFatal: null } + | { SysTransient: null } + | { DestinationInvalid: null } + | { CanisterReject: null } + | { CanisterError: null } + | { Unknown: null }; /** - * Returns the rejection code from the most recently executed cross-canister - * call + * Returns the rejection code from the most recently executed cross-canister call * @returns the rejection code */ export function rejectCode(): RejectionCode { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return { Unknown: null }; } - const rejectCodeNumber = Number(globalThis._azleIc.rejectCode()); + const rejectCodeNumber = + globalThis._azleIcExperimental !== undefined + ? Number(globalThis._azleIcExperimental.rejectCode()) + : globalThis._azleIcStable.rejectCode(); - switch (rejectCodeNumber) { - case 0: - return { NoError: null }; - case 1: - return { SysFatal: null }; - case 2: - return { SysTransient: null }; - case 3: - return { DestinationInvalid: null }; - case 4: - return { CanisterReject: null }; - case 5: - return { CanisterError: null }; - case 6: - return { Unknown: null }; - default: - throw Error(`Unknown rejection code: ${rejectCodeNumber}`); + const rejectCodeMap: { [key: number]: RejectionCode } = { + 0: { NoError: null }, + 1: { SysFatal: null }, + 2: { SysTransient: null }, + 3: { DestinationInvalid: null }, + 4: { CanisterReject: null }, + 5: { CanisterError: null }, + 6: { Unknown: null } + }; + + const result = rejectCodeMap[rejectCodeNumber]; + + if (result === undefined) { + throw new Error(`Unknown rejection code: ${rejectCodeNumber}`); } + + return result; } diff --git a/src/lib/stable/ic_apis/reject_message.ts b/src/lib/stable/ic_apis/reject_message.ts index ca627735e2..11477abbbb 100644 --- a/src/lib/stable/ic_apis/reject_message.ts +++ b/src/lib/stable/ic_apis/reject_message.ts @@ -11,5 +11,16 @@ import { rejectCode } from './reject_code'; // Used for links in comments * @returns the rejection message */ export function rejectMessage(): string { - return globalThis._azleIc ? globalThis._azleIc.rejectMessage() : ''; + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return ''; + } + + if (globalThis._azleIcExperimental !== undefined) { + return globalThis._azleIcExperimental.rejectMessage(); + } + + return globalThis._azleIcStable.rejectMessage(); } diff --git a/src/lib/stable/ic_apis/reply.ts b/src/lib/stable/ic_apis/reply.ts index 4b8a0ccafd..6dc14e0a9c 100644 --- a/src/lib/stable/ic_apis/reply.ts +++ b/src/lib/stable/ic_apis/reply.ts @@ -17,12 +17,17 @@ type ReplyInput = * uncaught `TypeError`. */ export function reply(input: ReplyInput): void { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return undefined; } if ('raw' in input) { - return globalThis._azleIc.replyRaw(input.raw.buffer); + return globalThis._azleIcExperimental !== undefined + ? globalThis._azleIcExperimental.replyRaw(input.raw.buffer) + : globalThis._azleIcStable.replyRaw(input.raw); } else { const idlType = input.idlType === undefined ? [] : [input.idlType]; const data = @@ -30,7 +35,12 @@ export function reply(input: ReplyInput): void { ? [] : [input.data]; - // @ts-ignore IDL.encode types are defined incorrectly https://github.com/demergent-labs/azle/issues/2061 - return globalThis._azleIc.replyRaw(IDL.encode(idlType, data).buffer); + return globalThis._azleIcExperimental !== undefined + ? globalThis._azleIcExperimental.replyRaw( + // @ts-ignore IDL.encode types are defined incorrectly https://github.com/demergent-labs/azle/issues/2061 + IDL.encode(idlType, data).buffer + ) + : // @ts-ignore IDL.encode types are defined incorrectly https://github.com/demergent-labs/azle/issues/2061 + globalThis._azleIcStable.replyRaw(IDL.encode(idlType, data)); } } diff --git a/src/lib/stable/ic_apis/set_certified_data.ts b/src/lib/stable/ic_apis/set_certified_data.ts index 85b2083f5f..a3b94d2aa4 100644 --- a/src/lib/stable/ic_apis/set_certified_data.ts +++ b/src/lib/stable/ic_apis/set_certified_data.ts @@ -18,12 +18,20 @@ * - called from an illegal context (e.g. from a {@link $query} call) * * @param data the data to be set - * @returns + * @returns void */ export function setCertifiedData(data: Uint8Array): void { - if (globalThis._azleIc === undefined) { - return undefined; + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return; } - return globalThis._azleIc.setCertifiedData(data.buffer); + if (globalThis._azleIcExperimental !== undefined) { + globalThis._azleIcExperimental.setCertifiedData(data.buffer); + return; + } + + globalThis._azleIcStable.setCertifiedData(data); } diff --git a/src/lib/stable/ic_apis/set_timer.ts b/src/lib/stable/ic_apis/set_timer.ts index ce1a78192d..5ede519e05 100644 --- a/src/lib/stable/ic_apis/set_timer.ts +++ b/src/lib/stable/ic_apis/set_timer.ts @@ -13,18 +13,29 @@ export function setTimer( delay: bigint, callback: () => void | Promise ): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } const timerCallbackId = `_timer_${v4()}`; - const timerId = globalThis._azleIc.setTimer( - delay.toString(), - timerCallbackId - ); + const timerId = + globalThis._azleIcExperimental !== undefined + ? BigInt( + globalThis._azleIcExperimental.setTimer( + delay.toString(), + timerCallbackId + ) + ) + : globalThis._azleIcStable.setTimer( + delay.toString(), + timerCallbackId + ); - globalThis._azleIcTimers[timerId] = timerCallbackId; + globalThis._azleIcTimers[timerId.toString()] = timerCallbackId; globalThis._azleTimerCallbacks[timerCallbackId] = (): void => { try { @@ -35,5 +46,5 @@ export function setTimer( } }; - return BigInt(timerId); + return timerId; } diff --git a/src/lib/stable/ic_apis/set_timer_interval.ts b/src/lib/stable/ic_apis/set_timer_interval.ts index c6d6e0cc43..c37e4bb107 100644 --- a/src/lib/stable/ic_apis/set_timer_interval.ts +++ b/src/lib/stable/ic_apis/set_timer_interval.ts @@ -13,22 +13,33 @@ export function setTimerInterval( interval: bigint, callback: () => void | Promise ): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } const timerCallbackId = `_interval_timer_${v4()}`; - const timerId = globalThis._azleIc.setTimerInterval( - interval.toString(), - timerCallbackId - ); + const timerId = + globalThis._azleIcExperimental !== undefined + ? BigInt( + globalThis._azleIcExperimental.setTimerInterval( + interval.toString(), + timerCallbackId + ) + ) + : globalThis._azleIcStable.setTimerInterval( + interval.toString(), + timerCallbackId + ); - globalThis._azleIcTimers[timerId] = timerCallbackId; + globalThis._azleIcTimers[timerId.toString()] = timerCallbackId; // We don't delete this even if the callback throws because // it still needs to be here for the next tick globalThis._azleTimerCallbacks[timerCallbackId] = callback; - return BigInt(timerId); + return timerId; } diff --git a/src/lib/stable/ic_apis/time.ts b/src/lib/stable/ic_apis/time.ts index e294b7616a..1584590a2a 100644 --- a/src/lib/stable/ic_apis/time.ts +++ b/src/lib/stable/ic_apis/time.ts @@ -3,9 +3,16 @@ * @returns the current timestamp */ export function time(): bigint { - if (globalThis._azleIc === undefined) { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { return 0n; } - return BigInt(globalThis._azleIc.time()); + if (globalThis._azleIcExperimental !== undefined) { + return BigInt(globalThis._azleIcExperimental.time()); + } + + return globalThis._azleIcStable.time(); } diff --git a/src/lib/stable/ic_apis/trap.ts b/src/lib/stable/ic_apis/trap.ts index 323e46e597..2c06b6651e 100644 --- a/src/lib/stable/ic_apis/trap.ts +++ b/src/lib/stable/ic_apis/trap.ts @@ -4,9 +4,16 @@ * @param message the rejection message */ export function trap(message: string): never { - if (globalThis._azleIc === undefined) { - throw new Error(); + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + throw new Error('IC API not available'); } - return globalThis._azleIc.trap(message); + if (globalThis._azleIcExperimental !== undefined) { + return globalThis._azleIcExperimental.trap(message); + } + + return globalThis._azleIcStable.trap(message); } diff --git a/src/lib/stable/stable_structures/stable_b_tree_map.ts b/src/lib/stable/stable_structures/stable_b_tree_map.ts index 4c96f17f37..5b0ccc1c61 100644 --- a/src/lib/stable/stable_structures/stable_b_tree_map.ts +++ b/src/lib/stable/stable_structures/stable_b_tree_map.ts @@ -12,13 +12,13 @@ export function StableBTreeMap( keySerializable: Serializable = stableJson, valueSerializable: Serializable = stableJson ) { - const memoryId = memoryIdNumber.toString(); + const memoryId = memoryIdNumber; if ( - globalThis._azleIc !== undefined && + globalThis._azleIcStable !== undefined && globalThis._azleNodeWasmEnvironment !== true ) { - globalThis._azleIc.stableBTreeMapInit(memoryId); + globalThis._azleIcStable.stableBTreeMapInit(memoryId); } isSerializable(keySerializable); @@ -31,13 +31,13 @@ export function StableBTreeMap( * @returns `true` if the key exists in the map, `false` otherwise. */ containsKey(key: Key): boolean { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcStable === undefined) { return undefined as any; } - const encodedKey = keySerializable.toBytes(key).buffer; + const encodedKey = keySerializable.toBytes(key); - return globalThis._azleIc.stableBTreeMapContainsKey( + return globalThis._azleIcStable.stableBTreeMapContainsKey( memoryId, encodedKey ); @@ -48,13 +48,13 @@ export function StableBTreeMap( * @returns the value associated with the given key, if it exists. */ get(key: Key): Value | null { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcStable === undefined) { return undefined as any; } - const encodedKey = keySerializable.toBytes(key).buffer; + const encodedKey = keySerializable.toBytes(key); - const encodedResult = globalThis._azleIc.stableBTreeMapGet( + const encodedResult = globalThis._azleIcStable.stableBTreeMapGet( memoryId, encodedKey ); @@ -74,14 +74,14 @@ export function StableBTreeMap( * @returns the previous value of the key, if present. */ insert(key: Key, value: Value): Value | null { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcStable === undefined) { return undefined as any; } - const encodedKey = keySerializable.toBytes(key).buffer; - const encodedValue = valueSerializable.toBytes(value).buffer; + const encodedKey = keySerializable.toBytes(key); + const encodedValue = valueSerializable.toBytes(value); - const encodedResult = globalThis._azleIc.stableBTreeMapInsert( + const encodedResult = globalThis._azleIcStable.stableBTreeMapInsert( memoryId, encodedKey, encodedValue @@ -100,11 +100,11 @@ export function StableBTreeMap( * @returns `true` if the map contains no elements, `false` otherwise. */ isEmpty(): boolean { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcStable === undefined) { return undefined as any; } - return globalThis._azleIc.stableBTreeMapIsEmpty(memoryId); + return globalThis._azleIcStable.stableBTreeMapIsEmpty(memoryId); }, /** * Retrieves the items in the map in sorted order. @@ -113,14 +113,14 @@ export function StableBTreeMap( * @returns tuples representing key/value pairs. */ items(startIndex?: number, length?: number): [Key, Value][] { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcStable === undefined) { return undefined as any; } - const encodedItems = globalThis._azleIc.stableBTreeMapItems( + const encodedItems = globalThis._azleIcStable.stableBTreeMapItems( memoryId, - startIndex?.toString() ?? '0', - length?.toString() ?? 'NOT_SET' + startIndex ?? 0, + length ?? -1 ); // TODO too much copying @@ -138,14 +138,14 @@ export function StableBTreeMap( * @returns they keys in the map. */ keys(startIndex?: number, length?: number): Key[] { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcStable === undefined) { return undefined as any; } - const encodedKeys = globalThis._azleIc.stableBTreeMapKeys( + const encodedKeys = globalThis._azleIcStable.stableBTreeMapKeys( memoryId, - startIndex?.toString() ?? '0', - length?.toString() ?? 'NOT_SET' + startIndex ?? 0, + length ?? -1 ); // TODO too much copying @@ -158,11 +158,11 @@ export function StableBTreeMap( * @returns the number of elements in the map. */ len(): bigint { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcStable === undefined) { return undefined as any; } - return BigInt(globalThis._azleIc.stableBTreeMapLen(memoryId)); + return BigInt(globalThis._azleIcStable.stableBTreeMapLen(memoryId)); }, /** * Removes a key from the map. @@ -170,13 +170,13 @@ export function StableBTreeMap( * @returns the previous value at the key if it exists, `null` otherwise. */ remove(key: Key): Value | null { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcStable === undefined) { return undefined as any; } - const encodedKey = keySerializable.toBytes(key).buffer; + const encodedKey = keySerializable.toBytes(key); - const encodedValue = globalThis._azleIc.stableBTreeMapRemove( + const encodedValue = globalThis._azleIcStable.stableBTreeMapRemove( memoryId, encodedKey ); @@ -196,14 +196,14 @@ export function StableBTreeMap( * @returns the values in the map. */ values(startIndex?: number, length?: number): Value[] { - if (globalThis._azleIc === undefined) { + if (globalThis._azleIcStable === undefined) { return undefined as any; } - const encodedValues = globalThis._azleIc.stableBTreeMapValues( + const encodedValues = globalThis._azleIcStable.stableBTreeMapValues( memoryId, - startIndex?.toString() ?? '0', - length?.toString() ?? 'NOT_SET' + startIndex ?? 0, + length ?? -1 ); // TODO too much copying diff --git a/tests/end_to_end/candid_rpc/class_syntax/ic_api/src/index.ts b/tests/end_to_end/candid_rpc/class_syntax/ic_api/src/index.ts index c5ce026d7d..36383583cd 100644 --- a/tests/end_to_end/candid_rpc/class_syntax/ic_api/src/index.ts +++ b/tests/end_to_end/candid_rpc/class_syntax/ic_api/src/index.ts @@ -93,7 +93,13 @@ export default class { // None. @query([], IDL.Opt(IDL.Vec(IDL.Nat8))) dataCertificate(): [Uint8Array] | [] { - return dataCertificate(); + const result = dataCertificate(); + + if (result === undefined) { + return []; + } + + return [result]; } // When called from a query call, returns the data certificate @@ -101,7 +107,13 @@ export default class { // None. @update([], IDL.Opt(IDL.Vec(IDL.Nat8))) dataCertificateNull(): [Uint8Array] | [] { - return dataCertificate(); + const result = dataCertificate(); + + if (result === undefined) { + return []; + } + + return [result]; } // returns this canister's id diff --git a/tests/end_to_end/candid_rpc/class_syntax/stable_structures/package-lock.json b/tests/end_to_end/candid_rpc/class_syntax/stable_structures/package-lock.json index 209dd4e012..4b2145fd65 100644 --- a/tests/end_to_end/candid_rpc/class_syntax/stable_structures/package-lock.json +++ b/tests/end_to_end/candid_rpc/class_syntax/stable_structures/package-lock.json @@ -17,6 +17,7 @@ } }, "../../functional_syntax/stable_structures": { + "name": "stable_structures_end_to_end_test_functional_syntax", "dev": true, "dependencies": { "azle": "0.24.1" diff --git a/tests/end_to_end/candid_rpc/functional_syntax/stable_b_tree_map_instruction_threshold/test/tests.ts b/tests/end_to_end/candid_rpc/functional_syntax/stable_b_tree_map_instruction_threshold/test/tests.ts index c126062b24..f7c9414186 100644 --- a/tests/end_to_end/candid_rpc/functional_syntax/stable_b_tree_map_instruction_threshold/test/tests.ts +++ b/tests/end_to_end/candid_rpc/functional_syntax/stable_b_tree_map_instruction_threshold/test/tests.ts @@ -15,7 +15,7 @@ export function getTests( const keysResult = await stableBTreeMapInstructionThresholdCanister.keysSmallRecord( - 4_000 + 3_800 ); const valuesResult = @@ -28,7 +28,7 @@ export function getTests( 1_000 ); - expect(keysResult).toHaveLength(4_000); + expect(keysResult).toHaveLength(3_800); expect(valuesResult).toHaveLength(4_000); expect(itemsResult).toHaveLength(1_000); }, 100_000);