Skip to content

feat(multitude): support trait object coercion - #617

Open
geeknoid wants to merge 1 commit into
mainfrom
multitude
Open

feat(multitude): support trait object coercion#617
geeknoid wants to merge 1 commit into
mainfrom
multitude

Conversation

@geeknoid

Copy link
Copy Markdown
Member

Add compiler-checked coercion APIs for Box, Rc, and Arc using hybrid metadata. Sized values, strings, and slices retain thin handles, while trait objects carry their vtable metadata in each erased handle.

Define unwind-safety contracts for Multitude and Plurality, strengthen DST and refcount coverage, and correct Serde ignored-value dispatch.

Audit API documentation and make Criterion and Callgrind benchmark setup, teardown, naming, and reporting consistent.

Copilot AI review requested due to automatic review settings July 29, 2026 16:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends multitude (and aligns related plurality behavior) to support compiler-checked trait-object coercion for Box/Rc/Arc using a hybrid metadata strategy (thin handles for sized/str/slice, vtable carried in erased handles), while also tightening unwind-safety contracts, correcting Serde ignored-value dispatch, and standardizing benchmark naming/setup/teardown and related docs.

Changes:

  • Add trait-object coercion API (Coercion + coerce!) and update smart-pointer internals to support handle-resident vtable metadata.
  • Define/verify unwind-safety contracts for arenas/pools and escaped handles, including new behavioral tests.
  • Fix deserialize_ignored_any to dispatch through deserialize_any, and audit/update documentation and benchmark organization to match new behavior.

Reviewed changes

