diff --git a/examples/cycles/src/cycles/index.did b/examples/cycles/src/cycles/index.did index 9c3081c7ea..0d3dfd51c0 100644 --- a/examples/cycles/src/cycles/index.did +++ b/examples/cycles/src/cycles/index.did @@ -1,6 +1,6 @@ service: () -> { - receiveCycles: () -> (nat64); - receiveCycles128: () -> (nat); getCanisterBalance: () -> (nat64) query; getCanisterBalance128: () -> (nat) query; + receiveCycles: () -> (nat64); + receiveCycles128: () -> (nat); } diff --git a/examples/cycles/src/intermediary/index.did b/examples/cycles/src/intermediary/index.did index b57fdf08ef..74274cb464 100644 --- a/examples/cycles/src/intermediary/index.did +++ b/examples/cycles/src/intermediary/index.did @@ -1,8 +1,8 @@ service: () -> { + getCanisterBalance: () -> (nat64) query; + getCanisterBalance128: () -> (nat) query; sendCycles: () -> (nat64); - sendCyclesNotify: () -> (); sendCycles128: () -> (nat); sendCycles128Notify: () -> (); - getCanisterBalance: () -> (nat64) query; - getCanisterBalance128: () -> (nat) query; + sendCyclesNotify: () -> (); } diff --git a/examples/func_types/canisters/func_types/index.did b/examples/func_types/canisters/func_types/index.did index c3796cd593..236c78c089 100644 --- a/examples/func_types/canisters/func_types/index.did +++ b/examples/func_types/canisters/func_types/index.did @@ -1,13 +1,13 @@ -type rec_26 = func (record {id:text; complexFunc:rec_26; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_26; Good; BasicFunc:func (text) -> (text) query}) -> (nat64); -type rec_29 = func (record {id:text; complexFunc:rec_29; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_29; Good; BasicFunc:func (text) -> (text) query}) -> (nat64); -type rec_34 = func (record {id:text; complexFunc:rec_34; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_34; Good; BasicFunc:func (text) -> (text) query}) -> (nat64); +type rec_0 = func (record {id:text; complexFunc:rec_0; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_0; Good; BasicFunc:func (text) -> (text) query}) -> (nat64); +type rec_1 = func (record {id:text; complexFunc:rec_1; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_1; Good; BasicFunc:func (text) -> (text) query}) -> (nat64); +type rec_2 = func (record {id:text; complexFunc:rec_2; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_2; Good; BasicFunc:func (text) -> (text) query}) -> (nat64); service: () -> { basicFuncParam: (func (text) -> (text) query) -> (func (text) -> (text) query) query; basicFuncParamArray: (vec func (text) -> (text) query) -> (vec func (text) -> (text) query) query; basicFuncReturnType: () -> (func (text) -> (text) query) query; basicFuncReturnTypeArray: () -> (vec func (text) -> (text) query) query; - complexFuncParam: (rec_26) -> (rec_29) query; - complexFuncReturnType: () -> (rec_34) query; + complexFuncParam: (rec_0) -> (rec_1) query; + complexFuncReturnType: () -> (rec_2) query; getNotifierFromNotifiersCanister: () -> (func (vec nat8) -> () oneway); getStableFunc: () -> (func (nat64, text) -> () query) query; nullFuncParam: (func (opt null, vec null, null, vec vec null, vec opt null) -> (null) query) -> (func (opt null, vec null, null, vec vec null, vec opt null) -> (null) query) query; diff --git a/examples/manual_reply/src/index.did b/examples/manual_reply/src/index.did index 671739a3ff..5d668e09e2 100644 --- a/examples/manual_reply/src/index.did +++ b/examples/manual_reply/src/index.did @@ -1,39 +1,25 @@ -type rec_1 = record {electrons:nat8; layer:nat8}; -type rec_3 = variant {Elemental; Mixed; Toxic}; -type rec_4 = record {element:text}; -type rec_2 = variant {Gas:rec_3; Solid:rec_4; Liquid}; -type rec_0 = record {id:text; orbitals:vec rec_1; state:rec_2}; -type rec_5 = variant {Elemental; Mixed; Toxic}; -type rec_7 = variant {Large; Small; Medium}; -type rec_6 = record {int:int; bool:bool; text:text; myBlob:vec nat8; myVariant:rec_7}; -type rec_9 = record {electrons:nat8; layer:nat8}; -type rec_11 = variant {Elemental; Mixed; Toxic}; -type rec_12 = record {element:text}; -type rec_10 = variant {Gas:rec_11; Solid:rec_12; Liquid}; -type rec_8 = record {id:text; orbitals:vec rec_9; state:rec_10}; -type rec_13 = variant {Elemental; Mixed; Toxic}; service: () -> { - manualUpdate: (text) -> (text); - updateBlob: () -> (vec nat8); - updateFloat32: () -> (float32); - updateInt8: () -> (int8); - updateNat: () -> (nat); - updateNull: () -> (null); - updateVoid: () -> (); - updateRecord: () -> (rec_0); - updateReserved: () -> (reserved); - updateString: () -> (text); - updateVariant: () -> (rec_5); - replyRaw: () -> (rec_6); manualQuery: (text) -> (text) query; + manualUpdate: (text) -> (text); queryBlob: () -> (vec nat8) query; queryFloat32: () -> (float32) query; queryInt8: () -> (int8) query; queryNat: () -> (nat) query; queryNull: () -> (null) query; - queryVoid: () -> () query; - queryRecord: () -> (rec_8) query; + queryRecord: () -> (record {id:text; orbitals:vec record {electrons:nat8; layer:nat8}; state:variant {Gas:variant {Elemental; Mixed; Toxic}; Solid:record {element:text}; Liquid}}) query; queryReserved: () -> (reserved) query; queryString: () -> (text) query; - queryVariant: () -> (rec_13) query; + queryVariant: () -> (variant {Elemental; Mixed; Toxic}) query; + queryVoid: () -> () query; + replyRaw: () -> (record {int:int; bool:bool; text:text; myBlob:vec nat8; myVariant:variant {Large; Small; Medium}}); + updateBlob: () -> (vec nat8); + updateFloat32: () -> (float32); + updateInt8: () -> (int8); + updateNat: () -> (nat); + updateNull: () -> (null); + updateRecord: () -> (record {id:text; orbitals:vec record {electrons:nat8; layer:nat8}; state:variant {Gas:variant {Elemental; Mixed; Toxic}; Solid:record {element:text}; Liquid}}); + updateReserved: () -> (reserved); + updateString: () -> (text); + updateVariant: () -> (variant {Elemental; Mixed; Toxic}); + updateVoid: () -> (); } diff --git a/examples/manual_reply/src/index.ts b/examples/manual_reply/src/index.ts index 8ef6a7eb15..0f6152efa4 100644 --- a/examples/manual_reply/src/index.ts +++ b/examples/manual_reply/src/index.ts @@ -121,7 +121,7 @@ export default Canister({ ), updateVoid: update( [], - Void, + Manual(Void), () => { ic.reply(undefined, Void); }, diff --git a/examples/motoko_examples/persistent-storage/src/index.did b/examples/motoko_examples/persistent-storage/src/index.did index de7d56cbc4..e63226e8ed 100644 --- a/examples/motoko_examples/persistent-storage/src/index.did +++ b/examples/motoko_examples/persistent-storage/src/index.did @@ -1,6 +1,6 @@ service: () -> { + get: () -> (nat) query; getRedeployed: () -> (bool) query; increment: () -> (nat); - get: () -> (nat) query; reset: () -> (nat); } diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did index 0b3b6b0e80..2070c9fbaa 100644 --- a/examples/recursion/src/recursion/index.did +++ b/examples/recursion/src/recursion/index.did @@ -1,53 +1,53 @@ -type rec_365 = func (rec_365) -> (rec_365) query; -type rec_368 = func (rec_368) -> (rec_368) query; -type rec_373 = func (rec_373) -> (rec_373) query; -type rec_281 = record {myOpt:opt rec_281}; -type rec_284 = record {myOpt:opt rec_284}; -type rec_329 = record {myOpt:opt rec_329}; -type rec_297 = record {myVar:variant {num:int8; varRec:rec_297}}; -type rec_300 = record {myVar:variant {num:int8; varRec:rec_300}}; -type rec_337 = record {myVar:variant {num:int8; varRec:rec_337}}; -type rec_289 = record {myVecRecords:vec rec_289}; -type rec_292 = record {myVecRecords:vec rec_292}; -type rec_333 = record {myVecRecords:vec rec_333}; -type rec_385 = service {getMessage: () -> (text) query; myQuery: (rec_385) -> (rec_385) query;}; -type rec_388 = service {getMessage: () -> (text) query; myQuery: (rec_388) -> (rec_388) query;}; -type rec_397 = service {getMessage: () -> (text) query; myQuery: (rec_397) -> (rec_397) query;}; -type rec_400 = service {getMessage: () -> (text) query; myQuery: (rec_400) -> (rec_400) query;}; -type rec_393 = service {getMessage: () -> (text) query; myQuery: (rec_393) -> (rec_393) query;}; -type rec_377 = service {myQuery: (rec_377) -> (rec_377) query;}; -type rec_380 = service {myQuery: (rec_380) -> (rec_380) query;}; -type rec_313 = record {opt rec_313; opt rec_313}; -type rec_316 = record {opt rec_316; opt rec_316}; -type rec_345 = record {opt rec_345; opt rec_345}; -type rec_353 = record {variant {num:int8; varTuple:rec_353}; variant {num:int8; varTuple:rec_353}}; -type rec_356 = record {variant {num:int8; varTuple:rec_356}; variant {num:int8; varTuple:rec_356}}; -type rec_361 = record {variant {num:int8; varTuple:rec_361}; variant {num:int8; varTuple:rec_361}}; -type rec_321 = record {vec rec_321; vec rec_321}; -type rec_324 = record {vec rec_324; vec rec_324}; -type rec_349 = record {vec rec_349; vec rec_349}; -type rec_305 = variant {num:int8; recVariant:rec_305}; -type rec_308 = variant {num:int8; recVariant:rec_308}; -type rec_341 = variant {num:int8; recVariant:rec_341}; +type rec_21 = func (rec_21) -> (rec_21) query; +type rec_22 = func (rec_22) -> (rec_22) query; +type rec_23 = func (rec_23) -> (rec_23) query; +type rec_0 = record {myOpt:opt rec_0}; +type rec_1 = record {myOpt:opt rec_1}; +type rec_12 = record {myOpt:opt rec_12}; +type rec_4 = record {myVar:variant {num:int8; varRec:rec_4}}; +type rec_5 = record {myVar:variant {num:int8; varRec:rec_5}}; +type rec_14 = record {myVar:variant {num:int8; varRec:rec_14}}; +type rec_2 = record {myVecRecords:vec rec_2}; +type rec_3 = record {myVecRecords:vec rec_3}; +type rec_13 = record {myVecRecords:vec rec_13}; +type rec_26 = service {getMessage: () -> (text) query; myQuery: (rec_26) -> (rec_26) query;}; +type rec_27 = service {getMessage: () -> (text) query; myQuery: (rec_27) -> (rec_27) query;}; +type rec_29 = service {getMessage: () -> (text) query; myQuery: (rec_29) -> (rec_29) query;}; +type rec_30 = service {getMessage: () -> (text) query; myQuery: (rec_30) -> (rec_30) query;}; +type rec_28 = service {getMessage: () -> (text) query; myQuery: (rec_28) -> (rec_28) query;}; +type rec_24 = service {myQuery: (rec_24) -> (rec_24) query;}; +type rec_25 = service {myQuery: (rec_25) -> (rec_25) query;}; +type rec_8 = record {opt rec_8; opt rec_8}; +type rec_9 = record {opt rec_9; opt rec_9}; +type rec_16 = record {opt rec_16; opt rec_16}; +type rec_18 = record {variant {num:int8; varTuple:rec_18}; variant {num:int8; varTuple:rec_18}}; +type rec_19 = record {variant {num:int8; varTuple:rec_19}; variant {num:int8; varTuple:rec_19}}; +type rec_20 = record {variant {num:int8; varTuple:rec_20}; variant {num:int8; varTuple:rec_20}}; +type rec_10 = record {vec rec_10; vec rec_10}; +type rec_11 = record {vec rec_11; vec rec_11}; +type rec_17 = record {vec rec_17; vec rec_17}; +type rec_6 = variant {num:int8; recVariant:rec_6}; +type rec_7 = variant {num:int8; recVariant:rec_7}; +type rec_15 = variant {num:int8; recVariant:rec_15}; service: () -> { - testRecFunc: (rec_365) -> (rec_368) query; - testRecFuncReturn: () -> (rec_373) query; - testRecRecordWithOpt: (rec_281) -> (rec_284) query; - testRecRecordWithOptReturn: () -> (rec_329) query; - testRecRecordWithVariant: (rec_297) -> (rec_300) query; - testRecRecordWithVariantReturn: () -> (rec_337) query; - testRecRecordWithVec: (rec_289) -> (rec_292) query; - testRecRecordWithVecReturn: () -> (rec_333) query; - testRecService: (rec_385) -> (rec_388) query; - testRecServiceCall: (rec_397) -> (rec_400); - testRecServiceReturn: () -> (rec_393) query; - testRecServiceSimple: (rec_377) -> (rec_380) query; - testRecTupleWithOpt: (rec_313) -> (rec_316) query; - testRecTupleWithOptReturn: () -> (rec_345) query; - testRecTupleWithVariant: (rec_353) -> (rec_356) query; - testRecTupleWithVariantReturn: () -> (rec_361) query; - testRecTupleWithVec: (rec_321) -> (rec_324) query; - testRecTupleWithVecReturn: () -> (rec_349) query; - testRecVariant: (rec_305) -> (rec_308) query; - testRecVariantReturn: () -> (rec_341) query; + testRecFunc: (rec_21) -> (rec_22) query; + testRecFuncReturn: () -> (rec_23) query; + testRecRecordWithOpt: (rec_0) -> (rec_1) query; + testRecRecordWithOptReturn: () -> (rec_12) query; + testRecRecordWithVariant: (rec_4) -> (rec_5) query; + testRecRecordWithVariantReturn: () -> (rec_14) query; + testRecRecordWithVec: (rec_2) -> (rec_3) query; + testRecRecordWithVecReturn: () -> (rec_13) query; + testRecService: (rec_26) -> (rec_27) query; + testRecServiceCall: (rec_29) -> (rec_30); + testRecServiceReturn: () -> (rec_28) query; + testRecServiceSimple: (rec_24) -> (rec_25) query; + testRecTupleWithOpt: (rec_8) -> (rec_9) query; + testRecTupleWithOptReturn: () -> (rec_16) query; + testRecTupleWithVariant: (rec_18) -> (rec_19) query; + testRecTupleWithVariantReturn: () -> (rec_20) query; + testRecTupleWithVec: (rec_10) -> (rec_11) query; + testRecTupleWithVecReturn: () -> (rec_17) query; + testRecVariant: (rec_6) -> (rec_7) query; + testRecVariantReturn: () -> (rec_15) query; } diff --git a/examples/recursion/src/recursive_canister/index.did b/examples/recursion/src/recursive_canister/index.did index c13cc9540d..7c6f8c66e8 100644 --- a/examples/recursion/src/recursive_canister/index.did +++ b/examples/recursion/src/recursive_canister/index.did @@ -1,6 +1,6 @@ -type rec_18 = service {getMessage: () -> (text) query; myQuery: (rec_18) -> (rec_18) query;}; -type rec_21 = service {getMessage: () -> (text) query; myQuery: (rec_21) -> (rec_21) query;}; +type rec_0 = service {getMessage: () -> (text) query; myQuery: (rec_0) -> (rec_0) query;}; +type rec_1 = service {getMessage: () -> (text) query; myQuery: (rec_1) -> (rec_1) query;}; service: (text) -> { getMessage: () -> (text) query; - myQuery: (rec_18) -> (rec_21) query; + myQuery: (rec_0) -> (rec_1) query; } diff --git a/src/compiler/compile_typescript_code.ts b/src/compiler/compile_typescript_code.ts index 80e6061b13..f6c28df740 100644 --- a/src/compiler/compile_typescript_code.ts +++ b/src/compiler/compile_typescript_code.ts @@ -38,23 +38,8 @@ export function compileTypeScriptToJavaScript( ${imports} `); - const javaScriptCodeWithRandom = ` - globalThis.crypto = { - getRandomValues: () => { - let array = new Uint8Array(32); - - for (let i = 0; i < array.length; i++) { - array[i] = Math.floor(Math.random() * 256); - } - - return array; - } - }; - ${bundledJavaScript} - `; - return { - ok: javaScriptCodeWithRandom + ok: bundledJavaScript }; } catch (err) { return { err }; diff --git a/src/compiler/rust/canister/src/ic/call_raw.rs b/src/compiler/rust/canister/src/ic/call_raw.rs index 125dc37941..2d5f9b4d71 100644 --- a/src/compiler/rust/canister/src/ic/call_raw.rs +++ b/src/compiler/rust/canister/src/ic/call_raw.rs @@ -69,11 +69,13 @@ pub fn native_function<'a>( if should_resolve { let resolve = global + .get_property("_azleResolveIds").unwrap() .get_property(format!("_resolve_{promise_id}").as_str()) .unwrap(); resolve.call(&resolve, &[js_value_ref]).unwrap(); } else { let reject = global + .get_property("_azleRejectIds").unwrap() .get_property(format!("_reject_{promise_id}").as_str()) .unwrap(); reject.call(&reject, &[js_value_ref]).unwrap(); diff --git a/src/compiler/rust/canister/src/ic/call_raw128.rs b/src/compiler/rust/canister/src/ic/call_raw128.rs index adaf3b7e7b..b7da057038 100644 --- a/src/compiler/rust/canister/src/ic/call_raw128.rs +++ b/src/compiler/rust/canister/src/ic/call_raw128.rs @@ -69,11 +69,13 @@ pub fn native_function<'a>( if should_resolve { let resolve = global + .get_property("_azleResolveIds").unwrap() .get_property(format!("_resolve_{promise_id}").as_str()) .unwrap(); resolve.call(&resolve, &[js_value_ref]).unwrap(); } else { let reject = global + .get_property("_azleRejectIds").unwrap() .get_property(format!("_reject_{promise_id}").as_str()) .unwrap(); reject.call(&reject, &[js_value_ref]).unwrap(); diff --git a/src/compiler/rust/canister/src/ic/set_timer.rs b/src/compiler/rust/canister/src/ic/set_timer.rs index 8c42e3f1bb..94858b6101 100644 --- a/src/compiler/rust/canister/src/ic/set_timer.rs +++ b/src/compiler/rust/canister/src/ic/set_timer.rs @@ -34,6 +34,7 @@ pub fn native_function<'a>( let global = context.global_object().unwrap(); let timer_callback = global + .get_property("_azleTimerCallbackIds").unwrap() .get_property(callback_id.as_str()) .unwrap_or_else(|e| ic_cdk::api::trap(e.to_string().as_str())); diff --git a/src/compiler/rust/canister/src/ic/set_timer_interval.rs b/src/compiler/rust/canister/src/ic/set_timer_interval.rs index 856000629f..78b8f8e399 100644 --- a/src/compiler/rust/canister/src/ic/set_timer_interval.rs +++ b/src/compiler/rust/canister/src/ic/set_timer_interval.rs @@ -34,6 +34,7 @@ pub fn native_function<'a>( let global = context.global_object().unwrap(); let timer_callback = global + .get_property("_azleTimerCallbackIds").unwrap() .get_property(callback_id.as_str()) .unwrap_or_else(|e| ic_cdk::api::trap(e.to_string().as_str())); diff --git a/src/lib/candid/did_visitor.ts b/src/lib/candid/did_visitor.ts index 05e1e2f564..1d621bd6b5 100644 --- a/src/lib/candid/did_visitor.ts +++ b/src/lib/candid/did_visitor.ts @@ -130,7 +130,7 @@ export class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const fields = components.map((value) => - hch(value).accept(this, { ...data, isOnService: false }) + value.accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(fields); return [`record {${candid[0].join('; ')}}`, candid[1]]; @@ -140,7 +140,7 @@ export class DidVisitor extends IDL.Visitor { ty: IDL.Type, data: VisitorData ): VisitorResult { - const candid = hch(ty).accept(this, { ...data, isOnService: false }); + const candid = ty.accept(this, { ...data, isOnService: false }); return [`opt ${candid[0]}`, candid[1]]; } visitVec( @@ -148,16 +148,16 @@ export class DidVisitor extends IDL.Visitor { ty: IDL.Type, data: VisitorData ): VisitorResult { - const candid = hch(ty).accept(this, { ...data, isOnService: false }); + const candid = ty.accept(this, { ...data, isOnService: false }); return [`vec ${candid[0]}`, candid[1]]; } visitFunc(t: IDL.FuncClass, data: VisitorData): VisitorResult { const argsTypes = t.argTypes.map((value) => - hch(value).accept(this, { ...data, isOnService: false }) + value.accept(this, { ...data, isOnService: false }) ); const candidArgs = extractCandid(argsTypes); const retsTypes = t.retTypes.map((value) => - hch(value).accept(this, { ...data, isOnService: false }) + value.accept(this, { ...data, isOnService: false }) ); const candidRets = extractCandid(retsTypes); const args = candidArgs[0].join(', '); @@ -180,7 +180,7 @@ export class DidVisitor extends IDL.Visitor { // Everything else will just be the normal inline candid def const usedRecClasses = data.usedRecClasses; if (!usedRecClasses.includes(t)) { - const candid = hch(ty).accept(this, { + const candid = ty.accept(this, { ...data, usedRecClasses: [...usedRecClasses, t], isOnService: false, @@ -198,7 +198,7 @@ export class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const candidFields = fields.map(([key, value]) => - hch(value).accept(this, { ...data, isOnService: false }) + value.accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(candidFields); const field_strings = fields.map( @@ -212,7 +212,7 @@ export class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const candidFields = fields.map(([key, value]) => - hch(value).accept(this, { ...data, isOnService: false }) + value.accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(candidFields); const fields_string = fields.map( @@ -249,10 +249,3 @@ function extractCandid( ); return [paramCandid, candidTypeDefs]; } - -function hch(value: any) { - if (value._azleIsCanister) { - return value().getIDL(); - } - return value; -} diff --git a/src/lib/candid/index.ts b/src/lib/candid/index.ts index 6722110160..3013d0aa1b 100644 --- a/src/lib/candid/index.ts +++ b/src/lib/candid/index.ts @@ -115,66 +115,26 @@ export type Parent = { name: string; }; -export function toIDLType(idl: CandidType, parents: Parent[]): IDL.Type { - if ('getIDL' in idl) { - if ('_azleName' in idl) { - const parent = parents.find( - (parent) => parent.name === idl._azleName - ); - if (parent !== undefined) { - return { - ...parent.idl, - _azleName: idl._azleName, - name: parent.idl.name, - valueToString: (x): string => { - return parent.idl.valueToString(x); - }, - buildTypeTable: (typeTable): void => { - return parent.idl.buildTypeTable(typeTable); - }, - covariant: (x): x is any => { - return parent.idl.covariant(x); - }, - encodeType: (typeTable): ArrayBuffer => { - return parent.idl.encodeType(typeTable); - }, - checkType: (t) => { - return parent.idl.checkType(t); - }, - _buildTypeTableImpl: (typeTable): void => { - return parent.idl._buildTypeTableImpl(typeTable); - }, - // TODO check if this is still being called. maybe by adding a throw here and see if we hit it - display: () => parent.idl.name, - decodeValue: (b, t) => { - return parent.idl.decodeValue(b, t); - }, - encodeValue: (b) => { - return parent.idl.encodeValue(b); - }, - accept: (v, d) => { - return parent.idl.accept(v, d); - }, - _id: parent.idl._id, - _type: parent.idl._type, - fill: (t: any): void => { - parent.idl.fill(t); - }, - getType: () => { - return parent.idl.getType(); - } - }; - } +export function toIDLType( + candidType: CandidType, + parents: Parent[] +): IDL.Type { + if ('_azleName' in candidType) { + const parent = parents.find( + (parent) => parent.name === candidType._azleName + ); + // If the parent isn't undefined (ie we found one with the same name) + // this is a recursive type and we should return the parent rec idl + // instead of calling getIDL + if (parent !== undefined) { + return parent.idl; } - return idl.getIDL(parents); } - if (idl._azleIsCanister) { - return toIDLType(idl(), parents); + if ('_azleIsCanister' in candidType && candidType._azleIsCanister) { + return toIDLType((candidType as any)(), parents); } - // if (idl.display === undefined || idl.getIDL === undefined) { - // throw Error(`${JSON.stringify(idl)} is not a candid type`); - // } - return idl; + // All CandidTypes ought to have a getIDL function defined for them + return (candidType as any).getIDL(parents); } export function toParamIDLTypes( diff --git a/src/lib/candid/recursive.ts b/src/lib/candid/recursive.ts index f8e34b2f95..77dc55abbb 100644 --- a/src/lib/candid/recursive.ts +++ b/src/lib/candid/recursive.ts @@ -1,23 +1,30 @@ import { v4 } from 'uuid'; import { IDL } from '@dfinity/candid'; -import { Parent } from './index'; +import { CandidType, Parent } from './index'; -export function Recursive(idlCallback: any): any { +export type _AzleRecursiveFunction = { + (...args: any[]): CandidType; + _azleName?: string; + _azleIsRecursive?: boolean; + getIDL?: (parents: Parent[]) => IDL.Type; +}; + +export function Recursive(candidTypeCallback: any): any { const name = v4(); - let result = (...args: any[]) => { - const idl = idlCallback(); - if (idl._azleIsCanister) { - return idl(...args); + let result: _AzleRecursiveFunction = (...args: any[]) => { + const candidType = candidTypeCallback(); + if (candidType._azleIsCanister) { + return candidType(...args); } - return idl; + return candidType; }; result._azleName = name; result._azleIsRecursive = true; result.getIDL = (parents: Parent[]) => { const idl = IDL.Rec(); - let filler = idlCallback(); + let filler = candidTypeCallback(); if (filler._azleIsCanister) { filler = filler(result); } diff --git a/src/lib/candid/serde/index.ts b/src/lib/candid/serde/index.ts index 8a7caa23db..3acb28def2 100644 --- a/src/lib/candid/serde/index.ts +++ b/src/lib/candid/serde/index.ts @@ -3,7 +3,7 @@ import { IDL } from '@dfinity/candid'; import { AzleVec, AzleOpt, AzleTuple } from '../types/constructed'; import { DecodeVisitor } from './visitors/decode_visitor'; import { EncodeVisitor } from './visitors/encode_visitor'; -import { CandidType, toIDLType } from '../../candid'; +import { CandidType, Parent, toIDLType } from '../../candid'; /** * Encodes the provided value as candid blob of the designated type. @@ -14,25 +14,28 @@ import { CandidType, toIDLType } from '../../candid'; * values, converting any Azle values to official IDL values. * * @param data the value to encode - * @param fakeIdl either a built-in IDL data type, or an Azle-defined super-type + * @param candidType either a built-in IDL data type, or an Azle-defined super-type * @returns candid bytes */ export function encode( + candidType: CandidType, data: any, - fakeIdl: IDL.Type | CandidType + parents: Parent[] = [] ): Uint8Array { - // TODO: there is a discrepancy between CandidType and CandidClass that - // needs to be aligned so that this isn't an error. Both are representing - // candid IDLs, either from the @dfinity/candid library or the - // Azle-augmented ones - const realIDL = toIDLType(fakeIdl, []); + const idl = toIDLType(candidType, parents); - const encodeReadyKey = realIDL.accept(new EncodeVisitor(), { - js_class: fakeIdl, + const idlIsAzleVoid = Array.isArray(idl); + + if (idlIsAzleVoid) { + return new Uint8Array(IDL.encode([], [])); + } + + const encodeReadyKey = idl.accept(new EncodeVisitor(), { + candidType: candidType, js_data: data }); - return new Uint8Array(IDL.encode([realIDL], [encodeReadyKey])); + return new Uint8Array(IDL.encode([idl], [encodeReadyKey])); } /** @@ -44,53 +47,55 @@ export function encode( * values, converting them from their native shape to the shape that Azle expects. * * @param data the value to decode - * @param fakeIdl either a built-in IDL data type, or an Azle-defined super-type + * @param candidType either a built-in IDL data type, or an Azle-defined super-type * @returns the Azle representation of the data */ export function decode( + candidType: CandidType, data: ArrayBuffer, - fakeIdl: IDL.Type | CandidType + parents: Parent[] = [] ): any { // TODO: there is a discrepancy between CandidType and CandidClass that // needs to be aligned so that this isn't an error. Both are representing // candid IDLs, either from the @dfinity/candid library or the // Azle-augmented ones - const realIDL = toIDLType(fakeIdl, []); + const idl = toIDLType(candidType, parents); - const idlIsAzleVoid = Array.isArray(realIDL); + const idlIsAzleVoid = Array.isArray(idl); if (idlIsAzleVoid) { return undefined; } - const candidDecodedValue = IDL.decode([realIDL], data)[0] as any; + const candidDecodedValue = IDL.decode([idl], data)[0] as any; - return realIDL.accept(new DecodeVisitor(), { - js_class: fakeIdl, + return idl.accept(new DecodeVisitor(), { + candidType: candidType, js_data: candidDecodedValue }); } export function encodeMultiple( + candidTypes: CandidType[], data: any[], - fakeIdls: (IDL.Type | CandidType)[] + parents: Parent[] = [] ): Uint8Array { const { values, idls } = data.reduce<{ values: any[]; idls: IDL.Type[]; }>( (acc, datum, index) => { - const fakeIdl = fakeIdls[index]; - const realIDL = toIDLType(fakeIdl, []); + const candidType = candidTypes[index]; + const idl = toIDLType(candidType, parents); - const encodeReadyValue = realIDL.accept(new EncodeVisitor(), { - js_class: fakeIdl, + const encodeReadyValue = idl.accept(new EncodeVisitor(), { + candidType: candidType, js_data: datum }); return { values: [...acc.values, encodeReadyValue], - idls: [...acc.idls, realIDL] + idls: [...acc.idls, idl] }; }, { values: [], idls: [] } @@ -98,3 +103,20 @@ export function encodeMultiple( return new Uint8Array(IDL.encode(idls, values)); } + +export function decodeMultiple( + candidTypes: CandidType[], + data: ArrayBuffer, + parents: Parent[] = [] +): any[] { + const idls = candidTypes.map((candidType) => + toIDLType(candidType, parents) + ); + const decoded = IDL.decode(idls, data); + return idls.map((idl, index) => + idl.accept(new DecodeVisitor(), { + candidType: candidTypes[index], + js_data: decoded[index] + }) + ); +} diff --git a/src/lib/candid/serde/visitors/decode_visitor.ts b/src/lib/candid/serde/visitors/decode_visitor.ts index 777323fbe0..c97d94f91b 100644 --- a/src/lib/candid/serde/visitors/decode_visitor.ts +++ b/src/lib/candid/serde/visitors/decode_visitor.ts @@ -1,6 +1,5 @@ import { IDL } from '@dfinity/candid'; import { - hch, VisitorData, VisitorResult, visitRec, @@ -19,7 +18,7 @@ import { Opt } from '../../types/constructed'; export class DecodeVisitor extends IDL.Visitor { visitService(t: IDL.ServiceClass, data: VisitorData): VisitorResult { - return data.js_class(data.js_data); + return data.candidType(data.js_data); } visitFunc(t: IDL.FuncClass, data: VisitorData): VisitorResult { return data.js_data; @@ -57,9 +56,9 @@ export class DecodeVisitor extends IDL.Visitor { return { None: null }; } - const candid = hch(ty).accept(this, { + const candid = ty.accept(this, { js_data: data.js_data[0], - js_class: data.js_class._azleType + candidType: data.candidType._azleType }); return { diff --git a/src/lib/candid/serde/visitors/encode_visitor.ts b/src/lib/candid/serde/visitors/encode_visitor.ts index 02b1f7d3bd..e931383364 100644 --- a/src/lib/candid/serde/visitors/encode_visitor.ts +++ b/src/lib/candid/serde/visitors/encode_visitor.ts @@ -1,6 +1,5 @@ import { IDL } from '@dfinity/candid'; import { - hch, VisitorData, VisitorResult, visitRec, @@ -56,9 +55,9 @@ export class EncodeVisitor extends IDL.Visitor { data: VisitorData ): [] | [any] { if ('Some' in data.js_data) { - const candid = hch(ty).accept(this, { + const candid = ty.accept(this, { js_data: data.js_data.Some, - js_class: data.js_class._azleType + candidType: data.candidType._azleType }); return [candid]; diff --git a/src/lib/candid/serde/visitors/index.ts b/src/lib/candid/serde/visitors/index.ts index 3c68dc138d..3b2150e865 100644 --- a/src/lib/candid/serde/visitors/index.ts +++ b/src/lib/candid/serde/visitors/index.ts @@ -2,6 +2,7 @@ import { IDL } from '@dfinity/candid'; import { DecodeVisitor } from './decode_visitor'; import { EncodeVisitor } from './encode_visitor'; import { AzleResult, Result } from '../../../system_types/result'; +import { CandidType } from '../..'; export { EncodeVisitor, DecodeVisitor }; /* @@ -9,7 +10,7 @@ export { EncodeVisitor, DecodeVisitor }; * encoded or was just decoded. js_class is the CandidClass (IDLable) class that * can be used to create the class. */ -export type VisitorData = { js_data: any; js_class: any }; +export type VisitorData = { js_data: any; candidType: any }; /** * The VisitorResult is the transformed version of js_data that is ready to * be consumed by the js or ready to be encoded. @@ -22,22 +23,15 @@ export type VisitorResult = any; * is extracted into these helper methods. */ -export function hch(value: any) { - if (value._azleIsCanister) { - return value().getIDL(); - } - return value; -} - export function visitTuple( visitor: DecodeVisitor | EncodeVisitor, components: IDL.Type[], data: VisitorData ): VisitorResult { const fields = components.map((value, index) => - hch(value).accept(visitor, { + value.accept(visitor, { js_data: data.js_data[index], - js_class: data.js_class._azleTypes[index] + candidType: data.candidType._azleTypes[index] }) ); return [...fields]; @@ -52,9 +46,9 @@ export function visitVec( return data.js_data; } return data.js_data.map((array_elem: any) => { - return hch(ty).accept(visitor, { + return ty.accept(visitor, { js_data: array_elem, - js_class: data.js_class._azleType + candidType: data.candidType._azleType }); }); } @@ -66,13 +60,13 @@ export function visitRecord( ): VisitorResult { const candidFields = fields.reduce((acc, [memberName, memberIdl]) => { const fieldData = data.js_data[memberName]; - const fieldClass = data.js_class[memberName]; + const fieldClass = data.candidType[memberName]; return { ...acc, - [memberName]: hch(memberIdl).accept(visitor, { + [memberName]: memberIdl.accept(visitor, { js_data: fieldData, - js_class: fieldClass + candidType: fieldClass }) }; }, {}); @@ -85,42 +79,42 @@ export function visitVariant( fields: [string, IDL.Type][], data: VisitorData ): VisitorResult { - if (data.js_class instanceof AzleResult) { + if (data.candidType instanceof AzleResult) { if ('Ok' in data.js_data) { const okField = fields[0]; const okData = data.js_data['Ok']; - const okClass = data.js_class._azleOk; + const okClass = data.candidType._azleOk; return Result.Ok( - hch(okField[1]).accept(visitor, { + okField[1].accept(visitor, { js_data: okData, - js_class: okClass + candidType: okClass }) ); } if ('Err' in data.js_data) { const errField = fields[0]; const errData = data.js_data['Err']; - const errClass = data.js_class._azleErr; + const errClass = data.candidType._azleErr; return Result.Err( - hch(errField[1]).accept(visitor, { + errField[1].accept(visitor, { js_data: errData, - js_class: errClass + candidType: errClass }) ); } } const candidFields = fields.reduce((acc, [memberName, memberIdl]) => { const fieldData = data.js_data[memberName]; - const fieldClass = data.js_class[memberName]; + const fieldClass = data.candidType[memberName]; if (fieldData === undefined) { // If the field data is undefined then it is not the variant that was used return acc; } return { ...acc, - [memberName]: hch(memberIdl).accept(visitor, { - js_class: fieldClass, + [memberName]: memberIdl.accept(visitor, { + candidType: fieldClass, js_data: fieldData }) }; @@ -134,12 +128,12 @@ export function visitRec( ty: IDL.ConstructType, data: VisitorData ): VisitorResult { - let js_class = data.js_class(); - if (js_class._azleIsCanister) { - js_class = js_class([]); + let candidType = data.candidType(); + if (candidType._azleIsCanister) { + candidType = candidType([]); } - return hch(ty).accept(visitor, { + return ty.accept(visitor, { ...data, - js_class + candidType }); } diff --git a/src/lib/candid/types/constructed/record.ts b/src/lib/candid/types/constructed/record.ts index 623b78dde6..8bcf3541dd 100644 --- a/src/lib/candid/types/constructed/record.ts +++ b/src/lib/candid/types/constructed/record.ts @@ -12,11 +12,8 @@ export function Record< ): { [K in keyof T]: TypeMapping; } & { _azleCandidType?: '_azleCandidType' } { - const name = v4(); - return { ...obj, - _azleName: name, getIDL(parents: Parent[]) { return IDL.Record(processMap(obj as any, parents)); } diff --git a/src/lib/candid/types/constructed/variant.ts b/src/lib/candid/types/constructed/variant.ts index 171824cb38..7ac6cf4939 100644 --- a/src/lib/candid/types/constructed/variant.ts +++ b/src/lib/candid/types/constructed/variant.ts @@ -12,11 +12,8 @@ export function Variant< ): RequireExactlyOne<{ [K in keyof T]: TypeMapping; }> & { _azleCandidType?: '_azleCandidType' } { - const name = v4(); - return { ...obj, - _azleName: name, getIDL(parents: any) { return IDL.Variant(processMap(obj as any, parents)); } diff --git a/src/lib/candid/types/reference/func.ts b/src/lib/candid/types/reference/func.ts index 94aaf8d54b..aa3483a826 100644 --- a/src/lib/candid/types/reference/func.ts +++ b/src/lib/candid/types/reference/func.ts @@ -1,7 +1,6 @@ import { CandidType } from '../../index'; import { IDL } from '@dfinity/candid'; import { Principal } from './principal'; -import { v4 } from 'uuid'; import { Parent, toParamIDLTypes, toReturnIDLType } from '../../index'; type Mode = 'query' | 'update' | 'oneway'; @@ -9,23 +8,19 @@ type Mode = 'query' | 'update' | 'oneway'; const modeToCandid = { query: ['query'], oneway: ['oneway'], - update: [] // TODO what is the proper way to do updates + update: [] }; export function Func( - paramsIdls: CandidType[], - returnIdl: CandidType, + paramCandidTypes: CandidType[], + returnCandidTypes: CandidType, mode: Mode ): [Principal, string] & { _azleCandidType?: '_azleCandidType' } { - // TODO can't Func be recursive? - // TODO can't Opt be recursive? - // const name = v4(); - return { getIDL(parents: Parent[]) { return IDL.Func( - toParamIDLTypes(paramsIdls, parents), - toReturnIDLType(returnIdl, parents), + toParamIDLTypes(paramCandidTypes, parents), + toReturnIDLType(returnCandidTypes, parents), modeToCandid[mode] ); } diff --git a/src/lib/candid/types/reference/service.ts b/src/lib/candid/types/reference/service.ts index 089ff58b03..e56c794982 100644 --- a/src/lib/candid/types/reference/service.ts +++ b/src/lib/candid/types/reference/service.ts @@ -2,8 +2,10 @@ import { TypeMapping, Parent, toParamIDLTypes, - toReturnIDLType + toReturnIDLType, + CandidType } from '../../index'; +import { _AzleRecursiveFunction } from '../../recursive'; import { ic } from '../../../ic'; import { Principal } from './principal'; import { IDL } from '@dfinity/candid'; @@ -14,6 +16,31 @@ type CanisterOptions = { [key: string]: CanisterMethodInfo; }; +type _AzleCanisterOptions = { + [key: string]: ( + parentOrUndefined: _AzleRecursiveFunction | undefined + ) => CanisterMethodInfo; +}; + +type _AzleFunctionReturnType = { + (principal: Principal): void; + init?: any; + post_upgrade?: any; + pre_upgrade?: any; + heartbeat?: any; + inspect_message?: any; + queries?: any[]; + updates?: any[]; + callbacks?: any; + getSystemFunctionIDLs?: (parents: Parent[]) => IDL.FuncClass[]; + getIDL?: (parents: Parent[]) => IDL.Type; +}; + +type _AzleCanisterReturnType = { + (parentOrPrincipal: _AzleRecursiveFunction | Principal): void; + _azleIsCanister?: boolean; +}; + type CanisterReturn = { [EndpointName in keyof T]: T[EndpointName] extends CanisterMethodInfo< infer Params, @@ -32,30 +59,19 @@ type CallableObject = { export function Canister( serviceOptions: T ): CallableObject & { _azleCandidType?: '_azleCandidType' } { - let result = (parentOrPrincipal: any) => { + const _azleCanisterOptions = + serviceOptions as unknown as _AzleCanisterOptions; + let result: _AzleCanisterReturnType = (parentOrPrincipal: any) => { const originalPrincipal = parentOrPrincipal; const parentOrUndefined = parentOrPrincipal !== undefined && parentOrPrincipal._isPrincipal ? undefined : parentOrPrincipal; - const callbacks = Object.entries(serviceOptions).reduce( + const callbacks = Object.entries(_azleCanisterOptions).reduce( (acc, entry) => { const key = entry[0]; const value = entry[1](parentOrUndefined); - // if (principal === undefined) { - // return { - // ...acc, - // [key]: (...args: any[]) => { - // return serviceCall( - // principal as any, - // key, - // value.paramsIdls, - // value.returnIdl - // )(...args); - // } - // }; - // } else { return { ...acc, [key]: { @@ -64,8 +80,8 @@ export function Canister( return serviceCall( this.principal as any, key, - value.paramsIdls, - value.returnIdl + value.paramCandidTypes, + value.returnCandidType )(...args); } } @@ -75,7 +91,7 @@ export function Canister( {} ); - const initOption = Object.entries(serviceOptions).find( + const initOption = Object.entries(_azleCanisterOptions).find( ([key, value]) => value(parentOrUndefined).mode === 'init' ); const init = @@ -85,7 +101,7 @@ export function Canister( name: initOption[0] }; - const postUpgradeOption = Object.entries(serviceOptions).find( + const postUpgradeOption = Object.entries(_azleCanisterOptions).find( ([key, value]) => value(parentOrUndefined).mode === 'postUpgrade' ); const postUpgrade = @@ -95,7 +111,7 @@ export function Canister( name: postUpgradeOption[0] }; - const preUpgradeOption = Object.entries(serviceOptions).find( + const preUpgradeOption = Object.entries(_azleCanisterOptions).find( ([key, value]) => value(parentOrUndefined).mode === 'preUpgrade' ); const preUpgrade = @@ -105,7 +121,7 @@ export function Canister( name: preUpgradeOption[0] }; - const heartbeatOption = Object.entries(serviceOptions).find( + const heartbeatOption = Object.entries(_azleCanisterOptions).find( ([key, value]) => value(parentOrUndefined).mode === 'heartbeat' ); const heartbeat = @@ -115,7 +131,7 @@ export function Canister( name: heartbeatOption[0] }; - const inspectMessageOption = Object.entries(serviceOptions).find( + const inspectMessageOption = Object.entries(_azleCanisterOptions).find( ([key, value]) => value(parentOrUndefined).mode === 'inspectMessage' ); const inspectMessage = @@ -125,7 +141,7 @@ export function Canister( name: inspectMessageOption[0] }; - const queries = Object.entries(serviceOptions) + const queries = Object.entries(_azleCanisterOptions) .filter((entry) => { const key = entry[0]; const value = entry[1](parentOrUndefined); @@ -143,7 +159,7 @@ export function Canister( }; }); - const updates = Object.entries(serviceOptions) + const updates = Object.entries(_azleCanisterOptions) .filter((entry) => { const key = entry[0]; const value = entry[1](parentOrUndefined); @@ -160,25 +176,14 @@ export function Canister( }; }); - let returnFunction = (principal: Principal) => { - const callbacks = Object.entries(serviceOptions).reduce( + let returnFunction: _AzleFunctionReturnType = ( + principal: Principal + ) => { + const callbacks = Object.entries(_azleCanisterOptions).reduce( (acc, entry) => { const key = entry[0]; const value = entry[1](parentOrUndefined); - // if (principal === undefined) { - // return { - // ...acc, - // [key]: (...args: any[]) => { - // return serviceCall( - // principal as any, - // key, - // value.paramsIdls, - // value.returnIdl - // )(...args); - // } - // }; - // } else { return { ...acc, [key]: { @@ -187,8 +192,8 @@ export function Canister( return serviceCall( principal as any, key, - value.paramsIdls, - value.returnIdl + value.paramCandidTypes, + value.returnCandidType )(...args); } } @@ -212,10 +217,11 @@ export function Canister( returnFunction.queries = queries; returnFunction.updates = updates; returnFunction.callbacks = callbacks; - (returnFunction.getSystemFunctionIDLs = ( + returnFunction.getSystemFunctionIDLs = ( parents: Parent[] ): IDL.FuncClass[] => { - const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; + const serviceFunctionInfo = + _azleCanisterOptions as unknown as ServiceFunctionInfo; return Object.entries(serviceFunctionInfo).reduce( (accumulator, [_methodName, functionInfo]) => { @@ -226,11 +232,11 @@ export function Canister( } const paramRealIdls = toParamIDLTypes( - functionInfo(parentOrUndefined).paramsIdls, + functionInfo(parentOrUndefined).paramCandidTypes, parents ); const returnRealIdl = toReturnIDLType( - functionInfo(parentOrUndefined).returnIdl, + functionInfo(parentOrUndefined).returnCandidType, parents ); return [ @@ -240,107 +246,66 @@ export function Canister( }, [] as IDL.FuncClass[] ); - }), - (returnFunction.getIDL = (parents: Parent[]): IDL.ServiceClass => { - const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; - - const record = Object.entries(serviceFunctionInfo).reduce( - (accumulator, [methodName, functionInfo]) => { - const paramRealIdls = toParamIDLTypes( - functionInfo(parentOrUndefined).paramsIdls, - parents - ); - const returnRealIdl = toReturnIDLType( - functionInfo(parentOrUndefined).returnIdl, - parents - ); - - const mode = functionInfo(parentOrUndefined).mode; - let annotations: string[] = []; - if (mode === 'update') { - // do nothing - } else if (mode === 'query') { - annotations = ['query']; - } else { - // We don't want init, post upgrade, etc showing up in the idl - return accumulator; - } + }; + returnFunction.getIDL = (parents: Parent[]): IDL.ServiceClass => { + const serviceFunctionInfo = + _azleCanisterOptions as unknown as ServiceFunctionInfo; - return { - ...accumulator, - [methodName]: IDL.Func( - paramRealIdls, - returnRealIdl, - annotations - ) - }; - }, - {} as Record - ); + const record = Object.entries(serviceFunctionInfo).reduce( + (accumulator, [methodName, functionInfo]) => { + const paramRealIdls = toParamIDLTypes( + functionInfo(parentOrUndefined).paramCandidTypes, + parents + ); + const returnRealIdl = toReturnIDLType( + functionInfo(parentOrUndefined).returnCandidType, + parents + ); - return IDL.Service(record); - }); + const mode = functionInfo(parentOrUndefined).mode; + let annotations: string[] = []; + if (mode === 'update') { + // do nothing + } else if (mode === 'query') { + annotations = ['query']; + } else { + // We don't want init, post upgrade, etc showing up in the idl + return accumulator; + } + + return { + ...accumulator, + [methodName]: IDL.Func( + paramRealIdls, + returnRealIdl, + annotations + ) + }; + }, + {} as Record + ); + + return IDL.Service(record); + }; if (originalPrincipal !== undefined && originalPrincipal._isPrincipal) { return returnFunction(originalPrincipal); } return returnFunction; - - // TODO loop through each key and simply grab the candid off - // TODO grab the init/post_upgrade candid as well - // return { - // candid: `${ - // candidTypes.length === 0 ? '' : candidTypes.join('\n') + '\n' - // }service: () -> { - // ${Object.entries(serviceOptions) - // .map((entry) => { - // return `${entry[0]}: ${entry[1].candid}`; - // }) - // .join('\n ')} - // } - // `, - // queries, - // updates, - // callbacks, - // principal, - // ...callbacks, // TODO then we can't use any names that could collide in this object - // getIDL(parents: Parent[]): IDL.ServiceClass { - // const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; - - // const record = Object.entries(serviceFunctionInfo).reduce( - // (accumulator, [methodName, functionInfo]) => { - // const paramRealIdls = toParamIDLTypes(functionInfo.paramsIdls); - // const returnRealIdl = toReturnIDLType(functionInfo.returnIdl); - - // const annotations = - // functionInfo.mode === 'update' ? [] : ['query']; - - // return { - // ...accumulator, - // [methodName]: IDL.Func( - // paramRealIdls, - // returnRealIdl, - // annotations - // ) - // }; - // }, - // {} as Record - // ); - - // return IDL.Service(record); - // } - // } as any; }; result._azleIsCanister = true; - return result; + return result as any; } +type CallRawFunction = typeof ic.callRaw | typeof ic.callRaw128; +type NotifyRawFunction = typeof ic.notifyRaw; + function serviceCall( canisterId: Principal, methodName: string, - paramsIdls: any[], - returnIdl: any + paramCandidTypes: CandidType[], + returnCandidType: CandidType ) { // This must remain a function and not an arrow function // in order to set the context (this) correctly @@ -348,18 +313,15 @@ function serviceCall( this: any, // TODO in lib_new this was Service, I'm not sure we need this anymore _: '_AZLE_CROSS_CANISTER_CALL', notify: boolean, - callFunction: - | typeof ic.callRaw - | typeof ic.callRaw128 - | typeof ic.notifyRaw, + callFunction: CallRawFunction | NotifyRawFunction, cycles: bigint, ...args: any[] ) { - const encodedArgs = encodeMultiple(args, paramsIdls); + const encodedArgs = encodeMultiple(paramCandidTypes, args); if (notify) { try { - return callFunction( + return (callFunction as NotifyRawFunction)( canisterId, methodName, encodedArgs, @@ -369,14 +331,14 @@ function serviceCall( throw error; } } else { - const encodedResult = await callFunction( + const encodedResult = await (callFunction as CallRawFunction)( canisterId, methodName, encodedArgs, cycles ); - return decode(encodedResult, returnIdl); + return decode(returnCandidType, encodedResult); } }; } @@ -397,10 +359,10 @@ function createGlobalGuard( type FunctionInfo = { mode: 'query' | 'update'; - paramIdls: any[]; - returnIdl: any; + paramCandidTypes: CandidType[]; + returnCandidType: CandidType; }; interface ServiceFunctionInfo { - [key: string]: FunctionInfo; + [key: string]: (parent: _AzleRecursiveFunction | undefined) => FunctionInfo; } diff --git a/src/lib/canister_methods/heartbeat.ts b/src/lib/canister_methods/heartbeat.ts index 15ae3471f1..ae5ec61dda 100644 --- a/src/lib/canister_methods/heartbeat.ts +++ b/src/lib/canister_methods/heartbeat.ts @@ -1,30 +1,21 @@ import { CanisterMethodInfo, executeMethod, isAsync } from '.'; -import { Void } from '../candid/'; +import { Void } from '../candid/types/primitive/void'; export function heartbeat( callback: () => void | Promise ): CanisterMethodInfo<[], Void> { - return () => { + return (() => { const finalCallback = (...args: any[]) => { - executeMethod( - 'heartbeat', - undefined, - undefined, - args, - callback, - [], - Void, - false - ); + executeMethod('heartbeat', args, callback, [], Void, false, []); }; return { mode: 'heartbeat', callback: finalCallback, - paramsIdls: [], - returnIdl: Void, + paramCandidTypes: [], + returnCandidType: Void, async: isAsync(callback), guard: undefined - }; - }; + } as CanisterMethodInfo<[], Void>; + }) as any; } diff --git a/src/lib/canister_methods/index.ts b/src/lib/canister_methods/index.ts index a3483ffd4c..35ed2b7a55 100644 --- a/src/lib/canister_methods/index.ts +++ b/src/lib/canister_methods/index.ts @@ -1,9 +1,7 @@ import { AzleVoid } from '../candid/types/primitive/void'; -import { IDL } from '@dfinity/candid'; import { ic } from '../ic'; import { CandidType, TypeMapping, Parent } from '../candid'; -import { DecodeVisitor } from '../candid/serde/visitors/decode_visitor'; -import { EncodeVisitor } from '../candid/serde/visitors/encode_visitor'; +import { decodeMultiple, encode } from '../candid/serde'; export * from './heartbeat'; export * from './init'; @@ -30,8 +28,8 @@ export type CanisterMethodInfo, K> = { | 'preUpgrade'; async: boolean; callback?: (...args: any) => any; - paramsIdls: any[]; - returnIdl: any; + paramCandidTypes: any[]; + returnCandidType: any; guard: (() => any) | undefined; }; @@ -44,13 +42,12 @@ export type Callback< export function executeMethod( mode: CanisterMethodInfo['mode'], - finalParamIdls: any, - finalReturnIdl: any, args: any[], callback: any, - userMadeParamsIdls: any[], - userMadeReturnIdl: any, - manual: boolean + paramCandidTypes: CandidType[], + returnCandidType: CandidType, + manual: boolean, + parents: Parent[] ) { if (mode === 'heartbeat') { const result = callback(); @@ -73,16 +70,9 @@ export function executeMethod( return; } - const decoded = IDL.decode(finalParamIdls as any, args[0]); + const decodedArgs = decodeMultiple(paramCandidTypes, args[0], parents); - const myDecodedObject = finalParamIdls.map((idl: any, index: any) => { - return idl.accept(new DecodeVisitor(), { - js_class: userMadeParamsIdls[index], - js_data: decoded[index] - }); - }); - - const result = callback(...myDecodedObject); + const result = callback(...decodedArgs); if ( mode === 'init' || @@ -104,18 +94,7 @@ export function executeMethod( console.log(`final instructions: ${ic.instructionCounter()}`); if (!manual) { - // const encodeReadyResult = result === undefined ? [] : [result]; - const encodeReadyResult = finalReturnIdl.map((idl: any) => { - return idl.accept(new EncodeVisitor(), { - js_class: userMadeReturnIdl, - js_data: result - }); - }); - const encoded = IDL.encode( - finalReturnIdl as any, - encodeReadyResult - ); - ic.replyRaw(new Uint8Array(encoded)); + ic.replyRaw(encode(returnCandidType, result, parents)); } }) .catch((error: any) => { @@ -123,19 +102,7 @@ export function executeMethod( }); } else { if (!manual) { - // const encodeReadyResult = result === undefined ? [] : [result]; - const encodeReadyResult = finalReturnIdl.map((idl: any) => { - return idl.accept(new EncodeVisitor(), { - js_class: userMadeReturnIdl, - js_data: result - }); - }); - - const encoded = IDL.encode( - finalReturnIdl as any, - encodeReadyResult - ); - ic.replyRaw(new Uint8Array(encoded)); + ic.replyRaw(encode(returnCandidType, result)); } console.log(`final instructions: ${ic.instructionCounter()}`); diff --git a/src/lib/canister_methods/init.ts b/src/lib/canister_methods/init.ts index 665dc43162..90a4a47da0 100644 --- a/src/lib/canister_methods/init.ts +++ b/src/lib/canister_methods/init.ts @@ -1,44 +1,39 @@ import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; import { CandidType, TypeMapping } from '../candid'; -import { Void, toParamIDLTypes, toReturnIDLType } from '../'; +import { Void } from '../candid/types/primitive/void'; export function init< const Params extends ReadonlyArray, GenericCallback extends Callback >( - paramsIdls: Params, + paramCandidTypes: Params, callback?: Awaited> extends TypeMapping ? GenericCallback : never ): CanisterMethodInfo { - return (parent: any) => { - const parents = createParents(parent); - const paramCandid = toParamIDLTypes(paramsIdls as any, parents); - const returnCandid = toReturnIDLType(Void as any, parents); - + return ((parent: any) => { const finalCallback = callback === undefined ? undefined : (...args: any[]) => { executeMethod( 'init', - paramCandid, - returnCandid, args, callback, - paramsIdls as any, + paramCandidTypes as unknown as CandidType[], Void, - false + false, + createParents(parent) ); }; return { mode: 'init', callback: finalCallback, - paramsIdls: paramsIdls as any, - returnIdl: Void, + paramCandidTypes: paramCandidTypes as any, + returnCandidType: Void, async: false, guard: undefined - }; - }; + } as CanisterMethodInfo; + }) as any; } diff --git a/src/lib/canister_methods/inspect_message.ts b/src/lib/canister_methods/inspect_message.ts index c1c174ae01..a90833e79f 100644 --- a/src/lib/canister_methods/inspect_message.ts +++ b/src/lib/canister_methods/inspect_message.ts @@ -1,35 +1,29 @@ -import { CanisterMethodInfo, createParents, executeMethod } from '.'; -import { Void, toParamIDLTypes, toReturnIDLType } from '../candid/'; +import { CanisterMethodInfo, executeMethod } from '.'; +import { Void } from '../candid/types/primitive/void'; export function inspectMessage( callback: () => void | Promise ): CanisterMethodInfo<[], Void> { - return (parent: any) => { - const parents = createParents(parent); - // TODO why are we doing this handle recursive params when there are none? - const paramCandid = toParamIDLTypes([], parents); - const returnCandid = toReturnIDLType(Void as any, parents); - + return (() => { const finalCallback = (...args: any[]) => { executeMethod( 'inspectMessage', - paramCandid, - returnCandid, args, callback, [], Void, - false + false, + [] ); }; return { mode: 'inspectMessage', callback: finalCallback, - paramsIdls: [], - returnIdl: Void, + paramCandidTypes: [], + returnCandidType: Void, async: false, guard: undefined - }; - }; + } as CanisterMethodInfo<[], Void>; + }) as any; } diff --git a/src/lib/canister_methods/post_upgrade.ts b/src/lib/canister_methods/post_upgrade.ts index d644fd85b3..4b34b622e2 100644 --- a/src/lib/canister_methods/post_upgrade.ts +++ b/src/lib/canister_methods/post_upgrade.ts @@ -1,49 +1,39 @@ import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; -import { - CandidType, - TypeMapping, - Void, - toParamIDLTypes, - toReturnIDLType -} from '../candid'; +import { CandidType, TypeMapping } from '../candid'; +import { Void } from '../candid/types/primitive/void'; export function postUpgrade< const Params extends ReadonlyArray, GenericCallback extends Callback >( - paramsIdls: Params, + paramCandidTypes: Params, callback?: Awaited> extends TypeMapping ? GenericCallback : never ): CanisterMethodInfo { - return (parent: any) => { - const parents = createParents(parent); - const paramCandid = toParamIDLTypes(paramsIdls as any, parents); - const returnCandid = toReturnIDLType(Void as any, parents); - + return ((parent: any) => { const finalCallback = callback === undefined ? undefined : (...args: any[]) => { executeMethod( 'postUpgrade', - paramCandid, - returnCandid, args, callback, - paramsIdls as any, + paramCandidTypes as unknown as CandidType[], Void, - false + false, + createParents(parent) ); }; return { mode: 'postUpgrade', callback: finalCallback, - paramsIdls: paramsIdls as any, - returnIdl: Void, + paramCandidTypes: paramCandidTypes as unknown as CandidType[], + returnCandidType: Void, async: false, guard: undefined - }; - }; + } as CanisterMethodInfo; + }) as any; } diff --git a/src/lib/canister_methods/pre_upgrade.ts b/src/lib/canister_methods/pre_upgrade.ts index 52140811e7..6ffa18fe95 100644 --- a/src/lib/canister_methods/pre_upgrade.ts +++ b/src/lib/canister_methods/pre_upgrade.ts @@ -1,30 +1,21 @@ import { CanisterMethodInfo, executeMethod, isAsync } from '.'; -import { Void } from '../candid'; +import { Void } from '../candid/types/primitive/void'; export function preUpgrade( callback: () => void | Promise ): CanisterMethodInfo<[], Void> { - return () => { + return (() => { const finalCallback = (...args: any[]) => { - executeMethod( - 'preUpgrade', - undefined, - undefined, - args, - callback, - [], - Void, - false - ); + executeMethod('preUpgrade', args, callback, [], Void, false, []); }; return { mode: 'preUpgrade', callback: finalCallback, - paramsIdls: [], - returnIdl: Void, + paramCandidTypes: [], + returnCandidType: Void, async: isAsync(callback), guard: undefined - }; - }; + } as CanisterMethodInfo<[], Void>; + }) as any; } diff --git a/src/lib/canister_methods/query.ts b/src/lib/canister_methods/query.ts index b598ae089c..d9a7947aac 100644 --- a/src/lib/canister_methods/query.ts +++ b/src/lib/canister_methods/query.ts @@ -6,30 +6,21 @@ import { executeMethod, isAsync } from '.'; -import { - CandidType, - TypeMapping, - toParamIDLTypes, - toReturnIDLType -} from '../candid'; +import { CandidType, TypeMapping } from '../candid'; export function query< const Params extends ReadonlyArray, Return extends CandidType, GenericCallback extends Callback >( - paramsIdls: Params, - returnIdl: Return, + paramCandidTypes: Params, + returnCandidType: Return, callback?: Awaited> extends TypeMapping ? GenericCallback : never, methodArgs?: MethodArgs ): CanisterMethodInfo { - return (parent: any) => { - const parents = createParents(parent); - const paramCandid = toParamIDLTypes(paramsIdls as any, parents); - const returnCandid = toReturnIDLType(returnIdl as any, parents); - + return ((parent: any) => { // TODO maybe the cross canister callback should be made here? const finalCallback = callback === undefined @@ -37,23 +28,22 @@ export function query< : (...args: any[]) => { executeMethod( 'query', - paramCandid, - returnCandid, args, callback, - paramsIdls as any, - returnIdl, - methodArgs?.manual ?? false + paramCandidTypes as unknown as CandidType[], + returnCandidType, + methodArgs?.manual ?? false, + createParents(parent) ); }; return { mode: 'query', callback: finalCallback, - paramsIdls: paramsIdls as any, - returnIdl, + paramCandidTypes: paramCandidTypes as unknown as CandidType[], + returnCandidType, async: callback === undefined ? false : isAsync(callback), guard: methodArgs?.guard - }; - }; + } as CanisterMethodInfo; + }) as any; } diff --git a/src/lib/canister_methods/update.ts b/src/lib/canister_methods/update.ts index 7225598857..d02d74729b 100644 --- a/src/lib/canister_methods/update.ts +++ b/src/lib/canister_methods/update.ts @@ -6,12 +6,7 @@ import { executeMethod, isAsync } from '.'; -import { - CandidType, - TypeMapping, - toParamIDLTypes, - toReturnIDLType -} from '../candid'; +import { CandidType, TypeMapping } from '../candid'; export function update< const Params extends ReadonlyArray, @@ -25,34 +20,29 @@ export function update< : never, methodArgs?: MethodArgs ): CanisterMethodInfo { - return (parent: any) => { - const parents = createParents(parent); - const paramIdls = toParamIDLTypes(paramCandidTypes as any, parents); - const returnIdls = toReturnIDLType(returnCandidType as any, parents); - + return ((parent: any) => { const finalCallback = callback === undefined ? undefined : (...args: any[]) => { executeMethod( 'update', - paramIdls, - returnIdls, args, callback, - paramCandidTypes as any, + paramCandidTypes as unknown as CandidType[], returnCandidType, - methodArgs?.manual ?? false + methodArgs?.manual ?? false, + createParents(parent) ); }; return { mode: 'update', callback: finalCallback, - paramsIdls: paramCandidTypes as any, - returnIdl: returnCandidType, + paramCandidTypes: paramCandidTypes as unknown as CandidType[], + returnCandidType, async: callback === undefined ? false : isAsync(callback), guard: methodArgs?.guard - }; - }; + } as CanisterMethodInfo; + }) as any; } diff --git a/src/lib/globals.ts b/src/lib/globals.ts index 9c19760a0a..cb89ddc31e 100644 --- a/src/lib/globals.ts +++ b/src/lib/globals.ts @@ -1,25 +1,39 @@ import { ic } from './ic'; +import { AzleIc } from './ic/types/azle_ic'; import { Buffer } from 'buffer'; -export declare var globalThis: { - _azleCandidInitParams: any[]; - _azleCandidMethods: any[]; - _azleCandidTypes: any[]; - Buffer: BufferConstructor; - console: any; - crypto: { - getRandomValues: () => Uint8Array; - }; - icTimers: { +declare global { + var _azleIc: AzleIc; + var _azleResolveIds: { [key: string]: (buf: ArrayBuffer) => void }; + var _azleRejectIds: { [key: string]: (err: any) => void }; + var icTimers: { [key: string]: string }; + var _azleTimerCallbackIds: { [key: string]: () => void }; + var Buffer: BufferConstructor; + // var console: Console; + // var crypto: Crypto; + var icTimers: { [key: string]: string; }; - TextDecoder: any; - TextEncoder: any; -}; + // var TextDecoder: any; + // var TextEncoder: any; +} + +// export declare var globalThis: { +// Buffer: BufferConstructor; +// console: any; +// crypto: { +// getRandomValues: () => Uint8Array; +// }; +// TextDecoder: any; +// TextEncoder: any; +// }; globalThis.TextDecoder = require('text-encoding').TextDecoder; globalThis.TextEncoder = require('text-encoding').TextEncoder; globalThis.icTimers ||= {}; +globalThis._azleResolveIds = {}; +globalThis._azleRejectIds = {}; +globalThis._azleTimerCallbackIds = {}; globalThis.console = { ...globalThis.console, @@ -31,7 +45,8 @@ globalThis.console = { // TODO be careful we are using a random seed of 0 I think // TODO the randomness is predictable globalThis.crypto = { - getRandomValues: () => { + ...globalThis.crypto, + getRandomValues: (() => { let array = new Uint8Array(32); for (let i = 0; i < array.length; i++) { @@ -39,7 +54,7 @@ globalThis.crypto = { } return array; - } + }) as any }; globalThis.Buffer = Buffer; diff --git a/src/lib/ic/accept_message.ts b/src/lib/ic/accept_message.ts index dad0cc6aea..e503d49180 100644 --- a/src/lib/ic/accept_message.ts +++ b/src/lib/ic/accept_message.ts @@ -4,4 +4,6 @@ import { Void } from '../candid/types/primitive/void'; * Accepts the ingress message. Calling from outside the * {@link $inspectMessage} context will cause the canister to trap. */ -export const acceptMessage = () => Void; +export function acceptMessage(): Void { + return globalThis._azleIc ? globalThis._azleIc.acceptMessage() : undefined; +} diff --git a/src/lib/ic/arg_data_raw.ts b/src/lib/ic/arg_data_raw.ts index a26da132ae..bd356b77ff 100644 --- a/src/lib/ic/arg_data_raw.ts +++ b/src/lib/ic/arg_data_raw.ts @@ -5,5 +5,7 @@ import { blob } from '../candid/types/constructed/blob'; * @returns the argument data */ export function argDataRaw(): blob { - return new Uint8Array(globalThis._azleIc.argDataRaw()); + return globalThis._azleIc + ? new Uint8Array(globalThis._azleIc.argDataRaw()) + : (undefined as any); } diff --git a/src/lib/ic/arg_data_raw_size.ts b/src/lib/ic/arg_data_raw_size.ts index b98a22854f..103cfef538 100644 --- a/src/lib/ic/arg_data_raw_size.ts +++ b/src/lib/ic/arg_data_raw_size.ts @@ -1,7 +1,11 @@ -import { nat } from '../candid/types/primitive/nats/nat'; +import { nat32 } from '../candid/types/primitive/nats/nat32'; /** * Gets the length of the raw-argument-data-bytes * @returns the data size */ -export const argDataRawSize = () => nat; +export function argDataRawSize(): nat32 { + return globalThis._azleIc + ? globalThis._azleIc.argDataRawSize() + : (undefined as any); +} diff --git a/src/lib/ic/call.ts b/src/lib/ic/call.ts index e036667026..04a53a3951 100644 --- a/src/lib/ic/call.ts +++ b/src/lib/ic/call.ts @@ -19,8 +19,12 @@ export function call any>( cycles?: nat64; } ): ReturnTypeOf { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + // TODO probably get rid of .crossCanisterCallback - return method.crossCanisterCallback( + return (method as any).crossCanisterCallback( '_AZLE_CROSS_CANISTER_CALL', false, callRaw, diff --git a/src/lib/ic/call128.ts b/src/lib/ic/call128.ts index c2d0a1c419..a2bd65eb78 100644 --- a/src/lib/ic/call128.ts +++ b/src/lib/ic/call128.ts @@ -19,7 +19,11 @@ export function call128 any>( cycles?: nat; } ): ReturnTypeOf { - return method.crossCanisterCallback( + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + return (method as any).crossCanisterCallback( '_AZLE_CROSS_CANISTER_CALL', false, callRaw128, diff --git a/src/lib/ic/call_raw.ts b/src/lib/ic/call_raw.ts index 81bf6152a1..7ae3f575e4 100644 --- a/src/lib/ic/call_raw.ts +++ b/src/lib/ic/call_raw.ts @@ -4,6 +4,7 @@ import { blob } from '../candid/types/constructed/blob'; import { nat64 } from '../candid/types/primitive/nats/nat64'; import { v4 } from 'uuid'; import { text } from '../candid/types/primitive/text'; +import { encode } from '../candid/serde'; /** * Performs an asynchronous call to another canister using the [System API]( @@ -21,6 +22,10 @@ export function callRaw( argsRaw: blob, payment: nat64 ): Promise { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + // TODO this should use a Result remember return new Promise((resolve, reject) => { const promiseId = v4(); @@ -30,25 +35,23 @@ export function callRaw( // TODO perhaps we should be more robust // TODO for example, we can keep the time with these // TODO if they are over a certain amount old we can delete them - globalThis[globalResolveId] = (bytes: ArrayBuffer) => { + globalThis._azleResolveIds[globalResolveId] = (bytes: ArrayBuffer) => { resolve(new Uint8Array(bytes)); - delete globalThis[globalResolveId]; - delete globalThis[globalRejectId]; + delete globalThis._azleResolveIds[globalResolveId]; + delete globalThis._azleRejectIds[globalRejectId]; }; - globalThis[globalRejectId] = (error: any) => { + globalThis._azleRejectIds[globalRejectId] = (error: any) => { reject(error); - delete globalThis[globalResolveId]; - delete globalThis[globalRejectId]; + delete globalThis._azleResolveIds[globalResolveId]; + delete globalThis._azleRejectIds[globalRejectId]; }; const canisterIdBytes = canisterId.toUint8Array().buffer; const argsRawBuffer = argsRaw.buffer; - const paymentCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat64], [payment]) - ).buffer; + const paymentCandidBytes = encode(nat64, payment).buffer; // TODO consider finally, what if deletion goes wrong try { @@ -60,8 +63,8 @@ export function callRaw( paymentCandidBytes ); } catch (error) { - delete globalThis[globalResolveId]; - delete globalThis[globalRejectId]; + delete globalThis._azleResolveIds[globalResolveId]; + delete globalThis._azleRejectIds[globalRejectId]; throw error; } }); diff --git a/src/lib/ic/call_raw_128.ts b/src/lib/ic/call_raw_128.ts index 19d3257c8e..b1c6ea90e3 100644 --- a/src/lib/ic/call_raw_128.ts +++ b/src/lib/ic/call_raw_128.ts @@ -4,6 +4,7 @@ import { blob } from '../candid/types/constructed/blob'; import { nat } from '../candid/types/primitive/nats/nat'; import { v4 } from 'uuid'; import { text } from '../candid/types/primitive/text'; +import { encode } from '../candid/serde'; /** * Performs an asynchronous call to another canister using the [System API]( @@ -21,6 +22,10 @@ export function callRaw128( argsRaw: blob, payment: nat ): Promise { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + // TODO this should use a Result remember return new Promise((resolve, reject) => { const promiseId = v4(); @@ -30,25 +35,23 @@ export function callRaw128( // TODO perhaps we should be more robust // TODO for example, we can keep the time with these // TODO if they are over a certain amount old we can delete them - globalThis[globalResolveId] = (bytes: ArrayBuffer) => { + globalThis._azleResolveIds[globalResolveId] = (bytes: ArrayBuffer) => { resolve(new Uint8Array(bytes)); - delete globalThis[globalResolveId]; - delete globalThis[globalRejectId]; + delete globalThis._azleResolveIds[globalResolveId]; + delete globalThis._azleRejectIds[globalRejectId]; }; - globalThis[globalRejectId] = (error: any) => { + globalThis._azleRejectIds[globalRejectId] = (error: any) => { reject(error); - delete globalThis[globalResolveId]; - delete globalThis[globalRejectId]; + delete globalThis._azleResolveIds[globalResolveId]; + delete globalThis._azleRejectIds[globalRejectId]; }; const canisterIdBytes = canisterId.toUint8Array().buffer; const argsRawBuffer = argsRaw.buffer; - const paymentCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat], [payment]) - ).buffer; + const paymentCandidBytes = encode(nat, payment).buffer; // TODO consider finally, what if deletion goes wrong try { @@ -60,8 +63,8 @@ export function callRaw128( paymentCandidBytes ); } catch (error) { - delete globalThis[globalResolveId]; - delete globalThis[globalRejectId]; + delete globalThis._azleResolveIds[globalResolveId]; + delete globalThis._azleRejectIds[globalRejectId]; throw error; } }); diff --git a/src/lib/ic/caller.ts b/src/lib/ic/caller.ts index 97543dea94..3d8d847f86 100644 --- a/src/lib/ic/caller.ts +++ b/src/lib/ic/caller.ts @@ -5,6 +5,10 @@ import { Principal } from '../candid/types/reference/principal'; * @returns the caller of the current call */ export function caller(): Principal { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const callerBytes = globalThis._azleIc.caller(); return Principal.fromUint8Array(new Uint8Array(callerBytes)); } diff --git a/src/lib/ic/candid_decode.ts b/src/lib/ic/candid_decode.ts index 91a8881676..bc0b35d4bc 100644 --- a/src/lib/ic/candid_decode.ts +++ b/src/lib/ic/candid_decode.ts @@ -7,5 +7,9 @@ import { text } from '../candid/types/primitive/text'; * @returns the Candid string */ export function candidDecode(candidEncoded: blob): text { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + return globalThis._azleIc.candidDecode(candidEncoded.buffer); } diff --git a/src/lib/ic/candid_encode.ts b/src/lib/ic/candid_encode.ts index 9082a9e29c..f60c086986 100644 --- a/src/lib/ic/candid_encode.ts +++ b/src/lib/ic/candid_encode.ts @@ -7,5 +7,9 @@ import { text } from '../candid/types/primitive/text'; * @returns the candid value as bytes */ export function candidEncode(candidString: text): blob { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + return new Uint8Array(globalThis._azleIc.candidEncode(candidString)); } diff --git a/src/lib/ic/canister_balance.ts b/src/lib/ic/canister_balance.ts index ca83658e91..5e59b98868 100644 --- a/src/lib/ic/canister_balance.ts +++ b/src/lib/ic/canister_balance.ts @@ -1,13 +1,15 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode } from '../candid/serde'; /** * Gets the amount of funds available in the canister * @returns the number of cycles in the canister */ export function canisterBalance(): nat64 { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const canisterBalanceCandidBytes = globalThis._azleIc.canisterBalance(); - return BigInt( - IDL.decode([IDL.Nat64], canisterBalanceCandidBytes)[0] as number - ); + return BigInt(decode(nat64, canisterBalanceCandidBytes) as number); } diff --git a/src/lib/ic/canister_balance_128.ts b/src/lib/ic/canister_balance_128.ts index 5b69388081..e74483aed3 100644 --- a/src/lib/ic/canister_balance_128.ts +++ b/src/lib/ic/canister_balance_128.ts @@ -1,14 +1,16 @@ -import { IDL } from '@dfinity/candid'; import { nat } from '../candid/types/primitive/nats/nat'; +import { decode } from '../candid/serde'; /** * Gets the amount of funds available in the canister * @returns the number of cycles in the canister */ export function canisterBalance128(): nat { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const canisterBalance128CandidBytes = globalThis._azleIc.canisterBalance128(); - return BigInt( - IDL.decode([IDL.Nat], canisterBalance128CandidBytes)[0] as number - ); + return BigInt(decode(nat, canisterBalance128CandidBytes) as number); } diff --git a/src/lib/ic/canister_version.ts b/src/lib/ic/canister_version.ts index 8a09cc45db..fdeea1116f 100644 --- a/src/lib/ic/canister_version.ts +++ b/src/lib/ic/canister_version.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode } from '../candid/serde'; /** * Returns the canister version number @@ -7,8 +7,10 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the version number */ export function canisterVersion(): nat64 { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const canisterVersionCandidBytes = globalThis._azleIc.canisterVersion(); - return BigInt( - IDL.decode([IDL.Nat64], canisterVersionCandidBytes)[0] as number - ); + return BigInt(decode(nat64, canisterVersionCandidBytes) as number); } diff --git a/src/lib/ic/clear_timer.ts b/src/lib/ic/clear_timer.ts index f6b937200e..475abe858a 100644 --- a/src/lib/ic/clear_timer.ts +++ b/src/lib/ic/clear_timer.ts @@ -1,20 +1,21 @@ import { IDL } from '@dfinity/candid'; import { Void } from '../candid/types/primitive/void'; import { TimerId } from './types'; +import { encode } from '../candid/serde'; /** * Cancels an existing timer. Does nothing if the timer has already been canceled. * @param id The ID of the timer to be cancelled. */ export function clearTimer(timerId: TimerId): Void { - const encode = (value: TimerId) => { - return new Uint8Array(IDL.encode([IDL.Nat64], [value])).buffer; - }; + if (globalThis._azleIc === undefined) { + return undefined as any; + } - globalThis._azleIc.clearTimer(encode(timerId)); + globalThis._azleIc.clearTimer(encode(TimerId, timerId).buffer); const timerCallbackId = globalThis.icTimers[timerId.toString()]; delete globalThis.icTimers[timerId.toString()]; - delete globalThis[timerCallbackId]; + delete globalThis._azleTimerCallbackIds[timerCallbackId]; } diff --git a/src/lib/ic/data_certificate.ts b/src/lib/ic/data_certificate.ts index 1e27904962..7ea0ee212f 100644 --- a/src/lib/ic/data_certificate.ts +++ b/src/lib/ic/data_certificate.ts @@ -8,8 +8,11 @@ import { None, Opt, Some } from '../candid/types/constructed/opt'; * @returns the data certificate or None */ export function dataCertificate(): Opt { - const rawRustValue: ArrayBuffer | undefined = - globalThis._azleIc.dataCertificate(); + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const rawRustValue = globalThis._azleIc.dataCertificate(); return rawRustValue === undefined ? None diff --git a/src/lib/ic/id.ts b/src/lib/ic/id.ts index 5d84916601..99b5b0e370 100644 --- a/src/lib/ic/id.ts +++ b/src/lib/ic/id.ts @@ -5,6 +5,10 @@ import { Principal } from '../candid/types/reference/principal'; * @returns the canister id */ export function id() { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + // TODO consider bytes instead of string, just like with caller const idString = globalThis._azleIc.id(); return Principal.fromText(idString); diff --git a/src/lib/ic/index.ts b/src/lib/ic/index.ts index 38e747eefb..672d916854 100644 --- a/src/lib/ic/index.ts +++ b/src/lib/ic/index.ts @@ -50,142 +50,54 @@ import { trap } from './trap'; export * from './types'; -type Ic = { - acceptMessage: typeof acceptMessage; - argDataRaw: typeof argDataRaw; - argDataRawSize: typeof argDataRawSize; - call: typeof call; - call128: typeof call128; - callRaw: typeof callRaw; - callRaw128: typeof callRaw128; - caller: typeof caller; - candidDecode: typeof candidDecode; - candidEncode: typeof candidEncode; - canisterBalance: typeof canisterBalance; - canisterBalance128: typeof canisterBalance128; - canisterVersion: typeof canisterVersion; - clearTimer: typeof clearTimer; - dataCertificate: typeof dataCertificate; - id: typeof id; - instructionCounter: typeof instructionCounter; - isController: typeof isController; - methodName: typeof methodName; - msgCyclesAccept: typeof msgCyclesAccept; - msgCyclesAccept128: typeof msgCyclesAccept; - msgCyclesAvailable: typeof msgCyclesAvailable; - msgCyclesAvailable128: typeof msgCyclesAvailable128; - msgCyclesRefunded: typeof msgCyclesRefunded; - msgCyclesRefunded128: typeof msgCyclesRefunded128; - notify: typeof notify; - notifyRaw: typeof notifyRaw; - performanceCounter: typeof performanceCounter; - print: typeof print; - reject: typeof reject; - rejectCode: typeof rejectCode; - rejectMessage: typeof rejectMessage; - reply: typeof reply; - replyRaw: typeof replyRaw; - setCertifiedData: typeof setCertifiedData; - setTimer: typeof setTimer; - setTimerInterval: typeof setTimerInterval; - stableBytes: typeof stableBytes; - stableGrow: typeof stableGrow; - stableRead: typeof stableRead; - stableSize: typeof stableSize; - stableWrite: typeof stableWrite; - stable64Grow: typeof stable64Grow; - stable64Read: typeof stable64Read; - stable64Size: typeof stable64Size; - stable64Write: typeof stable64Write; - time: typeof time; - trap: typeof trap; -}; - /** API entrypoint for interacting with the Internet Computer */ -export const ic: Ic = globalThis._azleIc - ? { - ...globalThis._azleIc, - argDataRaw, - call, - call128, - callRaw, - callRaw128, - caller, - candidDecode, - candidEncode, - canisterBalance, - canisterBalance128, - canisterVersion, - clearTimer, - dataCertificate, - id, - instructionCounter, - isController, - msgCyclesAccept, - msgCyclesAccept128, - msgCyclesAvailable, - msgCyclesAvailable128, - msgCyclesRefunded, - msgCyclesRefunded128, - notify, - notifyRaw, - performanceCounter, - rejectCode, - reply, - replyRaw, - setCertifiedData, - setTimer, - setTimerInterval, - stableBytes, - stableGrow, - stableRead, - stableSize, - stableWrite, - stable64Grow, - stable64Read, - stable64Size, - stable64Write, - time - } - : { - acceptMessage: () => {}, - argDataRaw: () => {}, - argDataRawSize: () => {}, - callRaw: () => {}, - caller: () => {}, - candidDecode: () => {}, - candidEncode: () => {}, - canisterBalance: () => {}, - canisterBalance128: () => {}, - canisterVersion: () => {}, - clearTimer: () => {}, - id: () => {}, - instructionCounter: () => {}, - isController: () => {}, - methodName: () => {}, - msgCyclesAccept: () => {}, - msgCyclesAccept128: () => {}, - msgCyclesAvailable: () => {}, - msgCyclesAvailable128: () => {}, - msgCyclesRefunded: () => {}, - msgCyclesRefunded128: () => {}, - performanceCounter: () => {}, - print: () => {}, - reject: () => {}, - rejectCode: () => {}, - rejectMessage: () => {}, - reply: () => {}, - replyRaw: () => {}, - setCertifiedData: () => {}, - stableBytes: () => {}, - stableGrow: () => {}, - stableRead: () => {}, - stableSize: () => {}, - stableWrite: () => {}, - stable64Grow: () => {}, - stable64Read: () => {}, - stable64Size: () => {}, - stable64Write: () => {}, - time: () => {}, - trap: () => {} - }; +export const ic = { + acceptMessage, + argDataRawSize, + argDataRaw, + call, + call128, + callRaw, + callRaw128, + caller, + candidDecode, + candidEncode, + canisterBalance, + canisterBalance128, + canisterVersion, + clearTimer, + dataCertificate, + id, + instructionCounter, + isController, + methodName, + msgCyclesAccept, + msgCyclesAccept128, + msgCyclesAvailable, + msgCyclesAvailable128, + msgCyclesRefunded, + msgCyclesRefunded128, + notify, + notifyRaw, + performanceCounter, + print, + reject, + rejectCode, + rejectMessage, + reply, + replyRaw, + setCertifiedData, + setTimer, + setTimerInterval, + stableBytes, + stableGrow, + stableRead, + stableSize, + stableWrite, + stable64Grow, + stable64Read, + stable64Size, + stable64Write, + time, + trap +}; diff --git a/src/lib/ic/instruction_counter.ts b/src/lib/ic/instruction_counter.ts index c46730a383..366774132a 100644 --- a/src/lib/ic/instruction_counter.ts +++ b/src/lib/ic/instruction_counter.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode } from '../candid/serde'; /** * Returns the number of instructions that the canister executed since the @@ -10,9 +10,11 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the number of instructions */ export function instructionCounter(): nat64 { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const instructionCounterCandidBytes = globalThis._azleIc.instructionCounter(); - return BigInt( - IDL.decode([IDL.Nat64], instructionCounterCandidBytes)[0] as number - ); + return BigInt(decode(nat64, instructionCounterCandidBytes) as number); } diff --git a/src/lib/ic/is_controller.ts b/src/lib/ic/is_controller.ts index 597bb671f2..ab7da249d3 100644 --- a/src/lib/ic/is_controller.ts +++ b/src/lib/ic/is_controller.ts @@ -3,5 +3,9 @@ import { bool } from '../candid/types/primitive/bool'; /** Determine if a {@link Principal} is a controller of the canister. */ export function isController(principal: Principal): bool { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + return globalThis._azleIc.isController(principal.toUint8Array().buffer); } diff --git a/src/lib/ic/method_name.ts b/src/lib/ic/method_name.ts index f38248af45..52ef9d39b4 100644 --- a/src/lib/ic/method_name.ts +++ b/src/lib/ic/method_name.ts @@ -4,4 +4,8 @@ import { text } from '../candid/types/primitive/text'; * Returns the name of the current canister methods * @returns the current canister method */ -export const methodName = () => text; +export function methodName(): text { + return globalThis._azleIc + ? globalThis._azleIc.methodName() + : (undefined as any); +} diff --git a/src/lib/ic/msg_cycles_accept.ts b/src/lib/ic/msg_cycles_accept.ts index ac6dfbdb0c..0964133d27 100644 --- a/src/lib/ic/msg_cycles_accept.ts +++ b/src/lib/ic/msg_cycles_accept.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode, encode } from '../candid/serde'; /** * Moves cycles from the call to the canister balance @@ -7,14 +7,14 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the actual amount moved */ export function msgCyclesAccept(maxAmount: nat64): nat64 { - const maxAmountCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat64], [maxAmount]) - ).buffer; + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const maxAmountCandidBytes = encode(nat64, maxAmount).buffer; const msgCyclesAcceptCandidBytes = globalThis._azleIc.msgCyclesAccept(maxAmountCandidBytes); - return BigInt( - IDL.decode([IDL.Nat64], msgCyclesAcceptCandidBytes)[0] as number - ); + return BigInt(decode(nat64, msgCyclesAcceptCandidBytes) as number); } diff --git a/src/lib/ic/msg_cycles_accept_128.ts b/src/lib/ic/msg_cycles_accept_128.ts index 172764ef0d..c7365d29b4 100644 --- a/src/lib/ic/msg_cycles_accept_128.ts +++ b/src/lib/ic/msg_cycles_accept_128.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat } from '../candid/types/primitive/nats/nat'; +import { decode, encode } from '../candid/serde'; /** * Moves cycles from the call to the canister balance @@ -7,14 +7,14 @@ import { nat } from '../candid/types/primitive/nats/nat'; * @returns the actual amount moved */ export function msgCyclesAccept128(maxAmount: nat): nat { - const maxAmountCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat], [maxAmount]) - ).buffer; + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const maxAmountCandidBytes = encode(nat, maxAmount).buffer; const msgCyclesAccept128CandidBytes = globalThis._azleIc.msgCyclesAccept128(maxAmountCandidBytes); - return BigInt( - IDL.decode([IDL.Nat], msgCyclesAccept128CandidBytes)[0] as number - ); + return BigInt(decode(nat, msgCyclesAccept128CandidBytes) as number); } diff --git a/src/lib/ic/msg_cycles_available.ts b/src/lib/ic/msg_cycles_available.ts index b1c8dcb986..c2e9a20275 100644 --- a/src/lib/ic/msg_cycles_available.ts +++ b/src/lib/ic/msg_cycles_available.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode } from '../candid/serde'; /** * Returns the amount of cycles that were transferred by the caller of the @@ -7,10 +7,12 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the amount of cycles */ export function msgCyclesAvailable(): nat64 { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const msgCyclesAvailableCandidBytes = globalThis._azleIc.msgCyclesAvailable(); - return BigInt( - IDL.decode([IDL.Nat64], msgCyclesAvailableCandidBytes)[0] as number - ); + return BigInt(decode(nat64, msgCyclesAvailableCandidBytes) as number); } diff --git a/src/lib/ic/msg_cycles_available_128.ts b/src/lib/ic/msg_cycles_available_128.ts index 90e878cbc5..f5e223f721 100644 --- a/src/lib/ic/msg_cycles_available_128.ts +++ b/src/lib/ic/msg_cycles_available_128.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat } from '../candid/types/primitive/nats/nat'; +import { decode } from '../candid/serde'; /** * Returns the amount of cycles that were transferred by the caller of the @@ -7,10 +7,12 @@ import { nat } from '../candid/types/primitive/nats/nat'; * @returns the amount of cycles */ export function msgCyclesAvailable128(): nat { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const msgCyclesAvailable128CandidBytes = globalThis._azleIc.msgCyclesAvailable128(); - return BigInt( - IDL.decode([IDL.Nat], msgCyclesAvailable128CandidBytes)[0] as number - ); + return BigInt(decode(nat, msgCyclesAvailable128CandidBytes) as number); } diff --git a/src/lib/ic/msg_cycles_refunded.ts b/src/lib/ic/msg_cycles_refunded.ts index 3bdc841680..65ebfcf442 100644 --- a/src/lib/ic/msg_cycles_refunded.ts +++ b/src/lib/ic/msg_cycles_refunded.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode } from '../candid/serde'; /** * Returns the amount of cycles that came back with the response as a refund. @@ -7,9 +7,11 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the amount of cycles */ export function msgCyclesRefunded(): nat64 { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const msgCyclesRefundedCandidBytes = globalThis._azleIc.msgCyclesRefunded(); - return BigInt( - IDL.decode([IDL.Nat64], msgCyclesRefundedCandidBytes)[0] as number - ); + return BigInt(decode(nat64, msgCyclesRefundedCandidBytes) as number); } diff --git a/src/lib/ic/msg_cycles_refunded_128.ts b/src/lib/ic/msg_cycles_refunded_128.ts index 839d88dd8e..c8afc15865 100644 --- a/src/lib/ic/msg_cycles_refunded_128.ts +++ b/src/lib/ic/msg_cycles_refunded_128.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat } from '../candid/types/primitive/nats/nat'; +import { decode } from '../candid/serde'; /** * Returns the amount of cycles that came back with the response as a refund. @@ -7,10 +7,12 @@ import { nat } from '../candid/types/primitive/nats/nat'; * @returns the amount of cycles */ export function msgCyclesRefunded128(): nat { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const msgCyclesRefunded128CandidBytes = globalThis._azleIc.msgCyclesRefunded128(); - return BigInt( - IDL.decode([IDL.Nat], msgCyclesRefunded128CandidBytes)[0] as number - ); + return BigInt(decode(nat, msgCyclesRefunded128CandidBytes) as number); } diff --git a/src/lib/ic/notify.ts b/src/lib/ic/notify.ts index 18be210fc2..245939fcd7 100644 --- a/src/lib/ic/notify.ts +++ b/src/lib/ic/notify.ts @@ -39,7 +39,11 @@ export function notify any>( cycles?: nat; } ): Void { - return method.crossCanisterCallback( + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + return (method as any).crossCanisterCallback( '_AZLE_CROSS_CANISTER_CALL', true, notifyRaw, diff --git a/src/lib/ic/notify_raw.ts b/src/lib/ic/notify_raw.ts index 264df8c9a4..65615de609 100644 --- a/src/lib/ic/notify_raw.ts +++ b/src/lib/ic/notify_raw.ts @@ -1,8 +1,8 @@ -import { IDL } from '@dfinity/candid'; import { Void } from '../candid/types/primitive/void'; import { nat } from '../candid/types/primitive/nats/nat'; import { blob } from '../candid/types/constructed/blob'; import { Principal, text } from '../candid'; +import { encode } from '../candid/serde'; /** * Like notify, but sends the argument as raw bytes, skipping Candid serialization. @@ -18,10 +18,13 @@ export function notifyRaw( argsRaw: blob, payment: nat ): Void { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const canisterIdBytes = canisterId.toUint8Array().buffer; const argsRawBuffer = argsRaw.buffer; - const paymentCandidBytes = new Uint8Array(IDL.encode([IDL.Nat], [payment])) - .buffer; + const paymentCandidBytes = encode(nat, payment).buffer; return globalThis._azleIc.notifyRaw( canisterIdBytes, diff --git a/src/lib/ic/performance_counter.ts b/src/lib/ic/performance_counter.ts index 61418da01a..9955754361 100644 --- a/src/lib/ic/performance_counter.ts +++ b/src/lib/ic/performance_counter.ts @@ -1,6 +1,6 @@ -import { IDL } from '@dfinity/candid'; import { nat32 } from '../candid/types/primitive/nats/nat32'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode, encode } from '../candid/serde'; /** * Gets the value of the specified performance counter @@ -12,15 +12,15 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the performance counter metric */ export function performanceCounter(counterType: nat32): nat64 { - const counterTypeCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat32], [counterType]) - ).buffer; + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const counterTypeCandidBytes = encode(nat32, counterType).buffer; const performanceCounterCandidBytes = globalThis._azleIc.performanceCounter( counterTypeCandidBytes ); - return BigInt( - IDL.decode([IDL.Nat64], performanceCounterCandidBytes)[0] as number - ); + return BigInt(decode(nat64, performanceCounterCandidBytes) as number); } diff --git a/src/lib/ic/print.ts b/src/lib/ic/print.ts index a059ee0206..a88d9d8f19 100644 --- a/src/lib/ic/print.ts +++ b/src/lib/ic/print.ts @@ -4,4 +4,6 @@ import { Void } from '../candid/types/primitive/void'; * Prints the given message * @param args the message to print */ -export const print = (...args: any) => Void; +export function print(...args: any): Void { + return globalThis._azleIc ? globalThis._azleIc.print() : undefined; +} diff --git a/src/lib/ic/reject.ts b/src/lib/ic/reject.ts index b8a1e75d28..8b5bfa866e 100644 --- a/src/lib/ic/reject.ts +++ b/src/lib/ic/reject.ts @@ -5,4 +5,6 @@ import { Void } from '../candid/types/primitive/void'; * Rejects the current call with the provided message * @param message the rejection message */ -export const reject = (message: text) => Void; +export function reject(message: text): Void { + return globalThis._azleIc ? globalThis._azleIc.reject(message) : undefined; +} diff --git a/src/lib/ic/reject_code.ts b/src/lib/ic/reject_code.ts index d63398f35b..0e90b538cc 100644 --- a/src/lib/ic/reject_code.ts +++ b/src/lib/ic/reject_code.ts @@ -6,6 +6,10 @@ import { RejectionCode } from '../system_types'; * @returns the rejection code */ export function rejectCode(): typeof RejectionCode { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const rejectCodeNumber = globalThis._azleIc.rejectCode(); switch (rejectCodeNumber) { diff --git a/src/lib/ic/reject_message.ts b/src/lib/ic/reject_message.ts index ab572a53ac..c6cf9a097f 100644 --- a/src/lib/ic/reject_message.ts +++ b/src/lib/ic/reject_message.ts @@ -9,4 +9,8 @@ import { text } from '../candid/types/primitive/text'; * * @returns the rejection message */ -export const rejectMessage = () => text; +export function rejectMessage(): text { + return globalThis._azleIc + ? globalThis._azleIc.rejectMessage() + : (undefined as any); +} diff --git a/src/lib/ic/reply.ts b/src/lib/ic/reply.ts index 1026fe98d0..2c9873d33e 100644 --- a/src/lib/ic/reply.ts +++ b/src/lib/ic/reply.ts @@ -1,7 +1,6 @@ -import { IDL } from '@dfinity/candid'; -import { CandidType, toIDLType } from '../candid'; +import { CandidType } from '../candid'; import { Void } from '../candid/types/primitive/void'; -import { EncodeVisitor } from '../candid/serde/visitors/encode_visitor'; +import { encode } from '../candid/serde'; /** * Used to manually reply to an ingress message. Intended to be used in @@ -11,20 +10,9 @@ import { EncodeVisitor } from '../candid/serde/visitors/encode_visitor'; * uncaught `TypeError`. */ export function reply(data: any, type: CandidType): Void { - if (type.name === 'AzleVoid') { - // return type is void - const bytes = new Uint8Array(IDL.encode([], [])).buffer; - return globalThis._azleIc.replyRaw(bytes); + if (globalThis._azleIc === undefined) { + return undefined as any; } - const idlType = toIDLType(type, []); - - const encodeReadyResult = idlType.accept(new EncodeVisitor(), { - js_class: type, - js_data: data - }); - - const bytes = new Uint8Array(IDL.encode([idlType], [encodeReadyResult])) - .buffer; - return globalThis._azleIc.replyRaw(bytes); + return globalThis._azleIc.replyRaw(encode(type, data).buffer); } diff --git a/src/lib/ic/reply_raw.ts b/src/lib/ic/reply_raw.ts index 4d46e17e64..c3a0955b0a 100644 --- a/src/lib/ic/reply_raw.ts +++ b/src/lib/ic/reply_raw.ts @@ -19,5 +19,7 @@ import { blob } from '../candid/types/constructed/blob'; * ``` */ export function replyRaw(replyBuffer: blob): Void { - return globalThis._azleIc.replyRaw(replyBuffer.buffer); + return globalThis._azleIc + ? globalThis._azleIc.replyRaw(replyBuffer.buffer) + : undefined; } diff --git a/src/lib/ic/set_certified_data.ts b/src/lib/ic/set_certified_data.ts index d3fbdd0d14..2472fbc66d 100644 --- a/src/lib/ic/set_certified_data.ts +++ b/src/lib/ic/set_certified_data.ts @@ -1,6 +1,6 @@ -import { IDL } from '@dfinity/candid'; import { blob } from '../candid/types/constructed/blob'; import { Void } from '../candid/types/primitive/void'; +import { encode } from '../candid/serde'; /** * Sets the certified data of this canister. @@ -25,8 +25,11 @@ import { Void } from '../candid/types/primitive/void'; * @returns */ export function setCertifiedData(data: blob): Void { - const dataBytes = new Uint8Array(IDL.encode([IDL.Vec(IDL.Nat8)], [data])) - .buffer; + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const dataBytes = encode(blob, data).buffer; return globalThis._azleIc.setCertifiedData(dataBytes); } diff --git a/src/lib/ic/set_timer.ts b/src/lib/ic/set_timer.ts index dd75ea3789..1a97519433 100644 --- a/src/lib/ic/set_timer.ts +++ b/src/lib/ic/set_timer.ts @@ -1,6 +1,7 @@ -import { IDL } from '@dfinity/candid'; import { Duration, TimerId } from './types'; import { v4 } from 'uuid'; +import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { encode, decode as azleDecode } from '../candid/serde'; /** * Sets callback to be executed later, after delay. Panics if `delay` + time() is more than 2^64 - 1. @@ -15,28 +16,31 @@ export function setTimer( delay: Duration, callback: () => void | Promise ): TimerId { - const encode = (value: Duration) => { - return new Uint8Array(IDL.encode([IDL.Nat64], [value])).buffer; - }; + if (globalThis._azleIc === undefined) { + return undefined as any; + } const decode = (value: ArrayBufferLike) => { - return BigInt(IDL.decode([IDL.Nat64], value)[0] as number); + return BigInt(azleDecode(nat64, value) as number); }; const timerCallbackId = `_timer_${v4()}`; const timerId = decode( - globalThis._azleIc.setTimer(encode(delay), timerCallbackId) + globalThis._azleIc.setTimer( + encode(nat64, delay).buffer, + timerCallbackId + ) ); globalThis.icTimers[timerId.toString()] = timerCallbackId; - globalThis[timerCallbackId] = () => { + globalThis._azleTimerCallbackIds[timerCallbackId] = () => { try { callback(); } finally { delete globalThis.icTimers[timerId.toString()]; - delete globalThis[timerCallbackId]; + delete globalThis._azleTimerCallbackIds[timerCallbackId]; } }; diff --git a/src/lib/ic/set_timer_interval.ts b/src/lib/ic/set_timer_interval.ts index bb9a8856d8..f397e34c9d 100644 --- a/src/lib/ic/set_timer_interval.ts +++ b/src/lib/ic/set_timer_interval.ts @@ -1,6 +1,7 @@ -import { IDL } from '@dfinity/candid'; import { Duration, TimerId } from './types'; import { v4 } from 'uuid'; +import { encode as azleEncode, decode as azleDecode } from '../candid/serde'; +import { nat64 } from '../candid/types/primitive/nats/nat64'; /** * Sets callback to be executed every interval. Panics if `interval` + time() is more than 2^64 - 1. @@ -15,25 +16,28 @@ export function setTimerInterval( interval: Duration, callback: () => void | Promise ): TimerId { - const encode = (value: Duration) => { - return new Uint8Array(IDL.encode([IDL.Nat64], [value])).buffer; - }; + if (globalThis._azleIc === undefined) { + return undefined as any; + } const decode = (value: ArrayBufferLike) => { - return BigInt(IDL.decode([IDL.Nat64], value)[0] as number); + return BigInt(azleDecode(nat64, value) as number); }; const timerCallbackId = `_interval_timer_${v4()}`; const timerId = decode( - globalThis._azleIc.setTimerInterval(encode(interval), timerCallbackId) + globalThis._azleIc.setTimerInterval( + azleEncode(nat64, interval).buffer, + timerCallbackId + ) ); globalThis.icTimers[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[timerCallbackId] = callback; + globalThis._azleTimerCallbackIds[timerCallbackId] = callback; return timerId; } diff --git a/src/lib/ic/stable_64_grow.ts b/src/lib/ic/stable_64_grow.ts index e627241a20..e65145defa 100644 --- a/src/lib/ic/stable_64_grow.ts +++ b/src/lib/ic/stable_64_grow.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode, encode } from '../candid/serde'; /** * Attempts to grow the stable memory by `newPages`. @@ -8,14 +8,16 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the previous size that was reserved. */ export function stable64Grow(newPages: nat64): nat64 { - const newPagesCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat64], [newPages]) - ).buffer; + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const newPagesCandidBytes = encode(nat64, newPages).buffer; return BigInt( - IDL.decode( - [IDL.Nat64], + decode( + nat64, globalThis._azleIc.stable64Grow(newPagesCandidBytes) - )[0] as number + ) as number ); } diff --git a/src/lib/ic/stable_64_read.ts b/src/lib/ic/stable_64_read.ts index 5bb045bc94..2417906b1f 100644 --- a/src/lib/ic/stable_64_read.ts +++ b/src/lib/ic/stable_64_read.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { encodeMultiple } from '../candid/serde'; /** * Reads data from the stable memory location specified by an offset. @@ -9,8 +9,13 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the raw bytes in stable memory */ export function stable64Read(offset: nat64, length: nat64): Uint8Array { - const paramsCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat64, IDL.Nat64], [offset, length]) + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const paramsCandidBytes = encodeMultiple( + [nat64, nat64], + [offset, length] ).buffer; return new Uint8Array(globalThis._azleIc.stable64Read(paramsCandidBytes)); diff --git a/src/lib/ic/stable_64_size.ts b/src/lib/ic/stable_64_size.ts index 4fe33ffb00..9bcc7af0d8 100644 --- a/src/lib/ic/stable_64_size.ts +++ b/src/lib/ic/stable_64_size.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode } from '../candid/serde'; /** * Gets current size of the stable memory (in WASM pages). Supports 64-bit @@ -7,7 +7,9 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @returns the current memory size */ export function stable64Size(): nat64 { - return BigInt( - IDL.decode([IDL.Nat64], globalThis._azleIc.stable64Size())[0] as number - ); + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + return BigInt(decode(nat64, globalThis._azleIc.stable64Size()) as number); } diff --git a/src/lib/ic/stable_64_write.ts b/src/lib/ic/stable_64_write.ts index 9f959c7a70..015f8740af 100644 --- a/src/lib/ic/stable_64_write.ts +++ b/src/lib/ic/stable_64_write.ts @@ -1,6 +1,6 @@ -import { IDL } from '@dfinity/candid'; import { blob } from '../candid/types/constructed/blob'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { encodeMultiple } from '../candid/serde'; /** * Writes data to the stable memory location specified by an offset. @@ -13,8 +13,13 @@ import { nat64 } from '../candid/types/primitive/nats/nat64'; * @param buffer the data to write */ export function stable64Write(offset: nat64, buffer: blob): void { - const paramsCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat64, IDL.Vec(IDL.Nat8)], [offset, buffer]) + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const paramsCandidBytes = encodeMultiple( + [nat64, blob], + [offset, buffer] ).buffer; return globalThis._azleIc.stable64Write(paramsCandidBytes); diff --git a/src/lib/ic/stable_bytes.ts b/src/lib/ic/stable_bytes.ts index bc3c11f6cf..c3675d6e7d 100644 --- a/src/lib/ic/stable_bytes.ts +++ b/src/lib/ic/stable_bytes.ts @@ -8,5 +8,9 @@ import { blob } from '../candid/types/constructed/blob'; * @returns a copy of the stable memory */ export function stableBytes(): blob { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + return new Uint8Array(globalThis._azleIc.stableBytes()); } diff --git a/src/lib/ic/stable_grow.ts b/src/lib/ic/stable_grow.ts index 6dfd4b3170..6df0aeef70 100644 --- a/src/lib/ic/stable_grow.ts +++ b/src/lib/ic/stable_grow.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat32 } from '../candid/types/primitive/nats/nat32'; +import { decode, encode } from '../candid/serde'; /** * Attempts to grow the stable memory by `newPages`. @@ -7,12 +7,14 @@ import { nat32 } from '../candid/types/primitive/nats/nat32'; * @returns the previous size that was reserved. */ export function stableGrow(newPages: nat32): nat32 { - const newPagesCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat32], [newPages]) - ).buffer; + if (globalThis._azleIc === undefined) { + return undefined as any; + } - return IDL.decode( - [IDL.Nat32], + const newPagesCandidBytes = encode(nat32, newPages).buffer; + + return decode( + nat32, globalThis._azleIc.stableGrow(newPagesCandidBytes) - )[0] as number; + ) as number; } diff --git a/src/lib/ic/stable_read.ts b/src/lib/ic/stable_read.ts index fc1e7b9cab..be91c18e29 100644 --- a/src/lib/ic/stable_read.ts +++ b/src/lib/ic/stable_read.ts @@ -1,5 +1,5 @@ -import { IDL } from '@dfinity/candid'; import { nat32 } from '../candid/types/primitive/nats/nat32'; +import { encodeMultiple } from '../candid/serde'; /** * Reads data from the stable memory location specified by an offset @@ -8,8 +8,13 @@ import { nat32 } from '../candid/types/primitive/nats/nat32'; * @returns the raw bytes in stable memory */ export function stableRead(offset: nat32, length: nat32): Uint8Array { - const paramsCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat32, IDL.Nat32], [offset, length]) + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const paramsCandidBytes = encodeMultiple( + [nat32, nat32], + [offset, length] ).buffer; return new Uint8Array(globalThis._azleIc.stableRead(paramsCandidBytes)); diff --git a/src/lib/ic/stable_size.ts b/src/lib/ic/stable_size.ts index 7f83534987..e44a7f4674 100644 --- a/src/lib/ic/stable_size.ts +++ b/src/lib/ic/stable_size.ts @@ -1,13 +1,14 @@ -import { IDL } from '@dfinity/candid'; import { nat32 } from '../candid/types/primitive/nats/nat32'; +import { decode } from '../candid/serde'; /** * Gets current size of the stable memory (in WASM pages) * @returns the current memory size */ export function stableSize(): nat32 { - return IDL.decode( - [IDL.Nat32], - globalThis._azleIc.stableSize() - )[0] as number; + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + return decode(nat32, globalThis._azleIc.stableSize()) as number; } diff --git a/src/lib/ic/stable_write.ts b/src/lib/ic/stable_write.ts index cc4fc447e9..51b79bcff1 100644 --- a/src/lib/ic/stable_write.ts +++ b/src/lib/ic/stable_write.ts @@ -1,6 +1,6 @@ -import { IDL } from '@dfinity/candid'; import { nat32 } from '../candid/types/primitive/nats/nat32'; import { blob } from '../candid/types/constructed/blob'; +import { encodeMultiple } from '../candid/serde'; /** * Writes data to the stable memory location specified by an offset @@ -12,8 +12,13 @@ import { blob } from '../candid/types/constructed/blob'; * @param buffer the data to write */ export function stableWrite(offset: nat32, buffer: blob): void { - const paramsCandidBytes = new Uint8Array( - IDL.encode([IDL.Nat32, IDL.Vec(IDL.Nat8)], [offset, buffer]) + if (globalThis._azleIc === undefined) { + return undefined as any; + } + + const paramsCandidBytes = encodeMultiple( + [nat32, blob], + [offset, buffer] ).buffer; return globalThis._azleIc.stableWrite(paramsCandidBytes); diff --git a/src/lib/ic/time.ts b/src/lib/ic/time.ts index 695788ed5b..3e068b9f6a 100644 --- a/src/lib/ic/time.ts +++ b/src/lib/ic/time.ts @@ -1,11 +1,15 @@ -import { IDL } from '@dfinity/candid'; import { nat64 } from '../candid/types/primitive/nats/nat64'; +import { decode } from '../candid/serde'; /** * Gets current timestamp, in nanoseconds since the epoch (1970-01-01) * @returns the current timestamp */ export function time(): nat64 { + if (globalThis._azleIc === undefined) { + return undefined as any; + } + const timeCandidBytes = globalThis._azleIc.time(); - return BigInt(IDL.decode([IDL.Nat64], timeCandidBytes)[0] as number); + return BigInt(decode(nat64, timeCandidBytes) as number); } diff --git a/src/lib/ic/trap.ts b/src/lib/ic/trap.ts index 772ec00efa..81f76380e8 100644 --- a/src/lib/ic/trap.ts +++ b/src/lib/ic/trap.ts @@ -6,4 +6,10 @@ import { text } from '../candid/types/primitive/text'; * (5) rejection code and the provided message * @param message the rejection message */ -export const trap = (message: text) => empty; +export function trap(message: text): empty { + if (globalThis._azleIc === undefined) { + return undefined as never; + } + + globalThis._azleIc.trap(message); +} diff --git a/src/lib/ic/types/azle_ic.ts b/src/lib/ic/types/azle_ic.ts new file mode 100644 index 0000000000..9b4e977f31 --- /dev/null +++ b/src/lib/ic/types/azle_ic.ts @@ -0,0 +1,91 @@ +import { text } from '../../candid/types/primitive/text'; +import { Void } from '../../candid/types/primitive/void'; + +/** + * 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 = { + argDataRaw: () => ArrayBufferLike; + argDataRawSize: () => number; + callRaw: ( + promiseId: string, + canisterIdBytes: ArrayBufferLike, + method: string, + argsRaw: ArrayBufferLike, + paymentCandidBytes: ArrayBufferLike + ) => void; + callRaw128: ( + promiseId: string, + canisterIdBytes: ArrayBufferLike, + method: string, + argsRaw: ArrayBufferLike, + paymentCandidBytes: ArrayBufferLike + ) => void; + caller: () => ArrayBufferLike; + candidDecode: (candidBytes: ArrayBufferLike) => string; + candidEncode: (candidString: string) => ArrayBufferLike; + canisterBalance: () => ArrayBufferLike; + canisterBalance128: () => ArrayBufferLike; + canisterVersion: () => ArrayBufferLike; + clearTimer: (timerIdBytes: ArrayBufferLike) => void; + dataCertificate: () => ArrayBufferLike | undefined; + id: () => string; + instructionCounter: () => ArrayBufferLike; + isController: (principalBytes: ArrayBufferLike) => boolean; + msgCyclesAccept: (maxAmountCandidBytes: ArrayBufferLike) => ArrayBufferLike; + msgCyclesAccept128: ( + maxAmountCandidBytes: ArrayBufferLike + ) => ArrayBufferLike; + msgCyclesAvailable: () => ArrayBufferLike; + msgCyclesAvailable128: () => ArrayBufferLike; + msgCyclesRefunded: () => ArrayBufferLike; + msgCyclesRefunded128: () => ArrayBufferLike; + notifyRaw: ( + canisterIdBytes: ArrayBufferLike, + method: string, + argsRawBuffer: ArrayBufferLike, + paymentCandidBytes: ArrayBufferLike + ) => void; + performanceCounter: ( + counterTypeCandidBytes: ArrayBufferLike + ) => ArrayBufferLike; + rejectCode: () => number; + replyRaw: (bytes: ArrayBufferLike) => void; + setCertifiedData: (dataBytes: ArrayBufferLike) => void; + setTimer: ( + delayBytes: ArrayBufferLike, + timerCallbackId: string + ) => ArrayBufferLike; + setTimerInterval: ( + intervalBytes: ArrayBufferLike, + timerCallbackId: string + ) => ArrayBufferLike; + stableBytes: () => ArrayBufferLike; + stableGrow: (newPagesCandidBytes: ArrayBufferLike) => ArrayBufferLike; + stableRead: (paramsCandidBytes: ArrayBufferLike) => ArrayBufferLike; + stableSize: () => ArrayBufferLike; + stableWrite: (paramsCandidBytes: ArrayBufferLike) => void; + stable64Grow: (newPagesCandidBytes: ArrayBufferLike) => ArrayBufferLike; + stable64Read: (paramsCandidBytes: ArrayBufferLike) => ArrayBufferLike; + stable64Size: () => ArrayBufferLike; + stable64Write: (paramsCandidBytes: ArrayBufferLike) => void; + time: () => ArrayBufferLike; + // 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; + call128: () => never; + notify: () => never; + reply: () => never; +}; diff --git a/src/lib/ic/types.ts b/src/lib/ic/types/index.ts similarity index 89% rename from src/lib/ic/types.ts rename to src/lib/ic/types/index.ts index 670868d4cd..fd3cf50ac9 100644 --- a/src/lib/ic/types.ts +++ b/src/lib/ic/types/index.ts @@ -1,4 +1,4 @@ -import { nat64, AzleNat64 } from '../candid/types/primitive/nats/nat64'; +import { nat64, AzleNat64 } from '../../candid/types/primitive/nats/nat64'; export type ArgsType = T extends (...args: infer U) => any ? U : any; export type ReturnTypeOf = T extends (...args: any[]) => infer R ? R : any; diff --git a/src/lib/stable_b_tree_map.ts b/src/lib/stable_b_tree_map.ts index a0ba6925fe..5773174785 100644 --- a/src/lib/stable_b_tree_map.ts +++ b/src/lib/stable_b_tree_map.ts @@ -1,6 +1,5 @@ -import { CandidType, TypeMapping, toIDLType } from './candid'; +import { CandidType, TypeMapping } from './candid'; import { None, Opt, Some } from './candid/types/constructed/opt'; -import { IDL } from '@dfinity/candid'; import { nat64 } from './candid/types/primitive/nats/nat64'; import { nat8 } from './candid/types/primitive/nats/nat8'; import { encode, decode } from './candid/serde'; @@ -9,12 +8,7 @@ export function StableBTreeMap< Key extends CandidType, Value extends CandidType >(keyType: Key, valueType: Value, memoryId: nat8) { - const keyIdl = toIDLType(keyType, []); - const valueIdl = toIDLType(valueType, []); - - const candidEncodedMemoryId = new Uint8Array( - IDL.encode([IDL.Nat8], [memoryId]) - ).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; if ((globalThis as any)._azleIc !== undefined) { (globalThis as any)._azleIc.stableBTreeMapInit(candidEncodedMemoryId); @@ -27,8 +21,8 @@ export function StableBTreeMap< * @returns `true` if the key exists in the map, `false` otherwise. */ containsKey(key: TypeMapping): boolean { - const candidEncodedMemoryId = encode(memoryId, IDL.Nat8).buffer; - const candidEncodedKey = encode(key, keyType).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; + const candidEncodedKey = encode(keyType, key).buffer; return (globalThis as any)._azleIc.stableBTreeMapContainsKey( candidEncodedMemoryId, @@ -41,8 +35,8 @@ export function StableBTreeMap< * @returns the value associated with the given key, if it exists. */ get(key: TypeMapping): Opt> { - const candidEncodedMemoryId = encode(memoryId, IDL.Nat8).buffer; - const candidEncodedKey = encode(key, keyType).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; + const candidEncodedKey = encode(keyType, key).buffer; const candidEncodedValue = ( globalThis as any @@ -54,7 +48,7 @@ export function StableBTreeMap< if (candidEncodedValue === undefined) { return None; } else { - return Some(decode(candidEncodedValue, valueType)); + return Some(decode(valueType, candidEncodedValue)); } }, /** @@ -67,9 +61,9 @@ export function StableBTreeMap< key: TypeMapping, value: TypeMapping ): Opt> { - const candidEncodedMemoryId = encode(memoryId, IDL.Nat8).buffer; - const candidEncodedKey = encode(key, keyType).buffer; - const candidEncodedValue = encode(value, valueType).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; + const candidEncodedKey = encode(keyType, key).buffer; + const candidEncodedValue = encode(valueType, value).buffer; const candidEncodedResultValue = ( globalThis as any @@ -82,7 +76,7 @@ export function StableBTreeMap< if (candidEncodedResultValue === undefined) { return None; } else { - return Some(decode(candidEncodedResultValue, valueType)); + return Some(decode(valueType, candidEncodedResultValue)); } }, /** @@ -90,7 +84,7 @@ export function StableBTreeMap< * @returns `true` if the map contains no elements, `false` otherwise. */ isEmpty(): boolean { - const candidEncodedMemoryId = encode(memoryId, IDL.Nat8).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; return (globalThis as any)._azleIc.stableBTreeMapIsEmpty( candidEncodedMemoryId @@ -101,7 +95,7 @@ export function StableBTreeMap< * @returns tuples representing key/value pairs. */ items(): [TypeMapping, TypeMapping][] { - const candidEncodedMemoryId = encode(memoryId, IDL.Nat8).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; const candidEncodedItems = ( globalThis as any @@ -110,8 +104,8 @@ export function StableBTreeMap< // TODO too much copying return candidEncodedItems.map((candidEncodedItem: any) => { return [ - decode(candidEncodedItem[0], keyType), - decode(candidEncodedItem[1], valueType) + decode(keyType, candidEncodedItem[0]), + decode(valueType, candidEncodedItem[1]) ]; }); }, @@ -120,7 +114,7 @@ export function StableBTreeMap< * @returns they keys in the map. */ keys(): TypeMapping[] { - const candidEncodedMemoryId = encode(memoryId, IDL.Nat8).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; const candidEncodedKeys = ( globalThis as any @@ -128,7 +122,7 @@ export function StableBTreeMap< // TODO too much copying return candidEncodedKeys.map((candidEncodedKey: any) => { - return decode(candidEncodedKey, keyType); + return decode(keyType, candidEncodedKey); }); }, /** @@ -136,13 +130,13 @@ export function StableBTreeMap< * @returns the number of elements in the map. */ len(): nat64 { - const candidEncodedMemoryId = encode(memoryId, IDL.Nat8).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; const candidEncodedLen = ( globalThis as any )._azleIc.stableBTreeMapLen(candidEncodedMemoryId); - return decode(candidEncodedLen, IDL.Nat64); + return decode(nat64, candidEncodedLen); }, /** * Removes a key from the map. @@ -150,8 +144,8 @@ export function StableBTreeMap< * @returns the previous value at the key if it exists, `null` otherwise. */ remove(key: TypeMapping): Opt> { - const candidEncodedMemoryId = encode(memoryId, IDL.Nat8).buffer; - const candidEncodedKey = encode(key, keyType).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; + const candidEncodedKey = encode(keyType, key).buffer; const candidEncodedValue = ( globalThis as any @@ -163,7 +157,7 @@ export function StableBTreeMap< if (candidEncodedValue === undefined) { return None; } else { - return Some(decode(candidEncodedValue, valueType)); + return Some(decode(valueType, candidEncodedValue)); } }, /** @@ -171,7 +165,7 @@ export function StableBTreeMap< * @returns the values in the map. */ values(): TypeMapping[] { - const candidEncodedMemoryId = encode(memoryId, IDL.Nat8).buffer; + const candidEncodedMemoryId = encode(nat8, memoryId).buffer; const candidEncodedValues = ( globalThis as any @@ -179,7 +173,7 @@ export function StableBTreeMap< // TODO too much copying return candidEncodedValues.map((candidEncodedValue: any) => { - return decode(candidEncodedValue, valueType); + return decode(valueType, candidEncodedValue); }); } };