@@ -48,9 +48,144 @@ pub use builder::{
4848} ;
4949pub use errors:: Error ;
5050pub use pkgspec:: PkgSpec ;
51+ use std:: fmt;
5152
5253/// A crate's unique identifier
53- pub type Kid = cargo_metadata:: PackageId ;
54+ #[ derive( Clone , Default ) ]
55+ pub struct Kid {
56+ /// The full package id string as supplied by cargo
57+ pub repr : String ,
58+ /// The subslices for each component in name -> version -> source order
59+ components : [ ( usize , usize ) ; 3 ] ,
60+ }
61+
62+ impl Kid {
63+ /// Gets the name of the package
64+ #[ inline]
65+ pub fn name ( & self ) -> & str {
66+ let ( s, e) = self . components [ 0 ] ;
67+ & self . repr [ s..e]
68+ }
69+
70+ /// Gets the semver of the package
71+ #[ inline]
72+ pub fn version ( & self ) -> & str {
73+ let ( s, e) = self . components [ 1 ] ;
74+ & self . repr [ s..e]
75+ }
76+
77+ /// Gets the source url of the package
78+ #[ inline]
79+ pub fn source ( & self ) -> & str {
80+ let ( s, e) = self . components [ 2 ] ;
81+ & self . repr [ s..e]
82+ }
83+ }
84+
85+ #[ allow( clippy:: fallible_impl_from) ]
86+ impl From < cargo_metadata:: PackageId > for Kid {
87+ fn from ( pid : cargo_metadata:: PackageId ) -> Self {
88+ let repr = pid. repr ;
89+
90+ let gen = || {
91+ let components = if repr. contains ( ' ' ) {
92+ let name = ( 0 , repr. find ( ' ' ) ?) ;
93+ let version = ( name. 1 + 1 , repr[ name. 1 + 1 ..] . find ( ' ' ) ? + name. 1 + 1 ) ;
94+ // Note we skip the open and close parentheses as they are superfluous
95+ // as every source has them, as well as not being present in the new
96+ // stabilized format
97+ //
98+ // Note that we also chop off the commit id, it is not present in
99+ // the stabilized format and is not used for package identification anyways
100+ let source = ( version. 1 + 2 , repr. rfind ( '#' ) . unwrap_or ( repr. len ( ) - 1 ) ) ;
101+
102+ [ name, version, source]
103+ } else {
104+ let vmn = repr. rfind ( '#' ) ?;
105+ let ( name, version) = if let Some ( split) = repr[ vmn..] . find ( '@' ) {
106+ ( ( vmn + 1 , vmn + split) , ( vmn + split + 1 , repr. len ( ) ) )
107+ } else {
108+ let begin = repr. rfind ( '/' ) ? + 1 ;
109+ let end = if repr. starts_with ( "git+" ) {
110+ repr[ begin..] . find ( '?' ) ? + begin
111+ } else {
112+ vmn
113+ } ;
114+
115+ ( ( begin, end) , ( vmn + 1 , repr. len ( ) ) )
116+ } ;
117+
118+ [ name, version, ( 0 , vmn) ]
119+ } ;
120+
121+ Some ( components)
122+ } ;
123+
124+ if let Some ( components) = gen ( ) {
125+ Self { repr, components }
126+ } else {
127+ panic ! ( "unable to parse package id '{repr}'" ) ;
128+ }
129+ }
130+ }
131+
132+ impl fmt:: Debug for Kid {
133+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
134+ let mut ds = f. debug_struct ( "Kid" ) ;
135+
136+ ds. field ( "name" , & self . name ( ) )
137+ . field ( "version" , & self . version ( ) ) ;
138+
139+ let src = self . source ( ) ;
140+ if src != "registry+https://github.com/rust-lang/crates.io-index" {
141+ ds. field ( "source" , & src) ;
142+ }
143+
144+ ds. finish ( )
145+ }
146+ }
147+
148+ impl fmt:: Display for Kid {
149+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
150+ f. write_str ( & self . repr )
151+ }
152+ }
153+
154+ impl std:: hash:: Hash for Kid {
155+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
156+ state. write ( self . repr . as_bytes ( ) ) ;
157+ }
158+ }
159+
160+ impl Ord for Kid {
161+ fn cmp ( & self , o : & Self ) -> std:: cmp:: Ordering {
162+ let a = & self . repr ;
163+ let b = & o. repr ;
164+
165+ for ( ar, br) in self . components . into_iter ( ) . zip ( o. components . into_iter ( ) ) {
166+ let ord = a[ ar. 0 ..ar. 1 ] . cmp ( & b[ br. 0 ..br. 1 ] ) ;
167+ if ord != std:: cmp:: Ordering :: Equal {
168+ return ord;
169+ }
170+ }
171+
172+ std:: cmp:: Ordering :: Equal
173+ }
174+ }
175+
176+ impl PartialOrd for Kid {
177+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
178+ Some ( self . cmp ( other) )
179+ }
180+ }
181+
182+ impl Eq for Kid { }
183+
184+ impl PartialEq for Kid {
185+ fn eq ( & self , other : & Self ) -> bool {
186+ self . cmp ( other) == std:: cmp:: Ordering :: Equal
187+ }
188+ }
54189
55190/// The set of features that have been enabled on a crate
56191pub type EnabledFeatures = std:: collections:: BTreeSet < String > ;
@@ -84,8 +219,6 @@ impl PartialEq<DK> for DepKind {
84219 }
85220}
86221
87- use std:: fmt;
88-
89222impl fmt:: Display for DepKind {
90223 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
91224 match self {
@@ -509,29 +642,36 @@ where
509642 ///
510643 /// fn print(krates: &Krates, name: &str) {
511644 /// let req = VersionReq::parse("=0.2").unwrap();
512- /// for vs in krates.search_matches(name, req.clone()).map(|(_, krate) | &krate.version) {
513- /// println!("found version {} matching {}!", vs, req );
645+ /// for vs in krates.search_matches(name, req.clone()).map(|km | &km. krate.version) {
646+ /// println!("found version {vs } matching {req }!");
514647 /// }
515648 /// }
516649 /// ```
517650 pub fn search_matches (
518651 & self ,
519652 name : impl Into < String > ,
520653 req : semver:: VersionReq ,
521- ) -> impl Iterator < Item = ( NodeId , & N ) > {
654+ ) -> impl Iterator < Item = KrateMatch < ' _ , N > > {
522655 let raw_nodes = & self . graph . raw_nodes ( ) [ 0 ..self . krates_end ] ;
523656
524657 let name = name. into ( ) ;
525658
526- raw_nodes. iter ( ) . enumerate ( ) . filter_map ( move |( id, node) | {
527- if let Node :: Krate { krate, .. } = & node. weight {
528- if krate. name ( ) == name && req. matches ( krate. version ( ) ) {
529- return Some ( ( NodeId :: new ( id) , krate) ) ;
659+ raw_nodes
660+ . iter ( )
661+ . enumerate ( )
662+ . filter_map ( move |( index, node) | {
663+ if let Node :: Krate { krate, id, .. } = & node. weight {
664+ if krate. name ( ) == name && req. matches ( krate. version ( ) ) {
665+ return Some ( KrateMatch {
666+ node_id : NodeId :: new ( index) ,
667+ krate,
668+ kid : id,
669+ } ) ;
670+ }
530671 }
531- }
532672
533- None
534- } )
673+ None
674+ } )
535675 }
536676
537677 /// Get an iterator over all of the crates in the graph with the given name,
@@ -541,28 +681,44 @@ where
541681 /// use krates::Krates;
542682 ///
543683 /// fn print_all_versions(krates: &Krates, name: &str) {
544- /// for vs in krates.krates_by_name(name).map(|(_, krate) | &krate.version) {
545- /// println!("found version {}", vs );
684+ /// for vs in krates.krates_by_name(name).map(|km | &km. krate.version) {
685+ /// println!("found version {vs}" );
546686 /// }
547687 /// }
548688 /// ```
549- pub fn krates_by_name ( & self , name : impl Into < String > ) -> impl Iterator < Item = ( NodeId , & N ) > {
689+ pub fn krates_by_name (
690+ & self ,
691+ name : impl Into < String > ,
692+ ) -> impl Iterator < Item = KrateMatch < ' _ , N > > {
550693 let raw_nodes = & self . graph . raw_nodes ( ) [ 0 ..self . krates_end ] ;
551694
552695 let name = name. into ( ) ;
553696
554- raw_nodes. iter ( ) . enumerate ( ) . filter_map ( move |( id, node) | {
555- if let Node :: Krate { krate, .. } = & node. weight {
556- if krate. name ( ) == name {
557- return Some ( ( NodeId :: new ( id) , krate) ) ;
697+ raw_nodes
698+ . iter ( )
699+ . enumerate ( )
700+ . filter_map ( move |( index, node) | {
701+ if let Node :: Krate { krate, id, .. } = & node. weight {
702+ if krate. name ( ) == name {
703+ return Some ( KrateMatch {
704+ node_id : NodeId :: new ( index) ,
705+ krate,
706+ kid : id,
707+ } ) ;
708+ }
558709 }
559- }
560710
561- None
562- } )
711+ None
712+ } )
563713 }
564714}
565715
716+ pub struct KrateMatch < ' graph , N > {
717+ pub krate : & ' graph N ,
718+ pub kid : & ' graph Kid ,
719+ pub node_id : NodeId ,
720+ }
721+
566722impl < N , E > std:: ops:: Index < NodeId > for Krates < N , E > {
567723 type Output = N ;
568724
@@ -586,3 +742,31 @@ impl<N, E> std::ops::Index<usize> for Krates<N, E> {
586742 }
587743 }
588744}
745+
746+ #[ cfg( test) ]
747+ mod tests {
748+ #[ test]
749+ fn converts_package_ids ( ) {
750+ let ids = [
751+ ( "registry+https://github.com/rust-lang/crates.io-index#[email protected] " , "ab_glyph" , "0.2.22" , "registry+https://github.com/rust-lang/crates.io-index" ) , 752+ ( "git+https://github.com/EmbarkStudios/egui-stylist?rev=3900e8aedc5801e42c1bb747cfd025615bf3b832#0.2.0" , "egui-stylist" , "0.2.0" , "git+https://github.com/EmbarkStudios/egui-stylist?rev=3900e8aedc5801e42c1bb747cfd025615bf3b832" ) ,
753+ ( "path+file:///home/jake/code/ark/components/allocator#[email protected] " , "ark-allocator" , "0.1.0" , "path+file:///home/jake/code/ark/components/allocator" ) , 754+ ( "git+https://github.com/EmbarkStudios/ash?branch=nv-low-latency2#0.38.0+1.3.269" , "ash" , "0.38.0+1.3.269" , "git+https://github.com/EmbarkStudios/ash?branch=nv-low-latency2" ) ,
755+ ( "git+https://github.com/EmbarkStudios/fsr-rs?branch=nv-low-latency2#[email protected] " , "fsr" , "0.1.7" , "git+https://github.com/EmbarkStudios/fsr-rs?branch=nv-low-latency2" ) , 756+ ( "fuser 0.4.1 (git+https://github.com/cberner/fuser?branch=master#b2e7622942e52a28ffa85cdaf48e28e982bb6923)" , "fuser" , "0.4.1" , "git+https://github.com/cberner/fuser?branch=master" ) ,
757+ ( "fuser 0.4.1 (git+https://github.com/cberner/fuser?rev=b2e7622#b2e7622942e52a28ffa85cdaf48e28e982bb6923)" , "fuser" , "0.4.1" , "git+https://github.com/cberner/fuser?rev=b2e7622" ) ,
758+ ( "a 0.1.0 (path+file:///home/jake/code/krates/tests/ws/a)" , "a" , "0.1.0" , "path+file:///home/jake/code/krates/tests/ws/a" ) ,
759+ ( "bindgen 0.59.2 (registry+https://github.com/rust-lang/crates.io-index)" , "bindgen" , "0.59.2" , "registry+https://github.com/rust-lang/crates.io-index" ) ,
760+ ] ;
761+
762+ for ( repr, name, version, source) in ids {
763+ let kid = super :: Kid :: from ( cargo_metadata:: PackageId {
764+ repr : repr. to_owned ( ) ,
765+ } ) ;
766+
767+ assert_eq ! ( kid. name( ) , name) ;
768+ assert_eq ! ( kid. version( ) , version) ;
769+ assert_eq ! ( kid. source( ) , source) ;
770+ }
771+ }
772+ }
0 commit comments