1818//! * Library features have at most one `since` value
1919
2020use std:: collections:: HashMap ;
21+ use std:: fmt;
2122use std:: fs:: File ;
2223use std:: io:: prelude:: * ;
2324use std:: path:: Path ;
2425
25- const STATUSES : & ' static [ & ' static str ] = & [
26- "Active" , "Deprecated" , "Removed" , "Accepted" ,
27- ] ;
26+ #[ derive( PartialEq ) ]
27+ enum Status {
28+ Stable ,
29+ Unstable ,
30+ }
31+
32+ impl fmt:: Display for Status {
33+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
34+ let as_str = match * self {
35+ Status :: Stable => "stable" ,
36+ Status :: Unstable => "unstable" ,
37+ } ;
38+ fmt:: Display :: fmt ( as_str, f)
39+ }
40+ }
41+
2842
2943struct Feature {
3044 name : String ,
45+ level : Status ,
3146 since : String ,
32- status : String ,
3347}
3448
3549struct LibFeature {
36- level : String ,
50+ level : Status ,
3751 since : String ,
3852}
3953
4054pub fn check ( path : & Path , bad : & mut bool ) {
4155 let features = collect_lang_features ( & path. join ( "libsyntax/feature_gate.rs" ) ) ;
56+ assert ! ( !features. is_empty( ) ) ;
4257 let mut lib_features = HashMap :: < String , LibFeature > :: new ( ) ;
4358
4459 let mut contents = String :: new ( ) ;
@@ -48,7 +63,7 @@ pub fn check(path: &Path, bad: &mut bool) {
4863 let filename = file. file_name ( ) . unwrap ( ) . to_string_lossy ( ) ;
4964 if !filename. ends_with ( ".rs" ) || filename == "features.rs" ||
5065 filename == "diagnostic_list.rs" {
51- return
66+ return ;
5267 }
5368
5469 contents. truncate ( 0 ) ;
@@ -60,24 +75,24 @@ pub fn check(path: &Path, bad: &mut bool) {
6075 * bad = true ;
6176 } ;
6277 let level = if line. contains ( "[unstable(" ) {
63- "unstable"
78+ Status :: Unstable
6479 } else if line. contains ( "[stable(" ) {
65- "stable"
80+ Status :: Stable
6681 } else {
67- continue
82+ continue ;
6883 } ;
6984 let feature_name = match find_attr_val ( line, "feature" ) {
7085 Some ( name) => name,
7186 None => {
7287 err ( "malformed stability attribute" ) ;
73- continue
88+ continue ;
7489 }
7590 } ;
7691 let since = match find_attr_val ( line, "since" ) {
7792 Some ( name) => name,
78- None if level == "stable" => {
93+ None if level == Status :: Stable => {
7994 err ( "malformed stability attribute" ) ;
80- continue
95+ continue ;
8196 }
8297 None => "None" ,
8398 } ;
@@ -92,27 +107,34 @@ pub fn check(path: &Path, bad: &mut bool) {
92107 if s. since != since {
93108 err ( "different `since` than before" ) ;
94109 }
95- continue
110+ continue ;
96111 }
97- lib_features. insert ( feature_name. to_owned ( ) , LibFeature {
98- level : level. to_owned ( ) ,
99- since : since. to_owned ( ) ,
100- } ) ;
112+ lib_features. insert ( feature_name. to_owned ( ) ,
113+ LibFeature {
114+ level : level,
115+ since : since. to_owned ( ) ,
116+ } ) ;
101117 }
102118 } ) ;
103119
104120 if * bad {
105- return
121+ return ;
106122 }
107123
108124 let mut lines = Vec :: new ( ) ;
109125 for feature in features {
110126 lines. push ( format ! ( "{:<32} {:<8} {:<12} {:<8}" ,
111- feature. name, "lang" , feature. status, feature. since) ) ;
127+ feature. name,
128+ "lang" ,
129+ feature. level,
130+ feature. since) ) ;
112131 }
113132 for ( name, feature) in lib_features {
114133 lines. push ( format ! ( "{:<32} {:<8} {:<12} {:<8}" ,
115- name, "lib" , feature. level, feature. since) ) ;
134+ name,
135+ "lib" ,
136+ feature. level,
137+ feature. since) ) ;
116138 }
117139
118140 lines. sort ( ) ;
@@ -122,39 +144,32 @@ pub fn check(path: &Path, bad: &mut bool) {
122144}
123145
124146fn find_attr_val < ' a > ( line : & ' a str , attr : & str ) -> Option < & ' a str > {
125- line. find ( attr) . and_then ( |i| {
126- line[ i..] . find ( "\" " ) . map ( |j| i + j + 1 )
127- } ) . and_then ( |i| {
128- line[ i..] . find ( "\" " ) . map ( |j| ( i, i + j) )
129- } ) . map ( |( i, j) | {
130- & line[ i..j]
131- } )
147+ line. find ( attr)
148+ . and_then ( |i| line[ i..] . find ( '"' ) . map ( |j| i + j + 1 ) )
149+ . and_then ( |i| line[ i..] . find ( '"' ) . map ( |j| ( i, i + j) ) )
150+ . map ( |( i, j) | & line[ i..j] )
132151}
133152
134153fn collect_lang_features ( path : & Path ) -> Vec < Feature > {
135154 let mut contents = String :: new ( ) ;
136155 t ! ( t!( File :: open( path) ) . read_to_string( & mut contents) ) ;
137156
138- let mut features = Vec :: new ( ) ;
139- for line in contents. lines ( ) . map ( |l| l. trim ( ) ) {
140- if !STATUSES . iter ( ) . any ( |s| line. starts_with ( & format ! ( "({}" , s) ) ) {
141- continue
142- }
143- let mut parts = line. split ( "," ) ;
144- let status = match & parts. next ( ) . unwrap ( ) . trim ( ) . replace ( "(" , "" ) [ ..] {
145- "active" => "unstable" ,
146- "removed" => "unstable" ,
147- "accepted" => "stable" ,
148- s => panic ! ( "unknown status: {}" , s) ,
149- } ;
150- let name = parts. next ( ) . unwrap ( ) . trim ( ) . to_owned ( ) ;
151- let since = parts. next ( ) . unwrap ( ) . trim ( ) . replace ( "\" " , "" ) ;
152-
153- features. push ( Feature {
154- name : name,
155- since : since,
156- status : status. to_owned ( ) ,
157- } ) ;
158- }
159- return features
157+ contents. lines ( )
158+ . filter_map ( |line| {
159+ let mut parts = line. trim ( ) . split ( "," ) ;
160+ let level = match parts. next ( ) . map ( |l| l. trim ( ) . trim_left_matches ( '(' ) ) {
161+ Some ( "active" ) => Status :: Unstable ,
162+ Some ( "removed" ) => Status :: Unstable ,
163+ Some ( "accepted" ) => Status :: Stable ,
164+ _ => return None ,
165+ } ;
166+ let name = parts. next ( ) . unwrap ( ) . trim ( ) ;
167+ let since = parts. next ( ) . unwrap ( ) . trim ( ) . trim_matches ( '"' ) ;
168+ Some ( Feature {
169+ name : name. to_owned ( ) ,
170+ level : level,
171+ since : since. to_owned ( ) ,
172+ } )
173+ } )
174+ . collect ( )
160175}
0 commit comments