Copilot reviewed 79 out of 79 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/plurality/tests/unwind_safe.rs Adds unwind-safety contract tests for plurality pool/owners.
crates/plurality/src/sync.rs Adds explicit unwind-safety trait impls for plurality::Arc.
crates/plurality/src/rc.rs Adds explicit unwind-safety trait impls for plurality::Rc.
crates/plurality/src/pool.rs Adds explicit unwind-safety trait impls for plurality::Pool.
crates/plurality/src/boxed.rs Adds explicit unwind-safety trait impls for plurality::Box.
crates/plurality/src/alloced.rs Adds explicit unwind-safety trait impls for plurality::Alloc.
crates/multitude/tests/variance_and_zst.rs Extends variance assertions to cover Rc.
crates/multitude/tests/utf16.rs Updates test docs to match revised refcount/metadata wording.
crates/multitude/tests/unwind_safe.rs Adds unwind-safety contract tests for multitude arena/owners.
crates/multitude/tests/unsize.rs Adds trait-object coercion + hybrid handle layout tests (feature dst).
crates/multitude/tests/send_sync.rs Updates Send/Sync rationale wording for Rc.
crates/multitude/tests/loom.rs Adds loom coverage for mixed sized/erased Arc drop races (feature dst).
crates/multitude/tests/audit_repro.rs Updates doc text to match allocation-local shared strong count model.
crates/multitude/tests/arena.rs Updates doc text to match allocation-local shared strong count model.
crates/multitude/tests/arena_string.rs Updates string handle-size rationale to match prefix-based length storage.
crates/multitude/src/zerocopy.rs Clarifies alignment panic wording.
crates/multitude/src/vec/mutate.rs Improves doc precision for capacity reclamation and reserve_exact.
crates/multitude/src/vec/mod.rs Updates struct docs and refill-hint comments for shared freeze prefix.
crates/multitude/src/vec/freeze.rs Extends freeze docs to include Rc and clarifies metadata usage.
crates/multitude/src/thin_smart_ptr_common.rs Updates shared impl macro for handle-resident metadata + new trait bounds.
crates/multitude/src/strings/utf16_string.rs Updates drain docs and parameterizes common-string docs with units.
crates/multitude/src/strings/string.rs Updates drain docs and parameterizes common-string docs with units.
crates/multitude/src/strings/string_common.rs Refactors shared string docs to use $units and trims repetitive examples.
crates/multitude/src/rc.rs Refactors Rc to support handle metadata + adds unsize/unsize_pin.
crates/multitude/src/lib.rs Updates crate-level docs for hybrid pointer widths, Rc freezes, and DST APIs.
crates/multitude/src/internal/constants.rs Clarifies freeze-prefix behavior and alignment-related semantics.
crates/multitude/src/internal/chunk.rs Updates chunk docs for per-family chunk refs and ordering explanations.
crates/multitude/src/internal/chunk_provider.rs Clarifies cache-floor publication comment.
crates/multitude/src/internal/chunk_mutator.rs Updates docs for shared strong counts and shared freeze prefix.
crates/multitude/src/internal/arena_buf.rs Updates freeze-prefix docs and invariants for shared-owner prefix.
crates/multitude/src/dst/mod.rs Updates DST module docs to reflect hybrid metadata storage.
crates/multitude/src/de/value/tests.rs Adds regression test proving deserialize_ignored_any dispatch correctness.
crates/multitude/src/de/value.rs Fixes deserialize_ignored_any to delegate to deserialize_any.
crates/multitude/src/de/reuse.rs Updates docs for all-or-nothing String reuse semantics.
crates/multitude/src/de/mod.rs Updates module docs and bounds to use SmartPointerPointee.
crates/multitude/src/de/json.rs Clarifies trailing-input check timing and arena reset/reuse wording.
crates/multitude/src/de/json_error.rs Clarifies Display behavior for limit violations vs parse/shape errors.
crates/multitude/src/cow.rs Updates bounds from ptr_meta::Pointee to SmartPointerPointee.
crates/multitude/src/coerce.rs Introduces Coercion + coerce! macro for compiler-checked unsizing.
crates/multitude/src/bytemuck.rs Clarifies alignment panic wording.
crates/multitude/src/box.rs Refactors Box to support handle metadata + adds unsize.
crates/multitude/src/arena/reserve.rs Updates reserve docs for shared freeze prefix and Rc freezes.
crates/multitude/src/arena/mod.rs Adds explicit unwind-safety trait impls for Arena.
crates/multitude/src/arena/alloc_value.rs Updates docs/comments around strong counts and chunk pinning.
crates/multitude/src/arena/alloc_utf16.rs Updates UTF-16 allocation docs for Rc and shared strong counts.
crates/multitude/src/arena/alloc_unsized.rs Refactors DST allocation docs and metadata sizing logic for hybrid model.
crates/multitude/src/arena/alloc_uninit.rs Updates alignment limits wording for slice APIs (64 KiB for ref slices).
crates/multitude/src/arena/alloc_str.rs Updates str allocation docs for Rc + shared strong counts.
crates/multitude/src/arena/alloc_slice_ref.rs Updates alignment-limit docs for &mut [T] allocations.
crates/multitude/src/arena/alloc_slice_box.rs Removes outdated dst-feature note from docs.
crates/multitude/src/arena/alloc_prefixed.rs Updates prefixed allocation docs for Box vs Rc/Arc layouts.
crates/multitude/src/arc.rs Refactors Arc to support handle metadata + adds unsize/unsize_pin.
crates/multitude/src/allocator_impl.rs Clarifies allocator alignment cap wording and grow fast-path comment.
crates/multitude/src/alloc_handle.rs Clarifies pinning constraints and adds unwind-safety impls for Alloc.
crates/multitude/docs/DESIGN.md Updates design documentation for hybrid metadata and freeze semantics.
crates/multitude/docs/BUMPALO.md Updates comparison table for trait-object pointer width and DST support scope.
crates/multitude/Cargo.toml Renames Callgrind bench targets to consistent criterion_*_cg naming.
crates/multitude/benches/multitude_serde_cg.rs Renames typed lifecycle bench functions for clearer grouping.
crates/multitude/benches/multitude_record_batch/shared.rs Makes hot paths reset arena internally; centralizes warm-cache setup.
crates/multitude/benches/multitude_record_batch.rs Removes allocation tracking, adopts per-iteration reclamation + consistent setup.
crates/multitude/benches/multitude_record_batch_cg.rs Switches state to &mut so hot paths can reset between iterations.
crates/multitude/benches/gungraun_alloc/linux.rs Removes old Callgrind wrapper (superseded by criterion_alloc_cg).
crates/multitude/benches/criterion_rc_array.rs Switches to batched Criterion harness excluding setup/teardown.
crates/multitude/benches/criterion_rc_array_cg/linux.rs Renames/reshapes Callgrind group and functions to match Criterion pairing.
crates/multitude/benches/criterion_rc_array_cg.rs Updates bench wiring and naming to criterion_rc_array_cg.
crates/multitude/benches/criterion_drop.rs Renames groups/benches for consistent naming and pairing with Callgrind.
crates/multitude/benches/criterion_drop_cg/linux.rs Renames Callgrind groups/functions to match Criterion pairing.
crates/multitude/benches/criterion_drop_cg.rs Updates bench wiring and naming to criterion_drop_cg.
crates/multitude/benches/criterion_arena_vs_allocator.rs Renames Criterion group for consistent prefixing.
crates/multitude/benches/criterion_arc_array.rs Switches to batched Criterion harness excluding setup/teardown.
crates/multitude/benches/criterion_arc_array_cg/linux.rs Renames/reshapes Callgrind group and functions to match Criterion pairing.
crates/multitude/benches/criterion_arc_array_cg.rs Updates bench wiring and naming to criterion_arc_array_cg.
crates/multitude/benches/criterion_alloc.rs Renames groups and aligns naming/pairing with Callgrind bench.
crates/multitude/benches/criterion_alloc_cg/linux.rs Adds new Callgrind wrapper organized by Criterion group/variant naming.
crates/multitude/benches/criterion_alloc_cg.rs Wires new Callgrind groups and updates naming/invocation docs.
Comments suppressed due to low confidence (1)

