From e3aa8f0b1f1edec6bf4ca04c397775ccfdfe9dec Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 19 Dec 2024 13:38:27 -0700 Subject: [PATCH 1/3] make stable b tree map a class --- .../candid_rpc/audio_recorder/src/index.ts | 4 +- .../candid_rpc/ethereum_json_rpc/src/index.ts | 2 +- .../func_types/canisters/func_types/index.ts | 2 +- .../motoko_examples/http_counter/src/index.ts | 2 +- .../persistent-storage/src/index.ts | 2 +- .../pre_and_post_upgrade/src/index.ts | 2 +- .../package-lock.json | 13 +- .../src/index.ts | 6 +- .../stable_structures/src/canister1/index.ts | 10 +- .../stable_structures/src/canister2/index.ts | 10 +- .../stable_structures/src/canister3/index.ts | 16 +- .../canister_methods/pre_upgrade/test/test.ts | 2 +- .../test/property/ic_api/caller/src/index.ts | 2 +- .../ic_api/canister_version/src/index.ts | 7 +- .../ic_api/certified_data/src/index.ts | 2 +- .../test/property/ic_api/id/src/index.ts | 2 +- .../stable_structures/stable_b_tree_map.ts | 583 +++++++++--------- .../arbitraries/stable_b_tree_map_arb.ts | 2 +- 18 files changed, 340 insertions(+), 329 deletions(-) diff --git a/examples/stable/test/end_to_end/candid_rpc/audio_recorder/src/index.ts b/examples/stable/test/end_to_end/candid_rpc/audio_recorder/src/index.ts index 1b4de8ce73..8725738384 100644 --- a/examples/stable/test/end_to_end/candid_rpc/audio_recorder/src/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/audio_recorder/src/index.ts @@ -29,8 +29,8 @@ type Recording = { }; export default class { - users = StableBTreeMap(0); - recordings = StableBTreeMap(1); + users = new StableBTreeMap(0); + recordings = new StableBTreeMap(1); @update([IDL.Text], User) createUser(username: string): User { diff --git a/examples/stable/test/end_to_end/candid_rpc/ethereum_json_rpc/src/index.ts b/examples/stable/test/end_to_end/candid_rpc/ethereum_json_rpc/src/index.ts index dd5f967349..32968f942a 100644 --- a/examples/stable/test/end_to_end/candid_rpc/ethereum_json_rpc/src/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/ethereum_json_rpc/src/index.ts @@ -15,7 +15,7 @@ import { } from 'azle/canisters/management'; export default class { - stableStorage = StableBTreeMap(0); + stableStorage = new StableBTreeMap(0); @init([IDL.Text]) init(ethereumUrl: string): void { diff --git a/examples/stable/test/end_to_end/candid_rpc/func_types/canisters/func_types/index.ts b/examples/stable/test/end_to_end/candid_rpc/func_types/canisters/func_types/index.ts index 669df8eea8..dad245b50e 100644 --- a/examples/stable/test/end_to_end/candid_rpc/func_types/canisters/func_types/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/func_types/canisters/func_types/index.ts @@ -56,7 +56,7 @@ const NullFunc = IDL.Func( type NullFunc = Func; export default class { - stableStorage = StableBTreeMap(0); + stableStorage = new StableBTreeMap(0); @init([]) init(): void { diff --git a/examples/stable/test/end_to_end/candid_rpc/motoko_examples/http_counter/src/index.ts b/examples/stable/test/end_to_end/candid_rpc/motoko_examples/http_counter/src/index.ts index 43abc9fc89..6a430a411a 100644 --- a/examples/stable/test/end_to_end/candid_rpc/motoko_examples/http_counter/src/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/motoko_examples/http_counter/src/index.ts @@ -98,7 +98,7 @@ export type HttpResponse = { }; export default class { - stableStorage = StableBTreeMap(0); + stableStorage = new StableBTreeMap(0); @init([]) init(): void { diff --git a/examples/stable/test/end_to_end/candid_rpc/motoko_examples/persistent-storage/src/index.ts b/examples/stable/test/end_to_end/candid_rpc/motoko_examples/persistent-storage/src/index.ts index 1907efe711..4d0b44cb26 100644 --- a/examples/stable/test/end_to_end/candid_rpc/motoko_examples/persistent-storage/src/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/motoko_examples/persistent-storage/src/index.ts @@ -9,7 +9,7 @@ import { } from 'azle'; export default class { - stableStorage = StableBTreeMap(0); + stableStorage = new StableBTreeMap(0); redeployed = false; @init([]) diff --git a/examples/stable/test/end_to_end/candid_rpc/pre_and_post_upgrade/src/index.ts b/examples/stable/test/end_to_end/candid_rpc/pre_and_post_upgrade/src/index.ts index e959246d3a..4b921d1068 100644 --- a/examples/stable/test/end_to_end/candid_rpc/pre_and_post_upgrade/src/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/pre_and_post_upgrade/src/index.ts @@ -18,7 +18,7 @@ type Entry = { }; export default class { - stableStorage = StableBTreeMap(0); + stableStorage = new StableBTreeMap(0); entries: { [key: string]: bigint; diff --git a/examples/stable/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold/package-lock.json b/examples/stable/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold/package-lock.json index 8cc291c29b..c84113cd26 100644 --- a/examples/stable/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold/package-lock.json +++ b/examples/stable/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold/package-lock.json @@ -9,16 +9,23 @@ "uuid": "^9.0.1" }, "devDependencies": { - "stable_b_tree_map_instruction_threshold_end_to_end_test_functional_syntax": "file:../../functional_syntax/stable_b_tree_map_instruction_threshold" + "stable_b_tree_map_instruction_threshold_end_to_end_test_functional_syntax": "file:../../../../../experimental/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold" } }, - "../../functional_syntax/stable_b_tree_map_instruction_threshold": { + "../../../../../experimental/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold": { "name": "stable_b_tree_map_instruction_threshold_end_to_end_test_functional_syntax", "dev": true, "dependencies": { "azle": "0.24.1" } }, + "../../functional_syntax/stable_b_tree_map_instruction_threshold": { + "name": "stable_b_tree_map_instruction_threshold_end_to_end_test_functional_syntax", + "extraneous": true, + "dependencies": { + "azle": "0.24.1" + } + }, "node_modules/@adraffy/ens-normalize": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", @@ -2006,7 +2013,7 @@ "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==" }, "node_modules/stable_b_tree_map_instruction_threshold_end_to_end_test_functional_syntax": { - "resolved": "../../functional_syntax/stable_b_tree_map_instruction_threshold", + "resolved": "../../../../../experimental/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold", "link": true }, "node_modules/stream-buffers": { diff --git a/examples/stable/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold/src/index.ts b/examples/stable/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold/src/index.ts index 44a7b99409..9cebd802e1 100644 --- a/examples/stable/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold/src/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/stable_b_tree_map_instruction_threshold/src/index.ts @@ -41,9 +41,9 @@ type LargeRecord = { }; export default class { - smallRecordMap = StableBTreeMap(0); - mediumRecordMap = StableBTreeMap(1); - largeRecordMap = StableBTreeMap(2); + smallRecordMap = new StableBTreeMap(0); + mediumRecordMap = new StableBTreeMap(1); + largeRecordMap = new StableBTreeMap(2); @update([IDL.Nat32]) insertSmallRecord(numToInsert: number): void { diff --git a/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister1/index.ts b/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister1/index.ts index d19c3293c6..1c970b467d 100644 --- a/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister1/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister1/index.ts @@ -3,11 +3,11 @@ import { IDL, query, StableBTreeMap, update } from 'azle'; import { Reaction, User } from '../types'; export default class { - stableMap0 = StableBTreeMap(0); - stableMap1 = StableBTreeMap(1); - stableMap2 = StableBTreeMap(2); - stableMap3 = StableBTreeMap(3); - stableMap4 = StableBTreeMap(4); + stableMap0 = new StableBTreeMap(0); + stableMap1 = new StableBTreeMap(1); + stableMap2 = new StableBTreeMap(2); + stableMap3 = new StableBTreeMap(3); + stableMap4 = new StableBTreeMap(4); @query([], IDL.Bool) getRedeployed(): boolean { diff --git a/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister2/index.ts b/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister2/index.ts index bd503fcbf8..01fe9446b8 100644 --- a/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister2/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister2/index.ts @@ -1,11 +1,11 @@ import { IDL, query, StableBTreeMap, update } from 'azle'; export default class { - stableMap5 = StableBTreeMap<[string] | [], number>(5); - stableMap6 = StableBTreeMap(6); - stableMap7 = StableBTreeMap(7); - stableMap8 = StableBTreeMap(8); - stableMap9 = StableBTreeMap(9); + stableMap5 = new StableBTreeMap<[string] | [], number>(5); + stableMap6 = new StableBTreeMap(6); + stableMap7 = new StableBTreeMap(7); + stableMap8 = new StableBTreeMap(8); + stableMap9 = new StableBTreeMap(9); @query([], IDL.Bool) getRedeployed(): boolean { diff --git a/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister3/index.ts b/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister3/index.ts index a66807e20e..c8851286ef 100644 --- a/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister3/index.ts +++ b/examples/stable/test/end_to_end/candid_rpc/stable_structures/src/canister3/index.ts @@ -3,14 +3,14 @@ import { IDL, Principal, query, StableBTreeMap, update } from 'azle'; import { Callback, Reaction, User } from '../types'; export default class { - stableMap10 = StableBTreeMap(10); - stableMap11 = StableBTreeMap(11); - stableMap12 = StableBTreeMap(12); - stableMap13 = StableBTreeMap(13); - stableMap14 = StableBTreeMap(14); - stableMap15 = StableBTreeMap(15); - stableMap16 = StableBTreeMap(16); - stableMap17 = StableBTreeMap(17); + stableMap10 = new StableBTreeMap(10); + stableMap11 = new StableBTreeMap(11); + stableMap12 = new StableBTreeMap(12); + stableMap13 = new StableBTreeMap(13); + stableMap14 = new StableBTreeMap(14); + stableMap15 = new StableBTreeMap(15); + stableMap16 = new StableBTreeMap(16); + stableMap17 = new StableBTreeMap(17); @query([], IDL.Bool) getRedeployed(): boolean { diff --git a/examples/stable/test/property/candid_rpc/canister_methods/pre_upgrade/test/test.ts b/examples/stable/test/property/candid_rpc/canister_methods/pre_upgrade/test/test.ts index 34b901f0cc..283d1dc71e 100644 --- a/examples/stable/test/property/candid_rpc/canister_methods/pre_upgrade/test/test.ts +++ b/examples/stable/test/property/candid_rpc/canister_methods/pre_upgrade/test/test.ts @@ -85,7 +85,7 @@ const CanisterConfigArb = fc > => { const globalDeclarations = [ /*TS*/ `const PRE_UPGRADE_HOOK_EXECUTED = 'PRE_UPGRADE_HOOK_EXECUTED';`, - /*TS*/ `let stable = StableBTreeMap(0);` + /*TS*/ `let stable = new StableBTreeMap(0);` ]; return { diff --git a/examples/stable/test/property/ic_api/caller/src/index.ts b/examples/stable/test/property/ic_api/caller/src/index.ts index f6e56167aa..e4ebdb6a7b 100644 --- a/examples/stable/test/property/ic_api/caller/src/index.ts +++ b/examples/stable/test/property/ic_api/caller/src/index.ts @@ -17,7 +17,7 @@ import { AssertType, NotAnyAndExact } from 'azle/type_tests/assert_type'; export default class { initCaller: Principal | null = null; postUpgradeCaller: Principal | null = null; - preUpgradeCaller = StableBTreeMap<'PRE_UPGRADE_CALLER', Principal>(0); + preUpgradeCaller = new StableBTreeMap<'PRE_UPGRADE_CALLER', Principal>(0); inspectMessageCaller: Principal | null = null; @init([]) diff --git a/examples/stable/test/property/ic_api/canister_version/src/index.ts b/examples/stable/test/property/ic_api/canister_version/src/index.ts index ccfa54d3ca..70a31f79a5 100644 --- a/examples/stable/test/property/ic_api/canister_version/src/index.ts +++ b/examples/stable/test/property/ic_api/canister_version/src/index.ts @@ -16,9 +16,10 @@ import { AssertType, NotAnyAndExact } from 'azle/type_tests/assert_type'; export default class { initCanisterVersion: bigint | null = null; postUpgradeCanisterVersion: bigint | null = null; - preUpgradeCanisterVersion = StableBTreeMap<'PRE_UPGRADE_VERSION', bigint>( - 0 - ); + preUpgradeCanisterVersion = new StableBTreeMap< + 'PRE_UPGRADE_VERSION', + bigint + >(0); inspectMessageCanisterVersion: bigint | null = null; meaninglessState: bigint = 0n; diff --git a/examples/stable/test/property/ic_api/certified_data/src/index.ts b/examples/stable/test/property/ic_api/certified_data/src/index.ts index f254819ff5..813592ef59 100644 --- a/examples/stable/test/property/ic_api/certified_data/src/index.ts +++ b/examples/stable/test/property/ic_api/certified_data/src/index.ts @@ -28,7 +28,7 @@ const PRE_UPGRADE_DATA = new Uint8Array([ export default class { data: Uint8Array = new Uint8Array(); - stableStorage = StableBTreeMap(0); + stableStorage = new StableBTreeMap(0); afterFirstPostUpgrade = false; @init([IDL.Bool, IDL.Vec(IDL.Nat8)]) diff --git a/examples/stable/test/property/ic_api/id/src/index.ts b/examples/stable/test/property/ic_api/id/src/index.ts index 73533abe9d..841f3ea7d2 100644 --- a/examples/stable/test/property/ic_api/id/src/index.ts +++ b/examples/stable/test/property/ic_api/id/src/index.ts @@ -17,7 +17,7 @@ import { AssertType, NotAnyAndExact } from 'azle/type_tests/assert_type'; export default class { initId: Principal | null = null; postUpgradeId: Principal | null = null; - preUpgradeId = StableBTreeMap<'PRE_UPGRADE_ID', Principal>(0); + preUpgradeId = new StableBTreeMap<'PRE_UPGRADE_ID', Principal>(0); inspectMessageId: Principal | null = null; @init([]) 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 199f2bceae..6b6d4e22c4 100644 --- a/src/lib/stable/stable_structures/stable_b_tree_map.ts +++ b/src/lib/stable/stable_structures/stable_b_tree_map.ts @@ -5,318 +5,321 @@ export interface Serializable { fromBytes: (bytes: Uint8Array) => any; } -export type StableBTreeMap = { - containsKey(key: Key): boolean; - get(key: Key): Value | null; - insert(key: Key, value: Value): Value | null; - isEmpty(): boolean; - items(startIndex?: number, length?: number): [Key, Value][]; - keys(startIndex?: number, length?: number): Key[]; - len(): bigint; - remove(key: Key): Value | null; - values(startIndex?: number, length?: number): Value[]; -}; - -export function StableBTreeMap( - memoryIdNumber: number, - keySerializable: Serializable = stableJson, - valueSerializable: Serializable = stableJson -): StableBTreeMap { - const memoryId = memoryIdNumber; - - if (globalThis._azleNodeWasmEnvironment !== true) { +export class StableBTreeMap { + memoryId: number; + keySerializable: Serializable; + valueSerializable: Serializable; + + constructor( + memoryId: number, + keySerializable: Serializable = stableJson, + valueSerializable: Serializable = stableJson + ) { + this.memoryId = memoryId; + this.keySerializable = keySerializable; + this.valueSerializable = valueSerializable; + + if (globalThis._azleNodeWasmEnvironment !== true) { + if (globalThis._azleIcExperimental !== undefined) { + globalThis._azleIcExperimental.stableBTreeMapInit( + memoryId.toString() + ); + } + + if (globalThis._azleIcStable !== undefined) { + globalThis._azleIcStable.stableBTreeMapInit(memoryId); + } + } + + isSerializable(keySerializable); + isSerializable(valueSerializable); + } + + /** + * 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._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined as any; + } + + const encodedKey = this.keySerializable.toBytes(key); + if (globalThis._azleIcExperimental !== undefined) { - globalThis._azleIcExperimental.stableBTreeMapInit( - memoryId.toString() + return globalThis._azleIcExperimental.stableBTreeMapContainsKey( + this.memoryId.toString(), + encodedKey.buffer ); } - if (globalThis._azleIcStable !== undefined) { - globalThis._azleIcStable.stableBTreeMapInit(memoryId); + return globalThis._azleIcStable.stableBTreeMapContainsKey( + this.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._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined as any; + } + + const encodedKey = this.keySerializable.toBytes(key); + + const encodedResult = + globalThis._azleIcExperimental !== undefined + ? globalThis._azleIcExperimental.stableBTreeMapGet( + this.memoryId.toString(), + encodedKey.buffer + ) + : globalThis._azleIcStable.stableBTreeMapGet( + this.memoryId, + encodedKey + ); + + if (encodedResult === undefined) { + return null; + } else { + return this.valueSerializable.fromBytes( + new Uint8Array(encodedResult) + ); } } - 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._azleIcStable === undefined && - globalThis._azleIcExperimental === undefined - ) { - return undefined as any; - } + /** + * 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._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined as any; + } - const encodedKey = keySerializable.toBytes(key); + const encodedKey = this.keySerializable.toBytes(key); + const encodedValue = this.valueSerializable.toBytes(value); - if (globalThis._azleIcExperimental !== undefined) { - return globalThis._azleIcExperimental.stableBTreeMapContainsKey( - memoryId.toString(), - encodedKey.buffer - ); - } + const encodedResult = + globalThis._azleIcExperimental !== undefined + ? globalThis._azleIcExperimental.stableBTreeMapInsert( + this.memoryId.toString(), + encodedKey.buffer, + encodedValue.buffer + ) + : globalThis._azleIcStable.stableBTreeMapInsert( + this.memoryId, + encodedKey, + encodedValue + ); - return globalThis._azleIcStable.stableBTreeMapContainsKey( - memoryId, - encodedKey + if (encodedResult === undefined) { + return null; + } else { + return this.valueSerializable.fromBytes( + new Uint8Array(encodedResult) ); - }, - /** - * 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._azleIcStable === undefined && - globalThis._azleIcExperimental === undefined - ) { - return undefined as any; - } + } + } - const encodedKey = keySerializable.toBytes(key); - - const encodedResult = - globalThis._azleIcExperimental !== undefined - ? globalThis._azleIcExperimental.stableBTreeMapGet( - memoryId.toString(), - encodedKey.buffer - ) - : globalThis._azleIcStable.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._azleIcStable === undefined && - globalThis._azleIcExperimental === undefined - ) { - return undefined as any; - } + /** + * Checks if the map is empty. + * @returns `true` if the map contains no elements, `false` otherwise. + */ + isEmpty(): boolean { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined as any; + } - const encodedKey = keySerializable.toBytes(key); - const encodedValue = valueSerializable.toBytes(value); - - const encodedResult = - globalThis._azleIcExperimental !== undefined - ? globalThis._azleIcExperimental.stableBTreeMapInsert( - memoryId.toString(), - encodedKey.buffer, - encodedValue.buffer - ) - : globalThis._azleIcStable.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._azleIcStable === undefined && - globalThis._azleIcExperimental === undefined - ) { - return undefined as any; - } + if (globalThis._azleIcExperimental !== undefined) { + return globalThis._azleIcExperimental.stableBTreeMapIsEmpty( + this.memoryId.toString() + ); + } - if (globalThis._azleIcExperimental !== undefined) { - return globalThis._azleIcExperimental.stableBTreeMapIsEmpty( - memoryId.toString() - ); - } + return globalThis._azleIcStable.stableBTreeMapIsEmpty(this.memoryId); + } - return globalThis._azleIcStable.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._azleIcStable === undefined && - globalThis._azleIcExperimental === undefined - ) { - return undefined as any; - } + /** + * 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._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined as any; + } - const encodedItems = - globalThis._azleIcExperimental !== undefined - ? globalThis._azleIcExperimental.stableBTreeMapItems( - memoryId.toString(), - startIndex?.toString() ?? '0', - length?.toString() ?? 'NOT_SET' - ) - : globalThis._azleIcStable.stableBTreeMapItems( - memoryId, - startIndex ?? 0, - length ?? -1 - ); - - // 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._azleIcStable === undefined && - globalThis._azleIcExperimental === undefined - ) { - return undefined as any; - } + const encodedItems = + globalThis._azleIcExperimental !== undefined + ? globalThis._azleIcExperimental.stableBTreeMapItems( + this.memoryId.toString(), + startIndex?.toString() ?? '0', + length?.toString() ?? 'NOT_SET' + ) + : globalThis._azleIcStable.stableBTreeMapItems( + this.memoryId, + startIndex ?? 0, + length ?? -1 + ); - const encodedKeys = - globalThis._azleIcExperimental !== undefined - ? globalThis._azleIcExperimental.stableBTreeMapKeys( - memoryId.toString(), - startIndex?.toString() ?? '0', - length?.toString() ?? 'NOT_SET' - ) - : globalThis._azleIcStable.stableBTreeMapKeys( - memoryId, - startIndex ?? 0, - length ?? -1 - ); - - // 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._azleIcStable === undefined && - globalThis._azleIcExperimental === undefined - ) { - return undefined as any; - } + // TODO too much copying + return encodedItems.map(([encodedKey, encodedValue]) => { + return [ + this.keySerializable.fromBytes(new Uint8Array(encodedKey)), + this.valueSerializable.fromBytes(new Uint8Array(encodedValue)) + ]; + }); + } - if (globalThis._azleIcExperimental !== undefined) { - return BigInt( - globalThis._azleIcExperimental.stableBTreeMapLen( - memoryId.toString() - ) - ); - } + /** + * 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._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined as any; + } - return BigInt(globalThis._azleIcStable.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._azleIcStable === undefined && - globalThis._azleIcExperimental === undefined - ) { - return undefined as any; - } + const encodedKeys = + globalThis._azleIcExperimental !== undefined + ? globalThis._azleIcExperimental.stableBTreeMapKeys( + this.memoryId.toString(), + startIndex?.toString() ?? '0', + length?.toString() ?? 'NOT_SET' + ) + : globalThis._azleIcStable.stableBTreeMapKeys( + this.memoryId, + startIndex ?? 0, + length ?? -1 + ); - const encodedKey = keySerializable.toBytes(key); - - const encodedValue = - globalThis._azleIcExperimental !== undefined - ? globalThis._azleIcExperimental.stableBTreeMapRemove( - memoryId.toString(), - encodedKey.buffer - ) - : globalThis._azleIcStable.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._azleIcStable === undefined && - globalThis._azleIcExperimental === undefined - ) { - return undefined as any; - } + // TODO too much copying + return encodedKeys.map((encodedKey) => { + return this.keySerializable.fromBytes(new Uint8Array(encodedKey)); + }); + } - const encodedValues = - globalThis._azleIcExperimental !== undefined - ? globalThis._azleIcExperimental.stableBTreeMapValues( - memoryId.toString(), - startIndex?.toString() ?? '0', - length?.toString() ?? 'NOT_SET' - ) - : globalThis._azleIcStable.stableBTreeMapValues( - memoryId, - startIndex ?? 0, - length ?? -1 - ); - - // TODO too much copying - return encodedValues.map((encodedValue) => { - return valueSerializable.fromBytes( - new Uint8Array(encodedValue) - ); - }); + /** + * Checks to see how many elements are in the map. + * @returns the number of elements in the map. + */ + len(): bigint { + if ( + globalThis._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined as any; } - }; + + if (globalThis._azleIcExperimental !== undefined) { + return BigInt( + globalThis._azleIcExperimental.stableBTreeMapLen( + this.memoryId.toString() + ) + ); + } + + return BigInt( + globalThis._azleIcStable.stableBTreeMapLen(this.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._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined as any; + } + + const encodedKey = this.keySerializable.toBytes(key); + + const encodedValue = + globalThis._azleIcExperimental !== undefined + ? globalThis._azleIcExperimental.stableBTreeMapRemove( + this.memoryId.toString(), + encodedKey.buffer + ) + : globalThis._azleIcStable.stableBTreeMapRemove( + this.memoryId, + encodedKey + ); + + if (encodedValue === undefined) { + return null; + } else { + return this.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._azleIcStable === undefined && + globalThis._azleIcExperimental === undefined + ) { + return undefined as any; + } + + const encodedValues = + globalThis._azleIcExperimental !== undefined + ? globalThis._azleIcExperimental.stableBTreeMapValues( + this.memoryId.toString(), + startIndex?.toString() ?? '0', + length?.toString() ?? 'NOT_SET' + ) + : globalThis._azleIcStable.stableBTreeMapValues( + this.memoryId, + startIndex ?? 0, + length ?? -1 + ); + + // TODO too much copying + return encodedValues.map((encodedValue) => { + return this.valueSerializable.fromBytes( + new Uint8Array(encodedValue) + ); + }); + } } function isSerializable(obj: any): asserts obj is Serializable { diff --git a/test/property/arbitraries/stable_b_tree_map_arb.ts b/test/property/arbitraries/stable_b_tree_map_arb.ts index f0b9c65b3f..12f38e748f 100644 --- a/test/property/arbitraries/stable_b_tree_map_arb.ts +++ b/test/property/arbitraries/stable_b_tree_map_arb.ts @@ -65,7 +65,7 @@ export function StableBTreeMapArb( return { name, imports, - definition: `let ${name} = StableBTreeMap<${key}, ${value}>(${memoryId}${serializableArguments});`, + definition: `let ${name} = new StableBTreeMap<${key}, ${value}>(${memoryId}${serializableArguments});`, keySample, valueSample }; From 64016f1629bc7e1698cd37afa3d028d708f8afbd Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 20 Dec 2024 14:10:03 -0700 Subject: [PATCH 2/3] pr fixes --- .../candid_rpc/stable_structures/package-lock.json | 12 +++++++++--- .../stable/stable_structures/stable_b_tree_map.ts | 14 +------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/examples/stable/test/end_to_end/candid_rpc/stable_structures/package-lock.json b/examples/stable/test/end_to_end/candid_rpc/stable_structures/package-lock.json index 747ddfb293..b9d4718621 100644 --- a/examples/stable/test/end_to_end/candid_rpc/stable_structures/package-lock.json +++ b/examples/stable/test/end_to_end/candid_rpc/stable_structures/package-lock.json @@ -8,12 +8,18 @@ "azle": "0.24.1" }, "devDependencies": { - "stable_structures_end_to_end_test_functional_syntax": "file:../../functional_syntax/stable_structures" + "stable_structures_end_to_end_test_functional_syntax": "file:../../../../../experimental/test/end_to_end/candid_rpc/stable_structures" + } + }, + "../../../../../experimental/test/end_to_end/candid_rpc/stable_structures": { + "dev": true, + "dependencies": { + "azle": "0.24.1" } }, "../../functional_syntax/stable_structures": { "name": "stable_structures_end_to_end_test_functional_syntax", - "dev": true, + "extraneous": true, "dependencies": { "azle": "0.24.1" } @@ -2005,7 +2011,7 @@ "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==" }, "node_modules/stable_structures_end_to_end_test_functional_syntax": { - "resolved": "../../functional_syntax/stable_structures", + "resolved": "../../../../../experimental/test/end_to_end/candid_rpc/stable_structures", "link": true }, "node_modules/stream-buffers": { 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 6b6d4e22c4..bbb575401a 100644 --- a/src/lib/stable/stable_structures/stable_b_tree_map.ts +++ b/src/lib/stable/stable_structures/stable_b_tree_map.ts @@ -30,9 +30,6 @@ export class StableBTreeMap { globalThis._azleIcStable.stableBTreeMapInit(memoryId); } } - - isSerializable(keySerializable); - isSerializable(valueSerializable); } /** @@ -62,6 +59,7 @@ export class StableBTreeMap { encodedKey ); } + /** * Retrieves the value stored at the provided key. * @param key the location from which to retrieve. @@ -321,13 +319,3 @@ export class StableBTreeMap { }); } } - -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`); - } -} From 4d6d596b93c4a0468759d1b16dc3eb5c938664ea Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 20 Dec 2024 14:13:09 -0700 Subject: [PATCH 3/3] fix typo --- src/lib/stable/stable_structures/stable_b_tree_map.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 bbb575401a..941a78cd7c 100644 --- a/src/lib/stable/stable_structures/stable_b_tree_map.ts +++ b/src/lib/stable/stable_structures/stable_b_tree_map.ts @@ -195,7 +195,7 @@ export class StableBTreeMap { * 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. + * @returns the keys in the map. */ keys(startIndex?: number, length?: number): Key[] { if (