diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 565e0dc0ca..954e2368c9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -124,7 +124,7 @@ jobs: "examples/robust_imports", "examples/simple_erc20", "examples/simple_user_accounts", - "examples/stable_json", + "examples/stable_b_tree_map_instruction_threshold", "examples/stable_memory", "examples/stable_structures", "examples/timers", diff --git a/examples/stable_json/.gitignore b/examples/stable_b_tree_map_instruction_threshold/.gitignore similarity index 100% rename from examples/stable_json/.gitignore rename to examples/stable_b_tree_map_instruction_threshold/.gitignore diff --git a/examples/stable_b_tree_map_instruction_threshold/dfx.json b/examples/stable_b_tree_map_instruction_threshold/dfx.json new file mode 100644 index 0000000000..2830522f25 --- /dev/null +++ b/examples/stable_b_tree_map_instruction_threshold/dfx.json @@ -0,0 +1,16 @@ +{ + "canisters": { + "stable_b_tree_map_instruction_threshold": { + "type": "custom", + "main": "src/index.ts", + "candid": "src/index.did", + "build": "npx azle stable_b_tree_map_instruction_threshold", + "wasm": ".azle/stable_b_tree_map_instruction_threshold/stable_b_tree_map_instruction_threshold.wasm", + "gzip": true, + "declarations": { + "output": "test/dfx_generated/stable_b_tree_map_instruction_threshold", + "node_compatibility": true + } + } + } +} diff --git a/examples/stable_json/package-lock.json b/examples/stable_b_tree_map_instruction_threshold/package-lock.json similarity index 100% rename from examples/stable_json/package-lock.json rename to examples/stable_b_tree_map_instruction_threshold/package-lock.json diff --git a/examples/stable_json/package.json b/examples/stable_b_tree_map_instruction_threshold/package.json similarity index 100% rename from examples/stable_json/package.json rename to examples/stable_b_tree_map_instruction_threshold/package.json diff --git a/examples/stable_b_tree_map_instruction_threshold/src/index.did b/examples/stable_b_tree_map_instruction_threshold/src/index.did new file mode 100644 index 0000000000..d6f7cc939a --- /dev/null +++ b/examples/stable_b_tree_map_instruction_threshold/src/index.did @@ -0,0 +1,8 @@ +service: () -> { + insertLargeRecord: (nat32) -> (); + insertMediumRecord: (nat32) -> (); + insertSmallRecord: (nat32) -> (); + valuesLargeRecord: (nat32) -> (vec record {id:text; age:nat; signature:vec nat8; internetIdentity:principal; username:text; mediumRecord:record {id:text; age:nat; internetIdentity:principal; username:text}; friends:vec text}) query; + valuesMediumRecord: (nat32) -> (vec record {id:text; age:nat; internetIdentity:principal; username:text}) query; + valuesSmallRecord: (nat32) -> (vec record {id:principal}) query; +} diff --git a/examples/stable_b_tree_map_instruction_threshold/src/index.ts b/examples/stable_b_tree_map_instruction_threshold/src/index.ts new file mode 100644 index 0000000000..ebecad5643 --- /dev/null +++ b/examples/stable_b_tree_map_instruction_threshold/src/index.ts @@ -0,0 +1,111 @@ +import { + blob, + Canister, + nat, + nat32, + Principal, + query, + Record, + StableBTreeMap, + stableJson, + text, + update, + Vec, + Void +} from 'azle'; +import { v4 } from 'uuid'; + +const SmallRecord = Record({ + id: Principal +}); +type SmallRecord = typeof SmallRecord.tsType; + +let smallRecordMap = StableBTreeMap( + stableJson, + stableJson, + 0 +); + +const MediumRecord = Record({ + id: text, + username: text, + age: nat, + internetIdentity: Principal +}); +type MediumRecord = typeof MediumRecord.tsType; + +let mediumRecordMap = StableBTreeMap( + stableJson, + stableJson, + 1 +); + +const LargeRecord = Record({ + id: text, + username: text, + age: nat, + internetIdentity: Principal, + signature: blob, + friends: Vec(text), + mediumRecord: MediumRecord +}); +type LargeRecord = typeof LargeRecord.tsType; + +let largeRecordMap = StableBTreeMap( + stableJson, + stableJson, + 2 +); + +export default Canister({ + insertSmallRecord: update([nat32], Void, (numToInsert) => { + for (let i = 0; i < numToInsert; i++) { + const id = v4(); + + smallRecordMap.insert(id, { + id: Principal.fromText('aaaaa-aa') + }); + } + }), + valuesSmallRecord: query([nat32], Vec(SmallRecord), (numToReturn) => { + return smallRecordMap.values(0, numToReturn); + }), + insertMediumRecord: update([nat32], Void, (numToInsert) => { + for (let i = 0; i < numToInsert; i++) { + const id = v4(); + + mediumRecordMap.insert(id, { + id, + username: `lastmjs${i}`, + age: BigInt(i), + internetIdentity: Principal.fromText('aaaaa-aa') + }); + } + }), + valuesMediumRecord: query([nat32], Vec(MediumRecord), (numToReturn) => { + return mediumRecordMap.values(0, numToReturn); + }), + insertLargeRecord: update([nat32], Void, (numToInsert) => { + for (let i = 0; i < numToInsert; i++) { + const id = v4(); + + largeRecordMap.insert(id, { + id, + username: `lastmjs${i}`, + age: BigInt(i), + internetIdentity: Principal.fromText('aaaaa-aa'), + signature: Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + friends: [v4(), v4(), v4(), v4()], + mediumRecord: { + id, + username: `lastmjs${i}`, + age: BigInt(i), + internetIdentity: Principal.fromText('aaaaa-aa') + } + }); + } + }), + valuesLargeRecord: query([nat32], Vec(LargeRecord), (numToReturn) => { + return largeRecordMap.values(0, numToReturn); + }) +}); diff --git a/examples/stable_b_tree_map_instruction_threshold/test/pretest.ts b/examples/stable_b_tree_map_instruction_threshold/test/pretest.ts new file mode 100644 index 0000000000..e4ca2cb848 --- /dev/null +++ b/examples/stable_b_tree_map_instruction_threshold/test/pretest.ts @@ -0,0 +1,20 @@ +import { execSync } from 'child_process'; + +async function pretest() { + execSync( + `dfx canister uninstall-code stable_b_tree_map_instruction_threshold || true`, + { + stdio: 'inherit' + } + ); + + execSync(`dfx deploy stable_b_tree_map_instruction_threshold`, { + stdio: 'inherit' + }); + + execSync(`dfx generate stable_b_tree_map_instruction_threshold`, { + stdio: 'inherit' + }); +} + +pretest(); diff --git a/examples/stable_b_tree_map_instruction_threshold/test/test.ts b/examples/stable_b_tree_map_instruction_threshold/test/test.ts new file mode 100644 index 0000000000..14df77ae18 --- /dev/null +++ b/examples/stable_b_tree_map_instruction_threshold/test/test.ts @@ -0,0 +1,14 @@ +import { getCanisterId, runTests } from 'azle/test'; +import { createActor } from './dfx_generated/stable_b_tree_map_instruction_threshold'; +import { getTests } from './tests'; + +const stableBTreeMapInstructionThresholdCanister = createActor( + getCanisterId('stable_b_tree_map_instruction_threshold'), + { + agentOptions: { + host: 'http://127.0.0.1:8000' + } + } +); + +runTests(getTests(stableBTreeMapInstructionThresholdCanister)); diff --git a/examples/stable_b_tree_map_instruction_threshold/test/tests.ts b/examples/stable_b_tree_map_instruction_threshold/test/tests.ts new file mode 100644 index 0000000000..bf7f222925 --- /dev/null +++ b/examples/stable_b_tree_map_instruction_threshold/test/tests.ts @@ -0,0 +1,61 @@ +import { ActorSubclass } from '@dfinity/agent'; +import { Test } from 'azle/test'; +import { _SERVICE } from './dfx_generated/stable_b_tree_map_instruction_threshold/stable_b_tree_map_instruction_threshold.did'; + +export function getTests( + stableBTreeMapInstructionThresholdCanister: ActorSubclass<_SERVICE> +): Test[] { + return [ + { + name: 'test SmallRecord', + test: async () => { + await stableBTreeMapInstructionThresholdCanister.insertSmallRecord( + 10_000 + ); + + const result = + await stableBTreeMapInstructionThresholdCanister.valuesSmallRecord( + 6_000 + ); + + return { + Ok: result.length === 6_000 + }; + } + }, + { + name: 'test MediumRecord', + test: async () => { + await stableBTreeMapInstructionThresholdCanister.insertMediumRecord( + 5_000 + ); + + const result = + await stableBTreeMapInstructionThresholdCanister.valuesMediumRecord( + 1_000 + ); + + return { + Ok: result.length === 1_000 + }; + } + }, + { + name: 'test LargeRecord', + test: async () => { + await stableBTreeMapInstructionThresholdCanister.insertLargeRecord( + 2_000 + ); + + const result = + await stableBTreeMapInstructionThresholdCanister.valuesLargeRecord( + 500 + ); + + return { + Ok: result.length === 500 + }; + } + } + ]; +} diff --git a/examples/stable_json/tsconfig.json b/examples/stable_b_tree_map_instruction_threshold/tsconfig.json similarity index 100% rename from examples/stable_json/tsconfig.json rename to examples/stable_b_tree_map_instruction_threshold/tsconfig.json diff --git a/examples/stable_json/dfx.json b/examples/stable_json/dfx.json deleted file mode 100644 index e27016afdc..0000000000 --- a/examples/stable_json/dfx.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "canisters": { - "stable_json": { - "type": "custom", - "main": "src/index.ts", - "candid": "src/index.did", - "build": "npx azle stable_json", - "wasm": ".azle/stable_json/stable_json.wasm", - "gzip": true, - "declarations": { - "output": "test/dfx_generated/stable_json", - "node_compatibility": true - } - } - } -} diff --git a/examples/stable_json/src/index.did b/examples/stable_json/src/index.did deleted file mode 100644 index 3deded9b0c..0000000000 --- a/examples/stable_json/src/index.did +++ /dev/null @@ -1,4 +0,0 @@ -service: () -> { - insert: () -> (); - values: () -> (vec record {id:principal; age:nat; signature:vec nat8; username:text}) query; -} diff --git a/examples/stable_json/src/index.ts b/examples/stable_json/src/index.ts deleted file mode 100644 index 252c037f68..0000000000 --- a/examples/stable_json/src/index.ts +++ /dev/null @@ -1,53 +0,0 @@ -// TODO use string for nat64/bigint conversions to and from the Rust environment - -import { - blob, - Canister, - nat, - nat32, - Principal, - query, - Record, - Serializable, - StableJson, - StableBTreeMap, - text, - update, - Vec, - Void, - Func, - Opt -} from 'azle'; -import { v1 } from 'uuid'; - -const User = Record({ - id: Principal, - username: text, - age: nat, - signature: blob -}); -type User = typeof User.tsType; - -// TODO figure out good minimum for: -// TODO number keys and json objects with 1, 5, 10, 15, 20 records -// TODO use a combination of different types -// TODO should we create special StableNumber and StableBigInt and StableString? -// TODO we should measure the performance to see what we can do - -let map = StableBTreeMap(text, StableJson(), 0); - -export default Canister({ - insert: update([], Void, () => { - for (let i = 0; i < 1_000; i++) { - map.insert(v1(), { - id: Principal.fromText('aaaaa-aa'), - username: i.toString(), - age: BigInt(i), - signature: Uint8Array.from([0, 1, 2, 3, 4, 5]) - }); - } - }), - values: query([], Vec(User), () => { - return map.values(0, 5); - }) -}); diff --git a/examples/stable_json/test/pretest.ts b/examples/stable_json/test/pretest.ts deleted file mode 100644 index dc27cd1bb9..0000000000 --- a/examples/stable_json/test/pretest.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { execSync } from 'child_process'; - -async function pretest() { - await new Promise((resolve) => setTimeout(resolve, 5000)); - - execSync(`dfx canister uninstall-code stable_json || true`, { - stdio: 'inherit' - }); - - execSync(`dfx deploy stable_json`, { - stdio: 'inherit' - }); - - execSync(`dfx generate stable_json`, { - stdio: 'inherit' - }); -} - -pretest(); diff --git a/examples/stable_json/test/test.ts b/examples/stable_json/test/test.ts deleted file mode 100644 index 1792f5d37a..0000000000 --- a/examples/stable_json/test/test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { getCanisterId, runTests } from 'azle/test'; -import { createActor } from '../test/dfx_generated/stable_json'; -import { getTests } from './tests'; - -const stableJsonCanister = createActor(getCanisterId('stable_json'), { - agentOptions: { - host: 'http://127.0.0.1:8000' - } -}); - -runTests(getTests(stableJsonCanister)); diff --git a/examples/stable_json/test/tests.ts b/examples/stable_json/test/tests.ts deleted file mode 100644 index cd0a0939ed..0000000000 --- a/examples/stable_json/test/tests.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Principal } from '@dfinity/principal'; -import { ActorSubclass } from '@dfinity/agent'; -import { Test } from 'azle/test'; -import { _SERVICE } from './dfx_generated/stable_json/stable_json.did'; - -export function getTests(stableJsonCanister: ActorSubclass<_SERVICE>): Test[] { - return []; -} diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_contains_key.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_contains_key.rs index 2089f1203a..4e14756262 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_contains_key.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_contains_key.rs @@ -9,11 +9,12 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_contains_key argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; let key: Vec = args .get(1) @@ -25,8 +26,7 @@ pub fn native_function<'a>( .with(|stable_b_tree_maps| { let stable_b_tree_maps = stable_b_tree_maps.borrow(); - stable_b_tree_maps[&(memory_id as u8)] - .contains_key(&AzleStableBTreeMapKey { bytes: key }) + stable_b_tree_maps[&memory_id].contains_key(&AzleStableBTreeMapKey { bytes: key }) }) .into(); diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_get.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_get.rs index 6c3a7cabcb..0ed85c31e5 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_get.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_get.rs @@ -9,11 +9,12 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_get argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; let key: Vec = args .get(1) @@ -24,7 +25,7 @@ pub fn native_function<'a>( let value_option = 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 as u8)].get(&AzleStableBTreeMapKey { bytes: key }) + stable_b_tree_maps[&memory_id].get(&AzleStableBTreeMapKey { bytes: key }) }); // TODO could we somehow encode the entire option here more easily diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_init.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_init.rs index 7d24001cee..e8098515c3 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_init.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_init.rs @@ -10,18 +10,19 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_init argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; 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 as u8, + memory_id, StableBTreeMap::init( - MEMORY_MANAGER_REF_CELL.with(|m| m.borrow().get(MemoryId::new(memory_id as u8))), + MEMORY_MANAGER_REF_CELL.with(|m| m.borrow().get(MemoryId::new(memory_id))), ), ); }); diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_insert.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_insert.rs index b2896c3f1d..153676367c 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_insert.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_insert.rs @@ -9,11 +9,12 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_insert argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; let key: Vec = args .get(1) @@ -29,13 +30,10 @@ pub fn native_function<'a>( let value_option = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { let mut stable_b_tree_maps = stable_b_tree_maps.borrow_mut(); - let result = stable_b_tree_maps - .get_mut(&(memory_id as u8)) - .unwrap() - .insert( - AzleStableBTreeMapKey { bytes: key }, - AzleStableBTreeMapValue { bytes: value }, - ); + let result = stable_b_tree_maps.get_mut(&memory_id).unwrap().insert( + AzleStableBTreeMapKey { bytes: key }, + AzleStableBTreeMapValue { bytes: value }, + ); result }); diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_is_empty.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_is_empty.rs index da14a4d81c..2a2d065056 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_is_empty.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_is_empty.rs @@ -9,17 +9,18 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_is_empty argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; let result_js_value: JSValue = 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 as u8)].is_empty() + stable_b_tree_maps[&memory_id].is_empty() }) .into(); diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_items.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_items.rs index ce39ef8738..42a846bedf 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_items.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_items.rs @@ -9,16 +9,17 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_items argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; let items: 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 as u8)] + stable_b_tree_maps[&memory_id] .iter() .map(|(key, value)| vec![key.bytes, value.bytes]) .collect() diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_keys.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_keys.rs index 2084e3f221..012543e6f9 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_keys.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_keys.rs @@ -9,16 +9,17 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_keys argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; let keys: 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 as u8)] + stable_b_tree_maps[&memory_id] .iter() .map(|(key, _)| key.bytes) .collect() diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_len.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_len.rs index ad34b9964d..d5b300154c 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_len.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_len.rs @@ -9,16 +9,17 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_len argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; 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 as u8)].len() + stable_b_tree_maps[&memory_id].len() }); let len_js_value: JSValue = candid::encode_one(len)?.into(); diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_remove.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_remove.rs index 1fe686bf5e..b40a3dc084 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_remove.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_remove.rs @@ -9,11 +9,12 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_remove argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; let key: Vec = args .get(1) @@ -25,7 +26,7 @@ pub fn native_function<'a>( let mut stable_b_tree_maps = stable_b_tree_maps.borrow_mut(); stable_b_tree_maps - .get_mut(&(memory_id as u8)) + .get_mut(&memory_id) .unwrap() .remove(&AzleStableBTreeMapKey { bytes: key }) }); diff --git a/src/compiler/rust/canister/src/ic/stable_b_tree_map_values.rs b/src/compiler/rust/canister/src/ic/stable_b_tree_map_values.rs index 1dc1d0cda8..e9cdba93fe 100644 --- a/src/compiler/rust/canister/src/ic/stable_b_tree_map_values.rs +++ b/src/compiler/rust/canister/src/ic/stable_b_tree_map_values.rs @@ -9,19 +9,21 @@ pub fn native_function<'a>( _this: &CallbackArg, args: &[CallbackArg], ) -> Result, anyhow::Error> { - let memory_id: usize = args + let memory_id_string: String = args .get(0) .expect("stable_b_tree_map_values argument 0 is undefined") .to_js_value()? .try_into()?; + let memory_id: u8 = memory_id_string.parse()?; - let start_index: usize = args + let start_index_string: String = args .get(1) .expect("stable_b_tree_map_values argument 1 is undefined") .to_js_value()? .try_into()?; + let start_index: usize = start_index_string.parse()?; - let length: usize = args + let length_string: String = args .get(2) .expect("stable_b_tree_map_values argument 2 is undefined") .to_js_value()? @@ -29,15 +31,15 @@ pub fn native_function<'a>( 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 as u8)]; + let stable_b_tree_map = &stable_b_tree_maps[&memory_id]; stable_b_tree_map .iter() .skip(start_index) - .take(if length == 0 { + .take(if length_string == "NOT_SET" { stable_b_tree_map.len().try_into().unwrap() } else { - length + length_string.parse().unwrap() }) .map(|(_, value)| value.bytes) .collect() diff --git a/src/lib/ic/types/azle_ic.ts b/src/lib/ic/types/azle_ic.ts index 35c2513665..b650af106d 100644 --- a/src/lib/ic/types/azle_ic.ts +++ b/src/lib/ic/types/azle_ic.ts @@ -84,31 +84,31 @@ export type AzleIc = { notify: () => never; reply: () => never; // Stable B Tree Map Functions - stableBTreeMapInit: (memoryId: number) => void; + stableBTreeMapInit: (memoryId: string) => void; stableBTreeMapContainsKey: ( - memoryId: number, + memoryId: string, encodedKey: ArrayBufferLike ) => boolean; stableBTreeMapGet: ( - memoryId: number, + memoryId: string, encodedKey: ArrayBufferLike ) => ArrayBuffer | undefined; stableBTreeMapInsert: ( - memoryId: number, + memoryId: string, encodedKey: ArrayBufferLike, encodedValue: ArrayBufferLike ) => ArrayBuffer | undefined; - stableBTreeMapIsEmpty: (memoryId: number) => boolean; - stableBTreeMapItems: (memoryId: number) => [ArrayBuffer, ArrayBuffer][]; - stableBTreeMapKeys: (memoryId: number) => ArrayBuffer[]; - stableBTreeMapLen: (memoryId: number) => ArrayBuffer; + stableBTreeMapIsEmpty: (memoryId: string) => boolean; + stableBTreeMapItems: (memoryId: string) => [ArrayBuffer, ArrayBuffer][]; + stableBTreeMapKeys: (memoryId: string) => ArrayBuffer[]; + stableBTreeMapLen: (memoryId: string) => ArrayBuffer; stableBTreeMapRemove( - memoryId: number, + memoryId: string, encodedKey: ArrayBufferLike ): ArrayBuffer; stableBTreeMapValues: ( - memoryId: number, - startIndex: number, - length: number + memoryId: string, + startIndex: string, + length: string ) => ArrayBuffer[]; }; diff --git a/src/lib/stable_structures/stable_b_tree_map.ts b/src/lib/stable_structures/stable_b_tree_map.ts index 6e05a1146e..b62bdd2c8b 100644 --- a/src/lib/stable_structures/stable_b_tree_map.ts +++ b/src/lib/stable_structures/stable_b_tree_map.ts @@ -11,8 +11,10 @@ export interface Serializable { export function StableBTreeMap( keySerializable: Serializable, valueSerializable: Serializable, - memoryId: nat8 + memoryIdNumber: nat8 ) { + const memoryId = memoryIdNumber.toString(); + if (globalThis._azleIc !== undefined) { globalThis._azleIc.stableBTreeMapInit(memoryId); } @@ -184,15 +186,15 @@ export function StableBTreeMap( * @param length the number of values to retrieve * @returns the values in the map. */ - values(startIndex: number = 0, length: number = 0): Value[] { + values(startIndex?: number, length?: number): Value[] { if (globalThis._azleIc === undefined) { return undefined as any; } const encodedValues = globalThis._azleIc.stableBTreeMapValues( memoryId, - startIndex, - length + startIndex?.toString() ?? '0', + length?.toString() ?? 'NOT_SET' ); // TODO too much copying diff --git a/src/lib/stable_structures/stable_json.ts b/src/lib/stable_structures/stable_json.ts index 879adaff8c..223cf9c2a1 100644 --- a/src/lib/stable_structures/stable_json.ts +++ b/src/lib/stable_structures/stable_json.ts @@ -7,9 +7,9 @@ export function StableJson(options?: { }): Serializable { return { toBytes(data: any) { - return Uint8Array.from( - Buffer.from(JSON.stringify(data, options?.replacer ?? replacer)) - ); + const result = JSON.stringify(data, options?.replacer ?? replacer); + + return Uint8Array.from(Buffer.from(result)); }, fromBytes(bytes: Uint8Array) { return JSON.parse( @@ -20,6 +20,8 @@ export function StableJson(options?: { }; } +export const stableJson = StableJson(); + export function replacer(_key: string, value: any): any { if (typeof value === 'bigint') { return { @@ -27,6 +29,12 @@ export function replacer(_key: string, value: any): any { }; } + if (typeof value === 'object' && value._isPrincipal === true) { + return { + __principal__: value.toString() + }; + } + if (value instanceof Int8Array) { return { __int8array__: Array.from(value)