crates/multitude/src/box.rs:108

  • RefUnwindSafe/UnwindSafe are implemented only for Box<T, A> (default metadata). Like the Send/Sync impls above, any explicit non-default M would fall back to auto-trait behavior and may bypass the intended unwind-safety bounds. Implement these for Box<T, A, M> instead.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/multitude/src/arc.rs
Comment thread crates/multitude/src/rc.rs
Comment thread crates/multitude/src/box.rs Outdated
Copilot AI review requested due to automatic review settings July 29, 2026 17:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 79 out of 79 changed files in this pull request and generated 1 comment.

Comment thread crates/multitude/tests/unsize.rs
@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.0%. Comparing base (c1df038) to head (830f674).

Additional details and impacted files
@@           Coverage Diff            @@
##             main     #617    +/-   ##
========================================
  Coverage   100.0%   100.0%            
========================================
  Files         470      471     +1     
  Lines       45251    45399   +148     
========================================
+ Hits        45251    45399   +148     
Flag Coverage Δ
linux 87.2% <100.0%> (?)
linux-arm 86.9% <100.0%> (?)
windows 87.5% <100.0%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI review requested due to automatic review settings July 29, 2026 22:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 79 out of 79 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

crates/multitude/tests/unsize.rs:18

  • size_of::<...>() is used later in this test file, but size_of is never imported or qualified. As written, this will not compile (e.g. the assertions in trailing_trait_object_dst_uses_handle_metadata and only_trait_object_handles_pay_for_metadata).

Comment thread crates/multitude/src/coerce.rs Outdated
Comment thread crates/multitude/src/box.rs
Comment thread crates/plurality/src/alloced.rs
Comment thread crates/multitude/src/internal/thin_dst.rs
Comment thread crates/multitude/src/coerce.rs
@psandana

Copy link
Copy Markdown
Contributor

