From d2654f9ec316767ae59c82a33a7f09dd1d82cb75 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 3 May 2024 10:29:59 -0700 Subject: [PATCH 01/36] fix principal length check (#545) --- rust/candid/src/binary_parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/candid/src/binary_parser.rs b/rust/candid/src/binary_parser.rs index 03a7b6e2..d0c1ea0e 100644 --- a/rust/candid/src/binary_parser.rs +++ b/rust/candid/src/binary_parser.rs @@ -129,7 +129,7 @@ pub struct Len( pub struct PrincipalBytes { #[br(assert(flag == 1u8, "Opaque reference not supported"))] pub flag: u8, - #[br(parse_with = read_leb)] + #[br(parse_with = read_leb, assert(len <= 29, "Principal is longer than 29 bytes"))] pub len: u64, #[br(count = len)] pub inner: Vec, From ea3c3e9f51feb78617bec401e4fbeb28284628c2 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 3 May 2024 10:41:06 -0700 Subject: [PATCH 02/36] Candid type selector (#544) * replace dhall with toml * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * random works * test * fix * fix * Refactor Rust bindgen with the new config (#546) * checkpoint * checkpoint * connect with didc and test * checkpoint * vis * vis * checkpoint * fix merging semantics * checkpoint * fix * fix * fix root config fallback * checkpoint * add unmatched config * fix attr * handlebar * update test, diff is only space and newline * forget to commit test * move pp_actor inside impl * fix * refactor * init args * add test * add_config * clippy * changelog and bump version --- Cargo.lock | 778 +++++--------- Changelog.md | 20 +- rust/candid/Cargo.toml | 2 +- rust/candid/src/ser.rs | 8 +- rust/candid/src/types/mod.rs | 8 +- rust/candid_parser/Cargo.toml | 11 +- rust/candid_parser/src/bindings/rust.rs | 970 +++++++++++------- .../candid_parser/src/bindings/rust_agent.hbs | 22 + rust/candid_parser/src/bindings/rust_call.hbs | 21 + rust/candid_parser/src/configs.rs | 439 +++++++- rust/candid_parser/src/error.rs | 8 +- rust/candid_parser/src/lib.rs | 2 - rust/candid_parser/src/random.rs | 195 ++-- rust/candid_parser/tests/assets/example.toml | 11 + rust/candid_parser/tests/assets/ok/actor.rs | 1 + rust/candid_parser/tests/assets/ok/class.rs | 1 + rust/candid_parser/tests/assets/ok/comment.rs | 1 + rust/candid_parser/tests/assets/ok/cyclic.rs | 13 +- rust/candid_parser/tests/assets/ok/empty.rs | 5 +- rust/candid_parser/tests/assets/ok/escape.rs | 1 + rust/candid_parser/tests/assets/ok/example.rs | 164 ++- .../candid_parser/tests/assets/ok/fieldnat.rs | 15 +- rust/candid_parser/tests/assets/ok/keyword.rs | 21 +- .../tests/assets/ok/management.rs | 87 +- .../tests/assets/ok/recursion.rs | 8 +- .../tests/assets/ok/recursive_class.rs | 2 + rust/candid_parser/tests/assets/ok/service.rs | 1 + rust/candid_parser/tests/assets/ok/unicode.rs | 8 +- rust/candid_parser/tests/parse_type.rs | 26 +- tools/didc/Cargo.toml | 2 +- tools/didc/random.dhall | 30 - tools/didc/random.toml | 24 + tools/didc/src/main.rs | 68 +- 33 files changed, 1597 insertions(+), 1376 deletions(-) create mode 100644 rust/candid_parser/src/bindings/rust_agent.hbs create mode 100644 rust/candid_parser/src/bindings/rust_call.hbs create mode 100644 rust/candid_parser/tests/assets/example.toml delete mode 100644 tools/didc/random.dhall create mode 100644 tools/didc/random.toml diff --git a/Cargo.lock b/Cargo.lock index f21af487..a076a7af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,98 +2,59 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "abnf" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33741baa462d86e43fdec5e8ffca7c6ac82847ad06cbfb382c1bdbf527de9e6b" -dependencies = [ - "abnf-core", - "nom", -] - -[[package]] -name = "abnf-core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c44e09c43ae1c368fb91a03a566472d0087c26cf7e1b9e8e289c14ede681dd7d" -dependencies = [ - "nom", -] - -[[package]] -name = "abnf_to_pest" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "939d59666dd9a7964a3a5312b9d24c9c107630752ee64f2dd5038189a23fe331" -dependencies = [ - "abnf", - "indexmap 1.9.3", - "itertools 0.10.5", - "pretty 0.11.3", -] - [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] -[[package]] -name = "annotate-snippets" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" -dependencies = [ - "unicode-width", -] - [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys", @@ -101,9 +62,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "arbitrary" @@ -128,9 +89,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "beef" @@ -165,8 +126,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" dependencies = [ "either", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -187,24 +148,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -234,7 +180,7 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "candid" -version = "0.10.7" +version = "0.10.8" dependencies = [ "anyhow", "bincode", @@ -247,7 +193,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", - "pretty 0.12.3", + "pretty", "rand", "serde", "serde_bytes", @@ -262,14 +208,14 @@ name = "candid_derive" version = "0.6.6" dependencies = [ "lazy_static", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.52", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "candid_parser" -version = "0.1.4" +version = "0.2.0-beta.0" dependencies = [ "anyhow", "arbitrary", @@ -281,25 +227,26 @@ dependencies = [ "dialoguer", "fake", "goldenfile", + "handlebars", "hex", "lalrpop", "lalrpop-util", "logos", "num-bigint", "num-traits", - "pretty 0.12.3", + "pretty", "rand", "serde", - "serde_dhall", "test-generator", "thiserror", + "toml", ] [[package]] name = "cc" -version = "1.0.90" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" [[package]] name = "cfg-if" @@ -307,11 +254,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "clap" -version = "4.5.2" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -331,14 +284,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.52", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -359,9 +312,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "console" @@ -421,9 +374,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.2" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" +checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" dependencies = [ "nix", "windows-sys", @@ -431,51 +384,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "deunicode" -version = "1.4.3" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94" - -[[package]] -name = "dhall" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9093ee48621ca9db16cd4948c7acf24a8ecc9af41cc9e226e39ea719df06d8b5" -dependencies = [ - "abnf_to_pest", - "annotate-snippets", - "elsa", - "hex", - "home", - "itertools 0.9.0", - "lazy_static", - "once_cell", - "percent-encoding", - "pest", - "pest_consume", - "pest_generator", - "quote 1.0.35", - "serde", - "serde_cbor", - "sha2 0.9.9", - "url", -] - -[[package]] -name = "dhall_proc_macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7c81d16870879ef530b07cef32bc6088f98937ab4168106cc8e382a05146bf" -dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.109", -] +checksum = "322ef0094744e63628e6f0eb2295517f79276a5b342a4c2ff3042566ca181d4e" [[package]] name = "dialoguer" @@ -491,7 +408,7 @@ dependencies = [ [[package]] name = "didc" -version = "0.3.7" +version = "0.4.0" dependencies = [ "anyhow", "candid_parser", @@ -501,22 +418,13 @@ dependencies = [ "rand", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "crypto-common", ] @@ -541,26 +449,11 @@ dependencies = [ "winapi", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" - -[[package]] -name = "elsa" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" -dependencies = [ - "stable_deref_trait", -] +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "ena" @@ -605,9 +498,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fixedbitset" @@ -621,15 +514,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -642,9 +526,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -659,9 +543,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "goldenfile" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a67453a3b358bd8213aedafd4feed75eecab9fb04bed26ba6fdf94694be560" +checksum = "a0d5c44265baec620ea19c97b4ce9f068e28f8c3d7faccc483f02968b5e3c587" dependencies = [ "scopeguard", "similar-asserts", @@ -676,22 +560,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] -name = "hashbrown" -version = "0.12.3" +name = "handlebars" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hex" @@ -699,15 +591,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys", -] - [[package]] name = "ic_principal" version = "0.1.1" @@ -720,20 +603,10 @@ dependencies = [ "serde_cbor", "serde_json", "serde_test", - "sha2 0.10.8", + "sha2", "thiserror", ] -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "impls" version = "1.0.3" @@ -742,41 +615,19 @@ checksum = "7a46645bbd70538861a90d0f26c31537cdf1e44aae99a794fb75a664b70951bc" [[package]] name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown", ] [[package]] -name = "itertools" -version = "0.9.0" +name = "is_terminal_polyfill" +version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" [[package]] name = "itertools" @@ -789,9 +640,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "lalrpop" @@ -802,12 +653,12 @@ dependencies = [ "ascii-canvas", "bit-set", "ena", - "itertools 0.11.0", + "itertools", "lalrpop-util", "petgraph", "pico-args", "regex", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", "string_cache", "term", "tiny-keccak", @@ -838,19 +689,18 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.2", + "bitflags", "libc", - "redox_syscall", ] [[package]] @@ -861,9 +711,9 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -892,10 +742,10 @@ checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" dependencies = [ "beef", "fnv", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "regex-syntax 0.6.29", - "syn 2.0.52", + "syn 2.0.60", ] [[package]] @@ -909,43 +759,28 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "new_debug_unreachable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nix" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.2", + "bitflags", "cfg-if", + "cfg_aliases", "libc", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-bigint" version = "0.4.4" @@ -982,17 +817,11 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -1000,15 +829,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -1017,50 +846,22 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - [[package]] name = "pest" -version = "2.7.8" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", "thiserror", "ucd-trie", ] -[[package]] -name = "pest_consume" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79447402d15d18e7142e14c72f2e63fa3d155be1bc5b70b3ccbb610ac55f536b" -dependencies = [ - "pest", - "pest_consume_macros", - "pest_derive", -] - -[[package]] -name = "pest_consume_macros" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d8630a7a899cb344ec1c16ba0a6b24240029af34bdc0a21f84e411d7f793f29" -dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.109", -] - [[package]] name = "pest_derive" -version = "2.7.8" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ "pest", "pest_generator", @@ -1068,26 +869,26 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.8" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.52", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "pest_meta" -version = "2.7.8" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ "once_cell", "pest", - "sha2 0.10.8", + "sha2", ] [[package]] @@ -1097,7 +898,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.5", + "indexmap", ] [[package]] @@ -1127,18 +928,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "pretty" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f3aa1e3ca87d3b124db7461265ac176b40c277f37e503eaa29c9c75c037846" -dependencies = [ - "arrayvec", - "log", - "typed-arena", - "unicode-segmentation", -] - [[package]] name = "pretty" version = "0.12.3" @@ -1167,9 +956,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -1194,11 +983,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "proc-macro2 1.0.78", + "proc-macro2 1.0.81", ] [[package]] @@ -1233,18 +1022,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -1253,14 +1042,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.6", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -1277,7 +1066,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -1288,17 +1077,17 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.2", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1307,9 +1096,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" [[package]] name = "ryu" @@ -1334,9 +1123,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] @@ -1362,36 +1151,32 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.52", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] -name = "serde_dhall" -version = "0.11.2" +name = "serde_json" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c01a6b1d6f9f33bb1ad5652249e938297e43a1f43418236f7b72e64837e347" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ - "dhall", - "dhall_proc_macros", - "doc-comment", + "itoa", + "ryu", "serde", - "url", ] [[package]] -name = "serde_json" -version = "1.0.114" +name = "serde_spanned" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ - "itoa", - "ryu", "serde", ] @@ -1404,19 +1189,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.8" @@ -1425,7 +1197,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -1436,9 +1208,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "similar" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" +checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" dependencies = [ "bstr", "unicode-segmentation", @@ -1462,15 +1234,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "stacker" @@ -1500,9 +1266,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" @@ -1521,19 +1287,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.52" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "unicode-ident", ] @@ -1583,22 +1349,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.52", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -1611,19 +1377,38 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "toml" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ - "tinyvec_macros", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", ] [[package]] -name = "tinyvec_macros" -version = "0.1.1" +name = "toml_datetime" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] [[package]] name = "typed-arena" @@ -1643,27 +1428,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.11.0" @@ -1672,9 +1442,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -1688,17 +1458,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "utf8parse" version = "0.2.1" @@ -1745,11 +1504,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys", ] [[package]] @@ -1764,125 +1523,84 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" -dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] -name = "windows_i686_gnu" -version = "0.52.4" +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.4" +name = "winnow" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" +dependencies = [ + "memchr", +] [[package]] name = "yansi" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2861d76f58ec8fc95708b9b1e417f7b12fd72ad33c01fa6886707092dea0d3" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/Changelog.md b/Changelog.md index e8dcf97c..ddca135f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,14 +1,32 @@ # Changelog +## 2024-05-03 + +### candid_parser 0.2.0-beta.0 + +* Breaking changes: + + Rewrite `configs` and `random` modules, adapting TOML format as the parser. `configs` module is no longer under a feature flag, and no longer depend on dhall. + + Rewrite Rust bindgen to use the new `configs` module. Use `emit_bindgen` to generate type bindings, and use `output_handlebar` to provide a handlebar template for the generated module. `compile` function provides a default template. The generated file without config is exactly the same as before. + +* TO-DOs + + Spec for path and matching semantics + + Warning for unused path + + Rust bindgen: + * Generate `use_type` tests. How to handle recursive types? + * Threading state through `nominalize` + * When the path starts with method, duplicate type definition when necessary. + * Number label renaming + ## 2024-04-11 -### Candid 0.10.7 -- 0.10.5 +### Candid 0.10.5 -- 0.10.8 * Switch `HashMap` to `BTreeMap` in serialization and `T::ty()`. This leads to around 20% perf improvement for serializing complicated types. * Disable memoization for unrolled types in serialization to save cycle cost. In some cases, type table can get slightly larger, but it's worth the trade off. * Fix bug in `text_size` * Fix decoding cost calculation overflow +* Fix length check in decoding principal type ## 2024-02-27 diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index 93949bae..6a61a33b 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid" -version = "0.10.7" +version = "0.10.8" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] diff --git a/rust/candid/src/ser.rs b/rust/candid/src/ser.rs index 002c6717..15750555 100644 --- a/rust/candid/src/ser.rs +++ b/rust/candid/src/ser.rs @@ -169,9 +169,9 @@ impl<'a> types::Serializer for &'a mut ValueSerializer { self.serialize_principal(blob)?; self.serialize_text(meth) } - fn serialize_option(self, v: Option<&T>) -> Result<()> + fn serialize_option(self, v: Option<&T>) -> Result<()> where - T: super::CandidType, + T: super::CandidType + ?Sized, { match v { None => { @@ -207,9 +207,9 @@ pub struct Compound<'a> { } impl<'a> types::Compound for Compound<'a> { type Error = Error; - fn serialize_element(&mut self, value: &T) -> Result<()> + fn serialize_element(&mut self, value: &T) -> Result<()> where - T: types::CandidType, + T: types::CandidType + ?Sized, { value.idl_serialize(&mut *self.ser)?; Ok(()) diff --git a/rust/candid/src/types/mod.rs b/rust/candid/src/types/mod.rs index f844ab72..aab4554a 100644 --- a/rust/candid/src/types/mod.rs +++ b/rust/candid/src/types/mod.rs @@ -81,9 +81,9 @@ pub trait Serializer: Sized { fn serialize_text(self, v: &str) -> Result<(), Self::Error>; fn serialize_null(self, v: ()) -> Result<(), Self::Error>; fn serialize_empty(self) -> Result<(), Self::Error>; - fn serialize_option(self, v: Option<&T>) -> Result<(), Self::Error> + fn serialize_option(self, v: Option<&T>) -> Result<(), Self::Error> where - T: CandidType; + T: CandidType + ?Sized; fn serialize_struct(self) -> Result; fn serialize_vec(self, len: usize) -> Result; fn serialize_blob(self, v: &[u8]) -> Result<(), Self::Error>; @@ -94,9 +94,9 @@ pub trait Serializer: Sized { pub trait Compound { type Error; - fn serialize_element(&mut self, v: &T) -> Result<(), Self::Error> + fn serialize_element(&mut self, v: &T) -> Result<(), Self::Error> where - T: CandidType; + T: CandidType + ?Sized; // Used for simulating serde(with = "serde_bytes"). We can remove this when specialization is stable in Rust, // or generalize this function to take a closure for with. #[doc(hidden)] diff --git a/rust/candid_parser/Cargo.toml b/rust/candid_parser/Cargo.toml index 503322ed..2630d651 100644 --- a/rust/candid_parser/Cargo.toml +++ b/rust/candid_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid_parser" -version = "0.1.4" +version = "0.2.0-beta.0" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] @@ -26,18 +26,18 @@ num-bigint.workspace = true pretty.workspace = true thiserror.workspace = true anyhow.workspace = true +serde.workspace = true lalrpop-util = "0.20.0" logos = "0.13" convert_case = "0.6" +handlebars = "5.1" +toml = { version = "0.8", default-features = false, features = ["parse"] } arbitrary = { workspace = true, optional = true } -# Don't upgrade serde_dhall. It will introduce dependency with invalid license. -serde_dhall = { version = "0.11", default-features = false, optional = true } fake = { version = "2.4", optional = true } rand = { version = "0.8", optional = true } num-traits = { workspace = true, optional = true } -serde = { workspace = true, optional = true } dialoguer = { version = "0.11", default-features = false, features = ["editor", "completion"], optional = true } console = { version = "0.15", optional = true } ctrlc = { version = "3.4", optional = true } @@ -48,8 +48,7 @@ test-generator = "0.3.0" rand.workspace = true [features] -configs = ["serde_dhall"] -random = ["configs", "arbitrary", "fake", "rand", "num-traits", "serde"] +random = ["dep:arbitrary", "dep:fake", "dep:rand", "dep:num-traits"] assist = ["dep:dialoguer", "dep:console", "dep:ctrlc"] all = ["random", "assist"] diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index ee1b1b8c..afeb98ff 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -1,63 +1,51 @@ use super::analysis::{chase_actor, infer_rec}; +use crate::{ + configs::{ConfigState, ConfigTree, Configs, StateElem}, + Deserialize, +}; use candid::pretty::utils::*; use candid::types::{Field, Function, Label, SharedLabel, Type, TypeEnv, TypeInner}; use convert_case::{Case, Casing}; use pretty::RcDoc; -use std::collections::BTreeSet; +use serde::Serialize; +use std::collections::{BTreeMap, BTreeSet}; -#[derive(Clone)] -pub enum Target { - CanisterCall, - Agent, - CanisterStub, +#[derive(Default, Deserialize, Clone, Debug)] +pub struct BindingConfig { + name: Option, + use_type: Option, + attributes: Option, + visibility: Option, } - -#[derive(Clone)] -pub struct Config { - candid_crate: String, - type_attributes: String, - canister_id: Option, - service_name: String, - target: Target, -} -impl Config { - pub fn new() -> Self { - Config { - candid_crate: "candid".to_string(), - type_attributes: "".to_string(), - canister_id: None, - service_name: "service".to_string(), - target: Target::CanisterCall, +impl ConfigState for BindingConfig { + fn merge_config(&mut self, config: &Self, elem: Option<&StateElem>, _is_recursive: bool) { + self.name.clone_from(&config.name); + // match use_type can survive across types, so that label.use_type works + if !matches!(elem, Some(StateElem::Label(_))) { + if let Some(use_type) = &config.use_type { + self.use_type = Some(use_type.clone()); + } + } else { + self.use_type.clone_from(&config.use_type); + } + // matched attributes can survive across labels, so that record.attributes works + if matches!(elem, Some(StateElem::Label(_))) { + if let Some(attr) = &config.attributes { + self.attributes = Some(attr.clone()); + } + } else { + self.attributes.clone_from(&config.attributes); + } + if config.visibility.is_some() { + self.visibility.clone_from(&config.visibility); } } - pub fn set_candid_crate(&mut self, name: String) -> &mut Self { - self.candid_crate = name; - self - } - /// Applies to all types for now - pub fn set_type_attributes(&mut self, attr: String) -> &mut Self { - self.type_attributes = attr; - self - } - /// Only generates SERVICE struct if canister_id is not provided - pub fn set_canister_id(&mut self, id: candid::Principal) -> &mut Self { - self.canister_id = Some(id); - self - } - /// Service name when canister id is provided - pub fn set_service_name(&mut self, name: String) -> &mut Self { - self.service_name = name; - self - } - pub fn set_target(&mut self, name: Target) -> &mut Self { - self.target = name; - self - } + fn update_state(&mut self, _elem: &StateElem) {} + fn restore_state(&mut self, _elem: &StateElem) {} } -impl Default for Config { - fn default() -> Self { - Self::new() - } +pub struct State<'a> { + state: crate::configs::State<'a, BindingConfig>, + recs: RecPoints<'a>, } type RecPoints<'a> = BTreeSet<&'a str>; @@ -101,363 +89,408 @@ fn ident_(id: &str, case: Option) -> (RcDoc, bool) { fn ident(id: &str, case: Option) -> RcDoc { ident_(id, case).0 } - -fn pp_ty<'a>(ty: &'a Type, recs: &RecPoints) -> RcDoc<'a> { - use TypeInner::*; - match ty.as_ref() { - Null => str("()"), - Bool => str("bool"), - Nat => str("candid::Nat"), - Int => str("candid::Int"), - Nat8 => str("u8"), - Nat16 => str("u16"), - Nat32 => str("u32"), - Nat64 => str("u64"), - Int8 => str("i8"), - Int16 => str("i16"), - Int32 => str("i32"), - Int64 => str("i64"), - Float32 => str("f32"), - Float64 => str("f64"), - Text => str("String"), - Reserved => str("candid::Reserved"), - Empty => str("candid::Empty"), - Var(ref id) => { - let name = ident(id, Some(Case::Pascal)); - if recs.contains(id.as_str()) { - str("Box<").append(name).append(">") - } else { - name - } - } - Principal => str("Principal"), - Opt(ref t) => str("Option").append(enclose("<", pp_ty(t, recs), ">")), - // It's a bit tricky to use `deserialize_with = "serde_bytes"`. It's not working for `type t = blob` - Vec(ref t) if matches!(t.as_ref(), Nat8) => str("serde_bytes::ByteBuf"), - Vec(ref t) => str("Vec").append(enclose("<", pp_ty(t, recs), ">")), - Record(ref fs) => pp_record_fields(fs, recs, ""), - Variant(_) => unreachable!(), // not possible after rewriting - Func(_) => unreachable!(), // not possible after rewriting - Service(_) => unreachable!(), // not possible after rewriting - Class(_, _) => unreachable!(), - Knot(_) | Unknown | Future => unreachable!(), +fn pp_vis<'a>(vis: &Option) -> RcDoc<'a> { + match vis { + Some(vis) if vis.is_empty() => RcDoc::nil(), + Some(vis) => RcDoc::text(vis.clone()).append(" "), + None => RcDoc::text("pub "), } } - -fn pp_label<'a>(id: &'a SharedLabel, is_variant: bool, vis: &'a str) -> RcDoc<'a> { - let vis = if vis.is_empty() { - RcDoc::nil() - } else { - kwd(vis) - }; - match &**id { - Label::Named(id) => { - let case = if is_variant { Some(Case::Pascal) } else { None }; - let (doc, is_rename) = ident_(id, case); - if is_rename { - str("#[serde(rename=\"") - .append(id.escape_debug().to_string()) - .append("\")]") - .append(RcDoc::line()) - .append(vis) - .append(doc) - } else { - vis.append(doc) +impl<'a> State<'a> { + fn pp_ty<'b>(&mut self, ty: &'b Type, is_ref: bool) -> RcDoc<'b> { + use TypeInner::*; + let elem = StateElem::Type(ty); + let old = self.state.push_state(&elem); + let res = if let Some(t) = &self.state.config.use_type { + RcDoc::text(t.clone()) + } else { + match ty.as_ref() { + Null => str("()"), + Bool => str("bool"), + Nat => str("candid::Nat"), + Int => str("candid::Int"), + Nat8 => str("u8"), + Nat16 => str("u16"), + Nat32 => str("u32"), + Nat64 => str("u64"), + Int8 => str("i8"), + Int16 => str("i16"), + Int32 => str("i32"), + Int64 => str("i64"), + Float32 => str("f32"), + Float64 => str("f64"), + Text => str("String"), + Reserved => str("candid::Reserved"), + Empty => str("candid::Empty"), + Var(ref id) => { + let name = if let Some(name) = &self.state.config.name { + RcDoc::text(name.clone()) + } else { + ident(id, Some(Case::Pascal)) + }; + if !is_ref && self.recs.contains(id.as_str()) { + str("Box<").append(name).append(">") + } else { + name + } + } + Principal => str("Principal"), + Opt(ref t) => str("Option").append(enclose("<", self.pp_ty(t, is_ref), ">")), + // It's a bit tricky to use `deserialize_with = "serde_bytes"`. It's not working for `type t = blob` + Vec(ref t) if matches!(t.as_ref(), Nat8) => str("serde_bytes::ByteBuf"), + Vec(ref t) => str("Vec").append(enclose("<", self.pp_ty(t, is_ref), ">")), + Record(ref fs) => self.pp_record_fields(fs, false, is_ref), + Variant(_) => unreachable!(), // not possible after rewriting + Func(_) => unreachable!(), // not possible after rewriting + Service(_) => unreachable!(), // not possible after rewriting + Class(_, _) => unreachable!(), + Knot(_) | Unknown | Future => unreachable!(), } - } - Label::Id(n) | Label::Unnamed(n) => vis.append("_").append(RcDoc::as_string(n)).append("_"), + }; + self.state.pop_state(old, elem); + res } -} - -fn pp_record_field<'a>(field: &'a Field, recs: &RecPoints, vis: &'a str) -> RcDoc<'a> { - pp_label(&field.id, false, vis) - .append(kwd(":")) - .append(pp_ty(&field.ty, recs)) -} - -fn pp_record_fields<'a>(fs: &'a [Field], recs: &RecPoints, vis: &'a str) -> RcDoc<'a> { - if is_tuple(fs) { - let vis = if vis.is_empty() { + fn pp_label<'b>(&mut self, id: &'b SharedLabel, is_variant: bool, need_vis: bool) -> RcDoc<'b> { + let vis = if need_vis { + pp_vis(&self.state.config.visibility) + } else { RcDoc::nil() + }; + let attr = self + .state + .config + .attributes + .clone() + .map(|s| RcDoc::text(s).append(RcDoc::line())) + .unwrap_or(RcDoc::nil()); + match &**id { + Label::Named(id) => { + let (doc, is_rename) = if let Some(name) = &self.state.config.name { + (RcDoc::text(name.clone()), true) + } else { + let case = if is_variant { Some(Case::Pascal) } else { None }; + ident_(id, case) + }; + let attr = if is_rename { + attr.append("#[serde(rename=\"") + .append(id.escape_debug().to_string()) + .append("\")]") + .append(RcDoc::line()) + } else { + attr + }; + attr.append(vis).append(doc) + } + Label::Id(n) | Label::Unnamed(n) => { + // TODO rename + vis.append("_").append(RcDoc::as_string(n)).append("_") + } + } + } + fn pp_tuple<'b>(&mut self, fs: &'b [Field], need_vis: bool, is_ref: bool) -> RcDoc<'b> { + let tuple = fs.iter().enumerate().map(|(i, f)| { + let lab = i.to_string(); + let old = self.state.push_state(&StateElem::Label(&lab)); + let vis = if need_vis { + pp_vis(&self.state.config.visibility) + } else { + RcDoc::nil() + }; + let res = vis.append(self.pp_ty(&f.ty, is_ref)).append(","); + self.state.pop_state(old, StateElem::Label(&lab)); + res + }); + enclose("(", RcDoc::concat(tuple), ")") + } + fn pp_record_field<'b>(&mut self, field: &'b Field, need_vis: bool, is_ref: bool) -> RcDoc<'b> { + let lab = field.id.to_string(); + let old = self.state.push_state(&StateElem::Label(&lab)); + let res = self + .pp_label(&field.id, false, need_vis) + .append(kwd(":")) + .append(self.pp_ty(&field.ty, is_ref)); + self.state.pop_state(old, StateElem::Label(&lab)); + res + } + fn pp_record_fields<'b>(&mut self, fs: &'b [Field], need_vis: bool, is_ref: bool) -> RcDoc<'b> { + let old = self.state.push_state(&StateElem::TypeStr("record")); + let res = if is_tuple(fs) { + // TODO check if there is no name/attr in the label subtree + self.pp_tuple(fs, need_vis, is_ref) } else { - kwd(vis) + let fields: Vec<_> = fs + .iter() + .map(|f| self.pp_record_field(f, need_vis, is_ref)) + .collect(); + let fields = concat(fields.into_iter(), ","); + enclose_space("{", fields, "}") }; - let tuple = RcDoc::concat( - fs.iter() - .map(|f| vis.clone().append(pp_ty(&f.ty, recs)).append(",")), - ); - enclose("(", tuple, ")") - } else { - let fields = concat(fs.iter().map(|f| pp_record_field(f, recs, vis)), ","); - enclose_space("{", fields, "}") + self.state.pop_state(old, StateElem::TypeStr("record")); + res } -} - -fn pp_variant_field<'a>(field: &'a Field, recs: &RecPoints) -> RcDoc<'a> { - match field.ty.as_ref() { - TypeInner::Null => pp_label(&field.id, true, ""), - TypeInner::Record(fs) => { - pp_label(&field.id, true, "").append(pp_record_fields(fs, recs, "")) - } - _ => pp_label(&field.id, true, "").append(enclose("(", pp_ty(&field.ty, recs), ")")), + fn pp_variant_field<'b>(&mut self, field: &'b Field) -> RcDoc<'b> { + let lab = field.id.to_string(); + let old = self.state.push_state(&StateElem::Label(&lab)); + let res = match field.ty.as_ref() { + TypeInner::Null => self.pp_label(&field.id, true, false), + TypeInner::Record(fs) => self + .pp_label(&field.id, true, false) + .append(self.pp_record_fields(fs, false, false)), + _ => self.pp_label(&field.id, true, false).append(enclose( + "(", + self.pp_ty(&field.ty, false), + ")", + )), + }; + self.state.pop_state(old, StateElem::Label(&lab)); + res } -} - -fn pp_variant_fields<'a>(fs: &'a [Field], recs: &RecPoints) -> RcDoc<'a> { - let fields = concat(fs.iter().map(|f| pp_variant_field(f, recs)), ","); - enclose_space("{", fields, "}") -} - -fn pp_defs<'a>( - config: &'a Config, - env: &'a TypeEnv, - def_list: &'a [&'a str], - recs: &'a RecPoints, -) -> RcDoc<'a> { - let derive = if config.type_attributes.is_empty() { - "#[derive(CandidType, Deserialize)]" - } else { - &config.type_attributes - }; - lines(def_list.iter().map(|id| { - let ty = env.find_type(id).unwrap(); - let name = ident(id, Some(Case::Pascal)).append(" "); - let vis = "pub "; - match ty.as_ref() { - TypeInner::Record(fs) => { - let separator = if is_tuple(fs) { - RcDoc::text(";") - } else { - RcDoc::nil() - }; - str(derive) - .append(RcDoc::line()) - .append(vis) - .append("struct ") - .append(name) - .append(pp_record_fields(fs, recs, "pub")) - .append(separator) - .append(RcDoc::hardline()) + fn pp_variant_fields<'b>(&mut self, fs: &'b [Field]) -> RcDoc<'b> { + let old = self.state.push_state(&StateElem::TypeStr("variant")); + let fields: Vec<_> = fs.iter().map(|f| self.pp_variant_field(f)).collect(); + let fields = concat(fields.into_iter(), ","); + let res = enclose_space("{", fields, "}"); + self.state.pop_state(old, StateElem::TypeStr("variant")); + res + } + fn pp_defs(&mut self, def_list: &'a [&'a str]) -> RcDoc<'a> { + let mut res = Vec::with_capacity(def_list.len()); + for id in def_list { + let old = self.state.push_state(&StateElem::Label(id)); + if self.state.config.use_type.is_some() { + self.state.pop_state(old, StateElem::Label(id)); + continue; } - TypeInner::Variant(fs) => str(derive) - .append(RcDoc::line()) - .append(vis) - .append("enum ") - .append(name) - .append(pp_variant_fields(fs, recs)) - .append(RcDoc::hardline()), - TypeInner::Func(func) => str("candid::define_function!(") - .append(vis) - .append(name) - .append(": ") - .append(pp_ty_func(func)) - .append(");"), - TypeInner::Service(serv) => str("candid::define_service!(") - .append(vis) - .append(name) - .append(": ") - .append(pp_ty_service(serv)) - .append(");"), - _ => { - if recs.contains(id) { - str(derive) + let ty = self.state.env.find_type(id).unwrap(); + let name = self + .state + .config + .name + .clone() + .map(RcDoc::text) + .unwrap_or_else(|| ident(id, Some(Case::Pascal))); + let vis = pp_vis(&self.state.config.visibility); + let derive = self + .state + .config + .attributes + .clone() + .map(RcDoc::text) + .unwrap_or(RcDoc::text("#[derive(CandidType, Deserialize)]")); + let line = match ty.as_ref() { + TypeInner::Record(fs) => { + let separator = if is_tuple(fs) { + RcDoc::text(";") + } else { + RcDoc::nil() + }; + derive .append(RcDoc::line()) .append(vis) .append("struct ") - .append(ident(id, Some(Case::Pascal))) - .append(enclose("(", pp_ty(ty, recs), ")")) - .append(";") - .append(RcDoc::hardline()) - } else { - str(vis) - .append(kwd("type")) .append(name) - .append("= ") - .append(pp_ty(ty, recs)) - .append(";") + .append(" ") + .append(self.pp_record_fields(fs, true, false)) + .append(separator) } - } + TypeInner::Variant(fs) => derive + .append(RcDoc::line()) + .append(vis) + .append("enum ") + .append(name) + .append(" ") + .append(self.pp_variant_fields(fs)), + TypeInner::Func(func) => str("candid::define_function!(") + .append(vis) + .append(name) + .append(" : ") + .append(self.pp_ty_func(func)) + .append(");"), + TypeInner::Service(serv) => str("candid::define_service!(") + .append(vis) + .append(name) + .append(" : ") + .append(self.pp_ty_service(serv)) + .append(");"), + _ => { + if self.recs.contains(id) { + derive + .append(RcDoc::line()) + .append(vis) + .append("struct ") + .append(name) + .append(enclose("(", self.pp_ty(ty, false), ")")) + .append(";") + } else { + vis.append(kwd("type")) + .append(name) + .append(" = ") + .append(self.pp_ty(ty, false)) + .append(";") + } + } + }; + self.state.pop_state(old, StateElem::Label(id)); + res.push(line) } - })) -} - -fn pp_args(args: &[Type]) -> RcDoc { - let empty = RecPoints::default(); - let doc = concat(args.iter().map(|t| pp_ty(t, &empty)), ","); - enclose("(", doc, ")") -} -fn pp_ty_func(f: &Function) -> RcDoc { - let args = pp_args(&f.args); - let rets = pp_args(&f.rets); - let modes = candid::pretty::candid::pp_modes(&f.modes); - args.append(" ->") - .append(RcDoc::space()) - .append(rets.append(modes)) - .nest(INDENT_SPACE) -} -fn pp_ty_service(serv: &[(String, Type)]) -> RcDoc { - let doc = concat( - serv.iter().map(|(id, func)| { + lines(res.into_iter()) + } + fn pp_args<'b>(&mut self, args: &'b [Type], prefix: &'b str) -> RcDoc<'b> { + let doc: Vec<_> = args + .iter() + .enumerate() + .map(|(i, t)| { + let lab = format!("{prefix}{i}"); + let old = self.state.push_state(&StateElem::Label(&lab)); + let res = self.pp_ty(t, true); + self.state.pop_state(old, StateElem::Label(&lab)); + res + }) + .collect(); + let doc = concat(doc.into_iter(), ","); + enclose("(", doc, ")") + } + fn pp_ty_func<'b>(&mut self, f: &'b Function) -> RcDoc<'b> { + let lab = StateElem::TypeStr("func"); + let old = self.state.push_state(&lab); + let args = self.pp_args(&f.args, "arg"); + let rets = self.pp_args(&f.rets, "ret"); + let modes = candid::pretty::candid::pp_modes(&f.modes); + let res = args + .append(" ->") + .append(RcDoc::space()) + .append(rets.append(modes)) + .nest(INDENT_SPACE); + self.state.pop_state(old, lab); + res + } + fn pp_ty_service<'b>(&mut self, serv: &'b [(String, Type)]) -> RcDoc<'b> { + let lab = StateElem::TypeStr("service"); + let old = self.state.push_state(&lab); + let mut list = Vec::new(); + for (id, func) in serv.iter() { let func_doc = match func.as_ref() { - TypeInner::Func(ref f) => enclose("candid::func!(", pp_ty_func(f), ")"), - TypeInner::Var(_) => pp_ty(func, &RecPoints::default()).append("::ty()"), + TypeInner::Func(ref f) => enclose("candid::func!(", self.pp_ty_func(f), ")"), + TypeInner::Var(_) => self.pp_ty(func, true).append("::ty()"), _ => unreachable!(), }; - RcDoc::text("\"") - .append(id) - .append(kwd("\" :")) - .append(func_doc) - }), - ";", - ); - enclose_space("{", doc, "}") -} - -fn pp_function<'a>(config: &Config, id: &'a str, func: &'a Function) -> RcDoc<'a> { - let name = ident(id, Some(Case::Snake)); - let empty = BTreeSet::new(); - let arg_prefix = str(match config.target { - Target::CanisterCall => "&self", - Target::Agent => "&self", - Target::CanisterStub => unimplemented!(), - }); - let args = concat( - std::iter::once(arg_prefix).chain( - func.args - .iter() - .enumerate() - .map(|(i, ty)| RcDoc::as_string(format!("arg{i}: ")).append(pp_ty(ty, &empty))), - ), - ",", - ); - let rets = match config.target { - Target::CanisterCall => enclose( - "(", - RcDoc::concat(func.rets.iter().map(|ty| pp_ty(ty, &empty).append(","))), - ")", - ), - Target::Agent => match func.rets.len() { - 0 => str("()"), - 1 => pp_ty(&func.rets[0], &empty), - _ => enclose( - "(", - RcDoc::intersperse( - func.rets.iter().map(|ty| pp_ty(ty, &empty)), - RcDoc::text(", "), - ), - ")", - ), - }, - Target::CanisterStub => unimplemented!(), - }; - let sig = kwd("pub async fn") - .append(name) - .append(enclose("(", args, ")")) - .append(kwd(" ->")) - .append(enclose("Result<", rets, "> ")); - let method = id.escape_debug().to_string(); - let body = match config.target { - Target::CanisterCall => { - let args = RcDoc::concat((0..func.args.len()).map(|i| RcDoc::text(format!("arg{i},")))); - str("ic_cdk::call(self.0, \"") - .append(method) - .append("\", ") - .append(enclose("(", args, ")")) - .append(").await") - } - Target::Agent => { - let is_query = func.is_query(); - let builder_method = if is_query { "query" } else { "update" }; - let call = if is_query { "call" } else { "call_and_wait" }; - let args = RcDoc::intersperse( - (0..func.args.len()).map(|i| RcDoc::text(format!("&arg{i}"))), - RcDoc::text(", "), - ); - let blob = str("Encode!").append(enclose("(", args, ")?;")); - let rets = RcDoc::concat( - func.rets - .iter() - .map(|ty| str(", ").append(pp_ty(ty, &empty))), + list.push( + RcDoc::text("\"") + .append(id) + .append(kwd("\" :")) + .append(func_doc), ); - str("let args = ").append(blob).append(RcDoc::hardline()) - .append(format!("let bytes = self.1.{builder_method}(&self.0, \"{method}\").with_arg(args).{call}().await?;")) - .append(RcDoc::hardline()) - .append("Ok(Decode!(&bytes").append(rets).append(")?)") } - Target::CanisterStub => unimplemented!(), - }; - sig.append(enclose_space("{", body, "}")) -} - -fn pp_actor<'a>(config: &'a Config, env: &'a TypeEnv, actor: &'a Type) -> RcDoc<'a> { - // TODO trace to service before we figure out what canister means in Rust - let serv = env.as_service(actor).unwrap(); - let body = RcDoc::intersperse( - serv.iter().map(|(id, func)| { - let func = env.as_func(func).unwrap(); - pp_function(config, id, func) - }), - RcDoc::hardline(), - ); - let struct_name = config.service_name.to_case(Case::Pascal); - let service_def = match config.target { - Target::CanisterCall => format!("pub struct {}(pub Principal);", struct_name), - Target::Agent => format!( - "pub struct {}<'a>(pub Principal, pub &'a ic_agent::Agent);", - struct_name - ), - Target::CanisterStub => unimplemented!(), - }; - let service_impl = match config.target { - Target::CanisterCall => format!("impl {} ", struct_name), - Target::Agent => format!("impl<'a> {}<'a> ", struct_name), - Target::CanisterStub => unimplemented!(), - }; - let res = RcDoc::text(service_def) - .append(RcDoc::hardline()) - .append(service_impl) - .append(enclose_space("{", body, "}")) - .append(RcDoc::hardline()); - if let Some(cid) = config.canister_id { - let slice = cid - .as_slice() + let doc = concat(list.into_iter(), ";"); + let res = enclose_space("{", doc, "}"); + self.state.pop_state(old, lab); + res + } + fn pp_function(&mut self, id: &str, func: &Function) -> Method { + let old = self.state.push_state(&StateElem::Label(id)); + let name = self + .state + .config + .name + .clone() + .unwrap_or_else(|| ident(id, Some(Case::Snake)).pretty(LINE_WIDTH).to_string()); + let args: Vec<_> = func + .args .iter() - .map(|b| b.to_string()) - .collect::>() - .join(", "); - let id = RcDoc::text(format!( - "pub const CANISTER_ID : Principal = Principal::from_slice(&[{}]); // {}", - slice, cid - )); - let instance = match config.target { - Target::CanisterCall => format!( - "pub const {} : {} = {}(CANISTER_ID);", - config.service_name, struct_name, struct_name - ), - Target::Agent => "".to_string(), - Target::CanisterStub => unimplemented!(), + .enumerate() + .map(|(i, ty)| { + let lab = format!("arg{i}"); + let old = self.state.push_state(&StateElem::Label(&lab)); + let name = self + .state + .config + .name + .clone() + .unwrap_or_else(|| lab.clone()); + let res = self.pp_ty(ty, true); + self.state.pop_state(old, StateElem::Label(&lab)); + (name, res) + }) + .collect(); + let rets: Vec<_> = func + .rets + .iter() + .enumerate() + .map(|(i, ty)| { + let lab = format!("ret{i}"); + let old = self.state.push_state(&StateElem::Label(&lab)); + let res = self.pp_ty(ty, true); + self.state.pop_state(old, StateElem::Label(&lab)); + res + }) + .collect(); + let mode = if func.is_query() { "query" } else { "update" }.to_string(); + let res = Method { + name, + original_name: id.to_string(), + args: args + .into_iter() + .map(|(id, t)| (id, t.pretty(LINE_WIDTH).to_string())) + .collect(), + rets: rets + .into_iter() + .map(|x| x.pretty(LINE_WIDTH).to_string()) + .collect(), + mode, }; - res.append(id).append(RcDoc::hardline()).append(instance) - } else { + self.state.pop_state(old, StateElem::Label(id)); res } -} - -pub fn compile(config: &Config, env: &TypeEnv, actor: &Option) -> String { - let header = format!( - r#"// This is an experimental feature to generate Rust binding from Candid. -// You may want to manually adjust some of the types. -#![allow(dead_code, unused_imports)] -use {}::{{self, CandidType, Deserialize, Principal, Encode, Decode}}; -"#, - config.candid_crate - ); - let header = header - + match &config.target { - Target::CanisterCall => "use ic_cdk::api::call::CallResult as Result;\n", - Target::Agent => "type Result = std::result::Result;\n", - Target::CanisterStub => "", + fn pp_actor(&mut self, actor: &Type) -> (Vec, Option>) { + let actor = self.state.env.trace_type(actor).unwrap(); + let init = if let TypeInner::Class(args, _) = actor.as_ref() { + let old = self.state.push_state(&StateElem::Label("init")); + let args: Vec<_> = args + .iter() + .enumerate() + .map(|(i, ty)| { + let lab = format!("arg{i}"); + let old = self.state.push_state(&StateElem::Label(&lab)); + let name = self + .state + .config + .name + .clone() + .unwrap_or_else(|| lab.clone()); + let res = self.pp_ty(ty, true); + self.state.pop_state(old, StateElem::Label(&lab)); + (name, res.pretty(LINE_WIDTH).to_string()) + }) + .collect(); + self.state.pop_state(old, StateElem::Label("init")); + Some(args) + } else { + None }; + let serv = self.state.env.as_service(&actor).unwrap(); + let mut res = Vec::new(); + for (id, func) in serv.iter() { + let func = self.state.env.as_func(func).unwrap(); + res.push(self.pp_function(id, func)); + } + (res, init) + } +} +#[derive(Serialize, Debug)] +pub struct Output { + type_defs: String, + methods: Vec, + init_args: Option>, +} +#[derive(Serialize, Debug)] +pub struct Method { + name: String, + original_name: String, + args: Vec<(String, String)>, + rets: Vec, + mode: String, +} +pub fn emit_bindgen(tree: &Config, env: &TypeEnv, actor: &Option) -> Output { let (env, actor) = nominalize_all(env, actor); let def_list: Vec<_> = if let Some(actor) = &actor { chase_actor(&env, actor).unwrap() @@ -465,16 +498,72 @@ use {}::{{self, CandidType, Deserialize, Principal, Encode, Decode}}; env.0.iter().map(|pair| pair.0.as_ref()).collect() }; let recs = infer_rec(&env, &def_list).unwrap(); - let defs = pp_defs(config, &env, &def_list, &recs); - let doc = match &actor { - None => defs, - Some(actor) => { - let actor = pp_actor(config, &env, actor); - defs.append(actor) - } + let mut state = State { + state: crate::configs::State::new(&tree.0, &env), + recs, + }; + let defs = state.pp_defs(&def_list); + let (methods, init_args) = if let Some(actor) = &actor { + state.pp_actor(actor) + } else { + (Vec::new(), None) + }; + Output { + type_defs: defs.pretty(LINE_WIDTH).to_string(), + methods, + init_args, + } +} +pub fn output_handlebar(output: Output, config: ExternalConfig, template: &str) -> String { + let hbs = get_hbs(); + #[derive(Serialize)] + struct HBOutput { + #[serde(flatten)] + external: BTreeMap, + type_defs: String, + methods: Vec, + } + let data = HBOutput { + type_defs: output.type_defs, + methods: output.methods, + external: config.0, + }; + hbs.render_template(template, &data).unwrap() +} +pub struct Config(ConfigTree); +impl Config { + pub fn new(configs: Configs) -> Self { + Self(ConfigTree::from_configs("rust", configs).unwrap()) + } +} +pub struct ExternalConfig(pub BTreeMap); +impl Default for ExternalConfig { + fn default() -> Self { + Self( + [ + ("candid_crate", "candid"), + ("service_name", "service"), + ("target", "canister_call"), + ] + .into_iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(), + ) + } +} +pub fn compile( + tree: &Config, + env: &TypeEnv, + actor: &Option, + external: ExternalConfig, +) -> String { + let source = match external.0.get("target").map(|s| s.as_str()) { + Some("canister_call") | None => include_str!("rust_call.hbs"), + Some("agent") => include_str!("rust_agent.hbs"), + _ => unimplemented!(), }; - let doc = RcDoc::text(header).append(RcDoc::line()).append(doc); - doc.pretty(LINE_WIDTH).to_string() + let output = emit_bindgen(tree, env, actor); + output_handlebar(output, external, source) } pub enum TypePath { @@ -665,3 +754,104 @@ fn nominalize_all(env: &TypeEnv, actor: &Option) -> (TypeEnv, Option .map(|ty| nominalize(&mut res, &mut vec![], ty)); (res, actor) } + +fn get_hbs() -> handlebars::Handlebars<'static> { + use handlebars::*; + let mut hbs = Handlebars::new(); + hbs.register_escape_fn(handlebars::no_escape); + hbs.set_strict_mode(true); + hbs.register_helper( + "escape_debug", + Box::new( + |h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output| + -> HelperResult { + let s = h.param(0).unwrap().value().as_str().unwrap(); + out.write(&s.escape_debug().to_string())?; + Ok(()) + }, + ), + ); + hbs.register_helper( + "snake_case", + Box::new( + |h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output| + -> HelperResult { + let s = h.param(0).unwrap().value().as_str().unwrap(); + out.write(s.to_case(Case::Snake).as_ref())?; + Ok(()) + }, + ), + ); + hbs.register_helper( + "PascalCase", + Box::new( + |h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output| + -> HelperResult { + let s = h.param(0).unwrap().value().as_str().unwrap(); + out.write(s.to_case(Case::Pascal).as_ref())?; + Ok(()) + }, + ), + ); + hbs.register_helper( + "vec_to_arity", + Box::new( + |h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output| + -> HelperResult { + let vec: Vec<_> = h + .param(0) + .unwrap() + .value() + .as_array() + .unwrap() + .iter() + .map(|v| v.as_str().unwrap()) + .collect(); + match vec.len() { + 1 => out.write(vec[0])?, + _ => out.write(&format!("({})", vec.join(", ")))?, + } + Ok(()) + }, + ), + ); + hbs.register_helper( + "principal_slice", + Box::new( + |h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output| + -> HelperResult { + let s = h.param(0).unwrap().value().as_str().unwrap(); + let id = crate::Principal::from_text(s).unwrap(); + let slice = id + .as_slice() + .iter() + .map(|b| b.to_string()) + .collect::>() + .join(", "); + out.write(slice.as_str())?; + Ok(()) + }, + ), + ); + hbs +} diff --git a/rust/candid_parser/src/bindings/rust_agent.hbs b/rust/candid_parser/src/bindings/rust_agent.hbs new file mode 100644 index 00000000..f48fefc6 --- /dev/null +++ b/rust/candid_parser/src/bindings/rust_agent.hbs @@ -0,0 +1,22 @@ +// This is an experimental feature to generate Rust binding from Candid. +// You may want to manually adjust some of the types. +#![allow(dead_code, unused_imports)] +use {{candid_crate}}::{self, CandidType, Deserialize, Principal, Encode, Decode}; +type Result = std::result::Result; + +{{type_defs}} +{{#if methods}} +pub struct {{PascalCase service_name}}<'a>(pub Principal, pub &'a ic_agent::Agent); +impl<'a> {{PascalCase service_name}}<'a> { + {{#each methods}} + pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: {{this.1}}{{/each}}) -> Result<{{vec_to_arity this.rets}}> { + let args = Encode!({{#each this.args}}&{{this.0}}{{#unless @last}},{{/unless}}{{/each}})?; + let bytes = self.1.{{this.mode}}(&self.0, "{{escape_debug this.original_name}}").with_arg(args).{{#if (eq this.mode "query")}}call{{else}}call_and_wait(){{/if}}.await?; + Ok(Decode!(&bytes{{#each this.rets}}, {{this}}{{/each}})?) + } + {{/each}} +} +{{#if canister_id}} +pub const CANISTER_ID : Principal = Principal::from_slice(&[{{principal_slice canister_id}}]); // {{canister_id}} +{{/if}} +{{/if}} diff --git a/rust/candid_parser/src/bindings/rust_call.hbs b/rust/candid_parser/src/bindings/rust_call.hbs new file mode 100644 index 00000000..6be0fe4b --- /dev/null +++ b/rust/candid_parser/src/bindings/rust_call.hbs @@ -0,0 +1,21 @@ +// This is an experimental feature to generate Rust binding from Candid. +// You may want to manually adjust some of the types. +#![allow(dead_code, unused_imports)] +use {{candid_crate}}::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use ic_cdk::api::call::CallResult as Result; + +{{type_defs}} +{{#if methods}} +pub struct {{PascalCase service_name}}(pub Principal); +impl {{PascalCase service_name}} { + {{#each methods}} + pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: {{this.1}}{{/each}}) -> Result<({{#each this.rets}}{{this}},{{/each}})> { + ic_cdk::call(self.0, "{{escape_debug this.original_name}}", ({{#each this.args}}{{this.0}},{{/each}})).await + } + {{/each}} +} +{{#if canister_id}} +pub const CANISTER_ID : Principal = Principal::from_slice(&[{{principal_slice canister_id}}]); // {{canister_id}} +pub const {{snake_case service_name}} : {{PascalCase service_name}} = {{PascalCase service_name}}(CANISTER_ID); +{{/if}} +{{/if}} diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index 7acceb41..c711e4fd 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -1,82 +1,421 @@ -use crate::Result; -use candid::types::Type; +use anyhow::Result; +use candid::types::{Type, TypeEnv, TypeInner}; use serde::de::DeserializeOwned; -use serde_dhall::{from_simple_value, SimpleValue}; +use std::collections::BTreeMap; +use toml::{Table, Value}; -pub struct Configs(SimpleValue); +pub struct State<'a, T: ConfigState> { + tree: &'a ConfigTree, + open_tree: Option<&'a ConfigTree>, + path: Vec, + pub config: T, + pub env: &'a TypeEnv, +} +#[derive(Debug)] +pub enum StateElem<'a> { + Type(&'a Type), + TypeStr(&'a str), + Label(&'a str), +} +#[derive(Debug)] +pub struct Scope<'a> { + pub method: &'a str, + pub position: Option, +} +#[derive(Debug)] +pub enum ScopePos { + Arg, + Ret, +} -impl Configs { - pub fn from_dhall(v: &str) -> Result { - let v = serde_dhall::from_str(v).parse::()?; - Ok(Configs(v)) +impl<'a, T: ConfigState> State<'a, T> { + pub fn new(tree: &'a ConfigTree, env: &'a TypeEnv) -> Self { + let mut config = T::default(); + if let Some(state) = &tree.state { + config.merge_config(state, None, false); + } + Self { + tree, + open_tree: None, + path: Vec::new(), + config, + env, + } } - pub fn with_method(&self, method: &str) -> Self { - let path = format!("[{method}]"); - let mut res = self.0.clone(); - if let SimpleValue::Record(ref mut map) = res { - if let Some(SimpleValue::Record(mut subtree)) = map.remove(&path) { - map.append(&mut subtree); + /// Match paths in the scope first. If `scope` is None, clear the scope. + pub fn with_scope(&mut self, scope: &Option, idx: usize) { + match scope { + None => self.open_tree = None, + Some(scope) => { + let mut path = vec![format!("method:{}", scope.method)]; + match self.tree.with_prefix(&path) { + Some(tree) => { + match scope.position { + Some(ScopePos::Arg) => path.push(format!("arg:{}", idx)), + Some(ScopePos::Ret) => path.push(format!("ret:{}", idx)), + None => (), + } + self.open_tree = self.tree.with_prefix(&path).or(Some(tree)); + if let Some(state) = self.open_tree.unwrap().state.as_ref() { + self.config.merge_config(state, None, false); + } + } + None => self.open_tree = None, + } } - Configs(res) + } + } + /// Update config based on the new elem in the path. Return the old state AFTER `update_state`. + pub fn push_state(&mut self, elem: &StateElem) -> T { + self.config.update_state(elem); + let old_config = self.config.clone(); + self.path.push(elem.to_string()); + let new_state = if let Some(subtree) = self.open_tree { + subtree + .get_config(&self.path) + .or_else(|| self.tree.get_config(&self.path)) } else { - unreachable!() + self.tree.get_config(&self.path) + }; + if let Some((state, is_recursive)) = new_state { + self.config.merge_config(state, Some(elem), is_recursive); + //eprintln!("match path: {:?}, state: {:?}", self.path, self.config); + } else { + self.config + .merge_config(&T::unmatched_config(), Some(elem), false); + //eprintln!("path: {:?}, state: {:?}", self.path, self.config); } + old_config } - fn get_helper(&self, path: &[String]) -> Option<&SimpleValue> { - let mut result = &self.0; - for elem in path.iter() { - if let SimpleValue::Record(map) = result { - result = map.get(elem)?; + pub fn pop_state(&mut self, old_config: T, elem: StateElem) { + self.config = old_config; + assert_eq!(self.path.pop(), Some(elem.to_string())); + self.config.restore_state(&elem); + } +} + +pub trait ConfigState: DeserializeOwned + Default + Clone + std::fmt::Debug { + fn merge_config(&mut self, config: &Self, elem: Option<&StateElem>, is_recursive: bool); + fn update_state(&mut self, elem: &StateElem); + fn restore_state(&mut self, elem: &StateElem); + fn unmatched_config() -> Self { + Self::default() + } +} +#[derive(Debug)] +pub struct ConfigTree { + state: Option, + subtree: BTreeMap>, + // max_depth is only here to optimize the performance of `get_config` + max_depth: u8, +} +impl ConfigTree { + pub fn from_configs(kind: &str, configs: Configs) -> Result { + let mut map = configs.0; + if let Some(v) = map.remove(kind) { + generate_state_tree(v) + } else { + generate_state_tree(Value::Table(map)) + } + } + /// Return the subtree starting with prefix + pub fn with_prefix(&self, prefix: &[String]) -> Option<&Self> { + let mut tree = self; + for elem in prefix.iter() { + tree = tree.subtree.get(elem)?; + } + Some(tree) + } + pub fn add_config(&mut self, path: &[String], config: T) { + let n = path.len(); + let mut tree: &Self = self; + let mut i = 0; + while i < n { + if let Some(subtree) = tree.subtree.get(&path[i]) { + tree = subtree; + i += 1; } else { - unreachable!() + break; + } + } + let mut node = Self { + state: Some(config.clone()), + subtree: BTreeMap::default(), + max_depth: 0, + }; + for k in (i + 1..n).rev() { + node = Self { + state: None, + max_depth: node.max_depth + 1, + subtree: [(path[k].clone(), node)].into_iter().collect(), } } - if has_leaf(result) { - Some(result) + let mut tree = self; + let mut d = n as u8; + #[allow(clippy::needless_range_loop)] + for k in 0..i { + tree.max_depth = std::cmp::max(d, tree.max_depth); + tree = tree.subtree.get_mut(&path[k]).unwrap(); + d -= 1; + } + if i == n { + tree.state = Some(config); } else { - None + tree.subtree.insert(path[i].clone(), node); + tree.max_depth = std::cmp::max(d, tree.max_depth); } } - /// Get config that starts somewhere in the path and ends at the end of the path. - /// The second return bool is whether the matched path appears earlier in the path (inside a recursion). - /// Empty path returns the top-level config. - pub fn get(&self, path: &[String]) -> Option<(T, bool)> { - if path.is_empty() { - return Some((from_simple_value::(self.0.clone()).ok()?, false)); - } - for i in (0..path.len()).rev() { - let (_, tail) = path.split_at(i); - match self.get_helper(tail) { - Some(v) => { - let parsed_config = from_simple_value::(v.clone()).ok()?; - return Some((parsed_config, is_repeated(path, tail))); - } + pub fn get_config(&self, path: &[String]) -> Option<(&T, bool)> { + let len = path.len(); + assert!(len > 0); + let start = len.saturating_sub(self.max_depth as usize); + for i in (start..len).rev() { + let (path, tail) = path.split_at(i); + match self.match_exact_path(tail) { + Some(v) => return Some((v, is_repeated(path, tail))), None => continue, } } None } + fn match_exact_path(&self, path: &[String]) -> Option<&T> { + let mut result = self; + for elem in path.iter() { + result = result.subtree.get(elem)?; + } + result.state.as_ref() + } +} + +pub struct Configs(Table); + +impl std::str::FromStr for Configs { + type Err = crate::Error; + fn from_str(v: &str) -> Result { + let v = v.parse::()?; + Ok(Configs(v)) + } +} +impl<'a> std::fmt::Display for StateElem<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + StateElem::Type(t) => write!(f, "{}", path_name(t)), + StateElem::Label(l) => write!(f, "{}", l), + StateElem::TypeStr(s) => write!(f, "{}", s), + } + } } fn is_repeated(path: &[String], matched: &[String]) -> bool { - let (test, _) = path.split_at(path.len() - matched.len()); - test.join(".").contains(&matched.join(".")) + let iter = path.as_ref().windows(matched.len()); + for slice in iter { + if slice == matched { + return true; + } + } + false +} + +fn special_key(key: &str) -> bool { + key.starts_with("method:") || key.starts_with("arg:") || key.starts_with("ret:") } -fn has_leaf(v: &SimpleValue) -> bool { - if let SimpleValue::Record(map) = v { - for (_, val) in map.iter() { - match val { - SimpleValue::Record(_) => continue, - _ => return true, +fn generate_state_tree(v: Value) -> Result> { + let mut subtree = BTreeMap::new(); + let mut leaves = toml::Table::new(); + let mut depth = 0; + if let Value::Table(map) = v { + for (k, v) in map.into_iter() { + match v { + Value::Table(_) => { + let v = generate_state_tree(v)?; + let dep = if special_key(&k) { + v.max_depth + } else { + v.max_depth + 1 + }; + depth = std::cmp::max(depth, dep); + subtree.insert(k, v); + } + v => drop(leaves.insert(k, v)), } } - false + let state = if !leaves.is_empty() { + Some(leaves.try_into::()?) + } else { + None + }; + Ok(ConfigTree { + state, + subtree, + max_depth: depth, + }) } else { - false + Err(anyhow::anyhow!("Expected a table")) } } pub fn path_name(t: &Type) -> String { - t.to_string().split(' ').next().unwrap().to_string() + match t.as_ref() { + TypeInner::Null => "null", + TypeInner::Bool => "bool", + TypeInner::Nat => "nat", + TypeInner::Int => "int", + TypeInner::Nat8 => "nat8", + TypeInner::Nat16 => "nat16", + TypeInner::Nat32 => "nat32", + TypeInner::Nat64 => "nat64", + TypeInner::Int8 => "int8", + TypeInner::Int16 => "int16", + TypeInner::Int32 => "int32", + TypeInner::Int64 => "int64", + TypeInner::Float32 => "float32", + TypeInner::Float64 => "float64", + TypeInner::Text => "text", + TypeInner::Reserved => "reserved", + TypeInner::Empty => "empty", + TypeInner::Var(id) => id, + TypeInner::Knot(id) => id.name, + TypeInner::Principal => "principal", + TypeInner::Opt(_) => "opt", + TypeInner::Vec(t) if matches!(t.as_ref(), TypeInner::Nat8) => "blob", + TypeInner::Vec(_) => "vec", + TypeInner::Record(_) => "record", + TypeInner::Variant(_) => "variant", + TypeInner::Func(_) => "func", + TypeInner::Service(_) => "service", + TypeInner::Future => "future", + TypeInner::Class(..) | TypeInner::Unknown => unreachable!(), + } + .to_string() +} + +#[test] +fn parse() { + use serde::Deserialize; + #[derive(Debug, Deserialize, Clone, PartialEq, Default)] + struct T { + depth: Option, + size: Option, + text: Option, + } + impl ConfigState for T { + fn merge_config(&mut self, config: &Self, _elem: Option<&StateElem>, is_recursive: bool) { + *self = config.clone(); + if is_recursive { + self.size = Some(0); + } + } + fn update_state(&mut self, _elem: &StateElem) { + self.size = self.size.map(|s| s + 1); + } + fn restore_state(&mut self, _elem: &StateElem) { + self.size = self.size.map(|s| s - 1); + } + } + let toml = r#" +[random] +list = { depth = 20, size = 50 } +val.text = "42" +left.list = { depth = 1 } +vec.nat8.text = "blob" +Vec = { width = 2, size = 10 } +"method:f"."arg:0".list = { depth = 2, size = 20 } +"method:f".list = { depth = 3, size = 30 } + "#; + let configs = toml.parse::().unwrap(); + let mut tree: ConfigTree = ConfigTree::from_configs("random", configs).unwrap(); + assert_eq!(tree.state, None); + assert_eq!(tree.subtree.len(), 6); + assert_eq!(tree.max_depth, 2); + assert_eq!( + tree.get_config(&["list".to_string()]).unwrap().0.depth, + Some(20) + ); + let t = T { + text: None, + depth: Some(100), + size: None, + }; + tree.add_config(&[], t.clone()); + assert_eq!(tree.state, Some(t.clone())); + tree.add_config(&["left".to_string(), "list".to_string()], t.clone()); + assert_eq!( + tree.match_exact_path(&["left".to_string(), "list".to_string()]) + .unwrap() + .depth, + Some(100) + ); + assert_eq!( + tree.match_exact_path(&["left".to_string(), "a".to_string()]), + None + ); + tree.add_config(&["left".to_string(), "a".to_string()], t.clone()); + assert_eq!( + tree.match_exact_path(&["left".to_string(), "a".to_string()]) + .unwrap() + .depth, + Some(100) + ); + assert_eq!(tree.max_depth, 2); + tree.add_config( + &["a".to_string(), "b".to_string(), "c".to_string()], + t.clone(), + ); + assert_eq!( + tree.match_exact_path(&["a".to_string(), "b".to_string(), "c".to_string()]) + .unwrap() + .depth, + Some(100) + ); + assert_eq!(tree.max_depth, 3); + tree.add_config( + &["a".to_string(), "b".to_string(), "d".to_string()], + t.clone(), + ); + assert_eq!(tree.max_depth, 3); + tree.add_config( + &[ + "a".to_string(), + "b".to_string(), + "c".to_string(), + "d".to_string(), + ], + t.clone(), + ); + assert_eq!(tree.max_depth, 4); + let env = TypeEnv::default(); + let mut state = State::new(&tree, &env); + state.with_scope( + &Some(Scope { + method: "f", + position: Some(ScopePos::Arg), + }), + 0, + ); + let old = state.push_state(&StateElem::Label("list")); + assert_eq!(state.config.depth, Some(2)); + assert_eq!(state.config.size, Some(20)); + assert_eq!(state.config.text, None); + assert_eq!(old.size, None); + state.push_state(&StateElem::Label("val")); + assert_eq!(state.config.text, Some("42".to_string())); + state.with_scope( + &Some(Scope { + method: "f", + position: None, + }), + 0, + ); + state.push_state(&StateElem::Label("list")); + assert_eq!(state.config.depth, Some(3)); + assert_eq!(state.config.size, Some(0)); + state.with_scope(&None, 0); + let old = state.push_state(&StateElem::Label("list")); + assert_eq!(state.config.depth, Some(20)); + assert_eq!(state.config.size, Some(0)); + assert_eq!(old.size, Some(1)); + state.pop_state(old, StateElem::Label("list")); + assert_eq!(state.config.size, Some(0)); + assert_eq!(state.config.depth, Some(3)); } diff --git a/rust/candid_parser/src/error.rs b/rust/candid_parser/src/error.rs index 1bceb030..75b46e3e 100644 --- a/rust/candid_parser/src/error.rs +++ b/rust/candid_parser/src/error.rs @@ -99,11 +99,9 @@ impl From for Error { } } -#[cfg_attr(docsrs, doc(cfg(feature = "configs")))] -#[cfg(feature = "configs")] -impl From for Error { - fn from(e: serde_dhall::Error) -> Error { - Error::msg(format!("dhall error: {e}")) +impl From for Error { + fn from(e: toml::de::Error) -> Error { + Error::msg(format!("toml error: {e}")) } } diff --git a/rust/candid_parser/src/lib.rs b/rust/candid_parser/src/lib.rs index dc034d5b..9853c3d0 100644 --- a/rust/candid_parser/src/lib.rs +++ b/rust/candid_parser/src/lib.rs @@ -136,8 +136,6 @@ pub use candid::*; #[cfg_attr(docsrs, doc(cfg(feature = "assist")))] #[cfg(feature = "assist")] pub mod assist; -#[cfg_attr(docsrs, doc(cfg(feature = "configs")))] -#[cfg(feature = "configs")] pub mod configs; #[cfg_attr(docsrs, doc(cfg(feature = "random")))] #[cfg(feature = "random")] diff --git a/rust/candid_parser/src/random.rs b/rust/candid_parser/src/random.rs index de8bd428..0fdc81bf 100644 --- a/rust/candid_parser/src/random.rs +++ b/rust/candid_parser/src/random.rs @@ -1,4 +1,5 @@ -use super::configs::{path_name, Configs}; +use super::configs::{ConfigState, Configs, Scope, State}; +use crate::configs::StateElem; use crate::{Error, Result}; use arbitrary::{unstructured::Int, Arbitrary, Unstructured}; use candid::types::value::{IDLArgs, IDLField, IDLValue, VariantValue}; @@ -30,124 +31,91 @@ impl Default for GenConfig { } } } -impl GenConfig { - pub fn update(&self, config: GenConfig, recursive: bool) -> GenConfig { - // TODO support removing properties - let old = self.clone(); - GenConfig { - range: config.range.or(old.range), - text: config.text.or(old.text), - value: config.value.or(old.value), - width: config.width.or(old.width), - // These properties only update when it's not inside a recursion. - depth: if recursive { None } else { config.depth }, - size: if recursive { None } else { config.size }, +impl ConfigState for GenConfig { + fn merge_config(&mut self, config: &Self, _elem: Option<&StateElem>, is_recursive: bool) { + self.range = config.range.or(self.range); + if config.text.is_some() { + self.text.clone_from(&config.text); } - } -} - -pub struct GenState<'a> { - tree: &'a Configs, - env: &'a TypeEnv, - // state - path: Vec, - config: GenConfig, - depth: isize, - size: isize, -} -impl<'a> GenState<'a> { - fn new(tree: &'a Configs, env: &'a TypeEnv) -> Self { - let mut config = GenConfig::default(); - if let Some((global_config, _)) = tree.get::(&[]) { - config = config.update(global_config, false); + self.width = config.width.or(self.width); + if config.value.is_some() { + self.value.clone_from(&config.value); } - GenState { - depth: config.depth.take().unwrap_or(5), - size: config.size.take().unwrap_or(50), - tree, - config, - env, - path: Vec::new(), + if !is_recursive { + self.depth = config.depth.or(self.depth); + self.size = config.size.or(self.size); } } - // Update state and return the old config state. Label and var type are cost free. - fn push_state(&mut self, ty: &Type, label: Option) -> GenConfig { - let elem = if let Some(lab) = label { - lab - } else { - match ty.as_ref() { - TypeInner::Var(_) => (), - _ => { - self.depth -= 1; - self.size -= 1; - } + fn update_state(&mut self, elem: &StateElem) { + if let StateElem::Type(t) = elem { + if !matches!(t.as_ref(), TypeInner::Var(_)) { + self.depth = self.depth.map(|d| d - 1); + self.size = self.size.map(|s| s - 1); } - path_name(ty) - }; - let mut old_config = self.config.clone(); - self.path.push(elem); - if let Some((config, recursive)) = self.tree.get::(&self.path) { - self.config = self.config.update(config, recursive); } - // Current depth and size are stored in old_config for pop_state to restore states. - old_config.depth = Some(self.depth); - old_config.size = Some(self.size); - self.depth = self.config.depth.take().unwrap_or(self.depth); - self.size = self.config.size.take().unwrap_or(self.size); - old_config } - fn pop_state(&mut self, old_config: GenConfig, ty: &Type, is_label: bool) { - if !is_label { - match ty.as_ref() { - TypeInner::Var(_) => (), - _ => { - self.depth += 1; - } + fn restore_state(&mut self, elem: &StateElem) { + if let StateElem::Type(t) = elem { + if !matches!(t.as_ref(), TypeInner::Var(_)) { + self.depth = self.depth.map(|d| d + 1); } } - self.path.pop(); - self.config = old_config; - self.depth = self.config.depth.take().unwrap(); - self.size = self.config.size.take().unwrap(); } + fn unmatched_config() -> Self { + GenConfig { + range: None, + text: None, + width: None, + value: None, + depth: None, + size: None, + } + } +} + +pub struct RandState<'a>(State<'a, GenConfig>); +impl<'a> RandState<'a> { pub fn any(&mut self, u: &mut Unstructured, ty: &Type) -> Result { - let old_config = self.push_state(ty, None); - assert!(self.config.depth.is_none()); - if let Some(vec) = &self.config.value { + let old_config = self.0.push_state(&StateElem::Type(ty)); + if let Some(vec) = &self.0.config.value { let v = u.choose(vec)?; let v: IDLValue = super::parse_idl_value(v)?; - let v = v.annotate_type(true, self.env, ty)?; - self.pop_state(old_config, ty, false); + let v = v.annotate_type(true, self.0.env, ty)?; + self.0.pop_state(old_config, StateElem::Type(ty)); return Ok(v); } let res = Ok(match ty.as_ref() { TypeInner::Var(id) => { - let ty = self.env.rec_find_type(id)?; + let ty = self.0.env.rec_find_type(id)?; self.any(u, ty)? } TypeInner::Null => IDLValue::Null, TypeInner::Reserved => IDLValue::Reserved, TypeInner::Bool => IDLValue::Bool(u.arbitrary()?), - TypeInner::Int => IDLValue::Int(arbitrary_num::(u, self.config.range)?.into()), - TypeInner::Nat => IDLValue::Nat(arbitrary_num::(u, self.config.range)?.into()), - TypeInner::Nat8 => IDLValue::Nat8(arbitrary_num(u, self.config.range)?), - TypeInner::Nat16 => IDLValue::Nat16(arbitrary_num(u, self.config.range)?), - TypeInner::Nat32 => IDLValue::Nat32(arbitrary_num(u, self.config.range)?), - TypeInner::Nat64 => IDLValue::Nat64(arbitrary_num(u, self.config.range)?), - TypeInner::Int8 => IDLValue::Int8(arbitrary_num(u, self.config.range)?), - TypeInner::Int16 => IDLValue::Int16(arbitrary_num(u, self.config.range)?), - TypeInner::Int32 => IDLValue::Int32(arbitrary_num(u, self.config.range)?), - TypeInner::Int64 => IDLValue::Int64(arbitrary_num(u, self.config.range)?), + TypeInner::Int => IDLValue::Int(arbitrary_num::(u, self.0.config.range)?.into()), + TypeInner::Nat => IDLValue::Nat(arbitrary_num::(u, self.0.config.range)?.into()), + TypeInner::Nat8 => IDLValue::Nat8(arbitrary_num(u, self.0.config.range)?), + TypeInner::Nat16 => IDLValue::Nat16(arbitrary_num(u, self.0.config.range)?), + TypeInner::Nat32 => IDLValue::Nat32(arbitrary_num(u, self.0.config.range)?), + TypeInner::Nat64 => IDLValue::Nat64(arbitrary_num(u, self.0.config.range)?), + TypeInner::Int8 => IDLValue::Int8(arbitrary_num(u, self.0.config.range)?), + TypeInner::Int16 => IDLValue::Int16(arbitrary_num(u, self.0.config.range)?), + TypeInner::Int32 => IDLValue::Int32(arbitrary_num(u, self.0.config.range)?), + TypeInner::Int64 => IDLValue::Int64(arbitrary_num(u, self.0.config.range)?), TypeInner::Float32 => IDLValue::Float32(u.arbitrary()?), TypeInner::Float64 => IDLValue::Float64(u.arbitrary()?), - TypeInner::Text => { - IDLValue::Text(arbitrary_text(u, &self.config.text, &self.config.width)?) - } + TypeInner::Text => IDLValue::Text(arbitrary_text( + u, + &self.0.config.text, + &self.0.config.width, + )?), TypeInner::Opt(t) => { - let depths = if self.depth <= 0 || self.size <= 0 { + let depths = if self.0.config.depth.is_some_and(|d| d <= 0) + || self.0.config.size.is_some_and(|s| s <= 0) + { [1, 0] } else { - [1, size(self.env, t).unwrap_or(MAX_DEPTH)] + [1, size(self.0.env, t).unwrap_or(MAX_DEPTH)] }; let idx = arbitrary_variant(u, &depths)?; if idx == 0 { @@ -157,9 +125,9 @@ impl<'a> GenState<'a> { } } TypeInner::Vec(t) => { - let width = self.config.width.or_else(|| { - let elem_size = size(self.env, t).unwrap_or(MAX_DEPTH); - Some(std::cmp::max(0, self.size) as usize / elem_size) + let width = self.0.config.width.or_else(|| { + let elem_size = size(self.0.env, t).unwrap_or(MAX_DEPTH); + Some(std::cmp::max(0, self.0.config.size.unwrap_or(0)) as usize / elem_size) }); let len = arbitrary_len(u, width)?; let mut vec = Vec::with_capacity(len); @@ -172,9 +140,11 @@ impl<'a> GenState<'a> { TypeInner::Record(fs) => { let mut res = Vec::new(); for Field { id, ty } in fs.iter() { - let old_config = self.push_state(ty, Some(id.to_string())); + let lab_str = id.to_string(); + let elem = StateElem::Label(&lab_str); + let old_config = self.0.push_state(&elem); let val = self.any(u, ty)?; - self.pop_state(old_config, ty, true); + self.0.pop_state(old_config, elem); res.push(IDLField { id: id.as_ref().clone(), val, @@ -185,8 +155,10 @@ impl<'a> GenState<'a> { TypeInner::Variant(fs) => { let choices = fs .iter() - .map(|Field { ty, .. }| size(self.env, ty).unwrap_or(MAX_DEPTH)); - let sizes: Vec<_> = if self.depth <= 0 || self.size <= 0 { + .map(|Field { ty, .. }| size(self.0.env, ty).unwrap_or(MAX_DEPTH)); + let sizes: Vec<_> = if self.0.config.depth.is_some_and(|d| d <= 0) + || self.0.config.size.is_some_and(|s| s <= 0) + { let min = choices.clone().min().unwrap_or(0); choices.map(|d| if d > min { 0 } else { d }).collect() } else { @@ -194,9 +166,11 @@ impl<'a> GenState<'a> { }; let idx = arbitrary_variant(u, &sizes)?; let Field { id, ty } = &fs[idx]; - let old_config = self.push_state(ty, Some(id.to_string())); + let lab_str = id.to_string(); + let elem = StateElem::Label(&lab_str); + let old_config = self.0.push_state(&elem); let val = self.any(u, ty)?; - self.pop_state(old_config, ty, true); + self.0.pop_state(old_config, elem); let field = IDLField { id: id.as_ref().clone(), val, @@ -206,22 +180,31 @@ impl<'a> GenState<'a> { TypeInner::Principal => IDLValue::Principal(crate::Principal::arbitrary(u)?), TypeInner::Func(_) => IDLValue::Func( crate::Principal::arbitrary(u)?, - arbitrary_text(u, &self.config.text, &self.config.width)?, + arbitrary_text(u, &self.0.config.text, &self.0.config.width)?, ), TypeInner::Service(_) => IDLValue::Service(crate::Principal::arbitrary(u)?), _ => unimplemented!(), }); - self.pop_state(old_config, ty, false); + self.0.pop_state(old_config, StateElem::Type(ty)); res } } -pub fn any(seed: &[u8], tree: &Configs, env: &TypeEnv, types: &[Type]) -> Result { +pub fn any( + seed: &[u8], + configs: Configs, + env: &TypeEnv, + types: &[Type], + scope: &Option, +) -> Result { let mut u = arbitrary::Unstructured::new(seed); + let tree = super::configs::ConfigTree::from_configs("random", configs)?; let mut args = Vec::new(); for (i, t) in types.iter().enumerate() { - let tree = tree.with_method(&i.to_string()); - let mut state = GenState::new(&tree, env); + let mut state = State::new(&tree, env); + state.with_scope(scope, i); + let mut state = RandState(state); + state.0.push_state(&StateElem::Label(&i.to_string())); let v = state.any(&mut u, t)?; args.push(v); } diff --git a/rust/candid_parser/tests/assets/example.toml b/rust/candid_parser/tests/assets/example.toml new file mode 100644 index 00000000..90d9f14a --- /dev/null +++ b/rust/candid_parser/tests/assets/example.toml @@ -0,0 +1,11 @@ +[rust] +attributes = "#[derive(CandidType, Deserialize, Debug)]" +visibility = "pub(crate)" +List.name = "MyList" +Nested41.variant.A = { name = "AAA", attributes = "#[serde(skip_deserializing)]" } +ListInner.attributes = "#derive[CandidType, Deserialize, Clone]" +ListInner.record = { visibility = "", head.name = "HEAD", attributes = "#[serde(skip_deserializing)]", tail.use_type = "Arc" } +my_type = { visibility = "", name = "CanisterId" } +nat.use_type = "u128" +BrokerFindRet = { name = "BrokerReturn", visibility = "pub" } +g1 = { name = "G11", arg0.name = "id", arg1.name = "list", arg2.name = "is_okay", ret0.use_type = "i128" } diff --git a/rust/candid_parser/tests/assets/ok/actor.rs b/rust/candid_parser/tests/assets/ok/actor.rs index 2f2dc6ad..79138a42 100644 --- a/rust/candid_parser/tests/assets/ok/actor.rs +++ b/rust/candid_parser/tests/assets/ok/actor.rs @@ -27,3 +27,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/class.rs b/rust/candid_parser/tests/assets/ok/class.rs index 17a8df14..2198ab57 100644 --- a/rust/candid_parser/tests/assets/ok/class.rs +++ b/rust/candid_parser/tests/assets/ok/class.rs @@ -18,3 +18,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/comment.rs b/rust/candid_parser/tests/assets/ok/comment.rs index 4839a3f7..c819f2f1 100644 --- a/rust/candid_parser/tests/assets/ok/comment.rs +++ b/rust/candid_parser/tests/assets/ok/comment.rs @@ -6,3 +6,4 @@ use ic_cdk::api::call::CallResult as Result; pub type Id = u8; + diff --git a/rust/candid_parser/tests/assets/ok/cyclic.rs b/rust/candid_parser/tests/assets/ok/cyclic.rs index cb7c2821..f3fae3f3 100644 --- a/rust/candid_parser/tests/assets/ok/cyclic.rs +++ b/rust/candid_parser/tests/assets/ok/cyclic.rs @@ -8,23 +8,16 @@ pub type C = Box; pub type B = Option; #[derive(CandidType, Deserialize)] pub struct A(Option); - pub type Z = Box; pub type Y = Z; pub type X = Y; + pub struct Service(pub Principal); impl Service { - pub async fn f( - &self, - arg0: A, - arg1: B, - arg2: C, - arg3: X, - arg4: Y, - arg5: Z, - ) -> Result<()> { + pub async fn f(&self, arg0: A, arg1: B, arg2: C, arg3: X, arg4: Y, arg5: Z) -> Result<()> { ic_cdk::call(self.0, "f", (arg0,arg1,arg2,arg3,arg4,arg5,)).await } } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/empty.rs b/rust/candid_parser/tests/assets/ok/empty.rs index ee1eed61..64d70472 100644 --- a/rust/candid_parser/tests/assets/ok/empty.rs +++ b/rust/candid_parser/tests/assets/ok/empty.rs @@ -6,16 +6,12 @@ use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] pub struct FArg {} - #[derive(CandidType, Deserialize)] pub enum FRet {} - #[derive(CandidType, Deserialize)] pub struct T (pub Box,); - #[derive(CandidType, Deserialize)] pub enum GRet { #[serde(rename="a")] A(Box) } - #[derive(CandidType, Deserialize)] pub enum HRet { #[serde(rename="a")] A(Box), #[serde(rename="b")] B{} } @@ -33,3 +29,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/escape.rs b/rust/candid_parser/tests/assets/ok/escape.rs index 6325fdc9..c6b66fef 100644 --- a/rust/candid_parser/tests/assets/ok/escape.rs +++ b/rust/candid_parser/tests/assets/ok/escape.rs @@ -24,3 +24,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/example.rs b/rust/candid_parser/tests/assets/ok/example.rs index 180f01f6..18891eb8 100644 --- a/rust/candid_parser/tests/assets/ok/example.rs +++ b/rust/candid_parser/tests/assets/ok/example.rs @@ -4,83 +4,88 @@ use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; -#[derive(CandidType, Deserialize)] -pub struct B (pub candid::Int,pub candid::Nat,); - -#[derive(CandidType, Deserialize)] -pub struct Node { pub head: candid::Nat, pub tail: Box } - -#[derive(CandidType, Deserialize)] -pub struct List(Option); - -pub type A = Box; -#[derive(CandidType, Deserialize)] -pub struct B(Option); - -#[derive(CandidType, Deserialize)] -pub enum Tree { +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct B (pub(crate) candid::Int,pub(crate) u128,); +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct Node { pub(crate) head: u128, pub(crate) tail: Box } +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct List(Option); +pub(crate) type A = Box; +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct B(Option); +#[derive(CandidType, Deserialize, Debug)] +pub(crate) enum Tree { #[serde(rename="branch")] Branch{ val: candid::Int, left: Box, right: Box }, #[serde(rename="leaf")] Leaf(candid::Int), } - -candid::define_function!(pub StreamInnerNext : () -> (Stream) query); -#[derive(CandidType, Deserialize)] -pub struct StreamInner { pub head: candid::Nat, pub next: StreamInnerNext } - -#[derive(CandidType, Deserialize)] -pub struct Stream(Option); - -candid::define_service!(pub S : { +candid::define_function!(pub(crate) StreamInnerNext : () -> (Stream) query); +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct StreamInner { + pub(crate) head: u128, + pub(crate) next: StreamInnerNext, +} +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct Stream(Option); +candid::define_service!(pub(crate) S : { "f" : T::ty(); "g" : candid::func!((List) -> (B, Tree, Stream)); }); -candid::define_function!(pub T : (S) -> ()); -pub type MyType = Principal; -#[derive(CandidType, Deserialize)] -pub struct ListInner { pub head: candid::Int, pub tail: Box } - -#[derive(CandidType, Deserialize)] -pub struct List(Option); - -#[derive(CandidType, Deserialize)] -pub struct Nested3 { pub _0_: candid::Nat, pub _42_: candid::Nat, pub _43_: u8 } - -#[derive(CandidType, Deserialize)] -pub enum Nested41 { _42_, A, B, C } - -#[derive(CandidType, Deserialize)] -pub struct Nested { - pub _0_: candid::Nat, - pub _1_: candid::Nat, - pub _2_: (candid::Nat,candid::Int,), - pub _3_: Nested3, - pub _40_: candid::Nat, - pub _41_: Nested41, - pub _42_: candid::Nat, +candid::define_function!(pub(crate) T : (S) -> ()); +type CanisterId = Principal; +#derive[CandidType, Deserialize, Clone] +pub(crate) struct ListInner { + #[serde(skip_deserializing)] + #[serde(rename="head")] + HEAD: candid::Int, + #[serde(skip_deserializing)] + tail: Arc, } - -candid::define_service!(pub BrokerFindRet : { +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct MyList(Option); +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct Nested3 { + pub(crate) _0_: u128, + pub(crate) _42_: u128, + pub(crate) _43_: u8, +} +#[derive(CandidType, Deserialize, Debug)] +pub(crate) enum Nested41 { + _42_, + #[serde(skip_deserializing)] + #[serde(rename="A")] + AAA, + B, + C, +} +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct Nested { + pub(crate) _0_: u128, + pub(crate) _1_: u128, + pub(crate) _2_: (u128,candid::Int,), + pub(crate) _3_: Nested3, + pub(crate) _40_: u128, + pub(crate) _41_: Nested41, + pub(crate) _42_: u128, +} +candid::define_service!(pub BrokerReturn : { "current" : candid::func!(() -> (u32)); "up" : candid::func!(() -> ()); }); -candid::define_service!(pub Broker : { - "find" : candid::func!((String) -> (BrokerFindRet)); +candid::define_service!(pub(crate) Broker : { + "find" : candid::func!((String) -> (BrokerReturn)); }); -#[derive(CandidType, Deserialize)] -pub enum HArg1 { A(candid::Nat), B(Option) } - -#[derive(CandidType, Deserialize)] -pub struct HRet42 {} - -#[derive(CandidType, Deserialize)] -pub struct HRet { pub _42_: HRet42, pub id: candid::Nat } - -candid::define_function!(pub FArg1 : (i32) -> (i64)); -candid::define_function!(pub F : (List, FArg1) -> (Option)); -#[derive(CandidType, Deserialize)] -pub enum A { #[serde(rename="a")] A, #[serde(rename="b")] B(B) } +#[derive(CandidType, Deserialize, Debug)] +pub(crate) enum HArg1 { A(u128), B(Option) } +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct HRet42 {} +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct HRet { pub(crate) _42_: HRet42, pub(crate) id: u128 } +candid::define_function!(pub(crate) FArg1 : (i32) -> (i64)); +candid::define_function!(pub(crate) F : (MyList, FArg1) -> (Option)); +#[derive(CandidType, Deserialize, Debug)] +pub(crate) enum A { #[serde(rename="a")] A, #[serde(rename="b")] B(B) } pub struct Service(pub Principal); impl Service { @@ -90,31 +95,19 @@ impl Service { pub async fn f(&self, arg0: S) -> Result<()> { ic_cdk::call(self.0, "f", (arg0,)).await } - pub async fn f_1( - &self, - arg0: List, - arg1: serde_bytes::ByteBuf, - arg2: Option, - ) -> Result<()> { ic_cdk::call(self.0, "f1", (arg0,arg1,arg2,)).await } + pub async fn f_1(&self, arg0: List, arg1: serde_bytes::ByteBuf, arg2: Option) -> Result<()> { + ic_cdk::call(self.0, "f1", (arg0,arg1,arg2,)).await + } pub async fn g(&self, arg0: List) -> Result<(B,Tree,Stream,)> { ic_cdk::call(self.0, "g", (arg0,)).await } - pub async fn g_1( - &self, - arg0: MyType, - arg1: List, - arg2: Option, - arg3: Nested, - ) -> Result<(candid::Int,Broker,)> { - ic_cdk::call(self.0, "g1", (arg0,arg1,arg2,arg3,)).await + pub async fn G11(&self, id: CanisterId, list: MyList, is_okay: Option, arg3: Nested) -> Result<(i128,Broker,)> { + ic_cdk::call(self.0, "g1", (id,list,is_okay,arg3,)).await } - pub async fn h( - &self, - arg0: Vec>, - arg1: HArg1, - arg2: Option, - ) -> Result<(HRet,)> { ic_cdk::call(self.0, "h", (arg0,arg1,arg2,)).await } - pub async fn i(&self, arg0: List, arg1: FArg1) -> Result<(Option,)> { + pub async fn h(&self, arg0: Vec>, arg1: HArg1, arg2: Option) -> Result<(HRet,)> { + ic_cdk::call(self.0, "h", (arg0,arg1,arg2,)).await + } + pub async fn i(&self, arg0: MyList, arg1: FArg1) -> Result<(Option,)> { ic_cdk::call(self.0, "i", (arg0,arg1,)).await } pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,)> { @@ -123,3 +116,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/fieldnat.rs b/rust/candid_parser/tests/assets/ok/fieldnat.rs index a42fec7c..8cbba81a 100644 --- a/rust/candid_parser/tests/assets/ok/fieldnat.rs +++ b/rust/candid_parser/tests/assets/ok/fieldnat.rs @@ -6,32 +6,24 @@ use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] pub struct BarArg { #[serde(rename="2")] pub _50_: candid::Int } - #[derive(CandidType, Deserialize)] pub enum BarRet { #[serde(rename="e20")] E20, #[serde(rename="e30")] E30 } - #[derive(CandidType, Deserialize)] pub struct BazArg { pub _2_: candid::Int, #[serde(rename="2")] pub _50_: candid::Nat, } - #[derive(CandidType, Deserialize)] pub struct BazRet {} - #[derive(CandidType, Deserialize)] pub struct Tuple (pub String,pub String,); - #[derive(CandidType, Deserialize)] pub struct NonTuple { pub _1_: String, pub _2_: String } - #[derive(CandidType, Deserialize)] pub enum BibRet { _0_(candid::Int) } - #[derive(CandidType, Deserialize)] pub struct FooArg { pub _2_: candid::Int } - #[derive(CandidType, Deserialize)] pub struct FooRet { pub _2_: candid::Int, pub _2: candid::Int } @@ -43,9 +35,9 @@ impl Service { pub async fn bar(&self, arg0: BarArg) -> Result<(BarRet,)> { ic_cdk::call(self.0, "bar", (arg0,)).await } - pub async fn bas(&self, arg0: (candid::Int,candid::Int,)) -> Result< - ((String,candid::Nat,),) - > { ic_cdk::call(self.0, "bas", (arg0,)).await } + pub async fn bas(&self, arg0: (candid::Int,candid::Int,)) -> Result<((String,candid::Nat,),)> { + ic_cdk::call(self.0, "bas", (arg0,)).await + } pub async fn baz(&self, arg0: BazArg) -> Result<(BazRet,)> { ic_cdk::call(self.0, "baz", (arg0,)).await } @@ -61,3 +53,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/keyword.rs b/rust/candid_parser/tests/assets/ok/keyword.rs index 0010e120..fd6ce914 100644 --- a/rust/candid_parser/tests/assets/ok/keyword.rs +++ b/rust/candid_parser/tests/assets/ok/keyword.rs @@ -6,26 +6,20 @@ use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] pub struct O(Option>); - #[derive(CandidType, Deserialize)] pub struct FieldArg { pub test: u16, pub _1291438163_: u8 } - #[derive(CandidType, Deserialize)] pub struct FieldRet {} - #[derive(CandidType, Deserialize)] pub struct FieldnatArg { pub _2_: candid::Int, #[serde(rename="2")] pub _50_: candid::Nat, } - #[derive(CandidType, Deserialize)] pub struct Node { pub head: candid::Nat, pub tail: Box } - #[derive(CandidType, Deserialize)] pub struct List(Option); - #[derive(CandidType, Deserialize)] pub enum If { #[serde(rename="branch")] @@ -33,14 +27,11 @@ pub enum If { #[serde(rename="leaf")] Leaf(candid::Int), } - candid::define_function!(pub StreamInnerNext : () -> (Stream) query); #[derive(CandidType, Deserialize)] pub struct StreamInner { pub head: candid::Nat, pub next: StreamInnerNext } - #[derive(CandidType, Deserialize)] pub struct Stream(Option); - candid::define_service!(pub Return : { "f" : T::ty(); "g" : candid::func!((List) -> (If, Stream)); @@ -69,19 +60,16 @@ impl Service { pub async fn oneway(&self, arg0: u8) -> Result<()> { ic_cdk::call(self.0, "oneway_", (arg0,)).await } - pub async fn query(&self, arg0: serde_bytes::ByteBuf) -> Result< - (serde_bytes::ByteBuf,) - > { ic_cdk::call(self.0, "query", (arg0,)).await } + pub async fn query(&self, arg0: serde_bytes::ByteBuf) -> Result<(serde_bytes::ByteBuf,)> { + ic_cdk::call(self.0, "query", (arg0,)).await + } pub async fn r#return(&self, arg0: O) -> Result<(O,)> { ic_cdk::call(self.0, "return", (arg0,)).await } pub async fn service(&self, arg0: Return) -> Result<()> { ic_cdk::call(self.0, "service", (arg0,)).await } - pub async fn tuple( - &self, - arg0: (candid::Int,serde_bytes::ByteBuf,String,), - ) -> Result<((candid::Int,u8,),)> { + pub async fn tuple(&self, arg0: (candid::Int,serde_bytes::ByteBuf,String,)) -> Result<((candid::Int,u8,),)> { ic_cdk::call(self.0, "tuple", (arg0,)).await } pub async fn variant(&self, arg0: VariantArg) -> Result<()> { @@ -90,3 +78,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/management.rs b/rust/candid_parser/tests/assets/ok/management.rs index a74b2a2b..a3715bbe 100644 --- a/rust/candid_parser/tests/assets/ok/management.rs +++ b/rust/candid_parser/tests/assets/ok/management.rs @@ -11,7 +11,6 @@ pub enum BitcoinNetwork { #[serde(rename="testnet")] Testnet, } - pub type BitcoinAddress = String; #[derive(CandidType, Deserialize)] pub struct GetBalanceRequest { @@ -19,11 +18,9 @@ pub struct GetBalanceRequest { pub address: BitcoinAddress, pub min_confirmations: Option, } - pub type Satoshi = u64; #[derive(CandidType, Deserialize)] pub struct GetCurrentFeePercentilesRequest { pub network: BitcoinNetwork } - pub type MillisatoshiPerByte = u64; #[derive(CandidType, Deserialize)] pub enum GetUtxosRequestFilterInner { @@ -32,21 +29,17 @@ pub enum GetUtxosRequestFilterInner { #[serde(rename="min_confirmations")] MinConfirmations(u32), } - #[derive(CandidType, Deserialize)] pub struct GetUtxosRequest { pub network: BitcoinNetwork, pub filter: Option, pub address: BitcoinAddress, } - pub type BlockHash = serde_bytes::ByteBuf; #[derive(CandidType, Deserialize)] pub struct Outpoint { pub txid: serde_bytes::ByteBuf, pub vout: u32 } - #[derive(CandidType, Deserialize)] pub struct Utxo { pub height: u32, pub value: Satoshi, pub outpoint: Outpoint } - #[derive(CandidType, Deserialize)] pub struct GetUtxosResponse { pub next_page: Option, @@ -54,17 +47,14 @@ pub struct GetUtxosResponse { pub tip_block_hash: BlockHash, pub utxos: Vec, } - #[derive(CandidType, Deserialize)] pub struct SendTransactionRequest { pub transaction: serde_bytes::ByteBuf, pub network: BitcoinNetwork, } - pub type CanisterId = Principal; #[derive(CandidType, Deserialize)] pub struct CanisterStatusArg { pub canister_id: CanisterId } - #[derive(CandidType, Deserialize)] pub enum CanisterStatusRetStatus { #[serde(rename="stopped")] @@ -74,7 +64,6 @@ pub enum CanisterStatusRetStatus { #[serde(rename="running")] Running, } - #[derive(CandidType, Deserialize)] pub struct DefiniteCanisterSettings { pub freezing_threshold: candid::Nat, @@ -82,7 +71,6 @@ pub struct DefiniteCanisterSettings { pub memory_allocation: candid::Nat, pub compute_allocation: candid::Nat, } - #[derive(CandidType, Deserialize)] pub struct CanisterStatusRet { pub status: CanisterStatusRetStatus, @@ -92,7 +80,6 @@ pub struct CanisterStatusRet { pub idle_cycles_burned_per_day: candid::Nat, pub module_hash: Option, } - #[derive(CandidType, Deserialize)] pub struct CanisterSettings { pub freezing_threshold: Option, @@ -100,38 +87,29 @@ pub struct CanisterSettings { pub memory_allocation: Option, pub compute_allocation: Option, } - #[derive(CandidType, Deserialize)] pub struct CreateCanisterArg { pub settings: Option } - #[derive(CandidType, Deserialize)] pub struct CreateCanisterRet { pub canister_id: CanisterId } - #[derive(CandidType, Deserialize)] pub struct DeleteCanisterArg { pub canister_id: CanisterId } - #[derive(CandidType, Deserialize)] pub struct DepositCyclesArg { pub canister_id: CanisterId } - #[derive(CandidType, Deserialize)] pub enum EcdsaCurve { #[serde(rename="secp256k1")] Secp256K1 } - #[derive(CandidType, Deserialize)] pub struct EcdsaPublicKeyArgKeyId { pub name: String, pub curve: EcdsaCurve } - #[derive(CandidType, Deserialize)] pub struct EcdsaPublicKeyArg { pub key_id: EcdsaPublicKeyArgKeyId, pub canister_id: Option, pub derivation_path: Vec, } - #[derive(CandidType, Deserialize)] pub struct EcdsaPublicKeyRet { pub public_key: serde_bytes::ByteBuf, pub chain_code: serde_bytes::ByteBuf, } - #[derive(CandidType, Deserialize)] pub enum HttpRequestArgMethod { #[serde(rename="get")] @@ -141,23 +119,19 @@ pub enum HttpRequestArgMethod { #[serde(rename="post")] Post, } - #[derive(CandidType, Deserialize)] pub struct HttpHeader { pub value: String, pub name: String } - #[derive(CandidType, Deserialize)] pub struct HttpResponse { pub status: candid::Nat, pub body: serde_bytes::ByteBuf, pub headers: Vec, } - #[derive(CandidType, Deserialize)] pub struct HttpRequestArgTransformInnerFunctionArg { pub context: serde_bytes::ByteBuf, pub response: HttpResponse, } - candid::define_function!(pub HttpRequestArgTransformInnerFunction : ( HttpRequestArgTransformInnerFunctionArg, ) -> (HttpResponse) query); @@ -166,7 +140,6 @@ pub struct HttpRequestArgTransformInner { pub function: HttpRequestArgTransformInnerFunction, pub context: serde_bytes::ByteBuf, } - #[derive(CandidType, Deserialize)] pub struct HttpRequestArg { pub url: String, @@ -176,7 +149,6 @@ pub struct HttpRequestArg { pub transform: Option, pub headers: Vec, } - pub type WasmModule = serde_bytes::ByteBuf; #[derive(CandidType, Deserialize)] pub enum InstallCodeArgMode { @@ -187,7 +159,6 @@ pub enum InstallCodeArgMode { #[serde(rename="install")] Install, } - #[derive(CandidType, Deserialize)] pub struct InstallCodeArg { pub arg: serde_bytes::ByteBuf, @@ -195,47 +166,37 @@ pub struct InstallCodeArg { pub mode: InstallCodeArgMode, pub canister_id: CanisterId, } - #[derive(CandidType, Deserialize)] pub struct ProvisionalCreateCanisterWithCyclesArg { pub settings: Option, pub specified_id: Option, pub amount: Option, } - #[derive(CandidType, Deserialize)] pub struct ProvisionalCreateCanisterWithCyclesRet { pub canister_id: CanisterId, } - #[derive(CandidType, Deserialize)] pub struct ProvisionalTopUpCanisterArg { pub canister_id: CanisterId, pub amount: candid::Nat, } - #[derive(CandidType, Deserialize)] pub struct SignWithEcdsaArgKeyId { pub name: String, pub curve: EcdsaCurve } - #[derive(CandidType, Deserialize)] pub struct SignWithEcdsaArg { pub key_id: SignWithEcdsaArgKeyId, pub derivation_path: Vec, pub message_hash: serde_bytes::ByteBuf, } - #[derive(CandidType, Deserialize)] pub struct SignWithEcdsaRet { pub signature: serde_bytes::ByteBuf } - #[derive(CandidType, Deserialize)] pub struct StartCanisterArg { pub canister_id: CanisterId } - #[derive(CandidType, Deserialize)] pub struct StopCanisterArg { pub canister_id: CanisterId } - #[derive(CandidType, Deserialize)] pub struct UninstallCodeArg { pub canister_id: CanisterId } - #[derive(CandidType, Deserialize)] pub struct UpdateSettingsArg { pub canister_id: Principal, @@ -244,46 +205,32 @@ pub struct UpdateSettingsArg { pub struct Service<'a>(pub Principal, pub &'a ic_agent::Agent); impl<'a> Service<'a> { - pub async fn bitcoin_get_balance(&self, arg0: GetBalanceRequest) -> Result< - Satoshi - > { + pub async fn bitcoin_get_balance(&self, arg0: GetBalanceRequest) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "bitcoin_get_balance").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, Satoshi)?) } - pub async fn bitcoin_get_current_fee_percentiles( - &self, - arg0: GetCurrentFeePercentilesRequest, - ) -> Result> { + pub async fn bitcoin_get_current_fee_percentiles(&self, arg0: GetCurrentFeePercentilesRequest) -> Result> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "bitcoin_get_current_fee_percentiles").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, Vec)?) } - pub async fn bitcoin_get_utxos(&self, arg0: GetUtxosRequest) -> Result< - GetUtxosResponse - > { + pub async fn bitcoin_get_utxos(&self, arg0: GetUtxosRequest) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "bitcoin_get_utxos").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, GetUtxosResponse)?) } - pub async fn bitcoin_send_transaction( - &self, - arg0: SendTransactionRequest, - ) -> Result<()> { + pub async fn bitcoin_send_transaction(&self, arg0: SendTransactionRequest) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "bitcoin_send_transaction").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn canister_status(&self, arg0: CanisterStatusArg) -> Result< - CanisterStatusRet - > { + pub async fn canister_status(&self, arg0: CanisterStatusArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "canister_status").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, CanisterStatusRet)?) } - pub async fn create_canister(&self, arg0: CreateCanisterArg) -> Result< - CreateCanisterRet - > { + pub async fn create_canister(&self, arg0: CreateCanisterArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "create_canister").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, CreateCanisterRet)?) @@ -298,16 +245,12 @@ impl<'a> Service<'a> { let bytes = self.1.update(&self.0, "deposit_cycles").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn ecdsa_public_key(&self, arg0: EcdsaPublicKeyArg) -> Result< - EcdsaPublicKeyRet - > { + pub async fn ecdsa_public_key(&self, arg0: EcdsaPublicKeyArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "ecdsa_public_key").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, EcdsaPublicKeyRet)?) } - pub async fn http_request(&self, arg0: HttpRequestArg) -> Result< - HttpResponse - > { + pub async fn http_request(&self, arg0: HttpRequestArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "http_request").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, HttpResponse)?) @@ -317,18 +260,12 @@ impl<'a> Service<'a> { let bytes = self.1.update(&self.0, "install_code").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn provisional_create_canister_with_cycles( - &self, - arg0: ProvisionalCreateCanisterWithCyclesArg, - ) -> Result { + pub async fn provisional_create_canister_with_cycles(&self, arg0: ProvisionalCreateCanisterWithCyclesArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "provisional_create_canister_with_cycles").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, ProvisionalCreateCanisterWithCyclesRet)?) } - pub async fn provisional_top_up_canister( - &self, - arg0: ProvisionalTopUpCanisterArg, - ) -> Result<()> { + pub async fn provisional_top_up_canister(&self, arg0: ProvisionalTopUpCanisterArg) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "provisional_top_up_canister").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) @@ -338,9 +275,7 @@ impl<'a> Service<'a> { let bytes = self.1.update(&self.0, "raw_rand").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, serde_bytes::ByteBuf)?) } - pub async fn sign_with_ecdsa(&self, arg0: SignWithEcdsaArg) -> Result< - SignWithEcdsaRet - > { + pub async fn sign_with_ecdsa(&self, arg0: SignWithEcdsaArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "sign_with_ecdsa").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, SignWithEcdsaRet)?) diff --git a/rust/candid_parser/tests/assets/ok/recursion.rs b/rust/candid_parser/tests/assets/ok/recursion.rs index 25095093..939a8378 100644 --- a/rust/candid_parser/tests/assets/ok/recursion.rs +++ b/rust/candid_parser/tests/assets/ok/recursion.rs @@ -7,14 +7,11 @@ use ic_cdk::api::call::CallResult as Result; candid::define_function!(pub T : (S) -> ()); #[derive(CandidType, Deserialize)] pub struct Node { pub head: candid::Nat, pub tail: Box } - #[derive(CandidType, Deserialize)] pub struct List(Option); - pub type A = Box; #[derive(CandidType, Deserialize)] pub struct B(Option); - #[derive(CandidType, Deserialize)] pub enum Tree { #[serde(rename="branch")] @@ -22,18 +19,16 @@ pub enum Tree { #[serde(rename="leaf")] Leaf(candid::Int), } - candid::define_function!(pub StreamInnerNext : () -> (Stream) query); #[derive(CandidType, Deserialize)] pub struct StreamInner { pub head: candid::Nat, pub next: StreamInnerNext } - #[derive(CandidType, Deserialize)] pub struct Stream(Option); - candid::define_service!(pub S : { "f" : T::ty(); "g" : candid::func!((List) -> (B, Tree, Stream)); }); + pub struct Service(pub Principal); impl Service { pub async fn f(&self, arg0: S) -> Result<()> { @@ -45,3 +40,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/recursive_class.rs b/rust/candid_parser/tests/assets/ok/recursive_class.rs index 3edd2249..eda0084e 100644 --- a/rust/candid_parser/tests/assets/ok/recursive_class.rs +++ b/rust/candid_parser/tests/assets/ok/recursive_class.rs @@ -5,6 +5,7 @@ use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; candid::define_service!(pub S : { "next" : candid::func!(() -> (S)) }); + pub struct Service(pub Principal); impl Service { pub async fn next(&self) -> Result<(S,)> { @@ -13,3 +14,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/service.rs b/rust/candid_parser/tests/assets/ok/service.rs index d4ac89b4..bdf308f9 100644 --- a/rust/candid_parser/tests/assets/ok/service.rs +++ b/rust/candid_parser/tests/assets/ok/service.rs @@ -32,3 +32,4 @@ impl Service { } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/assets/ok/unicode.rs b/rust/candid_parser/tests/assets/ok/unicode.rs index 6bb2c33f..ca077654 100644 --- a/rust/candid_parser/tests/assets/ok/unicode.rs +++ b/rust/candid_parser/tests/assets/ok/unicode.rs @@ -15,7 +15,6 @@ pub struct A { #[serde(rename="字 段 名2")] pub _3133479156_: candid::Nat, } - #[derive(CandidType, Deserialize)] pub enum B { #[serde(rename="")] @@ -39,9 +38,10 @@ impl Service { pub async fn _3300066460_(&self, arg0: A) -> Result<(B,)> { ic_cdk::call(self.0, "函数名", (arg0,)).await } - pub async fn _2669435454_(&self, arg0: candid::Nat) -> Result< - (candid::Nat,) - > { ic_cdk::call(self.0, "👀", (arg0,)).await } + pub async fn _2669435454_(&self, arg0: candid::Nat) -> Result<(candid::Nat,)> { + ic_cdk::call(self.0, "👀", (arg0,)).await + } } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); + diff --git a/rust/candid_parser/tests/parse_type.rs b/rust/candid_parser/tests/parse_type.rs index 7dfb2fb6..2d7bb219 100644 --- a/rust/candid_parser/tests/parse_type.rs +++ b/rust/candid_parser/tests/parse_type.rs @@ -1,6 +1,7 @@ use candid::pretty::candid::compile; use candid::types::TypeEnv; use candid_parser::bindings::{javascript, motoko, rust, typescript}; +use candid_parser::configs::Configs; use candid_parser::types::IDLProg; use candid_parser::typing::{check_file, check_prog}; use goldenfile::Mint; @@ -62,13 +63,28 @@ fn compiler_test(resource: &str) { } } { - let mut config = rust::Config::new(); - config.set_canister_id(candid::Principal::from_text("aaaaa-aa").unwrap()); - if filename.file_name().unwrap().to_str().unwrap() == "management.did" { - config.set_target(rust::Target::Agent); + use rust::{Config, ExternalConfig}; + use std::str::FromStr; + let mut config = Config::new(Configs::from_str("").unwrap()); + let mut external = ExternalConfig::default(); + external + .0 + .insert("canister_id".to_string(), "aaaaa-aa".to_string()); + match filename.file_name().unwrap().to_str().unwrap() { + "management.did" => { + drop(external.0.insert("target".to_string(), "agent".to_string())) + } + "example.did" => { + let configs = std::fs::read_to_string(base_path.join("example.toml")) + .unwrap() + .parse::() + .unwrap(); + config = Config::new(configs); + } + _ => (), } let mut output = mint.new_goldenfile(filename.with_extension("rs")).unwrap(); - let content = rust::compile(&config, &env, &actor); + let content = rust::compile(&config, &env, &actor, external); writeln!(output, "{content}").unwrap(); } { diff --git a/tools/didc/Cargo.toml b/tools/didc/Cargo.toml index b1117a5f..7243aa19 100644 --- a/tools/didc/Cargo.toml +++ b/tools/didc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "didc" -version = "0.3.7" +version = "0.4.0" authors = ["DFINITY Team"] edition = "2021" diff --git a/tools/didc/random.dhall b/tools/didc/random.dhall deleted file mode 100644 index 81a6ca90..00000000 --- a/tools/didc/random.dhall +++ /dev/null @@ -1,30 +0,0 @@ -let default = - { range = None (List Natural) - , text = Some "emoji" - , width = Some 10 - , depth = Some 5 - , size = Some 100 - , value = None (List Text) - } - -in default - ∧ { `[h]` = { `[0]`.a.range = Some [ 42, 42 ], b.range = Some [ 0, 1 ] } - , list = { depth = Some 20, size = Some 50 } - , val.value = Some [ "42", "-1" ] - , left = { depth = Some 1, range = Some [ -200, -100 ] } - , right.tree = { depth = Some 5, range = Some [ 100, 200 ] } - , vec.nat8.range = Some [ 65, 90 ] - , Vec = { width = Some 2, size = Some 10 } - , profile.record - = - { name.text = Some "name" - , age.range = Some [ 18, 65 ] - , company.text = Some "company" - , country.text = Some "country" - , file.text = Some "path" - , description.text = Some "bs" - } - , principal.value - = Some - [ "principal \"aaaaa-aa\"", "principal \"2ibo7-dia\"" ] - } diff --git a/tools/didc/random.toml b/tools/didc/random.toml new file mode 100644 index 00000000..1b4f7f28 --- /dev/null +++ b/tools/didc/random.toml @@ -0,0 +1,24 @@ + +[random] +list = { depth = 20, size = 50 } +val.value = [ "42", "-1" ] +left = { depth = 1, range = [-200, -100] } +right.tree = { depth = 5, range = [100, 200] } +vec.nat8.range = [ 65, 90 ] +Vec = { width = 2, size = 10 } +text = "company" + +[random."method:h"] +"arg:0".a.range = [ 42, 42 ] +b.range = [ 0, 1 ] + +[random.profile.record] +name.text = "name" +age.range = [ 18, 65 ] +company.text = "company" +country.text = "country" +file.text = "path" +description = "bs" + +[random.principal] +value = [ "principal \"aaaaa-aa\"", "principal \"2ibo7-dia\"" ] diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index 9c5378f4..daeef0ca 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -1,6 +1,7 @@ use anyhow::{bail, Result}; use candid_parser::candid::types::{subtype, Type}; use candid_parser::{ + configs::Configs, parse_idl_args, parse_idl_value, pretty_check_file, pretty_parse, pretty_wrap, types::{IDLType, IDLTypes}, typing::ast_to_type, @@ -10,6 +11,7 @@ use clap::Parser; use std::collections::HashSet; use std::io; use std::path::PathBuf; +use std::str::FromStr; #[derive(Parser)] #[clap(version, author)] @@ -31,6 +33,9 @@ enum Command { #[clap(short, long, value_parser = ["js", "ts", "did", "mo", "rs", "rs-agent"])] /// Specifies target language target: String, + #[clap(short, long)] + /// Specifies binding generation config in TOML syntax + config: Option, }, /// Generate test suites for different languages Test { @@ -74,12 +79,9 @@ enum Command { Random { #[clap(flatten)] annotate: TypeAnnotation, - #[clap(short, long, conflicts_with("file"))] - /// Specifies random value generation config in Dhall syntax - config: Option, #[clap(short, long)] - /// Load random value generation config from file - file: Option, + /// Specifies random value generation config in TOML syntax + config: Option, #[clap(short, long, value_parser = ["did", "js"], default_value = "did")] /// Specifies target language lang: String, @@ -157,6 +159,13 @@ fn parse_args(str: &str) -> Result { fn parse_types(str: &str) -> Result { pretty_parse("type annotations", str) } +fn load_config(input: &Option) -> Result { + match input { + None => Configs::from_str(""), + Some(str) if str.ends_with(".toml") => Configs::from_str(&std::fs::read_to_string(str)?), + Some(str) => Configs::from_str(str), + } +} fn main() -> Result<()> { match Command::parse() { @@ -194,7 +203,12 @@ fn main() -> Result<()> { let ty2 = ast_to_type(&env, &ty2)?; subtype::subtype(&mut HashSet::new(), &env, &ty1, &ty2)?; } - Command::Bind { input, target } => { + Command::Bind { + input, + target, + config, + } => { + let configs = load_config(&config)?; let (env, actor) = pretty_check_file(&input)?; let content = match target.as_str() { "js" => candid_parser::bindings::javascript::compile(&env, &actor), @@ -202,13 +216,16 @@ fn main() -> Result<()> { "did" => candid_parser::pretty::candid::compile(&env, &actor), "mo" => candid_parser::bindings::motoko::compile(&env, &actor), "rs" => { - let config = candid_parser::bindings::rust::Config::new(); - candid_parser::bindings::rust::compile(&config, &env, &actor) + use candid_parser::bindings::rust::{compile, Config, ExternalConfig}; + let config = Config::new(configs); + compile(&config, &env, &actor, ExternalConfig::default()) } "rs-agent" => { - let mut config = candid_parser::bindings::rust::Config::new(); - config.set_target(candid_parser::bindings::rust::Target::Agent); - candid_parser::bindings::rust::compile(&config, &env, &actor) + use candid_parser::bindings::rust::{compile, Config, ExternalConfig}; + let config = Config::new(configs); + let mut external = ExternalConfig::default(); + external.0.insert("target".to_string(), "agent".to_string()); + compile(&config, &env, &actor, external) } _ => unreachable!(), }; @@ -305,31 +322,16 @@ fn main() -> Result<()> { annotate, lang, config, - file, args, } => { - use candid_parser::configs::Configs; + use candid_parser::configs::{Scope, ScopePos}; use rand::Rng; let (env, types) = if args.is_some() { annotate.get_types(Mode::Decode)? } else { annotate.get_types(Mode::Encode)? }; - let config = match (config, file) { - (None, None) => Configs::from_dhall("{=}")?, - (Some(str), None) => Configs::from_dhall(&str)?, - (None, Some(file)) => { - let content = std::fs::read_to_string(&file) - .map_err(|_| Error::msg(format!("could not read {file}")))?; - Configs::from_dhall(&content)? - } - _ => unreachable!(), - }; - let config = if let Some(ref method) = annotate.method { - config.with_method(method) - } else { - config - }; + let config = load_config(&config)?; // TODO figure out how many bytes of entropy we need let seed: Vec = if let Some(ref args) = args { let (env, types) = annotate.get_types(Mode::Encode)?; @@ -339,7 +341,15 @@ fn main() -> Result<()> { let mut rng = rand::thread_rng(); (0..2048).map(|_| rng.gen::()).collect() }; - let args = candid_parser::random::any(&seed, &config, &env, &types)?; + let scope = annotate.method.as_ref().map(|method| { + let position = Some(if args.is_some() { + ScopePos::Ret + } else { + ScopePos::Arg + }); + Scope { position, method } + }); + let args = candid_parser::random::any(&seed, config, &env, &types, &scope)?; match lang.as_str() { "did" => println!("{args}"), "js" => println!( From b0622bbbd3cc5c54f9b3ba6faf95de0385066df7 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 3 May 2024 13:14:03 -0700 Subject: [PATCH 03/36] ci: use macos-12 to build macos binary (#547) * ci: use macos-12 to build macos binary * fix * fix --- .github/workflows/bench.yml | 4 ++-- .github/workflows/coq.yml | 2 +- .github/workflows/release.yml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index f60ba266..e5f84308 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -6,7 +6,7 @@ jobs: name: run benchmark runs-on: ubuntu-latest env: - RUSTC_VERSION: 1.75.0 + RUSTC_VERSION: 1.77.0 steps: - uses: actions/checkout@v4 - name: Checkout base branch @@ -35,7 +35,7 @@ jobs: ~/.cargo target rust/bench/target - key: ${{ runner.os }}-bench-0.1.1-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-bench-0.1.3-${{ hashFiles('**/Cargo.lock') }} - name: Install canbench run: cargo install canbench - name: Run perf for base branch diff --git a/.github/workflows/coq.yml b/.github/workflows/coq.yml index 7b23c97d..ec56f00d 100644 --- a/.github/workflows/coq.yml +++ b/.github/workflows/coq.yml @@ -11,7 +11,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v12 #- run: nix-build s coq # The above would also build the shell, includling niv. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 352915fe..9bba0839 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,7 @@ on: tags: - '*' branches: # TODO: Remove before merging. - - musl # Pushing the feature branch should test this PR. + - fix-ci # Pushing the feature branch should test this PR. jobs: build: name: Build for ${{ matrix.name }} @@ -17,7 +17,7 @@ jobs: name: linux64 artifact_name: target/x86_64-unknown-linux-musl/release/didc asset_name: didc-linux64 - - os: macos-latest + - os: macos-12 name: macos artifact_name: target/release/didc asset_name: didc-macos @@ -26,7 +26,7 @@ jobs: artifact_name: target/arm-unknown-linux-gnueabihf/release/didc asset_name: didc-arm32 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install stable toolchain if: matrix.name != 'arm' uses: actions-rs/toolchain@v1 From a21d1b8ff255964caa63e61858fc600db544563d Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 14 May 2024 13:50:58 -0700 Subject: [PATCH 04/36] more improvements to Configs (#548) * add clone for configs * add open_path * report unused * add stub * add rust parser to extract cdk functions; didc to take external.rust section * fix mode * refactor to report span * checkpoint, use codespan_reporting * good * fix * move rust_check to cdk * bump version --- Cargo.lock | 146 +++++++++--------- rust/candid_parser/Cargo.toml | 4 +- rust/candid_parser/src/bindings/rust.rs | 83 ++++++++-- .../candid_parser/src/bindings/rust_agent.hbs | 2 +- rust/candid_parser/src/bindings/rust_call.hbs | 2 +- rust/candid_parser/src/bindings/rust_stub.hbs | 18 +++ rust/candid_parser/src/configs.rs | 124 ++++++++++++--- rust/candid_parser/tests/assets/ok/actor.rs | 2 +- rust/candid_parser/tests/assets/ok/class.rs | 2 +- rust/candid_parser/tests/assets/ok/comment.rs | 2 +- rust/candid_parser/tests/assets/ok/cyclic.rs | 2 +- rust/candid_parser/tests/assets/ok/empty.rs | 2 +- rust/candid_parser/tests/assets/ok/escape.rs | 2 +- rust/candid_parser/tests/assets/ok/example.rs | 2 +- .../candid_parser/tests/assets/ok/fieldnat.rs | 2 +- rust/candid_parser/tests/assets/ok/keyword.rs | 2 +- .../tests/assets/ok/recursion.rs | 2 +- .../tests/assets/ok/recursive_class.rs | 2 +- rust/candid_parser/tests/assets/ok/service.rs | 2 +- rust/candid_parser/tests/assets/ok/unicode.rs | 2 +- tools/didc/src/main.rs | 17 +- 21 files changed, 289 insertions(+), 133 deletions(-) create mode 100644 rust/candid_parser/src/bindings/rust_stub.hbs diff --git a/Cargo.lock b/Cargo.lock index a076a7af..04925dba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,9 +62,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" [[package]] name = "arbitrary" @@ -89,9 +89,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "beef" @@ -126,7 +126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" dependencies = [ "either", - "proc-macro2 1.0.81", + "proc-macro2 1.0.82", "quote 1.0.36", "syn 1.0.109", ] @@ -208,14 +208,14 @@ name = "candid_derive" version = "0.6.6" dependencies = [ "lazy_static", - "proc-macro2 1.0.81", + "proc-macro2 1.0.82", "quote 1.0.36", - "syn 2.0.60", + "syn 2.0.63", ] [[package]] name = "candid_parser" -version = "0.2.0-beta.0" +version = "0.2.0-beta.1" dependencies = [ "anyhow", "arbitrary", @@ -244,9 +244,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.96" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" [[package]] name = "cfg-if" @@ -289,9 +289,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", - "proc-macro2 1.0.81", + "proc-macro2 1.0.82", "quote 1.0.36", - "syn 2.0.60", + "syn 2.0.63", ] [[package]] @@ -390,9 +390,9 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "deunicode" -version = "1.4.4" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322ef0094744e63628e6f0eb2295517f79276a5b342a4c2ff3042566ca181d4e" +checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" [[package]] name = "dialoguer" @@ -457,9 +457,9 @@ checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "ena" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] @@ -478,9 +478,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys", @@ -526,9 +526,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -658,7 +658,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.8.3", + "regex-syntax", "string_cache", "term", "tiny-keccak", @@ -727,32 +727,33 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "logos" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" +checksum = "161971eb88a0da7ae0c333e1063467c5b5727e7fb6b710b8db4814eade3a42e8" dependencies = [ "logos-derive", ] [[package]] name = "logos-codegen" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" +checksum = "8e31badd9de5131fdf4921f6473d457e3dd85b11b7f091ceb50e4df7c3eeb12a" dependencies = [ "beef", "fnv", - "proc-macro2 1.0.81", + "lazy_static", + "proc-macro2 1.0.82", "quote 1.0.36", - "regex-syntax 0.6.29", - "syn 2.0.60", + "regex-syntax", + "syn 2.0.63", ] [[package]] name = "logos-derive" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +checksum = "1c2a69b3eb68d5bd595107c9ee58d7e07fe2bb5e360cc85b0f084dedac80de0a" dependencies = [ "logos-codegen", ] @@ -783,11 +784,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", "serde", @@ -804,9 +804,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -842,9 +842,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pest" @@ -875,9 +875,9 @@ checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.81", + "proc-macro2 1.0.82", "quote 1.0.36", - "syn 2.0.60", + "syn 2.0.63", ] [[package]] @@ -893,9 +893,9 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap", @@ -956,9 +956,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -987,7 +987,7 @@ version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "proc-macro2 1.0.81", + "proc-macro2 1.0.82", ] [[package]] @@ -1049,7 +1049,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-syntax", ] [[package]] @@ -1066,15 +1066,9 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.3" @@ -1096,15 +1090,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -1123,9 +1117,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.200" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] @@ -1151,20 +1145,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.200" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ - "proc-macro2 1.0.81", + "proc-macro2 1.0.82", "quote 1.0.36", - "syn 2.0.60", + "syn 2.0.63", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -1287,18 +1281,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.81", + "proc-macro2 1.0.82", "quote 1.0.36", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.60" +version = "2.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" dependencies = [ - "proc-macro2 1.0.81", + "proc-macro2 1.0.82", "quote 1.0.36", "unicode-ident", ] @@ -1349,22 +1343,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ - "proc-macro2 1.0.81", + "proc-macro2 1.0.82", "quote 1.0.36", - "syn 2.0.60", + "syn 2.0.63", ] [[package]] @@ -1592,9 +1586,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" dependencies = [ "memchr", ] diff --git a/rust/candid_parser/Cargo.toml b/rust/candid_parser/Cargo.toml index 2630d651..77051a3a 100644 --- a/rust/candid_parser/Cargo.toml +++ b/rust/candid_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid_parser" -version = "0.2.0-beta.0" +version = "0.2.0-beta.1" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] @@ -29,7 +29,7 @@ anyhow.workspace = true serde.workspace = true lalrpop-util = "0.20.0" -logos = "0.13" +logos = "0.14" convert_case = "0.6" handlebars = "5.1" toml = { version = "0.8", default-features = false, features = ["parse"] } diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index afeb98ff..d136b631 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -387,6 +387,7 @@ impl<'a> State<'a> { res } fn pp_function(&mut self, id: &str, func: &Function) -> Method { + use candid::types::internal::FuncMode; let old = self.state.push_state(&StateElem::Label(id)); let name = self .state @@ -424,7 +425,13 @@ impl<'a> State<'a> { res }) .collect(); - let mode = if func.is_query() { "query" } else { "update" }.to_string(); + let mode = match func.modes.first() { + None => "update", + Some(FuncMode::Query) => "query", + Some(FuncMode::CompositeQuery) => "composite_query", + Some(FuncMode::Oneway) => "update", + } + .to_string(); let res = Method { name, original_name: id.to_string(), @@ -478,19 +485,19 @@ impl<'a> State<'a> { } #[derive(Serialize, Debug)] pub struct Output { - type_defs: String, - methods: Vec, - init_args: Option>, + pub type_defs: String, + pub methods: Vec, + pub init_args: Option>, } #[derive(Serialize, Debug)] pub struct Method { - name: String, - original_name: String, - args: Vec<(String, String)>, - rets: Vec, - mode: String, + pub name: String, + pub original_name: String, + pub args: Vec<(String, String)>, + pub rets: Vec, + pub mode: String, } -pub fn emit_bindgen(tree: &Config, env: &TypeEnv, actor: &Option) -> Output { +pub fn emit_bindgen(tree: &Config, env: &TypeEnv, actor: &Option) -> (Output, Vec) { let (env, actor) = nominalize_all(env, actor); let def_list: Vec<_> = if let Some(actor) = &actor { chase_actor(&env, actor).unwrap() @@ -508,11 +515,15 @@ pub fn emit_bindgen(tree: &Config, env: &TypeEnv, actor: &Option) -> Outpu } else { (Vec::new(), None) }; - Output { - type_defs: defs.pretty(LINE_WIDTH).to_string(), - methods, - init_args, - } + let unused = state.state.report_unused(); + ( + Output { + type_defs: defs.pretty(LINE_WIDTH).to_string(), + methods, + init_args, + }, + unused, + ) } pub fn output_handlebar(output: Output, config: ExternalConfig, template: &str) -> String { let hbs = get_hbs(); @@ -522,11 +533,13 @@ pub fn output_handlebar(output: Output, config: ExternalConfig, template: &str) external: BTreeMap, type_defs: String, methods: Vec, + init_args: Option>, } let data = HBOutput { type_defs: output.type_defs, methods: output.methods, external: config.0, + init_args: output.init_args, }; hbs.render_template(template, &data).unwrap() } @@ -536,6 +549,7 @@ impl Config { Self(ConfigTree::from_configs("rust", configs).unwrap()) } } +#[derive(Deserialize)] pub struct ExternalConfig(pub BTreeMap); impl Default for ExternalConfig { fn default() -> Self { @@ -560,9 +574,13 @@ pub fn compile( let source = match external.0.get("target").map(|s| s.as_str()) { Some("canister_call") | None => include_str!("rust_call.hbs"), Some("agent") => include_str!("rust_agent.hbs"), + Some("stub") => include_str!("rust_stub.hbs"), _ => unimplemented!(), }; - let output = emit_bindgen(tree, env, actor); + let (output, unused) = emit_bindgen(tree, env, actor); + for e in unused { + eprintln!("WARNING: path {e} is unused"); + } output_handlebar(output, external, source) } @@ -754,7 +772,6 @@ fn nominalize_all(env: &TypeEnv, actor: &Option) -> (TypeEnv, Option .map(|ty| nominalize(&mut res, &mut vec![], ty)); (res, actor) } - fn get_hbs() -> handlebars::Handlebars<'static> { use handlebars::*; let mut hbs = Handlebars::new(); @@ -853,5 +870,37 @@ fn get_hbs() -> handlebars::Handlebars<'static> { }, ), ); + hbs.register_helper( + "cdk_attribute", + Box::new( + |h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output| + -> HelperResult { + let mode = h.param(0).unwrap().value().as_str().unwrap(); + let name = h.param(1).unwrap().value().as_str().unwrap(); + let original_name = h.param(2).unwrap().value().as_str().unwrap(); + if mode == "update" { + out.write("update")?; + } else { + out.write("query")?; + } + let mut attrs = Vec::new(); + if mode == "composite_query" { + attrs.push("composite = true".to_string()); + } + if name != original_name { + attrs.push(format!("name = \"{}\"", original_name.escape_debug())); + } + let attrs = attrs.join(", "); + if !attrs.is_empty() { + out.write(&format!("({attrs})"))?; + } + Ok(()) + }, + ), + ); hbs } diff --git a/rust/candid_parser/src/bindings/rust_agent.hbs b/rust/candid_parser/src/bindings/rust_agent.hbs index f48fefc6..9fffd9b4 100644 --- a/rust/candid_parser/src/bindings/rust_agent.hbs +++ b/rust/candid_parser/src/bindings/rust_agent.hbs @@ -11,7 +11,7 @@ impl<'a> {{PascalCase service_name}}<'a> { {{#each methods}} pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: {{this.1}}{{/each}}) -> Result<{{vec_to_arity this.rets}}> { let args = Encode!({{#each this.args}}&{{this.0}}{{#unless @last}},{{/unless}}{{/each}})?; - let bytes = self.1.{{this.mode}}(&self.0, "{{escape_debug this.original_name}}").with_arg(args).{{#if (eq this.mode "query")}}call{{else}}call_and_wait(){{/if}}.await?; + let bytes = self.1.{{#if (eq this.mode "update")}}update{{else}}query{{/if}}(&self.0, "{{escape_debug this.original_name}}").with_arg(args).{{#if (eq this.mode "update")}}call_and_wait{{else}}call{{/if}}().await?; Ok(Decode!(&bytes{{#each this.rets}}, {{this}}{{/each}})?) } {{/each}} diff --git a/rust/candid_parser/src/bindings/rust_call.hbs b/rust/candid_parser/src/bindings/rust_call.hbs index 6be0fe4b..b12654b6 100644 --- a/rust/candid_parser/src/bindings/rust_call.hbs +++ b/rust/candid_parser/src/bindings/rust_call.hbs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use {{candid_crate}}::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use {{candid_crate}}::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; {{type_defs}} diff --git a/rust/candid_parser/src/bindings/rust_stub.hbs b/rust/candid_parser/src/bindings/rust_stub.hbs new file mode 100644 index 00000000..5a85901a --- /dev/null +++ b/rust/candid_parser/src/bindings/rust_stub.hbs @@ -0,0 +1,18 @@ +// This is an experimental feature to generate Rust binding from Candid. +// You may want to manually adjust some of the types. +#![allow(dead_code, unused_imports)] +use {{candid_crate}}::{self, CandidType, Deserialize, Principal}; + +{{type_defs}} +{{#if init_args}} +#[ic_cdk::init] +fn init({{#each init_args}}{{#if (not @first)}}, {{/if}}{{this.0}}: {{this.1}}{{/each}}) { + unimplemented!() +} +{{/if}} +{{#each methods}} +#[ic_cdk::{{cdk_attribute this.mode this.name this.original_name}}] +fn {{this.name}}({{#each this.args}}{{#if (not @first)}}, {{/if}}{{this.0}}: {{this.1}}{{/each}}) -> {{vec_to_arity this.rets}} { + unimplemented!() +} +{{/each}} diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index c711e4fd..4b4e600b 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -1,13 +1,15 @@ use anyhow::Result; use candid::types::{Type, TypeEnv, TypeInner}; use serde::de::DeserializeOwned; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use toml::{Table, Value}; pub struct State<'a, T: ConfigState> { tree: &'a ConfigTree, - open_tree: Option<&'a ConfigTree>, path: Vec, + open_tree: Option<&'a ConfigTree>, + open_path: Vec, + stats: BTreeMap, u32>, pub config: T, pub env: &'a TypeEnv, } @@ -37,7 +39,9 @@ impl<'a, T: ConfigState> State<'a, T> { Self { tree, open_tree: None, + open_path: Vec::new(), path: Vec::new(), + stats: BTreeMap::new(), config, env, } @@ -45,7 +49,10 @@ impl<'a, T: ConfigState> State<'a, T> { /// Match paths in the scope first. If `scope` is None, clear the scope. pub fn with_scope(&mut self, scope: &Option, idx: usize) { match scope { - None => self.open_tree = None, + None => { + self.open_tree = None; + self.open_path.clear(); + } Some(scope) => { let mut path = vec![format!("method:{}", scope.method)]; match self.tree.with_prefix(&path) { @@ -55,12 +62,24 @@ impl<'a, T: ConfigState> State<'a, T> { Some(ScopePos::Ret) => path.push(format!("ret:{}", idx)), None => (), } - self.open_tree = self.tree.with_prefix(&path).or(Some(tree)); + match self.tree.with_prefix(&path) { + Some(subtree) => { + self.open_tree = Some(subtree); + self.open_path = path; + } + None => { + self.open_tree = Some(tree); + self.open_path = vec![path[0].clone()]; + } + } if let Some(state) = self.open_tree.unwrap().state.as_ref() { self.config.merge_config(state, None, false); } } - None => self.open_tree = None, + None => { + self.open_tree = None; + self.open_path.clear(); + } } } } @@ -70,14 +89,27 @@ impl<'a, T: ConfigState> State<'a, T> { self.config.update_state(elem); let old_config = self.config.clone(); self.path.push(elem.to_string()); + let mut from_open = false; let new_state = if let Some(subtree) = self.open_tree { - subtree - .get_config(&self.path) - .or_else(|| self.tree.get_config(&self.path)) + from_open = true; + subtree.get_config(&self.path).or_else(|| { + from_open = false; + self.tree.get_config(&self.path) + }) } else { self.tree.get_config(&self.path) }; - if let Some((state, is_recursive)) = new_state { + if let Some((state, is_recursive, idx)) = new_state { + let mut matched_path = if from_open { + self.open_path.clone() + } else { + vec![] + }; + matched_path.extend_from_slice(&self.path[idx..]); + self.stats + .entry(matched_path) + .and_modify(|v| *v += 1) + .or_insert(1); self.config.merge_config(state, Some(elem), is_recursive); //eprintln!("match path: {:?}, state: {:?}", self.path, self.config); } else { @@ -92,6 +124,26 @@ impl<'a, T: ConfigState> State<'a, T> { assert_eq!(self.path.pop(), Some(elem.to_string())); self.config.restore_state(&elem); } + pub fn report_unused(&self) -> Vec { + let mut res = BTreeSet::new(); + self.tree.traverse(&mut vec![], &mut res); + for k in self.stats.keys() { + res.remove(k); + } + res.remove(&vec![]); + res.into_iter().map(|v| v.join(".")).collect() + } + pub fn get_stats(mut self) -> BTreeMap { + let mut res = BTreeSet::new(); + self.tree.traverse(&mut vec![], &mut res); + for e in res { + self.stats.entry(e).or_insert(0); + } + self.stats + .into_iter() + .map(|(k, v)| (k.join("."), v)) + .collect() + } } pub trait ConfigState: DeserializeOwned + Default + Clone + std::fmt::Debug { @@ -127,6 +179,7 @@ impl ConfigTree { Some(tree) } pub fn add_config(&mut self, path: &[String], config: T) { + // TODO: correctly count the depth of scoped paths let n = path.len(); let mut tree: &Self = self; let mut i = 0; @@ -165,14 +218,15 @@ impl ConfigTree { tree.max_depth = std::cmp::max(d, tree.max_depth); } } - pub fn get_config(&self, path: &[String]) -> Option<(&T, bool)> { + /// Returns the config, is_recursive, and the index of the matched path + pub fn get_config(&self, path: &[String]) -> Option<(&T, bool, usize)> { let len = path.len(); assert!(len > 0); let start = len.saturating_sub(self.max_depth as usize); for i in (start..len).rev() { let (path, tail) = path.split_at(i); match self.match_exact_path(tail) { - Some(v) => return Some((v, is_repeated(path, tail))), + Some(v) => return Some((v, is_repeated(path, tail), i)), None => continue, } } @@ -185,10 +239,31 @@ impl ConfigTree { } result.state.as_ref() } + pub fn traverse(&self, path: &mut Vec, res: &mut BTreeSet>) { + if self.state.is_some() { + res.insert(path.clone()); + } + for (k, v) in self.subtree.iter() { + path.push(k.clone()); + v.traverse(path, res); + path.pop(); + } + } } - +#[derive(Clone)] pub struct Configs(Table); - +impl Configs { + pub fn get_subtable(&self, path: &[String]) -> Option<&Table> { + let mut res = &self.0; + for k in path { + match res.get(k)? { + Value::Table(t) => res = t, + _ => return None, + } + } + Some(res) + } +} impl std::str::FromStr for Configs { type Err = crate::Error; fn from_str(v: &str) -> Result { @@ -205,7 +280,6 @@ impl<'a> std::fmt::Display for StateElem<'a> { } } } - fn is_repeated(path: &[String], matched: &[String]) -> bool { let iter = path.as_ref().windows(matched.len()); for slice in iter { @@ -215,11 +289,9 @@ fn is_repeated(path: &[String], matched: &[String]) -> bool { } false } - fn special_key(key: &str) -> bool { key.starts_with("method:") || key.starts_with("arg:") || key.starts_with("ret:") } - fn generate_state_tree(v: Value) -> Result> { let mut subtree = BTreeMap::new(); let mut leaves = toml::Table::new(); @@ -254,8 +326,7 @@ fn generate_state_tree(v: Value) -> Result> { Err(anyhow::anyhow!("Expected a table")) } } - -pub fn path_name(t: &Type) -> String { +fn path_name(t: &Type) -> String { match t.as_ref() { TypeInner::Null => "null", TypeInner::Bool => "bool", @@ -393,6 +464,7 @@ Vec = { width = 2, size = 10 } }), 0, ); + assert_eq!(state.open_path, vec!["method:f", "arg:0"]); let old = state.push_state(&StateElem::Label("list")); assert_eq!(state.config.depth, Some(2)); assert_eq!(state.config.size, Some(20)); @@ -403,10 +475,11 @@ Vec = { width = 2, size = 10 } state.with_scope( &Some(Scope { method: "f", - position: None, + position: Some(ScopePos::Ret), }), 0, ); + assert_eq!(state.open_path, vec!["method:f"]); state.push_state(&StateElem::Label("list")); assert_eq!(state.config.depth, Some(3)); assert_eq!(state.config.size, Some(0)); @@ -418,4 +491,17 @@ Vec = { width = 2, size = 10 } state.pop_state(old, StateElem::Label("list")); assert_eq!(state.config.size, Some(0)); assert_eq!(state.config.depth, Some(3)); + let stats = state.report_unused(); + assert_eq!( + stats.iter().map(|x| x.as_str()).collect::>(), + [ + "Vec", + "a.b.c", + "a.b.c.d", + "a.b.d", + "left.a", + "left.list", + "vec.nat8" + ] + ); } diff --git a/rust/candid_parser/tests/assets/ok/actor.rs b/rust/candid_parser/tests/assets/ok/actor.rs index 79138a42..d9d385ec 100644 --- a/rust/candid_parser/tests/assets/ok/actor.rs +++ b/rust/candid_parser/tests/assets/ok/actor.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; candid::define_function!(pub F : (i8) -> (i8)); diff --git a/rust/candid_parser/tests/assets/ok/class.rs b/rust/candid_parser/tests/assets/ok/class.rs index 2198ab57..cfed8194 100644 --- a/rust/candid_parser/tests/assets/ok/class.rs +++ b/rust/candid_parser/tests/assets/ok/class.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] diff --git a/rust/candid_parser/tests/assets/ok/comment.rs b/rust/candid_parser/tests/assets/ok/comment.rs index c819f2f1..958f42fa 100644 --- a/rust/candid_parser/tests/assets/ok/comment.rs +++ b/rust/candid_parser/tests/assets/ok/comment.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; pub type Id = u8; diff --git a/rust/candid_parser/tests/assets/ok/cyclic.rs b/rust/candid_parser/tests/assets/ok/cyclic.rs index f3fae3f3..314286e9 100644 --- a/rust/candid_parser/tests/assets/ok/cyclic.rs +++ b/rust/candid_parser/tests/assets/ok/cyclic.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; pub type C = Box; diff --git a/rust/candid_parser/tests/assets/ok/empty.rs b/rust/candid_parser/tests/assets/ok/empty.rs index 64d70472..2338c077 100644 --- a/rust/candid_parser/tests/assets/ok/empty.rs +++ b/rust/candid_parser/tests/assets/ok/empty.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] diff --git a/rust/candid_parser/tests/assets/ok/escape.rs b/rust/candid_parser/tests/assets/ok/escape.rs index c6b66fef..776d7e6c 100644 --- a/rust/candid_parser/tests/assets/ok/escape.rs +++ b/rust/candid_parser/tests/assets/ok/escape.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] diff --git a/rust/candid_parser/tests/assets/ok/example.rs b/rust/candid_parser/tests/assets/ok/example.rs index 18891eb8..e5c735b8 100644 --- a/rust/candid_parser/tests/assets/ok/example.rs +++ b/rust/candid_parser/tests/assets/ok/example.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize, Debug)] diff --git a/rust/candid_parser/tests/assets/ok/fieldnat.rs b/rust/candid_parser/tests/assets/ok/fieldnat.rs index 8cbba81a..607c0445 100644 --- a/rust/candid_parser/tests/assets/ok/fieldnat.rs +++ b/rust/candid_parser/tests/assets/ok/fieldnat.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] diff --git a/rust/candid_parser/tests/assets/ok/keyword.rs b/rust/candid_parser/tests/assets/ok/keyword.rs index fd6ce914..f50de12e 100644 --- a/rust/candid_parser/tests/assets/ok/keyword.rs +++ b/rust/candid_parser/tests/assets/ok/keyword.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] diff --git a/rust/candid_parser/tests/assets/ok/recursion.rs b/rust/candid_parser/tests/assets/ok/recursion.rs index 939a8378..91aca069 100644 --- a/rust/candid_parser/tests/assets/ok/recursion.rs +++ b/rust/candid_parser/tests/assets/ok/recursion.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; candid::define_function!(pub T : (S) -> ()); diff --git a/rust/candid_parser/tests/assets/ok/recursive_class.rs b/rust/candid_parser/tests/assets/ok/recursive_class.rs index eda0084e..ce01cd0e 100644 --- a/rust/candid_parser/tests/assets/ok/recursive_class.rs +++ b/rust/candid_parser/tests/assets/ok/recursive_class.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; candid::define_service!(pub S : { "next" : candid::func!(() -> (S)) }); diff --git a/rust/candid_parser/tests/assets/ok/service.rs b/rust/candid_parser/tests/assets/ok/service.rs index bdf308f9..631c2095 100644 --- a/rust/candid_parser/tests/assets/ok/service.rs +++ b/rust/candid_parser/tests/assets/ok/service.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; candid::define_function!(pub Func : () -> (Service)); diff --git a/rust/candid_parser/tests/assets/ok/unicode.rs b/rust/candid_parser/tests/assets/ok/unicode.rs index ca077654..ec2ebbe1 100644 --- a/rust/candid_parser/tests/assets/ok/unicode.rs +++ b/rust/candid_parser/tests/assets/ok/unicode.rs @@ -1,7 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] -use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index daeef0ca..c0b59198 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -30,7 +30,7 @@ enum Command { Bind { /// Specifies did file for code generation input: PathBuf, - #[clap(short, long, value_parser = ["js", "ts", "did", "mo", "rs", "rs-agent"])] + #[clap(short, long, value_parser = ["js", "ts", "did", "mo", "rs", "rs-agent", "rs-stub"])] /// Specifies target language target: String, #[clap(short, long)] @@ -217,14 +217,23 @@ fn main() -> Result<()> { "mo" => candid_parser::bindings::motoko::compile(&env, &actor), "rs" => { use candid_parser::bindings::rust::{compile, Config, ExternalConfig}; + let external = configs + .get_subtable(&["external".to_string(), "rust".to_string()]) + .map(|x| x.clone().try_into().unwrap()) + .unwrap_or(ExternalConfig::default()); let config = Config::new(configs); - compile(&config, &env, &actor, ExternalConfig::default()) + compile(&config, &env, &actor, external) } - "rs-agent" => { + "rs-agent" | "rs-stub" => { use candid_parser::bindings::rust::{compile, Config, ExternalConfig}; let config = Config::new(configs); let mut external = ExternalConfig::default(); - external.0.insert("target".to_string(), "agent".to_string()); + let target = match target.as_str() { + "rs-agent" => "agent", + "rs-stub" => "stub", + _ => unreachable!(), + }; + external.0.insert("target".to_string(), target.to_string()); compile(&config, &env, &actor, external) } _ => unreachable!(), From 4fdc2a180b71cf4ef3b04cefc5f2469af1797029 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Thu, 23 May 2024 11:22:28 +0200 Subject: [PATCH 05/36] add custom target for didc (#550) * add custom target for didc * readme * bump canbench * try * gzip * fix * try * try * fix * fix --- .github/workflows/bench.yml | 2 +- rust/bench/Cargo.lock | 363 +++++++++++++++++------- rust/bench/canbench.yml | 5 +- rust/candid_parser/src/bindings/rust.rs | 16 +- tools/didc/README.md | 30 +- tools/didc/src/main.rs | 2 +- 6 files changed, 295 insertions(+), 123 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index e5f84308..19393119 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -35,7 +35,7 @@ jobs: ~/.cargo target rust/bench/target - key: ${{ runner.os }}-bench-0.1.3-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-bench-0.1.4-${{ hashFiles('**/Cargo.lock') }} - name: Install canbench run: cargo install canbench - name: Run perf for base branch diff --git a/rust/bench/Cargo.lock b/rust/bench/Cargo.lock index 9d3c9add..50edc5f5 100644 --- a/rust/bench/Cargo.lock +++ b/rust/bench/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arbitrary" @@ -40,9 +40,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "beef" @@ -101,12 +101,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.5.0" @@ -130,9 +124,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "canbench-rs" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5d551419a1547b5064111df7bfa6e87818750e7f6df611067a02e63a9cbb31" +checksum = "53574f268dbe23dc83f891a4751b118a6ba927c8bc92e839ff108f3aaf151aa9" dependencies = [ "canbench-rs-macros", "candid", @@ -142,9 +136,9 @@ dependencies = [ [[package]] name = "canbench-rs-macros" -version = "0.1.0" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5acd4a41fd2e7018508f7442d7ae90957a913c6fa0e4b767e5be9a8cc5848c8" +checksum = "d454906c77138a3802a7a680259cca7c006e9b268ba6905f7f4f2b8b74293fa4" dependencies = [ "proc-macro2", "quote", @@ -153,7 +147,7 @@ dependencies = [ [[package]] name = "candid" -version = "0.10.6" +version = "0.10.8" dependencies = [ "anyhow", "binread", @@ -179,31 +173,34 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] name = "candid_parser" -version = "0.1.4" +version = "0.2.0-beta.1" dependencies = [ "anyhow", "candid", "codespan-reporting", "convert_case", + "handlebars", "hex", "lalrpop", "lalrpop-util", "logos", "num-bigint", "pretty", + "serde", "thiserror", + "toml", ] [[package]] name = "cc" -version = "1.0.92" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" [[package]] name = "cfg-if" @@ -241,9 +238,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -266,9 +263,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "digest" @@ -303,15 +300,15 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "ena" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] @@ -346,20 +343,34 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hex" @@ -431,6 +442,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "lalrpop" version = "0.20.2" @@ -445,7 +462,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.8.3", + "regex-syntax", "string_cache", "term", "tiny-keccak", @@ -476,9 +493,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libredox" @@ -486,15 +503,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags", "libc", ] [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -508,32 +525,33 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "logos" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" +checksum = "161971eb88a0da7ae0c333e1063467c5b5727e7fb6b710b8db4814eade3a42e8" dependencies = [ "logos-derive", ] [[package]] name = "logos-codegen" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" +checksum = "8e31badd9de5131fdf4921f6473d457e3dd85b11b7f091ceb50e4df7c3eeb12a" dependencies = [ "beef", "fnv", + "lazy_static", "proc-macro2", "quote", - "regex-syntax 0.6.29", - "syn 2.0.58", + "regex-syntax", + "syn 2.0.65", ] [[package]] name = "logos-derive" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +checksum = "1c2a69b3eb68d5bd595107c9ee58d7e07fe2bb5e360cc85b0f084dedac80de0a" dependencies = [ "logos-codegen", ] @@ -552,11 +570,10 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", "serde", @@ -573,9 +590,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -588,9 +605,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -598,9 +615,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", @@ -611,15 +628,60 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2", +] [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap", @@ -659,9 +721,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] @@ -677,20 +739,20 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -713,7 +775,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.3", + "regex-syntax", ] [[package]] @@ -724,15 +786,9 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.3" @@ -741,9 +797,15 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -762,9 +824,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] @@ -780,13 +842,33 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", ] [[package]] @@ -862,9 +944,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" dependencies = [ "proc-macro2", "quote", @@ -893,22 +975,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] @@ -920,6 +1002,40 @@ dependencies = [ "crunchy", ] +[[package]] +name = "toml" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "typed-arena" version = "2.0.2" @@ -932,6 +1048,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -946,9 +1068,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -996,11 +1118,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys", ] [[package]] @@ -1009,15 +1131,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -1026,42 +1158,57 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +dependencies = [ + "memchr", +] diff --git a/rust/bench/canbench.yml b/rust/bench/canbench.yml index fc3ca40f..f96cbe42 100644 --- a/rust/bench/canbench.yml +++ b/rust/bench/canbench.yml @@ -1,5 +1,6 @@ build_cmd: - cargo build --release --target wasm32-unknown-unknown + cargo build --release --target wasm32-unknown-unknown && + gzip -f ./target/wasm32-unknown-unknown/release/bench.wasm wasm_path: - ./target/wasm32-unknown-unknown/release/bench.wasm + ./target/wasm32-unknown-unknown/release/bench.wasm.gz diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index d136b631..3e66a2f0 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -8,6 +8,7 @@ use candid::types::{Field, Function, Label, SharedLabel, Type, TypeEnv, TypeInne use convert_case::{Case, Casing}; use pretty::RcDoc; use serde::Serialize; +use std::borrow::Cow; use std::collections::{BTreeMap, BTreeSet}; #[derive(Default, Deserialize, Clone, Debug)] @@ -572,16 +573,23 @@ pub fn compile( external: ExternalConfig, ) -> String { let source = match external.0.get("target").map(|s| s.as_str()) { - Some("canister_call") | None => include_str!("rust_call.hbs"), - Some("agent") => include_str!("rust_agent.hbs"), - Some("stub") => include_str!("rust_stub.hbs"), + Some("canister_call") | None => Cow::Borrowed(include_str!("rust_call.hbs")), + Some("agent") => Cow::Borrowed(include_str!("rust_agent.hbs")), + Some("stub") => Cow::Borrowed(include_str!("rust_stub.hbs")), + Some("custom") => { + let template = external + .0 + .get("template") + .expect("template field expected for custom target"); + Cow::Owned(std::fs::read_to_string(template).unwrap()) + } _ => unimplemented!(), }; let (output, unused) = emit_bindgen(tree, env, actor); for e in unused { eprintln!("WARNING: path {e} is unused"); } - output_handlebar(output, external, source) + output_handlebar(output, external, &source) } pub enum TypePath { diff --git a/tools/didc/README.md b/tools/didc/README.md index 49326198..0140f272 100644 --- a/tools/didc/README.md +++ b/tools/didc/README.md @@ -15,7 +15,27 @@ SUBCOMMANDS: encode Encode Candid value decode Decode Candid binary data random Generate random Candid values - diff Diff two Candid values +``` + +## TOML config + +`didc bind -t rs` and `didc random` can take a TOML file to configure how `didc` generate Rust binding or random values. + +Rust bindgen can take an external Handlebar template with the following TOML file, + +```toml +[didc.rust] +target = "custom" # Other targets: canister_call, agent, stub +template = "template.hbs" # required for custom target +# any tags mentioned from hbs +candid_crate = "candid" +service_name = "service" + +[rust] +visibility = "pub(crate)" +attributes = "#[derive(CandidType, Deserialize, Debug)]" +GetBlocksResponse.attributes = "#[derive(CandidType, Deserialize, Debug, Clone, Serialize)]" +GetBlocksResponseArchivedBlocksItem.name = "ABetterName" ``` ## Examples @@ -41,10 +61,6 @@ $ didc decode '4449444c016d7c027c002a0301027d' $ didc decode '4449444c016d7c027c002a0301027d' -t '(int)' (42) -$ didc diff '(record{1;2;3}, 42)' '(record{1;5;9}, 42)' -record { edit { 1 put { 5 } }; edit { 2 put { 9 } }; } -skip - $ didc bind hello.did -t js export const idlFactory = ({ IDL }) => { return IDL.Service({ 'greet' : IDL.Func([IDL.Text], [IDL.Text], []) }); @@ -53,9 +69,9 @@ export const idlFactory = ({ IDL }) => { $ didc random -t '(int, text)' (-72_594_379_354_493_140_610_202_928_640_651_761_468, "_J`:t7^>") -$ didc random -t '(int, text)' -c '{ range = Some [-10, +10], text = "name" }' +$ didc random -t '(int, text)' -c 'random = { range = [-10, +10], text = "name" }' (-6, "Cindy Klocko") -$ didc random -d service.did -m method -f random.dhall -a '("seed argument")' -l js +$ didc random -d service.did -m method -c random.toml -a '("seed argument")' -l js [new BigNumber('-4'), 'Marcus Kris'] ``` diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index c0b59198..ee59bbff 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -218,7 +218,7 @@ fn main() -> Result<()> { "rs" => { use candid_parser::bindings::rust::{compile, Config, ExternalConfig}; let external = configs - .get_subtable(&["external".to_string(), "rust".to_string()]) + .get_subtable(&["didc".to_string(), "rust".to_string()]) .map(|x| x.clone().try_into().unwrap()) .unwrap_or(ExternalConfig::default()); let config = Config::new(configs); From 7755301c80273a642f53f78b4e3493f4e0ecde8e Mon Sep 17 00:00:00 2001 From: venkkatesh-sekar <94061546+venkkatesh-sekar@users.noreply.github.com> Date: Thu, 23 May 2024 11:29:23 +0200 Subject: [PATCH 06/36] Add new job fuzzing (#552) Co-authored-by: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> --- .github/workflows/rust.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3d63223e..c0ef9331 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -39,3 +39,19 @@ jobs: run: cargo clippy --features all --tests -- -D warnings - name: doc run: cargo doc + fuzzing: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust (nightly) + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + - name: Install cargo-fuzz + run: | + cargo install cargo-fuzz + - name: Build fuzzers + run: | + cd rust/candid + cargo +nightly fuzz build From 66cf68811fc622513dcc6966e2641f98522fe0d7 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:42:46 -0700 Subject: [PATCH 07/36] implement CandidType for serde_bytes::ByteArray (#557) * implement CandidType for serde_bytes::ByteArray * clippy * bump bench * bump --- .github/workflows/bench.yml | 2 +- Cargo.lock | 160 +++++++++++++++---------------- rust/bench/Cargo.lock | 70 +++++++------- rust/candid/fuzz/Cargo.lock | 142 +++++++++++++-------------- rust/candid/src/types/impls.rs | 13 +++ rust/candid_parser/src/assist.rs | 6 +- 6 files changed, 201 insertions(+), 192 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 19393119..afaf46ae 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -6,7 +6,7 @@ jobs: name: run benchmark runs-on: ubuntu-latest env: - RUSTC_VERSION: 1.77.0 + RUSTC_VERSION: 1.79.0 steps: - uses: actions/checkout@v4 - name: Checkout base branch diff --git a/Cargo.lock b/Cargo.lock index 04925dba..3c2e8e51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys", ] @@ -62,9 +62,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arbitrary" @@ -126,7 +126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" dependencies = [ "either", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -208,9 +208,9 @@ name = "candid_derive" version = "0.6.6" dependencies = [ "lazy_static", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -244,9 +244,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -262,9 +262,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "clap" -version = "4.5.4" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", "clap_derive", @@ -272,9 +272,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", @@ -284,21 +284,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "codespan-reporting" @@ -349,9 +349,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -451,9 +451,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "ena" @@ -672,7 +672,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.6", + "regex-automata 0.4.7", ] [[package]] @@ -689,9 +689,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libredox" @@ -705,9 +705,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" @@ -743,10 +743,10 @@ dependencies = [ "beef", "fnv", "lazy_static", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "regex-syntax", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -760,9 +760,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "new_debug_unreachable" @@ -819,9 +819,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -875,9 +875,9 @@ checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -956,9 +956,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -987,7 +987,7 @@ version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", ] [[package]] @@ -1022,9 +1022,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags", ] @@ -1042,13 +1042,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", + "regex-automata 0.4.7", "regex-syntax", ] @@ -1060,9 +1060,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1071,9 +1071,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustix" @@ -1090,9 +1090,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" @@ -1117,9 +1117,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.201" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -1145,13 +1145,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -1167,9 +1167,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -1281,18 +1281,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.63" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "unicode-ident", ] @@ -1343,22 +1343,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -1372,9 +1372,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", @@ -1384,18 +1384,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap", "serde", @@ -1436,9 +1436,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" @@ -1454,9 +1454,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" @@ -1586,9 +1586,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] diff --git a/rust/bench/Cargo.lock b/rust/bench/Cargo.lock index 50edc5f5..8e527578 100644 --- a/rust/bench/Cargo.lock +++ b/rust/bench/Cargo.lock @@ -173,7 +173,7 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -198,9 +198,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -544,7 +544,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -558,9 +558,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "new_debug_unreachable" @@ -605,9 +605,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -663,7 +663,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -721,9 +721,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -748,9 +748,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags", ] @@ -768,9 +768,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -780,9 +780,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -791,9 +791,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustversion" @@ -824,9 +824,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -842,13 +842,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -944,9 +944,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.65" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -990,7 +990,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1004,9 +1004,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", @@ -1025,9 +1025,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap", "serde", @@ -1068,9 +1068,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" @@ -1206,9 +1206,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] diff --git a/rust/candid/fuzz/Cargo.lock b/rust/candid/fuzz/Cargo.lock index 6da93d74..59f1cd8b 100644 --- a/rust/candid/fuzz/Cargo.lock +++ b/rust/candid/fuzz/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arbitrary" @@ -22,9 +22,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "binread" @@ -46,14 +46,14 @@ dependencies = [ "either", "proc-macro2", "quote", - "syn 1.0.107", + "syn 1.0.109", ] [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -66,7 +66,7 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "candid" -version = "0.10.4" +version = "0.10.8" dependencies = [ "anyhow", "binread", @@ -102,16 +102,18 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.66", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" dependencies = [ "jobserver", + "libc", + "once_cell", ] [[package]] @@ -122,18 +124,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -150,15 +152,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.3.3" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -166,15 +168,15 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -200,9 +202,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] @@ -221,15 +223,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libfuzzer-sys" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb09950ae85a0a94b27676cccf37da5ff13f27076aa1adbc6545dd0d0e1bd4e" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" dependencies = [ "arbitrary", "cc", @@ -238,11 +240,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", "serde", @@ -250,34 +251,33 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "paste" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pretty" @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -310,53 +310,53 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.8" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718dc5fff5b36f99093fc49b280cfc96ce6fc824317783bff5a1fed0c7a64819" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.66", ] [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -378,9 +378,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -389,9 +389,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -400,22 +400,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.66", ] [[package]] @@ -426,21 +426,21 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "version_check" diff --git a/rust/candid/src/types/impls.rs b/rust/candid/src/types/impls.rs index 923ffc59..f51493d0 100644 --- a/rust/candid/src/types/impls.rs +++ b/rust/candid/src/types/impls.rs @@ -166,6 +166,19 @@ impl CandidType for serde_bytes::Bytes { serializer.serialize_blob(self) } } +#[cfg_attr(docsrs, doc(cfg(feature = "serde_bytes")))] +#[cfg(feature = "serde_bytes")] +impl CandidType for serde_bytes::ByteArray { + fn _ty() -> Type { + TypeInner::Vec(TypeInner::Nat8.into()).into() + } + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: Serializer, + { + serializer.serialize_blob(self.as_slice()) + } +} macro_rules! map_impl { ($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => { diff --git a/rust/candid_parser/src/assist.rs b/rust/candid_parser/src/assist.rs index f92a89c4..0dfd3c5c 100644 --- a/rust/candid_parser/src/assist.rs +++ b/rust/candid_parser/src/assist.rs @@ -154,11 +154,7 @@ pub fn input(ctx: &Context, ty: &Type, dep: usize) -> Result { .with_prompt("Enter a text (type :e to use editor)") .interact()?; let text = if text == ":e" { - if let Some(rv) = Editor::new().edit("Enter your text")? { - rv - } else { - String::new() - } + Editor::new().edit("Enter your text")?.unwrap_or_default() } else { text }; From 223fe03b539d2a8ed1f62f8d1299858df8fee6cd Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Thu, 20 Jun 2024 16:50:46 -0700 Subject: [PATCH 08/36] more improvements for Rust bindgen (#558) * add clone for configs * add open_path * report unused * add stub * add rust parser to extract cdk functions; didc to take external.rust section * fix mode * refactor to report span * checkpoint, use codespan_reporting * good * fix * move rust_check to cdk * bump version * add def_use analysis * add custom target for didc * readme * generate only subset of bindings * s/method/func/ * checkpoint * checkpoint * checkpoint * use context * fix * add config_source * check unused at the property level * no scoped path * specialize result type * fix * prompt color * add use_type test * update tests * bump version * fix --- Cargo.lock | 5 +- Changelog.md | 17 +- rust/candid/Cargo.toml | 3 +- rust/candid/src/pretty/candid.rs | 3 + rust/candid/tests/serde.rs | 18 +- rust/candid_parser/Cargo.toml | 6 +- rust/candid_parser/src/bindings/analysis.rs | 54 +- rust/candid_parser/src/bindings/rust.rs | 523 ++++++++++++------ .../candid_parser/src/bindings/rust_agent.hbs | 3 + rust/candid_parser/src/bindings/rust_call.hbs | 3 + rust/candid_parser/src/bindings/rust_stub.hbs | 3 + rust/candid_parser/src/configs.rs | 169 ++++-- rust/candid_parser/src/random.rs | 136 ++++- rust/candid_parser/src/utils.rs | 16 + rust/candid_parser/tests/assets/example.did | 5 +- rust/candid_parser/tests/assets/example.toml | 1 + .../tests/assets/ok/example.d.ts | 14 +- .../candid_parser/tests/assets/ok/example.did | 9 +- rust/candid_parser/tests/assets/ok/example.js | 16 +- rust/candid_parser/tests/assets/ok/example.mo | 12 +- rust/candid_parser/tests/assets/ok/example.rs | 32 +- tools/didc/src/main.rs | 9 +- 22 files changed, 787 insertions(+), 270 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c2e8e51..832aa886 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,13 +180,14 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "candid" -version = "0.10.8" +version = "0.10.9" dependencies = [ "anyhow", "bincode", "binread", "byteorder", "candid_derive", + "candid_parser", "hex", "ic_principal", "leb128", @@ -215,7 +216,7 @@ dependencies = [ [[package]] name = "candid_parser" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "arbitrary", diff --git a/Changelog.md b/Changelog.md index ddca135f..0114116f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,30 +3,25 @@ ## 2024-05-03 -### candid_parser 0.2.0-beta.0 +### candid_parser 0.2.0-beta * Breaking changes: + Rewrite `configs` and `random` modules, adapting TOML format as the parser. `configs` module is no longer under a feature flag, and no longer depend on dhall. + Rewrite Rust bindgen to use the new `configs` module. Use `emit_bindgen` to generate type bindings, and use `output_handlebar` to provide a handlebar template for the generated module. `compile` function provides a default template. The generated file without config is exactly the same as before. - -* TO-DOs - + Spec for path and matching semantics - + Warning for unused path - + Rust bindgen: - * Generate `use_type` tests. How to handle recursive types? - * Threading state through `nominalize` - * When the path starts with method, duplicate type definition when necessary. - * Number label renaming +* Non-breaking changes: + + `utils::check_rust_type` function to check if a Rust type implements the provided candid type. ## 2024-04-11 -### Candid 0.10.5 -- 0.10.8 +### Candid 0.10.5 -- 0.10.9 * Switch `HashMap` to `BTreeMap` in serialization and `T::ty()`. This leads to around 20% perf improvement for serializing complicated types. * Disable memoization for unrolled types in serialization to save cycle cost. In some cases, type table can get slightly larger, but it's worth the trade off. * Fix bug in `text_size` * Fix decoding cost calculation overflow * Fix length check in decoding principal type +* Implement `CandidType` for `serde_bytes::ByteArray` +* Add `pretty::candid::pp_init_args` function to pretty print init args ## 2024-02-27 diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index 6a61a33b..326d7bac 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid" -version = "0.10.8" +version = "0.10.9" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] @@ -39,6 +39,7 @@ rand.workspace = true serde_cbor = "0.11.2" serde_json = "1.0.74" bincode = "1.3.3" +candid_parser = { path = "../candid_parser" } [features] bignum = ["dep:num-bigint", "dep:num-traits"] diff --git a/rust/candid/src/pretty/candid.rs b/rust/candid/src/pretty/candid.rs index c012da9d..5f67607d 100644 --- a/rust/candid/src/pretty/candid.rs +++ b/rust/candid/src/pretty/candid.rs @@ -205,6 +205,9 @@ fn pp_actor(ty: &Type) -> RcDoc { } } +pub fn pp_init_args<'a>(env: &'a TypeEnv, args: &'a [Type]) -> RcDoc<'a> { + pp_defs(env).append(pp_args(args)) +} pub fn compile(env: &TypeEnv, actor: &Option) -> String { match actor { None => pp_defs(env).pretty(LINE_WIDTH).to_string(), diff --git a/rust/candid/tests/serde.rs b/rust/candid/tests/serde.rs index f42133a9..87113a46 100644 --- a/rust/candid/tests/serde.rs +++ b/rust/candid/tests/serde.rs @@ -2,6 +2,7 @@ use candid::{ decode_one_with_config, encode_one, CandidType, Decode, DecoderConfig, Deserialize, Encode, Int, Nat, }; +use candid_parser::utils::check_rust_type; #[test] fn test_error() { @@ -263,6 +264,8 @@ fn test_struct() { // with memoization on the unrolled type, type table will have 2 entries. // all_check(list, "4449444c026e016c02a0d2aca8047c90eddae70400010000"); all_check(list, "4449444c036e016c02a0d2aca8047c90eddae704026e01010000"); + check_rust_type::("type List = record {head: int; tail: opt List}; (List)").unwrap(); + check_rust_type::("type T = record {head: int; tail: opt T}; (T)").unwrap(); } #[test] @@ -289,6 +292,10 @@ fn optional_fields() { bar: bool, baz: Option, } + check_rust_type::( + "(record { foo: opt nat8; bar: bool; baz: opt variant { Foo; Bar: bool; Baz: bool }})", + ) + .unwrap(); let bytes = encode(&OldStruct { bar: true, baz: Some(Old::Foo), @@ -334,6 +341,13 @@ fn test_equivalent_types() { struct TypeB { typea: Option, } + check_rust_type::( + r#" +type A = record { typeb: opt B }; +type B = record { typea: opt A }; +(record { typeas: vec A })"#, + ) + .unwrap(); // Encode to the following types leads to equivalent but different representations of TypeA all_check( RootType { typeas: Vec::new() }, @@ -569,6 +583,7 @@ fn test_tuple() { (Int::from(42), "💩".to_string()), "4449444c016c02007c017101002a04f09f92a9", ); + check_rust_type::<(Int, String)>("(record {int; text})").unwrap(); let none: Option = None; let bytes = hex("4449444c046c04007c017e020103026d7c6e036c02a0d2aca8047c90eddae7040201002b010302030400"); @@ -677,6 +692,7 @@ fn test_field_rename() { #[serde(rename = "a-b")] B(u8), } + check_rust_type::(r#"(variant { "1-2 + 3": int8; "a-b": nat8 })"#).unwrap(); all_check(E2::A(42), "4449444c016b02b684a7027bb493ee970d770100012a"); #[derive(CandidType, Deserialize, PartialEq, Debug)] struct S2 { @@ -698,7 +714,7 @@ fn test_generics() { g1: T, g2: E, } - + check_rust_type::>("(record {g1: int32; g2: bool})").unwrap(); let res = G { g1: Int::from(42), g2: true, diff --git a/rust/candid_parser/Cargo.toml b/rust/candid_parser/Cargo.toml index 77051a3a..ecf6052c 100644 --- a/rust/candid_parser/Cargo.toml +++ b/rust/candid_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid_parser" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] @@ -33,13 +33,13 @@ logos = "0.14" convert_case = "0.6" handlebars = "5.1" toml = { version = "0.8", default-features = false, features = ["parse"] } +console = "0.15" arbitrary = { workspace = true, optional = true } fake = { version = "2.4", optional = true } rand = { version = "0.8", optional = true } num-traits = { workspace = true, optional = true } dialoguer = { version = "0.11", default-features = false, features = ["editor", "completion"], optional = true } -console = { version = "0.15", optional = true } ctrlc = { version = "3.4", optional = true } [dev-dependencies] @@ -49,7 +49,7 @@ rand.workspace = true [features] random = ["dep:arbitrary", "dep:fake", "dep:rand", "dep:num-traits"] -assist = ["dep:dialoguer", "dep:console", "dep:ctrlc"] +assist = ["dep:dialoguer", "dep:ctrlc"] all = ["random", "assist"] # docs.rs-specific configuration diff --git a/rust/candid_parser/src/bindings/analysis.rs b/rust/candid_parser/src/bindings/analysis.rs index 6d8f717c..8a133a69 100644 --- a/rust/candid_parser/src/bindings/analysis.rs +++ b/rust/candid_parser/src/bindings/analysis.rs @@ -1,6 +1,17 @@ use crate::Result; use candid::types::{Type, TypeEnv, TypeInner}; -use std::collections::BTreeSet; +use std::collections::{BTreeMap, BTreeSet}; + +/// Select a subset of methods from an actor. +pub fn project_methods(env: &TypeEnv, actor: &Option, methods: &[String]) -> Option { + let service = env.as_service(actor.as_ref()?).ok()?; + let filtered = service + .iter() + .filter(|(name, _)| methods.contains(name)) + .cloned() + .collect(); + Some(TypeInner::Service(filtered).into()) +} /// Same as chase_actor, with seen set as part of the type. Used for chasing type names from type definitions. pub fn chase_type<'a>( @@ -53,6 +64,47 @@ pub fn chase_actor<'a>(env: &'a TypeEnv, actor: &'a Type) -> Result chase_type(&mut seen, &mut res, env, actor)?; Ok(res) } +/// Given an actor, return a map from variable names to the (methods, arg) that use them. +pub fn chase_def_use<'a>( + env: &'a TypeEnv, + actor: &'a Type, +) -> Result>> { + let mut res = BTreeMap::new(); + let actor = env.trace_type(actor)?; + if let TypeInner::Class(args, _) = actor.as_ref() { + for (i, arg) in args.iter().enumerate() { + let mut used = Vec::new(); + chase_type(&mut BTreeSet::new(), &mut used, env, arg)?; + for var in used { + res.entry(var.to_string()) + .or_insert_with(Vec::new) + .push(format!("init.arg{}", i)); + } + } + } + for (id, ty) in env.as_service(&actor)? { + let func = env.as_func(ty)?; + for (i, arg) in func.args.iter().enumerate() { + let mut used = Vec::new(); + chase_type(&mut BTreeSet::new(), &mut used, env, arg)?; + for var in used { + res.entry(var.to_string()) + .or_insert_with(Vec::new) + .push(format!("{}.arg{}", id, i)); + } + } + for (i, arg) in func.rets.iter().enumerate() { + let mut used = Vec::new(); + chase_type(&mut BTreeSet::new(), &mut used, env, arg)?; + for var in used { + res.entry(var.to_string()) + .or_insert_with(Vec::new) + .push(format!("{}.ret{}", id, i)); + } + } + } + Ok(res) +} pub fn chase_types<'a>(env: &'a TypeEnv, tys: &'a [Type]) -> Result> { let mut seen = BTreeSet::new(); diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index 3e66a2f0..facad992 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -1,10 +1,11 @@ use super::analysis::{chase_actor, infer_rec}; use crate::{ - configs::{ConfigState, ConfigTree, Configs, StateElem}, + configs::{ConfigState, ConfigTree, Configs, Context, StateElem}, Deserialize, }; use candid::pretty::utils::*; use candid::types::{Field, Function, Label, SharedLabel, Type, TypeEnv, TypeInner}; +use console::style; use convert_case::{Case, Casing}; use pretty::RcDoc; use serde::Serialize; @@ -19,34 +20,65 @@ pub struct BindingConfig { visibility: Option, } impl ConfigState for BindingConfig { - fn merge_config(&mut self, config: &Self, elem: Option<&StateElem>, _is_recursive: bool) { + fn merge_config(&mut self, config: &Self, ctx: Option) -> Vec { + let mut res = Vec::new(); self.name.clone_from(&config.name); + res.push("name"); // match use_type can survive across types, so that label.use_type works - if !matches!(elem, Some(StateElem::Label(_))) { + if ctx + .as_ref() + .is_some_and(|ctx| matches!(ctx.elem, StateElem::Type(_) | StateElem::TypeStr(_))) + { if let Some(use_type) = &config.use_type { self.use_type = Some(use_type.clone()); + res.push("use_type"); } } else { self.use_type.clone_from(&config.use_type); + res.push("use_type"); } // matched attributes can survive across labels, so that record.attributes works - if matches!(elem, Some(StateElem::Label(_))) { + if ctx + .as_ref() + .is_some_and(|ctx| matches!(ctx.elem, StateElem::Label(_))) + { if let Some(attr) = &config.attributes { self.attributes = Some(attr.clone()); + res.push("attributes"); } } else { self.attributes.clone_from(&config.attributes); + res.push("attributes"); } if config.visibility.is_some() { self.visibility.clone_from(&config.visibility); + res.push("visibility"); } + res.into_iter().map(|f| f.to_string()).collect() } fn update_state(&mut self, _elem: &StateElem) {} fn restore_state(&mut self, _elem: &StateElem) {} + fn list_properties(&self) -> Vec { + let mut res = Vec::new(); + if self.name.is_some() { + res.push("name"); + } + if self.use_type.is_some() { + res.push("use_type"); + } + if self.attributes.is_some() { + res.push("attributes"); + } + if self.visibility.is_some() { + res.push("visibility"); + } + res.into_iter().map(|f| f.to_string()).collect() + } } -pub struct State<'a> { +struct State<'a> { state: crate::configs::State<'a, BindingConfig>, recs: RecPoints<'a>, + tests: BTreeMap, } type RecPoints<'a> = BTreeSet<&'a str>; @@ -59,6 +91,17 @@ pub(crate) fn is_tuple(fs: &[Field]) -> bool { .enumerate() .any(|(i, field)| field.id.get_id() != (i as u32)) } +fn as_result(fs: &[Field]) -> Option<(&Type, &Type)> { + match fs { + [Field { id: ok, ty: t_ok }, Field { id: err, ty: t_err }] + if **ok == Label::Named("Ok".to_string()) + && **err == Label::Named("Err".to_string()) => + { + Some((t_ok, t_err)) + } + _ => None, + } +} static KEYWORDS: [&str; 51] = [ "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", @@ -97,13 +140,46 @@ fn pp_vis<'a>(vis: &Option) -> RcDoc<'a> { None => RcDoc::text("pub "), } } + impl<'a> State<'a> { + fn generate_test(&mut self, src: &Type, use_type: &str) { + if self.tests.contains_key(use_type) { + return; + } + let def_list = chase_actor(self.state.env, src).unwrap(); + let env = TypeEnv( + self.state + .env + .0 + .iter() + .filter(|(k, _)| def_list.contains(&k.as_str())) + .map(|(k, v)| (k.clone(), v.clone())) + .collect(), + ); + let src = candid::pretty::candid::pp_init_args(&env, &[src.clone()]) + .pretty(80) + .to_string(); + let match_path = self.state.config_source.get("use_type").unwrap().join("."); + let test_name = use_type.replace(|c: char| !c.is_ascii_alphanumeric(), "_"); + let body = format!( + r##"#[test] +fn test_{test_name}() {{ + // Generated from {match_path}.use_type = "{use_type}" + let candid_src = r#"{src}"#; + candid_parser::utils::check_rust_type::<{use_type}>(candid_src).unwrap(); +}}"## + ); + self.tests.insert(use_type.to_string(), body); + } fn pp_ty<'b>(&mut self, ty: &'b Type, is_ref: bool) -> RcDoc<'b> { use TypeInner::*; let elem = StateElem::Type(ty); let old = self.state.push_state(&elem); let res = if let Some(t) = &self.state.config.use_type { - RcDoc::text(t.clone()) + let res = RcDoc::text(t.clone()); + self.generate_test(ty, &t.clone()); + self.state.update_stats("use_type"); + res } else { match ty.as_ref() { Null => str("()"), @@ -125,7 +201,9 @@ impl<'a> State<'a> { Empty => str("candid::Empty"), Var(ref id) => { let name = if let Some(name) = &self.state.config.name { - RcDoc::text(name.clone()) + let res = RcDoc::text(name.clone()); + self.state.update_stats("name"); + res } else { ident(id, Some(Case::Pascal)) }; @@ -141,8 +219,16 @@ impl<'a> State<'a> { Vec(ref t) if matches!(t.as_ref(), Nat8) => str("serde_bytes::ByteBuf"), Vec(ref t) => str("Vec").append(enclose("<", self.pp_ty(t, is_ref), ">")), Record(ref fs) => self.pp_record_fields(fs, false, is_ref), - Variant(_) => unreachable!(), // not possible after rewriting - Func(_) => unreachable!(), // not possible after rewriting + Variant(ref fs) => { + // only possible for result variant + let (ok, err) = as_result(fs).unwrap(); + let body = self + .pp_ty(ok, is_ref) + .append(", ") + .append(self.pp_ty(err, is_ref)); + str("std::result::Result").append(enclose("<", body, ">")) + } + Func(_) => unreachable!(), // not possible after rewriting Service(_) => unreachable!(), // not possible after rewriting Class(_, _) => unreachable!(), Knot(_) | Unknown | Future => unreachable!(), @@ -153,6 +239,7 @@ impl<'a> State<'a> { } fn pp_label<'b>(&mut self, id: &'b SharedLabel, is_variant: bool, need_vis: bool) -> RcDoc<'b> { let vis = if need_vis { + self.state.update_stats("visibility"); pp_vis(&self.state.config.visibility) } else { RcDoc::nil() @@ -164,10 +251,13 @@ impl<'a> State<'a> { .clone() .map(|s| RcDoc::text(s).append(RcDoc::line())) .unwrap_or(RcDoc::nil()); + self.state.update_stats("attributes"); match &**id { Label::Named(id) => { let (doc, is_rename) = if let Some(name) = &self.state.config.name { - (RcDoc::text(name.clone()), true) + let res = (RcDoc::text(name.clone()), true); + self.state.update_stats("name"); + res } else { let case = if is_variant { Some(Case::Pascal) } else { None }; ident_(id, case) @@ -193,6 +283,7 @@ impl<'a> State<'a> { let lab = i.to_string(); let old = self.state.push_state(&StateElem::Label(&lab)); let vis = if need_vis { + self.state.update_stats("visibility"); pp_vis(&self.state.config.visibility) } else { RcDoc::nil() @@ -270,6 +361,9 @@ impl<'a> State<'a> { .clone() .map(RcDoc::text) .unwrap_or_else(|| ident(id, Some(Case::Pascal))); + self.state.update_stats("name"); + self.state.update_stats("visibility"); + self.state.update_stats("attributes"); let vis = pp_vis(&self.state.config.visibility); let derive = self .state @@ -294,13 +388,23 @@ impl<'a> State<'a> { .append(self.pp_record_fields(fs, true, false)) .append(separator) } - TypeInner::Variant(fs) => derive - .append(RcDoc::line()) - .append(vis) - .append("enum ") - .append(name) - .append(" ") - .append(self.pp_variant_fields(fs)), + TypeInner::Variant(fs) => { + if as_result(fs).is_some() { + vis.append(kwd("type")) + .append(name) + .append(" = ") + .append(self.pp_ty(ty, false)) + .append(";") + } else { + derive + .append(RcDoc::line()) + .append(vis) + .append("enum ") + .append(name) + .append(" ") + .append(self.pp_variant_fields(fs)) + } + } TypeInner::Func(func) => str("candid::define_function!(") .append(vis) .append(name) @@ -396,6 +500,7 @@ impl<'a> State<'a> { .name .clone() .unwrap_or_else(|| ident(id, Some(Case::Snake)).pretty(LINE_WIDTH).to_string()); + self.state.update_stats("name"); let args: Vec<_> = func .args .iter() @@ -409,6 +514,7 @@ impl<'a> State<'a> { .name .clone() .unwrap_or_else(|| lab.clone()); + self.state.update_stats("name"); let res = self.pp_ty(ty, true); self.state.pop_state(old, StateElem::Label(&lab)); (name, res) @@ -465,6 +571,7 @@ impl<'a> State<'a> { .name .clone() .unwrap_or_else(|| lab.clone()); + self.state.update_stats("name"); let res = self.pp_ty(ty, true); self.state.pop_state(old, StateElem::Label(&lab)); (name, res.pretty(LINE_WIDTH).to_string()) @@ -489,6 +596,7 @@ pub struct Output { pub type_defs: String, pub methods: Vec, pub init_args: Option>, + pub tests: String, } #[derive(Serialize, Debug)] pub struct Method { @@ -499,29 +607,37 @@ pub struct Method { pub mode: String, } pub fn emit_bindgen(tree: &Config, env: &TypeEnv, actor: &Option) -> (Output, Vec) { - let (env, actor) = nominalize_all(env, actor); - let def_list: Vec<_> = if let Some(actor) = &actor { + let mut state = NominalState { + state: crate::configs::State::new(&tree.0, env), + }; + let (env, actor) = state.nominalize_all(actor); + let old_stats = state.state.stats.clone(); + let def_list = if let Some(actor) = &actor { chase_actor(&env, actor).unwrap() } else { - env.0.iter().map(|pair| pair.0.as_ref()).collect() + env.0.iter().map(|pair| pair.0.as_ref()).collect::>() }; let recs = infer_rec(&env, &def_list).unwrap(); let mut state = State { state: crate::configs::State::new(&tree.0, &env), recs, + tests: BTreeMap::new(), }; + state.state.stats = old_stats; let defs = state.pp_defs(&def_list); let (methods, init_args) = if let Some(actor) = &actor { state.pp_actor(actor) } else { (Vec::new(), None) }; + let tests = state.tests.into_values().collect::>().join("\n"); let unused = state.state.report_unused(); ( Output { type_defs: defs.pretty(LINE_WIDTH).to_string(), methods, init_args, + tests, }, unused, ) @@ -535,12 +651,14 @@ pub fn output_handlebar(output: Output, config: ExternalConfig, template: &str) type_defs: String, methods: Vec, init_args: Option>, + tests: String, } let data = HBOutput { type_defs: output.type_defs, methods: output.methods, external: config.0, init_args: output.init_args, + tests: output.tests, }; hbs.render_template(template, &data).unwrap() } @@ -587,7 +705,11 @@ pub fn compile( }; let (output, unused) = emit_bindgen(tree, env, actor); for e in unused { - eprintln!("WARNING: path {e} is unused"); + eprintln!( + "{} path {} is unused", + style("WARNING:").red().bold(), + style(e).green() + ); } output_handlebar(output, external, &source) } @@ -615,170 +737,231 @@ fn path_to_var(path: &[TypePath]) -> String { .collect(); name.join("_").to_case(Case::Pascal) } -// Convert structural typing to nominal typing to fit Rust's type system -fn nominalize(env: &mut TypeEnv, path: &mut Vec, t: &Type) -> Type { - match t.as_ref() { - TypeInner::Opt(ty) => { - path.push(TypePath::Opt); - let ty = nominalize(env, path, ty); - path.pop(); - TypeInner::Opt(ty) - } - TypeInner::Vec(ty) => { - path.push(TypePath::Vec); - let ty = nominalize(env, path, ty); - path.pop(); - TypeInner::Vec(ty) - } - TypeInner::Record(fs) => { - if matches!( - path.last(), - None | Some(TypePath::VariantField(_)) | Some(TypePath::Id(_)) - ) || is_tuple(fs) - { - let fs: Vec<_> = fs - .iter() - .map(|Field { id, ty }| { - path.push(TypePath::RecordField(id.to_string())); - let ty = nominalize(env, path, ty); - path.pop(); - Field { id: id.clone(), ty } - }) - .collect(); - TypeInner::Record(fs) - } else { - let new_var = path_to_var(path); - let ty = nominalize( - env, - &mut vec![TypePath::Id(new_var.clone())], - &TypeInner::Record(fs.to_vec()).into(), - ); - env.0.insert(new_var.clone(), ty); - TypeInner::Var(new_var) +struct NominalState<'a> { + state: crate::configs::State<'a, BindingConfig>, +} +impl<'a> NominalState<'a> { + // Convert structural typing to nominal typing to fit Rust's type system + fn nominalize(&mut self, env: &mut TypeEnv, path: &mut Vec, t: &Type) -> Type { + let elem = StateElem::Type(t); + let old = if matches!(t.as_ref(), TypeInner::Func(_)) { + // strictly speaking, we want to avoid func label from the main service. But this is probably good enough. + None + } else { + Some(self.state.push_state(&elem)) + }; + let res = match t.as_ref() { + TypeInner::Opt(ty) => { + path.push(TypePath::Opt); + let ty = self.nominalize(env, path, ty); + path.pop(); + TypeInner::Opt(ty) } - } - TypeInner::Variant(fs) => match path.last() { - None | Some(TypePath::Id(_)) => { - let fs: Vec<_> = fs - .iter() - .map(|Field { id, ty }| { - path.push(TypePath::VariantField(id.to_string())); - let ty = nominalize(env, path, ty); - path.pop(); - Field { id: id.clone(), ty } - }) - .collect(); - TypeInner::Variant(fs) + TypeInner::Vec(ty) => { + path.push(TypePath::Vec); + let ty = self.nominalize(env, path, ty); + path.pop(); + TypeInner::Vec(ty) } - Some(_) => { - let new_var = path_to_var(path); - let ty = nominalize( - env, - &mut vec![TypePath::Id(new_var.clone())], - &TypeInner::Variant(fs.to_vec()).into(), - ); - env.0.insert(new_var.clone(), ty); - TypeInner::Var(new_var) + TypeInner::Record(fs) => { + if matches!( + path.last(), + None | Some(TypePath::VariantField(_)) | Some(TypePath::Id(_)) + ) || is_tuple(fs) + { + let fs: Vec<_> = fs + .iter() + .map(|Field { id, ty }| { + let lab = id.to_string(); + let elem = StateElem::Label(&lab); + let old = self.state.push_state(&elem); + path.push(TypePath::RecordField(id.to_string())); + let ty = self.nominalize(env, path, ty); + path.pop(); + self.state.pop_state(old, elem); + Field { id: id.clone(), ty } + }) + .collect(); + TypeInner::Record(fs) + } else { + let new_var = if let Some(name) = &self.state.config.name { + let res = name.to_string(); + self.state.update_stats("name"); + res + } else { + path_to_var(path) + }; + let ty = self.nominalize( + env, + &mut vec![TypePath::Id(new_var.clone())], + &TypeInner::Record(fs.to_vec()).into(), + ); + env.0.insert(new_var.clone(), ty); + TypeInner::Var(new_var) + } } - }, - TypeInner::Func(func) => match path.last() { - None | Some(TypePath::Id(_)) => { - let func = func.clone(); - TypeInner::Func(Function { - modes: func.modes, - args: func - .args - .into_iter() - .enumerate() - .map(|(i, ty)| { - let i = if i == 0 { - "".to_string() - } else { - i.to_string() - }; - path.push(TypePath::Func(format!("arg{i}"))); - let ty = nominalize(env, path, &ty); + TypeInner::Variant(fs) => { + if matches!(path.last(), None | Some(TypePath::Id(_))) || as_result(fs).is_some() { + let fs: Vec<_> = fs + .iter() + .map(|Field { id, ty }| { + let lab = id.to_string(); + let old = self.state.push_state(&StateElem::Label(&lab)); + path.push(TypePath::VariantField(id.to_string())); + let ty = self.nominalize(env, path, ty); path.pop(); - ty + self.state.pop_state(old, StateElem::Label(&lab)); + Field { id: id.clone(), ty } }) - .collect(), - rets: func - .rets - .into_iter() - .enumerate() - .map(|(i, ty)| { - let i = if i == 0 { - "".to_string() - } else { - i.to_string() - }; - path.push(TypePath::Func(format!("ret{i}"))); - let ty = nominalize(env, path, &ty); + .collect(); + TypeInner::Variant(fs) + } else { + let new_var = if let Some(name) = &self.state.config.name { + let res = name.to_string(); + self.state.update_stats("name"); + res + } else { + path_to_var(path) + }; + let ty = self.nominalize( + env, + &mut vec![TypePath::Id(new_var.clone())], + &TypeInner::Variant(fs.to_vec()).into(), + ); + env.0.insert(new_var.clone(), ty); + TypeInner::Var(new_var) + } + } + TypeInner::Func(func) => match path.last() { + None | Some(TypePath::Id(_)) => { + let func = func.clone(); + TypeInner::Func(Function { + modes: func.modes, + args: func + .args + .into_iter() + .enumerate() + .map(|(i, ty)| { + let lab = format!("arg{i}"); + let old = self.state.push_state(&StateElem::Label(&lab)); + let idx = if i == 0 { + "".to_string() + } else { + i.to_string() + }; + path.push(TypePath::Func(format!("arg{idx}"))); + let ty = self.nominalize(env, path, &ty); + path.pop(); + self.state.pop_state(old, StateElem::Label(&lab)); + ty + }) + .collect(), + rets: func + .rets + .into_iter() + .enumerate() + .map(|(i, ty)| { + let lab = format!("ret{i}"); + let old = self.state.push_state(&StateElem::Label(&lab)); + let idx = if i == 0 { + "".to_string() + } else { + i.to_string() + }; + path.push(TypePath::Func(format!("ret{idx}"))); + let ty = self.nominalize(env, path, &ty); + path.pop(); + self.state.pop_state(old, StateElem::Label(&lab)); + ty + }) + .collect(), + }) + } + Some(_) => { + let new_var = if let Some(name) = &self.state.config.name { + let res = name.to_string(); + self.state.update_stats("name"); + res + } else { + path_to_var(path) + }; + let ty = self.nominalize( + env, + &mut vec![TypePath::Id(new_var.clone())], + &TypeInner::Func(func.clone()).into(), + ); + env.0.insert(new_var.clone(), ty); + TypeInner::Var(new_var) + } + }, + TypeInner::Service(serv) => match path.last() { + None | Some(TypePath::Id(_)) => TypeInner::Service( + serv.iter() + .map(|(meth, ty)| { + let lab = meth.to_string(); + let old = self.state.push_state(&StateElem::Label(&lab)); + path.push(TypePath::Id(meth.to_string())); + let ty = self.nominalize(env, path, ty); path.pop(); - ty + self.state.pop_state(old, StateElem::Label(&lab)); + (meth.clone(), ty) }) .collect(), - }) - } - Some(_) => { - let new_var = path_to_var(path); - let ty = nominalize( - env, - &mut vec![TypePath::Id(new_var.clone())], - &TypeInner::Func(func.clone()).into(), - ); - env.0.insert(new_var.clone(), ty); - TypeInner::Var(new_var) - } - }, - TypeInner::Service(serv) => match path.last() { - None | Some(TypePath::Id(_)) => TypeInner::Service( - serv.iter() - .map(|(meth, ty)| { - path.push(TypePath::Id(meth.to_string())); - let ty = nominalize(env, path, ty); + ), + Some(_) => { + let new_var = if let Some(name) = &self.state.config.name { + let res = name.to_string(); + self.state.update_stats("name"); + res + } else { + path_to_var(path) + }; + let ty = self.nominalize( + env, + &mut vec![TypePath::Id(new_var.clone())], + &TypeInner::Service(serv.clone()).into(), + ); + env.0.insert(new_var.clone(), ty); + TypeInner::Var(new_var) + } + }, + TypeInner::Class(args, ty) => TypeInner::Class( + args.iter() + .map(|ty| { + let elem = StateElem::Label("init"); + let old = self.state.push_state(&elem); + path.push(TypePath::Init); + let ty = self.nominalize(env, path, ty); path.pop(); - (meth.clone(), ty) + self.state.pop_state(old, elem); + ty }) .collect(), + self.nominalize(env, path, ty), ), - Some(_) => { - let new_var = path_to_var(path); - let ty = nominalize( - env, - &mut vec![TypePath::Id(new_var.clone())], - &TypeInner::Service(serv.clone()).into(), - ); - env.0.insert(new_var.clone(), ty); - TypeInner::Var(new_var) - } - }, - TypeInner::Class(args, ty) => TypeInner::Class( - args.iter() - .map(|ty| { - path.push(TypePath::Init); - let ty = nominalize(env, path, ty); - path.pop(); - ty - }) - .collect(), - nominalize(env, path, ty), - ), - _ => return t.clone(), + t => t.clone(), + } + .into(); + if let Some(old) = old { + self.state.pop_state(old, elem); + } + res } - .into() -} -fn nominalize_all(env: &TypeEnv, actor: &Option) -> (TypeEnv, Option) { - let mut res = TypeEnv(Default::default()); - for (id, ty) in env.0.iter() { - let ty = nominalize(&mut res, &mut vec![TypePath::Id(id.clone())], ty); - res.0.insert(id.to_string(), ty); + fn nominalize_all(&mut self, actor: &Option) -> (TypeEnv, Option) { + let mut res = TypeEnv(Default::default()); + for (id, ty) in self.state.env.0.iter() { + let elem = StateElem::Label(id); + let old = self.state.push_state(&elem); + let ty = self.nominalize(&mut res, &mut vec![TypePath::Id(id.clone())], ty); + res.0.insert(id.to_string(), ty); + self.state.pop_state(old, elem); + } + let actor = actor + .as_ref() + .map(|ty| self.nominalize(&mut res, &mut vec![], ty)); + (res, actor) } - let actor = actor - .as_ref() - .map(|ty| nominalize(&mut res, &mut vec![], ty)); - (res, actor) } fn get_hbs() -> handlebars::Handlebars<'static> { use handlebars::*; diff --git a/rust/candid_parser/src/bindings/rust_agent.hbs b/rust/candid_parser/src/bindings/rust_agent.hbs index 9fffd9b4..f4521ae2 100644 --- a/rust/candid_parser/src/bindings/rust_agent.hbs +++ b/rust/candid_parser/src/bindings/rust_agent.hbs @@ -20,3 +20,6 @@ impl<'a> {{PascalCase service_name}}<'a> { pub const CANISTER_ID : Principal = Principal::from_slice(&[{{principal_slice canister_id}}]); // {{canister_id}} {{/if}} {{/if}} +{{#if tests}} +{{tests}} +{{/if}} diff --git a/rust/candid_parser/src/bindings/rust_call.hbs b/rust/candid_parser/src/bindings/rust_call.hbs index b12654b6..55fbf3a9 100644 --- a/rust/candid_parser/src/bindings/rust_call.hbs +++ b/rust/candid_parser/src/bindings/rust_call.hbs @@ -19,3 +19,6 @@ pub const CANISTER_ID : Principal = Principal::from_slice(&[{{principal_slice ca pub const {{snake_case service_name}} : {{PascalCase service_name}} = {{PascalCase service_name}}(CANISTER_ID); {{/if}} {{/if}} +{{#if tests}} +{{tests}} +{{/if}} diff --git a/rust/candid_parser/src/bindings/rust_stub.hbs b/rust/candid_parser/src/bindings/rust_stub.hbs index 5a85901a..32658194 100644 --- a/rust/candid_parser/src/bindings/rust_stub.hbs +++ b/rust/candid_parser/src/bindings/rust_stub.hbs @@ -16,3 +16,6 @@ fn {{this.name}}({{#each this.args}}{{#if (not @first)}}, {{/if}}{{this.0}}: {{t unimplemented!() } {{/each}} +{{#if tests}} +{{tests}} +{{/if}} diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index 4b4e600b..f6a50d94 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -6,13 +6,18 @@ use toml::{Table, Value}; pub struct State<'a, T: ConfigState> { tree: &'a ConfigTree, - path: Vec, + pub path: Vec, open_tree: Option<&'a ConfigTree>, open_path: Vec, - stats: BTreeMap, u32>, + pub stats: BTreeMap, u32>, pub config: T, + pub config_source: BTreeMap>, pub env: &'a TypeEnv, } +pub struct ConfigBackup { + config: T, + config_source: BTreeMap>, +} #[derive(Debug)] pub enum StateElem<'a> { Type(&'a Type), @@ -33,8 +38,12 @@ pub enum ScopePos { impl<'a, T: ConfigState> State<'a, T> { pub fn new(tree: &'a ConfigTree, env: &'a TypeEnv) -> Self { let mut config = T::default(); + let mut config_source = BTreeMap::new(); if let Some(state) = &tree.state { - config.merge_config(state, None, false); + let delta = config.merge_config(state, None); + for field in delta { + config_source.insert(field, vec![]); + } } Self { tree, @@ -43,6 +52,7 @@ impl<'a, T: ConfigState> State<'a, T> { path: Vec::new(), stats: BTreeMap::new(), config, + config_source, env, } } @@ -54,7 +64,7 @@ impl<'a, T: ConfigState> State<'a, T> { self.open_path.clear(); } Some(scope) => { - let mut path = vec![format!("method:{}", scope.method)]; + let mut path = vec![format!("func:{}", scope.method)]; match self.tree.with_prefix(&path) { Some(tree) => { match scope.position { @@ -73,7 +83,9 @@ impl<'a, T: ConfigState> State<'a, T> { } } if let Some(state) = self.open_tree.unwrap().state.as_ref() { - self.config.merge_config(state, None, false); + let delta = self.config.merge_config(state, None); + let path = self.open_path.clone(); + self.update_config_source(delta, &path); } } None => { @@ -85,9 +97,9 @@ impl<'a, T: ConfigState> State<'a, T> { } } /// Update config based on the new elem in the path. Return the old state AFTER `update_state`. - pub fn push_state(&mut self, elem: &StateElem) -> T { + pub fn push_state(&mut self, elem: &StateElem) -> ConfigBackup { self.config.update_state(elem); - let old_config = self.config.clone(); + let old_config = self.to_backup(); self.path.push(elem.to_string()); let mut from_open = false; let new_state = if let Some(subtree) = self.open_tree { @@ -106,24 +118,33 @@ impl<'a, T: ConfigState> State<'a, T> { vec![] }; matched_path.extend_from_slice(&self.path[idx..]); - self.stats - .entry(matched_path) - .and_modify(|v| *v += 1) - .or_insert(1); - self.config.merge_config(state, Some(elem), is_recursive); - //eprintln!("match path: {:?}, state: {:?}", self.path, self.config); + let ctx = Context { elem, is_recursive }; + let delta = self.config.merge_config(state, Some(ctx)); + self.update_config_source(delta, &matched_path); } else { - self.config - .merge_config(&T::unmatched_config(), Some(elem), false); - //eprintln!("path: {:?}, state: {:?}", self.path, self.config); + let ctx = Context { + elem, + is_recursive: false, + }; + let delta = self.config.merge_config(&T::unmatched_config(), Some(ctx)); + for field in delta { + self.config_source.remove(&field); + } } old_config } - pub fn pop_state(&mut self, old_config: T, elem: StateElem) { - self.config = old_config; + pub fn pop_state(&mut self, old_config: ConfigBackup, elem: StateElem) { + self.restore_from_backup(old_config); assert_eq!(self.path.pop(), Some(elem.to_string())); self.config.restore_state(&elem); } + pub fn update_stats(&mut self, key: &str) { + if let Some(path) = self.config_source.get(key) { + let mut path = path.clone(); + path.push(key.to_string()); + self.stats.entry(path).and_modify(|v| *v += 1).or_insert(1); + } + } pub fn report_unused(&self) -> Vec { let mut res = BTreeSet::new(); self.tree.traverse(&mut vec![], &mut res); @@ -144,12 +165,35 @@ impl<'a, T: ConfigState> State<'a, T> { .map(|(k, v)| (k.join("."), v)) .collect() } + fn update_config_source(&mut self, delta: Vec, path: &[String]) { + for field in delta { + self.config_source.insert(field, path.to_vec()); + } + } + fn to_backup(&self) -> ConfigBackup { + ConfigBackup { + config: self.config.clone(), + config_source: self.config_source.clone(), + } + } + fn restore_from_backup(&mut self, bak: ConfigBackup) { + self.config = bak.config; + self.config_source = bak.config_source; + } +} +#[derive(Debug)] +pub struct Context<'a> { + pub elem: &'a StateElem<'a>, + pub is_recursive: bool, } pub trait ConfigState: DeserializeOwned + Default + Clone + std::fmt::Debug { - fn merge_config(&mut self, config: &Self, elem: Option<&StateElem>, is_recursive: bool); + /// Specifies the merging semantics of two configs, returns a vector of updated config fields. + fn merge_config(&mut self, config: &Self, ctx: Option) -> Vec; fn update_state(&mut self, elem: &StateElem); fn restore_state(&mut self, elem: &StateElem); + /// List the properties in the current config, used for analyzing unused properties. + fn list_properties(&self) -> Vec; fn unmatched_config() -> Self { Self::default() } @@ -240,8 +284,12 @@ impl ConfigTree { result.state.as_ref() } pub fn traverse(&self, path: &mut Vec, res: &mut BTreeSet>) { - if self.state.is_some() { - res.insert(path.clone()); + if let Some(state) = &self.state { + for prop in state.list_properties() { + let mut path = path.clone(); + path.push(prop); + res.insert(path); + } } for (k, v) in self.subtree.iter() { path.push(k.clone()); @@ -289,8 +337,8 @@ fn is_repeated(path: &[String], matched: &[String]) -> bool { } false } -fn special_key(key: &str) -> bool { - key.starts_with("method:") || key.starts_with("arg:") || key.starts_with("ret:") +pub fn is_scoped_key(key: &str) -> bool { + key.starts_with("func:") || key.starts_with("arg:") || key.starts_with("ret:") } fn generate_state_tree(v: Value) -> Result> { let mut subtree = BTreeMap::new(); @@ -301,7 +349,7 @@ fn generate_state_tree(v: Value) -> Result> { match v { Value::Table(_) => { let v = generate_state_tree(v)?; - let dep = if special_key(&k) { + let dep = if is_scoped_key(&k) { v.max_depth } else { v.max_depth + 1 @@ -356,7 +404,8 @@ fn path_name(t: &Type) -> String { TypeInner::Func(_) => "func", TypeInner::Service(_) => "service", TypeInner::Future => "future", - TypeInner::Class(..) | TypeInner::Unknown => unreachable!(), + TypeInner::Class(..) => "func:init", + TypeInner::Unknown => unreachable!(), } .to_string() } @@ -371,11 +420,14 @@ fn parse() { text: Option, } impl ConfigState for T { - fn merge_config(&mut self, config: &Self, _elem: Option<&StateElem>, is_recursive: bool) { + fn merge_config(&mut self, config: &Self, ctx: Option) -> Vec { + let mut res = vec!["depth", "text", "size"]; *self = config.clone(); - if is_recursive { + if ctx.is_some_and(|c| c.is_recursive) { self.size = Some(0); + res.pop(); } + res.into_iter().map(|f| f.to_string()).collect() } fn update_state(&mut self, _elem: &StateElem) { self.size = self.size.map(|s| s + 1); @@ -383,6 +435,19 @@ fn parse() { fn restore_state(&mut self, _elem: &StateElem) { self.size = self.size.map(|s| s - 1); } + fn list_properties(&self) -> Vec { + let mut res = Vec::new(); + if self.depth.is_some() { + res.push("depth"); + } + if self.size.is_some() { + res.push("size"); + } + if self.text.is_some() { + res.push("text"); + } + res.into_iter().map(|f| f.to_string()).collect() + } } let toml = r#" [random] @@ -391,8 +456,8 @@ val.text = "42" left.list = { depth = 1 } vec.nat8.text = "blob" Vec = { width = 2, size = 10 } -"method:f"."arg:0".list = { depth = 2, size = 20 } -"method:f".list = { depth = 3, size = 30 } +"func:f"."arg:0".list = { depth = 2, size = 20 } +"func:f".list = { depth = 3, size = 30 } "#; let configs = toml.parse::().unwrap(); let mut tree: ConfigTree = ConfigTree::from_configs("random", configs).unwrap(); @@ -464,13 +529,21 @@ Vec = { width = 2, size = 10 } }), 0, ); - assert_eq!(state.open_path, vec!["method:f", "arg:0"]); + assert_eq!(state.open_path, vec!["func:f", "arg:0"]); let old = state.push_state(&StateElem::Label("list")); + state.update_stats("depth"); + state.update_stats("size"); + state.update_stats("text"); assert_eq!(state.config.depth, Some(2)); assert_eq!(state.config.size, Some(20)); assert_eq!(state.config.text, None); - assert_eq!(old.size, None); + assert_eq!( + state.config_source.get("depth").unwrap().join("."), + "func:f.arg:0.list" + ); + assert_eq!(old.config.size, None); state.push_state(&StateElem::Label("val")); + state.update_stats("text"); assert_eq!(state.config.text, Some("42".to_string())); state.with_scope( &Some(Scope { @@ -479,29 +552,45 @@ Vec = { width = 2, size = 10 } }), 0, ); - assert_eq!(state.open_path, vec!["method:f"]); + assert_eq!(state.open_path, vec!["func:f"]); state.push_state(&StateElem::Label("list")); + state.update_stats("depth"); + state.update_stats("size"); assert_eq!(state.config.depth, Some(3)); assert_eq!(state.config.size, Some(0)); + assert_eq!( + state.config_source.get("depth").unwrap().join("."), + "func:f.list" + ); + assert_eq!(state.config_source.get("size").unwrap().join("."), "val"); state.with_scope(&None, 0); let old = state.push_state(&StateElem::Label("list")); + state.update_stats("depth"); + state.update_stats("size"); assert_eq!(state.config.depth, Some(20)); assert_eq!(state.config.size, Some(0)); - assert_eq!(old.size, Some(1)); + assert_eq!(state.config_source.get("depth").unwrap().join("."), "list"); + assert_eq!(state.config_source.get("size").unwrap().join("."), "val"); + assert_eq!(old.config.size, Some(1)); state.pop_state(old, StateElem::Label("list")); + state.update_stats("size"); + state.update_stats("depth"); assert_eq!(state.config.size, Some(0)); assert_eq!(state.config.depth, Some(3)); let stats = state.report_unused(); assert_eq!( stats.iter().map(|x| x.as_str()).collect::>(), [ - "Vec", - "a.b.c", - "a.b.c.d", - "a.b.d", - "left.a", - "left.list", - "vec.nat8" + "Vec.size", + "a.b.c.d.depth", + "a.b.c.depth", + "a.b.d.depth", + "depth", + "func:f.list.size", + "left.a.depth", + "left.list.depth", + "list.size", + "vec.nat8.text" ] ); } diff --git a/rust/candid_parser/src/random.rs b/rust/candid_parser/src/random.rs index 0fdc81bf..81b55870 100644 --- a/rust/candid_parser/src/random.rs +++ b/rust/candid_parser/src/random.rs @@ -1,5 +1,4 @@ -use super::configs::{ConfigState, Configs, Scope, State}; -use crate::configs::StateElem; +use super::configs::{ConfigState, Configs, Context, Scope, State, StateElem}; use crate::{Error, Result}; use arbitrary::{unstructured::Int, Arbitrary, Unstructured}; use candid::types::value::{IDLArgs, IDLField, IDLValue, VariantValue}; @@ -32,19 +31,35 @@ impl Default for GenConfig { } } impl ConfigState for GenConfig { - fn merge_config(&mut self, config: &Self, _elem: Option<&StateElem>, is_recursive: bool) { - self.range = config.range.or(self.range); + fn merge_config(&mut self, config: &Self, ctx: Option) -> Vec { + let mut res = Vec::new(); + if config.range.is_some() { + self.range = config.range; + res.push("range"); + } if config.text.is_some() { self.text.clone_from(&config.text); + res.push("text"); + } + if config.width.is_some() { + self.width = config.width; + res.push("width"); } - self.width = config.width.or(self.width); if config.value.is_some() { self.value.clone_from(&config.value); + res.push("value"); } - if !is_recursive { - self.depth = config.depth.or(self.depth); - self.size = config.size.or(self.size); + if ctx.as_ref().is_some_and(|c| !c.is_recursive) { + if config.depth.is_some() { + self.depth = config.depth; + res.push("depth"); + } + if config.size.is_some() { + self.size = config.size; + res.push("size"); + } } + res.into_iter().map(|s| s.to_string()).collect() } fn update_state(&mut self, elem: &StateElem) { if let StateElem::Type(t) = elem { @@ -71,6 +86,28 @@ impl ConfigState for GenConfig { size: None, } } + fn list_properties(&self) -> Vec { + let mut res = Vec::new(); + if self.range.is_some() { + res.push("range".to_string()); + } + if self.text.is_some() { + res.push("text".to_string()); + } + if self.width.is_some() { + res.push("width".to_string()); + } + if self.value.is_some() { + res.push("value".to_string()); + } + if self.depth.is_some() { + res.push("depth".to_string()); + } + if self.size.is_some() { + res.push("size".to_string()); + } + res + } } pub struct RandState<'a>(State<'a, GenConfig>); @@ -82,6 +119,7 @@ impl<'a> RandState<'a> { let v: IDLValue = super::parse_idl_value(v)?; let v = v.annotate_type(true, self.0.env, ty)?; self.0.pop_state(old_config, StateElem::Type(ty)); + self.0.update_stats("value"); return Ok(v); } let res = Ok(match ty.as_ref() { @@ -92,24 +130,60 @@ impl<'a> RandState<'a> { TypeInner::Null => IDLValue::Null, TypeInner::Reserved => IDLValue::Reserved, TypeInner::Bool => IDLValue::Bool(u.arbitrary()?), - TypeInner::Int => IDLValue::Int(arbitrary_num::(u, self.0.config.range)?.into()), - TypeInner::Nat => IDLValue::Nat(arbitrary_num::(u, self.0.config.range)?.into()), - TypeInner::Nat8 => IDLValue::Nat8(arbitrary_num(u, self.0.config.range)?), - TypeInner::Nat16 => IDLValue::Nat16(arbitrary_num(u, self.0.config.range)?), - TypeInner::Nat32 => IDLValue::Nat32(arbitrary_num(u, self.0.config.range)?), - TypeInner::Nat64 => IDLValue::Nat64(arbitrary_num(u, self.0.config.range)?), - TypeInner::Int8 => IDLValue::Int8(arbitrary_num(u, self.0.config.range)?), - TypeInner::Int16 => IDLValue::Int16(arbitrary_num(u, self.0.config.range)?), - TypeInner::Int32 => IDLValue::Int32(arbitrary_num(u, self.0.config.range)?), - TypeInner::Int64 => IDLValue::Int64(arbitrary_num(u, self.0.config.range)?), + TypeInner::Int => { + self.0.update_stats("range"); + IDLValue::Int(arbitrary_num::(u, self.0.config.range)?.into()) + } + TypeInner::Nat => { + self.0.update_stats("range"); + IDLValue::Nat(arbitrary_num::(u, self.0.config.range)?.into()) + } + TypeInner::Nat8 => { + self.0.update_stats("range"); + IDLValue::Nat8(arbitrary_num(u, self.0.config.range)?) + } + TypeInner::Nat16 => { + self.0.update_stats("range"); + IDLValue::Nat16(arbitrary_num(u, self.0.config.range)?) + } + TypeInner::Nat32 => { + self.0.update_stats("range"); + IDLValue::Nat32(arbitrary_num(u, self.0.config.range)?) + } + TypeInner::Nat64 => { + self.0.update_stats("range"); + IDLValue::Nat64(arbitrary_num(u, self.0.config.range)?) + } + TypeInner::Int8 => { + self.0.update_stats("range"); + IDLValue::Int8(arbitrary_num(u, self.0.config.range)?) + } + TypeInner::Int16 => { + self.0.update_stats("range"); + IDLValue::Int16(arbitrary_num(u, self.0.config.range)?) + } + TypeInner::Int32 => { + self.0.update_stats("range"); + IDLValue::Int32(arbitrary_num(u, self.0.config.range)?) + } + TypeInner::Int64 => { + self.0.update_stats("range"); + IDLValue::Int64(arbitrary_num(u, self.0.config.range)?) + } TypeInner::Float32 => IDLValue::Float32(u.arbitrary()?), TypeInner::Float64 => IDLValue::Float64(u.arbitrary()?), - TypeInner::Text => IDLValue::Text(arbitrary_text( - u, - &self.0.config.text, - &self.0.config.width, - )?), + TypeInner::Text => { + self.0.update_stats("text"); + self.0.update_stats("width"); + IDLValue::Text(arbitrary_text( + u, + &self.0.config.text, + &self.0.config.width, + )?) + } TypeInner::Opt(t) => { + self.0.update_stats("depth"); + self.0.update_stats("size"); let depths = if self.0.config.depth.is_some_and(|d| d <= 0) || self.0.config.size.is_some_and(|s| s <= 0) { @@ -125,8 +199,10 @@ impl<'a> RandState<'a> { } } TypeInner::Vec(t) => { + self.0.update_stats("width"); let width = self.0.config.width.or_else(|| { let elem_size = size(self.0.env, t).unwrap_or(MAX_DEPTH); + self.0.update_stats("size"); Some(std::cmp::max(0, self.0.config.size.unwrap_or(0)) as usize / elem_size) }); let len = arbitrary_len(u, width)?; @@ -156,6 +232,8 @@ impl<'a> RandState<'a> { let choices = fs .iter() .map(|Field { ty, .. }| size(self.0.env, ty).unwrap_or(MAX_DEPTH)); + self.0.update_stats("size"); + self.0.update_stats("depth"); let sizes: Vec<_> = if self.0.config.depth.is_some_and(|d| d <= 0) || self.0.config.size.is_some_and(|s| s <= 0) { @@ -178,10 +256,14 @@ impl<'a> RandState<'a> { IDLValue::Variant(VariantValue(Box::new(field), idx as u64)) } TypeInner::Principal => IDLValue::Principal(crate::Principal::arbitrary(u)?), - TypeInner::Func(_) => IDLValue::Func( - crate::Principal::arbitrary(u)?, - arbitrary_text(u, &self.0.config.text, &self.0.config.width)?, - ), + TypeInner::Func(_) => { + self.0.update_stats("text"); + self.0.update_stats("width"); + IDLValue::Func( + crate::Principal::arbitrary(u)?, + arbitrary_text(u, &self.0.config.text, &self.0.config.width)?, + ) + } TypeInner::Service(_) => IDLValue::Service(crate::Principal::arbitrary(u)?), _ => unimplemented!(), }); diff --git a/rust/candid_parser/src/utils.rs b/rust/candid_parser/src/utils.rs index 82a1b32c..f3027180 100644 --- a/rust/candid_parser/src/utils.rs +++ b/rust/candid_parser/src/utils.rs @@ -80,3 +80,19 @@ pub fn merge_init_args(candid: &str, init: &str) -> Result<(TypeEnv, Type)> { _ => unreachable!(), } } +/// Check if a Rust type implements a Candid type. The candid type is given using the init args format. +/// Note that this only checks structural equality, not equivalence. For recursive types, it may reject +/// an unrolled type. +pub fn check_rust_type(candid_args: &str) -> Result<()> { + use crate::{types::IDLInitArgs, typing::check_init_args}; + use candid::types::{internal::TypeContainer, subtype::equal, TypeEnv}; + let parsed = candid_args.parse::()?; + let mut env = TypeEnv::new(); + let args = check_init_args(&mut env, &TypeEnv::new(), &parsed)?; + let mut rust_env = TypeContainer::new(); + let ty = rust_env.add::(); + let ty = env.merge_type(rust_env.env, ty); + let mut gamma = std::collections::HashSet::new(); + equal(&mut gamma, &env, &args[0], &ty)?; + Ok(()) +} diff --git a/rust/candid_parser/tests/assets/example.did b/rust/candid_parser/tests/assets/example.did index 755ef09e..a0a865d1 100644 --- a/rust/candid_parser/tests/assets/example.did +++ b/rust/candid_parser/tests/assets/example.did @@ -3,18 +3,19 @@ import "import/a.did"; import service "import/b/b.did"; type my_type = principal; type List = opt record { head: int; tail: List }; -type f = func (List, func (int32) -> (int64)) -> (opt List); +type f = func (List, func (int32) -> (int64)) -> (opt List, res); type broker = service { find : (name: text) -> (service {up:() -> (); current:() -> (nat32)}); }; type nested = record { nat; nat; record {nat;int;}; record { nat; 0x2a:nat; nat8; }; 42:nat; 40:nat; variant{ A; 0x2a; B; C }; }; +type res = variant { Ok: nat; Err: empty }; service server : { f1 : (list, test: blob, opt bool) -> () oneway; g1 : (my_type, List, opt List, nested) -> (int, broker) query; h : (vec opt text, variant { A: nat; B: opt text }, opt List) -> (record { id: nat; 0x2a: record {} }); i : f; - x : (a,b) -> (opt a, opt b) composite_query; + x : (a,b) -> (opt a, opt b, variant { Ok; Err: variant {a;b} }) composite_query; } diff --git a/rust/candid_parser/tests/assets/example.toml b/rust/candid_parser/tests/assets/example.toml index 90d9f14a..8f09274f 100644 --- a/rust/candid_parser/tests/assets/example.toml +++ b/rust/candid_parser/tests/assets/example.toml @@ -9,3 +9,4 @@ my_type = { visibility = "", name = "CanisterId" } nat.use_type = "u128" BrokerFindRet = { name = "BrokerReturn", visibility = "pub" } g1 = { name = "G11", arg0.name = "id", arg1.name = "list", arg2.name = "is_okay", ret0.use_type = "i128" } +x.ret2.variant.Err.variant.name = "Error" diff --git a/rust/candid_parser/tests/assets/ok/example.d.ts b/rust/candid_parser/tests/assets/ok/example.d.ts index 56722625..d7b7c8e3 100644 --- a/rust/candid_parser/tests/assets/ok/example.d.ts +++ b/rust/candid_parser/tests/assets/ok/example.d.ts @@ -9,7 +9,7 @@ export type a = { 'a' : null } | { 'b' : b }; export type b = [bigint, bigint]; export interface broker { 'find' : ActorMethod<[string], Principal> } -export type f = ActorMethod<[List, [Principal, string]], [] | [List]>; +export type f = ActorMethod<[List, [Principal, string]], [[] | [List], res]>; export type list = [] | [node]; export type my_type = Principal; export interface nested { @@ -25,6 +25,8 @@ export interface nested { _42_ : bigint, } export interface node { 'head' : bigint, 'tail' : list } +export type res = { 'Ok' : bigint } | + { 'Err' : never }; export interface s { 'f' : t, 'g' : ActorMethod<[list], [B, tree, stream]> } export type stream = [] | [{ 'head' : bigint, 'next' : [Principal, string] }]; export type t = ActorMethod<[Principal], undefined>; @@ -48,7 +50,15 @@ export interface _SERVICE { { _42_ : {}, 'id' : bigint } >, 'i' : f, - 'x' : ActorMethod<[a, b], [[] | [a], [] | [b]]>, + 'x' : ActorMethod< + [a, b], + [ + [] | [a], + [] | [b], + { 'Ok' : null } | + { 'Err' : { 'a' : null } | { 'b' : null } }, + ] + >, } export declare const idlFactory: IDL.InterfaceFactory; export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; diff --git a/rust/candid_parser/tests/assets/ok/example.did b/rust/candid_parser/tests/assets/ok/example.did index feb17030..d2063d17 100644 --- a/rust/candid_parser/tests/assets/ok/example.did +++ b/rust/candid_parser/tests/assets/ok/example.did @@ -6,7 +6,7 @@ type b = record { int; nat }; type broker = service { find : (text) -> (service { current : () -> (nat32); up : () -> () }); }; -type f = func (List, func (int32) -> (int64)) -> (opt List); +type f = func (List, func (int32) -> (int64)) -> (opt List, res); type list = opt node; type my_type = principal; type nested = record { @@ -19,6 +19,7 @@ type nested = record { 42 : nat; }; type node = record { head : nat; tail : list }; +type res = variant { Ok : nat; Err : empty }; type s = service { f : t; g : (list) -> (B, tree, stream) }; type stream = opt record { head : nat; next : func () -> (stream) query }; type t = func (s) -> (); @@ -36,5 +37,9 @@ service : { record { 42 : record {}; id : nat }, ); i : f; - x : (a, b) -> (opt a, opt b) composite_query; + x : (a, b) -> ( + opt a, + opt b, + variant { Ok; Err : variant { a; b } }, + ) composite_query; } diff --git a/rust/candid_parser/tests/assets/ok/example.js b/rust/candid_parser/tests/assets/ok/example.js index 8cecb1b9..7004ca7e 100644 --- a/rust/candid_parser/tests/assets/ok/example.js +++ b/rust/candid_parser/tests/assets/ok/example.js @@ -57,9 +57,10 @@ export const idlFactory = ({ IDL }) => { [], ), }); + const res = IDL.Variant({ 'Ok' : IDL.Nat, 'Err' : IDL.Empty }); const f = IDL.Func( [List, IDL.Func([IDL.Int32], [IDL.Int64], [])], - [IDL.Opt(List)], + [IDL.Opt(List), res], [], ); const a = IDL.Variant({ 'a' : IDL.Null, 'b' : b }); @@ -87,7 +88,18 @@ export const idlFactory = ({ IDL }) => { [], ), 'i' : f, - 'x' : IDL.Func([a, b], [IDL.Opt(a), IDL.Opt(b)], ['composite_query']), + 'x' : IDL.Func( + [a, b], + [ + IDL.Opt(a), + IDL.Opt(b), + IDL.Variant({ + 'Ok' : IDL.Null, + 'Err' : IDL.Variant({ 'a' : IDL.Null, 'b' : IDL.Null }), + }), + ], + ['composite_query'], + ), }); }; export const init = ({ IDL }) => { return []; }; diff --git a/rust/candid_parser/tests/assets/ok/example.mo b/rust/candid_parser/tests/assets/ok/example.mo index 40c95fac..9d87e459 100644 --- a/rust/candid_parser/tests/assets/ok/example.mo +++ b/rust/candid_parser/tests/assets/ok/example.mo @@ -13,7 +13,10 @@ module { up : shared () -> async (); }; }; - public type f = shared (List, shared Int32 -> async Int64) -> async ?List; + public type f = shared (List, shared Int32 -> async Int64) -> async ( + ?List, + res, + ); public type list = ?node; public type my_type = Principal; public type nested = { @@ -26,6 +29,7 @@ module { _42_ : Nat; }; public type node = { head : Nat; tail : list }; + public type res = { #Ok : Nat; #Err : None }; public type s = actor { f : t; g : shared list -> async (B, tree, stream) }; public type stream = ?{ head : Nat; next : shared query () -> async stream }; public type t = shared s -> async (); @@ -44,6 +48,10 @@ module { id : Nat; }; i : f; - x : shared composite query (a, b) -> async (?a, ?b); + x : shared composite query (a, b) -> async ( + ?a, + ?b, + { #Ok; #Err : { #a; #b } }, + ); } } diff --git a/rust/candid_parser/tests/assets/ok/example.rs b/rust/candid_parser/tests/assets/ok/example.rs index e5c735b8..84c5ae02 100644 --- a/rust/candid_parser/tests/assets/ok/example.rs +++ b/rust/candid_parser/tests/assets/ok/example.rs @@ -83,9 +83,15 @@ pub(crate) struct HRet42 {} #[derive(CandidType, Deserialize, Debug)] pub(crate) struct HRet { pub(crate) _42_: HRet42, pub(crate) id: u128 } candid::define_function!(pub(crate) FArg1 : (i32) -> (i64)); -candid::define_function!(pub(crate) F : (MyList, FArg1) -> (Option)); +pub(crate) type Res = std::result::Result; +candid::define_function!(pub(crate) F : (MyList, FArg1) -> ( + Option, + Res, + )); #[derive(CandidType, Deserialize, Debug)] pub(crate) enum A { #[serde(rename="a")] A, #[serde(rename="b")] B(B) } +#[derive(CandidType, Deserialize, Debug)] +pub(crate) enum Error { #[serde(rename="a")] A, #[serde(rename="b")] B } pub struct Service(pub Principal); impl Service { @@ -107,13 +113,33 @@ impl Service { pub async fn h(&self, arg0: Vec>, arg1: HArg1, arg2: Option) -> Result<(HRet,)> { ic_cdk::call(self.0, "h", (arg0,arg1,arg2,)).await } - pub async fn i(&self, arg0: MyList, arg1: FArg1) -> Result<(Option,)> { + pub async fn i(&self, arg0: MyList, arg1: FArg1) -> Result<(Option,Res,)> { ic_cdk::call(self.0, "i", (arg0,arg1,)).await } - pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,)> { + pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,std::result::Result<(), Error>,)> { ic_cdk::call(self.0, "x", (arg0,arg1,)).await } } pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa pub const service : Service = Service(CANISTER_ID); +#[test] +fn test_Arc_MyList_() { + // Generated from ListInner.record.tail.use_type = "Arc" + let candid_src = r#"type List = opt ListInner; +type ListInner = record { head : int; tail : List }; +(List)"#; + candid_parser::utils::check_rust_type::>(candid_src).unwrap(); +} +#[test] +fn test_i128() { + // Generated from g1.ret0.use_type = "i128" + let candid_src = r#"(int)"#; + candid_parser::utils::check_rust_type::(candid_src).unwrap(); +} +#[test] +fn test_u128() { + // Generated from nat.use_type = "u128" + let candid_src = r#"(nat)"#; + candid_parser::utils::check_rust_type::(candid_src).unwrap(); +} diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index ee59bbff..d6db3b70 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -36,6 +36,9 @@ enum Command { #[clap(short, long)] /// Specifies binding generation config in TOML syntax config: Option, + #[clap(short, long, num_args = 1.., value_delimiter = ',')] + /// Specifies a subset of methods to generate bindings. Allowed format: "-m foo,bar", "-m foo bar", "-m foo -m bar" + methods: Vec, }, /// Generate test suites for different languages Test { @@ -207,9 +210,13 @@ fn main() -> Result<()> { input, target, config, + methods, } => { let configs = load_config(&config)?; - let (env, actor) = pretty_check_file(&input)?; + let (env, mut actor) = pretty_check_file(&input)?; + if !methods.is_empty() { + actor = candid_parser::bindings::analysis::project_methods(&env, &actor, &methods); + } let content = match target.as_str() { "js" => candid_parser::bindings::javascript::compile(&env, &actor), "ts" => candid_parser::bindings::typescript::compile(&env, &actor), From 1caba6193c85449e5a49a5bf613cf96b669ffa82 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 21 Jun 2024 10:31:48 -0700 Subject: [PATCH 09/36] fix result struct binding (#559) * fix result struct binding * nested result test --- rust/candid_parser/src/bindings/rust.rs | 15 ++++++++++++--- rust/candid_parser/tests/assets/example.did | 7 ++++--- rust/candid_parser/tests/assets/ok/example.d.ts | 13 +++++++++---- rust/candid_parser/tests/assets/ok/example.did | 10 +++++++--- rust/candid_parser/tests/assets/ok/example.js | 16 +++++++++++++--- rust/candid_parser/tests/assets/ok/example.mo | 14 +++++++++++--- rust/candid_parser/tests/assets/ok/example.rs | 17 ++++++++++++++--- 7 files changed, 70 insertions(+), 22 deletions(-) diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index facad992..481b05f9 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -720,6 +720,7 @@ pub enum TypePath { Vec, RecordField(String), VariantField(String), + ResultField(String), Func(String), Init, } @@ -728,7 +729,9 @@ fn path_to_var(path: &[TypePath]) -> String { .iter() .map(|node| match node { TypePath::Id(id) => id.as_str(), - TypePath::RecordField(f) | TypePath::VariantField(f) => f.as_str(), + TypePath::RecordField(f) | TypePath::VariantField(f) | TypePath::ResultField(f) => { + f.as_str() + } TypePath::Opt => "inner", TypePath::Vec => "item", TypePath::Func(id) => id.as_str(), @@ -801,13 +804,19 @@ impl<'a> NominalState<'a> { } } TypeInner::Variant(fs) => { - if matches!(path.last(), None | Some(TypePath::Id(_))) || as_result(fs).is_some() { + let is_result = as_result(fs).is_some(); + if matches!(path.last(), None | Some(TypePath::Id(_))) || is_result { let fs: Vec<_> = fs .iter() .map(|Field { id, ty }| { let lab = id.to_string(); let old = self.state.push_state(&StateElem::Label(&lab)); - path.push(TypePath::VariantField(id.to_string())); + if is_result { + // so that inner record gets a new name + path.push(TypePath::ResultField(id.to_string())); + } else { + path.push(TypePath::VariantField(id.to_string())); + } let ty = self.nominalize(env, path, ty); path.pop(); self.state.pop_state(old, StateElem::Label(&lab)); diff --git a/rust/candid_parser/tests/assets/example.did b/rust/candid_parser/tests/assets/example.did index a0a865d1..a5a47fee 100644 --- a/rust/candid_parser/tests/assets/example.did +++ b/rust/candid_parser/tests/assets/example.did @@ -9,13 +9,14 @@ type broker = service { (service {up:() -> (); current:() -> (nat32)}); }; type nested = record { nat; nat; record {nat;int;}; record { nat; 0x2a:nat; nat8; }; 42:nat; 40:nat; variant{ A; 0x2a; B; C }; }; -type res = variant { Ok: nat; Err: empty }; +type res = variant { Ok: record{int;nat}; Err: record{ error: text } }; +type nested_res = variant { Ok: variant { Ok; Err }; Err: variant { Ok: record { content: text }; Err: record {int} } }; service server : { f1 : (list, test: blob, opt bool) -> () oneway; - g1 : (my_type, List, opt List, nested) -> (int, broker) query; + g1 : (my_type, List, opt List, nested) -> (int, broker, nested_res) query; h : (vec opt text, variant { A: nat; B: opt text }, opt List) -> (record { id: nat; 0x2a: record {} }); i : f; - x : (a,b) -> (opt a, opt b, variant { Ok; Err: variant {a;b} }) composite_query; + x : (a,b) -> (opt a, opt b, variant { Ok: record { result: text }; Err: variant {a;b} }) composite_query; } diff --git a/rust/candid_parser/tests/assets/ok/example.d.ts b/rust/candid_parser/tests/assets/ok/example.d.ts index d7b7c8e3..a3975f37 100644 --- a/rust/candid_parser/tests/assets/ok/example.d.ts +++ b/rust/candid_parser/tests/assets/ok/example.d.ts @@ -24,9 +24,11 @@ export interface nested { { 'C' : null }, _42_ : bigint, } +export type nested_res = { 'Ok' : { 'Ok' : null } | { 'Err' : null } } | + { 'Err' : { 'Ok' : { 'content' : string } } | { 'Err' : [bigint] } }; export interface node { 'head' : bigint, 'tail' : list } -export type res = { 'Ok' : bigint } | - { 'Err' : never }; +export type res = { 'Ok' : [bigint, bigint] } | + { 'Err' : { 'error' : string } }; export interface s { 'f' : t, 'g' : ActorMethod<[list], [B, tree, stream]> } export type stream = [] | [{ 'head' : bigint, 'next' : [Principal, string] }]; export type t = ActorMethod<[Principal], undefined>; @@ -39,7 +41,10 @@ export interface _SERVICE { 'f' : t, 'f1' : ActorMethod<[list, Uint8Array | number[], [] | [boolean]], undefined>, 'g' : ActorMethod<[list], [B, tree, stream]>, - 'g1' : ActorMethod<[my_type, List, [] | [List], nested], [bigint, Principal]>, + 'g1' : ActorMethod< + [my_type, List, [] | [List], nested], + [bigint, Principal, nested_res] + >, 'h' : ActorMethod< [ Array<[] | [string]>, @@ -55,7 +60,7 @@ export interface _SERVICE { [ [] | [a], [] | [b], - { 'Ok' : null } | + { 'Ok' : { 'result' : string } } | { 'Err' : { 'a' : null } | { 'b' : null } }, ] >, diff --git a/rust/candid_parser/tests/assets/ok/example.did b/rust/candid_parser/tests/assets/ok/example.did index d2063d17..2ec745f5 100644 --- a/rust/candid_parser/tests/assets/ok/example.did +++ b/rust/candid_parser/tests/assets/ok/example.did @@ -18,8 +18,12 @@ type nested = record { 41 : variant { 42; A; B; C }; 42 : nat; }; +type nested_res = variant { + Ok : variant { Ok; Err }; + Err : variant { Ok : record { content : text }; Err : record { int } }; +}; type node = record { head : nat; tail : list }; -type res = variant { Ok : nat; Err : empty }; +type res = variant { Ok : record { int; nat }; Err : record { error : text } }; type s = service { f : t; g : (list) -> (B, tree, stream) }; type stream = opt record { head : nat; next : func () -> (stream) query }; type t = func (s) -> (); @@ -32,7 +36,7 @@ service : { f : t; f1 : (list, blob, opt bool) -> () oneway; g : (list) -> (B, tree, stream); - g1 : (my_type, List, opt List, nested) -> (int, broker) query; + g1 : (my_type, List, opt List, nested) -> (int, broker, nested_res) query; h : (vec opt text, variant { A : nat; B : opt text }, opt List) -> ( record { 42 : record {}; id : nat }, ); @@ -40,6 +44,6 @@ service : { x : (a, b) -> ( opt a, opt b, - variant { Ok; Err : variant { a; b } }, + variant { Ok : record { result : text }; Err : variant { a; b } }, ) composite_query; } diff --git a/rust/candid_parser/tests/assets/ok/example.js b/rust/candid_parser/tests/assets/ok/example.js index 7004ca7e..4602f2a1 100644 --- a/rust/candid_parser/tests/assets/ok/example.js +++ b/rust/candid_parser/tests/assets/ok/example.js @@ -57,7 +57,17 @@ export const idlFactory = ({ IDL }) => { [], ), }); - const res = IDL.Variant({ 'Ok' : IDL.Nat, 'Err' : IDL.Empty }); + const nested_res = IDL.Variant({ + 'Ok' : IDL.Variant({ 'Ok' : IDL.Null, 'Err' : IDL.Null }), + 'Err' : IDL.Variant({ + 'Ok' : IDL.Record({ 'content' : IDL.Text }), + 'Err' : IDL.Tuple(IDL.Int), + }), + }); + const res = IDL.Variant({ + 'Ok' : IDL.Tuple(IDL.Int, IDL.Nat), + 'Err' : IDL.Record({ 'error' : IDL.Text }), + }); const f = IDL.Func( [List, IDL.Func([IDL.Int32], [IDL.Int64], [])], [IDL.Opt(List), res], @@ -75,7 +85,7 @@ export const idlFactory = ({ IDL }) => { 'g' : IDL.Func([list], [B, tree, stream], []), 'g1' : IDL.Func( [my_type, List, IDL.Opt(List), nested], - [IDL.Int, broker], + [IDL.Int, broker, nested_res], ['query'], ), 'h' : IDL.Func( @@ -94,7 +104,7 @@ export const idlFactory = ({ IDL }) => { IDL.Opt(a), IDL.Opt(b), IDL.Variant({ - 'Ok' : IDL.Null, + 'Ok' : IDL.Record({ 'result' : IDL.Text }), 'Err' : IDL.Variant({ 'a' : IDL.Null, 'b' : IDL.Null }), }), ], diff --git a/rust/candid_parser/tests/assets/ok/example.mo b/rust/candid_parser/tests/assets/ok/example.mo index 9d87e459..4847215a 100644 --- a/rust/candid_parser/tests/assets/ok/example.mo +++ b/rust/candid_parser/tests/assets/ok/example.mo @@ -28,8 +28,12 @@ module { _41_ : { #_42_ ; #A; #B; #C }; _42_ : Nat; }; + public type nested_res = { + #Ok : { #Ok; #Err }; + #Err : { #Ok : { content : Text }; #Err : { _0_ : Int } }; + }; public type node = { head : Nat; tail : list }; - public type res = { #Ok : Nat; #Err : None }; + public type res = { #Ok : (Int, Nat); #Err : { error : Text } }; public type s = actor { f : t; g : shared list -> async (B, tree, stream) }; public type stream = ?{ head : Nat; next : shared query () -> async stream }; public type t = shared s -> async (); @@ -42,7 +46,11 @@ module { f : t; f1 : shared (list, Blob, ?Bool) -> (); g : shared list -> async (B, tree, stream); - g1 : shared query (my_type, List, ?List, nested) -> async (Int, broker); + g1 : shared query (my_type, List, ?List, nested) -> async ( + Int, + broker, + nested_res, + ); h : shared ([?Text], { #A : Nat; #B : ?Text }, ?List) -> async { _42_ : {}; id : Nat; @@ -51,7 +59,7 @@ module { x : shared composite query (a, b) -> async ( ?a, ?b, - { #Ok; #Err : { #a; #b } }, + { #Ok : { result : Text }; #Err : { #a; #b } }, ); } } diff --git a/rust/candid_parser/tests/assets/ok/example.rs b/rust/candid_parser/tests/assets/ok/example.rs index 84c5ae02..73d307fd 100644 --- a/rust/candid_parser/tests/assets/ok/example.rs +++ b/rust/candid_parser/tests/assets/ok/example.rs @@ -77,13 +77,22 @@ candid::define_service!(pub(crate) Broker : { "find" : candid::func!((String) -> (BrokerReturn)); }); #[derive(CandidType, Deserialize, Debug)] +pub(crate) struct NestedResErrOk { pub(crate) content: String } +pub(crate) type NestedRes = std::result::Result< + std::result::Result<(), ()>, std::result::Result< + NestedResErrOk, (candid::Int,) + > +>; +#[derive(CandidType, Deserialize, Debug)] pub(crate) enum HArg1 { A(u128), B(Option) } #[derive(CandidType, Deserialize, Debug)] pub(crate) struct HRet42 {} #[derive(CandidType, Deserialize, Debug)] pub(crate) struct HRet { pub(crate) _42_: HRet42, pub(crate) id: u128 } candid::define_function!(pub(crate) FArg1 : (i32) -> (i64)); -pub(crate) type Res = std::result::Result; +#[derive(CandidType, Deserialize, Debug)] +pub(crate) struct ResErr { pub(crate) error: String } +pub(crate) type Res = std::result::Result<(candid::Int,u128,), ResErr>; candid::define_function!(pub(crate) F : (MyList, FArg1) -> ( Option, Res, @@ -91,6 +100,8 @@ candid::define_function!(pub(crate) F : (MyList, FArg1) -> ( #[derive(CandidType, Deserialize, Debug)] pub(crate) enum A { #[serde(rename="a")] A, #[serde(rename="b")] B(B) } #[derive(CandidType, Deserialize, Debug)] +pub(crate) struct XRet2Ok { pub(crate) result: String } +#[derive(CandidType, Deserialize, Debug)] pub(crate) enum Error { #[serde(rename="a")] A, #[serde(rename="b")] B } pub struct Service(pub Principal); @@ -107,7 +118,7 @@ impl Service { pub async fn g(&self, arg0: List) -> Result<(B,Tree,Stream,)> { ic_cdk::call(self.0, "g", (arg0,)).await } - pub async fn G11(&self, id: CanisterId, list: MyList, is_okay: Option, arg3: Nested) -> Result<(i128,Broker,)> { + pub async fn G11(&self, id: CanisterId, list: MyList, is_okay: Option, arg3: Nested) -> Result<(i128,Broker,NestedRes,)> { ic_cdk::call(self.0, "g1", (id,list,is_okay,arg3,)).await } pub async fn h(&self, arg0: Vec>, arg1: HArg1, arg2: Option) -> Result<(HRet,)> { @@ -116,7 +127,7 @@ impl Service { pub async fn i(&self, arg0: MyList, arg1: FArg1) -> Result<(Option,Res,)> { ic_cdk::call(self.0, "i", (arg0,arg1,)).await } - pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,std::result::Result<(), Error>,)> { + pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,std::result::Result,)> { ic_cdk::call(self.0, "x", (arg0,arg1,)).await } } From 258b6b6466a00d59d51dc9463a4f7f0d887f32ca Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:56:47 -0700 Subject: [PATCH 10/36] add new links in README (#561) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 435c9353..955c0f0b 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ A list of community maintained Candid libraries: * [didc](tools/didc): Candid CLI. Download [prebuilt binary](https://github.com/dfinity/candid/releases). * [ui](tools/ui): Candid UI canister. See deployed [canister](https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.ic0.app/) on the IC * [ic-repl](https://github.com/chenyan2002/ic-repl): A REPL environment to communicate with canisters using Candid +* [Explain Candid](https://fxa77-fiaaa-aaaae-aaana-cai.raw.icp0.io/explain): An online tool that decodes and explains a given Candid message. (Thanks to Ben Lynn) +* [Candid playground](https://sehgq-cqaaa-aaaap-ahc4q-cai.icp0.io/playground): A playground that generates UI dynamically as you type in the Candid definitions. (Thanks to B3Forge) ## Tests From af33ed8763151aeadebcf63c8a6c9d9736c144cc Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 25 Jun 2024 14:03:37 -0700 Subject: [PATCH 11/36] more rust bindgen (#560) * make configs public * fix newtype visibility * add variant.std::record::Record.use_type is rename Result type * report unused * no test annotation * fix * bump version * embed metadata * remove unused types in metadata * tests --- Cargo.lock | 3 +- Cargo.toml | 1 + rust/candid_parser/Cargo.toml | 6 +- rust/candid_parser/src/bindings/rust.rs | 80 +++++++++++++------ rust/candid_parser/src/bindings/rust_stub.hbs | 4 + rust/candid_parser/src/configs.rs | 2 +- rust/candid_parser/src/utils.rs | 19 ++++- rust/candid_parser/tests/assets/class.did | 3 +- rust/candid_parser/tests/assets/example.toml | 4 +- rust/candid_parser/tests/assets/ok/actor.rs | 2 +- rust/candid_parser/tests/assets/ok/class.d.ts | 1 + rust/candid_parser/tests/assets/ok/class.did | 3 +- rust/candid_parser/tests/assets/ok/class.js | 4 +- rust/candid_parser/tests/assets/ok/class.mo | 3 +- rust/candid_parser/tests/assets/ok/class.rs | 29 ++++--- rust/candid_parser/tests/assets/ok/cyclic.rs | 2 +- rust/candid_parser/tests/assets/ok/example.rs | 18 ++--- rust/candid_parser/tests/assets/ok/keyword.rs | 6 +- .../tests/assets/ok/recursion.rs | 6 +- rust/candid_parser/tests/parse_type.rs | 6 +- tools/didc/Cargo.toml | 1 + tools/didc/src/main.rs | 18 ++++- 22 files changed, 150 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 832aa886..30cb49fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "candid_parser" -version = "0.2.0-beta.2" +version = "0.2.0-beta.3" dependencies = [ "anyhow", "arbitrary", @@ -414,6 +414,7 @@ dependencies = [ "anyhow", "candid_parser", "clap", + "console", "hex", "pretty-hex", "rand", diff --git a/Cargo.toml b/Cargo.toml index 574ad071..341dbdde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ thiserror = "1.0" anyhow = "1.0" rand = "0.8" arbitrary = "1.3" +console = "0.15" diff --git a/rust/candid_parser/Cargo.toml b/rust/candid_parser/Cargo.toml index ecf6052c..4961df50 100644 --- a/rust/candid_parser/Cargo.toml +++ b/rust/candid_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid_parser" -version = "0.2.0-beta.2" +version = "0.2.0-beta.3" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] @@ -33,7 +33,6 @@ logos = "0.14" convert_case = "0.6" handlebars = "5.1" toml = { version = "0.8", default-features = false, features = ["parse"] } -console = "0.15" arbitrary = { workspace = true, optional = true } fake = { version = "2.4", optional = true } @@ -41,6 +40,7 @@ rand = { version = "0.8", optional = true } num-traits = { workspace = true, optional = true } dialoguer = { version = "0.11", default-features = false, features = ["editor", "completion"], optional = true } ctrlc = { version = "3.4", optional = true } +console = { workspace = true, optional = true } [dev-dependencies] goldenfile = "1.1.0" @@ -49,7 +49,7 @@ rand.workspace = true [features] random = ["dep:arbitrary", "dep:fake", "dep:rand", "dep:num-traits"] -assist = ["dep:dialoguer", "dep:ctrlc"] +assist = ["dep:dialoguer", "dep:console", "dep:ctrlc"] all = ["random", "assist"] # docs.rs-specific configuration diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index 481b05f9..8c8462eb 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -5,7 +5,6 @@ use crate::{ }; use candid::pretty::utils::*; use candid::types::{Field, Function, Label, SharedLabel, Type, TypeEnv, TypeInner}; -use console::style; use convert_case::{Case, Casing}; use pretty::RcDoc; use serde::Serialize; @@ -102,6 +101,13 @@ fn as_result(fs: &[Field]) -> Option<(&Type, &Type)> { _ => None, } } +fn parse_use_type(input: &str) -> (String, bool) { + if let Some((t, "")) = input.rsplit_once("(no test)") { + (t.trim_end().to_string(), false) + } else { + (input.to_string(), true) + } +} static KEYWORDS: [&str; 51] = [ "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", @@ -176,8 +182,11 @@ fn test_{test_name}() {{ let elem = StateElem::Type(ty); let old = self.state.push_state(&elem); let res = if let Some(t) = &self.state.config.use_type { - let res = RcDoc::text(t.clone()); - self.generate_test(ty, &t.clone()); + let (t, need_test) = parse_use_type(t); + if need_test { + self.generate_test(ty, &t); + } + let res = RcDoc::text(t); self.state.update_stats("use_type"); res } else { @@ -222,11 +231,28 @@ fn test_{test_name}() {{ Variant(ref fs) => { // only possible for result variant let (ok, err) = as_result(fs).unwrap(); - let body = self - .pp_ty(ok, is_ref) - .append(", ") - .append(self.pp_ty(err, is_ref)); - str("std::result::Result").append(enclose("<", body, ">")) + // This is a hacky way to redirect Result type + let old = self + .state + .push_state(&StateElem::TypeStr("std::result::Result")); + let result = if let Some(t) = &self.state.config.use_type { + let (res, _) = parse_use_type(t); + // not generating test for this use_type. rustc should be able to catch type mismatches. + self.state.update_stats("use_type"); + res + } else { + "std::result::Result".to_string() + }; + self.state + .pop_state(old, StateElem::TypeStr("std::result::Result")); + let old = self.state.push_state(&StateElem::Label("Ok")); + let ok = self.pp_ty(ok, is_ref); + self.state.pop_state(old, StateElem::Label("Ok")); + let old = self.state.push_state(&StateElem::Label("Err")); + let err = self.pp_ty(err, is_ref); + self.state.pop_state(old, StateElem::Label("Err")); + let body = ok.append(", ").append(err); + RcDoc::text(result).append(enclose("<", body, ">")) } Func(_) => unreachable!(), // not possible after rewriting Service(_) => unreachable!(), // not possible after rewriting @@ -305,9 +331,13 @@ fn test_{test_name}() {{ res } fn pp_record_fields<'b>(&mut self, fs: &'b [Field], need_vis: bool, is_ref: bool) -> RcDoc<'b> { - let old = self.state.push_state(&StateElem::TypeStr("record")); + let old = if self.state.path.last() == Some(&"record".to_string()) { + // don't push record again when coming from pp_ty + None + } else { + Some(self.state.push_state(&StateElem::TypeStr("record"))) + }; let res = if is_tuple(fs) { - // TODO check if there is no name/attr in the label subtree self.pp_tuple(fs, need_vis, is_ref) } else { let fields: Vec<_> = fs @@ -317,7 +347,9 @@ fn test_{test_name}() {{ let fields = concat(fields.into_iter(), ","); enclose_space("{", fields, "}") }; - self.state.pop_state(old, StateElem::TypeStr("record")); + if let Some(old) = old { + self.state.pop_state(old, StateElem::TypeStr("record")); + } res } fn pp_variant_field<'b>(&mut self, field: &'b Field) -> RcDoc<'b> { @@ -421,10 +453,11 @@ fn test_{test_name}() {{ if self.recs.contains(id) { derive .append(RcDoc::line()) - .append(vis) + .append(vis.clone()) .append("struct ") .append(name) - .append(enclose("(", self.pp_ty(ty, false), ")")) + // TODO: Unfortunately, the visibility of the inner newtype is also controlled by var.visibility + .append(enclose("(", vis.append(self.pp_ty(ty, false)), ")")) .append(";") } else { vis.append(kwd("type")) @@ -688,12 +721,18 @@ pub fn compile( tree: &Config, env: &TypeEnv, actor: &Option, - external: ExternalConfig, -) -> String { + mut external: ExternalConfig, +) -> (String, Vec) { let source = match external.0.get("target").map(|s| s.as_str()) { Some("canister_call") | None => Cow::Borrowed(include_str!("rust_call.hbs")), Some("agent") => Cow::Borrowed(include_str!("rust_agent.hbs")), - Some("stub") => Cow::Borrowed(include_str!("rust_stub.hbs")), + Some("stub") => { + let metadata = crate::utils::get_metadata(env, actor); + if let Some(metadata) = metadata { + external.0.insert("metadata".to_string(), metadata); + } + Cow::Borrowed(include_str!("rust_stub.hbs")) + } Some("custom") => { let template = external .0 @@ -704,14 +743,7 @@ pub fn compile( _ => unimplemented!(), }; let (output, unused) = emit_bindgen(tree, env, actor); - for e in unused { - eprintln!( - "{} path {} is unused", - style("WARNING:").red().bold(), - style(e).green() - ); - } - output_handlebar(output, external, &source) + (output_handlebar(output, external, &source), unused) } pub enum TypePath { diff --git a/rust/candid_parser/src/bindings/rust_stub.hbs b/rust/candid_parser/src/bindings/rust_stub.hbs index 32658194..a0cf2c4c 100644 --- a/rust/candid_parser/src/bindings/rust_stub.hbs +++ b/rust/candid_parser/src/bindings/rust_stub.hbs @@ -19,3 +19,7 @@ fn {{this.name}}({{#each this.args}}{{#if (not @first)}}, {{/if}}{{this.0}}: {{t {{#if tests}} {{tests}} {{/if}} +{{#if metadata}} +#[link_section = "icp:public candid:service"] +pub static __SERVICE: [u8; {{len metadata}}] = *br#"{{metadata}}"#; +{{/if}} diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index f6a50d94..c2880f2e 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -299,7 +299,7 @@ impl ConfigTree { } } #[derive(Clone)] -pub struct Configs(Table); +pub struct Configs(pub Table); impl Configs { pub fn get_subtable(&self, path: &[String]) -> Option<&Table> { let mut res = &self.0; diff --git a/rust/candid_parser/src/utils.rs b/rust/candid_parser/src/utils.rs index f3027180..f465a756 100644 --- a/rust/candid_parser/src/utils.rs +++ b/rust/candid_parser/src/utils.rs @@ -1,4 +1,5 @@ use crate::{check_prog, pretty_check_file, pretty_parse, Error, Result}; +use candid::types::TypeInner; use candid::{types::Type, TypeEnv}; use std::path::Path; @@ -49,7 +50,6 @@ pub fn service_equal(left: CandidSource, right: CandidSource) -> Result<()> { /// If the original did file contains imports, the output flattens the type definitions. /// For now, the comments from the original did file is omitted. pub fn instantiate_candid(candid: CandidSource) -> Result<(Vec, (TypeEnv, Type))> { - use candid::types::TypeInner; let (env, serv) = candid.load()?; let serv = serv.ok_or_else(|| Error::msg("the Candid interface has no main service type"))?; let serv = env.trace_type(&serv)?; @@ -59,6 +59,23 @@ pub fn instantiate_candid(candid: CandidSource) -> Result<(Vec, (TypeEnv, _ => unreachable!(), }) } +pub fn get_metadata(env: &TypeEnv, serv: &Option) -> Option { + let serv = serv.clone()?; + let serv = env.trace_type(&serv).ok()?; + let serv = match serv.as_ref() { + TypeInner::Class(_, ty) => ty.clone(), + TypeInner::Service(_) => serv, + _ => unreachable!(), + }; + let def_list = crate::bindings::analysis::chase_actor(env, &serv).ok()?; + let mut filtered = TypeEnv::new(); + for d in def_list { + if let Some(t) = env.0.get(d) { + filtered.0.insert(d.to_string(), t.clone()); + } + } + Some(candid::pretty::candid::compile(&filtered, &Some(serv))) +} /// Merge canister metadata candid:args and candid:service into a service constructor. /// If candid:service already contains init args, returns the original did file. diff --git a/rust/candid_parser/tests/assets/class.did b/rust/candid_parser/tests/assets/class.did index 326a0520..662461b1 100644 --- a/rust/candid_parser/tests/assets/class.did +++ b/rust/candid_parser/tests/assets/class.did @@ -1,5 +1,6 @@ +type Profile = record { age: nat8; name: text }; type List = opt record { int; List }; -service : (int, List) -> { +service : (int, List, Profile) -> { get : () -> (List); set : (List) -> (List); } diff --git a/rust/candid_parser/tests/assets/example.toml b/rust/candid_parser/tests/assets/example.toml index 8f09274f..92156e9c 100644 --- a/rust/candid_parser/tests/assets/example.toml +++ b/rust/candid_parser/tests/assets/example.toml @@ -6,7 +6,9 @@ Nested41.variant.A = { name = "AAA", attributes = "#[serde(skip_deserializing)]" ListInner.attributes = "#derive[CandidType, Deserialize, Clone]" ListInner.record = { visibility = "", head.name = "HEAD", attributes = "#[serde(skip_deserializing)]", tail.use_type = "Arc" } my_type = { visibility = "", name = "CanisterId" } -nat.use_type = "u128" +nat.use_type = "u128 (no test)" BrokerFindRet = { name = "BrokerReturn", visibility = "pub" } g1 = { name = "G11", arg0.name = "id", arg1.name = "list", arg2.name = "is_okay", ret0.use_type = "i128" } x.ret2.variant.Err.variant.name = "Error" +nested_res.variant.Ok.variant."std::result::Result".use_type = "my::Result" +nested_res.variant.Err.variant."std::result::Result".use_type = "another::Result" diff --git a/rust/candid_parser/tests/assets/ok/actor.rs b/rust/candid_parser/tests/assets/ok/actor.rs index d9d385ec..7049c0a4 100644 --- a/rust/candid_parser/tests/assets/ok/actor.rs +++ b/rust/candid_parser/tests/assets/ok/actor.rs @@ -8,7 +8,7 @@ candid::define_function!(pub F : (i8) -> (i8)); candid::define_function!(pub H : (F) -> (F)); pub type G = F; #[derive(CandidType, Deserialize)] -pub struct O(Option>); +pub struct O(pub Option>); pub struct Service(pub Principal); impl Service { diff --git a/rust/candid_parser/tests/assets/ok/class.d.ts b/rust/candid_parser/tests/assets/ok/class.d.ts index 5cbc5acb..412ee851 100644 --- a/rust/candid_parser/tests/assets/ok/class.d.ts +++ b/rust/candid_parser/tests/assets/ok/class.d.ts @@ -3,6 +3,7 @@ import type { ActorMethod } from '@dfinity/agent'; import type { IDL } from '@dfinity/candid'; export type List = [] | [[bigint, List]]; +export interface Profile { 'age' : number, 'name' : string } export interface _SERVICE { 'get' : ActorMethod<[], List>, 'set' : ActorMethod<[List], List>, diff --git a/rust/candid_parser/tests/assets/ok/class.did b/rust/candid_parser/tests/assets/ok/class.did index d2ffe0f6..a4749756 100644 --- a/rust/candid_parser/tests/assets/ok/class.did +++ b/rust/candid_parser/tests/assets/ok/class.did @@ -1,2 +1,3 @@ type List = opt record { int; List }; -service : (int, List) -> { get : () -> (List); set : (List) -> (List) } +type Profile = record { age : nat8; name : text }; +service : (int, List, Profile) -> { get : () -> (List); set : (List) -> (List) } diff --git a/rust/candid_parser/tests/assets/ok/class.js b/rust/candid_parser/tests/assets/ok/class.js index 93e6cfdd..5f052ee0 100644 --- a/rust/candid_parser/tests/assets/ok/class.js +++ b/rust/candid_parser/tests/assets/ok/class.js @@ -1,6 +1,7 @@ export const idlFactory = ({ IDL }) => { const List = IDL.Rec(); List.fill(IDL.Opt(IDL.Tuple(IDL.Int, List))); + const Profile = IDL.Record({ 'age' : IDL.Nat8, 'name' : IDL.Text }); return IDL.Service({ 'get' : IDL.Func([], [List], []), 'set' : IDL.Func([List], [List], []), @@ -9,5 +10,6 @@ export const idlFactory = ({ IDL }) => { export const init = ({ IDL }) => { const List = IDL.Rec(); List.fill(IDL.Opt(IDL.Tuple(IDL.Int, List))); - return [IDL.Int, List]; + const Profile = IDL.Record({ 'age' : IDL.Nat8, 'name' : IDL.Text }); + return [IDL.Int, List, Profile]; }; diff --git a/rust/candid_parser/tests/assets/ok/class.mo b/rust/candid_parser/tests/assets/ok/class.mo index 1a62c956..ad5666f4 100644 --- a/rust/candid_parser/tests/assets/ok/class.mo +++ b/rust/candid_parser/tests/assets/ok/class.mo @@ -3,7 +3,8 @@ module { public type List = ?(Int, List); - public type Self = (Int, List) -> async actor { + public type Profile = { age : Nat8; name : Text }; + public type Self = (Int, List, Profile) -> async actor { get : shared () -> async List; set : shared List -> async List; } diff --git a/rust/candid_parser/tests/assets/ok/class.rs b/rust/candid_parser/tests/assets/ok/class.rs index cfed8194..ecb1b190 100644 --- a/rust/candid_parser/tests/assets/ok/class.rs +++ b/rust/candid_parser/tests/assets/ok/class.rs @@ -2,20 +2,25 @@ // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] use candid::{self, CandidType, Deserialize, Principal}; -use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] -pub struct List(Option<(candid::Int,Box,)>); +pub struct List(pub Option<(candid::Int,Box,)>); +#[derive(CandidType, Deserialize)] +pub struct Profile { pub age: u8, pub name: String } -pub struct Service(pub Principal); -impl Service { - pub async fn get(&self) -> Result<(List,)> { - ic_cdk::call(self.0, "get", ()).await - } - pub async fn set(&self, arg0: List) -> Result<(List,)> { - ic_cdk::call(self.0, "set", (arg0,)).await - } +#[ic_cdk::init] +fn init(arg0: candid::Int, arg1: List, arg2: Profile) { + unimplemented!() +} +#[ic_cdk::update] +fn get() -> List { + unimplemented!() +} +#[ic_cdk::update] +fn set(arg0: List) -> List { + unimplemented!() } -pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa -pub const service : Service = Service(CANISTER_ID); +#[link_section = "icp:public candid:service"] +pub static __SERVICE: [u8; 94] = *br#"type List = opt record { int; List }; +service : { get : () -> (List); set : (List) -> (List) }"#; diff --git a/rust/candid_parser/tests/assets/ok/cyclic.rs b/rust/candid_parser/tests/assets/ok/cyclic.rs index 314286e9..a7186883 100644 --- a/rust/candid_parser/tests/assets/ok/cyclic.rs +++ b/rust/candid_parser/tests/assets/ok/cyclic.rs @@ -7,7 +7,7 @@ use ic_cdk::api::call::CallResult as Result; pub type C = Box; pub type B = Option; #[derive(CandidType, Deserialize)] -pub struct A(Option); +pub struct A(pub Option); pub type Z = Box; pub type Y = Z; pub type X = Y; diff --git a/rust/candid_parser/tests/assets/ok/example.rs b/rust/candid_parser/tests/assets/ok/example.rs index 73d307fd..dac11e1d 100644 --- a/rust/candid_parser/tests/assets/ok/example.rs +++ b/rust/candid_parser/tests/assets/ok/example.rs @@ -9,10 +9,10 @@ pub(crate) struct B (pub(crate) candid::Int,pub(crate) u128,); #[derive(CandidType, Deserialize, Debug)] pub(crate) struct Node { pub(crate) head: u128, pub(crate) tail: Box } #[derive(CandidType, Deserialize, Debug)] -pub(crate) struct List(Option); +pub(crate) struct List(pub(crate) Option); pub(crate) type A = Box; #[derive(CandidType, Deserialize, Debug)] -pub(crate) struct B(Option); +pub(crate) struct B(pub(crate) Option); #[derive(CandidType, Deserialize, Debug)] pub(crate) enum Tree { #[serde(rename="branch")] @@ -27,7 +27,7 @@ pub(crate) struct StreamInner { pub(crate) next: StreamInnerNext, } #[derive(CandidType, Deserialize, Debug)] -pub(crate) struct Stream(Option); +pub(crate) struct Stream(pub(crate) Option); candid::define_service!(pub(crate) S : { "f" : T::ty(); "g" : candid::func!((List) -> (B, Tree, Stream)); @@ -43,7 +43,7 @@ pub(crate) struct ListInner { tail: Arc, } #[derive(CandidType, Deserialize, Debug)] -pub(crate) struct MyList(Option); +pub(crate) struct MyList(pub(crate) Option); #[derive(CandidType, Deserialize, Debug)] pub(crate) struct Nested3 { pub(crate) _0_: u128, @@ -79,9 +79,7 @@ candid::define_service!(pub(crate) Broker : { #[derive(CandidType, Deserialize, Debug)] pub(crate) struct NestedResErrOk { pub(crate) content: String } pub(crate) type NestedRes = std::result::Result< - std::result::Result<(), ()>, std::result::Result< - NestedResErrOk, (candid::Int,) - > + my::Result<(), ()>, another::Result >; #[derive(CandidType, Deserialize, Debug)] pub(crate) enum HArg1 { A(u128), B(Option) } @@ -147,10 +145,4 @@ fn test_i128() { let candid_src = r#"(int)"#; candid_parser::utils::check_rust_type::(candid_src).unwrap(); } -#[test] -fn test_u128() { - // Generated from nat.use_type = "u128" - let candid_src = r#"(nat)"#; - candid_parser::utils::check_rust_type::(candid_src).unwrap(); -} diff --git a/rust/candid_parser/tests/assets/ok/keyword.rs b/rust/candid_parser/tests/assets/ok/keyword.rs index f50de12e..ae002bb1 100644 --- a/rust/candid_parser/tests/assets/ok/keyword.rs +++ b/rust/candid_parser/tests/assets/ok/keyword.rs @@ -5,7 +5,7 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] -pub struct O(Option>); +pub struct O(pub Option>); #[derive(CandidType, Deserialize)] pub struct FieldArg { pub test: u16, pub _1291438163_: u8 } #[derive(CandidType, Deserialize)] @@ -19,7 +19,7 @@ pub struct FieldnatArg { #[derive(CandidType, Deserialize)] pub struct Node { pub head: candid::Nat, pub tail: Box } #[derive(CandidType, Deserialize)] -pub struct List(Option); +pub struct List(pub Option); #[derive(CandidType, Deserialize)] pub enum If { #[serde(rename="branch")] @@ -31,7 +31,7 @@ candid::define_function!(pub StreamInnerNext : () -> (Stream) query); #[derive(CandidType, Deserialize)] pub struct StreamInner { pub head: candid::Nat, pub next: StreamInnerNext } #[derive(CandidType, Deserialize)] -pub struct Stream(Option); +pub struct Stream(pub Option); candid::define_service!(pub Return : { "f" : T::ty(); "g" : candid::func!((List) -> (If, Stream)); diff --git a/rust/candid_parser/tests/assets/ok/recursion.rs b/rust/candid_parser/tests/assets/ok/recursion.rs index 91aca069..480962c7 100644 --- a/rust/candid_parser/tests/assets/ok/recursion.rs +++ b/rust/candid_parser/tests/assets/ok/recursion.rs @@ -8,10 +8,10 @@ candid::define_function!(pub T : (S) -> ()); #[derive(CandidType, Deserialize)] pub struct Node { pub head: candid::Nat, pub tail: Box } #[derive(CandidType, Deserialize)] -pub struct List(Option); +pub struct List(pub Option); pub type A = Box; #[derive(CandidType, Deserialize)] -pub struct B(Option); +pub struct B(pub Option); #[derive(CandidType, Deserialize)] pub enum Tree { #[serde(rename="branch")] @@ -23,7 +23,7 @@ candid::define_function!(pub StreamInnerNext : () -> (Stream) query); #[derive(CandidType, Deserialize)] pub struct StreamInner { pub head: candid::Nat, pub next: StreamInnerNext } #[derive(CandidType, Deserialize)] -pub struct Stream(Option); +pub struct Stream(pub Option); candid::define_service!(pub S : { "f" : T::ty(); "g" : candid::func!((List) -> (B, Tree, Stream)); diff --git a/rust/candid_parser/tests/parse_type.rs b/rust/candid_parser/tests/parse_type.rs index 2d7bb219..ad956940 100644 --- a/rust/candid_parser/tests/parse_type.rs +++ b/rust/candid_parser/tests/parse_type.rs @@ -74,6 +74,9 @@ fn compiler_test(resource: &str) { "management.did" => { drop(external.0.insert("target".to_string(), "agent".to_string())) } + "class.did" => { + drop(external.0.insert("target".to_string(), "stub".to_string())) + } "example.did" => { let configs = std::fs::read_to_string(base_path.join("example.toml")) .unwrap() @@ -84,7 +87,8 @@ fn compiler_test(resource: &str) { _ => (), } let mut output = mint.new_goldenfile(filename.with_extension("rs")).unwrap(); - let content = rust::compile(&config, &env, &actor, external); + let (content, unused) = rust::compile(&config, &env, &actor, external); + assert!(unused.is_empty()); writeln!(output, "{content}").unwrap(); } { diff --git a/tools/didc/Cargo.toml b/tools/didc/Cargo.toml index 7243aa19..d6a61b46 100644 --- a/tools/didc/Cargo.toml +++ b/tools/didc/Cargo.toml @@ -11,4 +11,5 @@ pretty-hex = "0.2.1" hex.workspace = true anyhow.workspace = true rand.workspace = true +console.workspace = true diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index d6db3b70..bed24ab0 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -8,6 +8,7 @@ use candid_parser::{ Error, IDLArgs, IDLValue, TypeEnv, }; use clap::Parser; +use console::style; use std::collections::HashSet; use std::io; use std::path::PathBuf; @@ -169,6 +170,15 @@ fn load_config(input: &Option) -> Result { Some(str) => Configs::from_str(str), } } +fn warn_unused(unused: &[String]) { + for e in unused { + eprintln!( + "{} path {} is unused.", + style("WARNING:").red().bold(), + style(e).green(), + ); + } +} fn main() -> Result<()> { match Command::parse() { @@ -229,7 +239,9 @@ fn main() -> Result<()> { .map(|x| x.clone().try_into().unwrap()) .unwrap_or(ExternalConfig::default()); let config = Config::new(configs); - compile(&config, &env, &actor, external) + let (res, unused) = compile(&config, &env, &actor, external); + warn_unused(&unused); + res } "rs-agent" | "rs-stub" => { use candid_parser::bindings::rust::{compile, Config, ExternalConfig}; @@ -241,7 +253,9 @@ fn main() -> Result<()> { _ => unreachable!(), }; external.0.insert("target".to_string(), target.to_string()); - compile(&config, &env, &actor, external) + let (res, unused) = compile(&config, &env, &actor, external); + warn_unused(&unused); + res } _ => unreachable!(), }; From cccaa04668e992300135960c1bc35401c050f4d0 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:19:50 -0700 Subject: [PATCH 12/36] fix test suite (#564) * fix test suite * fix * fix * fix * Apply suggestions from code review Co-authored-by: Claudio Russo --------- Co-authored-by: Claudio Russo --- test/spacebomb.test.did | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/spacebomb.test.did b/test/spacebomb.test.did index fed3a2da..1c611046 100644 --- a/test/spacebomb.test.did +++ b/test/spacebomb.test.did @@ -16,22 +16,22 @@ // Plain decoding (unused arguments) assert blob "DIDL\01\6d\7f\01\00\80\94\eb\dc\03" !: () "vec null (extra argument)"; assert blob "DIDL\01\6d\70\01\00\80\94\eb\dc\03" !: () "vec reserved (extra argument)"; -assert blob "DIDL\04\6c\03\01\7f\02\01\03\02\6c\01\01\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: () "zero-sized record (extra argument)"; +assert blob "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: () "zero-sized record (extra argument)"; assert blob "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" !: () "vec vec null (extra argument)"; -assert blob "DIDL\03\6c\01\d6\fc\a7\02\01\6d\02\6c\00\01\00\80\ad\e2\04" !: () "vec record {} (extra argument)"; +assert blob "DIDL\02\6d\01\6c\00\01\00\80\ad\e2\04" !: () "vec record {} (extra argument)"; assert blob "DIDL\17\6c\02\01\7f\02\7f\6c\02\01\00\02\00\6c\02\00\01\01\01\6c\02\00\02\01\02\6c\02\00\03\01\03\6c\02\00\04\01\04\6c\02\00\05\01\05\6c\02\00\06\01\06\6c\02\00\07\01\07\6c\02\00\08\01\08\6c\02\00\09\01\09\6c\02\00\0a\01\0a\6c\02\00\0b\01\0b\6c\02\00\0c\01\0c\6c\02\00\0d\02\0d\6c\02\00\0e\01\0e\6c\02\00\0f\01\0f\6c\02\00\10\01\10\6c\02\00\11\01\11\6c\02\00\12\01\12\6c\02\00\13\01\13\6e\14\6d\15\01\16\02\01\01" !: () "vec opt record with 2^20 null (extra argument)"; // Decoding to actual type assert blob "DIDL\01\6d\7f\01\00\80\94\eb\dc\03" !: (vec opt nat) "vec null (not ignored)"; assert blob "DIDL\01\6d\70\01\00\80\94\eb\dc\03" !: (vec reserved) "vec reserved (not ignored)"; -assert blob "DIDL\04\6c\03\01\7f\02\01\03\02\6c\01\01\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: (vec record {null;record{reserved};record{}}) "zero-sized record (not ignored)"; +assert blob "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: (vec record {null;record{reserved};record{}}) "zero-sized record (not ignored)"; assert blob "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" !: (vec vec null) "vec vec null (not ignored)"; -assert blob "DIDL\03\6c\01\d6\fc\a7\02\01\6d\02\6c\00\01\00\80\ad\e2\04" !: (vec record {}) "vec record {} (not ignored)"; +assert blob "DIDL\02\6d\01\6c\00\01\00\80\ad\e2\04" !: (vec record {}) "vec record {} (not ignored)"; // Decoding under opt assert blob "DIDL\01\6d\7f\01\00\80\94\eb\dc\03" !: (opt nat) "vec null (subtyping)"; assert blob "DIDL\01\6d\70\01\00\80\94\eb\dc\03" !: (opt nat) "vec reserved (subtyping)"; -assert blob "DIDL\04\6c\03\01\7f\02\01\03\02\6c\01\01\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: (opt nat) "zero-sized record (subtyping)"; +assert blob "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: (opt nat) "zero-sized record (subtyping)"; assert blob "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" !: (vec opt nat) "vec vec null (subtyping)"; -assert blob "DIDL\03\6c\01\d6\fc\a7\02\01\6d\02\6c\00\01\00\80\ad\e2\04" !: (opt nat) "vec record {} (subtyping)"; +assert blob "DIDL\02\6d\01\6c\00\01\00\80\ad\e2\04" !: (opt nat) "vec record {} (subtyping)"; assert blob "DIDL\17\6c\02\01\7f\02\7f\6c\02\01\00\02\00\6c\02\00\01\01\01\6c\02\00\02\01\02\6c\02\00\03\01\03\6c\02\00\04\01\04\6c\02\00\05\01\05\6c\02\00\06\01\06\6c\02\00\07\01\07\6c\02\00\08\01\08\6c\02\00\09\01\09\6c\02\00\0a\01\0a\6c\02\00\0b\01\0b\6c\02\00\0c\01\0c\6c\02\00\0d\02\0d\6c\02\00\0e\01\0e\6c\02\00\0f\01\0f\6c\02\00\10\01\10\6c\02\00\11\01\11\6c\02\00\12\01\12\6c\02\00\13\01\13\6e\14\6d\15\01\16\05\01\01\01\01\01" !: (vec opt record {}) "vec opt record with 2^20 null (subtyping)"; From 47f6cae26f60c642bda8df2f047e5fd8f0a9e9c1 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:13:11 -0700 Subject: [PATCH 13/36] More rust bindgen fix (#562) * project_methods fail on not found * snake case for record fields * add MotokoResult * change template to take reference for call * bump dependencies --- Cargo.lock | 247 +++++++++--------- Changelog.md | 4 + rust/candid/Cargo.toml | 2 +- rust/candid/src/lib.rs | 1 + rust/candid/src/types/mod.rs | 1 + rust/candid/src/types/result.rs | 60 +++++ rust/candid_parser/Cargo.toml | 4 +- rust/candid_parser/src/bindings/analysis.rs | 30 ++- rust/candid_parser/src/bindings/rust.rs | 22 +- .../candid_parser/src/bindings/rust_agent.hbs | 2 +- rust/candid_parser/src/bindings/rust_call.hbs | 2 +- rust/candid_parser/tests/assets/ok/actor.rs | 8 +- rust/candid_parser/tests/assets/ok/cyclic.rs | 2 +- rust/candid_parser/tests/assets/ok/empty.rs | 6 +- rust/candid_parser/tests/assets/ok/escape.rs | 2 +- rust/candid_parser/tests/assets/ok/example.rs | 16 +- .../candid_parser/tests/assets/ok/fieldnat.rs | 14 +- rust/candid_parser/tests/assets/ok/keyword.rs | 20 +- .../tests/assets/ok/management.rs | 36 +-- .../tests/assets/ok/recursion.rs | 4 +- rust/candid_parser/tests/assets/ok/unicode.rs | 6 +- tools/didc/Cargo.toml | 2 +- tools/didc/src/main.rs | 4 +- 23 files changed, 296 insertions(+), 199 deletions(-) create mode 100644 rust/candid/src/types/result.rs diff --git a/Cargo.lock b/Cargo.lock index 30cb49fe..7e5c9381 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -28,33 +28,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys", @@ -126,7 +126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" dependencies = [ "either", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", "syn 1.0.109", ] @@ -148,9 +148,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -163,13 +163,13 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.17" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ - "lazy_static", "memchr", - "regex-automata 0.1.10", + "regex-automata", + "serde", ] [[package]] @@ -180,7 +180,7 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "candid" -version = "0.10.9" +version = "0.10.10" dependencies = [ "anyhow", "bincode", @@ -209,14 +209,14 @@ name = "candid_derive" version = "0.6.6" dependencies = [ "lazy_static", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "candid_parser" -version = "0.2.0-beta.3" +version = "0.2.0-beta.4" dependencies = [ "anyhow", "arbitrary", @@ -245,9 +245,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.99" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" [[package]] name = "cfg-if" @@ -263,9 +263,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "clap" -version = "4.5.7" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" dependencies = [ "clap_builder", "clap_derive", @@ -273,9 +273,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.7" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" dependencies = [ "anstream", "anstyle", @@ -285,21 +285,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.5" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" dependencies = [ "heck", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "codespan-reporting" @@ -313,9 +313,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "console" @@ -453,9 +453,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "ena" @@ -563,9 +563,9 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "handlebars" -version = "5.1.2" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "5226a0e122dc74917f3a701484482bed3ee86d016c7356836abbaa033133a157" dependencies = [ "log", "pest", @@ -627,9 +627,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -674,14 +674,14 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.7", + "regex-automata", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leb128" @@ -723,9 +723,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "logos" @@ -745,10 +745,10 @@ dependencies = [ "beef", "fnv", "lazy_static", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", "regex-syntax", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -786,9 +786,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -850,9 +850,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" dependencies = [ "memchr", "thiserror", @@ -861,9 +861,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" dependencies = [ "pest", "pest_generator", @@ -871,22 +871,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "pest_meta" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" dependencies = [ "once_cell", "pest", @@ -943,9 +943,9 @@ dependencies = [ [[package]] name = "pretty-hex" -version = "0.2.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" +checksum = "bbc83ee4a840062f368f9096d80077a9841ec117e17e7f700df81958f1451254" [[package]] name = "proc-macro2" @@ -958,9 +958,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -989,7 +989,7 @@ version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", ] [[package]] @@ -1024,9 +1024,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags", ] @@ -1050,16 +1050,10 @@ checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", + "regex-automata", "regex-syntax", ] -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - [[package]] name = "regex-automata" version = "0.4.7" @@ -1119,18 +1113,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] @@ -1147,31 +1141,32 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -1204,9 +1199,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "similar" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" dependencies = [ "bstr", "unicode-segmentation", @@ -1283,18 +1278,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.66" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", "unicode-ident", ] @@ -1345,22 +1340,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -1374,9 +1369,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.14" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +checksum = "81967dd0dd2c1ab0bc3468bd7caecc32b8a4aa47d0c8c695d8c2b2108168d62c" dependencies = [ "serde", "serde_spanned", @@ -1386,18 +1381,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.14" +version = "0.22.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +checksum = "8d9f8729f5aea9562aac1cc0441f5d6de3cff1ee0c5d67293eeca5eb36ee7c16" dependencies = [ "indexmap", "serde", @@ -1462,9 +1457,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -1524,9 +1519,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1540,57 +1535,57 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.13" +version = "0.6.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "b480ae9340fc261e6be3e95a1ba86d54ae3f9171132a73ce8d4bbaf68339507c" dependencies = [ "memchr", ] diff --git a/Changelog.md b/Changelog.md index 0114116f..22ff7790 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,10 @@ ## 2024-05-03 +### Candid 0.10.10 + +* Add `candid::MotokoResult` type. Use `motoko_result.into_result()` to convert the value into Rust result, and `rust_result.into()` to get Motoko result. + ### candid_parser 0.2.0-beta * Breaking changes: diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index 326d7bac..3385f1b2 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid" -version = "0.10.9" +version = "0.10.10" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] diff --git a/rust/candid/src/lib.rs b/rust/candid/src/lib.rs index 07bcca22..e83807b4 100644 --- a/rust/candid/src/lib.rs +++ b/rust/candid/src/lib.rs @@ -250,6 +250,7 @@ pub use types::{ rc, reference::{Func, Service}, reserved::{Empty, Reserved}, + result::MotokoResult, TypeEnv, }; diff --git a/rust/candid/src/types/mod.rs b/rust/candid/src/types/mod.rs index aab4554a..49af606d 100644 --- a/rust/candid/src/types/mod.rs +++ b/rust/candid/src/types/mod.rs @@ -25,6 +25,7 @@ pub mod number; pub mod principal; pub mod reference; pub mod reserved; +pub mod result; pub mod arc; pub mod rc; diff --git a/rust/candid/src/types/result.rs b/rust/candid/src/types/result.rs new file mode 100644 index 00000000..70eef1c1 --- /dev/null +++ b/rust/candid/src/types/result.rs @@ -0,0 +1,60 @@ +use crate::types::{CandidType, Compound, Field, Label, Serializer, Type, TypeInner}; +use serde::{Deserialize, Serialize}; + +#[allow(non_camel_case_types)] +#[derive(Deserialize, Debug, Clone, Serialize)] +pub enum MotokoResult { + ok(T), + err(E), +} +impl MotokoResult { + pub fn into_result(self) -> Result { + match self { + MotokoResult::ok(v) => Ok(v), + MotokoResult::err(e) => Err(e), + } + } +} +impl From> for MotokoResult { + fn from(r: Result) -> Self { + match r { + Ok(v) => MotokoResult::ok(v), + Err(e) => MotokoResult::err(e), + } + } +} +impl CandidType for MotokoResult +where + T: CandidType, + E: CandidType, +{ + fn _ty() -> Type { + TypeInner::Variant(vec![ + // Make sure the field id is sorted by idl_hash + Field { + id: Label::Named("ok".to_owned()).into(), + ty: T::ty(), + }, + Field { + id: Label::Named("err".to_owned()).into(), + ty: E::ty(), + }, + ]) + .into() + } + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: Serializer, + { + match *self { + MotokoResult::ok(ref v) => { + let mut ser = serializer.serialize_variant(0)?; + Compound::serialize_element(&mut ser, v) + } + MotokoResult::err(ref e) => { + let mut ser = serializer.serialize_variant(1)?; + Compound::serialize_element(&mut ser, e) + } + } + } +} diff --git a/rust/candid_parser/Cargo.toml b/rust/candid_parser/Cargo.toml index 4961df50..e648989c 100644 --- a/rust/candid_parser/Cargo.toml +++ b/rust/candid_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid_parser" -version = "0.2.0-beta.3" +version = "0.2.0-beta.4" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] @@ -31,7 +31,7 @@ serde.workspace = true lalrpop-util = "0.20.0" logos = "0.14" convert_case = "0.6" -handlebars = "5.1" +handlebars = "6.0" toml = { version = "0.8", default-features = false, features = ["parse"] } arbitrary = { workspace = true, optional = true } diff --git a/rust/candid_parser/src/bindings/analysis.rs b/rust/candid_parser/src/bindings/analysis.rs index 8a133a69..edd316bc 100644 --- a/rust/candid_parser/src/bindings/analysis.rs +++ b/rust/candid_parser/src/bindings/analysis.rs @@ -1,16 +1,36 @@ -use crate::Result; +use crate::{Error, Result}; use candid::types::{Type, TypeEnv, TypeInner}; use std::collections::{BTreeMap, BTreeSet}; /// Select a subset of methods from an actor. -pub fn project_methods(env: &TypeEnv, actor: &Option, methods: &[String]) -> Option { - let service = env.as_service(actor.as_ref()?).ok()?; +pub fn project_methods( + env: &TypeEnv, + actor: &Option, + mut methods: Vec, +) -> Result { + let actor = actor + .as_ref() + .ok_or_else(|| Error::Custom(anyhow::anyhow!("no actor")))?; + let service = env.as_service(actor)?; let filtered = service .iter() - .filter(|(name, _)| methods.contains(name)) + .filter(|(name, _)| { + if let Some(idx) = methods.iter().position(|m| m == name) { + methods.swap_remove(idx); + true + } else { + false + } + }) .cloned() .collect(); - Some(TypeInner::Service(filtered).into()) + if !methods.is_empty() { + return Err(Error::Custom(anyhow::anyhow!( + "methods not found: {:?}", + methods + ))); + } + Ok(TypeInner::Service(filtered).into()) } /// Same as chase_actor, with seen set as part of the type. Used for chasing type names from type definitions. diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index 8c8462eb..ab173079 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -90,13 +90,19 @@ pub(crate) fn is_tuple(fs: &[Field]) -> bool { .enumerate() .any(|(i, field)| field.id.get_id() != (i as u32)) } -fn as_result(fs: &[Field]) -> Option<(&Type, &Type)> { +fn as_result(fs: &[Field]) -> Option<(&Type, &Type, bool)> { match fs { [Field { id: ok, ty: t_ok }, Field { id: err, ty: t_err }] if **ok == Label::Named("Ok".to_string()) && **err == Label::Named("Err".to_string()) => { - Some((t_ok, t_err)) + Some((t_ok, t_err, false)) + } + [Field { id: ok, ty: t_ok }, Field { id: err, ty: t_err }] + if **ok == Label::Named("ok".to_string()) + && **err == Label::Named("err".to_string()) => + { + Some((t_ok, t_err, true)) } _ => None, } @@ -230,7 +236,7 @@ fn test_{test_name}() {{ Record(ref fs) => self.pp_record_fields(fs, false, is_ref), Variant(ref fs) => { // only possible for result variant - let (ok, err) = as_result(fs).unwrap(); + let (ok, err, is_motoko) = as_result(fs).unwrap(); // This is a hacky way to redirect Result type let old = self .state @@ -240,6 +246,8 @@ fn test_{test_name}() {{ // not generating test for this use_type. rustc should be able to catch type mismatches. self.state.update_stats("use_type"); res + } else if is_motoko { + "candid::MotokoResult".to_string() } else { "std::result::Result".to_string() }; @@ -285,7 +293,13 @@ fn test_{test_name}() {{ self.state.update_stats("name"); res } else { - let case = if is_variant { Some(Case::Pascal) } else { None }; + let case = if is_variant { + Some(Case::Pascal) + } else if !id.starts_with('_') { + Some(Case::Snake) + } else { + None + }; ident_(id, case) }; let attr = if is_rename { diff --git a/rust/candid_parser/src/bindings/rust_agent.hbs b/rust/candid_parser/src/bindings/rust_agent.hbs index f4521ae2..4e052625 100644 --- a/rust/candid_parser/src/bindings/rust_agent.hbs +++ b/rust/candid_parser/src/bindings/rust_agent.hbs @@ -9,7 +9,7 @@ type Result = std::result::Result; pub struct {{PascalCase service_name}}<'a>(pub Principal, pub &'a ic_agent::Agent); impl<'a> {{PascalCase service_name}}<'a> { {{#each methods}} - pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: {{this.1}}{{/each}}) -> Result<{{vec_to_arity this.rets}}> { + pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: &{{this.1}}{{/each}}) -> Result<{{vec_to_arity this.rets}}> { let args = Encode!({{#each this.args}}&{{this.0}}{{#unless @last}},{{/unless}}{{/each}})?; let bytes = self.1.{{#if (eq this.mode "update")}}update{{else}}query{{/if}}(&self.0, "{{escape_debug this.original_name}}").with_arg(args).{{#if (eq this.mode "update")}}call_and_wait{{else}}call{{/if}}().await?; Ok(Decode!(&bytes{{#each this.rets}}, {{this}}{{/each}})?) diff --git a/rust/candid_parser/src/bindings/rust_call.hbs b/rust/candid_parser/src/bindings/rust_call.hbs index 55fbf3a9..788fc0db 100644 --- a/rust/candid_parser/src/bindings/rust_call.hbs +++ b/rust/candid_parser/src/bindings/rust_call.hbs @@ -9,7 +9,7 @@ use ic_cdk::api::call::CallResult as Result; pub struct {{PascalCase service_name}}(pub Principal); impl {{PascalCase service_name}} { {{#each methods}} - pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: {{this.1}}{{/each}}) -> Result<({{#each this.rets}}{{this}},{{/each}})> { + pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: &{{this.1}}{{/each}}) -> Result<({{#each this.rets}}{{this}},{{/each}})> { ic_cdk::call(self.0, "{{escape_debug this.original_name}}", ({{#each this.args}}{{this.0}},{{/each}})).await } {{/each}} diff --git a/rust/candid_parser/tests/assets/ok/actor.rs b/rust/candid_parser/tests/assets/ok/actor.rs index 7049c0a4..2b30a305 100644 --- a/rust/candid_parser/tests/assets/ok/actor.rs +++ b/rust/candid_parser/tests/assets/ok/actor.rs @@ -12,16 +12,16 @@ pub struct O(pub Option>); pub struct Service(pub Principal); impl Service { - pub async fn f(&self, arg0: candid::Nat) -> Result<(H,)> { + pub async fn f(&self, arg0: &candid::Nat) -> Result<(H,)> { ic_cdk::call(self.0, "f", (arg0,)).await } - pub async fn g(&self, arg0: i8) -> Result<(i8,)> { + pub async fn g(&self, arg0: &i8) -> Result<(i8,)> { ic_cdk::call(self.0, "g", (arg0,)).await } - pub async fn h(&self, arg0: i8) -> Result<(i8,)> { + pub async fn h(&self, arg0: &i8) -> Result<(i8,)> { ic_cdk::call(self.0, "h", (arg0,)).await } - pub async fn o(&self, arg0: O) -> Result<(O,)> { + pub async fn o(&self, arg0: &O) -> Result<(O,)> { ic_cdk::call(self.0, "o", (arg0,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/cyclic.rs b/rust/candid_parser/tests/assets/ok/cyclic.rs index a7186883..33eaa02f 100644 --- a/rust/candid_parser/tests/assets/ok/cyclic.rs +++ b/rust/candid_parser/tests/assets/ok/cyclic.rs @@ -14,7 +14,7 @@ pub type X = Y; pub struct Service(pub Principal); impl Service { - pub async fn f(&self, arg0: A, arg1: B, arg2: C, arg3: X, arg4: Y, arg5: Z) -> Result<()> { + pub async fn f(&self, arg0: &A, arg1: &B, arg2: &C, arg3: &X, arg4: &Y, arg5: &Z) -> Result<()> { ic_cdk::call(self.0, "f", (arg0,arg1,arg2,arg3,arg4,arg5,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/empty.rs b/rust/candid_parser/tests/assets/ok/empty.rs index 2338c077..4477e9f9 100644 --- a/rust/candid_parser/tests/assets/ok/empty.rs +++ b/rust/candid_parser/tests/assets/ok/empty.rs @@ -17,13 +17,13 @@ pub enum HRet { #[serde(rename="a")] A(Box), #[serde(rename="b")] B{} } pub struct Service(pub Principal); impl Service { - pub async fn f(&self, arg0: FArg) -> Result<(FRet,)> { + pub async fn f(&self, arg0: &FArg) -> Result<(FRet,)> { ic_cdk::call(self.0, "f", (arg0,)).await } - pub async fn g(&self, arg0: T) -> Result<(GRet,)> { + pub async fn g(&self, arg0: &T) -> Result<(GRet,)> { ic_cdk::call(self.0, "g", (arg0,)).await } - pub async fn h(&self, arg0: (T,candid::Empty,)) -> Result<(HRet,)> { + pub async fn h(&self, arg0: &(T,candid::Empty,)) -> Result<(HRet,)> { ic_cdk::call(self.0, "h", (arg0,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/escape.rs b/rust/candid_parser/tests/assets/ok/escape.rs index 776d7e6c..0fde3e5d 100644 --- a/rust/candid_parser/tests/assets/ok/escape.rs +++ b/rust/candid_parser/tests/assets/ok/escape.rs @@ -18,7 +18,7 @@ pub struct T { pub struct Service(pub Principal); impl Service { - pub async fn _2635468193_(&self, arg0: T) -> Result<()> { + pub async fn _2635468193_(&self, arg0: &T) -> Result<()> { ic_cdk::call(self.0, "\n\'\"\'\'\"\"\r\t", (arg0,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/example.rs b/rust/candid_parser/tests/assets/ok/example.rs index dac11e1d..03559464 100644 --- a/rust/candid_parser/tests/assets/ok/example.rs +++ b/rust/candid_parser/tests/assets/ok/example.rs @@ -104,28 +104,28 @@ pub(crate) enum Error { #[serde(rename="a")] A, #[serde(rename="b")] B } pub struct Service(pub Principal); impl Service { - pub async fn bbbbb(&self, arg0: B) -> Result<()> { + pub async fn bbbbb(&self, arg0: &B) -> Result<()> { ic_cdk::call(self.0, "bbbbb", (arg0,)).await } - pub async fn f(&self, arg0: S) -> Result<()> { + pub async fn f(&self, arg0: &S) -> Result<()> { ic_cdk::call(self.0, "f", (arg0,)).await } - pub async fn f_1(&self, arg0: List, arg1: serde_bytes::ByteBuf, arg2: Option) -> Result<()> { + pub async fn f_1(&self, arg0: &List, arg1: &serde_bytes::ByteBuf, arg2: &Option) -> Result<()> { ic_cdk::call(self.0, "f1", (arg0,arg1,arg2,)).await } - pub async fn g(&self, arg0: List) -> Result<(B,Tree,Stream,)> { + pub async fn g(&self, arg0: &List) -> Result<(B,Tree,Stream,)> { ic_cdk::call(self.0, "g", (arg0,)).await } - pub async fn G11(&self, id: CanisterId, list: MyList, is_okay: Option, arg3: Nested) -> Result<(i128,Broker,NestedRes,)> { + pub async fn G11(&self, id: &CanisterId, list: &MyList, is_okay: &Option, arg3: &Nested) -> Result<(i128,Broker,NestedRes,)> { ic_cdk::call(self.0, "g1", (id,list,is_okay,arg3,)).await } - pub async fn h(&self, arg0: Vec>, arg1: HArg1, arg2: Option) -> Result<(HRet,)> { + pub async fn h(&self, arg0: &Vec>, arg1: &HArg1, arg2: &Option) -> Result<(HRet,)> { ic_cdk::call(self.0, "h", (arg0,arg1,arg2,)).await } - pub async fn i(&self, arg0: MyList, arg1: FArg1) -> Result<(Option,Res,)> { + pub async fn i(&self, arg0: &MyList, arg1: &FArg1) -> Result<(Option,Res,)> { ic_cdk::call(self.0, "i", (arg0,arg1,)).await } - pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,std::result::Result,)> { + pub async fn x(&self, arg0: &A, arg1: &B) -> Result<(Option,Option,std::result::Result,)> { ic_cdk::call(self.0, "x", (arg0,arg1,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/fieldnat.rs b/rust/candid_parser/tests/assets/ok/fieldnat.rs index 607c0445..93720cb9 100644 --- a/rust/candid_parser/tests/assets/ok/fieldnat.rs +++ b/rust/candid_parser/tests/assets/ok/fieldnat.rs @@ -29,25 +29,25 @@ pub struct FooRet { pub _2_: candid::Int, pub _2: candid::Int } pub struct Service(pub Principal); impl Service { - pub async fn bab(&self, arg0: candid::Int, arg1: candid::Nat) -> Result<()> { + pub async fn bab(&self, arg0: &candid::Int, arg1: &candid::Nat) -> Result<()> { ic_cdk::call(self.0, "bab", (arg0,arg1,)).await } - pub async fn bar(&self, arg0: BarArg) -> Result<(BarRet,)> { + pub async fn bar(&self, arg0: &BarArg) -> Result<(BarRet,)> { ic_cdk::call(self.0, "bar", (arg0,)).await } - pub async fn bas(&self, arg0: (candid::Int,candid::Int,)) -> Result<((String,candid::Nat,),)> { + pub async fn bas(&self, arg0: &(candid::Int,candid::Int,)) -> Result<((String,candid::Nat,),)> { ic_cdk::call(self.0, "bas", (arg0,)).await } - pub async fn baz(&self, arg0: BazArg) -> Result<(BazRet,)> { + pub async fn baz(&self, arg0: &BazArg) -> Result<(BazRet,)> { ic_cdk::call(self.0, "baz", (arg0,)).await } - pub async fn bba(&self, arg0: Tuple) -> Result<(NonTuple,)> { + pub async fn bba(&self, arg0: &Tuple) -> Result<(NonTuple,)> { ic_cdk::call(self.0, "bba", (arg0,)).await } - pub async fn bib(&self, arg0: (candid::Int,)) -> Result<(BibRet,)> { + pub async fn bib(&self, arg0: &(candid::Int,)) -> Result<(BibRet,)> { ic_cdk::call(self.0, "bib", (arg0,)).await } - pub async fn foo(&self, arg0: FooArg) -> Result<(FooRet,)> { + pub async fn foo(&self, arg0: &FooArg) -> Result<(FooRet,)> { ic_cdk::call(self.0, "foo", (arg0,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/keyword.rs b/rust/candid_parser/tests/assets/ok/keyword.rs index ae002bb1..20df13b4 100644 --- a/rust/candid_parser/tests/assets/ok/keyword.rs +++ b/rust/candid_parser/tests/assets/ok/keyword.rs @@ -45,34 +45,34 @@ impl Service { pub async fn oneway(&self) -> Result<()> { ic_cdk::call(self.0, "Oneway", ()).await } - pub async fn f(&self, arg0: O) -> Result<(O,)> { + pub async fn f(&self, arg0: &O) -> Result<(O,)> { ic_cdk::call(self.0, "f_", (arg0,)).await } - pub async fn field(&self, arg0: FieldArg) -> Result<(FieldRet,)> { + pub async fn field(&self, arg0: &FieldArg) -> Result<(FieldRet,)> { ic_cdk::call(self.0, "field", (arg0,)).await } - pub async fn fieldnat(&self, arg0: FieldnatArg) -> Result<((candid::Int,),)> { + pub async fn fieldnat(&self, arg0: &FieldnatArg) -> Result<((candid::Int,),)> { ic_cdk::call(self.0, "fieldnat", (arg0,)).await } - pub async fn oneway(&self, arg0: u8) -> Result<()> { + pub async fn oneway(&self, arg0: &u8) -> Result<()> { ic_cdk::call(self.0, "oneway", (arg0,)).await } - pub async fn oneway(&self, arg0: u8) -> Result<()> { + pub async fn oneway(&self, arg0: &u8) -> Result<()> { ic_cdk::call(self.0, "oneway_", (arg0,)).await } - pub async fn query(&self, arg0: serde_bytes::ByteBuf) -> Result<(serde_bytes::ByteBuf,)> { + pub async fn query(&self, arg0: &serde_bytes::ByteBuf) -> Result<(serde_bytes::ByteBuf,)> { ic_cdk::call(self.0, "query", (arg0,)).await } - pub async fn r#return(&self, arg0: O) -> Result<(O,)> { + pub async fn r#return(&self, arg0: &O) -> Result<(O,)> { ic_cdk::call(self.0, "return", (arg0,)).await } - pub async fn service(&self, arg0: Return) -> Result<()> { + pub async fn service(&self, arg0: &Return) -> Result<()> { ic_cdk::call(self.0, "service", (arg0,)).await } - pub async fn tuple(&self, arg0: (candid::Int,serde_bytes::ByteBuf,String,)) -> Result<((candid::Int,u8,),)> { + pub async fn tuple(&self, arg0: &(candid::Int,serde_bytes::ByteBuf,String,)) -> Result<((candid::Int,u8,),)> { ic_cdk::call(self.0, "tuple", (arg0,)).await } - pub async fn variant(&self, arg0: VariantArg) -> Result<()> { + pub async fn variant(&self, arg0: &VariantArg) -> Result<()> { ic_cdk::call(self.0, "variant", (arg0,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/management.rs b/rust/candid_parser/tests/assets/ok/management.rs index a3715bbe..311f8e1d 100644 --- a/rust/candid_parser/tests/assets/ok/management.rs +++ b/rust/candid_parser/tests/assets/ok/management.rs @@ -205,67 +205,67 @@ pub struct UpdateSettingsArg { pub struct Service<'a>(pub Principal, pub &'a ic_agent::Agent); impl<'a> Service<'a> { - pub async fn bitcoin_get_balance(&self, arg0: GetBalanceRequest) -> Result { + pub async fn bitcoin_get_balance(&self, arg0: &GetBalanceRequest) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "bitcoin_get_balance").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, Satoshi)?) } - pub async fn bitcoin_get_current_fee_percentiles(&self, arg0: GetCurrentFeePercentilesRequest) -> Result> { + pub async fn bitcoin_get_current_fee_percentiles(&self, arg0: &GetCurrentFeePercentilesRequest) -> Result> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "bitcoin_get_current_fee_percentiles").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, Vec)?) } - pub async fn bitcoin_get_utxos(&self, arg0: GetUtxosRequest) -> Result { + pub async fn bitcoin_get_utxos(&self, arg0: &GetUtxosRequest) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "bitcoin_get_utxos").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, GetUtxosResponse)?) } - pub async fn bitcoin_send_transaction(&self, arg0: SendTransactionRequest) -> Result<()> { + pub async fn bitcoin_send_transaction(&self, arg0: &SendTransactionRequest) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "bitcoin_send_transaction").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn canister_status(&self, arg0: CanisterStatusArg) -> Result { + pub async fn canister_status(&self, arg0: &CanisterStatusArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "canister_status").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, CanisterStatusRet)?) } - pub async fn create_canister(&self, arg0: CreateCanisterArg) -> Result { + pub async fn create_canister(&self, arg0: &CreateCanisterArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "create_canister").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, CreateCanisterRet)?) } - pub async fn delete_canister(&self, arg0: DeleteCanisterArg) -> Result<()> { + pub async fn delete_canister(&self, arg0: &DeleteCanisterArg) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "delete_canister").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn deposit_cycles(&self, arg0: DepositCyclesArg) -> Result<()> { + pub async fn deposit_cycles(&self, arg0: &DepositCyclesArg) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "deposit_cycles").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn ecdsa_public_key(&self, arg0: EcdsaPublicKeyArg) -> Result { + pub async fn ecdsa_public_key(&self, arg0: &EcdsaPublicKeyArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "ecdsa_public_key").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, EcdsaPublicKeyRet)?) } - pub async fn http_request(&self, arg0: HttpRequestArg) -> Result { + pub async fn http_request(&self, arg0: &HttpRequestArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "http_request").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, HttpResponse)?) } - pub async fn install_code(&self, arg0: InstallCodeArg) -> Result<()> { + pub async fn install_code(&self, arg0: &InstallCodeArg) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "install_code").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn provisional_create_canister_with_cycles(&self, arg0: ProvisionalCreateCanisterWithCyclesArg) -> Result { + pub async fn provisional_create_canister_with_cycles(&self, arg0: &ProvisionalCreateCanisterWithCyclesArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "provisional_create_canister_with_cycles").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, ProvisionalCreateCanisterWithCyclesRet)?) } - pub async fn provisional_top_up_canister(&self, arg0: ProvisionalTopUpCanisterArg) -> Result<()> { + pub async fn provisional_top_up_canister(&self, arg0: &ProvisionalTopUpCanisterArg) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "provisional_top_up_canister").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) @@ -275,27 +275,27 @@ impl<'a> Service<'a> { let bytes = self.1.update(&self.0, "raw_rand").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, serde_bytes::ByteBuf)?) } - pub async fn sign_with_ecdsa(&self, arg0: SignWithEcdsaArg) -> Result { + pub async fn sign_with_ecdsa(&self, arg0: &SignWithEcdsaArg) -> Result { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "sign_with_ecdsa").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes, SignWithEcdsaRet)?) } - pub async fn start_canister(&self, arg0: StartCanisterArg) -> Result<()> { + pub async fn start_canister(&self, arg0: &StartCanisterArg) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "start_canister").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn stop_canister(&self, arg0: StopCanisterArg) -> Result<()> { + pub async fn stop_canister(&self, arg0: &StopCanisterArg) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "stop_canister").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn uninstall_code(&self, arg0: UninstallCodeArg) -> Result<()> { + pub async fn uninstall_code(&self, arg0: &UninstallCodeArg) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "uninstall_code").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) } - pub async fn update_settings(&self, arg0: UpdateSettingsArg) -> Result<()> { + pub async fn update_settings(&self, arg0: &UpdateSettingsArg) -> Result<()> { let args = Encode!(&arg0)?; let bytes = self.1.update(&self.0, "update_settings").with_arg(args).call_and_wait().await?; Ok(Decode!(&bytes)?) diff --git a/rust/candid_parser/tests/assets/ok/recursion.rs b/rust/candid_parser/tests/assets/ok/recursion.rs index 480962c7..236f2254 100644 --- a/rust/candid_parser/tests/assets/ok/recursion.rs +++ b/rust/candid_parser/tests/assets/ok/recursion.rs @@ -31,10 +31,10 @@ candid::define_service!(pub S : { pub struct Service(pub Principal); impl Service { - pub async fn f(&self, arg0: S) -> Result<()> { + pub async fn f(&self, arg0: &S) -> Result<()> { ic_cdk::call(self.0, "f", (arg0,)).await } - pub async fn g(&self, arg0: List) -> Result<(B,Tree,Stream,)> { + pub async fn g(&self, arg0: &List) -> Result<(B,Tree,Stream,)> { ic_cdk::call(self.0, "g", (arg0,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/unicode.rs b/rust/candid_parser/tests/assets/ok/unicode.rs index ec2ebbe1..87c596f4 100644 --- a/rust/candid_parser/tests/assets/ok/unicode.rs +++ b/rust/candid_parser/tests/assets/ok/unicode.rs @@ -29,16 +29,16 @@ pub enum B { pub struct Service(pub Principal); impl Service { - pub async fn _0_(&self, arg0: candid::Nat) -> Result<(candid::Nat,)> { + pub async fn _0_(&self, arg0: &candid::Nat) -> Result<(candid::Nat,)> { ic_cdk::call(self.0, "", (arg0,)).await } pub async fn _356566390_(&self) -> Result<()> { ic_cdk::call(self.0, "✈️ 🚗 ⛱️ ", ()).await } - pub async fn _3300066460_(&self, arg0: A) -> Result<(B,)> { + pub async fn _3300066460_(&self, arg0: &A) -> Result<(B,)> { ic_cdk::call(self.0, "函数名", (arg0,)).await } - pub async fn _2669435454_(&self, arg0: candid::Nat) -> Result<(candid::Nat,)> { + pub async fn _2669435454_(&self, arg0: &candid::Nat) -> Result<(candid::Nat,)> { ic_cdk::call(self.0, "👀", (arg0,)).await } } diff --git a/tools/didc/Cargo.toml b/tools/didc/Cargo.toml index d6a61b46..19ab3a7f 100644 --- a/tools/didc/Cargo.toml +++ b/tools/didc/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] candid_parser = { path = "../../rust/candid_parser", features = ["all"] } clap = { version = "4.5", features = ["derive"] } -pretty-hex = "0.2.1" +pretty-hex = "0.4.1" hex.workspace = true anyhow.workspace = true rand.workspace = true diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index bed24ab0..68861b2a 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -225,7 +225,9 @@ fn main() -> Result<()> { let configs = load_config(&config)?; let (env, mut actor) = pretty_check_file(&input)?; if !methods.is_empty() { - actor = candid_parser::bindings::analysis::project_methods(&env, &actor, &methods); + actor = Some(candid_parser::bindings::analysis::project_methods( + &env, &actor, methods, + )?); } let content = match target.as_str() { "js" => candid_parser::bindings::javascript::compile(&env, &actor), From 34b4eb0b581bbf04902e20bf1370e3a293d1956f Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Mon, 29 Jul 2024 18:08:11 -0700 Subject: [PATCH 14/36] remove macos 11 test (#565) --- .github/workflows/release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9bba0839..cb88cab5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,8 +82,6 @@ jobs: asset_name: didc-macos - os: macos-12 asset_name: didc-macos - - os: macos-11 - asset_name: didc-macos steps: - name: Get executable id: download From bba0b53d47ba3a14bc7da0b2b11119f8afcea37e Mon Sep 17 00:00:00 2001 From: David Frank Date: Fri, 9 Aug 2024 18:03:06 +0200 Subject: [PATCH 15/36] Remove unnecessary allocation/copy from the string serialization implementation (#566) --- rust/candid/src/ser.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/candid/src/ser.rs b/rust/candid/src/ser.rs index 15750555..79064070 100644 --- a/rust/candid/src/ser.rs +++ b/rust/candid/src/ser.rs @@ -147,9 +147,9 @@ impl<'a> types::Serializer for &'a mut ValueSerializer { serialize_num!(float64, f64, write_f64::); fn serialize_text(self, v: &str) -> Result<()> { - let mut buf = Vec::from(v.as_bytes()); + let buf = v.as_bytes(); self.write_leb128(buf.len() as u64)?; - self.value.append(&mut buf); + self.value.extend_from_slice(buf); Ok(()) } fn serialize_null(self, _v: ()) -> Result<()> { @@ -316,9 +316,9 @@ impl TypeSerialize { sleb128_encode(&mut buf, Opcode::Service as i64)?; leb128_encode(&mut buf, ms.len() as u64)?; for (id, ty) in ms { - let mut name = Vec::from(id.as_bytes()); + let name = id.as_bytes(); leb128_encode(&mut buf, name.len() as u64)?; - buf.append(&mut name); + buf.extend_from_slice(name); self.encode(&mut buf, ty)?; } } From f324a1686d6f2bd4fba9307a37f8e3f90cc7222b Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Thu, 15 Aug 2024 09:22:24 -0700 Subject: [PATCH 16/36] spec: candid type selector (#555) * spec: candid type selector * s/method/func/ * no scoped path for bindgen * clarify about use_type * Apply suggestions from code review Co-authored-by: Claudio Russo --------- Co-authored-by: Claudio Russo --- spec/Type-selector.md | 127 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 spec/Type-selector.md diff --git a/spec/Type-selector.md b/spec/Type-selector.md new file mode 100644 index 00000000..d2467afe --- /dev/null +++ b/spec/Type-selector.md @@ -0,0 +1,127 @@ +# Candid Type Selector specification + +Date: Jun 10, 2024 + +## Motivation + +We need a way to customize how we interpret Candid data for various use cases, for example, + +* Candid binding generation. One Candid type can map to several types in a host language, such as Rust and TypeScript. We may also want to adjust the type name and field name in the generated code to fit in the host language’s naming convention. +* Pretty printer and Candid UI. One Candid type can have different meanings in different canisters. For example, a `blob` type can represent an image, an account id, a Wasm binary, etc. We want to customize the format when showing the data in the terminal or in the browser. +* Data validation in deserialization. For canisters taking variable-length arguments, e.g., `blob`, `vec` and recursive types, we may want to limit the size of the input data to prevent spending too many cycles in deserializing invalid data. +* Random value generator. We want to customize how we generate random Candid values for fuzz testing. For example, we may want to restrict the range of a `nat` type, or limit the maximal depth of a recursive type. + +We can of course implement all these customizations in each application, but it is beneficial if we can identify a common syntax to express the type level customization and apply the same syntax to all applications to enforce a consistent user experience and reduce the learning curve. + +## Design + +Motivated by Cascading Style Sheets ([CSS](https://en.wikipedia.org/wiki/CSS)), we define a configuration language to specify the customization of a Candid interface. The configuration file enables the separation of the Candid interface and its configuration, including layout, binding, validation, etc. + +There are two parts in the config language: 1) A way to quickly select particular type nodes in Candid types; 2) Attach semantic meaning to the selected type nodes. + +### Type selector + +For the first part, we define a type selector `` similar to a CSS selector. + +``` + := (. )? | + := (. )* + := (. )* + := func: | func:init | arg: | ret: +``` + +`` is a sequence of names separated by "`.`". It is a pattern used to select the Candid type node you want to customize. For example, given the following Candid interface, + +``` +type tree = variant { leaf: int; branch: record { left: tree; right: tree } }; +type pair = record { left: int; right: int }; +service : { + f : (pair, pair) -> (pair); +} +``` + +Paths `left.tree`, `branch.record.left` and `tree.variant.branch.record.left` all match the left branch of a tree. Path `left` will match the "left" field in both `tree` and `pair`. We greedily match the path with a shorter pattern. For example, if you have both path `left` and `left.tree`, we will always match `left`, and `left.tree` will never be matched (we will issue a warning, if a path is never matched). If you want to match `left.tree`, you can replace the `left` path with `pair.record.left`. + +`` is a special form of path, where each name has a prefix of `func:`, `arg:`, or `ret:`. It indicates that the path can only be matched when it’s inside a scope of a function or argument position. A scoped path match always takes precedence over a non-scoped path. For example, `func:f.left` matches the `left` field in `pair`, but not the `left` field in `tree`, and the global `left` path will not be matched when processing function `f`; `func:f.arg:1.left` matches the `left` field in the second input argument of `f`; `ret:0.left` matches the first return type of all functions. + +Note that scoped path may not be available for some applications. For example, bindgen and deserialization don't support scoped path. In these applications, when a type variable is shared among multiple functions, scoped path can lead to duplication of type definitions, which makes the client code harder to maintain. You can still use non-scoped paths to match functions or arguments. We establish the following convention: + +* `func:` can be matched with ``. +* `func:init`, the initialization arguments of the service constructor, can be matched with `init`. +* `arg:` can be matched with `arg`. +* `ret:` can be matched with `ret`. + +Open question: The path doesn’t distinguish between label and type name. We cannot match just label `left`, but not type name `left`. We could add a prefix like `label:left`, but it means more things to type for the end user. We could work around this problem by providing a longer path if needed. + +### Config properties + +For the second part, we assign a set of key-value pairs (config) to the selected type nodes. It’s up to the implementer to interpret the meaning of these key-value pairs for different use cases. Concretely, each application defines its own config struct satisfying the following trait: + +```rust +trait Config { + fn merge_config(&mut self, config: &Self, ctx: &Context); + fn unmatched_config() -> Self; + fn update_state(&mut self, ctx: &Context); + fn restore_state(&mut self, ctx: &Context); +} +``` + +As the application traverses through the Candid type AST, we check if there is any path match with the current type node. If there is a match, we load the associated config and merge it with the current config. + +`merge_config` specifies the merging semantics of the key-value pairs. Specifically, whether these properties apply to the subtree rooted at the selected type node, or just the node itself. The merging semantics can depend on the `context`, which indicates the type of the current node (type or label), and whether the matched path is the first occurrence of the type path. Some properties, such as depth, can only apply to the first occurrence of the match. Otherwise, we get an infinite loop. + +When there is a path match, the matched key-value pairs is provided to the `merge_config` function to merge the current config with the matched config. If there is no path match, `unmatched_config` is provided to the `merge_config` function, which usually is an empty config. + +`update_state` and `restore_state` functions are used to update the config when traversing down/popping up the type AST. + +### TOML config + +Based on the above requirements, we choose TOML to specify our configurations for several reasons: + +1) The "." syntax to specify path is already part of the TOML syntax, and TOML allows to specify arbitrary key-value pairs as configurations; +2) Both Rust and Motoko developers are already familiar with the TOML format (used in Cargo and mops). + +A TOML config is always tied to a particular did file, similar to how CSS is tied to a particular HTML/JS file. Users can specify multiple config sections for different applications. A few known top level labels are `random`, `display`, `rust`, `motoko`, `typescript`. Developers are free to add new top-level labels. If the TOML file only contains config for one application, the top-level label can be omitted. + +The following is an example TOML config file for the Candid interface we showed earlier. It contains the configs for two applications: `random` and `rust`. The random config specifies that when generating a tree, the left branch is at most of depth 1, and the right branch is at most depth 5. The numbers on the leaves of the left branch are in [-200, -100], and the numbers on the leaves of the right branch are in [100, 200]. When generating Rust bindings, all types have `pub(crate)` visibility. The top-level structs and enums have attribute `#[derive(CandidType, Deserialize, Clone, Debug)]`, and we use `i128` to represent the `int` type. The first argument name of function `f` is `input`. + +```toml +[random] +left.tree = { depth = 1, range = [-200, -100] } +right.tree = { depth = 5, range = [100, 200] } + +[rust] +visibility = "pub(crate)" +attributes = "#[derive(CandidType, Deserialize, Clone, Debug)]" +int.use_type = "i128" +f.arg0.name = "input" +``` + +Note that TOML is just one implemented way to specify configs for the end user. Any format that can be parsed into [candid_parser::configs::ConfigTree](https://docs.rs/candid_parser/0.2.0-beta.1/candid_parser/configs/struct.ConfigTree.html) is acceptable. Users can also add configs programmatically in Rust via [add_config](https://docs.rs/candid_parser/0.2.0-beta.1/candid_parser/configs/struct.ConfigTree.html#method.add_config). For deserialization validation, we also want to support specifying config via Rust attributes. + +To facilitate tooling, we will add a new canister metadata `candid:config` to store the TOML config file if the canister author chooses to. + +## Rust binding configuration + +To generate Rust binding, we define the following config properties: + +* `name`: Rename a type variable or label. It only applies to the current node. +* `use_type`: Map a Candid type to a known/user-defined Rust type. It applies to the current node, or the next type node when the current node is a label. This allows `label.use_type = "T"` to indicate that we want to map the type of label to T. Otherwise, we have to use `label.type.use_type = "T"`. +* `attributes`: Set the attributes for struct/enum or fields. It applies to the current node, or the next label when the current node is a type. This allows us to apply field attributes to all fields in a struct/enum with `record.attributes`. +* `visibility`: Set the visibility for a type variable or label. It applies to the subtree rooted at the current node. For example, `tree.visibility` applies to the type variable tree and its fields. + +**Note** ++ Scoped path is not available in binding generation. You can use the non-scoped path, e.g., `init.arg0`, `f.ret0`, to match functions. ++ The bindgen generates a unit test for each instance of `use_type`. This is to ensure that the user provided type always conforms to Candid type. + +## Random value generation + +For random value generation, we define the following properties: + +* `range`: Specifies the range for all integer types. If omitted or invalid, we use the full integer range for that type. +* `width`: Specifies the maximal length for `vec` and `text` value. If omitted, we estimate the length based on the size of the vector element. +* `text`: Specifies the kind of text we want to generate. If omitted, it generates a random utf8 text. The implemented kinds are "ascii", "emoji", as well as some words from the fake crate: "name", "name.cn", "company", "country", "path" and "bs". +* `value`: Specifies a list of Candid values to choose from. It will be type checked against the expected type. +* `depth`: Specifies the maximal depth of the Candid value. For recursive types, it only applies to the first occurrence of the type selector. The depth bound is a soft limit. +* `size`: Specifies the maximal size of the Candid value. For recursive types, it only applies to the first occurrence of the type selector. The size bound is a soft limit. + From cfa7b54c2552fbaff0029c10d24fa37925e42b02 Mon Sep 17 00:00:00 2001 From: David Frank Date: Wed, 21 Aug 2024 18:25:12 +0200 Subject: [PATCH 17/36] Optimize the performance of deserializing types containing options (#568) The recoverable_visit_some method needs to clone the Deserializer in order to backtrack in case of errors. This cloning is a very expensive operation which this PR optimizes. 1. Wrap the TypeEnv in an Rc. Since the TypeEnv is a heavy object and is barely updated after the Deserializer is constructed, it makes sense to keep a single instance of it so cloning becomes cheap. 2. Make the happy path in recoverable_visit_some as cheap as possible by recursing on self instead of the clone. In case of an error, we reset the state from the clone. --- rust/candid/src/de.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/rust/candid/src/de.rs b/rust/candid/src/de.rs index afe5b14a..33bb9529 100644 --- a/rust/candid/src/de.rs +++ b/rust/candid/src/de.rs @@ -17,7 +17,7 @@ use binread::BinRead; use byteorder::{LittleEndian, ReadBytesExt}; use serde::de::{self, Visitor}; use std::fmt::Write; -use std::{collections::VecDeque, io::Cursor, mem::replace}; +use std::{collections::VecDeque, io::Cursor, mem::replace, rc::Rc}; const MAX_TYPE_LEN: i32 = 500; @@ -59,7 +59,7 @@ impl<'de> IDLDeserialize<'de> { env: &TypeEnv, expected_type: &Type, ) -> Result { - self.de.table.merge(env)?; + Rc::make_mut(&mut self.de.table).merge(env)?; self.de.is_untyped = true; self.deserialize_with_type(expected_type.clone()) } @@ -298,7 +298,7 @@ macro_rules! check_recursion { #[derive(Clone)] struct Deserializer<'de> { input: Cursor<&'de [u8]>, - table: TypeEnv, + table: Rc, types: VecDeque<(usize, Type)>, wire_type: Type, expect_type: Type, @@ -322,7 +322,7 @@ impl<'de> Deserializer<'de> { let (env, types) = header.to_types()?; Ok(Deserializer { input: reader, - table: env, + table: env.into(), types: types.into_iter().enumerate().collect(), wire_type: TypeInner::Unknown.into(), expect_type: TypeInner::Unknown.into(), @@ -603,15 +603,15 @@ impl<'de> Deserializer<'de> { } // This is safe, because the visitor either impl Copy or is zero sized let v = unsafe { std::ptr::read(&visitor) }; - let mut self_clone = self.clone(); - match v.visit_some(&mut self_clone) { - Ok(v) => { - *self = self_clone; - Ok(v) - } + let self_clone = self.clone(); + match v.visit_some(&mut *self) { + Ok(v) => Ok(v), Err(Error::Subtype(_)) => { - // Remember the backtracking cost - self.config = self_clone.config; + *self = Self { + // Remember the backtracking cost + config: self.config.clone(), + ..self_clone + }; self.add_cost(10)?; self.deserialize_ignored_any(serde::de::IgnoredAny)?; visitor.visit_none() From 0ed73c1448a07d00a1aa2d21bb2bd92208afd81a Mon Sep 17 00:00:00 2001 From: David Frank Date: Tue, 27 Aug 2024 09:39:57 +0200 Subject: [PATCH 18/36] Add size hints in order to optimize allocation during deserialization (#570) --- rust/candid/src/de.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/rust/candid/src/de.rs b/rust/candid/src/de.rs index 33bb9529..4fd6652e 100644 --- a/rust/candid/src/de.rs +++ b/rust/candid/src/de.rs @@ -1128,6 +1128,14 @@ impl<'de, 'a> de::SeqAccess<'de> for Compound<'a, 'de> { _ => Err(Error::subtype("expect vector or tuple")), } } + + fn size_hint(&self) -> Option { + match &self.style { + Style::Vector { len, .. } => Some(*len), + Style::Struct { expect, wire, .. } => Some(expect.len().min(wire.len())), + _ => None, + } + } } impl<'de, 'a> de::MapAccess<'de> for Compound<'a, 'de> { @@ -1221,6 +1229,14 @@ impl<'de, 'a> de::MapAccess<'de> for Compound<'a, 'de> { } } } + + fn size_hint(&self) -> Option { + match &self.style { + Style::Map { len, .. } => Some(*len), + Style::Struct { expect, wire, .. } => Some(expect.len().min(wire.len())), + _ => None, + } + } } impl<'de, 'a> de::EnumAccess<'de> for Compound<'a, 'de> { From 8c20762b734316613792226fb247a2aabd8fb823 Mon Sep 17 00:00:00 2001 From: mraszyk <31483726+mraszyk@users.noreply.github.com> Date: Fri, 30 Aug 2024 07:22:18 +0200 Subject: [PATCH 19/36] feat(didjs): skip asset certification in Candid UI canister (#571) * feat(didjs): asset certification in Candid UI canister * skip certification --- tools/ui/Cargo.lock | 92 ++++++++++++++++++++++++++++++++++- tools/ui/src/didjs/Cargo.toml | 8 ++- tools/ui/src/didjs/lib.rs | 74 +++++++++++++++++++++++++++- 3 files changed, 169 insertions(+), 5 deletions(-) diff --git a/tools/ui/Cargo.lock b/tools/ui/Cargo.lock index 1ef92a17..6222ebcf 100644 --- a/tools/ui/Cargo.lock +++ b/tools/ui/Cargo.lock @@ -44,6 +44,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "beef" version = "0.5.2" @@ -115,9 +121,15 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" + [[package]] name = "candid" -version = "0.10.4" +version = "0.10.10" dependencies = [ "anyhow", "binread", @@ -240,11 +252,16 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" name = "didjs" version = "0.1.0" dependencies = [ + "base64", "candid", "candid_parser", "ic-cdk", + "ic-certification", + "ic-http-certification", + "ic-representation-independent-hash", "serde", "serde_bytes", + "serde_cbor", ] [[package]] @@ -332,6 +349,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "half" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" + [[package]] name = "hashbrown" version = "0.14.3" @@ -344,6 +367,17 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "ic-cdk" version = "0.13.1" @@ -371,6 +405,40 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ic-certification" +version = "2.6.0" +source = "git+https://github.com/dfinity/response-verification?rev=da70db93832f88ecc556ae082612aedec47d3816#da70db93832f88ecc556ae082612aedec47d3816" +dependencies = [ + "hex", + "serde", + "serde_bytes", + "sha2", +] + +[[package]] +name = "ic-http-certification" +version = "2.6.0" +source = "git+https://github.com/dfinity/response-verification?rev=da70db93832f88ecc556ae082612aedec47d3816#da70db93832f88ecc556ae082612aedec47d3816" +dependencies = [ + "candid", + "http", + "ic-certification", + "ic-representation-independent-hash", + "serde", + "thiserror", + "urlencoding", +] + +[[package]] +name = "ic-representation-independent-hash" +version = "2.6.0" +source = "git+https://github.com/dfinity/response-verification?rev=da70db93832f88ecc556ae082612aedec47d3816#da70db93832f88ecc556ae082612aedec47d3816" +dependencies = [ + "leb128", + "sha2", +] + [[package]] name = "ic0" version = "0.21.1" @@ -408,6 +476,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "lalrpop" version = "0.20.2" @@ -756,6 +830,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.197" @@ -934,6 +1018,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "version_check" version = "0.9.4" diff --git a/tools/ui/src/didjs/Cargo.toml b/tools/ui/src/didjs/Cargo.toml index 2ac00da4..aa3d5a23 100644 --- a/tools/ui/src/didjs/Cargo.toml +++ b/tools/ui/src/didjs/Cargo.toml @@ -8,9 +8,13 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = "0.13" +base64 = "0.22.1" candid = "0.10" candid_parser = "0.1" +ic-cdk = "0.13" +ic-certification = { git = "https://github.com/dfinity/response-verification", rev = "da70db93832f88ecc556ae082612aedec47d3816" } +ic-http-certification = { git = "https://github.com/dfinity/response-verification", rev = "da70db93832f88ecc556ae082612aedec47d3816" } +ic-representation-independent-hash = { git = "https://github.com/dfinity/response-verification", rev = "da70db93832f88ecc556ae082612aedec47d3816" } serde = "1.0" serde_bytes = "0.11" - +serde_cbor = "0.11.2" diff --git a/tools/ui/src/didjs/lib.rs b/tools/ui/src/didjs/lib.rs index 6109052c..9aa60f5e 100644 --- a/tools/ui/src/didjs/lib.rs +++ b/tools/ui/src/didjs/lib.rs @@ -1,5 +1,13 @@ +use base64::engine::general_purpose::STANDARD as BASE64; +use base64::Engine; use candid::types::{subtype, Type, TypeInner}; use candid_parser::{check_prog, CandidType, Deserialize, IDLProg, TypeEnv}; +use ic_cdk::api::{data_certificate, set_certified_data}; +use ic_cdk::{init, post_upgrade}; +use ic_certification::{labeled, leaf, HashTree}; +use ic_http_certification::DefaultCelBuilder; +use ic_representation_independent_hash::hash; +use serde::Serialize; #[derive(CandidType, Deserialize)] pub struct HeaderField(pub String, pub String); @@ -97,7 +105,7 @@ fn get_path(url: &str) -> Option<&str> { fn http_request(request: HttpRequest) -> HttpResponse { //TODO add /canister_id/ as endpoint when ICQC is available. let path = get_path(request.url.as_str()).unwrap_or("/"); - if let Some((content_type, bytes)) = retrieve(path) { + let mut response = if let Some((content_type, bytes)) = retrieve(path) { HttpResponse { status_code: 200, headers: vec![ @@ -113,7 +121,69 @@ fn http_request(request: HttpRequest) -> HttpResponse { headers: Vec::new(), body: path.as_bytes().to_vec(), } - } + }; + add_certification_headers(&mut response); + response +} + +// Certify that frontend asset certification is skipped for this canister. + +const IC_CERTIFICATE_HEADER: &str = "IC-Certificate"; +const IC_CERTIFICATE_EXPRESSION_HEADER: &str = "IC-CertificateExpression"; + +fn skip_certification_cel_expr() -> String { + DefaultCelBuilder::skip_certification().to_string() +} + +fn skip_certification_asset_tree() -> HashTree { + let cel_expr_hash = hash(skip_certification_cel_expr().as_bytes()); + labeled( + "http_expr", + labeled("<*>", labeled(cel_expr_hash, leaf(vec![]))), + ) +} + +fn add_certification_headers(response: &mut HttpResponse) { + let certified_data = data_certificate().expect("No data certificate available"); + let witness = cbor_encode(&skip_certification_asset_tree()); + let expr_path = ["http_expr", "<*>"]; + let expr_path = cbor_encode(&expr_path); + + response.headers.push(HeaderField( + IC_CERTIFICATE_EXPRESSION_HEADER.to_string(), + skip_certification_cel_expr(), + )); + response.headers.push(HeaderField( + IC_CERTIFICATE_HEADER.to_string(), + format!( + "certificate=:{}:, tree=:{}:, expr_path=:{}:, version=2", + BASE64.encode(certified_data), + BASE64.encode(witness), + BASE64.encode(expr_path) + ), + )); +} + +// Encoding +fn cbor_encode(value: &impl Serialize) -> Vec { + let mut serializer = serde_cbor::Serializer::new(Vec::new()); + serializer + .self_describe() + .expect("Failed to self describe CBOR"); + value + .serialize(&mut serializer) + .expect("Failed to serialize value"); + serializer.into_inner() +} + +#[init] +fn init() { + set_certified_data(&skip_certification_asset_tree().digest()); +} + +#[post_upgrade] +fn post_upgrade() { + init(); } ic_cdk::export_candid!(); From 5234523fca11d4cbc75f6bdca21c704918361387 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Mon, 9 Sep 2024 11:15:05 -0700 Subject: [PATCH 20/36] add cross-origin header for candid UI (#572) --- tools/ui/Cargo.lock | 296 ++++++++++++++++++---------------- tools/ui/src/didjs/Cargo.toml | 2 +- tools/ui/src/didjs/lib.rs | 2 + 3 files changed, 160 insertions(+), 140 deletions(-) diff --git a/tools/ui/Cargo.lock b/tools/ui/Cargo.lock index 6222ebcf..e0b1e328 100644 --- a/tools/ui/Cargo.lock +++ b/tools/ui/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" [[package]] name = "arbitrary" @@ -40,9 +40,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base64" @@ -96,15 +96,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -155,7 +149,7 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -179,9 +173,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.88" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" +checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -210,18 +207,18 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -244,9 +241,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "didjs" @@ -297,15 +294,15 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "ena" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] @@ -340,9 +337,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -357,9 +354,9 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hex" @@ -380,9 +377,9 @@ dependencies = [ [[package]] name = "ic-cdk" -version = "0.13.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c63a6fceb94127bda86bd6d05f859a0e2a67d128a8ffb5ddab17e1f15ac8f555" +checksum = "dd8ecacd682fa05a985253592963306cb9799622d7b1cce4b1edb89c6ec85be1" dependencies = [ "candid", "ic-cdk-macros", @@ -393,16 +390,16 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.9.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fde5ca6ef1e69825c68916ff1bf7256b8f7ed69ac5ea3f1756f6e57f1503e27" +checksum = "0d4d857135deef20cc7ea8f3869a30cd9cfeb1392b3a81043790b2cd82adc3e0" dependencies = [ "candid", "proc-macro2", "quote", "serde", "serde_tokenstream", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] @@ -441,9 +438,9 @@ dependencies = [ [[package]] name = "ic0" -version = "0.21.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a54b5297861c651551676e8c43df805dad175cc33bc97dbd992edbbb85dcbcdf" +checksum = "8de254dd67bbd58073e23dc1c8553ba12fa1dc610a19de94ad2bbcd0460c067f" [[package]] name = "ic_principal" @@ -459,9 +456,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -496,7 +493,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.8.2", + "regex-syntax 0.8.4", "string_cache", "term", "tiny-keccak", @@ -515,9 +512,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leb128" @@ -527,26 +524,25 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.2", + "bitflags", "libc", - "redox_syscall", ] [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -554,9 +550,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "logos" @@ -578,7 +574,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -592,23 +588,22 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "new_debug_unreachable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", "serde", @@ -625,9 +620,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -640,9 +635,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -650,9 +645,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", @@ -663,15 +658,15 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap", @@ -711,45 +706,45 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" dependencies = [ "cc", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -758,25 +753,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.2", + "regex-syntax 0.8.4", ] [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.4", ] [[package]] @@ -787,15 +782,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "same-file" @@ -814,18 +809,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] @@ -842,24 +837,25 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "serde_tokenstream" -version = "0.1.7" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "797ba1d80299b264f3aac68ab5d12e5825a561749db4df7cd7c8083900c5d4e9" +checksum = "64060d864397305347a78851c51588fd283767e7e7589829e8121d65512340f1" dependencies = [ "proc-macro2", + "quote", "serde", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] @@ -873,6 +869,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "siphasher" version = "0.3.11" @@ -881,21 +883,21 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "stacker" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" dependencies = [ "cc", "cfg-if", "libc", "psm", - "winapi", + "windows-sys", ] [[package]] @@ -924,9 +926,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -955,22 +957,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -1008,15 +1010,15 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "urlencoding" @@ -1026,9 +1028,9 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -1064,11 +1066,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys", ] [[package]] @@ -1077,15 +1079,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -1094,42 +1106,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/tools/ui/src/didjs/Cargo.toml b/tools/ui/src/didjs/Cargo.toml index aa3d5a23..361a430b 100644 --- a/tools/ui/src/didjs/Cargo.toml +++ b/tools/ui/src/didjs/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib"] base64 = "0.22.1" candid = "0.10" candid_parser = "0.1" -ic-cdk = "0.13" +ic-cdk = "0.16" ic-certification = { git = "https://github.com/dfinity/response-verification", rev = "da70db93832f88ecc556ae082612aedec47d3816" } ic-http-certification = { git = "https://github.com/dfinity/response-verification", rev = "da70db93832f88ecc556ae082612aedec47d3816" } ic-representation-independent-hash = { git = "https://github.com/dfinity/response-verification", rev = "da70db93832f88ecc556ae082612aedec47d3816" } diff --git a/tools/ui/src/didjs/lib.rs b/tools/ui/src/didjs/lib.rs index 9aa60f5e..c1f74f9d 100644 --- a/tools/ui/src/didjs/lib.rs +++ b/tools/ui/src/didjs/lib.rs @@ -112,6 +112,8 @@ fn http_request(request: HttpRequest) -> HttpResponse { HeaderField("Content-Type".to_string(), content_type.to_string()), HeaderField("Content-Length".to_string(), format!("{}", bytes.len())), HeaderField("Cache-Control".to_string(), format!("max-age={}", 600)), + HeaderField("Cross-Origin-Embedder-Policy".to_string(), "require-corp".to_string()), + HeaderField("Cross-Origin-Resource-Policy".to_string(), "cross-origin".to_string()), ], body: bytes.to_vec(), } From 829343f682c727639386d5f306783008c6f07a45 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:42:13 -0700 Subject: [PATCH 21/36] fix d3 url to bypass CORS (#574) * fix d3 url to bypass CORS * bump agent-js --- tools/ui/package-lock.json | 163 +++++++++++++++++++------------------ tools/ui/package.json | 10 +-- tools/ui/src/candid.html | 2 +- tools/ui/src/candid.ts | 4 +- 4 files changed, 91 insertions(+), 88 deletions(-) diff --git a/tools/ui/package-lock.json b/tools/ui/package-lock.json index d2aabb24..fd65f66e 100644 --- a/tools/ui/package-lock.json +++ b/tools/ui/package-lock.json @@ -8,11 +8,11 @@ "name": "ui", "version": "0.1.0", "devDependencies": { - "@dfinity/agent": "1.0.1", - "@dfinity/auth-client": "1.0.1", - "@dfinity/candid": "1.0.1", - "@dfinity/identity": "1.0.1", - "@dfinity/principal": "1.0.1", + "@dfinity/agent": "2.1.0", + "@dfinity/auth-client": "2.1.0", + "@dfinity/candid": "2.1.0", + "@dfinity/identity": "2.1.0", + "@dfinity/principal": "2.1.0", "buffer": "6.0.3", "copy-webpack-plugin": "^9.0.1", "css-loader": "^6.8.1", @@ -30,12 +30,12 @@ "extraneous": true }, "node_modules/@dfinity/agent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-1.0.1.tgz", - "integrity": "sha512-QoCiKIWEgsXoaiHpb76M2qLXYDS9IdfvC81dLJYvX9KVXRq8Ojo4S82tBqBFGtM0j0EKEC6mIAJV/bqhOJTtjQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-2.1.0.tgz", + "integrity": "sha512-DXIg9Yx/80xERtEXzd37jGA/5kyR4gC57A3+JElOvBt/lWlfq+cEemaAEArI+cYmeE0xkB9DROCM7r5yEbRg7Q==", "dev": true, "dependencies": { - "@noble/curves": "^1.2.0", + "@noble/curves": "^1.4.0", "@noble/hashes": "^1.3.1", "base64-arraybuffer": "^0.2.0", "borc": "^2.1.1", @@ -43,37 +43,37 @@ "simple-cbor": "^0.4.1" }, "peerDependencies": { - "@dfinity/candid": "^1.0.1", - "@dfinity/principal": "^1.0.1" + "@dfinity/candid": "^2.1.0", + "@dfinity/principal": "^2.1.0" } }, "node_modules/@dfinity/auth-client": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/auth-client/-/auth-client-1.0.1.tgz", - "integrity": "sha512-QooHufXCDHTXySC1Tb1xf9+KRJISbw1sLYLIgY7PTxrA4Nc1ZgA7o4exwgRyIuJgoWMKrjgHPUZcu4N5ak69OQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/auth-client/-/auth-client-2.1.0.tgz", + "integrity": "sha512-Xnps491cxt22w4+Cz0EODzmVk5DRUYB1mpSKENJEeLNVJpH+9z6gbwaHyYYzxq0cKvd7V4iM1NmuT3kXUtAJeQ==", "dev": true, "dependencies": { "idb": "^7.0.2" }, "peerDependencies": { - "@dfinity/agent": "^1.0.1", - "@dfinity/identity": "^1.0.1", - "@dfinity/principal": "^1.0.1" + "@dfinity/agent": "^2.1.0", + "@dfinity/identity": "^2.1.0", + "@dfinity/principal": "^2.1.0" } }, "node_modules/@dfinity/candid": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-1.0.1.tgz", - "integrity": "sha512-PfZNV1fTOWtl+NhLOw71ACLYGugKF9HdEJKtkyBJqbj+6pqshvK6rllCUkGwMsmXfP8YopLzmoNVdy1rp/eOgg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-2.1.0.tgz", + "integrity": "sha512-MMD+bcIVrIJTLjyGx8xpj8A0Dwb8OPrFXWp/QHGXTSOezXxSMp2yG2QjxYkbV4EN5eCkwjeOY5mH2gHSa18pNA==", "dev": true, "peerDependencies": { - "@dfinity/principal": "^1.0.1" + "@dfinity/principal": "^2.1.0" } }, "node_modules/@dfinity/identity": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-1.0.1.tgz", - "integrity": "sha512-ArajyKSkiA4LjOq/ocGLMd66svgMVntF9j9P7irZScrzTCPcEXk5c7VteAqRGMwHCpI4LRipjmuZA1agwmUzRw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-2.1.0.tgz", + "integrity": "sha512-cB16Af65RpJwc3JR4r0jV+TckDiflPFHSRUh/JZ3920CUEDB1wYbzCcUtUb/IWiU101oKZNi5QdQrHp1haZq6w==", "dev": true, "dependencies": { "@noble/curves": "^1.2.0", @@ -81,15 +81,15 @@ "borc": "^2.1.1" }, "peerDependencies": { - "@dfinity/agent": "^1.0.1", - "@dfinity/principal": "^1.0.1", + "@dfinity/agent": "^2.1.0", + "@dfinity/principal": "^2.1.0", "@peculiar/webcrypto": "^1.4.0" } }, "node_modules/@dfinity/principal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-1.0.1.tgz", - "integrity": "sha512-pCAuTLcvZEZ8fYgVzTVhfUfFGadxeWN4v2z8Q0rizeiqcHKhbJVfWUiXXjzPGG5lNz2DxKyUHQ/WS4UTbTaxvg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-2.1.0.tgz", + "integrity": "sha512-nC3tI2Kxe9153mI3QdWzAsCnsyNygqnb9O/qhJOks97RCE1vfn3nkhq4dN6yBVpvlCv3hOMSleAcZm3DzH3NsQ==", "dev": true, "dependencies": { "@noble/hashes": "^1.3.1" @@ -136,24 +136,27 @@ } }, "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", + "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", "dev": true, "dependencies": { - "@noble/hashes": "1.3.2" + "@noble/hashes": "1.5.0" + }, + "engines": { + "node": "^14.21.3 || >=16" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", "dev": true, "engines": { - "node": ">= 16" + "node": "^14.21.3 || >=16" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -195,9 +198,9 @@ } }, "node_modules/@peculiar/asn1-schema": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", - "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.13.tgz", + "integrity": "sha512-3Xq3a01WkHRZL8X04Zsfg//mGaA21xlL4tlVn4v2xGT0JStiztATRkMwa5b+f/HXmY2smsiLXYK46Gwgzvfg3g==", "dev": true, "peer": true, "dependencies": { @@ -220,9 +223,9 @@ } }, "node_modules/@peculiar/webcrypto": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.5.tgz", - "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", + "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", "dev": true, "peer": true, "dependencies": { @@ -230,7 +233,7 @@ "@peculiar/json-schema": "^1.1.12", "pvtsutils": "^1.3.5", "tslib": "^2.6.2", - "webcrypto-core": "^1.7.8" + "webcrypto-core": "^1.8.0" }, "engines": { "node": ">=10.12.0" @@ -2715,9 +2718,9 @@ } }, "node_modules/webcrypto-core": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", - "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.0.tgz", + "integrity": "sha512-kR1UQNH8MD42CYuLzvibfakG5Ew5seG85dMMoAM/1LqvckxaF6pUiidLuraIu4V+YCIFabYecUZAW0TuxAoaqw==", "dev": true, "peer": true, "dependencies": { @@ -2932,12 +2935,12 @@ }, "dependencies": { "@dfinity/agent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-1.0.1.tgz", - "integrity": "sha512-QoCiKIWEgsXoaiHpb76M2qLXYDS9IdfvC81dLJYvX9KVXRq8Ojo4S82tBqBFGtM0j0EKEC6mIAJV/bqhOJTtjQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-2.1.0.tgz", + "integrity": "sha512-DXIg9Yx/80xERtEXzd37jGA/5kyR4gC57A3+JElOvBt/lWlfq+cEemaAEArI+cYmeE0xkB9DROCM7r5yEbRg7Q==", "dev": true, "requires": { - "@noble/curves": "^1.2.0", + "@noble/curves": "^1.4.0", "@noble/hashes": "^1.3.1", "base64-arraybuffer": "^0.2.0", "borc": "^2.1.1", @@ -2946,25 +2949,25 @@ } }, "@dfinity/auth-client": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/auth-client/-/auth-client-1.0.1.tgz", - "integrity": "sha512-QooHufXCDHTXySC1Tb1xf9+KRJISbw1sLYLIgY7PTxrA4Nc1ZgA7o4exwgRyIuJgoWMKrjgHPUZcu4N5ak69OQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/auth-client/-/auth-client-2.1.0.tgz", + "integrity": "sha512-Xnps491cxt22w4+Cz0EODzmVk5DRUYB1mpSKENJEeLNVJpH+9z6gbwaHyYYzxq0cKvd7V4iM1NmuT3kXUtAJeQ==", "dev": true, "requires": { "idb": "^7.0.2" } }, "@dfinity/candid": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-1.0.1.tgz", - "integrity": "sha512-PfZNV1fTOWtl+NhLOw71ACLYGugKF9HdEJKtkyBJqbj+6pqshvK6rllCUkGwMsmXfP8YopLzmoNVdy1rp/eOgg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-2.1.0.tgz", + "integrity": "sha512-MMD+bcIVrIJTLjyGx8xpj8A0Dwb8OPrFXWp/QHGXTSOezXxSMp2yG2QjxYkbV4EN5eCkwjeOY5mH2gHSa18pNA==", "dev": true, "requires": {} }, "@dfinity/identity": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-1.0.1.tgz", - "integrity": "sha512-ArajyKSkiA4LjOq/ocGLMd66svgMVntF9j9P7irZScrzTCPcEXk5c7VteAqRGMwHCpI4LRipjmuZA1agwmUzRw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-2.1.0.tgz", + "integrity": "sha512-cB16Af65RpJwc3JR4r0jV+TckDiflPFHSRUh/JZ3920CUEDB1wYbzCcUtUb/IWiU101oKZNi5QdQrHp1haZq6w==", "dev": true, "requires": { "@noble/curves": "^1.2.0", @@ -2973,9 +2976,9 @@ } }, "@dfinity/principal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-1.0.1.tgz", - "integrity": "sha512-pCAuTLcvZEZ8fYgVzTVhfUfFGadxeWN4v2z8Q0rizeiqcHKhbJVfWUiXXjzPGG5lNz2DxKyUHQ/WS4UTbTaxvg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-2.1.0.tgz", + "integrity": "sha512-nC3tI2Kxe9153mI3QdWzAsCnsyNygqnb9O/qhJOks97RCE1vfn3nkhq4dN6yBVpvlCv3hOMSleAcZm3DzH3NsQ==", "dev": true, "requires": { "@noble/hashes": "^1.3.1" @@ -3016,18 +3019,18 @@ } }, "@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", + "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", "dev": true, "requires": { - "@noble/hashes": "1.3.2" + "@noble/hashes": "1.5.0" } }, "@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", "dev": true }, "@nodelib/fs.scandir": { @@ -3057,9 +3060,9 @@ } }, "@peculiar/asn1-schema": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", - "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.13.tgz", + "integrity": "sha512-3Xq3a01WkHRZL8X04Zsfg//mGaA21xlL4tlVn4v2xGT0JStiztATRkMwa5b+f/HXmY2smsiLXYK46Gwgzvfg3g==", "dev": true, "peer": true, "requires": { @@ -3079,9 +3082,9 @@ } }, "@peculiar/webcrypto": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.5.tgz", - "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", + "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", "dev": true, "peer": true, "requires": { @@ -3089,7 +3092,7 @@ "@peculiar/json-schema": "^1.1.12", "pvtsutils": "^1.3.5", "tslib": "^2.6.2", - "webcrypto-core": "^1.7.8" + "webcrypto-core": "^1.8.0" } }, "@types/eslint": { @@ -4901,9 +4904,9 @@ } }, "webcrypto-core": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", - "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.0.tgz", + "integrity": "sha512-kR1UQNH8MD42CYuLzvibfakG5Ew5seG85dMMoAM/1LqvckxaF6pUiidLuraIu4V+YCIFabYecUZAW0TuxAoaqw==", "dev": true, "peer": true, "requires": { diff --git a/tools/ui/package.json b/tools/ui/package.json index 23d2ddcb..c048ccac 100644 --- a/tools/ui/package.json +++ b/tools/ui/package.json @@ -7,11 +7,11 @@ "build": "webpack" }, "devDependencies": { - "@dfinity/agent": "1.0.1", - "@dfinity/candid": "1.0.1", - "@dfinity/auth-client": "1.0.1", - "@dfinity/identity": "1.0.1", - "@dfinity/principal": "1.0.1", + "@dfinity/agent": "2.1.0", + "@dfinity/candid": "2.1.0", + "@dfinity/auth-client": "2.1.0", + "@dfinity/identity": "2.1.0", + "@dfinity/principal": "2.1.0", "buffer": "6.0.3", "copy-webpack-plugin": "^9.0.1", "css-loader": "^6.8.1", diff --git a/tools/ui/src/candid.html b/tools/ui/src/candid.html index 475ee03a..942bd1a5 100644 --- a/tools/ui/src/candid.html +++ b/tools/ui/src/candid.html @@ -76,7 +76,7 @@

Candid UI

- +