diff options
Diffstat (limited to 'crates/shirabe/src/repository/array_repository.rs')
| -rw-r--r-- | crates/shirabe/src/repository/array_repository.rs | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/crates/shirabe/src/repository/array_repository.rs b/crates/shirabe/src/repository/array_repository.rs index 6467c14..3a05513 100644 --- a/crates/shirabe/src/repository/array_repository.rs +++ b/crates/shirabe/src/repository/array_repository.rs @@ -2,6 +2,7 @@ use std::any::Any; use std::cell::RefCell; +use std::rc::Weak; use anyhow::Result; use indexmap::IndexMap; @@ -17,7 +18,7 @@ use crate::package::version::StabilityFilter; use crate::package::version::VersionParser; use crate::repository::{ AbandonedInfo, FindPackageConstraint, LoadPackagesResult, ProviderInfo, RepositoryInterface, - SearchResult, + RepositoryInterfaceHandle, RepositoryInterfaceWeakHandle, SearchResult, }; /// A repository implementation that simply stores packages in an array @@ -29,6 +30,10 @@ pub struct ArrayRepository { /// @var ?array<BasePackage> indexed by package unique name and used to cache hasPackage calls pub(crate) package_map: RefCell<Option<IndexMap<String, BasePackageHandle>>>, + + /// Weak reference to the outermost repository handle wrapping this `ArrayRepository`, + /// injected via `set_self_handle`. Used to wire package -> repository back-references. + self_weak: RefCell<Option<RepositoryInterfaceWeakHandle>>, } impl ArrayRepository { @@ -37,6 +42,7 @@ impl ArrayRepository { let this = Self { packages: RefCell::new(None), package_map: RefCell::new(None), + self_weak: RefCell::new(None), }; for package in packages { this.add_package(package)?; @@ -49,8 +55,12 @@ impl ArrayRepository { if self.packages.borrow().is_none() { self.initialize(); } - // TODO(phase-b): pass a reference to self, not a clone - package.set_repository(todo!("self as Box<dyn RepositoryInterface>"))?; + // PHP: $package->setRepository($this). The back-reference is wired only once this + // repository (or its outermost wrapper) has been put behind a RepositoryInterfaceHandle; + // packages added during construction are wired later in set_self_handle. + if let Some(handle) = self.self_weak.borrow().as_ref().and_then(Weak::upgrade) { + package.set_repository(RepositoryInterfaceHandle::from_rc(handle))?; + } let aliased_package: Option<PackageHandle> = package.as_alias().map(|alias| alias.get_alias_of()); @@ -59,13 +69,13 @@ impl ArrayRepository { .borrow_mut() .as_mut() .unwrap() - .push(package.into()); + .push(package.clone()); if let Some(aliased_package) = aliased_package { // PHP: if ($aliasedPackage->getRepository() === null) $this->addPackage($aliasedPackage); - // TODO(phase-c): the handle does not expose get_repository (a `RefCell`-borrowed - // back-reference); this needs repository back-references on handles. - let _ = aliased_package; + if aliased_package.get_repository().is_none() { + self.add_package(aliased_package.into())?; + } } // invalidate package map cache @@ -438,4 +448,23 @@ impl RepositoryInterface for ArrayRepository { fn as_any(&self) -> &dyn std::any::Any { self } + + fn set_self_handle(&self, weak: RepositoryInterfaceWeakHandle) { + *self.self_weak.borrow_mut() = Some(weak.clone()); + // Wire back-references for packages added before this repository was wrapped in a handle + // (e.g. those passed to ArrayRepository::new). Reads the field directly to avoid + // triggering lazy initialization in wrapper repositories. + if let Some(handle) = weak.upgrade() { + let handle = RepositoryInterfaceHandle::from_rc(handle); + let pkgs: Vec<BasePackageHandle> = self + .packages + .borrow() + .as_ref() + .map(|v| v.clone()) + .unwrap_or_default(); + for pkg in pkgs { + let _ = pkg.set_repository(handle.clone()); + } + } + } } |
