From e068a9d644fde6659a88accd55b3f1d0d9d7cf46 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 23 May 2026 03:07:15 +0900 Subject: refactor(promise): rewrite promise bodies to async/await Mechanically convert promise-returning function bodies to async/await: resolve() returns the value directly, forwarding calls get .await, and simple .then chains become await sequences. Also collapse the installer double-Option (Result>> -> Result>). Hard spots that depend on the Loop::wait / job-machine boundary (accept/reject orchestration, closures capturing &mut self, batch waits) are left intact and marked with TODO(phase-c-promise) for manual porting. The crate does not compile yet; traits still need #[async_trait]. Co-Authored-By: Claude Opus 4.7 --- .../shirabe/src/repository/composer_repository.rs | 107 +++++++++------------ 1 file changed, 48 insertions(+), 59 deletions(-) (limited to 'crates/shirabe/src/repository') diff --git a/crates/shirabe/src/repository/composer_repository.rs b/crates/shirabe/src/repository/composer_repository.rs index 7601117..3c5eb31 100644 --- a/crates/shirabe/src/repository/composer_repository.rs +++ b/crates/shirabe/src/repository/composer_repository.rs @@ -1103,6 +1103,9 @@ impl ComposerRepository { .map_or(false, |c| c.metadata) && (allow_partial_advisories || api_url.is_none()) { + // TODO(phase-c-promise): collects start_cached_async_download().then_boxed() promises and + // drives them via Loop::wait; rewrite to await the collected futures once the async Loop + // boundary lands. let mut promises: Vec> = Vec::new(); let names: Vec = package_constraint_map.keys().cloned().collect(); for name in names { @@ -1848,6 +1851,9 @@ impl ComposerRepository { let mut packages: IndexMap> = IndexMap::new(); let mut names_found: IndexMap = IndexMap::new(); + // TODO(phase-c-promise): collects start_cached_async_download().then_boxed() promises and + // drives them via Loop::wait; rewrite to await the collected futures once the async Loop + // boundary lands. let mut promises: Vec> = Vec::new(); if self.lazy_providers_url.is_none() { @@ -2131,62 +2137,43 @@ impl ComposerRepository { contents_opt = None; } - let promise = self.async_fetch_file(&url, &cache_key, last_modified.as_deref())?; - let url_owned = url.clone(); - let cache_key_owned = cache_key.clone(); - let contents = contents_opt; - // TODO(phase-b): then_boxed expects closure returning Box, - // not anyhow::Result; needs structural reshape - Ok(promise.then_boxed( - Some(Box::new( - move |response: PhpMixed| -> Box { - let _result: anyhow::Result = (|| -> anyhow::Result { - let mut packages_source = - format!("downloaded file ({})", Url::sanitize(url_owned.clone())); - - let response_data = if response.as_bool() == Some(true) { - packages_source = format!( - "cached file ({} originating from {})", - cache_key_owned, - Url::sanitize(url_owned.clone()) - ); - contents - .clone() - .map(|m| { - PhpMixed::Array( - m.into_iter().map(|(k, v)| (k, Box::new(v))).collect(), - ) - }) - .unwrap_or(PhpMixed::Null) - } else { - response - }; + // PHP: return $this->asyncFetchFile(...)->then(function ($response) use (...): array { ... }); + let response = self + .async_fetch_file(&url, &cache_key, last_modified.as_deref()) + .await?; - let response_arr = response_data.as_array(); - let has_pkg = response_arr - .and_then(|a| a.get("packages")) - .and_then(|v| v.as_array()) - .map_or(false, |a| a.contains_key(&package_name)); - let has_advisories = - response_arr.map_or(false, |a| a.contains_key("security-advisories")); - if !has_pkg && !has_advisories { - return Ok(PhpMixed::List(vec![ - Box::new(PhpMixed::Null), - Box::new(PhpMixed::String(packages_source)), - ])); - } + let mut packages_source = format!("downloaded file ({})", Url::sanitize(url.clone())); - Ok(PhpMixed::List(vec![ - Box::new(response_data), - Box::new(PhpMixed::String(packages_source)), - ])) - })(); - // TODO(phase-b): return a real PromiseInterface - todo!("return real PromiseInterface") - }, - )), - None, - )) + let response_data = if response.as_bool() == Some(true) { + packages_source = format!( + "cached file ({} originating from {})", + cache_key, + Url::sanitize(url.clone()) + ); + contents_opt + .map(|m| PhpMixed::Array(m.into_iter().map(|(k, v)| (k, Box::new(v))).collect())) + .unwrap_or(PhpMixed::Null) + } else { + response + }; + + let response_arr = response_data.as_array(); + let has_pkg = response_arr + .and_then(|a| a.get("packages")) + .and_then(|v| v.as_array()) + .map_or(false, |a| a.contains_key(&package_name)); + let has_advisories = response_arr.map_or(false, |a| a.contains_key("security-advisories")); + if !has_pkg && !has_advisories { + return Ok(PhpMixed::List(vec![ + Box::new(PhpMixed::Null), + Box::new(PhpMixed::String(packages_source)), + ])); + } + + Ok(PhpMixed::List(vec![ + Box::new(response_data), + Box::new(PhpMixed::String(packages_source)), + ])) } /// @param name package name (must be lowercased already) @@ -3293,18 +3280,20 @@ impl ComposerRepository { if self.packagesNotFoundCache.contains_key(filename) { let mut empty: IndexMap = IndexMap::new(); empty.insert("packages".to_string(), PhpMixed::Array(IndexMap::new())); - return Ok(react_promise_resolve(PhpMixed::Array( + return Ok(PhpMixed::Array( empty.into_iter().map(|(k, v)| (k, Box::new(v))).collect(), - ))); + )); } if self.freshMetadataUrls.contains_key(filename) && last_modified_time.is_some() { // make it look like we got a 304 response - let promise = react_promise_resolve(PhpMixed::Bool(true)); - - return Ok(promise); + return Ok(PhpMixed::Bool(true)); } + // TODO(phase-c-promise): the live fetch path builds accept/reject closures (with raw-pointer + // shared state) and returns http_downloader.add(...).then_with_reject_boxed(accept, reject). + // Rewrite as an async fetch + inline accept/reject handling once the HttpDownloader async + // boundary lands. let mut filename = filename.to_string(); let mut options = self.options.clone(); if let Some(dispatcher) = self.event_dispatcher.as_ref() { -- cgit v1.3.1