@@ -86,6 +86,7 @@ at your option.
8686*/
8787
8888use std:: {
89+ cmp:: Ordering ,
8990 collections:: btree_map:: { self , BTreeMap } ,
9091 env, fmt, fs, io,
9192 path:: { Path , PathBuf } ,
@@ -94,7 +95,10 @@ use std::{
9495 time:: SystemTime ,
9596} ;
9697
97- use toml_edit:: { DocumentMut , Item , Table , TomlError } ;
98+ use tomling:: {
99+ cargo:: { Dependencies , Dependency , Manifest } ,
100+ from_str, Error as TomlError ,
101+ } ;
98102
99103/// Error type used by this crate.
100104pub enum Error {
@@ -125,8 +129,9 @@ impl fmt::Debug for Error {
125129impl fmt:: Display for Error {
126130 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
127131 match self {
128- Error :: NotFound ( path) =>
129- write ! ( f, "Could not find `Cargo.toml` in manifest dir: `{}`." , path. display( ) ) ,
132+ Error :: NotFound ( path) => {
133+ write ! ( f, "Could not find `Cargo.toml` in manifest dir: `{}`." , path. display( ) )
134+ } ,
130135 Error :: CargoManifestDirNotSet =>
131136 f. write_str ( "`CARGO_MANIFEST_DIR` env variable not set." ) ,
132137 Error :: CouldNotRead { path, .. } => write ! ( f, "Could not read `{}`." , path. display( ) ) ,
@@ -280,10 +285,12 @@ fn read_cargo_toml(
280285 manifest_ts : SystemTime ,
281286 workspace_manifest_ts : SystemTime ,
282287) -> Result < CacheEntry , Error > {
283- let manifest = open_cargo_toml ( manifest_path) ?;
288+ let content = open_cargo_toml ( manifest_path) ?;
289+ let manifest = parse_cargo_toml ( & content) ?;
284290
285291 let workspace_dependencies = if manifest_path != workspace_manifest_path {
286- let workspace_manifest = open_cargo_toml ( workspace_manifest_path) ?;
292+ let content = open_cargo_toml ( workspace_manifest_path) ?;
293+ let workspace_manifest = parse_cargo_toml ( & content) ?;
287294 extract_workspace_dependencies ( & workspace_manifest) ?
288295 } else {
289296 extract_workspace_dependencies ( & manifest) ?
@@ -304,42 +311,41 @@ fn read_cargo_toml(
304311/// Returns a hash map that maps from dep name to the package name. Dep name
305312/// and package name can be the same if there doesn't exist any rename.
306313fn extract_workspace_dependencies (
307- workspace_toml : & DocumentMut ,
314+ workspace_toml : & Manifest ,
308315) -> Result < BTreeMap < String , String > , Error > {
309- Ok ( workspace_dep_tables ( & workspace_toml)
316+ Ok ( workspace_toml
317+ . workspace ( )
318+ . and_then ( |w| w. dependencies ( ) )
319+ . map ( |d| d. iter ( ) )
310320 . into_iter ( )
311321 . flatten ( )
312- . map ( move |( dep_name, dep_value ) | {
313- let pkg_name = dep_value . get ( " package" ) . and_then ( |i| i . as_str ( ) ) . unwrap_or ( dep_name) ;
322+ . map ( move |( dep_name, dep ) | {
323+ let pkg_name = dep . package ( ) . unwrap_or ( dep_name) ;
314324
315325 ( dep_name. to_owned ( ) , pkg_name. to_owned ( ) )
316326 } )
317327 . collect ( ) )
318328}
319329
320- /// Return an iterator over all `[workspace.dependencies]`
321- fn workspace_dep_tables ( cargo_toml : & DocumentMut ) -> Option < & Table > {
322- cargo_toml
323- . get ( "workspace" )
324- . and_then ( |w| w. as_table ( ) ?. get ( "dependencies" ) ?. as_table ( ) )
325- }
326-
327330/// Make sure that the given crate name is a valid rust identifier.
328331fn sanitize_crate_name < S : AsRef < str > > ( name : S ) -> String {
329332 name. as_ref ( ) . replace ( '-' , "_" )
330333}
331334
335+ /// Open the given `Cargo.toml` file and read it's content as a string.
336+ fn open_cargo_toml ( path : & Path ) -> Result < String , Error > {
337+ fs:: read_to_string ( path) . map_err ( |e| Error :: CouldNotRead { source : e, path : path. into ( ) } )
338+ }
339+
332340/// Open the given `Cargo.toml` and parse it into a hashmap.
333- fn open_cargo_toml ( path : & Path ) -> Result < DocumentMut , Error > {
334- let content = fs:: read_to_string ( path)
335- . map_err ( |e| Error :: CouldNotRead { source : e, path : path. into ( ) } ) ?;
336- content. parse :: < DocumentMut > ( ) . map_err ( |e| Error :: InvalidToml { source : e } )
341+ fn parse_cargo_toml ( content : & str ) -> Result < Manifest < ' _ > , Error > {
342+ from_str ( content) . map_err ( |e| Error :: InvalidToml { source : e } )
337343}
338344
339345/// Extract all crate names from the given `Cargo.toml` by checking the `dependencies` and
340346/// `dev-dependencies`.
341347fn extract_crate_names (
342- cargo_toml : & DocumentMut ,
348+ cargo_toml : & Manifest ,
343349 workspace_dependencies : BTreeMap < String , String > ,
344350) -> Result < CrateNames , Error > {
345351 let package_name = extract_package_name ( cargo_toml) ;
@@ -355,16 +361,16 @@ fn extract_crate_names(
355361 } ) ;
356362
357363 let dep_tables = dep_tables ( cargo_toml) . chain ( target_dep_tables ( cargo_toml) ) ;
358- let dep_pkgs = dep_tables. flatten ( ) . filter_map ( move |( dep_name, dep_value ) | {
359- let pkg_name = dep_value . get ( " package" ) . and_then ( |i| i . as_str ( ) ) . unwrap_or ( dep_name) ;
364+ let dep_pkgs = dep_tables. filter_map ( move |( dep_name, dep ) | {
365+ let pkg_name = dep . package ( ) . unwrap_or ( dep_name) ;
360366
361367 // We already handle this via `root_pkg` above.
362368 if package_name. as_ref ( ) . map_or ( false , |n| * n == pkg_name) {
363- return None
369+ return None ;
364370 }
365371
366372 // Check if this is a workspace dependency.
367- let workspace = dep_value . get ( " workspace" ) . and_then ( |w| w . as_bool ( ) ) . unwrap_or_default ( ) ;
373+ let workspace = dep . workspace ( ) . unwrap_or_default ( ) ;
368374
369375 let pkg_name = workspace
370376 . then ( || workspace_dependencies. get ( pkg_name) . map ( |p| p. as_ref ( ) ) )
@@ -379,22 +385,42 @@ fn extract_crate_names(
379385 Ok ( root_pkg. into_iter ( ) . chain ( dep_pkgs) . collect ( ) )
380386}
381387
382- fn extract_package_name ( cargo_toml : & DocumentMut ) -> Option < & str > {
383- cargo_toml. get ( " package" ) ? . get ( "name" ) ? . as_str ( )
388+ fn extract_package_name < ' c > ( cargo_toml : & ' c Manifest ) -> Option < & ' c str > {
389+ cargo_toml. package ( ) . map ( |p| p . name ( ) )
384390}
385391
386- fn target_dep_tables ( cargo_toml : & DocumentMut ) -> impl Iterator < Item = & Table > {
387- cargo_toml. get ( "target" ) . into_iter ( ) . filter_map ( Item :: as_table) . flat_map ( |t| {
388- t. iter ( ) . map ( |( _, value) | value) . filter_map ( Item :: as_table) . flat_map ( dep_tables)
392+ fn target_dep_tables < ' c > (
393+ cargo_toml : & ' c Manifest ,
394+ ) -> impl Iterator < Item = ( & ' c str , & ' c Dependency < ' c > ) > {
395+ cargo_toml. targets ( ) . into_iter ( ) . flat_map ( |t| {
396+ t. iter ( )
397+ . map ( |( _, t) | t)
398+ . flat_map ( |t| combined_dep_tables ( t. dependencies ( ) , t. dev_dependencies ( ) ) )
389399 } )
390400}
391401
392- fn dep_tables ( table : & Table ) -> impl Iterator < Item = & Table > {
393- table
394- . get ( "dependencies" )
402+ fn dep_tables < ' c > ( cargo_toml : & ' c Manifest ) -> impl Iterator < Item = ( & ' c str , & ' c Dependency < ' c > ) > {
403+ combined_dep_tables ( cargo_toml. dependencies ( ) , cargo_toml. dev_dependencies ( ) )
404+ }
405+
406+ fn combined_dep_tables < ' c > (
407+ deps : Option < & ' c Dependencies < ' c > > ,
408+ dev_deps : Option < & ' c Dependencies < ' c > > ,
409+ ) -> impl Iterator < Item = ( & ' c str , & ' c Dependency < ' c > ) > {
410+ let mut deps = deps
395411 . into_iter ( )
396- . chain ( table. get ( "dev-dependencies" ) )
397- . filter_map ( Item :: as_table)
412+ . flat_map ( |deps| deps. iter ( ) )
413+ . chain ( dev_deps. into_iter ( ) . flat_map ( |deps| deps. iter ( ) ) )
414+ . collect :: < Vec < _ > > ( ) ;
415+ // Ensure renames (i-e deps with `package` key) are listed the last.
416+ deps. sort_by ( |( _, a) , ( _, b) | match ( a. package ( ) , b. package ( ) ) {
417+ ( Some ( a) , Some ( b) ) => a. cmp ( b) ,
418+ ( Some ( _) , None ) => Ordering :: Greater ,
419+ ( None , Some ( _) ) => Ordering :: Less ,
420+ ( None , None ) => Ordering :: Equal ,
421+ } ) ;
422+
423+ deps. into_iter ( )
398424}
399425
400426#[ cfg( test) ]
@@ -410,16 +436,18 @@ mod tests {
410436 ) => {
411437 #[ test]
412438 fn $name( ) {
413- let cargo_toml = $cargo_toml. parse :: < DocumentMut > ( )
439+ let cargo_toml = from_str ( $cargo_toml)
414440 . expect( "Parses `Cargo.toml`" ) ;
415- let workspace_cargo_toml = $workspace_toml. parse :: < DocumentMut > ( )
441+ let workspace_cargo_toml = from_str ( $workspace_toml)
416442 . expect( "Parses workspace `Cargo.toml`" ) ;
417443
418444 let workspace_deps = extract_workspace_dependencies( & workspace_cargo_toml)
419445 . expect( "Extracts workspace dependencies" ) ;
420446
421447 match extract_crate_names( & cargo_toml, workspace_deps)
422- . map( |mut map| map. remove( "my_crate" ) )
448+ . map( |mut map| {
449+ map. remove( "my_crate" )
450+ } )
423451 {
424452 $( $result ) * => ( ) ,
425453 o => panic!( "Invalid result: {:?}" , o) ,
0 commit comments