[design] Box/Arc/Rc/Pool/Alloc in both multitude and plurality each get hand-written RefUnwindSafe/UnwindSafe impls with very similar reasoning comments, and each crate has its own near-identical tests/unwind_safe.rs with the same AmbiguousIfUnwindSafe/AmbiguousIfRefUnwindSafe negative-assertion harness copy-pasted. This is exactly the kind of cross-cutting contract that's easy to let drift — if a future refactor changes ownership semantics in one crate's smart pointer but the parallel crate is forgotten, the contracts could silently diverge with no shared enforcement point.

Would it be worth factoring the assert_(not_)unwind_safe/Ambiguous* test harness (and ideally the impl-generating pattern, via a shared internal macro if feasible given the different field sets) into a small shared internal testing/dev-dependency crate so both multitude and plurality consume one canonical implementation?

Copilot AI review requested due to automatic review settings July 30, 2026 00:01
@geeknoid

Copy link
Copy Markdown
Member Author

Thanks for the suggestion. I considered sharing the unwind assertion harness, but I prefer keeping these small test-only helpers local for now. A shared dev crate or macro would add dependency and macro indirection while centralizing only test syntax, not the intentionally distinct ownership and allocator contracts each crate must assert. Keeping each contract self-contained also makes drift visible as an explicit test change in that crate; extraction would make more sense if the harness grows materially.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 79 out of 79 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

crates/multitude/benches/criterion_arc_array.rs:6

  • The module-level docs say “Setup and result teardown are excluded”, but the iter_batched routine returns (result, arena). Criterion will drop that return value as part of the timed iteration loop, so teardown is still included in the measured cost. Please update the docs (or change the benchmark structure) so the description matches what’s being measured.
//! Builds an `Arc<[Arc<[u8]>]>` of `PROPERTIES` binary blobs two ways and
//! compares them: `std::sync::Arc` (global allocator) vs `multitude::Arc`.
//! Setup and result teardown are excluded, so every case measures build cost.

crates/multitude/benches/criterion_rc_array.rs:6

  • The module-level docs say “Setup and result teardown are excluded”, but the iter_batched routine returns (result, arena). Criterion will drop that return value as part of the timed iteration loop, so teardown is still included in the measured cost. Please update the docs (or change the benchmark structure) so the description matches what’s being measured.
//! Builds an `Rc<[Rc<[u8]>]>` of `PROPERTIES` binary blobs two ways and
//! compares them: `std::rc::Rc` (global allocator) vs `multitude::Rc`.
//! Setup and result teardown are excluded, so every case measures build cost.

Copilot AI review requested due to automatic review settings July 30, 2026 00:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 79 out of 79 changed files in this pull request and generated no new comments.

@sandersaares
sandersaares self-requested a review July 30, 2026 06:24
Copilot AI review requested due to automatic review settings July 30, 2026 11:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 79 out of 79 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

crates/multitude/src/coerce.rs:16

  • The type-level documentation overstates the guarantee: Coercion is only compiler-checked when constructed via coerce!; Coercion::new is explicitly unsafe and can violate the unsizing/coherence contract (even though unsize_metadata checks the data-pointer address at runtime). Tightening this wording helps API users understand when they actually have compiler-checked safety.

Comment thread crates/multitude/src/de/value.rs Outdated
Comment thread crates/multitude/src/de/reuse.rs Outdated
Comment thread crates/multitude/src/internal/thin_dst.rs
Comment thread crates/multitude/src/coerce.rs Outdated
Comment thread crates/multitude/benches/criterion_arc_array_cg/linux.rs
Comment thread crates/multitude/docs/BUMPALO.md Outdated
Comment thread crates/multitude/src/de/json_error.rs Outdated
Comment thread crates/multitude/src/lib.rs Outdated
Comment thread crates/multitude/src/box.rs Outdated
Comment thread crates/multitude/src/internal/thin_dst.rs Outdated
Copilot AI review requested due to automatic review settings July 30, 2026 13:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 85 out of 85 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

