@@ -220,32 +220,18 @@ impl Crate {
220
220
. unwrap_or ( false )
221
221
}
222
222
223
- pub fn invalid_dependency_name_msg ( dep : & str ) -> String {
224
- format ! (
225
- "\" {dep}\" is an invalid dependency name (dependency \
226
- names must start with a letter or underscore, contain only \
227
- letters, numbers, hyphens, or underscores and have at most \
228
- {MAX_NAME_LENGTH} characters)"
229
- )
230
- }
231
-
232
223
/// Validates the THIS parts of `features = ["THIS", "and/THIS", "dep:THIS", "dep?/THIS"]`.
233
224
/// 1. The name must be non-empty.
234
225
/// 2. The first character must be a Unicode XID start character, `_`, or a digit.
235
226
/// 3. The remaining characters must be Unicode XID characters, `_`, `+`, `-`, or `.`.
236
- pub fn valid_feature_name ( name : & str ) -> AppResult < ( ) > {
227
+ pub fn validate_feature_name ( name : & str ) -> Result < ( ) , InvalidFeature > {
237
228
if name. is_empty ( ) {
238
- return Err ( cargo_err ( "feature cannot be an empty" ) ) ;
229
+ return Err ( InvalidFeature :: Empty ) ;
239
230
}
240
231
let mut chars = name. chars ( ) ;
241
232
if let Some ( ch) = chars. next ( ) {
242
233
if !( unicode_xid:: UnicodeXID :: is_xid_start ( ch) || ch == '_' || ch. is_ascii_digit ( ) ) {
243
- return Err ( cargo_err ( & format ! (
244
- "invalid character `{}` in feature `{}`, \
245
- the first character must be a Unicode XID start character or digit \
246
- (most letters or `_` or `0` to `9`)",
247
- ch, name,
248
- ) ) ) ;
234
+ return Err ( InvalidFeature :: Start ( ch, name. into ( ) ) ) ;
249
235
}
250
236
}
251
237
for ch in chars {
@@ -254,33 +240,30 @@ impl Crate {
254
240
|| ch == '-'
255
241
|| ch == '.' )
256
242
{
257
- return Err ( cargo_err ( & format ! (
258
- "invalid character `{}` in feature `{}`, \
259
- characters must be Unicode XID characters, `+`, `-`, or `.` \
260
- (numbers, `+`, `-`, `_`, `.`, or most letters)",
261
- ch, name,
262
- ) ) ) ;
243
+ return Err ( InvalidFeature :: Char ( ch, name. into ( ) ) ) ;
263
244
}
264
245
}
265
246
266
247
Ok ( ( ) )
267
248
}
268
249
269
250
/// Validates a whole feature string, `features = ["THIS", "and/THIS", "dep:THIS", "dep?/THIS"]`.
270
- pub fn valid_feature ( name : & str ) -> AppResult < ( ) > {
251
+ pub fn validate_feature ( name : & str ) -> Result < ( ) , InvalidFeature > {
271
252
if let Some ( ( dep, dep_feat) ) = name. split_once ( '/' ) {
272
253
let dep = dep. strip_suffix ( '?' ) . unwrap_or ( dep) ;
273
254
if !Crate :: valid_dependency_name ( dep) {
274
- return Err ( cargo_err ( & Crate :: invalid_dependency_name_msg ( dep) ) ) ;
255
+ let err = InvalidDependencyName ( dep. into ( ) ) ;
256
+ return Err ( InvalidFeature :: DependencyName ( err) ) ;
275
257
}
276
- Crate :: valid_feature_name ( dep_feat)
258
+ Crate :: validate_feature_name ( dep_feat)
277
259
} else if let Some ( ( _, dep) ) = name. split_once ( "dep:" ) {
278
260
if !Crate :: valid_dependency_name ( dep) {
279
- return Err ( cargo_err ( & Crate :: invalid_dependency_name_msg ( dep) ) ) ;
261
+ let err = InvalidDependencyName ( dep. into ( ) ) ;
262
+ return Err ( InvalidFeature :: DependencyName ( err) ) ;
280
263
}
281
264
return Ok ( ( ) ) ;
282
265
} else {
283
- Crate :: valid_feature_name ( name)
266
+ Crate :: validate_feature_name ( name)
284
267
}
285
268
}
286
269
@@ -528,6 +511,34 @@ impl CrateVersions for [Crate] {
528
511
}
529
512
}
530
513
514
+ #[ derive( Debug , Eq , PartialEq , thiserror:: Error ) ]
515
+ pub enum InvalidFeature {
516
+ #[ error( "feature cannot be empty" ) ]
517
+ Empty ,
518
+ #[ error(
519
+ "invalid character `{0}` in feature `{1}`, the first character must be \
520
+ a Unicode XID start character or digit (most letters or `_` or `0` to \
521
+ `9`)"
522
+ ) ]
523
+ Start ( char , String ) ,
524
+ #[ error(
525
+ "invalid character `{0}` in feature `{1}`, characters must be Unicode \
526
+ XID characters, `+`, `-`, or `.` (numbers, `+`, `-`, `_`, `.`, or most \
527
+ letters)"
528
+ ) ]
529
+ Char ( char , String ) ,
530
+ #[ error( transparent) ]
531
+ DependencyName ( #[ from] InvalidDependencyName ) ,
532
+ }
533
+
534
+ #[ derive( Debug , Eq , PartialEq , thiserror:: Error ) ]
535
+ #[ error(
536
+ "\" {0}\" is an invalid dependency name (dependency names must start with a \
537
+ letter or underscore, contain only letters, numbers, hyphens, or \
538
+ underscores and have at most {MAX_NAME_LENGTH} characters)"
539
+ ) ]
540
+ pub struct InvalidDependencyName ( pub String ) ;
541
+
531
542
#[ cfg( test) ]
532
543
mod tests {
533
544
use crate :: models:: Crate ;
@@ -559,29 +570,57 @@ mod tests {
559
570
assert ! ( Crate :: valid_dependency_name( "_foo" ) ) ;
560
571
assert ! ( !Crate :: valid_dependency_name( "-foo" ) ) ;
561
572
}
573
+
562
574
#[ test]
563
575
fn valid_feature_names ( ) {
564
- assert ! ( Crate :: valid_feature( "foo" ) . is_ok( ) ) ;
565
- assert ! ( Crate :: valid_feature( "1foo" ) . is_ok( ) ) ;
566
- assert ! ( Crate :: valid_feature( "_foo" ) . is_ok( ) ) ;
567
- assert ! ( Crate :: valid_feature( "_foo-_+.1" ) . is_ok( ) ) ;
568
- assert ! ( Crate :: valid_feature( "_foo-_+.1" ) . is_ok( ) ) ;
569
- assert ! ( Crate :: valid_feature( "" ) . is_err( ) ) ;
570
- assert ! ( Crate :: valid_feature( "/" ) . is_err( ) ) ;
571
- assert ! ( Crate :: valid_feature( "%/%" ) . is_err( ) ) ;
572
- assert ! ( Crate :: valid_feature( "a/a" ) . is_ok( ) ) ;
573
- assert ! ( Crate :: valid_feature( "32-column-tables" ) . is_ok( ) ) ;
574
- assert ! ( Crate :: valid_feature( "c++20" ) . is_ok( ) ) ;
575
- assert ! ( Crate :: valid_feature( "krate/c++20" ) . is_ok( ) ) ;
576
- assert ! ( Crate :: valid_feature( "c++20/wow" ) . is_err( ) ) ;
577
- assert ! ( Crate :: valid_feature( "foo?/bar" ) . is_ok( ) ) ;
578
- assert ! ( Crate :: valid_feature( "dep:foo" ) . is_ok( ) ) ;
579
- assert ! ( Crate :: valid_feature( "dep:foo?/bar" ) . is_err( ) ) ;
580
- assert ! ( Crate :: valid_feature( "foo/?bar" ) . is_err( ) ) ;
581
- assert ! ( Crate :: valid_feature( "foo?bar" ) . is_err( ) ) ;
582
- assert ! ( Crate :: valid_feature( "bar.web" ) . is_ok( ) ) ;
583
- assert ! ( Crate :: valid_feature( "foo/bar.web" ) . is_ok( ) ) ;
584
- assert ! ( Crate :: valid_feature( "dep:0foo" ) . is_err( ) ) ;
585
- assert ! ( Crate :: valid_feature( "0foo?/bar.web" ) . is_err( ) ) ;
576
+ use super :: InvalidDependencyName ;
577
+ use super :: InvalidFeature :: * ;
578
+
579
+ assert_ok ! ( Crate :: validate_feature( "foo" ) ) ;
580
+ assert_ok ! ( Crate :: validate_feature( "1foo" ) ) ;
581
+ assert_ok ! ( Crate :: validate_feature( "_foo" ) ) ;
582
+ assert_ok ! ( Crate :: validate_feature( "_foo-_+.1" ) ) ;
583
+ assert_ok ! ( Crate :: validate_feature( "_foo-_+.1" ) ) ;
584
+ assert_err_eq ! ( Crate :: validate_feature( "" ) , Empty ) ;
585
+ assert_err_eq ! (
586
+ Crate :: validate_feature( "/" ) ,
587
+ InvalidDependencyName ( "" . into( ) ) . into( )
588
+ ) ;
589
+ assert_err_eq ! (
590
+ Crate :: validate_feature( "%/%" ) ,
591
+ InvalidDependencyName ( "%" . into( ) ) . into( )
592
+ ) ;
593
+ assert_ok ! ( Crate :: validate_feature( "a/a" ) ) ;
594
+ assert_ok ! ( Crate :: validate_feature( "32-column-tables" ) ) ;
595
+ assert_ok ! ( Crate :: validate_feature( "c++20" ) ) ;
596
+ assert_ok ! ( Crate :: validate_feature( "krate/c++20" ) ) ;
597
+ assert_err_eq ! (
598
+ Crate :: validate_feature( "c++20/wow" ) ,
599
+ InvalidDependencyName ( "c++20" . into( ) ) . into( )
600
+ ) ;
601
+ assert_ok ! ( Crate :: validate_feature( "foo?/bar" ) ) ;
602
+ assert_ok ! ( Crate :: validate_feature( "dep:foo" ) ) ;
603
+ assert_err_eq ! (
604
+ Crate :: validate_feature( "dep:foo?/bar" ) ,
605
+ InvalidDependencyName ( "dep:foo" . into( ) ) . into( )
606
+ ) ;
607
+ assert_err_eq ! (
608
+ Crate :: validate_feature( "foo/?bar" ) ,
609
+ Start ( '?' , "?bar" . into( ) )
610
+ ) ;
611
+ assert_err_eq ! (
612
+ Crate :: validate_feature( "foo?bar" ) ,
613
+ Char ( '?' , "foo?bar" . into( ) )
614
+ ) ;
615
+ assert_ok ! ( Crate :: validate_feature( "bar.web" ) ) ;
616
+ assert_ok ! ( Crate :: validate_feature( "foo/bar.web" ) ) ;
617
+ assert_err_eq ! (
618
+ Crate :: validate_feature( "dep:0foo" ) ,
619
+ InvalidDependencyName ( "0foo" . into( ) ) . into( )
620
+ ) ;
621
+ assert_err_eq ! (
622
+ Crate :: validate_feature( "0foo?/bar.web" ) ,
623
+ InvalidDependencyName ( "0foo" . into( ) ) . into( )
624
+ ) ;
586
625
}
587
626
}
0 commit comments