@@ -8,7 +8,11 @@ use diesel::prelude::*;
88/// This struct is used to load all versions of a crate from the database,
99/// without loading all the additional data unnecessary for default version
1010/// resolution.
11- #[ derive( Clone , Debug , Queryable , Selectable ) ]
11+ ///
12+ /// It implements [Ord] in a way that sorts versions by the criteria specified
13+ /// in the [update_default_version] function documentation. The default version
14+ /// will be the "maximum" element in a sorted list of versions.
15+ #[ derive( Clone , Debug , PartialEq , Eq , Queryable , Selectable ) ]
1216#[ diesel( table_name = versions) ]
1317#[ diesel( check_for_backend( diesel:: pg:: Pg ) ) ]
1418struct Version {
@@ -23,6 +27,22 @@ impl Version {
2327 fn is_prerelease ( & self ) -> bool {
2428 !self . num . pre . is_empty ( )
2529 }
30+
31+ fn ord_tuple ( & self ) -> ( bool , bool , & semver:: Version , i32 ) {
32+ ( !self . yanked , !self . is_prerelease ( ) , & self . num , self . id )
33+ }
34+ }
35+
36+ impl PartialOrd for Version {
37+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
38+ Some ( self . cmp ( other) )
39+ }
40+ }
41+
42+ impl Ord for Version {
43+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
44+ self . ord_tuple ( ) . cmp ( & other. ord_tuple ( ) )
45+ }
2646}
2747
2848/// Updates the `default_versions` table entry for the specified crate.
@@ -102,20 +122,16 @@ fn calculate_default_version(crate_id: i32, conn: &mut impl Conn) -> QueryResult
102122}
103123
104124fn find_default_version ( versions : & [ Version ] ) -> Option < & Version > {
105- highest ( versions, |v| !v. is_prerelease ( ) && !v. yanked )
106- . or_else ( || highest ( versions, |v| !v. yanked ) )
107- . or_else ( || highest ( versions, |_| true ) )
108- }
109-
110- fn highest ( versions : & [ Version ] , filter : impl FnMut ( & & Version ) -> bool ) -> Option < & Version > {
111- versions. iter ( ) . filter ( filter) . max_by_key ( |v| & v. num )
125+ versions. iter ( ) . max ( )
112126}
113127
114128#[ cfg( test) ]
115129mod tests {
116130 use super :: * ;
117131 use crate :: schema:: crates;
118132 use crate :: test_util:: test_db_connection;
133+ use insta:: assert_snapshot;
134+ use std:: fmt:: Write ;
119135
120136 fn v ( num : & str , yanked : bool ) -> Version {
121137 let num = semver:: Version :: parse ( num) . unwrap ( ) ;
@@ -179,6 +195,51 @@ mod tests {
179195 check ( & versions, "1.0.0-beta.3" ) ;
180196 }
181197
198+ #[ test]
199+ fn test_ord ( ) {
200+ let mut versions = vec ! [
201+ v( "1.0.0" , false ) ,
202+ v( "1.0.0-beta.1" , false ) ,
203+ v( "1.0.0-beta.2" , false ) ,
204+ v( "1.0.0-beta.3" , false ) ,
205+ v( "1.0.1" , true ) ,
206+ v( "1.0.2" , false ) ,
207+ v( "1.1.0" , false ) ,
208+ v( "1.1.1-beta.1" , true ) ,
209+ v( "1.1.1" , true ) ,
210+ v( "1.0.3" , false ) ,
211+ v( "2.0.0-beta.1" , false ) ,
212+ ] ;
213+
214+ versions. sort ( ) ;
215+
216+ assert_snapshot ! ( format_versions( & versions) , @r#"
217+ 1.1.1-beta.1 (yanked)
218+ 1.0.1 (yanked)
219+ 1.1.1 (yanked)
220+ 1.0.0-beta.1
221+ 1.0.0-beta.2
222+ 1.0.0-beta.3
223+ 2.0.0-beta.1
224+ 1.0.0
225+ 1.0.2
226+ 1.0.3
227+ 1.1.0
228+ "# ) ;
229+ }
230+
231+ fn format_versions ( versions : & [ Version ] ) -> String {
232+ let mut buf = String :: with_capacity ( versions. len ( ) * 20 ) ;
233+ for v in versions {
234+ write ! ( buf, "{}" , v. num) . unwrap ( ) ;
235+ if v. yanked {
236+ buf. push_str ( " (yanked)" ) ;
237+ }
238+ buf. push ( '\n' ) ;
239+ }
240+ buf
241+ }
242+
182243 fn create_crate ( name : & str , conn : & mut impl Conn ) -> i32 {
183244 diesel:: insert_into ( crates:: table)
184245 . values ( crates:: name. eq ( name) )
0 commit comments