Skip to content

Conversation

@SyMind
Copy link
Collaborator

@SyMind SyMind commented Nov 7, 2025

This PR fixes a bug in the size() method of ReplaceSource where replacements that start beyond the source bounds were causing incorrect size calculations. The fix adds an early check to handle out-of-bounds replacements by simply adding their content length to the total size.

This PR introduces significant performance improvements by optimizing the rope method implementations across various source types. The rope method provides a lightweight "rope" view of source content as borrowed string slices, avoiding expensive string concatenations and memory allocations.

Copilot AI review requested due to automatic review settings November 7, 2025 08:56
@codspeed-hq
Copy link

codspeed-hq bot commented Nov 7, 2025

CodSpeed Performance Report

Merging #204 will improve performances by ×5

Comparing fix-replace-size (b9d8cee) with main (aea29de)

Summary

⚡ 2 improvements
✅ 9 untouched
⏩ 6 skipped1

Benchmarks breakdown

Benchmark BASE HEAD Change
complex_replace_source_map_cached_source_stream_chunks 36.5 ms 7.3 ms ×5
repetitive_react_components_map 2.4 ms 2 ms +19.24%

Footnotes

  1. 6 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.

Copy link

Copilot AI left a comment

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 fixes a bug in the size() method of ReplaceSource where replacements that start beyond the source bounds were causing incorrect size calculations. The fix adds an early check to handle out-of-bounds replacements by simply adding their content length to the total size.

Key Changes:

  • Added a boundary check in the size() method to detect and handle replacements that start beyond the inner source size
  • Added a test case with an out-of-bounds replacement to verify the fix works correctly
Comments suppressed due to low confidence (1)

src/replace_source.rs:223

  • The current fix handles replacements that start entirely beyond the source bounds, but it doesn't handle the case where a replacement starts within bounds but extends beyond them (i.e., replacement.start < inner_source_size but replacement.end > inner_source_size).

For example, if the source is 1070 bytes and we have a replacement from position 1000 to 2000, the current code calculates:

  • original_length = 2000 - 1000 = 1000 (line 220-223)
  • But the actual original content is only 70 bytes (from 1000 to 1070)

This causes the size calculation to be incorrect because it subtracts the full 1000 bytes instead of just 70 bytes.

Consider clamping the replacement.end to inner_source_size when calculating original_length:

let original_length = replacement
  .end
  .min(inner_source_size as u32)  // Clamp to source size
  .saturating_sub(replacement.start.max(inner_pos))
  as usize;
      let original_length = replacement
        .end
        .saturating_sub(replacement.start.max(inner_pos))
        as usize;

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

@SyMind SyMind force-pushed the fix-replace-size branch 3 times, most recently from 083552b to 3d48556 Compare November 7, 2025 09:21
@SyMind SyMind force-pushed the fix-replace-size branch 2 times, most recently from 2be9e2c to adcbd42 Compare November 8, 2025 09:51
@SyMind SyMind force-pushed the fix-replace-size branch 2 times, most recently from 7220862 to 3c1808d Compare November 8, 2025 14:58
@SyMind SyMind requested a review from Copilot November 9, 2025 03:22
Copy link

Copilot AI left a comment

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 12 out of 12 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

src/replace_source.rs:304

  • The size calculation is incorrect when a replacement extends beyond the source size. The original_length calculation doesn't account for replacements where replacement.end > inner_source_size.

Example:

  • Source: "hello" (size=5)
  • Replacement: start=3, end=10, content="XX"
  • Current calculation: original_length = 10 - 3 = 7, but only 2 bytes (positions 3-4) actually exist in the source
  • This causes size to be calculated incorrectly

The correct original_length should be: min(replacement.end, inner_source_size) - replacement.start.max(inner_pos)

      // Handle the replacement itself
      let original_length = replacement
        .end
        .saturating_sub(replacement.start.max(inner_pos))
        as usize;

src/with_utf16.rs:84

  • The SAFETY comment is outdated. The code no longer uses CharIndices to iterate over characters. Instead, it manually parses UTF-8 byte sequences. The safety justification should be updated to reflect that the indices come from the manual UTF-8 parsing logic (lines 40-62), which ensures they are valid UTF-8 boundaries.
      // SAFETY: Since `indices` iterates over the `CharIndices` of `self`, we can guarantee
      // that the indices obtained from it will always be within the bounds of `self` and they
      // will always lie on UTF-8 sequence boundaries.

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

@SyMind SyMind merged commit 4b5693a into main Nov 10, 2025
10 checks passed
@SyMind SyMind deleted the fix-replace-size branch November 10, 2025 05:14
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