From eea4efe87e455742ec17881ee93d8095925e8516 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Thu, 28 May 2026 22:43:11 +0900 Subject: refactor(repository): introduce Rc> handles for repositories Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/shirabe/src/package/alias_package.rs | 24 ++++++------ crates/shirabe/src/package/base_package.rs | 17 +++------ crates/shirabe/src/package/complete_package.rs | 8 ++-- crates/shirabe/src/package/handle.rs | 10 +++-- crates/shirabe/src/package/package.rs | 51 ++++++++++++++++++------- crates/shirabe/src/package/package_interface.rs | 6 +-- crates/shirabe/src/package/root_package.rs | 10 ++--- 7 files changed, 73 insertions(+), 53 deletions(-) (limited to 'crates/shirabe/src/package') diff --git a/crates/shirabe/src/package/alias_package.rs b/crates/shirabe/src/package/alias_package.rs index 997685b..69e0723 100644 --- a/crates/shirabe/src/package/alias_package.rs +++ b/crates/shirabe/src/package/alias_package.rs @@ -11,14 +11,13 @@ use crate::package::Link; use crate::package::PackageHandle; use crate::package::PackageInterface; use crate::package::version::VersionParser; -use crate::repository::RepositoryInterface; +use crate::repository::RepositoryInterfaceHandle; #[derive(Debug)] pub struct AliasPackage { id: i64, name: String, pretty_name: String, - repository: Option>, /// @var string pub(crate) version: String, @@ -64,7 +63,6 @@ impl AliasPackage { id: -1, name: alias_name.to_lowercase(), pretty_name: alias_name, - repository: None, version, pretty_version, dev, @@ -452,12 +450,12 @@ impl PackageInterface for AliasPackage { self.alias_of.get_pretty_string() } - fn set_repository(&mut self, repository: Box) -> anyhow::Result<()> { + fn set_repository(&mut self, repository: RepositoryInterfaceHandle) -> anyhow::Result<()> { self.alias_of.set_repository(repository) } - fn get_repository(&self) -> Option<&dyn RepositoryInterface> { - todo!("AliasPackage::get_repository cannot return a borrow across the aliasOf handle") + fn get_repository(&self) -> Option { + self.alias_of.get_repository() } } @@ -486,15 +484,17 @@ impl BasePackage for AliasPackage { &mut self.pretty_name } - fn repository_opt(&self) -> Option<&dyn RepositoryInterface> { - self.repository.as_deref() + fn repository_opt(&self) -> Option { + // PHP `AliasPackage::getRepository()` delegates to `$this->aliasOf->getRepository()`. + self.alias_of.get_repository() } - fn set_repository_box(&mut self, repository: Box) { - todo!() + fn set_repository_box(&mut self, repository: RepositoryInterfaceHandle) { + let _ = self.alias_of.set_repository(repository); } - fn take_repository(&mut self) -> Option> { - todo!() + fn take_repository(&mut self) -> Option { + // AliasPackage holds no repository of its own; never mutate the aliased package here. + None } } diff --git a/crates/shirabe/src/package/base_package.rs b/crates/shirabe/src/package/base_package.rs index 64a5919..ca6f171 100644 --- a/crates/shirabe/src/package/base_package.rs +++ b/crates/shirabe/src/package/base_package.rs @@ -8,7 +8,7 @@ use shirabe_php_shim::{LogicException, UnexpectedValueException, preg_quote}; use crate::package::Link; use crate::package::PackageInterface; use crate::repository::PlatformRepository; -use crate::repository::RepositoryInterface; +use crate::repository::RepositoryInterfaceHandle; pub struct SupportedLinkType { pub description: &'static str, @@ -79,15 +79,9 @@ pub trait BasePackage: PackageInterface + std::fmt::Display { fn name_mut(&mut self) -> &mut String; fn pretty_name(&self) -> &str; fn pretty_name_mut(&mut self) -> &mut String; - fn repository_opt(&self) -> Option<&dyn RepositoryInterface>; - fn set_repository_box(&mut self, repository: Box); - fn take_repository(&mut self) -> Option>; - - /// PHP `setRepository($this)` from the containing repository — Rust port marker until - /// the borrow story for repository-package back-references is finalized in phase B. - fn set_repository_self(&mut self) { - // TODO(phase-b): wire up a back-reference to the containing repository when needed. - } + fn repository_opt(&self) -> Option; + fn set_repository_box(&mut self, repository: RepositoryInterfaceHandle); + fn take_repository(&mut self) -> Option; // as_alias_package / as_complete_package_interface inherited from PackageInterface. @@ -104,8 +98,7 @@ pub trait BasePackage: PackageInterface + std::fmt::Display { fn is_platform(&self) -> bool { self.repository_opt() - .and_then(|r| r.as_any().downcast_ref::()) - .is_some() + .map_or(false, |r| r.is::()) } fn equals(&self, _package: &dyn PackageInterface) -> bool { diff --git a/crates/shirabe/src/package/complete_package.rs b/crates/shirabe/src/package/complete_package.rs index b0adf52..a598389 100644 --- a/crates/shirabe/src/package/complete_package.rs +++ b/crates/shirabe/src/package/complete_package.rs @@ -311,13 +311,13 @@ impl PackageInterface for CompletePackage { fn set_repository( &mut self, - repository: Box, + repository: crate::repository::RepositoryInterfaceHandle, ) -> anyhow::Result<()> { - todo!() + self.inner.set_repository(repository) } - fn get_repository(&self) -> Option<&dyn crate::repository::RepositoryInterface> { - todo!() + fn get_repository(&self) -> Option { + self.inner.get_repository() } fn get_binaries(&self) -> Vec { diff --git a/crates/shirabe/src/package/handle.rs b/crates/shirabe/src/package/handle.rs index 931e196..e939c3a 100644 --- a/crates/shirabe/src/package/handle.rs +++ b/crates/shirabe/src/package/handle.rs @@ -273,11 +273,11 @@ macro_rules! delegate_package_interface_to_inner { } fn set_repository( &mut self, - repository: Box, + repository: crate::repository::RepositoryInterfaceHandle, ) -> anyhow::Result<()> { self.$field.set_repository(repository) } - fn get_repository(&self) -> Option<&dyn crate::repository::RepositoryInterface> { + fn get_repository(&self) -> Option { self.$field.get_repository() } fn get_binaries(&self) -> Vec { @@ -588,7 +588,7 @@ macro_rules! impl_package_interface_handle { pub fn set_repository( &self, - repository: Box, + repository: crate::repository::RepositoryInterfaceHandle, ) -> anyhow::Result<()> { self.0 .borrow_mut() @@ -596,6 +596,10 @@ macro_rules! impl_package_interface_handle { .set_repository(repository) } + pub fn get_repository(&self) -> Option { + self.0.borrow().as_package_interface().get_repository() + } + pub fn get_binaries(&self) -> Vec { self.0.borrow().as_package_interface().get_binaries() } diff --git a/crates/shirabe/src/package/package.rs b/crates/shirabe/src/package/package.rs index 92836a2..680443e 100644 --- a/crates/shirabe/src/package/package.rs +++ b/crates/shirabe/src/package/package.rs @@ -1,17 +1,20 @@ //! ref: composer/src/Composer/Package/Package.php +use std::rc::Rc; + use chrono::{DateTime, Utc}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::Preg; use shirabe_external_packages::composer::util::ComposerMirror; -use shirabe_php_shim::{E_USER_DEPRECATED, PhpMixed, strpos, trigger_error}; +use shirabe_php_shim::{E_USER_DEPRECATED, LogicException, PhpMixed, strpos, trigger_error}; use crate::package::BasePackage; use crate::package::Link; use crate::package::PackageInterface; use crate::package::version::VersionParser; -use crate::repository::RepositoryInterface; +use crate::repository::RepositoryInterfaceHandle; +use crate::repository::RepositoryInterfaceWeakHandle; /// Mirror entry, e.g. `['url' => 'https://...', 'preferred' => true]`. #[derive(Debug, Clone)] @@ -26,7 +29,8 @@ pub struct Package { id: i64, name: String, pretty_name: String, - repository: Option>, + /// Back-reference to the owning repository. `Weak` breaks the repository -> packages cycle. + repository: Option, pub(crate) r#type: Option, pub(crate) target_dir: Option, @@ -559,16 +563,22 @@ impl BasePackage for Package { &mut self.pretty_name } - fn repository_opt(&self) -> Option<&dyn RepositoryInterface> { - self.repository.as_deref() + fn repository_opt(&self) -> Option { + self.repository + .as_ref() + .and_then(|w| w.upgrade()) + .map(RepositoryInterfaceHandle::from_rc) } - fn set_repository_box(&mut self, repository: Box) { - todo!() + fn set_repository_box(&mut self, repository: RepositoryInterfaceHandle) { + self.repository = Some(repository.downgrade()); } - fn take_repository(&mut self) -> Option> { - todo!() + fn take_repository(&mut self) -> Option { + self.repository + .take() + .and_then(|w| w.upgrade()) + .map(RepositoryInterfaceHandle::from_rc) } } @@ -696,11 +706,24 @@ impl PackageInterface for Package { fn get_php_ext(&self) -> Option> { todo!() } - fn set_repository(&mut self, _repository: Box) -> anyhow::Result<()> { - todo!() - } - fn get_repository(&self) -> Option<&dyn RepositoryInterface> { - todo!() + fn set_repository(&mut self, repository: RepositoryInterfaceHandle) -> anyhow::Result<()> { + if let Some(existing) = self.repository.as_ref().and_then(|w| w.upgrade()) { + if !Rc::ptr_eq(&existing, repository.as_rc()) { + return Err(LogicException { + message: "A package can only be added to one repository".to_string(), + code: 0, + } + .into()); + } + } + self.repository = Some(repository.downgrade()); + Ok(()) + } + fn get_repository(&self) -> Option { + self.repository + .as_ref() + .and_then(|w| w.upgrade()) + .map(RepositoryInterfaceHandle::from_rc) } fn get_binaries(&self) -> Vec { todo!() diff --git a/crates/shirabe/src/package/package_interface.rs b/crates/shirabe/src/package/package_interface.rs index 0ec6e26..92729a4 100644 --- a/crates/shirabe/src/package/package_interface.rs +++ b/crates/shirabe/src/package/package_interface.rs @@ -5,7 +5,7 @@ use indexmap::IndexMap; use shirabe_php_shim::PhpMixed; use crate::package::Link; -use crate::repository::RepositoryInterface; +use crate::repository::RepositoryInterfaceHandle; /// Defines the essential information a package has that is used during solving/installation /// @@ -244,10 +244,10 @@ pub trait PackageInterface: std::fmt::Display + std::fmt::Debug { fn get_php_ext(&self) -> Option>; /// Stores a reference to the repository that owns the package - fn set_repository(&mut self, repository: Box) -> anyhow::Result<()>; + fn set_repository(&mut self, repository: RepositoryInterfaceHandle) -> anyhow::Result<()>; /// Returns a reference to the repository that owns the package - fn get_repository(&self) -> Option<&dyn RepositoryInterface>; + fn get_repository(&self) -> Option; /// Returns the package binaries /// diff --git a/crates/shirabe/src/package/root_package.rs b/crates/shirabe/src/package/root_package.rs index df676ff..028f43b 100644 --- a/crates/shirabe/src/package/root_package.rs +++ b/crates/shirabe/src/package/root_package.rs @@ -9,7 +9,7 @@ use crate::package::CompletePackageInterface; use crate::package::Link; use crate::package::PackageInterface; use crate::package::RootPackageInterface; -use crate::repository::RepositoryInterface; +use crate::repository::RepositoryInterfaceHandle; #[derive(Debug)] pub struct RootPackage { @@ -351,11 +351,11 @@ impl PackageInterface for RootPackage { fn get_php_ext(&self) -> Option> { todo!() } - fn set_repository(&mut self, _repository: Box) -> anyhow::Result<()> { - todo!() + fn set_repository(&mut self, repository: RepositoryInterfaceHandle) -> anyhow::Result<()> { + self.inner.set_repository(repository) } - fn get_repository(&self) -> Option<&dyn RepositoryInterface> { - todo!() + fn get_repository(&self) -> Option { + self.inner.get_repository() } fn get_binaries(&self) -> Vec { todo!() -- cgit v1.3.1