From 0cc9a0724afecfaefba4b41b39a66389edcdf64d Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 20 Mar 2024 19:20:33 -0700 Subject: [PATCH 01/14] replace dhall with toml --- Cargo.lock | 512 +++++++----------------------- rust/candid_parser/Cargo.toml | 5 +- rust/candid_parser/src/configs.rs | 36 ++- rust/candid_parser/src/error.rs | 6 +- tools/didc/random.dhall | 30 -- tools/didc/random.toml | 21 ++ tools/didc/src/main.rs | 7 +- 7 files changed, 156 insertions(+), 461 deletions(-) delete mode 100644 tools/didc/random.dhall create mode 100644 tools/didc/random.toml diff --git a/Cargo.lock b/Cargo.lock index ffa9b36e..37bb44f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,55 +2,15 @@ # 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" @@ -101,9 +61,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "arbitrary" @@ -165,7 +125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" dependencies = [ "either", - "proc-macro2 1.0.78", + "proc-macro2 1.0.79", "quote 1.0.35", "syn 1.0.109", ] @@ -193,18 +153,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "block-buffer" -version = "0.9.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -247,7 +198,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", - "pretty 0.12.3", + "pretty", "rand", "serde", "serde_bytes", @@ -262,9 +213,9 @@ name = "candid_derive" version = "0.6.6" dependencies = [ "lazy_static", - "proc-macro2 1.0.78", + "proc-macro2 1.0.79", "quote 1.0.35", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -287,12 +238,12 @@ dependencies = [ "logos", "num-bigint", "num-traits", - "pretty 0.12.3", + "pretty", "rand", "serde", - "serde_dhall", "test-generator", "thiserror", + "toml", ] [[package]] @@ -307,11 +258,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.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", "clap_derive", @@ -331,14 +288,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ "heck", - "proc-macro2 1.0.78", + "proc-macro2 1.0.79", "quote 1.0.35", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -421,9 +378,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", @@ -441,42 +398,6 @@ version = "1.4.3" 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", -] - [[package]] name = "dialoguer" version = "0.11.0" @@ -501,22 +422,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,27 +453,12 @@ 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" 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", -] - [[package]] name = "ena" version = "0.14.2" @@ -621,15 +518,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" @@ -675,12 +563,6 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.3" @@ -689,9 +571,9 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[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 +581,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,36 +593,16 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" 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" @@ -757,25 +610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", - "hashbrown 0.14.3", -] - -[[package]] -name = "itertools" -version = "0.9.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", + "hashbrown", ] [[package]] @@ -802,7 +637,7 @@ dependencies = [ "ascii-canvas", "bit-set", "ena", - "itertools 0.11.0", + "itertools", "lalrpop-util", "petgraph", "pico-args", @@ -848,7 +683,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall", ] @@ -892,10 +727,10 @@ checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" dependencies = [ "beef", "fnv", - "proc-macro2 1.0.78", + "proc-macro2 1.0.79", "quote 1.0.35", "regex-syntax 0.6.29", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -913,39 +748,24 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[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 2.5.0", "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,12 +802,6 @@ 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" @@ -1017,79 +831,6 @@ 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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.52", -] - -[[package]] -name = "pest_meta" -version = "2.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" -dependencies = [ - "once_cell", - "pest", - "sha2 0.10.8", -] - [[package]] name = "petgraph" version = "0.6.4" @@ -1097,7 +838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.5", + "indexmap", ] [[package]] @@ -1127,18 +868,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 +896,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1198,7 +927,7 @@ version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.78", + "proc-macro2 1.0.79", ] [[package]] @@ -1294,11 +1023,11 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -1366,22 +1095,9 @@ version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ - "proc-macro2 1.0.78", + "proc-macro2 1.0.79", "quote 1.0.35", - "syn 2.0.52", -] - -[[package]] -name = "serde_dhall" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c01a6b1d6f9f33bb1ad5652249e938297e43a1f43418236f7b72e64837e347" -dependencies = [ - "dhall", - "dhall_proc_macros", - "doc-comment", - "serde", - "url", + "syn 2.0.53", ] [[package]] @@ -1396,25 +1112,21 @@ dependencies = [ ] [[package]] -name = "serde_test" -version = "1.0.176" +name = "serde_spanned" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] [[package]] -name = "sha2" -version = "0.9.9" +name = "serde_test" +version = "1.0.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "serde", ] [[package]] @@ -1425,7 +1137,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -1462,15 +1174,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "smallvec" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "stacker" @@ -1521,18 +1227,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.78", + "proc-macro2 1.0.79", "quote 1.0.35", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.52" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ - "proc-macro2 1.0.78", + "proc-macro2 1.0.79", "quote 1.0.35", "unicode-ident", ] @@ -1583,22 +1289,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ - "proc-macro2 1.0.78", + "proc-macro2 1.0.79", "quote 1.0.35", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1611,19 +1317,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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] [[package]] name = "typed-arena" @@ -1637,33 +1362,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-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" @@ -1688,17 +1392,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" @@ -1881,8 +1574,17 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +[[package]] +name = "winnow" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +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/rust/candid_parser/Cargo.toml b/rust/candid_parser/Cargo.toml index 503322ed..06d8c87f 100644 --- a/rust/candid_parser/Cargo.toml +++ b/rust/candid_parser/Cargo.toml @@ -32,8 +32,7 @@ logos = "0.13" convert_case = "0.6" 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 } +toml = { version = "0.8", default-features = false, features = ["parse"], optional = true } fake = { version = "2.4", optional = true } rand = { version = "0.8", optional = true } num-traits = { workspace = true, optional = true } @@ -48,7 +47,7 @@ test-generator = "0.3.0" rand.workspace = true [features] -configs = ["serde_dhall"] +configs = ["toml"] random = ["configs", "arbitrary", "fake", "rand", "num-traits", "serde"] assist = ["dep:dialoguer", "dep:console", "dep:ctrlc"] all = ["random", "assist"] diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index 7acceb41..263706d5 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -1,31 +1,26 @@ -use crate::Result; use candid::types::Type; use serde::de::DeserializeOwned; -use serde_dhall::{from_simple_value, SimpleValue}; +use toml::Value; -pub struct Configs(SimpleValue); +pub struct Configs(Value); impl Configs { - pub fn from_dhall(v: &str) -> Result { - let v = serde_dhall::from_str(v).parse::()?; - Ok(Configs(v)) - } 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); + if let Value::Table(ref mut map) = res { + if let Some(Value::Table(subtree)) = map.remove(&path) { + map.extend(&mut subtree.into_iter()); } Configs(res) } else { unreachable!() } } - fn get_helper(&self, path: &[String]) -> Option<&SimpleValue> { + fn get_helper(&self, path: &[String]) -> Option<&Value> { let mut result = &self.0; for elem in path.iter() { - if let SimpleValue::Record(map) = result { + if let Value::Table(map) = result { result = map.get(elem)?; } else { unreachable!() @@ -42,13 +37,13 @@ impl Configs { /// 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)); + return Some((self.0.clone().try_into::().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()?; + let parsed_config = v.clone().try_into::().ok()?; return Some((parsed_config, is_repeated(path, tail))); } None => continue, @@ -57,17 +52,24 @@ impl Configs { None } } +impl std::str::FromStr for Configs { + type Err = crate::Error; + fn from_str(v: &str) -> Result { + let v = v.parse::()?; + Ok(Configs(v)) + } +} fn is_repeated(path: &[String], matched: &[String]) -> bool { let (test, _) = path.split_at(path.len() - matched.len()); test.join(".").contains(&matched.join(".")) } -fn has_leaf(v: &SimpleValue) -> bool { - if let SimpleValue::Record(map) = v { +fn has_leaf(v: &Value) -> bool { + if let Value::Table(map) = v { for (_, val) in map.iter() { match val { - SimpleValue::Record(_) => continue, + Value::Table(_) => continue, _ => return true, } } diff --git a/rust/candid_parser/src/error.rs b/rust/candid_parser/src/error.rs index 1bceb030..c88f4718 100644 --- a/rust/candid_parser/src/error.rs +++ b/rust/candid_parser/src/error.rs @@ -101,9 +101,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/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..e37cce07 --- /dev/null +++ b/tools/didc/random.toml @@ -0,0 +1,21 @@ +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 } + +["[h]"] +"[0]".a.range = [ 42, 42 ] +b.range = [ 0, 1 ] + +[profile.record] +name.text = "name" +age.range = [ 18, 65 ] +company.text = "company" +country.text = "country" +file.text = "path" +description = "bs" + +[principal] +value = [ "principal \"aaaaa-aa\"", "principal \"2ibo7-dia\"" ] diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index 9c5378f4..9c80c45e 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -310,18 +310,19 @@ fn main() -> Result<()> { } => { use candid_parser::configs::Configs; use rand::Rng; + use std::str::FromStr; 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, None) => Configs::from_str("")?, + (Some(str), None) => Configs::from_str(&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)? + Configs::from_str(&content)? } _ => unreachable!(), }; From 8b14b0e32cef9f7f7f86477732cbebe0f0701f5e Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Sun, 24 Mar 2024 16:18:47 -0700 Subject: [PATCH 02/14] checkpoint --- rust/candid/src/pretty/candid.rs | 2 +- rust/candid_parser/src/configs.rs | 33 +++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/rust/candid/src/pretty/candid.rs b/rust/candid/src/pretty/candid.rs index 29ebc0c4..7a30834a 100644 --- a/rust/candid/src/pretty/candid.rs +++ b/rust/candid/src/pretty/candid.rs @@ -119,7 +119,7 @@ pub fn pp_ty_inner(ty: &TypeInner) -> RcDoc { _ => unreachable!(), } } - Knot(ref id) => RcDoc::text(format!("{id}")), + Knot(ref id) => str(id.name), Unknown => str("unknown"), Future => str("future"), } diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index 263706d5..59c9c107 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -1,4 +1,4 @@ -use candid::types::Type; +use candid::types::{Type, TypeInner}; use serde::de::DeserializeOwned; use toml::Value; @@ -80,5 +80,34 @@ fn has_leaf(v: &Value) -> bool { } 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(_) => "vec", + TypeInner::Record(_) => "record", + TypeInner::Variant(_) => "variant", + TypeInner::Func(_) => "func", + TypeInner::Service(_) => "service", + TypeInner::Class(..) | TypeInner::Unknown | TypeInner::Future => unreachable!(), + } + .to_string() } From 000e9d9acd0672fb3ae3671f5b3fd3375e6c9c37 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Mon, 25 Mar 2024 08:54:39 -0700 Subject: [PATCH 03/14] checkpoint --- rust/candid_parser/src/configs.rs | 35 +++++++++++++++++++++++++++++++ tools/didc/random.toml | 8 ++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index 59c9c107..f6a454af 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -1,7 +1,34 @@ use candid::types::{Type, TypeInner}; use serde::de::DeserializeOwned; +use std::collections::BTreeMap; use toml::Value; +pub trait ConfigState: DeserializeOwned { + fn update(&mut self, config: &Self, is_recursive: bool); + fn push_state(&mut self, path: &[String]); +} + +pub struct StateTree { + state: Option, + subtree: BTreeMap>, +} +impl StateTree { + pub fn from_configs(kind: &str, configs: &Configs) -> Self { + if let Value::Table(map) = &configs.0 { + if let Some(v) = map.get(kind) { + generate_state_tree(v, None) + } else { + Self { + state: None, + subtree: BTreeMap::new(), + } + } + } else { + unreachable!() + } + } +} + pub struct Configs(Value); impl Configs { @@ -79,6 +106,14 @@ fn has_leaf(v: &Value) -> bool { } } +fn generate_state_tree(v: &Value, parent: Option<&T>) -> StateTree { + if let Value::Table(map) = v { + unimplemented!() + } else { + unimplemented!() + } +} + pub fn path_name(t: &Type) -> String { match t.as_ref() { TypeInner::Null => "null", diff --git a/tools/didc/random.toml b/tools/didc/random.toml index e37cce07..9bd8d496 100644 --- a/tools/didc/random.toml +++ b/tools/didc/random.toml @@ -1,3 +1,5 @@ + +[random] list = { depth = 20, size = 50 } val.value = [ "42", "-1" ] left = { depth = 1, range = [-200, -100] } @@ -5,11 +7,11 @@ right.tree = { depth = 5, range = [100, 200] } vec.nat8.range = [ 65, 90 ] Vec = { width = 2, size = 10 } -["[h]"] +[random."[h]"] "[0]".a.range = [ 42, 42 ] b.range = [ 0, 1 ] -[profile.record] +[random.profile.record] name.text = "name" age.range = [ 18, 65 ] company.text = "company" @@ -17,5 +19,5 @@ country.text = "country" file.text = "path" description = "bs" -[principal] +[random.principal] value = [ "principal \"aaaaa-aa\"", "principal \"2ibo7-dia\"" ] From e90e7c03669c3941b40ac2695a5b0be676c6db2b Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Sun, 31 Mar 2024 19:40:34 -0700 Subject: [PATCH 04/14] checkpoint --- rust/candid_parser/src/configs.rs | 182 +++++++++++++++++++++++++++--- rust/candid_parser/src/random.rs | 30 ++++- 2 files changed, 193 insertions(+), 19 deletions(-) diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index f6a454af..5843d930 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -1,32 +1,101 @@ +use anyhow::Result; use candid::types::{Type, TypeInner}; use serde::de::DeserializeOwned; use std::collections::BTreeMap; use toml::Value; -pub trait ConfigState: DeserializeOwned { - fn update(&mut self, config: &Self, is_recursive: bool); - fn push_state(&mut self, path: &[String]); +pub struct State<'a, T: ConfigState> { + tree: &'a mut ConfigTree, + path: Vec, + config: T, +} +pub enum StateElem<'a> { + Type(&'a Type), + Label(&'a str), +} +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), + } + } +} +impl<'a, T: ConfigState> State<'a, T> { + pub fn new(tree: &'a mut ConfigTree) -> Self { + let mut config = T::default(); + if let Some(state) = &tree.state { + config.merge_config(state, false); + } + Self { + tree, + path: Vec::new(), + config, + } + } + pub fn push_state(&mut self, elem: &StateElem) -> T { + self.config.update_mutable_state(elem); + let old_config = self.config.clone(); + self.path.push(elem.to_string()); + if let Some((state, is_recursive)) = self.tree.get_config(&self.path) { + self.config.merge_config(state, is_recursive); + } + old_config + } + pub fn pop_state(&mut self, old_config: T, elem: StateElem) { + self.config = old_config; + /*let elem =*/ + self.path.pop(); + self.config.restore_mutable_state(&elem); + } } -pub struct StateTree { +pub trait ConfigState: DeserializeOwned + Default + Clone { + fn merge_config(&mut self, config: &Self, is_recursive: bool); + fn update_mutable_state(&mut self, elem: &StateElem); + fn restore_mutable_state(&mut self, elem: &StateElem); +} +#[derive(Debug)] +pub struct ConfigTree { state: Option, - subtree: BTreeMap>, + max_depth: u8, + subtree: BTreeMap>, } -impl StateTree { - pub fn from_configs(kind: &str, configs: &Configs) -> Self { - if let Value::Table(map) = &configs.0 { - if let Some(v) = map.get(kind) { - generate_state_tree(v, None) +impl ConfigTree { + pub fn from_configs(kind: &str, configs: Configs) -> Result { + if let Value::Table(mut map) = configs.0 { + if let Some(v) = map.remove(kind) { + generate_state_tree(v) } else { - Self { + Ok(Self { state: None, subtree: BTreeMap::new(), - } + max_depth: 0, + }) } } else { unreachable!() } } + pub fn get_config(&self, path: &[String]) -> Option<(&T, bool)> { + let len = path.len(); + let start = len.saturating_sub(self.max_depth as usize); + for i in (start..len).rev() { + let tail = &path[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(Value); @@ -88,8 +157,15 @@ impl std::str::FromStr for Configs { } 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 + //let (test, _) = path.split_at(path.len() - matched.len()); + //test.join(".").contains(&matched.join(".")) } fn has_leaf(v: &Value) -> bool { @@ -105,12 +181,42 @@ fn has_leaf(v: &Value) -> bool { false } } +fn special_key(key: &str) -> bool { + key.starts_with('_') || key.starts_with('[') +} -fn generate_state_tree(v: &Value, parent: Option<&T>) -> StateTree { +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 { - unimplemented!() + 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)), + } + } + let state = if !leaves.is_empty() { + Some(leaves.try_into::()?) + } else { + None + }; + Ok(ConfigTree { + state, + subtree, + max_depth: depth, + }) } else { - unimplemented!() + Err(anyhow::anyhow!("Expected table")) } } @@ -142,7 +248,47 @@ pub fn path_name(t: &Type) -> String { TypeInner::Variant(_) => "variant", TypeInner::Func(_) => "func", TypeInner::Service(_) => "service", - TypeInner::Class(..) | TypeInner::Unknown | TypeInner::Future => unreachable!(), + 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, is_recursive: bool) { + unimplemented!() + } + fn update_mutable_state(&mut self, elem: &StateElem) { + unimplemented!() + } + fn restore_mutable_state(&mut self, elem: &StateElem) { + unimplemented!() + } + } + 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 } + "#; + let configs = toml.parse::().unwrap(); + let tree: ConfigTree = ConfigTree::from_configs("random", configs).unwrap(); + assert_eq!(tree.state, None); + assert_eq!(tree.subtree.len(), 5); + assert_eq!(tree.max_depth, 2); + assert_eq!( + tree.get_config(&["list".to_string()]).unwrap().0.depth, + Some(20) + ); +} diff --git a/rust/candid_parser/src/random.rs b/rust/candid_parser/src/random.rs index de8bd428..0406b1c7 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::{path_name, ConfigState, Configs}; +use crate::configs::StateElem; use crate::{Error, Result}; use arbitrary::{unstructured::Int, Arbitrary, Unstructured}; use candid::types::value::{IDLArgs, IDLField, IDLValue, VariantValue}; @@ -30,6 +31,33 @@ impl Default for GenConfig { } } } +impl ConfigState for GenConfig { + fn merge_config(&mut self, config: &Self, is_recursive: bool) { + self.range = config.range; + self.text = config.text.clone(); + self.width = config.width; + self.value = config.value.clone(); + if !is_recursive { + self.depth = config.depth; + self.size = config.size; + } + } + fn update_mutable_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); + } + } + } + fn restore_mutable_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); + } + } + } +} impl GenConfig { pub fn update(&self, config: GenConfig, recursive: bool) -> GenConfig { // TODO support removing properties From 186680b69cfb3f3f0ef5c4d19340ab2d7f98c484 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Mon, 8 Apr 2024 14:17:59 -0700 Subject: [PATCH 05/14] checkpoint --- rust/candid_parser/src/configs.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index 5843d930..9e6c8d1b 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -58,8 +58,9 @@ pub trait ConfigState: DeserializeOwned + Default + Clone { #[derive(Debug)] pub struct ConfigTree { state: Option, - max_depth: u8, 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 { @@ -77,6 +78,14 @@ impl ConfigTree { unreachable!() } } + /// Return the subtree starting with prefix + pub fn with_method(&self, prefix: Vec) -> Option<&Self> { + let mut tree = self; + for elem in prefix.iter() { + tree = tree.subtree.get(elem)?; + } + Some(tree) + } pub fn get_config(&self, path: &[String]) -> Option<(&T, bool)> { let len = path.len(); let start = len.saturating_sub(self.max_depth as usize); From c4d3e11b368c8e5758aaf67c6a4f13b5af154403 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:33:12 -0700 Subject: [PATCH 06/14] checkpoint --- rust/candid_parser/src/configs.rs | 22 ++-- rust/candid_parser/src/random.rs | 185 ++++++++++-------------------- 2 files changed, 73 insertions(+), 134 deletions(-) diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index 9e6c8d1b..95eecb22 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use candid::types::{Type, TypeInner}; +use candid::types::{Type, TypeEnv, TypeInner}; use serde::de::DeserializeOwned; use std::collections::BTreeMap; use toml::Value; @@ -7,7 +7,8 @@ use toml::Value; pub struct State<'a, T: ConfigState> { tree: &'a mut ConfigTree, path: Vec, - config: T, + pub config: T, + pub env: &'a TypeEnv, } pub enum StateElem<'a> { Type(&'a Type), @@ -22,7 +23,7 @@ impl<'a> std::fmt::Display for StateElem<'a> { } } impl<'a, T: ConfigState> State<'a, T> { - pub fn new(tree: &'a mut ConfigTree) -> Self { + pub fn new(tree: &'a mut ConfigTree, env: &'a TypeEnv) -> Self { let mut config = T::default(); if let Some(state) = &tree.state { config.merge_config(state, false); @@ -31,10 +32,12 @@ impl<'a, T: ConfigState> State<'a, T> { tree, path: Vec::new(), config, + env, } } + /// Return the old state AFTER `update_state`. pub fn push_state(&mut self, elem: &StateElem) -> T { - self.config.update_mutable_state(elem); + self.config.update_state(elem); let old_config = self.config.clone(); self.path.push(elem.to_string()); if let Some((state, is_recursive)) = self.tree.get_config(&self.path) { @@ -44,16 +47,15 @@ impl<'a, T: ConfigState> State<'a, T> { } pub fn pop_state(&mut self, old_config: T, elem: StateElem) { self.config = old_config; - /*let elem =*/ self.path.pop(); - self.config.restore_mutable_state(&elem); + self.config.restore_state(&elem); } } pub trait ConfigState: DeserializeOwned + Default + Clone { fn merge_config(&mut self, config: &Self, is_recursive: bool); - fn update_mutable_state(&mut self, elem: &StateElem); - fn restore_mutable_state(&mut self, elem: &StateElem); + fn update_state(&mut self, elem: &StateElem); + fn restore_state(&mut self, elem: &StateElem); } #[derive(Debug)] pub struct ConfigTree { @@ -276,10 +278,10 @@ fn parse() { fn merge_config(&mut self, config: &Self, is_recursive: bool) { unimplemented!() } - fn update_mutable_state(&mut self, elem: &StateElem) { + fn update_state(&mut self, elem: &StateElem) { unimplemented!() } - fn restore_mutable_state(&mut self, elem: &StateElem) { + fn restore_state(&mut self, elem: &StateElem) { unimplemented!() } } diff --git a/rust/candid_parser/src/random.rs b/rust/candid_parser/src/random.rs index 0406b1c7..7b5632a3 100644 --- a/rust/candid_parser/src/random.rs +++ b/rust/candid_parser/src/random.rs @@ -1,4 +1,4 @@ -use super::configs::{path_name, ConfigState, Configs}; +use super::configs::{ConfigState, Configs, State}; use crate::configs::StateElem; use crate::{Error, Result}; use arbitrary::{unstructured::Int, Arbitrary, Unstructured}; @@ -33,16 +33,20 @@ impl Default for GenConfig { } impl ConfigState for GenConfig { fn merge_config(&mut self, config: &Self, is_recursive: bool) { - self.range = config.range; - self.text = config.text.clone(); - self.width = config.width; - self.value = config.value.clone(); + self.range = config.range.or(self.range); + if config.text.is_some() { + self.text = config.text.clone(); + } + self.width = config.width.or(self.width); + if config.value.is_some() { + self.value = config.value.clone(); + } if !is_recursive { - self.depth = config.depth; - self.size = config.size; + self.depth = config.depth.or(self.depth); + self.size = config.size.or(self.size); } } - fn update_mutable_state(&mut self, elem: &StateElem) { + 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); @@ -50,7 +54,7 @@ impl ConfigState for GenConfig { } } } - fn restore_mutable_state(&mut self, elem: &StateElem) { + 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); @@ -58,124 +62,50 @@ impl ConfigState 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 }, - } - } -} -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); - } - GenState { - depth: config.depth.take().unwrap_or(5), - size: config.size.take().unwrap_or(50), - tree, - config, - env, - path: Vec::new(), - } - } - // 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; - } - } - 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; - } - } - } - self.path.pop(); - self.config = old_config; - self.depth = self.config.depth.take().unwrap(); - self.size = self.config.size.take().unwrap(); - } +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 { @@ -185,9 +115,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); @@ -200,9 +130,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, @@ -213,8 +145,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 { @@ -222,9 +156,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, @@ -234,22 +170,23 @@ 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]) -> Result { let mut u = arbitrary::Unstructured::new(seed); + let mut 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); + for (_i, t) in types.iter().enumerate() { + //let tree = tree.with_method(&i.to_string()); + let mut state = RandState(State::new(&mut tree, env)); let v = state.any(&mut u, t)?; args.push(v); } From e0a6938ebe79094a0175e8bbb448f5df280a3d3c Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 17 Apr 2024 09:59:24 -0700 Subject: [PATCH 07/14] checkpoint --- rust/candid_parser/src/configs.rs | 75 +++---------------------------- 1 file changed, 7 insertions(+), 68 deletions(-) diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index 95eecb22..3e544e4b 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use toml::Value; pub struct State<'a, T: ConfigState> { - tree: &'a mut ConfigTree, + tree: &'a ConfigTree, path: Vec, pub config: T, pub env: &'a TypeEnv, @@ -23,7 +23,7 @@ impl<'a> std::fmt::Display for StateElem<'a> { } } impl<'a, T: ConfigState> State<'a, T> { - pub fn new(tree: &'a mut ConfigTree, env: &'a TypeEnv) -> Self { + 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, false); @@ -35,7 +35,7 @@ impl<'a, T: ConfigState> State<'a, T> { env, } } - /// Return the old state AFTER `update_state`. + /// 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(); @@ -47,7 +47,7 @@ impl<'a, T: ConfigState> State<'a, T> { } pub fn pop_state(&mut self, old_config: T, elem: StateElem) { self.config = old_config; - self.path.pop(); + assert_eq!(self.path.pop(), Some(elem.to_string())); self.config.restore_state(&elem); } } @@ -111,54 +111,6 @@ impl ConfigTree { pub struct Configs(Value); -impl Configs { - pub fn with_method(&self, method: &str) -> Self { - let path = format!("[{method}]"); - let mut res = self.0.clone(); - if let Value::Table(ref mut map) = res { - if let Some(Value::Table(subtree)) = map.remove(&path) { - map.extend(&mut subtree.into_iter()); - } - Configs(res) - } else { - unreachable!() - } - } - fn get_helper(&self, path: &[String]) -> Option<&Value> { - let mut result = &self.0; - for elem in path.iter() { - if let Value::Table(map) = result { - result = map.get(elem)?; - } else { - unreachable!() - } - } - if has_leaf(result) { - Some(result) - } else { - None - } - } - /// 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((self.0.clone().try_into::().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 = v.clone().try_into::().ok()?; - return Some((parsed_config, is_repeated(path, tail))); - } - None => continue, - } - } - None - } -} impl std::str::FromStr for Configs { type Err = crate::Error; fn from_str(v: &str) -> Result { @@ -179,19 +131,6 @@ fn is_repeated(path: &[String], matched: &[String]) -> bool { //test.join(".").contains(&matched.join(".")) } -fn has_leaf(v: &Value) -> bool { - if let Value::Table(map) = v { - for (_, val) in map.iter() { - match val { - Value::Table(_) => continue, - _ => return true, - } - } - false - } else { - false - } -} fn special_key(key: &str) -> bool { key.starts_with('_') || key.starts_with('[') } @@ -275,13 +214,13 @@ fn parse() { text: Option, } impl ConfigState for T { - fn merge_config(&mut self, config: &Self, is_recursive: bool) { + fn merge_config(&mut self, _config: &Self, _is_recursive: bool) { unimplemented!() } - fn update_state(&mut self, elem: &StateElem) { + fn update_state(&mut self, _elem: &StateElem) { unimplemented!() } - fn restore_state(&mut self, elem: &StateElem) { + fn restore_state(&mut self, _elem: &StateElem) { unimplemented!() } } From ef204b8a897f849acaee8731487ef30d2681440c Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 17 Apr 2024 10:06:15 -0700 Subject: [PATCH 08/14] checkpoint --- rust/candid_parser/src/configs.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index 3e544e4b..ed6da3ce 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -2,7 +2,7 @@ use anyhow::Result; use candid::types::{Type, TypeEnv, TypeInner}; use serde::de::DeserializeOwned; use std::collections::BTreeMap; -use toml::Value; +use toml::{Table, Value}; pub struct State<'a, T: ConfigState> { tree: &'a ConfigTree, @@ -66,18 +66,15 @@ pub struct ConfigTree { } impl ConfigTree { pub fn from_configs(kind: &str, configs: Configs) -> Result { - if let Value::Table(mut map) = configs.0 { - if let Some(v) = map.remove(kind) { - generate_state_tree(v) - } else { - Ok(Self { - state: None, - subtree: BTreeMap::new(), - max_depth: 0, - }) - } + let mut map = configs.0; + if let Some(v) = map.remove(kind) { + generate_state_tree(v) } else { - unreachable!() + Ok(Self { + state: None, + subtree: BTreeMap::new(), + max_depth: 0, + }) } } /// Return the subtree starting with prefix @@ -109,12 +106,12 @@ impl ConfigTree { } } -pub struct Configs(Value); +pub struct Configs(Table); impl std::str::FromStr for Configs { type Err = crate::Error; fn from_str(v: &str) -> Result { - let v = v.parse::()?; + let v = v.parse::()?; Ok(Configs(v)) } } @@ -166,7 +163,7 @@ fn generate_state_tree(v: Value) -> Result> { max_depth: depth, }) } else { - Err(anyhow::anyhow!("Expected table")) + Err(anyhow::anyhow!("Expected a table")) } } From e596bdbe9d7e59ca670cab56847531f281eee7a2 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 17 Apr 2024 18:37:24 -0700 Subject: [PATCH 09/14] random works --- rust/candid_parser/src/configs.rs | 66 +++++++++++++++++++++++-------- rust/candid_parser/src/random.rs | 20 +++++++--- tools/didc/random.toml | 5 ++- tools/didc/src/main.rs | 19 +++++---- 4 files changed, 77 insertions(+), 33 deletions(-) diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index ed6da3ce..c6ff7d8f 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -7,6 +7,7 @@ use toml::{Table, Value}; pub struct State<'a, T: ConfigState> { tree: &'a ConfigTree, path: Vec, + open_tree: Option<&'a ConfigTree>, pub config: T, pub env: &'a TypeEnv, } @@ -14,14 +15,15 @@ pub enum StateElem<'a> { Type(&'a Type), Label(&'a str), } -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), - } - } +pub struct Scope<'a> { + pub method: &'a str, + pub position: Option, +} +pub enum ScopePos { + Arg, + Ret, } + impl<'a, T: ConfigState> State<'a, T> { pub fn new(tree: &'a ConfigTree, env: &'a TypeEnv) -> Self { let mut config = T::default(); @@ -30,17 +32,45 @@ impl<'a, T: ConfigState> State<'a, T> { } Self { tree, + open_tree: None, path: Vec::new(), config, env, } } + /// 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)); + } + None => self.open_tree = None, + } + } + } + } /// 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()); - if let Some((state, is_recursive)) = self.tree.get_config(&self.path) { + let new_state = if let Some(subtree) = self.open_tree { + subtree + .get_config(&self.path) + .or_else(|| self.tree.get_config(&self.path)) + } else { + self.tree.get_config(&self.path) + }; + if let Some((state, is_recursive)) = new_state { self.config.merge_config(state, is_recursive); } old_config @@ -70,15 +100,11 @@ impl ConfigTree { if let Some(v) = map.remove(kind) { generate_state_tree(v) } else { - Ok(Self { - state: None, - subtree: BTreeMap::new(), - max_depth: 0, - }) + generate_state_tree(Value::Table(map)) } } /// Return the subtree starting with prefix - pub fn with_method(&self, prefix: Vec) -> Option<&Self> { + pub fn with_prefix(&self, prefix: &[String]) -> Option<&Self> { let mut tree = self; for elem in prefix.iter() { tree = tree.subtree.get(elem)?; @@ -115,6 +141,14 @@ impl std::str::FromStr for Configs { 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), + } + } +} fn is_repeated(path: &[String], matched: &[String]) -> bool { let iter = path.as_ref().windows(matched.len()); @@ -124,12 +158,10 @@ fn is_repeated(path: &[String], matched: &[String]) -> bool { } } false - //let (test, _) = path.split_at(path.len() - matched.len()); - //test.join(".").contains(&matched.join(".")) } fn special_key(key: &str) -> bool { - key.starts_with('_') || key.starts_with('[') + key.starts_with("method:") || key.starts_with("arg:") || key.starts_with("ret:") } fn generate_state_tree(v: Value) -> Result> { diff --git a/rust/candid_parser/src/random.rs b/rust/candid_parser/src/random.rs index 7b5632a3..e62989b8 100644 --- a/rust/candid_parser/src/random.rs +++ b/rust/candid_parser/src/random.rs @@ -1,4 +1,4 @@ -use super::configs::{ConfigState, Configs, State}; +use super::configs::{ConfigState, Configs, Scope, State}; use crate::configs::StateElem; use crate::{Error, Result}; use arbitrary::{unstructured::Int, Arbitrary, Unstructured}; @@ -180,13 +180,21 @@ impl<'a> RandState<'a> { } } -pub fn any(seed: &[u8], configs: 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 mut tree = super::configs::ConfigTree::from_configs("random", configs)?; + 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 = RandState(State::new(&mut tree, env)); + for (i, t) in types.iter().enumerate() { + 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/tools/didc/random.toml b/tools/didc/random.toml index 9bd8d496..1b4f7f28 100644 --- a/tools/didc/random.toml +++ b/tools/didc/random.toml @@ -6,9 +6,10 @@ 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."[h]"] -"[0]".a.range = [ 42, 42 ] +[random."method:h"] +"arg:0".a.range = [ 42, 42 ] b.range = [ 0, 1 ] [random.profile.record] diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index 9c80c45e..c5147a89 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -75,7 +75,7 @@ enum Command { #[clap(flatten)] annotate: TypeAnnotation, #[clap(short, long, conflicts_with("file"))] - /// Specifies random value generation config in Dhall syntax + /// Specifies random value generation config in TOML syntax config: Option, #[clap(short, long)] /// Load random value generation config from file @@ -308,7 +308,7 @@ fn main() -> Result<()> { file, args, } => { - use candid_parser::configs::Configs; + use candid_parser::configs::{Configs, Scope, ScopePos}; use rand::Rng; use std::str::FromStr; let (env, types) = if args.is_some() { @@ -326,11 +326,6 @@ fn main() -> Result<()> { } _ => unreachable!(), }; - let config = if let Some(ref method) = annotate.method { - config.with_method(method) - } else { - 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)?; @@ -340,7 +335,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().and_then(|method| { + let position = Some(if args.is_some() { + ScopePos::Ret + } else { + ScopePos::Arg + }); + Some(Scope { position, method }) + }); + let args = candid_parser::random::any(&seed, config, &env, &types, &scope)?; match lang.as_str() { "did" => println!("{args}"), "js" => println!( From d5a0b77715bedfe990016a025d5c75800c86d22f Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 17 Apr 2024 21:34:55 -0700 Subject: [PATCH 10/14] test --- rust/candid_parser/src/configs.rs | 51 +++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index c6ff7d8f..729fc214 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -115,7 +115,7 @@ impl ConfigTree { let len = path.len(); let start = len.saturating_sub(self.max_depth as usize); for i in (start..len).rev() { - let tail = &path[i..]; + let (path, tail) = path.split_at(i); match self.match_exact_path(tail) { Some(v) => return Some((v, is_repeated(path, tail))), None => continue, @@ -243,14 +243,17 @@ fn parse() { text: Option, } impl ConfigState for T { - fn merge_config(&mut self, _config: &Self, _is_recursive: bool) { - unimplemented!() + fn merge_config(&mut self, config: &Self, is_recursive: bool) { + *self = config.clone(); + if is_recursive { + self.size = Some(0); + } } fn update_state(&mut self, _elem: &StateElem) { - unimplemented!() + self.size = self.size.map(|s| s + 1); } fn restore_state(&mut self, _elem: &StateElem) { - unimplemented!() + self.size = self.size.map(|s| s - 1); } } let toml = r#" @@ -260,14 +263,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 tree: ConfigTree = ConfigTree::from_configs("random", configs).unwrap(); assert_eq!(tree.state, None); - assert_eq!(tree.subtree.len(), 5); + 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 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)); } From 89664137ece4e662f126ca1c98f43a35e618c804 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 17 Apr 2024 21:54:18 -0700 Subject: [PATCH 11/14] fix --- rust/candid/src/pretty/candid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/candid/src/pretty/candid.rs b/rust/candid/src/pretty/candid.rs index 60aa1c89..c012da9d 100644 --- a/rust/candid/src/pretty/candid.rs +++ b/rust/candid/src/pretty/candid.rs @@ -120,7 +120,7 @@ pub fn pp_ty_inner(ty: &TypeInner) -> RcDoc { _ => unreachable!(), } } - Knot(ref id) => str(id.name), + Knot(ref id) => RcDoc::text(format!("{id}")), Unknown => str("unknown"), Future => str("future"), } From 05b87af2cdca215f0d8c0ecafe0e675874f4b357 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 17 Apr 2024 22:19:43 -0700 Subject: [PATCH 12/14] fix --- tools/didc/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index c5147a89..f770bf01 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -335,13 +335,13 @@ fn main() -> Result<()> { let mut rng = rand::thread_rng(); (0..2048).map(|_| rng.gen::()).collect() }; - let scope = annotate.method.as_ref().and_then(|method| { + let scope = annotate.method.as_ref().map(|method| { let position = Some(if args.is_some() { ScopePos::Ret } else { ScopePos::Arg }); - Some(Scope { position, method }) + Scope { position, method } }); let args = candid_parser::random::any(&seed, config, &env, &types, &scope)?; match lang.as_str() { From 49d62b36a5b691e1a4b24bafeddf9a99bc6b4e51 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 3 May 2024 09:37:50 -0700 Subject: [PATCH 13/14] 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 --- Cargo.lock | 66 ++ rust/candid/src/ser.rs | 8 +- rust/candid/src/types/mod.rs | 8 +- rust/candid_parser/Cargo.toml | 8 +- 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 | 123 ++- rust/candid_parser/src/error.rs | 2 - rust/candid_parser/src/lib.rs | 2 - rust/candid_parser/src/random.rs | 16 +- 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/src/main.rs | 52 +- 28 files changed, 1007 insertions(+), 656 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 diff --git a/Cargo.lock b/Cargo.lock index dc81f332..c879abe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,6 +232,7 @@ dependencies = [ "dialoguer", "fake", "goldenfile", + "handlebars", "hex", "lalrpop", "lalrpop-util", @@ -563,6 +564,20 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[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" @@ -831,6 +846,51 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pest" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2 1.0.79", + "quote 1.0.35", + "syn 2.0.53", +] + +[[package]] +name = "pest_meta" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -1362,6 +1422,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" 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 06d8c87f..718aa119 100644 --- a/rust/candid_parser/Cargo.toml +++ b/rust/candid_parser/Cargo.toml @@ -26,17 +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 } -toml = { version = "0.8", default-features = false, features = ["parse"], 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 } @@ -47,8 +48,7 @@ test-generator = "0.3.0" rand.workspace = true [features] -configs = ["toml"] -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 729fc214..c711e4fd 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -6,19 +6,23 @@ use toml::{Table, Value}; pub struct State<'a, T: ConfigState> { tree: &'a ConfigTree, - path: Vec, 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, @@ -28,7 +32,7 @@ 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, false); + config.merge_config(state, None, false); } Self { tree, @@ -52,6 +56,9 @@ impl<'a, T: ConfigState> State<'a, T> { 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, } @@ -71,7 +78,12 @@ impl<'a, T: ConfigState> State<'a, T> { self.tree.get_config(&self.path) }; if let Some((state, is_recursive)) = new_state { - self.config.merge_config(state, is_recursive); + 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 } @@ -82,10 +94,13 @@ impl<'a, T: ConfigState> State<'a, T> { } } -pub trait ConfigState: DeserializeOwned + Default + Clone { - fn merge_config(&mut self, config: &Self, 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); 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 { @@ -111,8 +126,48 @@ impl ConfigTree { } 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 { + 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(), + } + } + 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 { + tree.subtree.insert(path[i].clone(), node); + tree.max_depth = std::cmp::max(d, tree.max_depth); + } + } 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); @@ -146,6 +201,7 @@ impl<'a> std::fmt::Display for StateElem<'a> { match self { StateElem::Type(t) => write!(f, "{}", path_name(t)), StateElem::Label(l) => write!(f, "{}", l), + StateElem::TypeStr(s) => write!(f, "{}", s), } } } @@ -222,6 +278,7 @@ pub fn path_name(t: &Type) -> String { 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", @@ -243,7 +300,7 @@ fn parse() { text: Option, } impl ConfigState for T { - fn merge_config(&mut self, config: &Self, is_recursive: bool) { + fn merge_config(&mut self, config: &Self, _elem: Option<&StateElem>, is_recursive: bool) { *self = config.clone(); if is_recursive { self.size = Some(0); @@ -267,7 +324,7 @@ Vec = { width = 2, size = 10 } "method:f".list = { depth = 3, size = 30 } "#; let configs = toml.parse::().unwrap(); - let tree: ConfigTree = ConfigTree::from_configs("random", configs).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); @@ -275,6 +332,58 @@ Vec = { width = 2, size = 10 } 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( diff --git a/rust/candid_parser/src/error.rs b/rust/candid_parser/src/error.rs index c88f4718..75b46e3e 100644 --- a/rust/candid_parser/src/error.rs +++ b/rust/candid_parser/src/error.rs @@ -99,8 +99,6 @@ impl From for Error { } } -#[cfg_attr(docsrs, doc(cfg(feature = "configs")))] -#[cfg(feature = "configs")] 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 e62989b8..0fdc81bf 100644 --- a/rust/candid_parser/src/random.rs +++ b/rust/candid_parser/src/random.rs @@ -32,14 +32,14 @@ impl Default for GenConfig { } } impl ConfigState for GenConfig { - fn merge_config(&mut self, config: &Self, is_recursive: bool) { + 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 = config.text.clone(); + self.text.clone_from(&config.text); } self.width = config.width.or(self.width); if config.value.is_some() { - self.value = config.value.clone(); + self.value.clone_from(&config.value); } if !is_recursive { self.depth = config.depth.or(self.depth); @@ -61,6 +61,16 @@ impl ConfigState for GenConfig { } } } + fn unmatched_config() -> Self { + GenConfig { + range: None, + text: None, + width: None, + value: None, + depth: None, + size: None, + } + } } pub struct RandState<'a>(State<'a, GenConfig>); 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/src/main.rs b/tools/didc/src/main.rs index f770bf01..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"))] + #[clap(short, long)] /// Specifies random value generation config in TOML syntax config: Option, - #[clap(short, long)] - /// Load random value generation config from file - file: 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,27 +322,16 @@ fn main() -> Result<()> { annotate, lang, config, - file, args, } => { - use candid_parser::configs::{Configs, Scope, ScopePos}; + use candid_parser::configs::{Scope, ScopePos}; use rand::Rng; - use std::str::FromStr; 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_str("")?, - (Some(str), None) => Configs::from_str(&str)?, - (None, Some(file)) => { - let content = std::fs::read_to_string(&file) - .map_err(|_| Error::msg(format!("could not read {file}")))?; - Configs::from_str(&content)? - } - _ => unreachable!(), - }; + 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)?; From da4f9c8a61e240bf6fef188ea4e0d04f27750d62 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 3 May 2024 10:34:53 -0700 Subject: [PATCH 14/14] changelog and bump version --- Cargo.lock | 394 +++++++++++++++------------------- Changelog.md | 20 +- rust/candid/Cargo.toml | 2 +- rust/candid_parser/Cargo.toml | 2 +- tools/didc/Cargo.toml | 2 +- 5 files changed, 194 insertions(+), 226 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c879abe3..a076a7af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,47 +13,48 @@ dependencies = [ [[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", @@ -61,9 +62,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "arbitrary" @@ -88,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" @@ -125,8 +126,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" dependencies = [ "either", - "proc-macro2 1.0.79", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -145,12 +146,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" @@ -185,7 +180,7 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "candid" -version = "0.10.7" +version = "0.10.8" dependencies = [ "anyhow", "bincode", @@ -213,14 +208,14 @@ name = "candid_derive" version = "0.6.6" dependencies = [ "lazy_static", - "proc-macro2 1.0.79", - "quote 1.0.35", - "syn 2.0.53", + "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", @@ -249,9 +244,9 @@ dependencies = [ [[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" @@ -267,9 +262,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "clap" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -289,14 +284,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", - "proc-macro2 1.0.79", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -317,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" @@ -389,15 +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" +checksum = "322ef0094744e63628e6f0eb2295517f79276a5b342a4c2ff3042566ca181d4e" [[package]] name = "dialoguer" @@ -413,7 +408,7 @@ dependencies = [ [[package]] name = "didc" -version = "0.3.7" +version = "0.4.0" dependencies = [ "anyhow", "candid_parser", @@ -456,9 +451,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "ena" @@ -503,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" @@ -531,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", @@ -548,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", @@ -580,9 +575,9 @@ dependencies = [ [[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" @@ -620,14 +615,20 @@ checksum = "7a46645bbd70538861a90d0f26c31537cdf1e44aae99a794fb75a664b70951bc" [[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", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.11.0" @@ -639,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" @@ -657,7 +658,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", "string_cache", "term", "tiny-keccak", @@ -688,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.5.0", + "bitflags", "libc", - "redox_syscall", ] [[package]] @@ -711,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", @@ -742,10 +742,10 @@ checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" dependencies = [ "beef", "fnv", - "proc-macro2 1.0.79", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "regex-syntax 0.6.29", - "syn 2.0.53", + "syn 2.0.60", ] [[package]] @@ -759,9 +759,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "new_debug_unreachable" @@ -775,7 +775,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.5.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -819,9 +819,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", @@ -829,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]] @@ -848,9 +848,9 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pest" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", "thiserror", @@ -859,9 +859,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ "pest", "pest_generator", @@ -869,22 +869,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.79", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "pest_meta" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ "once_cell", "pest", @@ -956,9 +956,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -983,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.79", + "proc-macro2 1.0.81", ] [[package]] @@ -1022,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", @@ -1042,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]] @@ -1066,7 +1066,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -1077,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.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1096,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" @@ -1123,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", ] @@ -1151,20 +1151,20 @@ 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.79", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -1208,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", @@ -1266,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" @@ -1287,19 +1287,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.79", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.53" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ - "proc-macro2 1.0.79", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "unicode-ident", ] @@ -1349,22 +1349,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ - "proc-macro2 1.0.79", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -1399,9 +1399,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.9" +version = "0.22.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" dependencies = [ "indexmap", "serde", @@ -1442,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" @@ -1504,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]] @@ -1523,128 +1523,78 @@ 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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" - -[[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 = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" dependencies = [ "memchr", ] 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_parser/Cargo.toml b/rust/candid_parser/Cargo.toml index 718aa119..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"] 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"