@@ -279,11 +279,11 @@ fn passes_bidi(label: &str, is_bidi_domain: bool) -> bool {
279
279
/// V1 (NFC) and V8 (Bidi) are checked inside `processing()` to prevent doing duplicate work.
280
280
///
281
281
/// http://www.unicode.org/reports/tr46/#Validity_Criteria
282
- fn is_valid ( label : & str , config : Config ) -> bool {
282
+ fn check_validity ( label : & str , config : Config , errors : & mut Errors ) {
283
283
let first_char = label. chars ( ) . next ( ) ;
284
284
if first_char == None {
285
285
// Empty string, pass
286
- return true ;
286
+ return ;
287
287
}
288
288
289
289
// V2: No U+002D HYPHEN-MINUS in both third and fourth positions.
@@ -294,7 +294,8 @@ fn is_valid(label: &str, config: Config) -> bool {
294
294
295
295
// V3: neither begin nor end with a U+002D HYPHEN-MINUS
296
296
if config. check_hyphens && ( label. starts_with ( '-' ) || label. ends_with ( '-' ) ) {
297
- return false ;
297
+ errors. check_hyphens = true ;
298
+ return ;
298
299
}
299
300
300
301
// V4: not contain a U+002E FULL STOP
@@ -303,7 +304,8 @@ fn is_valid(label: &str, config: Config) -> bool {
303
304
304
305
// V5: not begin with a GC=Mark
305
306
if is_combining_mark ( first_char. unwrap ( ) ) {
306
- return false ;
307
+ errors. start_combining_mark = true ;
308
+ return ;
307
309
}
308
310
309
311
// V6: Check against Mapping Table
@@ -313,15 +315,15 @@ fn is_valid(label: &str, config: Config) -> bool {
313
315
Mapping :: DisallowedStd3Valid => config. use_std3_ascii_rules ,
314
316
_ => true ,
315
317
} ) {
316
- return false ;
318
+ errors. invalid_mapping = true ;
319
+ return ;
317
320
}
318
321
319
322
// V7: ContextJ rules
320
323
//
321
324
// TODO: Implement rules and add *CheckJoiners* flag.
322
325
323
326
// V8: Bidi rules are checked inside `processing()`
324
- true
325
327
}
326
328
327
329
/// http://www.unicode.org/reports/tr46/#Processing
@@ -384,7 +386,7 @@ fn processing(
384
386
385
387
let mut decoder = punycode:: Decoder :: default ( ) ;
386
388
let non_transitional = config. transitional_processing ( false ) ;
387
- let ( mut first, mut valid , mut has_bidi_labels) = ( true , true , false ) ;
389
+ let ( mut first, mut has_bidi_labels) = ( true , false ) ;
388
390
for label in normalized. split ( '.' ) {
389
391
if !first {
390
392
output. push ( '.' ) ;
@@ -401,10 +403,12 @@ fn processing(
401
403
has_bidi_labels |= is_bidi_domain ( decoded_label) ;
402
404
}
403
405
404
- if valid
405
- && ( !is_nfc ( & decoded_label) || !is_valid ( decoded_label, non_transitional) )
406
- {
407
- valid = false ;
406
+ if !errors. is_err ( ) {
407
+ if !is_nfc ( & decoded_label) {
408
+ errors. nfc = true ;
409
+ } else {
410
+ check_validity ( decoded_label, non_transitional, & mut errors) ;
411
+ }
408
412
}
409
413
}
410
414
Err ( ( ) ) => {
@@ -418,7 +422,7 @@ fn processing(
418
422
}
419
423
420
424
// `normalized` is already `NFC` so we can skip that check
421
- valid &= is_valid ( label, config) ;
425
+ check_validity ( label, config, & mut errors ) ;
422
426
output. push_str ( label)
423
427
}
424
428
}
@@ -428,15 +432,11 @@ fn processing(
428
432
//
429
433
// TODO: Add *CheckBidi* flag
430
434
if !passes_bidi ( label, has_bidi_labels) {
431
- valid = false ;
435
+ errors . check_bidi = true ;
432
436
break ;
433
437
}
434
438
}
435
439
436
- if !valid {
437
- errors. validity_criteria = true ;
438
- }
439
-
440
440
errors
441
441
}
442
442
@@ -589,8 +589,11 @@ fn is_bidi_domain(s: &str) -> bool {
589
589
#[ derive( Default ) ]
590
590
pub struct Errors {
591
591
punycode : bool ,
592
- // https://unicode.org/reports/tr46/#Validity_Criteria
593
- validity_criteria : bool ,
592
+ check_hyphens : bool ,
593
+ check_bidi : bool ,
594
+ start_combining_mark : bool ,
595
+ invalid_mapping : bool ,
596
+ nfc : bool ,
594
597
disallowed_by_std3_ascii_rules : bool ,
595
598
disallowed_mapped_in_std3 : bool ,
596
599
disallowed_character : bool ,
@@ -602,15 +605,23 @@ impl Errors {
602
605
fn is_err ( & self ) -> bool {
603
606
let Errors {
604
607
punycode,
605
- validity_criteria,
608
+ check_hyphens,
609
+ check_bidi,
610
+ start_combining_mark,
611
+ invalid_mapping,
612
+ nfc,
606
613
disallowed_by_std3_ascii_rules,
607
614
disallowed_mapped_in_std3,
608
615
disallowed_character,
609
616
too_long_for_dns,
610
617
too_short_for_dns,
611
618
} = * self ;
612
619
punycode
613
- || validity_criteria
620
+ || check_hyphens
621
+ || check_bidi
622
+ || start_combining_mark
623
+ || invalid_mapping
624
+ || nfc
614
625
|| disallowed_by_std3_ascii_rules
615
626
|| disallowed_mapped_in_std3
616
627
|| disallowed_character
@@ -623,7 +634,11 @@ impl fmt::Debug for Errors {
623
634
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
624
635
let Errors {
625
636
punycode,
626
- validity_criteria,
637
+ check_hyphens,
638
+ check_bidi,
639
+ start_combining_mark,
640
+ invalid_mapping,
641
+ nfc,
627
642
disallowed_by_std3_ascii_rules,
628
643
disallowed_mapped_in_std3,
629
644
disallowed_character,
@@ -633,8 +648,15 @@ impl fmt::Debug for Errors {
633
648
634
649
let fields = [
635
650
( "punycode" , punycode) ,
636
- ( "validity_criteria" , validity_criteria) ,
637
- ( "disallowed_by_std3_ascii_rules" , disallowed_by_std3_ascii_rules) ,
651
+ ( "check_hyphens" , check_hyphens) ,
652
+ ( "check_bidi" , check_bidi) ,
653
+ ( "start_combining_mark" , start_combining_mark) ,
654
+ ( "invalid_mapping" , invalid_mapping) ,
655
+ ( "nfc" , nfc) ,
656
+ (
657
+ "disallowed_by_std3_ascii_rules" ,
658
+ disallowed_by_std3_ascii_rules,
659
+ ) ,
638
660
( "disallowed_mapped_in_std3" , disallowed_mapped_in_std3) ,
639
661
( "disallowed_character" , disallowed_character) ,
640
662
( "too_long_for_dns" , too_long_for_dns) ,
0 commit comments