From b5316f98b022df2c9180b5c01d9511243f4ecf09 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 27 Oct 2023 16:37:12 -0700 Subject: [PATCH] Remove candid dependencies (#485) * remove num_enum * clean up parser dependencies * checkpoint * value feature * remove codespan * fix * fix * pretty * remove mute_warning * fix * pretty refactor * fix * reexport candid in parser * fix * fix * fix * bignum feature * bump candid_derive * silence subtyping in decoder * fix service_equal error reporting (#486) * add IDLValue::Blob * builder for config * fix * fix --- .github/workflows/bench.yml | 2 +- .github/workflows/rust.yml | 8 +- Cargo.lock | 176 ++++++------------ Cargo.toml | 9 + Changelog.md | 17 +- rust/candid/Cargo.toml | 55 ++++-- rust/candid/src/de.rs | 101 +++++++--- rust/candid/src/error.rs | 41 +++- rust/candid/src/lib.rs | 32 +++- .../{pretty_printer.rs => pretty/candid.rs} | 31 ++- rust/candid/src/pretty/mod.rs | 4 + .../candid/src/{pretty.rs => pretty/utils.rs} | 0 rust/candid/src/ser.rs | 13 ++ rust/candid/src/types/arc.rs | 3 +- rust/candid/src/types/impls.rs | 8 +- rust/candid/src/types/internal.rs | 66 +++++-- rust/candid/src/types/leb128.rs | 100 ++++++++++ rust/candid/src/types/mod.rs | 10 + rust/candid/src/types/number.rs | 16 +- rust/candid/src/types/rc.rs | 3 +- rust/candid/src/types/subtype.rs | 104 ++++++++--- rust/candid/src/types/value.rs | 19 +- rust/candid/src/utils.rs | 14 ++ rust/candid/tests/number.rs | 13 ++ rust/candid/tests/serde.rs | 2 + rust/candid_derive/Cargo.toml | 2 +- rust/candid_derive/src/func.rs | 2 +- rust/candid_parser/Cargo.toml | 24 +-- rust/candid_parser/src/bindings/javascript.rs | 15 +- rust/candid_parser/src/bindings/motoko.rs | 4 +- rust/candid_parser/src/bindings/rust.rs | 40 +++- rust/candid_parser/src/bindings/typescript.rs | 2 +- rust/candid_parser/src/grammar.lalrpop | 5 +- rust/candid_parser/src/lib.rs | 5 + rust/candid_parser/tests/parse_type.rs | 6 +- tools/didc/Cargo.toml | 1 - tools/didc/src/main.rs | 19 +- 37 files changed, 666 insertions(+), 306 deletions(-) rename rust/candid/src/{pretty_printer.rs => pretty/candid.rs} (94%) create mode 100644 rust/candid/src/pretty/mod.rs rename rust/candid/src/{pretty.rs => pretty/utils.rs} (100%) create mode 100644 rust/candid/src/types/leb128.rs diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index ea2101ec..c9b3bb0e 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -2,7 +2,7 @@ name: Rust Bench on: pull_request: paths: - - 'rust/**' + - 'rust/candid/**' jobs: runBenchMark: name: run benchmark diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b50037a8..9f21e218 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -26,9 +26,13 @@ jobs: target key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Build - run: cargo build + run: | + cargo build - name: Run tests - run: cargo test --features all + run: | + cargo test --no-default-features + cargo test + cargo test --features all - name: fmt run: cargo fmt -v -- --check - name: lint diff --git a/Cargo.lock b/Cargo.lock index 8b07d2e9..9a9cfa8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,7 +138,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -264,14 +264,12 @@ dependencies = [ "binread", "byteorder", "candid_derive", - "codespan-reporting", "criterion", "hex", "ic_principal", "leb128", "num-bigint", "num-traits", - "num_enum", "paste", "pretty 0.12.3", "rand", @@ -285,7 +283,7 @@ dependencies = [ [[package]] name = "candid_derive" -version = "0.6.4" +version = "0.6.5" dependencies = [ "lazy_static", "proc-macro2 1.0.69", @@ -313,10 +311,7 @@ dependencies = [ "pretty 0.12.3", "rand", "serde", - "serde_bytes", "serde_dhall", - "sha2 0.10.8", - "stacker", "test-generator", "thiserror", ] @@ -383,9 +378,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", @@ -393,21 +388,21 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", - "clap_lex 0.5.1", + "clap_lex 0.6.0", "strsim", ] [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2 1.0.69", @@ -426,9 +421,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "codespan-reporting" @@ -576,6 +571,12 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +[[package]] +name = "deunicode" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1abaf4d861455be59f64fd2b55606cb151fce304ede7165f410243ce96bde6" + [[package]] name = "dhall" version = "0.11.1" @@ -617,14 +618,19 @@ name = "didc" version = "0.3.5" dependencies = [ "anyhow", - "candid", "candid_parser", - "clap 4.4.6", + "clap 4.4.7", "hex", "pretty-hex", "rand", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.9.0" @@ -719,12 +725,12 @@ dependencies = [ [[package]] name = "fake" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af7b0c58ac9d03169e27f080616ce9f64004edca3d2ef4147a811c21b23b319" +checksum = "26221445034074d46b276e13eb97a265ebdb8ed8da705c4dddd3dd20b66b45d2" dependencies = [ + "deunicode", "rand", - "unidecode", ] [[package]] @@ -824,6 +830,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + [[package]] name = "hex" version = "0.4.3" @@ -893,28 +905,30 @@ dependencies = [ ] [[package]] -name = "itertools" -version = "0.9.0" +name = "is-terminal" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "either", + "hermit-abi 0.3.3", + "rustix", + "windows-sys 0.48.0", ] [[package]] name = "itertools" -version = "0.10.5" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.11.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] @@ -936,14 +950,16 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.20.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83be602e051ada38d90c7841092adabeb585197afe9dabb20e4f8375cc87846e" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" dependencies = [ "ascii-canvas", "bit-set", + "diff", "ena", - "itertools 0.11.0", + "is-terminal", + "itertools 0.10.5", "lalrpop-util", "petgraph", "pico-args", @@ -957,11 +973,11 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.20.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365d88f9d803538a06641e6736f21d95ecf9226dc1693421212e62c405cdd199" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" dependencies = [ - "regex-automata 0.3.9", + "regex", ] [[package]] @@ -1104,27 +1120,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_enum" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" -dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.38", -] - [[package]] name = "once_cell" version = "1.18.0" @@ -1186,9 +1181,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" dependencies = [ "memchr", "thiserror", @@ -1219,9 +1214,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" dependencies = [ "pest", "pest_generator", @@ -1229,9 +1224,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" dependencies = [ "pest", "pest_meta", @@ -1242,9 +1237,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" dependencies = [ "once_cell", "pest", @@ -1345,16 +1340,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit", -] - [[package]] name = "proc-macro2" version = "0.4.30" @@ -1506,17 +1491,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -[[package]] -name = "regex-automata" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.7.5", -] - [[package]] name = "regex-automata" version = "0.4.3" @@ -1890,23 +1864,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.0.2", - "toml_datetime", - "winnow", -] - [[package]] name = "typed-arena" version = "2.0.2" @@ -1970,12 +1927,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "unidecode" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" - [[package]] name = "url" version = "2.4.1" @@ -2241,12 +2192,3 @@ name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "winnow" -version = "0.5.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" -dependencies = [ - "memchr", -] diff --git a/Cargo.toml b/Cargo.toml index eecbc858..10bfdee8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,12 @@ members = [ ] resolver = "2" +[workspace.dependencies] +hex = "0.4.3" +num-bigint = { version = "0.4", features = ["serde"] } +num-traits = "0.2" +pretty = "0.12" +serde = { version = "1.0", features = ["derive"] } +thiserror = "1.0" +anyhow = "1.0" +rand = "0.8" diff --git a/Changelog.md b/Changelog.md index 1d02bc51..cc7b8b34 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,14 +3,29 @@ ## Rust 0.10.0 +### Breaking changes + * The original `candid` crate is split into three crates: * `candid`: mainly for Candid data (de-)serialization. - + `candid::bindings::candid` becomes `candid::pretty_printer`. + + `candid::bindings::candid` moves to `candid::pretty::candid`. `candid::pretty` moves to `candid::pretty::utils`. These modules are only available under feature flag `printer` (enabled by default). + + `candid::{Int, Nat}` is only available under feature flag `bignum` (enabled by default). If this feature is not enabled, you can use `i128/u128` for `int/nat` type. + + Add `IDLValue::Blob(Vec)` enum for efficient handling of blob value. + + `candid::types::number::pp_num_str` moves to `candid::utils::pp_num_str`. + + `candid::types::value` module is only availble under feature flag `value`. + + `mute_warning` feature flag is removed, use `candid::types::subtype_with_config` instead. * `candid_parser`: used to be the `parser` and `bindings` module in `candid` crate. + Remove `FromStr` trait for `IDLArgs` and `IDLValue`. Use `parse_idl_args` and `parse_idl_value` respectively instead. + `TypeEnv.ast_to_type` becomes `candid_parser::typing::ast_to_type`. + + `bindings::rust::Config` uses builder pattern. + + `candid` is re-exported in `candid_parser::candid`. + + `candid::*` is re-exported in `candid_parser`. * `ic_principal`: only for `Principal` and `PrincipalError`. +### Non-breaking changes + +* Add `candid::types::subtype_with_config` to control the error reporting level of special opt rule. +* Add `Type.is_blob(env)` method to check if a type is a blob type. + ## Rust 0.9.9 -- 0.9.11 * Set different config values for `full_error_message` and `zero_sized_values` for Wasm and non-Wasm target. diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index ffb2a6b8..3f8571d8 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -14,28 +14,27 @@ keywords = ["internet-computer", "idl", "candid", "dfinity"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] -byteorder = "1.4.3" -candid_derive = { path = "../candid_derive", version = "=0.6.4" } -codespan-reporting = "0.11" -hex = "0.4.2" +candid_derive = { path = "../candid_derive", version = "=0.6.5" } ic_principal = { path = "../ic_principal", version = "0.1.0" } -leb128 = "0.2.4" -num_enum = "0.6.1" -num-bigint = { version = "0.4.2", features = ["serde"] } -num-traits = "0.2.12" -paste = "1.0.0" -pretty = "0.12.0" -serde = { version = "1.0.118", features = ["derive"] } -serde_bytes = "0.11" -thiserror = "1.0.20" -anyhow = "1.0" binread = { version = "2.1", features = ["debug_template"] } +byteorder = "1.5.0" +leb128 = "0.2.5" +paste = "1.0" +hex.workspace = true +serde.workspace = true +thiserror.workspace = true +anyhow.workspace = true + +serde_bytes = { version = "0.11", optional = true } +pretty = { workspace = true, optional = true } +num-bigint = { workspace = true, optional = true } +num-traits = { workspace = true, optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] stacker = "0.1" [dev-dependencies] -rand = "0.8" +rand.workspace = true criterion = "0.4" serde_cbor = "0.11.2" serde_json = "1.0.74" @@ -47,4 +46,28 @@ harness = false path = "benches/benchmark.rs" [features] -mute_warnings = [] +bignum = ["num-bigint", "num-traits"] +value = ["bignum"] +printer = ["pretty"] +default = ["serde_bytes", "printer", "bignum"] +all = ["default", "value"] + +[[test]] +name = "types" +path = "tests/types.rs" +required-features = ["value"] +[[test]] +name = "serde" +path = "tests/serde.rs" +required-features = ["bignum"] +[[test]] +name = "number" +path = "tests/number.rs" +required-features = ["bignum"] + +# docs.rs-specific configuration +# To test locally: RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --features all +[package.metadata.docs.rs] +features = ["all"] +# defines the configuration attribute `docsrs` +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rust/candid/src/de.rs b/rust/candid/src/de.rs index 036440c6..1df200e0 100644 --- a/rust/candid/src/de.rs +++ b/rust/candid/src/de.rs @@ -4,11 +4,13 @@ use super::{ error::{Error, Result}, types::internal::{text_size, type_of, TypeId}, types::{Field, Label, SharedLabel, Type, TypeEnv, TypeInner}, - CandidType, Int, Nat, + CandidType, }; +#[cfg(feature = "bignum")] +use super::{Int, Nat}; use crate::{ binary_parser::{BoolValue, Header, Len, PrincipalBytes}, - types::subtype::{subtype, Gamma}, + types::subtype::{subtype_with_config, Gamma, OptReport}, }; use anyhow::{anyhow, Context}; use binread::BinRead; @@ -56,6 +58,8 @@ impl<'de> IDLDeserialize<'de> { self.de.is_untyped = false; self.deserialize_with_type(T::ty()) } + #[cfg_attr(docsrs, doc(cfg(feature = "value")))] + #[cfg(feature = "value")] pub fn get_value_with_type( &mut self, env: &TypeEnv, @@ -136,8 +140,29 @@ impl<'de> IDLDeserialize<'de> { } pub struct Config { - pub zero_sized_values: usize, - pub full_error_message: bool, + zero_sized_values: usize, + full_error_message: bool, +} +impl Config { + pub fn new() -> Self { + Self { + zero_sized_values: 2_000_000, + full_error_message: true, + } + } + pub fn set_zero_sized_values(&mut self, n: usize) -> &mut Self { + self.zero_sized_values = n; + self + } + pub fn set_full_error_message(&mut self, n: bool) -> &mut Self { + self.full_error_message = n; + self + } +} +impl Default for Config { + fn default() -> Self { + Self::new() + } } macro_rules! assert { @@ -273,7 +298,8 @@ impl<'de> Deserializer<'de> { Ok(res) } fn check_subtype(&mut self) -> Result<()> { - subtype( + subtype_with_config( + OptReport::Silence, &mut self.gamma, &self.table, &self.wire_type, @@ -332,9 +358,11 @@ impl<'de> Deserializer<'de> { // Customize deserailization methods // Several deserialize functions will call visit_byte_buf. // We reserve the first byte to be a tag to distinguish between different callers: - // int(0), nat(1), principal(2), reserved(3), service(4), function(5) + // int(0), nat(1), principal(2), reserved(3), service(4), function(5), blob(6) // This is necessary for deserializing IDLValue because // it has only one visitor and we need a way to know who called the visitor. + #[cfg_attr(docsrs, doc(cfg(feature = "bignum")))] + #[cfg(feature = "bignum")] fn deserialize_int<'a, V>(&'a mut self, visitor: V) -> Result where V: Visitor<'de>, @@ -354,6 +382,8 @@ impl<'de> Deserializer<'de> { bytes.extend_from_slice(&int.0.to_signed_bytes_le()); visitor.visit_byte_buf(bytes) } + #[cfg_attr(docsrs, doc(cfg(feature = "bignum")))] + #[cfg(feature = "bignum")] fn deserialize_nat<'a, V>(&'a mut self, visitor: V) -> Result where V: Visitor<'de>, @@ -419,6 +449,22 @@ impl<'de> Deserializer<'de> { bytes.extend_from_slice(&id); visitor.visit_byte_buf(bytes) } + fn deserialize_blob<'a, V>(&'a mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.unroll_type()?; + check!( + self.expect_type.is_blob(&self.table) && self.wire_type.is_blob(&self.table), + "blob" + ); + let len = Len::read(&mut self.input)?.0; + let blob = self.borrow_bytes(len)?; + let mut bytes = Vec::with_capacity(len + 1); + bytes.push(6u8); + bytes.extend_from_slice(blob); + visitor.visit_byte_buf(bytes) + } fn deserialize_empty<'a, V>(&'a mut self, _visitor: V) -> Result where V: Visitor<'de>, @@ -449,14 +495,19 @@ impl<'de> Deserializer<'de> { { use de::Deserializer; let tid = type_of(&visitor); - if tid != TypeId::of::() // derive Copy - && tid != TypeId::of::() // derive Copy + if tid != TypeId::of::() // derive Copy // OptionVisitor doesn't derive Copy, but has only PhantomData. // OptionVisitor is private and we cannot get TypeId of OptionVisitor, // we also cannot downcast V to concrete type, because of 'de // The only option left seems to be type_name, but it is not guaranteed to be stable, so there is risk here. && !tid.name.starts_with("serde::de::impls::OptionVisitor<") { + #[cfg(feature = "value")] + if tid != TypeId::of::() { + // derive Copy + panic!("Not a valid visitor: {tid:?}"); + } + #[cfg(not(feature = "value"))] panic!("Not a valid visitor: {tid:?}"); } // This is safe, because the visitor either impl Copy or is zero sized @@ -501,8 +552,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { } self.unroll_type()?; match self.expect_type.as_ref() { + #[cfg(feature = "bignum")] TypeInner::Int => self.deserialize_int(visitor), + #[cfg(not(feature = "bignum"))] + TypeInner::Int => self.deserialize_i128(visitor), + #[cfg(feature = "bignum")] TypeInner::Nat => self.deserialize_nat(visitor), + #[cfg(not(feature = "bignum"))] + TypeInner::Nat => self.deserialize_u128(visitor), TypeInner::Nat8 => self.deserialize_u8(visitor), TypeInner::Nat16 => self.deserialize_u16(visitor), TypeInner::Nat32 => self.deserialize_u32(visitor), @@ -526,6 +583,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { TypeInner::Principal => self.deserialize_principal(visitor), // construct types TypeInner::Opt(_) => self.deserialize_option(visitor), + // This is an optimization for blob, mostly likely used by IDLValue, but it won't help the native Vec + TypeInner::Vec(_) if self.expect_type.is_blob(&self.table) => { + self.deserialize_blob(visitor) + } TypeInner::Vec(_) => self.deserialize_seq(visitor), TypeInner::Record(_) => self.deserialize_struct("_", &[], visitor), TypeInner::Variant(_) => self.deserialize_enum("_", &[], visitor), @@ -564,22 +625,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - use num_traits::ToPrimitive; + use crate::types::leb128::{decode_int, decode_nat}; self.unroll_type()?; assert!(*self.expect_type == TypeInner::Int); let value: i128 = match self.wire_type.as_ref() { - TypeInner::Int => { - let int = Int::decode(&mut self.input).map_err(Error::msg)?; - int.0 - .to_i128() - .ok_or_else(|| Error::msg("Cannot convert int to i128"))? - } - TypeInner::Nat => { - let nat = Nat::decode(&mut self.input).map_err(Error::msg)?; - nat.0 - .to_i128() - .ok_or_else(|| Error::msg("Cannot convert nat to i128"))? - } + TypeInner::Int => decode_int(&mut self.input)?, + TypeInner::Nat => i128::try_from(decode_nat(&mut self.input)?) + .map_err(|_| Error::msg("Cannot convert nat to i128"))?, t => return Err(Error::subtype(format!("{t} cannot be deserialized to int"))), }; visitor.visit_i128(value) @@ -588,17 +640,12 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - use num_traits::ToPrimitive; self.unroll_type()?; check!( *self.expect_type == TypeInner::Nat && *self.wire_type == TypeInner::Nat, "nat" ); - let nat = Nat::decode(&mut self.input).map_err(Error::msg)?; - let value = nat - .0 - .to_u128() - .ok_or_else(|| Error::msg("Cannot convert nat to u128"))?; + let value = crate::types::leb128::decode_nat(&mut self.input)?; visitor.visit_u128(value) } fn deserialize_unit(self, visitor: V) -> Result diff --git a/rust/candid/src/error.rs b/rust/candid/src/error.rs index 095b8208..db663896 100644 --- a/rust/candid/src/error.rs +++ b/rust/candid/src/error.rs @@ -1,16 +1,21 @@ //! `candid::Result = Result>` -use codespan_reporting::diagnostic::Label; use serde::{de, ser}; use std::{io, num::ParseIntError}; use thiserror::Error; pub type Result = std::result::Result; +#[derive(Debug)] +pub struct Label { + range: std::ops::Range, + message: String, +} + #[derive(Debug, Error)] pub enum Error { #[error("binary parser error: {}", .0.get(0).map(|f| format!("{} at byte offset {}", f.message, f.range.start/2)).unwrap_or_else(|| "io error".to_string()))] - Binread(Vec>), + Binread(Vec