Merge/master into next#740
Draft
raymondk wants to merge 44 commits into
Draft
Conversation
GItHub releases will include prebuilt `candid_ui.wasm` so that tools like `icp-cli` can integrate. A test release can be found [here](https://github.com/dfinity/candid/releases/tag/test_release_candid_ui_2).
**Overview** Cherry-pick of dfinity/icp-js-bindgen#102.
Changed imports generated by `candid_parser::bindings::typescript::compile` from `@dfinity/*` to `@icp-sdk/core/*`
We use rangemap in ic-agent for canister ranges. It has a feature to implement the required trait even if the upstream type doesn't, but it blocks implementing Debug and a couple other annoyances so it'd be nice for ic_principal to implement it directly.
Co-authored-by: Linwei Shang <linwei.shang@dfinity.org>
# Summary - Use `target_family = "wasm"` for platform detection to cover both wasm32 and wasm64; skip recursion check on wasm (sandboxed), use stack-based check on native platforms and a conservative depth limit on other niche platforms - Apply recursion guard to all recursive functions on deserialization path: type environment operations (`TypeEnv::is_empty`, `trace_type`, `rec_find_type`, `as_func`, `as_service`), value type annotation (`IDLValue::annotate_type`), and subtype checking (`subtype_()`, `equal()`) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Unblocks #702 --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This makes the `BoundedVec` type, thus far used in the [management canister types](https://sourcegraph.com/github.com/dfinity/ic/-/blob/rs/types/management_canister_types/src/bounded_vec.rs?L14), available for public use. --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org>
### Solution - Add `TypeDoc`, `FieldDoc`, and `TypeDocs` types to carry doc metadata alongside the type graph - Extend `CandidType` derive to extract Rust doc comments via new `_ty_doc()` hook; store per-TypeId in thread-local DOC_ENV - Update pretty-printer to render docs above type definitions, record fields, and variant members ### Details - Docs flow through `TypeContainer` which maps Rust TypeId docs to final Candid export names - Tuples with field docs fall back to explicit numeric field syntax ### Meta - This is needed for my work on Immutable Object Storage. I currently have some hacks to add doc comments to .did files, but everyone would benefit if this was fixed properly. --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
**Overview** Performance improvement **Requirements** Preserve existing wire compatibility and keep record decoding behavior unchanged. **Solution** Encode and decode Nat and Int values through native LEB128 when they fit in machine integers so common small numbers avoid bigint work. **Considerations** I expect performance improvement and full forward and backward compatibility Ref. #710 --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
**Overview** Reduce per-record allocation churn during Candid record decoding. **Requirements** Preserve existing wire compatibility and keep record decoding behavior unchanged. **Solution** Track expected and wire record fields by type plus index instead of cloning field queues for each decoded record. Add a compatibility test covering backward and forward compatible record vectors. **Considerations** This keeps the wire format unchanged and is intended to remain fully compatible with existing Candid data. Series-level benchmark context is tracked in #710. --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
**Overview** Reduce repeated per-element type work when decoding primitive vectors. **Requirements** Preserve vector decoding semantics, including compatibility with extra trailing arguments. **Solution** Add an exact-primitive fast path for vector elements so deserialization can skip repeated type unrolling and checks when expected and wire element types already match. Add a compatibility test covering extra-args behavior. **Considerations** The optimization is limited to exact primitive matches and leaves the general decode path unchanged. Series-level benchmark context is tracked in #710. --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
**Overview** Reduce parser work on tokenizer paths that do not capture trivia. **Requirements** Keep comment and doc-comment behavior unchanged when trivia capture is enabled. **Solution** Skip comment and line-tracking bookkeeping when the tokenizer runs without trivia capture. This trims successful DID and argument parsing on the hot path without changing the trivia-enabled path. **Considerations** Parser behavior with trivia capture is unchanged, and the parser test suite still passes. Series-level benchmark context is tracked in #710. Co-authored-by: Linwei Shang <linwei.shang@dfinity.org>
**Overview** Reduce duplicate whole-file work during DID typechecking. **Requirements** Preserve parser validation semantics while improving large DID load performance. **Solution** Validate deferred parser semantics from the built type environment instead of rebuilding every declaration a second time in `check_decs`. **Considerations** This keeps the validation flow intact while removing redundant reconstruction work, and the parser test suite still passes. Series-level benchmark context is tracked in #710. Co-authored-by: Linwei Shang <linwei.shang@dfinity.org>
## Summary On little-endian targets (including wasm32), `Vec<i16/u32/f64/etc.>` encoding now writes the backing memory directly instead of iterating element-by-element through the Serializer trait. - Added `try_write_raw_elements` default method to `Compound` trait - `ValueSerializer::Compound` implements it with direct byte write - `[T]::idl_serialize` detects fixed-width primitives via `TypeId` on `#[cfg(target_endian = "little")]` - `Vec<T>` and `[T; N]` delegate to the optimized slice path - Excludes `usize`/`isize` (platform-dependent size) ## Benchmark (canbench, wasm32) | Metric | Before | After | Change | |--------|--------|-------|--------| | vec_int16 Encoding | 123.7M inst | 8.4M inst | **14.7x faster (-93.2%)** | | vec_int16 Total | 817.9M inst | 704.7M inst | -13.8% | No regressions on any of the 9 benchmarks. ## Compatibility Wire format is **unchanged** — produces byte-identical output. Round-trip compatibility test added. Relates to #710 --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary Pre-compute the total decoding cost for primitive vectors at the vector level instead of calling `add_cost` per element. Also sets `primitive_vec_fast_path` once before `visit_seq` rather than saving and restoring it on every element. - Added `primitive_byte_cost` helper - Pre-computed `len * (3 + byte_cost)` in `deserialize_seq` for primitive vectors - Removed per-element `add_cost` from `primitive_impl!` and `deserialize_bool` fast paths - Moved `add_cost(3)` into non-primitive branch in `next_element_seed` ## Benchmark (canbench, wasm32) | Metric | Before | After | Change | |--------|--------|-------|--------| | vec_int16 Decoding | 694.2M inst | 409.0M inst | **41.1% faster** | | vec_int16 Total | 817.9M inst | 532.7M inst | -34.9% | No regressions on any of the 9 benchmarks. ## Compatibility Wire format and cost accounting semantics are **unchanged**. The total cost charged is identical — it's just computed once upfront instead of incrementally. Relates to #710
## Summary Decode SLEB128-encoded `Int` values into `i64` first, only falling back to `BigInt` for values that exceed 64-bit range. Mirrors the existing `Nat::decode` fast path from an earlier commit in this series. - Fast path: accumulates SLEB128 bytes into `i64` with proper sign extension - Fallback: converts accumulated `i64` to `BigInt` and continues with `BigInt` arithmetic - Most real-world `Int` values fit in `i64`, avoiding heap allocation entirely ## Benchmark (canbench, wasm32) | Metric | Before | After | Change | |--------|--------|-------|--------| | option_list Decoding | 26.2M inst | 23.2M inst | **-11.7%** | | variant_list Decoding | 25.1M inst | 22.1M inst | **-11.9%** | | option_list Heap | 2 pages | 1 page | **-50%** | | variant_list Heap | 2 pages | 1 page | **-50%** | No regressions on any of the 9 benchmarks. ## Compatibility Wire format is **unchanged**. Additional edge-case values added to the round-trip compatibility test (Int(0), Int(i64::MAX), large positive Int). Relates to #710 --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary Adds three new canbench benchmarks to complement the existing `vec_int16`: - **`vec_nat`** — 262K `Nat` elements (variable-length LEB128 encoding). Exercises the `Nat::encode`/`decode` paths and the serde visitor round-trip for bignum types. - **`vec_nat32`** — 2M `u32` elements (fixed-width 4 bytes). Tests fixed-width primitive vector performance. - **`vec_nat64`** — 2M `u64` elements (fixed-width 8 bytes). Tests the largest fixed-width primitive vector. ### Baseline results (master, `ba72cf4`) | Benchmark | Encoding | Decoding | Total | Heap | |-----------|----------|----------|-------|------| | vec_nat | 1.10B | 1.49B | 2.59B | 172 pages | | vec_nat32 | 136.28M | 1.06B | 1.20B | 518 pages | | vec_nat64 | 161.45M | 1.06B | 1.22B | 1031 pages | These baselines make the impact of the performance work in `sat-perf-improvements` directly measurable: | Benchmark | Metric | Master | Optimized | Change | |-----------|--------|--------|-----------|--------| | **vec_nat** | Encoding | 1.10B | 66.54M | **-93.9% (16.5x)** | | **vec_nat** | Decoding | 1.49B | 917.08M | **-38.5%** | | **vec_nat** | Total | 2.59B | 983.62M | **-62.0%** | | **vec_nat32** | Encoding | 136.28M | 16.79M | **-87.7% (8.1x)** | | **vec_nat32** | Decoding | 1.06B | 406.87M | **-61.6%** | | **vec_nat32** | Total | 1.20B | 423.67M | **-64.7%** | | **vec_nat64** | Encoding | 161.45M | 33.57M | **-79.2% (4.8x)** | | **vec_nat64** | Decoding | 1.06B | 411.07M | **-61.2%** | | **vec_nat64** | Total | 1.22B | 444.64M | **-63.6%** | Relates to #710 --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This release also includes some performance improvements that are not shown in the changelog. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary - Fix decoding failure when a trailing/extra argument is a primitive vector (`vec int8/16/32/64`, `vec nat8/16/32/64`, `vec float32/64`, `vec bool`) - The fast-path optimization (#712) skipped setting `expect_type`/`wire_type` per element; `deserialize_ignored_any` then misidentified the element type and corrupted the byte stream - Fix: always set element types before calling `seed.deserialize`, skipping only the `add_cost(3)` call in the fast path - Release candid 0.10.26 ## Test plan - [ ] New regression test `primitive_vector_is_extra_args` in `tests/compatibility_vectors.rs` covers the exact failure scenario - [ ] All existing `compatibility_vectors` tests continue to pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…721) **Overview** Four decode-side optimizations, all behavior-preserving: 1. Nat/Int deserialization bypass: for values fitting u64/i64, read LEB128 directly and call visitor.visit_u64/i64, avoiding the BigUint/BigInt → bytes → BigUint round-trip (saves 3 allocations per value). 2. BigNum vector fast path: batch cost tracking and skip per-element type cloning/checking for Vec<Nat>, Vec<Int>, and Vec<Int> with Nat wire type, mirroring the existing primitive vec fast path. 3. PrimitiveVecAccess with IntoDeserializer: on LE platforms, decode primitive vectors via a lightweight SeqAccess that reads directly from the input byte slice using serde's IntoDeserializer, bypassing the full Deserializer and Cursor overhead. 4. Borrowed string deserialization: use visit_borrowed_str instead of copying bytes, enabling zero-copy for &str targets. Benchmark improvements (decode, vs previous optimized baseline): vec_nat: 910M → 300M (-67%) vec_nat32: 406M → 247M (-39%) vec_nat64: 411M → 255M (-38%) vec_int16: 411M → 251M (-39%) btreemap: 13.3B → 11.2B (-16%) option_list: 23M → 18M (-20%) variant_list: 21M → 17M (-21%) --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
### Motivation - Remove external `binary_parser` dependency for hot deserialization paths. ### Solution - Inline LEB128 u64/i64, length, and bool reading directly in `Deserializer`. - Add `text_fast_path` flag to skip type checks when key types are known during map deserialization. - Apply fast path to map keys/values and bignum handling. ### Meta - Removed unused `BoolValue` import. --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
### Motivation - Existing benchmarks miss critical decode paths; issue #603 notes zero coverage of service subtype checking. ### Solution - Add 8 benchmarks covering production patterns: fully-populated NNS neurons, schema evolution (field skipping), vec of services (exercises check_subtype), Ok/Err result variants, wide records (34+ fields), large enums (21 arms), double optionals, and multi-arg encoding/decoding. ### Details - Enable `value` feature on candid dependency for IDLValue/IDLArgs APIs. - Each benchmark reports separate encode/decode timings via bench_scope. Relates to #603 --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org>
## Summary - Add a `publish.yml` workflow for publishing crates to crates.io via trusted publishing (OIDC) - Supports selective publishing of `ic_principal`, `candid`/`candid_derive` (always together), and `candid_parser` - Publishes in dependency order to avoid unmet dependency errors Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…0.27 (#725) ## Release - `candid` 0.10.27 - `candid_parser` 0.3.1 - `didc` 0.6.1 ## Summary - The compatibility check previously stopped at the **first** incompatibility, forcing users into a fix-and-retry loop. Now it collects all breaking changes and renders them as a grouped, hierarchical report. The number of reported errors is bounded only by the interface size (no artificial cap); recursion depth is bounded by the existing stack/depth guard (~512 levels). - Error messages are clearer: "missing in new interface" instead of "is only in expected type"; "function annotation changed from query to update" instead of "Function mode mismatch". - New public API: `subtype_check_all()`, `Incompatibility`, `format_report()` in `candid`; `service_compatibility_report()` in `candid_parser`. ### Before (stops at first error) ``` Method budget_check_v1: func (BudgetCheckRequest) -> (BudgetCheckResult) query is not a subtype of func (BudgetCheckRequest/1) -> (BudgetCheckResult/1) query ``` ### After (all errors, grouped by method) ``` Error: 7 incompatible changes found: - method "config" is expected by the old interface but missing in the new one method "audit": - function annotation changed from query to update return type: record field log: nat is not a subtype of text record field count: text is not a subtype of nat method "balance": return type: text is not a subtype of nat method "transfer": input type: record field amount: nat is not a subtype of text return type: record field ok: text is not a subtype of bool record field balance: text is not a subtype of nat ``` ## Changes | File | What | |------|------| | `rust/candid/src/types/subtype.rs` | `Incompatibility` struct, `subtype_check_all()`, `format_report()`, internal `subtype_collect_()` | | `rust/candid_parser/src/utils.rs` | `service_compatibility_report()` | | `tools/didc/src/main.rs` | `didc check` uses new report | | `tools/ui/src/didjs/lib.rs` | Web UI uses new report | | `rust/candid_parser/tests/compatibility.rs` | **29 new tests** | ## Test plan - [x] 8 tests: backward-compatible changes (add opt field, add method, widen nat→int in input, etc.) must NOT be flagged - [x] 6 tests: backward-incompatible changes (remove method, change type, add required field, etc.) must be caught - [x] 6 tests: multiple errors are ALL collected (multiple methods, multiple fields, both input+return) - [x] 3 tests: error message quality (mentions method names, types, clear wording) - [x] 3 tests: hierarchical report formatting (grouping, inlining, empty for compatible) - [x] 3 tests: variant/edge cases - [x] All 175 existing tests continue to pass --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Pin GitHub Actions to commit SHAs GitHub Actions referenced by tag (e.g. `actions/checkout@v4`) use a mutable pointer — the tag owner can move it to a different commit at any time, including a malicious one. This is the attack vector used in the tj-actions/changed-files incident (CVE-2025-30066). Pinning to a full 40-character commit SHA makes the reference immutable. The `# tag` comment preserves human readability so reviewers can tell which version is pinned. Important: a SHA can also originate from a forked repository. A malicious actor can fork an action, push a compromised commit to the fork, and the SHA will resolve — but it won't exist in the upstream canonical repo. Each SHA in this PR was verified against the action's canonical repository (not a fork). ### Changes - `actions/checkout@v4` -> `actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1` - Version: v4.3.1 | Latest: v6.0.2 | Release age: 88d - Commit: actions/checkout@34e1148 - `actions/setup-python@v4` -> `actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4.9.1` - Version: v4.9.1 | Latest: v6.2.0 | Release age: 76d - Commit: actions/setup-python@7f4fc3e - `actions/cache@v4` -> `actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0` - Version: v4.3.0 | Latest: v5.0.4 | Release age: 20d - Commit: actions/cache@0057852 - `thollander/actions-comment-pull-request@v2` -> `thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 # v2.5.0` - Version: v2.5.0 | Latest: v3.0.1 | Release age: 522d - Commit: thollander/actions-comment-pull-request@fabd468 - `cachix/install-nix-action@v12` -> `cachix/install-nix-action@07da2520eebede906fbeefa9dd0a2b635323909d # v12` - Version: v12 | Latest: v31.10.3 | Release age: 12d - Commit: cachix/install-nix-action@07da252 - `actions/checkout@v3` -> `actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0` - Version: v3.6.0 | Latest: v6.0.2 | Release age: 88d - Commit: actions/checkout@f43a0e5 - `EmbarkStudios/cargo-deny-action@v1` -> `EmbarkStudios/cargo-deny-action@3f4a782664881cf5725d0ffd23969fcce89fd868 # v1.6.3` - Version: v1.6.3 | Latest: v2.0.15 | Release age: 90d - Commit: EmbarkStudios/cargo-deny-action@3f4a782 - `actions/checkout@v6` -> `actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2` - Version: v6.0.2 | Latest: v6.0.2 | Release age: 88d - Commit: actions/checkout@de0fac2 - `actions-rust-lang/setup-rust-toolchain@v1` -> `actions-rust-lang/setup-rust-toolchain@150fca883cd4034361b621bd4e6a9d34e5143606 # v1.15.4` - Version: v1.15.4 | Latest: v1.15.4 | Release age: 24d - Commit: actions-rust-lang/setup-rust-toolchain@150fca8 - `rust-lang/crates-io-auth-action@v1` -> `rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec # v1` - Version: v1 | Latest: v1.0.4 | Release age: 15d - Commit: rust-lang/crates-io-auth-action@b7e9a28 - `actions-rs/cargo@v1` -> `actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1.0.3` - Version: v1.0.3 | Latest: v1.0.1 | Release age: 2397d - Commit: actions-rs/cargo@844f368 - `actions/upload-artifact@v4` -> `actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2` - Version: v4.6.2 | Latest: v3.2.2 | Release age: 22d - Commit: actions/upload-artifact@ea165f8 - `actions/download-artifact@v4` -> `actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0` - Version: v4.3.0 | Latest: v3.1.0-node20 | Release age: 22d - Commit: actions/download-artifact@d3f86a1 - Warnings: 1 security advisory(ies) found, Action has 1 known advisory(ies) - `svenstaro/upload-release-action@v2` -> `svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # 2.11.5` - Version: 2.11.5 | Latest: 2.11.5 | Release age: 22d - Commit: svenstaro/upload-release-action@29e53e9 - `actions/setup-node@v4` -> `actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0` - Version: v4.4.0 | Latest: v6.3.0 | Release age: 35d - Commit: actions/setup-node@49933ea - `pnpm/action-setup@v3` -> `pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3` - Version: v3 | Latest: v5.0.0 | Release age: 22d - Commit: pnpm/action-setup@a3252b7 ### Files modified - `.github/workflows/bench.yml` - `.github/workflows/coq.yml` - `.github/workflows/license.yml` - `.github/workflows/publish.yml` - `.github/workflows/release.yml` - `.github/workflows/rust.yml` - `.github/workflows/tools.yml` ### Security warnings - 1 security advisory(ies) found - Action has 1 known advisory(ies) --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org>
Co-authored-by: Linwei Shang <linwei.shang@dfinity.org>
…ding (#728) ## Summary - Replace `panic!("float32 not supported in Motoko")` with `str("Float32")` in the Motoko binding generator. - Add a `float.did` test fixture covering `float32`/`float64` round-trip methods. ## Why Motoko added `Float32` in version 1.4.0 ([caffeinelabs/motoko#5906](caffeinelabs/motoko#5906)), updating both the import and export IDL mappings. The spec (`design/IDL-Motoko.md`) is being updated in a companion PR. This brings `didc bind --target mo` in line with what `moc` already does when importing `.did` files directly. Concretely, any `.did` file using `float32` (e.g. the IC management canister interface) would previously cause `didc bind --target mo` to panic at runtime. --------- Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary - Fix LEB128/SLEB128 fast path silently truncating `Nat`/`Int` values near the `u64`/`i64` boundary during decoding (ecc0c45) - Fix `Int::decode` truncating large magnitudes due to fast-path leakage (d08b8da) - Bump `candid` 0.10.27 → 0.10.28 and `candid_derive` to match - Cut `candid_parser` 0.3.2, which moves the previously unreleased Motoko `Float32` binding fix into a dated release - Update `CHANGELOG.md` with a 2026-05-20 entry covering both crates ## Test plan - [x] `cargo check -p candid -p candid_derive -p candid_parser` - [x] Reviewer to confirm changelog wording / release scope - [ ] Publish to crates.io after merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
….29 (#732) ## Fix: `text_fast_path` leaks into nested maps with non-text keys ### Problem Decoding a `BTreeMap<String, V>` where `V` is an enum containing a `BTreeMap<K, V2>` with a non-`String` key type fails with a subtyping error: Type mismatch at de.rs:1380 The error fires in `deserialize_enum` when `expect_type` is not a `TypeInner::Variant`, even though the wire type correctly encodes the key as a Candid variant. ### Root cause `deserialize_map` has a fast path for `BTreeMap<String, V>`: when the key type is `Text`, it sets `self.text_fast_path = true` on the deserializer **globally** before entering `visitor.visit_map(...)`. This flag is then visible to any code that runs inside the visitor — including `next_key_seed` of a **nested** inner map. `next_key_seed` for `Style::Map` checked `self.de.text_fast_path` to decide whether to skip updating `expect_type`/`wire_type` for the key: ```rust if !self.de.text_fast_path { // ← reads global flag, not this map's flag self.de.expect_type = expect.0.clone(); self.de.wire_type = wire.0.clone(); } ``` When the inner map has non-text keys (e.g. an enum), the outer map's text_fast_path = true causes next_key_seed to skip the type update. The deserializer then calls deserialize_enum with a stale expect_type (whatever was left over from the enclosing context — a vec type, a record, etc.), which is not TypeInner::Variant, triggering the crash. ### Fix Add key_text_fast: bool to Style::Map so that each map compound carries its own fast-path decision, independent of any enclosing map's state. next_key_seed now: 1. uses style.key_text_fast (not the global flag) to decide whether the per-entry add_cost(4) was pre-paid, and 2. sets self.de.text_fast_path = key_text_fast immediately before calling the key deserializer, so deserialize_str's fast path is engaged only when this map's key is actually Text. No changes to next_value_seed are required: after next_key_seed sets text_fast_path correctly, next_value_seed's any_fast check (which reads self.de.text_fast_path) naturally reflects the current map's key type. ### Regression test test_nested_map_non_text_key in tests/serde.rs encodes and round-trips: ```rust BTreeMap<String, Value> "fun" => Value::Fun(BTreeMap<MapKey, u32>) // inner map with enum key "lit" => Value::Lit(String) ``` This test panicked with "Type mismatch" before the fix and passes after. --------- Co-authored-by: Linwei Shang <linwei.shang@dfinity.org> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Make the candid ui deployable with icp-cli
Update the candid ui cansiter to use the new TS libraries.
Update after: This is to be updated after #735 is merged There's a been a "temporary hack" since 2022 - I spot checked canisters and they seem to have the standard "candid:service" metadata, eg: ``` # bitcoin minter icp canister metadata -n ic mqygn-kiaaa-aaaar-qaadq-cai "candid:service" ```
…ie (#737) Don't merge before #736 This bumps the cdk to a more recent version so we can use environment variables and adds asset certification. Next steps will be to: - use environment variable to figure out the canister id on the frontend. - Update the vite config so the frontend can be iterated on without the canister (if possible)
Brings master's ~45 commits (releases up to candid 0.10.29 / candid_parser 0.3.2 / didc 0.6.1 / ic_principal 0.1.3, decode/encode perf work, the icp-cli/Vite UI rewrite, doc-comment preservation #707, collect-all subtype errors #725) onto the next branch while preserving next's breaking v-next features: ArgType return/arg name collection (#684), TypeKey named-type keys (#590, re-applied on next), the pretty-printing combinator (#668), and the JS/TS idlService/idlInitArgs exports (#665). Conflict resolution: - 16 .d.ts/.js/.mo/.rs goldenfiles regenerated from merged bindings (UPDATE_GOLDENFILES=1) — output now carries BOTH master's @icp-sdk/core imports AND next's idlService/idlInitArgs exports. - Cargo.lock / bench Cargo.lock regenerated; crate versions take master's. - 7 source files hand-merged: master's subtype-error rewrite (#725) re-threaded over next's ArgType signatures; doc-comment emission folded into next's pretty-printing combinator; doc-comment fields kept alongside TypeKey/ArgType types and the @icp-sdk TypeScript imports. - candid_parser/typing.rs (auto-merged but semantically broken): master's new validate_type recursion guard adapted to TypeKey-keyed env and ArgType args. Verified: cargo check/test pass under default, --no-default-features, and --features all; clippy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
✅ No security or compliance issues detected. Reviewed everything up to bab84c6. Security Overview
Detected Code ChangesThe diff is too large to display a summary of code changes. |
Click to see raw report |
lwshang
approved these changes
Jun 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.