use std::path::PathBuf;
use std::{collections::BTreeMap, num::NonZeroUsize};
use url::Url;
use uv_configuration::{
BuildIsolation, ExportFormat, IndexStrategy, KeyringProviderType, NoSources, ProxyUrl,
Reinstall, RequiredVersion, TargetTriple, TrustedPublishing, Upgrade,
};
use uv_distribution_types::{
ConfigSettings, ExtraBuildVariables, Index, IndexUrl, PackageConfigSettings, PipExtraIndex,
PipFindLinks, PipIndex,
};
use uv_install_wheel::LinkMode;
use uv_pypi_types::{SchemaConflicts, SupportedEnvironments};
use uv_python::{PythonDownloads, PythonPreference, PythonVersion};
use uv_redacted::DisplaySafeUrl;
use uv_resolver::{
AnnotationStyle, ExcludeNewer, ExcludeNewerPackage, ExcludeNewerValue, ForkStrategy,
PrereleaseMode, ResolutionMode,
};
use uv_torch::TorchMode;
use uv_workspace::pyproject::ExtraBuildDependencies;
use uv_workspace::pyproject_mut::AddBoundsKind;
use crate::{AuditOptions, FilesystemOptions, Options, PipOptions};
pub trait Combine {
#[must_use]
fn combine(self, other: Self) -> Self;
}
impl Combine for Option<FilesystemOptions> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(FilesystemOptions(
a.into_options().combine(b.into_options()),
)),
(a, b) => a.or(b),
}
}
}
impl Combine for Option<Options> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}
impl Combine for Option<PipOptions> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}
impl Combine for Option<AuditOptions> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}
macro_rules! impl_combine_or {
($name:ident) => {
impl Combine for Option<$name> {
fn combine(self, other: Option<$name>) -> Option<$name> {
self.or(other)
}
}
};
}
impl_combine_or!(AddBoundsKind);
impl_combine_or!(AnnotationStyle);
impl_combine_or!(ExcludeNewer);
impl_combine_or!(ExcludeNewerValue);
impl_combine_or!(ExportFormat);
impl_combine_or!(ForkStrategy);
impl_combine_or!(Index);
impl_combine_or!(IndexStrategy);
impl_combine_or!(IndexUrl);
impl_combine_or!(KeyringProviderType);
impl_combine_or!(LinkMode);
impl_combine_or!(DisplaySafeUrl);
impl_combine_or!(NonZeroUsize);
impl_combine_or!(PathBuf);
impl_combine_or!(PipExtraIndex);
impl_combine_or!(PipFindLinks);
impl_combine_or!(PipIndex);
impl_combine_or!(PrereleaseMode);
impl_combine_or!(ProxyUrl);
impl_combine_or!(PythonDownloads);
impl_combine_or!(PythonPreference);
impl_combine_or!(PythonVersion);
impl_combine_or!(RequiredVersion);
impl_combine_or!(ResolutionMode);
impl_combine_or!(SchemaConflicts);
impl_combine_or!(String);
impl_combine_or!(SupportedEnvironments);
impl_combine_or!(TargetTriple);
impl_combine_or!(TorchMode);
impl_combine_or!(TrustedPublishing);
impl_combine_or!(Url);
impl_combine_or!(bool);
impl<T> Combine for Option<Vec<T>> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(mut a), Some(b)) => {
a.extend(b);
Some(a)
}
(a, b) => a.or(b),
}
}
}
impl<K: Ord, T> Combine for Option<BTreeMap<K, Vec<T>>> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(mut a), Some(b)) => {
for (key, value) in b {
a.entry(key).or_default().extend(value);
}
Some(a)
}
(a, b) => a.or(b),
}
}
}
impl Combine for Option<ExcludeNewerPackage> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(mut a), Some(b)) => {
for (key, value) in b {
a.entry(key).or_insert(value);
}
Some(a)
}
(a, b) => a.or(b),
}
}
}
impl Combine for Option<ConfigSettings> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.merge(b)),
(a, b) => a.or(b),
}
}
}
impl Combine for Option<PackageConfigSettings> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.merge(b)),
(a, b) => a.or(b),
}
}
}
impl Combine for Option<NoSources> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}
impl Combine for Option<Upgrade> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}
impl Combine for Option<Reinstall> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}
impl Combine for Option<BuildIsolation> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}
impl Combine for serde::de::IgnoredAny {
fn combine(self, _other: Self) -> Self {
self
}
}
impl Combine for Option<serde::de::IgnoredAny> {
fn combine(self, _other: Self) -> Self {
self
}
}
impl Combine for ExcludeNewer {
fn combine(mut self, other: Self) -> Self {
self.global = self.global.combine(other.global);
if !other.package.is_empty() {
if self.package.is_empty() {
self.package = other.package;
} else {
for (pkg, setting) in &other.package {
self.package
.entry(pkg.clone())
.or_insert_with(|| setting.clone());
}
}
}
self
}
}
impl Combine for ExtraBuildDependencies {
fn combine(mut self, other: Self) -> Self {
for (key, value) in other {
match self.entry(key) {
std::collections::btree_map::Entry::Occupied(mut entry) => {
let existing = entry.get_mut();
existing.extend(value);
}
std::collections::btree_map::Entry::Vacant(entry) => {
entry.insert(value);
}
}
}
self
}
}
impl Combine for Option<ExtraBuildDependencies> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}
impl Combine for ExtraBuildVariables {
fn combine(mut self, other: Self) -> Self {
for (key, value) in other {
match self.entry(key) {
std::collections::btree_map::Entry::Occupied(mut entry) => {
let existing = entry.get_mut();
for (k, v) in value {
existing.entry(k).or_insert(v);
}
}
std::collections::btree_map::Entry::Vacant(entry) => {
entry.insert(value);
}
}
}
self
}
}
impl Combine for Option<ExtraBuildVariables> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}