//! ref: composer/src/Composer/Composer.php //! ref: composer/src/Composer/PartialComposer.php use shirabe_external_packages::composer::pcre::Preg; use crate::autoload::AutoloadGenerator; use crate::config::Config; use crate::downloader::DownloadManager; use crate::event_dispatcher::EventDispatcher; use crate::installer::InstallationManager; use crate::package::archiver::ArchiveManager; use crate::package::{Locker, RootPackageInterfaceHandle}; use crate::plugin::PluginManager; use crate::repository::RepositoryManager; use crate::util::r#loop::Loop; // TODO: change this information to Shirabe version. pub const VERSION: &'static str = "2.9.7"; pub const BRANCH_ALIAS_VERSION: &'static str = ""; pub const RELEASE_DATE: &'static str = "2026-04-14 13:31:52"; pub const SOURCE_VERSION: &'static str = ""; pub const RUNTIME_API_VERSION: &'static str = "2.2.2"; pub fn get_version() -> String { if VERSION == "@package_version@" { return SOURCE_VERSION.to_string(); } if BRANCH_ALIAS_VERSION != "" && Preg::is_match("{^[a-f0-9]{40}$}", VERSION).unwrap_or(false) { return format!("{}+{}", BRANCH_ALIAS_VERSION, VERSION); } VERSION.to_string() } /// Interface for \Composer\PartialComposer. Implemented by every composer handle, since both a /// partial and a full composer expose these common members. pub trait PartialComposer { fn set_package(&self, package: RootPackageInterfaceHandle); fn get_package(&self) -> RootPackageInterfaceHandle; fn set_config(&self, config: std::rc::Rc>); fn get_config(&self) -> std::rc::Rc>; fn set_loop(&self, r#loop: std::rc::Rc>); fn get_loop(&self) -> std::rc::Rc>; fn set_repository_manager(&self, manager: std::rc::Rc>); fn get_repository_manager(&self) -> std::rc::Rc>; fn set_installation_manager( &self, manager: std::rc::Rc>, ); fn get_installation_manager(&self) -> std::rc::Rc>; fn set_event_dispatcher( &self, event_dispatcher: std::rc::Rc>, ); fn get_event_dispatcher(&self) -> std::rc::Rc>; fn is_global(&self) -> bool; fn set_global(&self); } /// Interface for \Composer\Composer (`extends PartialComposer`). Implemented only by fully-loaded /// composer handles, which additionally expose the full-only members below. pub trait Composer: PartialComposer { fn set_locker(&self, locker: std::rc::Rc>); fn get_locker(&self) -> std::rc::Rc>; fn set_download_manager(&self, manager: std::rc::Rc>); fn get_download_manager(&self) -> std::rc::Rc>; // TODO(plugin): set_plugin_manager is part of the plugin API fn set_plugin_manager(&self, manager: std::rc::Rc>); // TODO(plugin): get_plugin_manager is part of the plugin API fn get_plugin_manager(&self) -> std::rc::Rc>; fn set_autoload_generator( &self, autoload_generator: std::rc::Rc>, ); fn get_autoload_generator(&self) -> std::rc::Rc>; fn set_archive_manager(&self, manager: std::rc::Rc>); fn get_archive_manager(&self) -> std::rc::Rc>; } /// Internal data type corresponding to \Composer\PartialComposer. #[derive(Debug, Default)] pub(crate) struct InnerPartialComposer { pub(crate) global: bool, pub(crate) package: Option, pub(crate) r#loop: Option>>, pub(crate) repository_manager: Option>>, pub(crate) installation_manager: Option>>, pub(crate) config: Option>>, pub(crate) event_dispatcher: Option>>, } /// Internal data type corresponding to \Composer\Composer. #[derive(Debug, Default)] pub(crate) struct InnerFullComposer { pub(crate) partial: InnerPartialComposer, pub(crate) locker: Option>>, pub(crate) download_manager: Option>>, // TODO(plugin): plugin_manager is part of the plugin API pub(crate) plugin_manager: Option>>, pub(crate) autoload_generator: Option>>, pub(crate) archive_manager: Option>>, } /// Shared reference to a fully-loaded \Composer\Composer. /// Use this for parameters or fields typed as \Composer\Composer in PHP. #[derive(Debug, Clone)] pub struct FullComposerHandle(std::rc::Rc>); impl FullComposerHandle { pub(crate) fn from_rc(rc: std::rc::Rc>) -> Self { Self(rc) } pub(crate) fn as_rc(&self) -> &std::rc::Rc> { &self.0 } pub fn downgrade(&self) -> FullComposerWeakHandle { FullComposerWeakHandle(std::rc::Rc::downgrade(&self.0)) } } impl PartialComposer for FullComposerHandle { fn set_package(&self, package: RootPackageInterfaceHandle) { self.0.borrow_mut().partial.package = Some(package); } fn get_package(&self) -> RootPackageInterfaceHandle { self.0.borrow().partial.package.as_ref().unwrap().clone() } fn set_config(&self, config: std::rc::Rc>) { self.0.borrow_mut().partial.config = Some(config); } fn get_config(&self) -> std::rc::Rc> { self.0.borrow().partial.config.as_ref().unwrap().clone() } fn set_loop(&self, r#loop: std::rc::Rc>) { self.0.borrow_mut().partial.r#loop = Some(r#loop); } fn get_loop(&self) -> std::rc::Rc> { self.0.borrow().partial.r#loop.as_ref().unwrap().clone() } fn set_repository_manager(&self, manager: std::rc::Rc>) { self.0.borrow_mut().partial.repository_manager = Some(manager); } fn get_repository_manager(&self) -> std::rc::Rc> { self.0 .borrow() .partial .repository_manager .as_ref() .unwrap() .clone() } fn set_installation_manager( &self, manager: std::rc::Rc>, ) { self.0.borrow_mut().partial.installation_manager = Some(manager); } fn get_installation_manager(&self) -> std::rc::Rc> { self.0 .borrow() .partial .installation_manager .as_ref() .unwrap() .clone() } fn set_event_dispatcher( &self, event_dispatcher: std::rc::Rc>, ) { self.0.borrow_mut().partial.event_dispatcher = Some(event_dispatcher); } fn get_event_dispatcher(&self) -> std::rc::Rc> { self.0 .borrow() .partial .event_dispatcher .as_ref() .unwrap() .clone() } fn is_global(&self) -> bool { self.0.borrow().partial.global } fn set_global(&self) { self.0.borrow_mut().partial.global = true; } } impl Composer for FullComposerHandle { fn set_locker(&self, locker: std::rc::Rc>) { self.0.borrow_mut().locker = Some(locker); } fn get_locker(&self) -> std::rc::Rc> { self.0.borrow().locker.as_ref().unwrap().clone() } fn set_download_manager(&self, manager: std::rc::Rc>) { self.0.borrow_mut().download_manager = Some(manager); } fn get_download_manager(&self) -> std::rc::Rc> { self.0.borrow().download_manager.as_ref().unwrap().clone() } fn set_plugin_manager(&self, manager: std::rc::Rc>) { self.0.borrow_mut().plugin_manager = Some(manager); } fn get_plugin_manager(&self) -> std::rc::Rc> { self.0.borrow().plugin_manager.as_ref().unwrap().clone() } fn set_autoload_generator( &self, autoload_generator: std::rc::Rc>, ) { self.0.borrow_mut().autoload_generator = Some(autoload_generator); } fn get_autoload_generator(&self) -> std::rc::Rc> { self.0.borrow().autoload_generator.as_ref().unwrap().clone() } fn set_archive_manager(&self, manager: std::rc::Rc>) { self.0.borrow_mut().archive_manager = Some(manager); } fn get_archive_manager(&self) -> std::rc::Rc> { self.0.borrow().archive_manager.as_ref().unwrap().clone() } } /// Shared weak reference to a fully-loaded \Composer\Composer. #[derive(Debug, Clone)] pub struct FullComposerWeakHandle(std::rc::Weak>); impl FullComposerWeakHandle { pub(crate) fn from_weak(weak: std::rc::Weak>) -> Self { Self(weak) } pub fn upgrade(&self) -> Option { self.0.upgrade().map(FullComposerHandle) } fn upgraded(&self) -> FullComposerHandle { self.upgrade() .expect("Composer has been dropped before its weak reference") } } impl PartialComposer for FullComposerWeakHandle { fn set_package(&self, package: RootPackageInterfaceHandle) { self.upgraded().set_package(package); } fn get_package(&self) -> RootPackageInterfaceHandle { self.upgraded().get_package() } fn set_config(&self, config: std::rc::Rc>) { self.upgraded().set_config(config); } fn get_config(&self) -> std::rc::Rc> { self.upgraded().get_config() } fn set_loop(&self, r#loop: std::rc::Rc>) { self.upgraded().set_loop(r#loop); } fn get_loop(&self) -> std::rc::Rc> { self.upgraded().get_loop() } fn set_repository_manager(&self, manager: std::rc::Rc>) { self.upgraded().set_repository_manager(manager); } fn get_repository_manager(&self) -> std::rc::Rc> { self.upgraded().get_repository_manager() } fn set_installation_manager( &self, manager: std::rc::Rc>, ) { self.upgraded().set_installation_manager(manager); } fn get_installation_manager(&self) -> std::rc::Rc> { self.upgraded().get_installation_manager() } fn set_event_dispatcher( &self, event_dispatcher: std::rc::Rc>, ) { self.upgraded().set_event_dispatcher(event_dispatcher); } fn get_event_dispatcher(&self) -> std::rc::Rc> { self.upgraded().get_event_dispatcher() } fn is_global(&self) -> bool { self.upgraded().is_global() } fn set_global(&self) { self.upgraded().set_global(); } } impl Composer for FullComposerWeakHandle { fn set_locker(&self, locker: std::rc::Rc>) { self.upgraded().set_locker(locker); } fn get_locker(&self) -> std::rc::Rc> { self.upgraded().get_locker() } fn set_download_manager(&self, manager: std::rc::Rc>) { self.upgraded().set_download_manager(manager); } fn get_download_manager(&self) -> std::rc::Rc> { self.upgraded().get_download_manager() } fn set_plugin_manager(&self, manager: std::rc::Rc>) { self.upgraded().set_plugin_manager(manager); } fn get_plugin_manager(&self) -> std::rc::Rc> { self.upgraded().get_plugin_manager() } fn set_autoload_generator( &self, autoload_generator: std::rc::Rc>, ) { self.upgraded().set_autoload_generator(autoload_generator); } fn get_autoload_generator(&self) -> std::rc::Rc> { self.upgraded().get_autoload_generator() } fn set_archive_manager(&self, manager: std::rc::Rc>) { self.upgraded().set_archive_manager(manager); } fn get_archive_manager(&self) -> std::rc::Rc> { self.upgraded().get_archive_manager() } } /// Shared reference to a \Composer\PartialComposer that may at runtime be either a partial composer /// or a full \Composer\Composer. Use this for parameters or fields typed as \Composer\PartialComposer /// in PHP; downcast with [`AnyComposerHandle::as_full`] (`$composer instanceof Composer`). #[derive(Debug, Clone)] pub enum AnyComposerHandle { Partial(std::rc::Rc>), Full(FullComposerHandle), } impl AnyComposerHandle { pub fn is_full(&self) -> bool { matches!(self, Self::Full(_)) } pub fn is_partial(&self) -> bool { matches!(self, Self::Partial(_)) } /// Downcast to a full Composer handle. PHP `$composer instanceof Composer`. pub fn as_full(&self) -> Option { match self { Self::Full(full) => Some(full.clone()), Self::Partial(_) => None, } } pub fn downgrade(&self) -> AnyComposerWeakHandle { match self { Self::Partial(rc) => AnyComposerWeakHandle::Partial(std::rc::Rc::downgrade(rc)), Self::Full(full) => AnyComposerWeakHandle::Full(full.downgrade()), } } } impl From for AnyComposerHandle { fn from(h: FullComposerHandle) -> Self { Self::Full(h) } } impl PartialComposer for AnyComposerHandle { fn set_package(&self, package: RootPackageInterfaceHandle) { match self { Self::Partial(rc) => rc.borrow_mut().package = Some(package), Self::Full(f) => f.set_package(package), } } fn get_package(&self) -> RootPackageInterfaceHandle { match self { Self::Partial(rc) => rc.borrow().package.as_ref().unwrap().clone(), Self::Full(f) => f.get_package(), } } fn set_config(&self, config: std::rc::Rc>) { match self { Self::Partial(rc) => rc.borrow_mut().config = Some(config), Self::Full(f) => f.set_config(config), } } fn get_config(&self) -> std::rc::Rc> { match self { Self::Partial(rc) => rc.borrow().config.as_ref().unwrap().clone(), Self::Full(f) => f.get_config(), } } fn set_loop(&self, r#loop: std::rc::Rc>) { match self { Self::Partial(rc) => rc.borrow_mut().r#loop = Some(r#loop), Self::Full(f) => f.set_loop(r#loop), } } fn get_loop(&self) -> std::rc::Rc> { match self { Self::Partial(rc) => rc.borrow().r#loop.as_ref().unwrap().clone(), Self::Full(f) => f.get_loop(), } } fn set_repository_manager(&self, manager: std::rc::Rc>) { match self { Self::Partial(rc) => rc.borrow_mut().repository_manager = Some(manager), Self::Full(f) => f.set_repository_manager(manager), } } fn get_repository_manager(&self) -> std::rc::Rc> { match self { Self::Partial(rc) => rc.borrow().repository_manager.as_ref().unwrap().clone(), Self::Full(f) => f.get_repository_manager(), } } fn set_installation_manager( &self, manager: std::rc::Rc>, ) { match self { Self::Partial(rc) => rc.borrow_mut().installation_manager = Some(manager), Self::Full(f) => f.set_installation_manager(manager), } } fn get_installation_manager(&self) -> std::rc::Rc> { match self { Self::Partial(rc) => rc.borrow().installation_manager.as_ref().unwrap().clone(), Self::Full(f) => f.get_installation_manager(), } } fn set_event_dispatcher( &self, event_dispatcher: std::rc::Rc>, ) { match self { Self::Partial(rc) => rc.borrow_mut().event_dispatcher = Some(event_dispatcher), Self::Full(f) => f.set_event_dispatcher(event_dispatcher), } } fn get_event_dispatcher(&self) -> std::rc::Rc> { match self { Self::Partial(rc) => rc.borrow().event_dispatcher.as_ref().unwrap().clone(), Self::Full(f) => f.get_event_dispatcher(), } } fn is_global(&self) -> bool { match self { Self::Partial(rc) => rc.borrow().global, Self::Full(f) => f.is_global(), } } fn set_global(&self) { match self { Self::Partial(rc) => rc.borrow_mut().global = true, Self::Full(f) => f.set_global(), } } } /// Shared weak reference to a \Composer\PartialComposer that may at runtime be either partial or full. #[derive(Debug, Clone)] pub enum AnyComposerWeakHandle { Partial(std::rc::Weak>), Full(FullComposerWeakHandle), } impl AnyComposerWeakHandle { pub fn upgrade(&self) -> Option { match self { Self::Partial(p) => p.upgrade().map(AnyComposerHandle::Partial), Self::Full(f) => f.upgrade().map(AnyComposerHandle::Full), } } fn upgraded(&self) -> AnyComposerHandle { self.upgrade() .expect("PartialComposer has been dropped before its weak reference") } } impl PartialComposer for AnyComposerWeakHandle { fn set_package(&self, package: RootPackageInterfaceHandle) { self.upgraded().set_package(package); } fn get_package(&self) -> RootPackageInterfaceHandle { self.upgraded().get_package() } fn set_config(&self, config: std::rc::Rc>) { self.upgraded().set_config(config); } fn get_config(&self) -> std::rc::Rc> { self.upgraded().get_config() } fn set_loop(&self, r#loop: std::rc::Rc>) { self.upgraded().set_loop(r#loop); } fn get_loop(&self) -> std::rc::Rc> { self.upgraded().get_loop() } fn set_repository_manager(&self, manager: std::rc::Rc>) { self.upgraded().set_repository_manager(manager); } fn get_repository_manager(&self) -> std::rc::Rc> { self.upgraded().get_repository_manager() } fn set_installation_manager( &self, manager: std::rc::Rc>, ) { self.upgraded().set_installation_manager(manager); } fn get_installation_manager(&self) -> std::rc::Rc> { self.upgraded().get_installation_manager() } fn set_event_dispatcher( &self, event_dispatcher: std::rc::Rc>, ) { self.upgraded().set_event_dispatcher(event_dispatcher); } fn get_event_dispatcher(&self) -> std::rc::Rc> { self.upgraded().get_event_dispatcher() } fn is_global(&self) -> bool { self.upgraded().is_global() } fn set_global(&self) { self.upgraded().set_global(); } } /// Downcasts a polymorphic composer handle to a fully-loaded \Composer\Composer. /// /// Commands obtain their Composer through `require_composer` / `create_composer_instance`, /// which always yield a fully-loaded instance, so the downcast is infallible here. pub fn composer_full(composer: &AnyComposerHandle) -> FullComposerHandle { composer .as_full() .expect("a fully loaded Composer is required here") }