1
1
use crate :: bound:: { Bound , Release } ;
2
2
use crate :: date:: Date ;
3
+ use crate :: time;
3
4
use crate :: version:: { Channel , Version } ;
4
5
use syn:: parse:: { Parse , ParseStream , Result } ;
5
6
use syn:: punctuated:: Punctuated ;
6
7
use syn:: { parenthesized, token, Token } ;
8
+ use std:: sync:: RwLock ;
7
9
8
10
pub enum Expr {
9
11
Stable ,
@@ -16,33 +18,142 @@ pub enum Expr {
16
18
Not ( Box < Expr > ) ,
17
19
Any ( Vec < Expr > ) ,
18
20
All ( Vec < Expr > ) ,
21
+ MinVer ( Bound ) ,
22
+ }
23
+
24
+ pub enum ExprError {
25
+ }
26
+
27
+ impl ExprError {
28
+ fn nightly_date ( mindate : Date , date : Date ) -> Self {
29
+ unimplemented ! ( )
30
+ }
31
+
32
+ fn nightly_channel ( channel : Channel ) -> Self {
33
+ unimplemented ! ( )
34
+ }
35
+
36
+ fn nightly_release ( release : Release ) -> Self {
37
+ unimplemented ! ( )
38
+ }
39
+
40
+ fn release ( minrel : Release , release : Release ) -> Self {
41
+ unimplemented ! ( )
42
+ }
43
+
44
+ fn bad_bound ( minver : Bound , bound : Bound ) -> Self {
45
+ unimplemented ! ( )
46
+ }
47
+
48
+ fn duplicate_minver ( minver : Bound , new_minver : Bound ) -> Self {
49
+ unimplemented ! ( )
50
+ }
51
+ }
52
+
53
+ pub type ExprResult < T > = std:: result:: Result < T , ExprError > ;
54
+
55
+ lazy_static ! {
56
+ static ref MINVER : RwLock <Option <Bound >> = RwLock :: new( None ) ;
57
+ }
58
+
59
+ fn check_minver_channel ( minver : Option < Bound > , channel : Channel ) -> ExprResult < ( ) > {
60
+ match minver {
61
+ Some ( Bound :: Nightly ( mindate) ) => {
62
+ match channel {
63
+ Channel :: Nightly ( checkdate) => if checkdate < mindate {
64
+ Err ( ExprError :: nightly_date ( mindate, checkdate) )
65
+ } else {
66
+ Ok ( ( ) )
67
+ } ,
68
+ Channel :: Stable | Channel :: Beta => Err ( ExprError :: nightly_channel ( channel) ) ,
69
+ _ => Ok ( ( ) ) ,
70
+ }
71
+ } ,
72
+ _ => Ok ( ( ) ) ,
73
+ }
74
+ }
75
+
76
+ fn check_minver_bound ( minver : Option < Bound > , bound : & Bound ) -> ExprResult < ( ) > {
77
+ match minver {
78
+ Some ( minver) => if bound < & minver {
79
+ Err ( ExprError :: bad_bound ( minver, * bound) )
80
+ } else {
81
+ Ok ( ( ) )
82
+ } ,
83
+ None => Ok ( ( ) ) ,
84
+ }
85
+ }
86
+
87
+ fn check_minver_release ( minver : Option < Bound > , release : & Release ) -> ExprResult < ( ) > {
88
+ match minver {
89
+ Some ( Bound :: Nightly ( _) ) => Err ( ExprError :: nightly_release ( * release) ) ,
90
+ Some ( Bound :: Stable ( minrel) ) => if release < & minrel {
91
+ Err ( ExprError :: release ( minrel, * release) )
92
+ } else {
93
+ Ok ( ( ) )
94
+ } ,
95
+ None => Ok ( ( ) ) ,
96
+ }
19
97
}
20
98
21
99
impl Expr {
22
- pub fn eval ( & self , rustc : Version ) -> Result < bool > {
100
+ pub fn eval ( & self , rustc : Version ) -> ExprResult < bool > {
23
101
use self :: Expr :: * ;
24
102
103
+ let minver = {
104
+ let bound = MINVER . read ( ) . expect ( "minver lock poisoned" ) ;
105
+ * bound
106
+ } ;
107
+
25
108
Ok ( match self {
26
- Stable => rustc. channel == Channel :: Stable ,
27
- Beta => rustc. channel == Channel :: Beta ,
28
- Nightly => match rustc. channel {
29
- Channel :: Nightly ( _) | Channel :: Dev => true ,
30
- Channel :: Stable | Channel :: Beta => false ,
109
+ Stable => {
110
+ check_minver_channel ( minver, Channel :: Stable ) ?;
111
+ rustc. channel == Channel :: Stable
112
+ } ,
113
+ Beta => {
114
+ check_minver_channel ( minver, Channel :: Beta ) ?;
115
+ rustc. channel == Channel :: Beta
116
+ } ,
117
+ Nightly => {
118
+ check_minver_channel ( minver, Channel :: Nightly ( time:: today ( ) ) ) ?;
119
+ match rustc. channel {
120
+ Channel :: Nightly ( _) | Channel :: Dev => true ,
121
+ Channel :: Stable | Channel :: Beta => false ,
122
+ }
31
123
} ,
32
- Date ( date) => match rustc. channel {
33
- Channel :: Nightly ( rustc) => rustc == * date,
34
- Channel :: Stable | Channel :: Beta | Channel :: Dev => false ,
124
+ Date ( date) => {
125
+ check_minver_channel ( minver, Channel :: Nightly ( * date) ) ?;
126
+ match rustc. channel {
127
+ Channel :: Nightly ( rustc) => rustc == * date,
128
+ Channel :: Stable | Channel :: Beta | Channel :: Dev => false ,
129
+ }
130
+ } ,
131
+ Since ( bound) => {
132
+ check_minver_bound ( minver, bound) ?;
133
+ rustc >= * bound
134
+ } ,
135
+ Before ( bound) => {
136
+ check_minver_bound ( minver, bound) ?;
137
+ rustc < * bound
35
138
} ,
36
- Since ( bound) => rustc >= * bound,
37
- Before ( bound) => rustc < * bound,
38
139
Release ( release) => {
140
+ check_minver_release ( minver, release) ?;
39
141
rustc. channel == Channel :: Stable
40
142
&& rustc. minor == release. minor
41
143
&& release. patch . map_or ( true , |patch| rustc. patch == patch)
42
144
}
43
145
Not ( expr) => !expr. eval ( rustc) ?,
44
- Any ( exprs) => exprs. iter ( ) . map ( |e| e. eval ( rustc) ) . collect :: < Result < Vec < _ > > > ( ) ?. into_iter ( ) . any ( |b| b) ,
45
- All ( exprs) => exprs. iter ( ) . map ( |e| e. eval ( rustc) ) . collect :: < Result < Vec < _ > > > ( ) ?. into_iter ( ) . all ( |b| b) ,
146
+ Any ( exprs) => exprs. iter ( ) . map ( |e| e. eval ( rustc) ) . collect :: < ExprResult < Vec < _ > > > ( ) ?. into_iter ( ) . any ( |b| b) ,
147
+ All ( exprs) => exprs. iter ( ) . map ( |e| e. eval ( rustc) ) . collect :: < ExprResult < Vec < _ > > > ( ) ?. into_iter ( ) . all ( |b| b) ,
148
+ MinVer ( bound) => {
149
+ if let Some ( minver) = minver {
150
+ Err ( ExprError :: duplicate_minver ( minver, * bound) ) ?
151
+ } else {
152
+ let mut new_minver = MINVER . write ( ) . expect ( "minver lock poisoned" ) ;
153
+ * new_minver = Some ( * bound) ;
154
+ true
155
+ }
156
+ } ,
46
157
} )
47
158
}
48
159
}
@@ -58,6 +169,7 @@ mod keyword {
58
169
syn:: custom_keyword!( not) ;
59
170
syn:: custom_keyword!( any) ;
60
171
syn:: custom_keyword!( all) ;
172
+ syn:: custom_keyword!( minver) ;
61
173
}
62
174
63
175
impl Parse for Expr {
@@ -79,6 +191,8 @@ impl Parse for Expr {
79
191
Self :: parse_any ( input)
80
192
} else if lookahead. peek ( keyword:: all) {
81
193
Self :: parse_all ( input)
194
+ } else if lookahead. peek ( keyword:: minver) {
195
+ Self :: parse_minver ( input)
82
196
} else {
83
197
Err ( lookahead. error ( ) )
84
198
}
@@ -174,4 +288,15 @@ impl Expr {
174
288
175
289
Ok ( Expr :: All ( exprs. into_iter ( ) . collect ( ) ) )
176
290
}
291
+
292
+ fn parse_minver ( input : ParseStream ) -> Result < Self > {
293
+ input. parse :: < keyword:: minver > ( ) ?;
294
+
295
+ let paren;
296
+ parenthesized ! ( paren in input) ;
297
+ let bound: Bound = paren. parse ( ) ?;
298
+ paren. parse :: < Option < Token ! [ , ] > > ( ) ?;
299
+
300
+ Ok ( Expr :: MinVer ( bound) )
301
+ }
177
302
}
0 commit comments