use crate::{
Error, PackageId,
graph::{
DependencyDirection, PackageGraph, PackageIx, PackageLink, PackageResolver, PackageSet,
cargo::build::CargoSetBuildState,
feature::{FeatureGraph, FeatureSet},
},
platform::PlatformSpec,
sorted_set::SortedSet,
};
use petgraph::prelude::*;
use serde::{Deserialize, Serialize};
use std::{collections::HashSet, fmt};
#[derive(Clone, Debug)]
pub struct CargoOptions<'a> {
pub(crate) resolver: CargoResolverVersion,
pub(crate) include_dev: bool,
pub(crate) initials_platform: InitialsPlatform,
pub(crate) host_platform: PlatformSpec,
pub(crate) target_platform: PlatformSpec,
pub(crate) omitted_packages: HashSet<&'a PackageId>,
}
impl<'a> CargoOptions<'a> {
pub fn new() -> Self {
Self {
resolver: CargoResolverVersion::V1,
include_dev: false,
initials_platform: InitialsPlatform::Standard,
host_platform: PlatformSpec::Any,
target_platform: PlatformSpec::Any,
omitted_packages: HashSet::new(),
}
}
pub fn set_resolver(&mut self, resolver: CargoResolverVersion) -> &mut Self {
self.resolver = resolver;
self
}
pub fn set_include_dev(&mut self, include_dev: bool) -> &mut Self {
self.include_dev = include_dev;
self
}
pub fn set_initials_platform(&mut self, initials_platform: InitialsPlatform) -> &mut Self {
self.initials_platform = initials_platform;
self
}
pub fn set_platform(&mut self, platform_spec: impl Into<PlatformSpec>) -> &mut Self {
let platform_spec = platform_spec.into();
self.target_platform = platform_spec.clone();
self.host_platform = platform_spec;
self
}
pub fn set_target_platform(&mut self, target_platform: impl Into<PlatformSpec>) -> &mut Self {
self.target_platform = target_platform.into();
self
}
pub fn set_host_platform(&mut self, host_platform: impl Into<PlatformSpec>) -> &mut Self {
self.host_platform = host_platform.into();
self
}
pub fn add_omitted_packages(
&mut self,
package_ids: impl IntoIterator<Item = &'a PackageId>,
) -> &mut Self {
self.omitted_packages.extend(package_ids);
self
}
}
impl Default for CargoOptions<'_> {
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[cfg_attr(feature = "proptest1", derive(proptest_derive::Arbitrary))]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum CargoResolverVersion {
#[serde(rename = "1", alias = "v1")]
V1,
#[serde(rename = "install", alias = "v1-install")]
V1Install,
#[serde(rename = "2", alias = "v2")]
V2,
#[serde(rename = "3", alias = "v3")]
V3,
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[cfg_attr(feature = "proptest1", derive(proptest_derive::Arbitrary))]
#[serde(rename_all = "kebab-case")]
pub enum InitialsPlatform {
Host,
Standard,
ProcMacrosOnTarget,
}
impl Default for InitialsPlatform {
fn default() -> Self {
InitialsPlatform::Standard
}
}
#[derive(Clone, Debug)]
pub struct CargoSet<'g> {
pub(super) initials: FeatureSet<'g>,
pub(super) features_only: FeatureSet<'g>,
pub(super) target_features: FeatureSet<'g>,
pub(super) host_features: FeatureSet<'g>,
pub(super) target_direct_deps: PackageSet<'g>,
pub(super) host_direct_deps: PackageSet<'g>,
pub(super) proc_macro_edge_ixs: SortedSet<EdgeIndex<PackageIx>>,
pub(super) build_dep_edge_ixs: SortedSet<EdgeIndex<PackageIx>>,
pub(super) target_edge_ixs: SortedSet<EdgeIndex<PackageIx>>,
pub(super) host_edge_ixs: SortedSet<EdgeIndex<PackageIx>>,
}
assert_covariant!(CargoSet);
impl<'g> CargoSet<'g> {
pub fn new(
initials: FeatureSet<'g>,
features_only: FeatureSet<'g>,
opts: &CargoOptions<'_>,
) -> Result<Self, Error> {
Self::new_internal(initials, features_only, None, opts)
}
pub fn with_package_resolver(
initials: FeatureSet<'g>,
features_only: FeatureSet<'g>,
mut resolver: impl PackageResolver<'g>,
opts: &CargoOptions<'_>,
) -> Result<Self, Error> {
Self::new_internal(initials, features_only, Some(&mut resolver), opts)
}
fn new_internal(
initials: FeatureSet<'g>,
features_only: FeatureSet<'g>,
resolver: Option<&mut dyn PackageResolver<'g>>,
opts: &CargoOptions<'_>,
) -> Result<Self, Error> {
let build_state = CargoSetBuildState::new(initials.graph().package_graph, opts)?;
Ok(build_state.build(initials, features_only, resolver))
}
#[doc(hidden)]
pub fn new_intermediate(
initials: &FeatureSet<'g>,
opts: &CargoOptions<'_>,
) -> Result<CargoIntermediateSet<'g>, Error> {
let build_state = CargoSetBuildState::new(initials.graph().package_graph, opts)?;
Ok(build_state.build_intermediate(initials.to_feature_query(DependencyDirection::Forward)))
}
pub fn feature_graph(&self) -> &FeatureGraph<'g> {
self.initials.graph()
}
pub fn package_graph(&self) -> &'g PackageGraph {
self.feature_graph().package_graph
}
pub fn initials(&self) -> &FeatureSet<'g> {
&self.initials
}
pub fn features_only(&self) -> &FeatureSet<'g> {
&self.features_only
}
pub fn target_features(&self) -> &FeatureSet<'g> {
&self.target_features
}
pub fn host_features(&self) -> &FeatureSet<'g> {
&self.host_features
}
pub fn platform_features(&self, build_platform: BuildPlatform) -> &FeatureSet<'g> {
match build_platform {
BuildPlatform::Target => self.target_features(),
BuildPlatform::Host => self.host_features(),
}
}
pub fn all_features(&self) -> [(BuildPlatform, &FeatureSet<'g>); 2] {
[
(BuildPlatform::Target, self.target_features()),
(BuildPlatform::Host, self.host_features()),
]
}
pub fn target_direct_deps(&self) -> &PackageSet<'g> {
&self.target_direct_deps
}
pub fn host_direct_deps(&self) -> &PackageSet<'g> {
&self.host_direct_deps
}
pub fn platform_direct_deps(&self, build_platform: BuildPlatform) -> &PackageSet<'g> {
match build_platform {
BuildPlatform::Target => self.target_direct_deps(),
BuildPlatform::Host => self.host_direct_deps(),
}
}
pub fn all_direct_deps(&self) -> [(BuildPlatform, &PackageSet<'g>); 2] {
[
(BuildPlatform::Target, self.target_direct_deps()),
(BuildPlatform::Host, self.host_direct_deps()),
]
}
pub fn proc_macro_links<'a>(&'a self) -> impl ExactSizeIterator<Item = PackageLink<'g>> + 'a {
let package_graph = self.target_features.graph().package_graph;
self.proc_macro_edge_ixs
.iter()
.map(move |edge_ix| package_graph.edge_ix_to_link(*edge_ix))
}
pub fn build_dep_links<'a>(&'a self) -> impl ExactSizeIterator<Item = PackageLink<'g>> + 'a {
let package_graph = self.target_features.graph().package_graph;
self.build_dep_edge_ixs
.iter()
.map(move |edge_ix| package_graph.edge_ix_to_link(*edge_ix))
}
pub fn target_links<'a>(&'a self) -> impl ExactSizeIterator<Item = PackageLink<'g>> + 'a {
let package_graph = self.target_features.graph().package_graph;
self.target_edge_ixs
.iter()
.map(move |edge_ix| package_graph.edge_ix_to_link(*edge_ix))
}
pub fn host_links<'a>(&'a self) -> impl ExactSizeIterator<Item = PackageLink<'g>> + 'a {
let package_graph = self.target_features.graph().package_graph;
self.host_edge_ixs
.iter()
.map(move |edge_ix| package_graph.edge_ix_to_link(*edge_ix))
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum BuildPlatform {
Target,
Host,
}
impl BuildPlatform {
pub const VALUES: &'static [Self; 2] = &[BuildPlatform::Target, BuildPlatform::Host];
pub fn flip(self) -> Self {
match self {
BuildPlatform::Host => BuildPlatform::Target,
BuildPlatform::Target => BuildPlatform::Host,
}
}
}
impl fmt::Display for BuildPlatform {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BuildPlatform::Target => write!(f, "target"),
BuildPlatform::Host => write!(f, "host"),
}
}
}
#[doc(hidden)]
#[derive(Debug)]
pub enum CargoIntermediateSet<'g> {
Unified(FeatureSet<'g>),
TargetHost {
target: FeatureSet<'g>,
host: FeatureSet<'g>,
},
}
impl<'g> CargoIntermediateSet<'g> {
#[doc(hidden)]
pub fn target_host_sets(&self) -> (&FeatureSet<'g>, &FeatureSet<'g>) {
match self {
CargoIntermediateSet::Unified(set) => (set, set),
CargoIntermediateSet::TargetHost { target, host } => (target, host),
}
}
}