From 6aeda8b237fcbf7a56ca0e8c0fff415477d31d22 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Tue, 18 Aug 2026 01:57:02 +0900 Subject: refactor(preg): make preg_match_all yield matches per occurrence PHP's PREG_PATTERN_ORDER is column-oriented, but 7 of the 10 call sites read it row-wise, rebuilding each occurrence by indexing every column at the same offset. Return an iterator of PregMatches instead, which is also what the set-order and offset-capture variants were carrying, so the three functions collapse into one and PregMatchesAll, PregMatchesAllWithOffsets, CaptureKey and preg_match_map! all go away. The offset-capture call sites are served by the new PregMatches get_offset/name_offset accessors. The search stays eager: regex::Captures borrows only the subject, so the matches outlive the pattern resolved for the call, and PHP's preg_match_all is eager too. Co-Authored-By: Claude Opus 5 (1M context) --- crates/shirabe/src/downloader/git_downloader.rs | 45 +++++++++++++------------ 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'crates/shirabe/src/downloader') diff --git a/crates/shirabe/src/downloader/git_downloader.rs b/crates/shirabe/src/downloader/git_downloader.rs index a8a4344d..2d506fdf 100644 --- a/crates/shirabe/src/downloader/git_downloader.rs +++ b/crates/shirabe/src/downloader/git_downloader.rs @@ -18,10 +18,9 @@ use crate::util::ProcessExecutor; use crate::util::Url; use indexmap::IndexMap; use shirabe_php_shim::{ - CaptureKey, CmpOp, PhpMixed, RuntimeException, array_map, basename, dirname, impl_php_class, - implode, in_array_strict, is_dir, php_regex, preg_is_match, preg_match, preg_match_all, - preg_quote, preg_replace, preg_split, realpath, rtrim, strlen, strpos, substr, trim, - version_compare, + CmpOp, PhpMixed, RuntimeException, array_map, basename, dirname, impl_php_class, implode, + in_array_strict, is_dir, php_regex, preg_is_match, preg_match, preg_match_all, preg_quote, + preg_replace, preg_split, realpath, rtrim, strlen, strpos, substr, trim, version_compare, }; #[derive(Debug)] @@ -101,21 +100,21 @@ impl GitDownloader { }; let head_ref = head_match.get(1).unwrap_or_default().to_string(); - let branches_match = preg_match_all( + let candidate_branches: Vec = preg_match_all( format!("{{^{} refs/heads/(.+)$}}mi", preg_quote(&head_ref, None)), &refs, - ); - if branches_match.occurrence_count() == 0 { + ) + .map(|branch_match| { + branch_match + .get(1) + .expect("group 1 participates whenever the pattern matches") + .to_string() + }) + .collect(); + if candidate_branches.is_empty() { // not on a branch, we are either on a not-modified tag or some sort of detached head, so skip this return Ok(None); } - let candidate_branches: Vec = branches_match - .get(&CaptureKey::ByIndex(1)) - .cloned() - .unwrap_or_default() - .into_iter() - .map(|branch| branch.expect("group 1 participates whenever the pattern matches")) - .collect(); // use the first match as branch name for now let mut branch = candidate_branches[0].clone(); @@ -128,21 +127,23 @@ impl GitDownloader { // try to find matching branch names in remote repos for candidate in &candidate_branches { - let m = preg_match_all( + let matches: Vec = preg_match_all( format!( "{{^[a-f0-9]+ refs/remotes/((?:[^/]+)/{})$}}mi", preg_quote(candidate, None) ), &refs, - ); - if m.occurrence_count() > 0 { - let matches: Vec> = - m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default(); + ) + .map(|m| { + m.get(1) + .expect("group 1 participates whenever the pattern matches") + .to_string() + }) + .collect(); + if !matches.is_empty() { for match_ in matches { branch = candidate.clone(); - remote_branches.push( - match_.expect("group 1 participates whenever the pattern matches"), - ); + remote_branches.push(match_); } break; } -- cgit v1.3.1-4-g156e