@@ -1600,20 +1600,102 @@ impl EnvironmentPreference {
16001600 }
16011601}
16021602
1603- #[ derive( Debug , Clone , Copy ) ]
1603+ #[ derive( Debug , Clone , Default , Copy , PartialEq , Eq ) ]
16041604pub ( crate ) struct ExecutableName {
1605- name : & ' static str ,
1605+ implementation : Option < ImplementationName > ,
16061606 major : Option < u8 > ,
16071607 minor : Option < u8 > ,
16081608 patch : Option < u8 > ,
16091609 prerelease : Option < Prerelease > ,
16101610 variant : PythonVariant ,
16111611}
16121612
1613+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
1614+ struct ExecutableNameComparator < ' a > {
1615+ name : ExecutableName ,
1616+ request : & ' a VersionRequest ,
1617+ implementation : Option < & ' a ImplementationName > ,
1618+ }
1619+
1620+ impl Ord for ExecutableNameComparator < ' _ > {
1621+ /// Note the comparison returns a reverse priority ordering.
1622+ ///
1623+ /// Higher priority items are "Greater" than lower priority items.
1624+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
1625+ // Prefer the default name over a specific implementation, unless an implementation was
1626+ // requested
1627+ let name_ordering = if self . implementation . is_some ( ) {
1628+ std:: cmp:: Ordering :: Greater
1629+ } else {
1630+ std:: cmp:: Ordering :: Less
1631+ } ;
1632+ if self . name . implementation . is_none ( ) && other. name . implementation . is_some ( ) {
1633+ return name_ordering. reverse ( ) ;
1634+ }
1635+ if self . name . implementation . is_some ( ) && other. name . implementation . is_none ( ) {
1636+ return name_ordering;
1637+ }
1638+ // Otherwise, use the names in supported order
1639+ let ordering = self . name . implementation . cmp ( & other. name . implementation ) ;
1640+ if ordering != std:: cmp:: Ordering :: Equal {
1641+ return ordering;
1642+ }
1643+ let ordering = self . name . major . cmp ( & other. name . major ) ;
1644+ let is_default_request =
1645+ matches ! ( self . request, VersionRequest :: Any | VersionRequest :: Default ) ;
1646+ if ordering != std:: cmp:: Ordering :: Equal {
1647+ return if is_default_request {
1648+ ordering. reverse ( )
1649+ } else {
1650+ ordering
1651+ } ;
1652+ }
1653+ let ordering = self . name . minor . cmp ( & other. name . minor ) ;
1654+ if ordering != std:: cmp:: Ordering :: Equal {
1655+ return if is_default_request {
1656+ ordering. reverse ( )
1657+ } else {
1658+ ordering
1659+ } ;
1660+ }
1661+ let ordering = self . name . patch . cmp ( & other. name . patch ) ;
1662+ if ordering != std:: cmp:: Ordering :: Equal {
1663+ return if is_default_request {
1664+ ordering. reverse ( )
1665+ } else {
1666+ ordering
1667+ } ;
1668+ }
1669+ let ordering = self . name . prerelease . cmp ( & other. name . prerelease ) ;
1670+ if ordering != std:: cmp:: Ordering :: Equal {
1671+ return if is_default_request {
1672+ ordering. reverse ( )
1673+ } else {
1674+ ordering
1675+ } ;
1676+ }
1677+ let ordering = self . name . variant . cmp ( & other. name . variant ) ;
1678+ if ordering != std:: cmp:: Ordering :: Equal {
1679+ return if is_default_request {
1680+ ordering. reverse ( )
1681+ } else {
1682+ ordering
1683+ } ;
1684+ }
1685+ ordering
1686+ }
1687+ }
1688+
1689+ impl PartialOrd for ExecutableNameComparator < ' _ > {
1690+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
1691+ Some ( self . cmp ( other) )
1692+ }
1693+ }
1694+
16131695impl ExecutableName {
16141696 #[ must_use]
1615- fn with_name ( mut self , name : & ' static str ) -> Self {
1616- self . name = name ;
1697+ fn with_implementation ( mut self , implementation : ImplementationName ) -> Self {
1698+ self . implementation = Some ( implementation ) ;
16171699 self
16181700 }
16191701
@@ -1646,24 +1728,27 @@ impl ExecutableName {
16461728 self . variant = variant;
16471729 self
16481730 }
1649- }
16501731
1651- impl Default for ExecutableName {
1652- fn default ( ) -> Self {
1653- Self {
1654- name : "python" ,
1655- major : None ,
1656- minor : None ,
1657- patch : None ,
1658- prerelease : None ,
1659- variant : PythonVariant :: Default ,
1732+ fn into_comparator < ' a > (
1733+ self ,
1734+ request : & ' a VersionRequest ,
1735+ implementation : Option < & ' a ImplementationName > ,
1736+ ) -> ExecutableNameComparator < ' a > {
1737+ ExecutableNameComparator {
1738+ name : self ,
1739+ request ,
1740+ implementation ,
16601741 }
16611742 }
16621743}
16631744
16641745impl std:: fmt:: Display for ExecutableName {
16651746 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
1666- write ! ( f, "{}" , self . name) ?;
1747+ if let Some ( implementation) = self . implementation {
1748+ write ! ( f, "{implementation}" ) ?;
1749+ } else {
1750+ f. write_str ( "python" ) ?;
1751+ }
16671752 if let Some ( major) = self . major {
16681753 write ! ( f, "{major}" ) ?;
16691754 if let Some ( minor) = self . minor {
@@ -1741,15 +1826,15 @@ impl VersionRequest {
17411826 // Add all the implementation-specific names
17421827 if let Some ( implementation) = implementation {
17431828 for i in 0 ..names. len ( ) {
1744- let name = names[ i] . with_name ( implementation. into ( ) ) ;
1829+ let name = names[ i] . with_implementation ( * implementation) ;
17451830 names. push ( name) ;
17461831 }
17471832 } else {
17481833 // When looking for all implementations, include all possible names
17491834 if matches ! ( self , Self :: Any ) {
17501835 for i in 0 ..names. len ( ) {
1751- for implementation in ImplementationName :: long_names ( ) {
1752- let name = names[ i] . with_name ( implementation) ;
1836+ for implementation in ImplementationName :: iter_all ( ) {
1837+ let name = names[ i] . with_implementation ( implementation) ;
17531838 names. push ( name) ;
17541839 }
17551840 }
@@ -1764,6 +1849,9 @@ impl VersionRequest {
17641849 }
17651850 }
17661851
1852+ names. sort_unstable_by_key ( |name| name. into_comparator ( self , implementation) ) ;
1853+ names. reverse ( ) ;
1854+
17671855 names
17681856 }
17691857
0 commit comments