@@ -3,329 +3,8 @@ extern crate regex;
3
3
#[ macro_use]
4
4
extern crate lazy_static;
5
5
6
- use regex:: Regex ;
6
+ pub mod version;
7
+ pub mod range;
7
8
8
- lazy_static ! {
9
- static ref REGEX : Regex = {
10
- // a numeric identifier is either zero or multiple numbers without a leading zero
11
- let numeric_identifier = r"0|(:?[1-9][0-9]*)" ;
12
-
13
- let major = numeric_identifier;
14
- let minor = numeric_identifier;
15
- let patch = numeric_identifier;
16
-
17
- let letters_numbers_dash_dot = r"[-.A-Za-z0-9]+" ;
18
-
19
- // This regex does not fully parse prereleases, just extracts the whole prerelease string.
20
- // parse_version() will parse this further.
21
- let pre = letters_numbers_dash_dot;
22
-
23
- // This regex does not fully parse builds, just extracts the whole build string.
24
- // parse_version() will parse this further.
25
- let build = letters_numbers_dash_dot;
26
-
27
- let regex = format!( r"^(?x) # heck yes x mode
28
- (?P<major>{}) # major version
29
- \. # dot
30
- (?P<minor>{}) # minor version
31
- \. # dot
32
- (?P<patch>{}) # patch version
33
- (:?-(?P<pre>{}))? # optional prerelease version
34
- (:?\+(?P<build>{}))? # optional build metadata
35
- $" ,
36
- major,
37
- minor,
38
- patch,
39
- pre,
40
- build) ;
41
- println!( "{:?}" , regex) ;
42
- let regex = Regex :: new( & regex) ;
43
-
44
- // this unwrap is okay because everything above here is const, so this will never fail.
45
- regex. unwrap( )
46
- } ;
47
- }
48
-
49
- pub struct Version {
50
- pub major : u64 ,
51
- pub minor : u64 ,
52
- pub patch : u64 ,
53
- pub pre : Option < Vec < Identifier > > ,
54
- pub build : Option < Vec < Identifier > > ,
55
- }
56
-
57
- #[ derive( Debug , PartialEq ) ]
58
- pub enum Identifier {
59
- /// An identifier that's solely numbers.
60
- Numeric ( u64 ) ,
61
- /// An identifier with letters and numbers.
62
- AlphaNumeric ( String ) ,
63
- }
64
-
65
- pub fn parse_version ( version : & str ) -> Result < Version , String > {
66
- let captures = match REGEX . captures ( version. trim ( ) ) {
67
- Some ( captures) => captures,
68
- None => return Err ( From :: from ( "Version did not parse properly." ) ) ,
69
- } ;
70
-
71
- let pre = captures. name ( "pre" ) . map ( parse_meta) ;
72
-
73
- let build = captures. name ( "build" ) . map ( parse_meta) ;
74
-
75
- Ok ( Version {
76
- major : captures. name ( "major" ) . unwrap ( ) . parse ( ) . unwrap ( ) ,
77
- minor : captures. name ( "minor" ) . unwrap ( ) . parse ( ) . unwrap ( ) ,
78
- patch : captures. name ( "patch" ) . unwrap ( ) . parse ( ) . unwrap ( ) ,
79
- pre : pre,
80
- build : build,
81
- } )
82
- }
83
-
84
- // by the time we get here, we know that it's all valid characters, so this doesn't need to return
85
- // a result or anything
86
- fn parse_meta ( pre : & str ) -> Vec < Identifier > {
87
- // Originally, I wanted to implement this method via calling parse, but parse is tolerant of
88
- // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not
89
- // numeric. So the strategy is to check with a regex first, and then call parse once we've
90
- // determined that it's a number without a leading zero.
91
- let regex = Regex :: new ( r"^[1-9][0-9]*$" ) . unwrap ( ) ;
92
-
93
- pre. split ( "." )
94
- . map ( |part| {
95
- // another wrinkle: we made sure that any number starts with a non-zero. But there's a
96
- // problem: an actual zero is a number, yet gets left out by this heuristic. So let's
97
- // also check for the single, lone zero.
98
- if regex. is_match ( part) || part == "0" {
99
- // we can unwrap here because we know it is only digits due to the regex
100
- Identifier :: Numeric ( part. parse ( ) . unwrap ( ) )
101
- } else {
102
- Identifier :: AlphaNumeric ( part. to_string ( ) )
103
- }
104
- } ) . collect ( )
105
- }
106
-
107
- #[ cfg( test) ]
108
- mod tests {
109
- use super :: * ;
110
-
111
- #[ test]
112
- fn parse_empty ( ) {
113
- let version = "" ;
114
-
115
- let parsed = parse_version ( version) ;
116
-
117
- assert ! ( parsed. is_err( ) , "empty string incorrectly considered a valid parse" ) ;
118
- }
119
-
120
- #[ test]
121
- fn parse_blank ( ) {
122
- let version = " " ;
123
-
124
- let parsed = parse_version ( version) ;
125
-
126
- assert ! ( parsed. is_err( ) , "blank string incorrectly considered a valid parse" ) ;
127
- }
128
-
129
- #[ test]
130
- fn parse_no_minor_patch ( ) {
131
- let version = "1" ;
132
-
133
- let parsed = parse_version ( version) ;
134
-
135
- assert ! ( parsed. is_err( ) , format!( "'{}' incorrectly considered a valid parse" , version) ) ;
136
- }
137
-
138
- #[ test]
139
- fn parse_no_patch ( ) {
140
- let version = "1.2" ;
141
-
142
- let parsed = parse_version ( version) ;
143
-
144
- assert ! ( parsed. is_err( ) , format!( "'{}' incorrectly considered a valid parse" , version) ) ;
145
- }
146
-
147
- #[ test]
148
- fn parse_empty_pre ( ) {
149
- let version = "1.2.3-" ;
150
-
151
- let parsed = parse_version ( version) ;
152
-
153
- assert ! ( parsed. is_err( ) , format!( "'{}' incorrectly considered a valid parse" , version) ) ;
154
- }
155
-
156
- #[ test]
157
- fn parse_letters ( ) {
158
- let version = "a.b.c" ;
159
-
160
- let parsed = parse_version ( version) ;
161
-
162
- assert ! ( parsed. is_err( ) , format!( "'{}' incorrectly considered a valid parse" , version) ) ;
163
- }
164
-
165
- #[ test]
166
- fn parse_version_with_letters ( ) {
167
- let version = "1.2.3 a.b.c" ;
168
-
169
- let parsed = parse_version ( version) ;
170
-
171
- assert ! ( parsed. is_err( ) , format!( "'{}' incorrectly considered a valid parse" , version) ) ;
172
- }
173
-
174
- #[ test]
175
- fn parse_basic_version ( ) {
176
- let version = "1.2.3" ;
177
-
178
- let parsed = parse_version ( version) . unwrap ( ) ;
179
-
180
- assert_eq ! ( 1 , parsed. major) ;
181
- assert_eq ! ( 2 , parsed. minor) ;
182
- assert_eq ! ( 3 , parsed. patch) ;
183
- }
184
-
185
- #[ test]
186
- fn parse_trims_input ( ) {
187
- let version = " 1.2.3 " ;
188
-
189
- let parsed = parse_version ( version) . unwrap ( ) ;
190
-
191
- assert_eq ! ( 1 , parsed. major) ;
192
- assert_eq ! ( 2 , parsed. minor) ;
193
- assert_eq ! ( 3 , parsed. patch) ;
194
- }
195
-
196
- #[ test]
197
- fn parse_version_no_major_leading_zeroes ( ) {
198
- let version = "01.0.0" ;
199
-
200
- let parsed = parse_version ( version) ;
201
-
202
- assert ! ( parsed. is_err( ) , "01 incorrectly considered a valid major version" ) ;
203
- }
204
-
205
- #[ test]
206
- fn parse_version_no_minor_leading_zeroes ( ) {
207
- let version = "0.01.0" ;
208
-
209
- let parsed = parse_version ( version) ;
210
-
211
- assert ! ( parsed. is_err( ) , "01 incorrectly considered a valid minor version" ) ;
212
- }
213
-
214
- #[ test]
215
- fn parse_version_no_patch_leading_zeroes ( ) {
216
- let version = "0.0.01" ;
217
-
218
- let parsed = parse_version ( version) ;
219
-
220
- assert ! ( parsed. is_err( ) , "01 incorrectly considered a valid patch version" ) ;
221
- }
222
-
223
- #[ test]
224
- fn parse_version_basic_prerelease ( ) {
225
- let version = "1.2.3-pre" ;
226
-
227
- let parsed = parse_version ( version) . unwrap ( ) ;
228
-
229
- let expected_pre = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "pre" ) ) ] ) ;
230
- assert_eq ! ( expected_pre, parsed. pre) ;
231
- }
232
-
233
- #[ test]
234
- fn parse_version_prerelease_alphanumeric ( ) {
235
- let version = "1.2.3-alpha1" ;
236
-
237
- let parsed = parse_version ( version) . unwrap ( ) ;
238
-
239
- let expected_pre = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "alpha1" ) ) ] ) ;
240
- assert_eq ! ( expected_pre, parsed. pre) ;
241
- }
242
-
243
- #[ test]
244
- fn parse_version_prerelease_zero ( ) {
245
- let version = "1.2.3-pre.0" ;
246
-
247
- let parsed = parse_version ( version) . unwrap ( ) ;
248
-
249
- let expected_pre = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "pre" ) ) ,
250
- Identifier :: Numeric ( 0 ) ] ) ;
251
- assert_eq ! ( expected_pre, parsed. pre) ;
252
- }
253
-
254
- #[ test]
255
- fn parse_version_basic_build ( ) {
256
- let version = "1.2.3+build" ;
257
-
258
- let parsed = parse_version ( version) . unwrap ( ) ;
259
-
260
- let expected_build = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "build" ) ) ] ) ;
261
- assert_eq ! ( expected_build, parsed. build) ;
262
- }
263
-
264
- #[ test]
265
- fn parse_version_build_alphanumeric ( ) {
266
- let version = "1.2.3+build5" ;
267
-
268
- let parsed = parse_version ( version) . unwrap ( ) ;
269
-
270
- let expected_build = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "build5" ) ) ] ) ;
271
- assert_eq ! ( expected_build, parsed. build) ;
272
- }
273
-
274
- #[ test]
275
- fn parse_version_pre_and_build ( ) {
276
- let version = "1.2.3-alpha1+build5" ;
277
-
278
- let parsed = parse_version ( version) . unwrap ( ) ;
279
-
280
- let expected_pre = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "alpha1" ) ) ] ) ;
281
- assert_eq ! ( expected_pre, parsed. pre) ;
282
-
283
- let expected_build = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "build5" ) ) ] ) ;
284
- assert_eq ! ( expected_build, parsed. build) ;
285
- }
286
-
287
- #[ test]
288
- fn parse_version_complex_metadata_01 ( ) {
289
- let version = "1.2.3-1.alpha1.9+build5.7.3aedf " ;
290
-
291
- let parsed = parse_version ( version) . unwrap ( ) ;
292
-
293
- let expected_pre = Some ( vec ! [ Identifier :: Numeric ( 1 ) ,
294
- Identifier :: AlphaNumeric ( String :: from( "alpha1" ) ) ,
295
- Identifier :: Numeric ( 9 ) ] ) ;
296
- assert_eq ! ( expected_pre, parsed. pre) ;
297
-
298
- let expected_build = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "build5" ) ) ,
299
- Identifier :: Numeric ( 7 ) ,
300
- Identifier :: AlphaNumeric ( String :: from( "3aedf" ) ) ] ) ;
301
- assert_eq ! ( expected_build, parsed. build) ;
302
- }
303
-
304
- #[ test]
305
- fn parse_version_complex_metadata_02 ( ) {
306
- let version = "0.4.0-beta.1+0851523" ;
307
-
308
- let parsed = parse_version ( version) . unwrap ( ) ;
309
-
310
- let expected_pre = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "beta" ) ) ,
311
- Identifier :: Numeric ( 1 ) ] ) ;
312
- assert_eq ! ( expected_pre, parsed. pre) ;
313
-
314
- let expected_build = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "0851523" ) ) ] ) ;
315
- assert_eq ! ( expected_build, parsed. build) ;
316
- }
317
-
318
- #[ test]
319
- fn parse_regression_01 ( ) {
320
- let version = "0.0.0-WIP" ;
321
-
322
- let parsed = parse_version ( version) . unwrap ( ) ;
323
-
324
- assert_eq ! ( 0 , parsed. major) ;
325
- assert_eq ! ( 0 , parsed. minor) ;
326
- assert_eq ! ( 0 , parsed. patch) ;
327
-
328
- let expected_pre = Some ( vec ! [ Identifier :: AlphaNumeric ( String :: from( "WIP" ) ) ] ) ;
329
- assert_eq ! ( expected_pre, parsed. pre) ;
330
- }
331
- }
9
+ // for private stuff the two share
10
+ mod common;
0 commit comments