From 52a0665acbbe5bf5b8c6875118fb9cdf7952453b Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 17 Aug 2026 06:43:52 +0900 Subject: refactor(preg): wrap the preg_* $matches maps in newtypes The five IndexMap shapes that the preg_* functions and Preg fill in are now distinct types generated by preg_match_map!, so a matches map no longer interchanges with any other map of the same key and value type. Index is kept alongside Index<&Q> because call sites such as config_command and event_dispatcher reach for a group by its position in the map rather than by its capture key. --- crates/shirabe/src/util/composer_mirror.rs | 6 +++--- crates/shirabe/src/util/filesystem.rs | 5 ++--- crates/shirabe/src/util/forgejo_url.rs | 3 +-- crates/shirabe/src/util/git.rs | 16 ++++++++-------- crates/shirabe/src/util/github.rs | 4 ++-- crates/shirabe/src/util/hg.rs | 4 ++-- crates/shirabe/src/util/http/response.rs | 3 +-- crates/shirabe/src/util/http_downloader.rs | 4 ++-- crates/shirabe/src/util/platform.rs | 4 ++-- crates/shirabe/src/util/process_executor.rs | 6 +++--- crates/shirabe/src/util/remote_filesystem.rs | 4 ++-- crates/shirabe/src/util/svn.rs | 5 ++--- crates/shirabe/src/util/url.rs | 9 ++++----- 13 files changed, 34 insertions(+), 39 deletions(-) (limited to 'crates/shirabe/src/util') diff --git a/crates/shirabe/src/util/composer_mirror.rs b/crates/shirabe/src/util/composer_mirror.rs index 1e57662a..1455613d 100644 --- a/crates/shirabe/src/util/composer_mirror.rs +++ b/crates/shirabe/src/util/composer_mirror.rs @@ -1,6 +1,6 @@ //! ref: composer/src/Composer/Util/ComposerMirror.php -use shirabe_pcre::{CaptureKey, Preg}; +use shirabe_pcre::{CaptureKey, Preg, PregMatchedGroups}; use shirabe_php_shim::{hash, php_regex}; pub struct ComposerMirror; @@ -53,8 +53,8 @@ impl ComposerMirror { url: &str, r#type: Option<&str>, ) -> String { - let mut gh_matches: indexmap::IndexMap = indexmap::IndexMap::new(); - let mut bb_matches: indexmap::IndexMap = indexmap::IndexMap::new(); + let mut gh_matches = PregMatchedGroups::new(); + let mut bb_matches = PregMatchedGroups::new(); let normalized_url = if Preg::match3( php_regex!( r"#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#" diff --git a/crates/shirabe/src/util/filesystem.rs b/crates/shirabe/src/util/filesystem.rs index 1a9ab703..21512a81 100644 --- a/crates/shirabe/src/util/filesystem.rs +++ b/crates/shirabe/src/util/filesystem.rs @@ -735,8 +735,7 @@ impl Filesystem { } // extract a prefix being a protocol://, protocol:, protocol://drive: or simply drive: - let mut prefix_match: indexmap::IndexMap = - indexmap::IndexMap::new(); + let mut prefix_match = shirabe_pcre::PregMatchedGroups::new(); if Preg::is_match3( php_regex!("{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix"), &path, @@ -768,7 +767,7 @@ impl Filesystem { // ensure c: is normalized to C: prefix = Preg::replace_callback( php_regex!("{(^|://)[a-z]:$}i"), - |m: &indexmap::IndexMap| -> String { + |m: &shirabe_pcre::PregMatchedGroups| -> String { let s = m .get(&shirabe_pcre::CaptureKey::ByIndex(0)) .cloned() diff --git a/crates/shirabe/src/util/forgejo_url.rs b/crates/shirabe/src/util/forgejo_url.rs index d2628409..7a5d2b10 100644 --- a/crates/shirabe/src/util/forgejo_url.rs +++ b/crates/shirabe/src/util/forgejo_url.rs @@ -37,8 +37,7 @@ impl ForgejoUrl { pub fn try_from(repo_url: Option<&str>) -> Option { let repo_url = repo_url?; - let mut matches: indexmap::IndexMap = - indexmap::IndexMap::new(); + let mut matches = shirabe_pcre::PregMatchedGroups::new(); if !Preg::match3(Self::URL_REGEX, repo_url, Some(&mut matches)) { return None; } diff --git a/crates/shirabe/src/util/git.rs b/crates/shirabe/src/util/git.rs index f8fea562..0f463aea 100644 --- a/crates/shirabe/src/util/git.rs +++ b/crates/shirabe/src/util/git.rs @@ -14,7 +14,7 @@ use crate::util::ProcessExecutor; use crate::util::Url; use crate::util::{AuthHelper, StoreAuth}; use indexmap::IndexMap; -use shirabe_pcre::{CaptureKey, Preg}; +use shirabe_pcre::{CaptureKey, Preg, PregMatchedGroups}; use shirabe_php_shim::{ AnyThrowable, CmpOp, InvalidArgumentException, PHP_EOL, PhpMixed, RuntimeException, array_map, clearstatcache, explode, implode, in_array_loose, in_array_strict, is_dir, php_regex, @@ -226,7 +226,7 @@ impl Git { &mut output, cwd, )?; - let mut m: IndexMap = IndexMap::new(); + let mut m = PregMatchedGroups::new(); if Preg::is_match3( php_regex!(r"{^(?:composer|origin)\s+https?://(.+):(.+)@([^/]+)}im"), &output, @@ -248,7 +248,7 @@ impl Git { let protocols = self.config.borrow_mut().get("github-protocols"); // public github, autoswitch protocols // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups - let mut m: IndexMap = IndexMap::new(); + let mut m = PregMatchedGroups::new(); if Preg::is_match3( format!( "{{^(?:https?|git)://{}/(.*)}}", @@ -344,7 +344,7 @@ impl Git { let mut error_msg = self.process.borrow().get_error_output().to_string(); // private github repository without ssh key access, try https with auth // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups - let mut m: IndexMap = IndexMap::new(); + let mut m = PregMatchedGroups::new(); let github_matched = Preg::is_match3( format!( "{{^git@{}:(.+?)\\.git$}}i", @@ -1089,8 +1089,8 @@ impl Git { Ok(false) } - fn get_authentication_failure(&self, url: &str) -> Option> { - let mut m: IndexMap = IndexMap::new(); + fn get_authentication_failure(&self, url: &str) -> Option { + let mut m = PregMatchedGroups::new(); if !Preg::is_match3( php_regex!(r"{^(https?://)([^/]+)(.*)$}i"), url, @@ -1179,7 +1179,7 @@ impl Git { .borrow() .split_lines(output_mixed.as_string().unwrap_or("")); for line in lines { - let mut matches: IndexMap = IndexMap::new(); + let mut matches = PregMatchedGroups::new(); if Preg::is_match3( php_regex!(r"{^\s*HEAD branch:\s(.+)\s*$}m"), &line, @@ -1308,7 +1308,7 @@ impl Git { Option::<&str>::None, ); if exit_code == 0 { - let mut matches: IndexMap = IndexMap::new(); + let mut matches = PregMatchedGroups::new(); if Preg::is_match3( php_regex!(r"/^git version (\d+(?:\.\d+)+)/m"), &output, diff --git a/crates/shirabe/src/util/github.rs b/crates/shirabe/src/util/github.rs index 25a95e57..b7659572 100644 --- a/crates/shirabe/src/util/github.rs +++ b/crates/shirabe/src/util/github.rs @@ -8,7 +8,7 @@ use crate::io::io_interface; use crate::util::HttpDownloader; use crate::util::ProcessExecutor; use indexmap::IndexMap; -use shirabe_pcre::{CaptureKey, Preg}; +use shirabe_pcre::{CaptureKey, Preg, PregMatchedGroups}; use shirabe_php_shim::Catch as _; use shirabe_php_shim::{PhpMixed, date_local, in_array_loose, php_regex, stripos, strtolower}; @@ -325,7 +325,7 @@ impl GitHub { if stripos(header, "x-github-sso: required").is_none() { continue; } - let mut caps: IndexMap = IndexMap::new(); + let mut caps = PregMatchedGroups::new(); if Preg::match3( php_regex!(r"{\burl=(?P[^\s;]+)}"), header, diff --git a/crates/shirabe/src/util/hg.rs b/crates/shirabe/src/util/hg.rs index f0cc56cc..8570af6d 100644 --- a/crates/shirabe/src/util/hg.rs +++ b/crates/shirabe/src/util/hg.rs @@ -5,7 +5,7 @@ use crate::io::IOInterface; use crate::io::IOInterfaceImmutable; use crate::util::ProcessExecutor; use crate::util::Url; -use shirabe_pcre::Preg; +use shirabe_pcre::{Preg, PregNamedGroups}; use shirabe_php_shim::{php_regex, rawurlencode}; use std::sync::OnceLock; @@ -56,7 +56,7 @@ impl Hg { } // Try with the authentication information available - let mut matches: indexmap::IndexMap = indexmap::IndexMap::new(); + let mut matches = PregNamedGroups::new(); let matched = Preg::is_match_named( php_regex!( r"{^(?Pssh|https?)://(?:(?P[^:@]+)(?::(?P[^:@]+))?@)?(?P[^/]+)(?P/.*)?}mi" diff --git a/crates/shirabe/src/util/http/response.rs b/crates/shirabe/src/util/http/response.rs index 47a1593f..6ce52643 100644 --- a/crates/shirabe/src/util/http/response.rs +++ b/crates/shirabe/src/util/http/response.rs @@ -65,8 +65,7 @@ impl Response { let mut value = None; let pattern = format!("{{^{}:\\s*(.+?)\\s*$}}i", preg_quote(name, None)); for header in headers { - let mut matches: indexmap::IndexMap = - indexmap::IndexMap::new(); + let mut matches = shirabe_pcre::PregMatchedGroups::new(); if Preg::match3(&pattern, header, Some(&mut matches)) && let Some(s) = matches.get(&shirabe_pcre::CaptureKey::ByIndex(1)) { diff --git a/crates/shirabe/src/util/http_downloader.rs b/crates/shirabe/src/util/http_downloader.rs index c8fb943b..c478d445 100644 --- a/crates/shirabe/src/util/http_downloader.rs +++ b/crates/shirabe/src/util/http_downloader.rs @@ -16,7 +16,7 @@ use crate::util::http::CurlDownloader; use crate::util::http::Response; use crate::util::sync_executor; use indexmap::IndexMap; -use shirabe_pcre::{CaptureKey, Preg}; +use shirabe_pcre::{CaptureKey, Preg, PregMatchedGroups}; use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ InvalidArgumentException, LogicException, PhpMixed, array_replace_recursive, extension_loaded, @@ -240,7 +240,7 @@ impl HttpDownloader { let origin = Url::get_origin(&self.config.borrow(), url); // capture username/password from URL if there is one - let mut m: IndexMap = IndexMap::new(); + let mut m = PregMatchedGroups::new(); if Preg::is_match3( php_regex!(r"{^https?://([^:/]+):([^@/]+)@([^/]+)}i"), url, diff --git a/crates/shirabe/src/util/platform.rs b/crates/shirabe/src/util/platform.rs index 4336de53..21ad869c 100644 --- a/crates/shirabe/src/util/platform.rs +++ b/crates/shirabe/src/util/platform.rs @@ -2,7 +2,7 @@ use crate::util::ProcessExecutor; use crate::util::Silencer; -use shirabe_pcre::Preg; +use shirabe_pcre::{Preg, PregMatchedGroups}; use shirabe_php_shim::{ PHP_ENV, PHP_SERVER, PhpMixed, PhpResource, RuntimeException, defined, file_exists, file_get_contents, fstat, function_exists, getcwd, getenv, ini_get, is_readable, mb_strlen, @@ -99,7 +99,7 @@ impl Platform { // not participate is reported as an empty string, which `\w+` can never capture. Preg::replace_callback( php_regex!(r"#^(?:\$(?P\w+)|%(?P\w+)%)(?P.*)#"), - |matches: &indexmap::IndexMap| -> String { + |matches: &PregMatchedGroups| -> String { let var = matches .get(&CaptureKey::ByName("dvar".to_string())) .filter(|dvar| !dvar.is_empty()) diff --git a/crates/shirabe/src/util/process_executor.rs b/crates/shirabe/src/util/process_executor.rs index fc67604e..d87e2ff4 100644 --- a/crates/shirabe/src/util/process_executor.rs +++ b/crates/shirabe/src/util/process_executor.rs @@ -7,7 +7,7 @@ use crate::signal::SignalSubscription; use crate::util::GitHub; use crate::util::Platform; use indexmap::IndexMap; -use shirabe_pcre::{CaptureKey, Preg}; +use shirabe_pcre::{CaptureKey, Preg, PregMatchedGroups}; use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ LogicException, PHP_EOL, PhpMixed, RuntimeException, array_intersect, array_map, @@ -217,7 +217,7 @@ impl ProcessExecutor { if is_string(&command) { let mut command_str = command.as_string().unwrap_or("").to_string(); if Platform::is_windows() { - let mut m: IndexMap = IndexMap::new(); + let mut m = PregMatchedGroups::new(); if Preg::is_match3(php_regex!(r"{^([^:/\\]++) }"), &command_str, Some(&mut m)) { let m1 = m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default(); command_str = substr_replace( @@ -832,7 +832,7 @@ impl ProcessExecutor { }; let safe_command = Preg::replace_callback( php_regex!(r"{://(?P[^:/\s]+):(?P[^@\s/]+)@}i"), - |m: &IndexMap| -> String { + |m: &PregMatchedGroups| -> String { let user_key = CaptureKey::ByName("user".to_string()); // if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx, github_pat_xxx) we obfuscate that if Preg::is_match( diff --git a/crates/shirabe/src/util/remote_filesystem.rs b/crates/shirabe/src/util/remote_filesystem.rs index 4a8ca267..40a69f28 100644 --- a/crates/shirabe/src/util/remote_filesystem.rs +++ b/crates/shirabe/src/util/remote_filesystem.rs @@ -13,7 +13,7 @@ use crate::util::Url; use crate::util::http::ProxyManager; use crate::util::http::Response; use indexmap::IndexMap; -use shirabe_pcre::{CaptureKey, Preg}; +use shirabe_pcre::{CaptureKey, Preg, PregMatchedGroups}; use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ PhpMixed, RuntimeException, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_FILE_SIZE_IS, @@ -148,7 +148,7 @@ impl RemoteFilesystem { pub fn find_status_code(headers: &[String]) -> Option { let mut value: Option = None; for header in headers { - let mut m: IndexMap = IndexMap::new(); + let mut m = PregMatchedGroups::new(); if Preg::is_match3(php_regex!("{^HTTP/\\S+ (\\d+)}i"), header, Some(&mut m)) { value = m .get(&CaptureKey::ByIndex(1)) diff --git a/crates/shirabe/src/util/svn.rs b/crates/shirabe/src/util/svn.rs index 9662c24d..d07b3ffe 100644 --- a/crates/shirabe/src/util/svn.rs +++ b/crates/shirabe/src/util/svn.rs @@ -6,8 +6,7 @@ use crate::io::IOInterfaceImmutable; use crate::io::io_interface; use crate::util::Platform; use crate::util::ProcessExecutor; -use indexmap::IndexMap; -use shirabe_pcre::{CaptureKey, Preg}; +use shirabe_pcre::{CaptureKey, Preg, PregMatchedGroups}; use shirabe_php_shim::{ LogicException, PhpMixed, RuntimeException, implode, parse_url, php_regex, stripos, strpos, trim, @@ -407,7 +406,7 @@ impl Svn { &mut output, None, ) { - let mut matches: IndexMap = IndexMap::new(); + let mut matches = PregMatchedGroups::new(); if Preg::is_match3( php_regex!(r"{(\d+(?:\.\d+)+)}"), &output, diff --git a/crates/shirabe/src/util/url.rs b/crates/shirabe/src/util/url.rs index ea9e4401..3afcd962 100644 --- a/crates/shirabe/src/util/url.rs +++ b/crates/shirabe/src/util/url.rs @@ -2,8 +2,7 @@ use crate::config::Config; use crate::util::GitHub; -use indexmap::IndexMap; -use shirabe_pcre::{CaptureKey, Preg}; +use shirabe_pcre::{CaptureKey, Preg, PregMatchedGroups}; use shirabe_php_shim::{PhpMixed, in_array_strict, parse_url, php_regex}; pub struct Url; @@ -15,7 +14,7 @@ impl Url { .unwrap_or_default(); if host == "api.github.com" || host == "github.com" || host == "www.github.com" { - let mut m: IndexMap = IndexMap::new(); + let mut m = PregMatchedGroups::new(); if Preg::match3( php_regex!( r"{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/(zip|tar)ball/(.+)$}i" @@ -60,7 +59,7 @@ impl Url { ); } } else if host == "bitbucket.org" || host == "www.bitbucket.org" { - let mut m: IndexMap = IndexMap::new(); + let mut m = PregMatchedGroups::new(); if Preg::match3( php_regex!( r"{^https?://(?:www\.)?bitbucket\.org/([^/]+)/([^/]+)/get/(.+)\.(zip|tar\.gz|tar\.bz2)$}i" @@ -77,7 +76,7 @@ impl Url { ); } } else if host == "gitlab.com" || host == "www.gitlab.com" { - let mut m: IndexMap = IndexMap::new(); + let mut m = PregMatchedGroups::new(); if Preg::match3( php_regex!( r"{^https?://(?:www\.)?gitlab\.com/api/v[34]/projects/([^/]+)/repository/archive\.(zip|tar\.gz|tar\.bz2|tar)\?sha=.+$}i" -- cgit v1.3.1-4-g156e