18
18
//! * Library features have at most one `since` value
19
19
20
20
use std::collections::HashMap;
21
+ use std::fmt;
21
22
use std::fs::File;
22
23
use std::io::prelude::*;
23
24
use std::path::Path;
24
25
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
+
28
42
29
43
struct Feature {
30
44
name: String,
45
+ level: Status,
31
46
since: String,
32
- status: String,
33
47
}
34
48
35
49
struct LibFeature {
36
- level: String ,
50
+ level: Status ,
37
51
since: String,
38
52
}
39
53
40
54
pub fn check(path: &Path, bad: &mut bool) {
41
55
let features = collect_lang_features(&path.join("libsyntax/feature_gate.rs"));
56
+ assert!(!features.is_empty());
42
57
let mut lib_features = HashMap::<String, LibFeature>::new();
43
58
44
59
let mut contents = String::new();
@@ -48,7 +63,7 @@ pub fn check(path: &Path, bad: &mut bool) {
48
63
let filename = file.file_name().unwrap().to_string_lossy();
49
64
if !filename.ends_with(".rs") || filename == "features.rs" ||
50
65
filename == "diagnostic_list.rs" {
51
- return
66
+ return;
52
67
}
53
68
54
69
contents.truncate(0);
@@ -60,24 +75,24 @@ pub fn check(path: &Path, bad: &mut bool) {
60
75
*bad = true;
61
76
};
62
77
let level = if line.contains("[unstable(") {
63
- "unstable"
78
+ Status::Unstable
64
79
} else if line.contains("[stable(") {
65
- "stable"
80
+ Status::Stable
66
81
} else {
67
- continue
82
+ continue;
68
83
};
69
84
let feature_name = match find_attr_val(line, "feature") {
70
85
Some(name) => name,
71
86
None => {
72
87
err("malformed stability attribute");
73
- continue
88
+ continue;
74
89
}
75
90
};
76
91
let since = match find_attr_val(line, "since") {
77
92
Some(name) => name,
78
- None if level == "stable" => {
93
+ None if level == Status::Stable => {
79
94
err("malformed stability attribute");
80
- continue
95
+ continue;
81
96
}
82
97
None => "None",
83
98
};
@@ -92,27 +107,34 @@ pub fn check(path: &Path, bad: &mut bool) {
92
107
if s.since != since {
93
108
err("different `since` than before");
94
109
}
95
- continue
110
+ continue;
96
111
}
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
+ });
101
117
}
102
118
});
103
119
104
120
if *bad {
105
- return
121
+ return;
106
122
}
107
123
108
124
let mut lines = Vec::new();
109
125
for feature in features {
110
126
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));
112
131
}
113
132
for (name, feature) in lib_features {
114
133
lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
115
- name, "lib", feature.level, feature.since));
134
+ name,
135
+ "lib",
136
+ feature.level,
137
+ feature.since));
116
138
}
117
139
118
140
lines.sort();
@@ -122,39 +144,32 @@ pub fn check(path: &Path, bad: &mut bool) {
122
144
}
123
145
124
146
fn 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])
132
151
}
133
152
134
153
fn collect_lang_features(path: &Path) -> Vec<Feature> {
135
154
let mut contents = String::new();
136
155
t!(t!(File::open(path)).read_to_string(&mut contents));
137
156
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()
160
175
}
0 commit comments