Skip to content

Migrate to Copy-on-Write (Cow) for zero-copy decoding support - #40

Merged
moreal merged 2 commits into
mainfrom
copy-on-write
Feb 1, 2026
Merged

Migrate to Copy-on-Write (Cow) for zero-copy decoding support#40
moreal merged 2 commits into
mainfrom
copy-on-write

Conversation

@moreal

@moreal moreal commented Feb 1, 2026

Copy link
Copy Markdown
Owner

Add lifetime parameters to BencodexValue<'a> and BencodexKey<'a>, replacing internal Vec<u8>/String with Cow<'a, [u8]>/Cow<'a, str>. This enables zero-copy decoding via the new decode_borrowed() API that borrows directly from the input slice. Also changes Encode trait from consuming self to &self, eliminating unnecessary clones during encoding.

Summary by CodeRabbit

  • New Features

    • Added zero-copy decoding via new decode_borrowed function for improved performance with borrowed data.
    • Extended benchmarking suite with zero-copy benchmark paths to measure performance improvements.
  • Bug Fixes

    • Eliminated unnecessary clones in encode and benchmark paths by adopting borrowing semantics.
  • Refactor

    • Changed Encode trait to borrow values instead of consuming them.
    • Enhanced internal data handling to support both borrowed and owned data throughout the codec pipeline.

✏️ Tip: You can customize this high-level summary in your review settings.

Add lifetime parameters to BencodexValue<'a> and BencodexKey<'a>, replacing
internal Vec<u8>/String with Cow<'a, [u8]>/Cow<'a, str>. This enables
zero-copy decoding via the new decode_borrowed() API that borrows directly
from the input slice. Also changes Encode trait from consuming self to &self,
eliminating unnecessary clones during encoding.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Feb 1, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This pull request introduces zero-copy borrowing semantics throughout the bencodex codec by adding lifetime parameters to BencodexValue and BencodexKey using Cow-backed storage, refactoring the Encode trait to accept borrowed references, and providing dual decode paths for both owned and borrowed data across all codec implementations.

Changes

Cohort / File(s) Summary
Core Type System
src/codec/types.rs
Introduces lifetime-parametric BencodexValue<'a> and BencodexKey<'a> with Cow-backed Binary/Text variants; updates BencodexList/BencodexDictionary to use lifetimes; adds into_owned() conversion methods; updates all From trait impls to leverage Cow for borrowed/owned data.
Decode Implementation
src/codec/decode.rs, src/codec/simd/mod.rs, src/codec/simd/stage2.rs
Adds const generic BORROW flag for dual-path decoding; introduces decode_borrowed(input: &[u8]) → Result<BencodexValue<'_>, DecodeError> API; refactors all internal decode functions to be generic over BORROW with helper functions cow_binary/cow_text; updates SIMD parser to propagate lifetimes through parse operations and return borrowed Cow variants; updates all decode trait implementations to return BencodexValue<'static>.
Encode Implementation
src/codec/encode.rs
Changes Encode trait method signature from encode(self, ...) to encode(&self, ...) across all implementations; adds encode_binary and encode_text helper functions; updates Vec<BencodexValue<'>> and BTreeMap<BencodexKey<'>, BencodexValue<'_>> to use lifetime parameters; refactors key/value encoding to use new helpers.
JSON Support
src/json/decode.rs, src/json/encode.rs
Updates from_json functions to return BencodexValue<'static> with Cow::Owned variants; adds lifetime annotations to BencodexJsonEncoder and related functions; updates to_json/to_json_with_options to accept BencodexValue<'_> references.
Library API
src/lib.rs, src/prelude.rs
Adds decode_borrowed to public codec::decode re-exports; replaces ToOwned with Cow in prelude.
Benchmarks
benches/decode.rs, benches/encode.rs
Introduces decode_borrowed benchmark path with macro support; updates decode_simd benchmark to use zero-copy path; converts encode benchmarks to use borrowed references instead of clones; updates benchmark groups to register new paths.
Examples & Test Data
examples/generate_test_data.rs
Updates random_key, random_primitive, random_value, generate_large_value signatures to return BencodexKey<'static>/BencodexValue<'static>; wraps generated data with Cow::Owned; adds Cow import.
Tests
tests/codec/encode.rs, tests/codec/utils.rs, tests/fuzz/mod.rs, tests/fuzz/simd_decode.rs
Updates Spec and TestsuiteYamlLoader to use BencodexValue<'static'> and BencodexKey<'static'>; modifies YAML loader to construct Cow::Owned variants; updates fuzz generators to produce 'static lifetimes with Cow-wrapped data; adds .into_owned() calls on SIMD decode results; removes unnecessary clones in encoding tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Hops through borrowed lands so free,
Where Cow owns what data be,
No clones today, just lifetimes bright,
Zero-copy hops—what a delight!
Static and borrowed in harmony.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch copy-on-write

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter

codecov-commenter commented Feb 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.82759% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.23%. Comparing base (5bcb841) to head (2e02f33).

Files with missing lines Patch % Lines
src/codec/decode.rs 80.64% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #40      +/-   ##
==========================================
+ Coverage   74.78%   75.23%   +0.44%     
==========================================
  Files          14       14              
  Lines         714      751      +37     
==========================================
+ Hits          534      565      +31     
- Misses        180      186       +6     

☔ View full report in Codecov by Sentry.
📢 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.

@codspeed-hq

codspeed-hq Bot commented Feb 1, 2026

Copy link
Copy Markdown

CodSpeed Performance Report

Merging this PR will improve performance by ×3.5

Comparing copy-on-write (2e02f33) with main (5bcb841)

Summary

⚡ 4 improved benchmarks
✅ 6 untouched benchmarks
🆕 3 new benchmarks
⏩ 4 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
🆕 large_random_0 (36.5MB) N/A 412.8 ms N/A
bigint (9223372036854775807) 3.7 µs 3.3 µs +14.42%
🆕 ncinventory_1 (45.6KB) N/A 1.6 ms N/A
ncinventory_1 (45.6KB) 2,656.7 µs 933.7 µs ×2.8
ncavatar_1 (20.6KB) 1,155.6 µs 327.5 µs ×3.5
large_random_0 (36.5MB) 535 ms 344.5 ms +55.28%
🆕 ncavatar_1 (20.6KB) N/A 696.4 µs N/A

Footnotes

  1. 4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@moreal moreal self-assigned this Feb 1, 2026
Parameterize decode_impl with const generic BORROW to control whether
leaf values (Binary/Text) use Cow::Borrowed or Cow::Owned. When
BORROW=false, owned values are produced directly during parsing,
eliminating the post-decode into_owned() walk that was rebuilding
every BTreeMap and Vec container. This fixes the 10-20% decode_scalar
regression on small/medium files introduced by the Cow migration.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@moreal
moreal marked this pull request as ready for review February 1, 2026 01:38
@moreal
moreal merged commit 58ce6cc into main Feb 1, 2026
22 of 24 checks passed
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.

2 participants