From 79b504e55cd4c4d1da102c3a076dc2a2e1edcd65 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 17 Aug 2026 08:05:42 +0900 Subject: refactor(pcre): return the Preg $matches instead of filling an out-param `Composer\Pcre\Preg` fills `$matches` through a by-ref parameter, and the port mirrored that with a `&mut` (or `Option<&mut>`) out-param plus a bool or count return. Callers had to declare an empty map one line ahead of the call, and the type never said the map is only meaningful when the call matched. Return the matches instead: - match3/match4/is_match3/is_match4 -> Option - is_match_named -> Option - match_all2/is_match_all -> PregMatchesAll - is_match_all_with_offsets3 -> PregMatchesAllWithOffsets Nothing is lost: the bool is `Option::is_some()`, and the occurrence count is the length of any one column of a PREG_PATTERN_ORDER map, now spelled `PregMatchesAll::occurrence_count()`. is_match() still answers the bool question directly for callers that want no groups. Co-Authored-By: Claude Opus 5 (1M context) --- crates/shirabe-pcre/src/preg.rs | 107 +++++++++++----------------------------- 1 file changed, 28 insertions(+), 79 deletions(-) (limited to 'crates/shirabe-pcre') diff --git a/crates/shirabe-pcre/src/preg.rs b/crates/shirabe-pcre/src/preg.rs index dd6e4950..25feafc9 100644 --- a/crates/shirabe-pcre/src/preg.rs +++ b/crates/shirabe-pcre/src/preg.rs @@ -32,58 +32,31 @@ preg_match_map! { pub struct Preg; impl Preg { - pub fn match3( - pattern: impl PregPattern, - subject: &str, - matches: Option<&mut PregMatchedGroups>, - ) -> bool { - Self::match4(pattern, subject, matches, 0) + pub fn match3(pattern: impl PregPattern, subject: &str) -> Option { + Self::match4(pattern, subject, 0) } pub fn match4( pattern: impl PregPattern, subject: &str, - matches: Option<&mut PregMatchedGroups>, offset: usize, - ) -> bool { - let internal = preg_match2(pattern, subject, offset); - - if let Some(out) = matches { - *out = match &internal { - Some(internal) => drop_null_matches(internal), - None => PregMatchedGroups::new(), - }; - } - - internal.is_some() + ) -> Option { + preg_match2(pattern, subject, offset).map(|internal| drop_null_matches(&internal)) } pub fn match_all(pattern: impl PregPattern, subject: &str) -> usize { - occurrence_count(&preg_match_all2(pattern, subject)) + Self::match_all2(pattern, subject).occurrence_count() } - pub fn match_all2( - pattern: impl PregPattern, - subject: &str, - matches: &mut PregMatchesAll, - ) -> usize { - *matches = preg_match_all2(pattern, subject); - occurrence_count(matches) + pub fn match_all2(pattern: impl PregPattern, subject: &str) -> PregMatchesAll { + preg_match_all2(pattern, subject) } fn match_all_with_offsets5( pattern: impl PregPattern, subject: &str, - matches: Option<&mut PregMatchesAllWithOffsets>, - ) -> usize { - let internal = preg_match_all_offset_capture(pattern, subject); - let count = internal[&CaptureKey::ByIndex(0)].len(); - - if let Some(out) = matches { - *out = internal; - } - - count + ) -> PregMatchesAllWithOffsets { + preg_match_all_offset_capture(pattern, subject) } pub fn replace(pattern: impl PregPattern, replacement: &str, subject: &str) -> String { @@ -127,44 +100,31 @@ impl Preg { } pub fn is_match(pattern: impl PregPattern, subject: &str) -> bool { - Self::match4(pattern, subject, None, 0) + Self::match4(pattern, subject, 0).is_some() } - pub fn is_match3( - pattern: impl PregPattern, - subject: &str, - matches: Option<&mut PregMatchedGroups>, - ) -> bool { - Self::match4(pattern, subject, matches, 0) + pub fn is_match3(pattern: impl PregPattern, subject: &str) -> Option { + Self::match4(pattern, subject, 0) } pub fn is_match4( pattern: impl PregPattern, subject: &str, - matches: Option<&mut PregMatchedGroups>, offset: usize, - ) -> bool { - Self::match4(pattern, subject, matches, offset) + ) -> Option { + Self::match4(pattern, subject, offset) } - pub fn is_match_named( - pattern: impl PregPattern, - subject: &str, - matches: &mut PregNamedGroups, - ) -> bool { - let internal = preg_match2(pattern, subject, 0); - let result = internal.is_some(); - - matches.clear(); - if let Some(internal) = internal { - for (key, value) in internal { - if let (CaptureKey::ByName(name), Some(value)) = (key, value) { - matches.insert(name, value); - } - } - } - - result + pub fn is_match_named(pattern: impl PregPattern, subject: &str) -> Option { + Some( + preg_match2(pattern, subject, 0)? + .into_iter() + .filter_map(|(key, value)| match (key, value) { + (CaptureKey::ByName(name), Some(value)) => Some((name, value)), + _ => None, + }) + .collect(), + ) } /// `is_match3` with the groups positioned by number rather than keyed, for callers that only @@ -184,20 +144,15 @@ impl Preg { ) } - pub fn is_match_all( - pattern: impl PregPattern, - subject: &str, - matches: &mut PregMatchesAll, - ) -> bool { - Self::match_all2(pattern, subject, matches) > 0 + pub fn is_match_all(pattern: impl PregPattern, subject: &str) -> PregMatchesAll { + Self::match_all2(pattern, subject) } pub fn is_match_all_with_offsets3( pattern: impl PregPattern, subject: &str, - matches: Option<&mut PregMatchesAllWithOffsets>, - ) -> bool { - Self::match_all_with_offsets5(pattern, subject, matches) > 0 + ) -> PregMatchesAllWithOffsets { + Self::match_all_with_offsets5(pattern, subject) } } @@ -209,9 +164,3 @@ fn drop_null_matches(matches: &PregMatches) -> PregMatchedGroups { .filter_map(|(key, value)| value.clone().map(|value| (key.clone(), value))) .collect() } - -// PHP's `preg_match_all` returns the number of occurrences; every column of a -// PREG_PATTERN_ORDER map holds one entry per occurrence. -fn occurrence_count(matches: &PregMatchesAll) -> usize { - matches[&CaptureKey::ByIndex(0)].len() -} -- cgit v1.3.1-4-g156e