aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/package
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-28 22:43:11 +0900
committernsfisis <nsfisis@gmail.com>2026-05-28 22:43:43 +0900
commiteea4efe87e455742ec17881ee93d8095925e8516 (patch)
tree6d242f4fdd0bf32f0494a6fbbd62bce9ed6e1dc7 /crates/shirabe/src/package
parentcc5d73c05a0abca2eebcc8a6afa0b1543ee49850 (diff)
downloadphp-shirabe-eea4efe87e455742ec17881ee93d8095925e8516.tar.gz
php-shirabe-eea4efe87e455742ec17881ee93d8095925e8516.tar.zst
php-shirabe-eea4efe87e455742ec17881ee93d8095925e8516.zip
refactor(repository): introduce Rc<RefCell<_>> handles for repositories
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/package')
-rw-r--r--crates/shirabe/src/package/alias_package.rs24
-rw-r--r--crates/shirabe/src/package/base_package.rs17
-rw-r--r--crates/shirabe/src/package/complete_package.rs8
-rw-r--r--crates/shirabe/src/package/handle.rs10
-rw-r--r--crates/shirabe/src/package/package.rs49
-rw-r--r--crates/shirabe/src/package/package_interface.rs6
-rw-r--r--crates/shirabe/src/package/root_package.rs10
7 files changed, 72 insertions, 52 deletions
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<Box<dyn RepositoryInterface>>,
/// @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<dyn RepositoryInterface>) -> 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<RepositoryInterfaceHandle> {
+ 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<RepositoryInterfaceHandle> {
+ // PHP `AliasPackage::getRepository()` delegates to `$this->aliasOf->getRepository()`.
+ self.alias_of.get_repository()
}
- fn set_repository_box(&mut self, repository: Box<dyn RepositoryInterface>) {
- todo!()
+ fn set_repository_box(&mut self, repository: RepositoryInterfaceHandle) {
+ let _ = self.alias_of.set_repository(repository);
}
- fn take_repository(&mut self) -> Option<Box<dyn RepositoryInterface>> {
- todo!()
+ fn take_repository(&mut self) -> Option<RepositoryInterfaceHandle> {
+ // 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<dyn RepositoryInterface>);
- fn take_repository(&mut self) -> Option<Box<dyn RepositoryInterface>>;
-
- /// 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<RepositoryInterfaceHandle>;
+ fn set_repository_box(&mut self, repository: RepositoryInterfaceHandle);
+ fn take_repository(&mut self) -> Option<RepositoryInterfaceHandle>;
// 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::<PlatformRepository>())
- .is_some()
+ .map_or(false, |r| r.is::<PlatformRepository>())
}
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<dyn crate::repository::RepositoryInterface>,
+ 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<crate::repository::RepositoryInterfaceHandle> {
+ self.inner.get_repository()
}
fn get_binaries(&self) -> Vec<String> {
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<dyn crate::repository::RepositoryInterface>,
+ 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<crate::repository::RepositoryInterfaceHandle> {
self.$field.get_repository()
}
fn get_binaries(&self) -> Vec<String> {
@@ -588,7 +588,7 @@ macro_rules! impl_package_interface_handle {
pub fn set_repository(
&self,
- repository: Box<dyn crate::repository::RepositoryInterface>,
+ 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<crate::repository::RepositoryInterfaceHandle> {
+ self.0.borrow().as_package_interface().get_repository()
+ }
+
pub fn get_binaries(&self) -> Vec<String> {
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<Box<dyn RepositoryInterface>>,
+ /// Back-reference to the owning repository. `Weak` breaks the repository -> packages cycle.
+ repository: Option<RepositoryInterfaceWeakHandle>,
pub(crate) r#type: Option<String>,
pub(crate) target_dir: Option<String>,
@@ -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<RepositoryInterfaceHandle> {
+ self.repository
+ .as_ref()
+ .and_then(|w| w.upgrade())
+ .map(RepositoryInterfaceHandle::from_rc)
}
- fn set_repository_box(&mut self, repository: Box<dyn RepositoryInterface>) {
- todo!()
+ fn set_repository_box(&mut self, repository: RepositoryInterfaceHandle) {
+ self.repository = Some(repository.downgrade());
}
- fn take_repository(&mut self) -> Option<Box<dyn RepositoryInterface>> {
- todo!()
+ fn take_repository(&mut self) -> Option<RepositoryInterfaceHandle> {
+ 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<IndexMap<String, PhpMixed>> {
todo!()
}
- fn set_repository(&mut self, _repository: Box<dyn RepositoryInterface>) -> anyhow::Result<()> {
- 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<&dyn RepositoryInterface> {
- todo!()
+ fn get_repository(&self) -> Option<RepositoryInterfaceHandle> {
+ self.repository
+ .as_ref()
+ .and_then(|w| w.upgrade())
+ .map(RepositoryInterfaceHandle::from_rc)
}
fn get_binaries(&self) -> Vec<String> {
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<IndexMap<String, PhpMixed>>;
/// Stores a reference to the repository that owns the package
- fn set_repository(&mut self, repository: Box<dyn RepositoryInterface>) -> 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<RepositoryInterfaceHandle>;
/// 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<IndexMap<String, PhpMixed>> {
todo!()
}
- fn set_repository(&mut self, _repository: Box<dyn RepositoryInterface>) -> 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<RepositoryInterfaceHandle> {
+ self.inner.get_repository()
}
fn get_binaries(&self) -> Vec<String> {
todo!()