mod private
{
use crate :: *;
use collection_tools :: collection;
use error ::
{
untyped ::format_err,
};
#[ derive( Debug, Clone, Copy ) ]
#[ repr( transparent ) ]
pub struct DependencyRef< 'a >
{
inner: &'a cargo_metadata ::Dependency,
}
impl DependencyRef< '_ >
{
#[ must_use ]
pub fn crate_dir( &self ) -> Option< CrateDir >
{
match &self.inner.path
{
Some( path ) => path.as_path().try_into().ok(),
None => None,
}
}
#[ must_use ]
pub fn name( &self ) -> String
{
self.inner.name.clone()
}
#[ must_use ]
pub fn kind( &self ) -> DependencyKind
{
match self.inner.kind
{
cargo_metadata ::DependencyKind ::Normal => DependencyKind ::Normal,
cargo_metadata ::DependencyKind ::Development => DependencyKind ::Development,
cargo_metadata ::DependencyKind ::Build => DependencyKind ::Build,
cargo_metadata ::DependencyKind ::Unknown => DependencyKind ::Unknown,
}
}
#[ must_use ]
pub fn req( &self ) -> semver ::VersionReq
{
self.inner.req.clone()
}
}
impl< 'a > From< &'a cargo_metadata ::Dependency > for DependencyRef< 'a >
{
#[ inline( always ) ]
fn from( inner: &'a cargo_metadata ::Dependency ) -> Self
{
Self { inner }
}
}
#[ derive( Eq, PartialEq, Debug, Clone, Copy ) ]
pub enum DependencyKind
{
Normal,
Development,
Build,
Unknown,
}
#[ derive( Debug, Clone, Hash, Eq, PartialEq ) ]
pub struct CrateId
{
pub name: String, pub crate_dir: Option< CrateDir >, }
impl< 'a > From< &WorkspacePackageRef< 'a > > for CrateId
{
fn from( value: &WorkspacePackageRef< 'a > ) -> Self
{
Self
{
name: value.name().into(),
crate_dir: Some( value.crate_dir().unwrap() )
}
}
}
impl From< &DependencyRef< '_ > > for CrateId
{
fn from( value: &DependencyRef< '_ > ) -> Self
{
Self
{
name: value.name(),
crate_dir: value.crate_dir(),
}
}
}
#[ derive( Debug, Copy, Clone ) ]
pub enum DependenciesSort
{
Topological,
Unordered,
}
#[ derive( Debug, Clone ) ]
pub struct DependenciesOptions
{
pub recursive: bool,
pub sort: DependenciesSort,
pub with_dev: bool,
pub with_remote: bool,
}
impl Default for DependenciesOptions
{
fn default() -> Self
{
Self
{
recursive: true,
sort: DependenciesSort ::Unordered,
with_dev: false,
with_remote: false,
}
}
}
#[ allow( clippy ::needless_pass_by_value, clippy ::implicit_hasher ) ]
pub fn list_rec
(
workspace: &Workspace, package: &Package< '_ >,
graph: &mut collection ::HashMap< CrateId, collection ::HashSet< CrateId > >,
opts: DependenciesOptions
)
-> error ::untyped ::Result< CrateId >
{
let DependenciesOptions
{
recursive,
sort: _,
with_dev,
with_remote,
} = opts;
if recursive && with_remote { unimplemented!( "`recursive` + `with_remote` options") }
let manifest_file = &package.manifest_file();
let package = workspace
.package_find_by_manifest( manifest_file )
.ok_or( format_err!( "Package not found in the workspace with path: `{}`", manifest_file.as_ref().display() ) )?;
let deps: collection ::HashSet< _ > = package
.dependencies()
.filter( | dep | ( with_remote || dep.crate_dir().is_some() ) && ( with_dev || dep.kind() != DependencyKind ::Development ) )
.map( | dep | CrateId ::from( &dep ) )
.collect();
let package = CrateId ::from( &package );
graph.insert( package.clone(), deps.clone() );
if recursive
{
for dep in deps
{
if graph.get( &dep ).is_none()
{
list_rec
(
workspace,
&dep.crate_dir.unwrap().try_into()?,
graph,
opts.clone(),
)?;
}
}
}
Ok( package )
}
#[ allow( clippy ::needless_pass_by_value ) ]
pub fn list
(
workspace: &mut Workspace,
package: &Package< '_ >,
opts: DependenciesOptions
)
-> error ::untyped ::Result< Vec< CrateId > >
{
let mut graph = collection ::HashMap ::new();
let root = list_rec( workspace, package, &mut graph, opts.clone() )?;
let output = match opts.sort
{
DependenciesSort ::Unordered =>
{
graph
.into_iter()
.flat_map( | ( id, dependency ) |
{
dependency
.into_iter()
.chain( Some( id ) )
})
.unique()
.filter( | x | x != &root )
.collect()
}
DependenciesSort ::Topological =>
{
graph ::toposort( graph ::construct( &graph ) )
.map_err( | err | format_err!( "{err}" ) )?
.into_iter()
.filter( | x | x != &root )
.collect()
},
};
Ok( output )
}
}
crate ::mod_interface!
{
exposed use DependencyRef;
exposed use DependencyKind;
own use CrateId;
own use DependenciesSort;
own use DependenciesOptions;
own use list_rec;
own use list;
}