1111
1212use self :: Mapping :: * ;
1313use crate :: punycode;
14- use std:: cmp:: Ordering :: { Equal , Greater , Less } ;
1514use std:: { error:: Error as StdError , fmt} ;
1615use unicode_bidi:: { bidi_class, BidiClass } ;
1716use unicode_normalization:: char:: is_combining_mark;
@@ -48,38 +47,26 @@ enum Mapping {
4847 Disallowed ,
4948 DisallowedStd3Valid ,
5049 DisallowedStd3Mapped ( StringTableSlice ) ,
51- }
52-
53- struct Range {
54- from : char ,
55- to : char ,
50+ DisallowedIdna2008 ,
5651}
5752
5853fn find_char ( codepoint : char ) -> & ' static Mapping {
59- let r = TABLE . binary_search_by ( |ref range| {
60- if codepoint > range. to {
61- Less
62- } else if codepoint < range. from {
63- Greater
64- } else {
65- Equal
66- }
67- } ) ;
68- r. ok ( )
69- . map ( |i| {
70- const SINGLE_MARKER : u16 = 1 << 15 ;
54+ let idx = match TABLE . binary_search_by_key ( & codepoint, |& val| val. 0 ) {
55+ Ok ( idx) => idx,
56+ Err ( idx) => idx - 1 ,
57+ } ;
7158
72- let x = INDEX_TABLE [ i] ;
73- let single = ( x & SINGLE_MARKER ) != 0 ;
74- let offset = !SINGLE_MARKER & x;
59+ const SINGLE_MARKER : u16 = 1 << 15 ;
7560
76- if single {
77- & MAPPING_TABLE [ offset as usize ]
78- } else {
79- & MAPPING_TABLE [ ( offset + ( codepoint as u16 - TABLE [ i] . from as u16 ) ) as usize ]
80- }
81- } )
82- . unwrap ( )
61+ let ( base, x) = TABLE [ idx] ;
62+ let single = ( x & SINGLE_MARKER ) != 0 ;
63+ let offset = !SINGLE_MARKER & x;
64+
65+ if single {
66+ & MAPPING_TABLE [ offset as usize ]
67+ } else {
68+ & MAPPING_TABLE [ ( offset + ( codepoint as u16 - base as u16 ) ) as usize ]
69+ }
8370}
8471
8572struct Mapper < ' a > {
@@ -140,6 +127,12 @@ impl<'a> Iterator for Mapper<'a> {
140127 self . slice = Some ( decode_slice ( slice) . chars ( ) ) ;
141128 continue ;
142129 }
130+ Mapping :: DisallowedIdna2008 => {
131+ if self . config . use_idna_2008_rules {
132+ self . errors . disallowed_in_idna_2008 = true ;
133+ }
134+ codepoint
135+ }
143136 } ) ;
144137 }
145138 }
@@ -310,7 +303,7 @@ fn check_validity(label: &str, config: Config, errors: &mut Errors) {
310303
311304 // V6: Check against Mapping Table
312305 if label. chars ( ) . any ( |c| match * find_char ( c) {
313- Mapping :: Valid => false ,
306+ Mapping :: Valid | Mapping :: DisallowedIdna2008 => false ,
314307 Mapping :: Deviation ( _) => config. transitional_processing ,
315308 Mapping :: DisallowedStd3Valid => config. use_std3_ascii_rules ,
316309 _ => true ,
@@ -510,6 +503,7 @@ pub struct Config {
510503 transitional_processing : bool ,
511504 verify_dns_length : bool ,
512505 check_hyphens : bool ,
506+ use_idna_2008_rules : bool ,
513507}
514508
515509/// The defaults are that of https://url.spec.whatwg.org/#idna
@@ -524,6 +518,7 @@ impl Default for Config {
524518
525519 // Only use for to_ascii, not to_unicode
526520 verify_dns_length : false ,
521+ use_idna_2008_rules : false ,
527522 }
528523 }
529524}
@@ -553,6 +548,12 @@ impl Config {
553548 self
554549 }
555550
551+ #[ inline]
552+ pub fn use_idna_2008_rules ( mut self , value : bool ) -> Self {
553+ self . use_idna_2008_rules = value;
554+ self
555+ }
556+
556557 /// http://www.unicode.org/reports/tr46/#ToASCII
557558 pub fn to_ascii ( self , domain : & str ) -> Result < String , Errors > {
558559 let mut result = String :: new ( ) ;
@@ -599,6 +600,7 @@ pub struct Errors {
599600 disallowed_character : bool ,
600601 too_long_for_dns : bool ,
601602 too_short_for_dns : bool ,
603+ disallowed_in_idna_2008 : bool ,
602604}
603605
604606impl Errors {
@@ -615,6 +617,7 @@ impl Errors {
615617 disallowed_character,
616618 too_long_for_dns,
617619 too_short_for_dns,
620+ disallowed_in_idna_2008,
618621 } = * self ;
619622 punycode
620623 || check_hyphens
@@ -627,6 +630,7 @@ impl Errors {
627630 || disallowed_character
628631 || too_long_for_dns
629632 || too_short_for_dns
633+ || disallowed_in_idna_2008
630634 }
631635}
632636
@@ -644,6 +648,7 @@ impl fmt::Debug for Errors {
644648 disallowed_character,
645649 too_long_for_dns,
646650 too_short_for_dns,
651+ disallowed_in_idna_2008,
647652 } = * self ;
648653
649654 let fields = [
@@ -661,6 +666,7 @@ impl fmt::Debug for Errors {
661666 ( "disallowed_character" , disallowed_character) ,
662667 ( "too_long_for_dns" , too_long_for_dns) ,
663668 ( "too_short_for_dns" , too_short_for_dns) ,
669+ ( "disallowed_in_idna_2008" , disallowed_in_idna_2008) ,
664670 ] ;
665671
666672 let mut empty = true ;
0 commit comments