From 9b7ceb2a392a236c34d2c832c04e8bf0be2d98b1 Mon Sep 17 00:00:00 2001 From: SayanthRock <202829406+SayanthRock@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:14:56 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[performance=20improvement]?= =?UTF-8?q?=20Replace=20char=5Findices=20with=20optimized=20scanning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .jules/bolt.md | 3 +++ compiler/rockql-parser/src/lib.rs | 27 +++++++++++++-------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 3644ef5..aca28d8 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -6,3 +6,6 @@ **Learning:** In `split_segments`, constructing `Segment` previously performed `text.to_owned()` for every split segment. This caused unnecessary memory allocation, as the parsed segment string could just borrow from the original input `&str`. **Action:** Update parsing intermediate structs (like `Segment`) to carry string slices (`&'a str`) representing chunks of the input string rather than owning `String`s when they are only used briefly to route segments to transformation parsers. +## 2024-08-14 - [Rust String Parsing - Whitespace Semantics Regression] +**Learning:** When optimizing whitespace scanning in Rust parsing loops by replacing `.char_indices()` with byte-level ASCII checks (e.g., `as_bytes().iter().position(|b| b.is_ascii_whitespace())`), it can introduce a subtle functional regression. Rust's `char::is_whitespace()` matches all Unicode whitespace characters (like non-breaking spaces), whereas `is_ascii_whitespace()` only matches standard ASCII whitespace. +**Action:** When exact Unicode semantics must be preserved while optimizing, use `.find()` (e.g., `text.find(char::is_whitespace)`) instead of dropping down to byte-level operations. This leverages internal optimizations while preserving the exact semantic meaning of the original code. diff --git a/compiler/rockql-parser/src/lib.rs b/compiler/rockql-parser/src/lib.rs index 1ddfaa9..312944d 100644 --- a/compiler/rockql-parser/src/lib.rs +++ b/compiler/rockql-parser/src/lib.rs @@ -70,16 +70,16 @@ fn split_segments(source: &str) -> Vec> { for (line_index, line) in source.lines().enumerate() { let mut start = 0; - for (byte_index, character) in line.char_indices() { - if character == '|' { - push_segment( - &mut segments, - &line[start..byte_index], - line_index + 1, - start, - ); - start = byte_index + character.len_utf8(); - } + // ⚡ Bolt Optimization: Use `match_indices` instead of `char_indices` + // to avoid UTF-8 decoding overhead when searching for an ASCII character. + for (byte_index, _) in line.match_indices('|') { + push_segment( + &mut segments, + &line[start..byte_index], + line_index + 1, + start, + ); + start = byte_index + 1; // '|' is 1 byte } push_segment(&mut segments, &line[start..], line_index + 1, start); @@ -102,10 +102,9 @@ fn push_segment<'a>(segments: &mut Vec>, raw: &'a str, line: usize, } fn parse_transform(text: &str, span: Span) -> Result { - let keyword_end = text - .char_indices() - .find_map(|(index, character)| character.is_whitespace().then_some(index)) - .unwrap_or(text.len()); + // ⚡ Bolt Optimization: Use `find(char::is_whitespace)` instead of `char_indices` + // to optimize whitespace scanning while preserving exact Unicode whitespace semantics. + let keyword_end = text.find(char::is_whitespace).unwrap_or(text.len()); let keyword = &text[..keyword_end]; let rest = text[keyword_end..].trim();