@@ -10,10 +10,25 @@ use crate::core::PartialVersionError;
1010#[ serde( transparent) ]
1111pub struct RustVersion ( PartialVersion ) ;
1212
13- impl std:: ops:: Deref for RustVersion {
14- type Target = PartialVersion ;
13+ impl RustVersion {
14+ pub fn is_compatible_with ( & self , rustc : & PartialVersion ) -> bool {
15+ let msrv = self . 0 . to_caret_req ( ) ;
16+ // Remove any pre-release identifiers for easier comparison
17+ let rustc = semver:: Version {
18+ major : rustc. major ,
19+ minor : rustc. minor . unwrap_or_default ( ) ,
20+ patch : rustc. patch . unwrap_or_default ( ) ,
21+ pre : Default :: default ( ) ,
22+ build : Default :: default ( ) ,
23+ } ;
24+ msrv. matches ( & rustc)
25+ }
26+
27+ pub fn into_partial ( self ) -> PartialVersion {
28+ self . 0
29+ }
1530
16- fn deref ( & self ) -> & Self :: Target {
31+ pub fn as_partial ( & self ) -> & PartialVersion {
1732 & self . 0
1833 }
1934}
@@ -28,6 +43,15 @@ impl std::str::FromStr for RustVersion {
2843 }
2944}
3045
46+ impl TryFrom < semver:: Version > for RustVersion {
47+ type Error = RustVersionError ;
48+
49+ fn try_from ( version : semver:: Version ) -> Result < Self , Self :: Error > {
50+ let version = PartialVersion :: from ( version) ;
51+ Self :: try_from ( version)
52+ }
53+ }
54+
3155impl TryFrom < PartialVersion > for RustVersion {
3256 type Error = RustVersionError ;
3357
@@ -78,3 +102,72 @@ enum RustVersionErrorKind {
78102 #[ error( transparent) ]
79103 PartialVersion ( #[ from] PartialVersionError ) ,
80104}
105+
106+ #[ cfg( test) ]
107+ mod test {
108+ use super :: * ;
109+
110+ #[ test]
111+ fn is_compatible_with_rustc ( ) {
112+ let cases = & [
113+ ( "1" , "1.70.0" , true ) ,
114+ ( "1.30" , "1.70.0" , true ) ,
115+ ( "1.30.10" , "1.70.0" , true ) ,
116+ ( "1.70" , "1.70.0" , true ) ,
117+ ( "1.70.0" , "1.70.0" , true ) ,
118+ ( "1.70.1" , "1.70.0" , false ) ,
119+ ( "1.70" , "1.70.0-nightly" , true ) ,
120+ ( "1.70.0" , "1.70.0-nightly" , true ) ,
121+ ( "1.71" , "1.70.0" , false ) ,
122+ ( "2" , "1.70.0" , false ) ,
123+ ] ;
124+ let mut passed = true ;
125+ for ( msrv, rustc, expected) in cases {
126+ let msrv: RustVersion = msrv. parse ( ) . unwrap ( ) ;
127+ let rustc = PartialVersion :: from ( semver:: Version :: parse ( rustc) . unwrap ( ) ) ;
128+ if msrv. is_compatible_with ( & rustc) != * expected {
129+ println ! ( "failed: {msrv} is_compatible_with {rustc} == {expected}" ) ;
130+ passed = false ;
131+ }
132+ }
133+ assert ! ( passed) ;
134+ }
135+
136+ #[ test]
137+ fn is_compatible_with_workspace_msrv ( ) {
138+ let cases = & [
139+ ( "1" , "1" , true ) ,
140+ ( "1" , "1.70" , true ) ,
141+ ( "1" , "1.70.0" , true ) ,
142+ ( "1.30" , "1" , false ) ,
143+ ( "1.30" , "1.70" , true ) ,
144+ ( "1.30" , "1.70.0" , true ) ,
145+ ( "1.30.10" , "1" , false ) ,
146+ ( "1.30.10" , "1.70" , true ) ,
147+ ( "1.30.10" , "1.70.0" , true ) ,
148+ ( "1.70" , "1" , false ) ,
149+ ( "1.70" , "1.70" , true ) ,
150+ ( "1.70" , "1.70.0" , true ) ,
151+ ( "1.70.0" , "1" , false ) ,
152+ ( "1.70.0" , "1.70" , true ) ,
153+ ( "1.70.0" , "1.70.0" , true ) ,
154+ ( "1.70.1" , "1" , false ) ,
155+ ( "1.70.1" , "1.70" , false ) ,
156+ ( "1.70.1" , "1.70.0" , false ) ,
157+ ( "1.71" , "1" , false ) ,
158+ ( "1.71" , "1.70" , false ) ,
159+ ( "1.71" , "1.70.0" , false ) ,
160+ ( "2" , "1.70.0" , false ) ,
161+ ] ;
162+ let mut passed = true ;
163+ for ( dep_msrv, ws_msrv, expected) in cases {
164+ let dep_msrv: RustVersion = dep_msrv. parse ( ) . unwrap ( ) ;
165+ let ws_msrv = ws_msrv. parse :: < RustVersion > ( ) . unwrap ( ) . into_partial ( ) ;
166+ if dep_msrv. is_compatible_with ( & ws_msrv) != * expected {
167+ println ! ( "failed: {dep_msrv} is_compatible_with {ws_msrv} == {expected}" ) ;
168+ passed = false ;
169+ }
170+ }
171+ assert ! ( passed) ;
172+ }
173+ }
0 commit comments