crates/multitude/src/bytemuck.rs:82

  • The alignment limit documented here ("64 KiB or greater") doesn’t match the actual scalar allocation guard: Arena::try_alloc_with rejects align_of::<T>() >= MAX_SMART_PTR_ALIGN (32 KiB) before attempting allocation. This should document the 32 KiB ceiling so callers know what will actually panic.
    crates/multitude/src/zerocopy.rs:79
  • The documented alignment cap ("64 KiB or greater") doesn’t match the scalar allocation path used here (Arena::try_alloc_with), which rejects align_of::<T>() >= 32 KiB (MAX_SMART_PTR_ALIGN). Please update the docs to reflect the actual limit.

Copilot AI review requested due to automatic review settings July 30, 2026 14:23
@geeknoid

Copy link
Copy Markdown
Member Author

Addressed the two suppressed alignment-documentation findings from the latest Copilot review in a501b81. The scalar BytemuckView::{alloc,try_alloc} and ZerocopyView::{alloc,try_alloc} contracts now state their actual 32 KiB ceiling inherited from Arena::try_alloc_with; the separate slice contracts retain their correct 64 KiB arena-reference ceiling.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 85 out of 85 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

crates/multitude/tests/serialization.rs:1168

  • These assertions assume JsonError's Display always includes a Backtrace: section, but backtrace capture/rendering is behind #[cfg(feature = "std")] in JsonError. Since serde_json does not imply std, to_string() will omit this section when std is disabled.

Gate the backtrace-related expectations (and the nearby error.backtrace() call) on feature = "std" so this test works under --no-default-features --features serde_json too.
crates/multitude/tests/serialization.rs:1041

  • These assertions assume multitude is built with the std feature (they require the Backtrace: section to be present in JsonError's Display). However serde_json does not imply std, and JsonError only includes backtrace rendering behind #[cfg(feature = "std")]. This makes the test fail (or become feature-combination dependent) under --no-default-features --features serde_json.

Gate the backtrace assertion on feature = "std" (and optionally assert its absence when std is disabled) so this test matches the actual Display contract across supported feature sets.

This issue also appears on line 1165 of the same file.

Add compiler-checked coercion APIs for Box, Rc, and Arc using hybrid metadata. Sized values, strings, and slices retain thin handles, while trait objects carry their vtable metadata in each erased handle.

Define unwind-safety contracts for Multitude and Plurality, strengthen DST and refcount coverage, and correct Serde ignored-value dispatch.

Audit API documentation and make Criterion and Callgrind benchmark setup, teardown, naming, and reporting consistent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 30099931-5bbd-4483-b487-915be7e43641
Copilot AI review requested due to automatic review settings July 30, 2026 14:57
@geeknoid

Copy link
Copy Markdown
Member Author

Addressed the latest suppressed no-std serialization-test findings in 830f674. Backtrace method calls and the dedicated capture test are now gated on std; display tests assert the backtrace section is present with std and absent without it while still checking the underlying JSON cause in both modes. The full --no-default-features --features serde_json serialization target now passes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 85 out of 85 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

crates/multitude/src/arena/alloc_uninit.rs:123

  • The docs here say allocations panic when align_of::<T>() is at least 64 KiB, but the smart-pointer alignment ceiling is CHUNK_ALIGN / 2 (= 32 KiB). This is likely to mislead users about what alignments are accepted (and there are other 64 KiB mentions later in this file that should be updated similarly).
    crates/multitude/src/arena/alloc_slice_ref.rs:82
  • These docs say allocations panic when align_of::<T>() is at least 64 KiB, but the arena’s smart-pointer alignment cap is CHUNK_ALIGN / 2 (= 32 KiB). This should be corrected (and the other 64 KiB mentions in this file should be updated similarly) to match the actual validation logic.

@geeknoid
geeknoid enabled auto-merge (squash) July 30, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants