Skip to content

[JULES] Refactor pattern stdlib to eliminate redundancy and allocations - #395

Closed
logbie wants to merge 1 commit into
mainfrom
jules-refactor-pattern-stdlib-12956706219001740784
Closed

[JULES] Refactor pattern stdlib to eliminate redundancy and allocations#395
logbie wants to merge 1 commit into
mainfrom
jules-refactor-pattern-stdlib-12956706219001740784

Conversation

@logbie

@logbie logbie commented Mar 8, 2026

Copy link
Copy Markdown
Collaborator

Summary of Changes

  • The Issue: The src/stdlib/pattern.rs module contained significant boilerplate code for argument validation and type extraction (Value::Text and Value::Pattern), which resulted in duplicated code and unnecessary to_string() allocations for error messages across all its native functions. Furthermore, native_pattern_split performed a highly inefficient O(N) memory allocation by collecting all character indices into a Vec<usize> (text.char_indices().map(...).collect()) just to perform character-to-byte offset conversions during splitting.
  • The Rational: Reducing duplicated logic improves maintainability and ensures consistent error messaging across the standard library. Optimizing the native_pattern_split function eliminates an unnecessary O(N) allocation, which reduces memory consumption and improves algorithmic efficiency when working with large strings.
  • The Solution:
    1. Implemented a generic expect_pattern helper in src/stdlib/helpers.rs to complement the existing expect_text helper.
    2. Refactored all pattern native functions (pattern_matches_native, pattern_find_native, etc.) to use check_arg_count, expect_text, and expect_pattern.
    3. Replaced .to_string() on static string keys in map constructions with String::from() to avoid format machinery overhead.
    4. Optimized native_pattern_split to use an incremental, state-preserving text.char_indices() iterator, avoiding the intermediate Vec<usize> allocation entirely.
    5. Updated the expected error messages in src/stdlib/pattern_test.rs to match the standardized output.

Verification Checklist

  • cargo fmt executed and passed.
  • cargo clippy returned no warnings or errors.
  • All cargo test suites passed (100% success rate).

PR created automatically by Jules for task 12956706219001740784 started by @logbie


Open with Devin

Summary by CodeRabbit

  • Refactor
    • Standardized pattern-related error messages for consistency.
    • Consolidated validation logic using helper utilities for improved code maintainability.

- Introduced `expect_pattern` helper in `src/stdlib/helpers.rs`
- Refactored `pattern_matches_native`, `pattern_find_native`, `pattern_find_all_native`, `native_pattern_replace`, and `native_pattern_split` to use `check_arg_count`, `expect_text`, and `expect_pattern` helpers, removing redundant match blocks and `.to_string()` allocations in error messages.
- Reduced static key allocations by replacing `.to_string()` with `String::from()` in hash map insertions within pattern match functions.
- Optimized `native_pattern_split` to eliminate full `O(N)` memory allocation of character-to-byte mappings by using an incremental `char_indices` iterator.
- Updated unit tests in `src/stdlib/pattern_test.rs` to reflect standardized error messages from the helper functions.

Co-authored-by: logbie <1138960+logbie@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings March 8, 2026 09:08
@coderabbitai

coderabbitai Bot commented Mar 8, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR refactors pattern module functions to use shared helper utilities for argument validation and type checking. It introduces a new expect_pattern helper function and updates pattern functions to consistently use helper-based extraction for text and pattern arguments, with standardized error messaging.

Changes

Cohort / File(s) Summary
Helper Utilities
src/stdlib/helpers.rs
Added new expect_pattern function to extract and validate Value::Pattern. Note: Function appears to be declared twice (duplicate definition).
Pattern Module Refactoring
src/stdlib/pattern.rs
Refactored pattern_matches, pattern_find, pattern_find_all, pattern_replace, and pattern_split to use check_arg_count, expect_text, and expect_pattern helpers. Standardized result key assignments with String::from(...). Reworked pattern_split with byte-index aware iteration for accurate text slicing. Integrated Arc-based text handling in value construction.
Test Updates
src/stdlib/pattern_test.rs
Updated error message expectations in tests to align with new helper-based validation messages (e.g., "exactly 2 arguments" → "expects 2 arguments", "First argument" → "Expected text").

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 Helpers unite the pattern quest,
No more scattered checks to contest!
One copy whispers—a pest, a test,
But validation flows its best! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main refactoring objective: eliminating redundancy and allocations in the pattern stdlib module, which aligns with all major changes across the three modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jules-refactor-pattern-stdlib-12956706219001740784

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.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
src/stdlib/pattern.rs (1)

224-226: Dead code can be removed.

This branch is unreachable: if text.is_empty(), then matches.is_empty() would have triggered the early return at lines 160-162. Even if a pattern could match empty text, the condition last_end_byte == text.len() && text.is_empty() simplifies to 0 == 0 && true, which is already handled by the preceding if.

🧹 Suggested cleanup
     // Add any remaining text after the last match
     if last_end_byte < text.len() {
         let part = &text[last_end_byte..];
         parts.push(Value::Text(Arc::from(part)));
-    } else if last_end_byte == text.len() && text.is_empty() {
-        // Should not happen, covered by is_empty check above, but for completeness
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/stdlib/pattern.rs` around lines 224 - 226, Remove the unreachable branch
that checks `else if last_end_byte == text.len() && text.is_empty()` in
src/stdlib/pattern.rs: the early return when `matches.is_empty()` already
handles empty `text`, so delete this conditional and its empty body (cleanup the
surrounding if/else to preserve flow in the function that contains
`last_end_byte`, `text`, and `matches`).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/stdlib/pattern.rs`:
- Around line 224-226: Remove the unreachable branch that checks `else if
last_end_byte == text.len() && text.is_empty()` in src/stdlib/pattern.rs: the
early return when `matches.is_empty()` already handles empty `text`, so delete
this conditional and its empty body (cleanup the surrounding if/else to preserve
flow in the function that contains `last_end_byte`, `text`, and `matches`).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fbfdd2e5-843a-4630-a720-9da6c23b2a63

📥 Commits

Reviewing files that changed from the base of the PR and between 6a37448 and 48bf566.

📒 Files selected for processing (3)
  • src/stdlib/helpers.rs
  • src/stdlib/pattern.rs
  • src/stdlib/pattern_test.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48bf566868

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/stdlib/pattern.rs
Comment on lines +221 to 223
if last_end_byte < text.len() {
let part = &text[last_end_byte..];
parts.push(Value::Text(Arc::from(part)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve trailing empty part when split ends with a match

This new tail-handling condition drops the final empty element whenever the last pattern match reaches the end of the string (for example, splitting "a,b," on "," now returns ["a","b"] instead of ["a","b",""]). The previous implementation included that trailing empty segment, which is important for round-tripping delimiter-separated data and for parity with existing split behavior in the codebase, so this is a user-visible regression in pattern_split results for inputs with trailing delimiters.

Useful? React with 👍 / 👎.

@devin-ai-integration devin-ai-integration Bot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

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 refactors the pattern standard library module (src/stdlib/pattern.rs) to eliminate boilerplate code for argument validation and type extraction by leveraging shared helper functions from src/stdlib/helpers.rs. It also replaces the O(N) Vec<usize> allocation in native_pattern_split with an incremental char_indices() iterator approach.

Changes:

  • Added a new expect_pattern helper function in src/stdlib/helpers.rs that extracts a compiled pattern from a Value, following the same pattern as the existing expect_text helper.
  • Refactored all pattern native functions (pattern_matches_native, pattern_find_native, pattern_find_all_native, native_pattern_replace, native_pattern_split) to use check_arg_count, expect_text, and expect_pattern instead of inline validation, and replaced .to_string() on string keys with String::from().
  • Optimized native_pattern_split to use an incremental char_indices() iterator for character-to-byte index conversion, eliminating the previous full Vec<usize> collection, and updated test expectations to match the new standardized error messages.

Reviewed changes

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

File Description
src/stdlib/helpers.rs Added expect_pattern helper with Rc<CompiledPattern> extraction and documentation
src/stdlib/pattern.rs Replaced inline validation with shared helpers; optimized native_pattern_split char-to-byte conversion
src/stdlib/pattern_test.rs Updated expected error message strings to match new standardized helper output

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

Comment thread src/stdlib/pattern.rs
Comment on lines +224 to +225
} else if last_end_byte == text.len() && text.is_empty() {
// Should not happen, covered by is_empty check above, but for completeness

Copilot AI Mar 8, 2026

Copy link

Choose a reason for hiding this comment

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

This else if branch has an empty body and is dead code. The condition last_end_byte == text.len() && text.is_empty() can never be true here because: (1) if text is empty, find_all would either return no matches (handled by the early return at line 160) or return zero-width matches where last_end_byte would be 0 == text.len() — but the branch body does nothing anyway. The comment "covered by is_empty check above" is also misleading since the check above is matches.is_empty(), not text.is_empty(). Consider removing this dead else if branch entirely for clarity.

Suggested change
} else if last_end_byte == text.len() && text.is_empty() {
// Should not happen, covered by is_empty check above, but for completeness

Copilot uses AI. Check for mistakes.
Comment thread src/stdlib/pattern.rs
Comment on lines +165 to +167
// Extract matched text from match result directly using matched_text
// Or slice using byte offsets. However, MatchResult currently only has `start` and `end` character indices.
// In Rust, using `.char_indices()` incrementally is more efficient than building a full vector.

Copilot AI Mar 8, 2026

Copy link

Choose a reason for hiding this comment

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

This multi-line comment is somewhat rambling and confusing. Line 165 mentions "Extract matched text from match result directly using matched_text" which suggests using match_result.matched_text directly, but the code below doesn't use matched_text at all — it slices using byte offsets. The comment on line 166 says "Or slice using byte offsets" as if presenting an alternative, but that's what the code actually does. Consider replacing these three lines with a single clear comment like: "Convert character indices from MatchResult to byte offsets using an incremental char_indices() iterator, avoiding a full Vec allocation."

Suggested change
// Extract matched text from match result directly using matched_text
// Or slice using byte offsets. However, MatchResult currently only has `start` and `end` character indices.
// In Rust, using `.char_indices()` incrementally is more efficient than building a full vector.
// Convert character indices from MatchResult to byte offsets using an incremental char_indices() iterator, avoiding a full Vec allocation.

Copilot uses AI. Check for mistakes.
@logbie

logbie commented Mar 27, 2026

Copy link
Copy Markdown
Collaborator Author

Closing: bot-generated PR, cleaning up duplicates.

@logbie logbie closed this Mar 27, 2026
@logbie
logbie deleted the jules-refactor-pattern-stdlib-12956706219001740784 branch June 19, 2026 04:06
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