@@ -160,12 +160,12 @@ pub struct Input<'i> {
160
160
161
161
impl < ' i > Input < ' i > {
162
162
pub fn new ( input : & ' i str ) -> Self {
163
- Input :: with_log ( input, ViolationFn :: NoOp )
163
+ Input :: with_log ( input, None )
164
164
}
165
165
166
- pub fn with_log ( original_input : & ' i str , vfn : ViolationFn ) -> Self {
166
+ pub fn with_log ( original_input : & ' i str , vfn : Option < ViolationFn > ) -> Self {
167
167
let input = original_input. trim_matches ( c0_control_or_space) ;
168
- if vfn . is_set ( ) {
168
+ if let Some ( vfn ) = vfn {
169
169
if input. len ( ) < original_input. len ( ) {
170
170
vfn. call ( SyntaxViolation :: C0SpaceIgnored )
171
171
}
@@ -268,7 +268,6 @@ impl<'i> Iterator for Input<'i> {
268
268
pub enum ViolationFn < ' a > {
269
269
NewFn ( & ' a ( Fn ( SyntaxViolation ) + ' a ) ) ,
270
270
OldFn ( & ' a ( Fn ( & ' static str ) + ' a ) ) ,
271
- NoOp
272
271
}
273
272
274
273
impl < ' a > ViolationFn < ' a > {
@@ -277,27 +276,6 @@ impl<'a> ViolationFn<'a> {
277
276
match self {
278
277
ViolationFn :: NewFn ( f) => f ( v) ,
279
278
ViolationFn :: OldFn ( f) => f ( v. description ( ) ) ,
280
- ViolationFn :: NoOp => { }
281
- }
282
- }
283
-
284
- /// Call with a violation, if provided test returns true. Avoids
285
- /// the test entirely if `NoOp`.
286
- pub fn call_if < F > ( self , v : SyntaxViolation , test : F )
287
- where F : Fn ( ) -> bool
288
- {
289
- match self {
290
- ViolationFn :: NewFn ( f) => if test ( ) { f ( v) } ,
291
- ViolationFn :: OldFn ( f) => if test ( ) { f ( v. description ( ) ) } ,
292
- ViolationFn :: NoOp => { } // avoid test
293
- }
294
- }
295
-
296
- /// True if not `NoOp`
297
- pub fn is_set ( self ) -> bool {
298
- match self {
299
- ViolationFn :: NoOp => false ,
300
- _ => true
301
279
}
302
280
}
303
281
}
@@ -307,7 +285,6 @@ impl<'a> fmt::Debug for ViolationFn<'a> {
307
285
match * self {
308
286
ViolationFn :: NewFn ( _) => write ! ( f, "NewFn(Fn(SyntaxViolation))" ) ,
309
287
ViolationFn :: OldFn ( _) => write ! ( f, "OldFn(Fn(&'static str))" ) ,
310
- ViolationFn :: NoOp => write ! ( f, "NoOp" )
311
288
}
312
289
}
313
290
}
@@ -316,7 +293,7 @@ pub struct Parser<'a> {
316
293
pub serialization : String ,
317
294
pub base_url : Option < & ' a Url > ,
318
295
pub query_encoding_override : EncodingOverride ,
319
- pub violation_fn : ViolationFn < ' a > ,
296
+ pub violation_fn : Option < ViolationFn < ' a > > ,
320
297
pub context : Context ,
321
298
}
322
299
@@ -333,11 +310,26 @@ impl<'a> Parser<'a> {
333
310
serialization : serialization,
334
311
base_url : None ,
335
312
query_encoding_override : EncodingOverride :: utf8 ( ) ,
336
- violation_fn : ViolationFn :: NoOp ,
313
+ violation_fn : None ,
337
314
context : Context :: Setter ,
338
315
}
339
316
}
340
317
318
+ fn syntax_violation ( & self , v : SyntaxViolation ) {
319
+ if let Some ( vfn) = self . violation_fn {
320
+ vfn. call ( v)
321
+ }
322
+ }
323
+
324
+ fn syntax_violation_if < F : Fn ( ) -> bool > ( & self , v : SyntaxViolation , test : F ) {
325
+ // Skip test if not logging.
326
+ if let Some ( vfn) = self . violation_fn {
327
+ if test ( ) {
328
+ vfn. call ( v)
329
+ }
330
+ }
331
+ }
332
+
341
333
/// https://url.spec.whatwg.org/#concept-basic-url-parser
342
334
pub fn parse_url ( mut self , input : & str ) -> ParseResult < Url > {
343
335
let input = Input :: with_log ( input, self . violation_fn ) ;
@@ -397,7 +389,7 @@ impl<'a> Parser<'a> {
397
389
self . serialization . push ( ':' ) ;
398
390
match scheme_type {
399
391
SchemeType :: File => {
400
- self . violation_fn . call_if ( ExpectedFileDoubleSlash , || !input. starts_with ( "//" ) ) ;
392
+ self . syntax_violation_if ( ExpectedFileDoubleSlash , || !input. starts_with ( "//" ) ) ;
401
393
let base_file_url = self . base_url . and_then ( |base| {
402
394
if base. scheme ( ) == "file" { Some ( base) } else { None }
403
395
} ) ;
@@ -417,7 +409,7 @@ impl<'a> Parser<'a> {
417
409
}
418
410
}
419
411
// special authority slashes state
420
- self . violation_fn . call_if ( ExpectedDoubleSlash , || {
412
+ self . syntax_violation_if ( ExpectedDoubleSlash , || {
421
413
input. clone ( ) . take_while ( |& c| matches ! ( c, '/' | '\\' ) )
422
414
. collect :: < String > ( ) != "//"
423
415
} ) ;
@@ -551,10 +543,10 @@ impl<'a> Parser<'a> {
551
543
}
552
544
}
553
545
Some ( '/' ) | Some ( '\\' ) => {
554
- self . violation_fn . call_if ( Backslash , || first_char == Some ( '\\' ) ) ;
546
+ self . syntax_violation_if ( Backslash , || first_char == Some ( '\\' ) ) ;
555
547
// file slash state
556
548
let ( next_char, input_after_next_char) = input_after_first_char. split_first ( ) ;
557
- self . violation_fn . call_if ( Backslash , || next_char == Some ( '\\' ) ) ;
549
+ self . syntax_violation_if ( Backslash , || next_char == Some ( '\\' ) ) ;
558
550
if matches ! ( next_char, Some ( '/' ) | Some ( '\\' ) ) {
559
551
// file host state
560
552
self . serialization . push_str ( "file://" ) ;
@@ -706,7 +698,7 @@ impl<'a> Parser<'a> {
706
698
Some ( '/' ) | Some ( '\\' ) => {
707
699
let ( slashes_count, remaining) = input. count_matching ( |c| matches ! ( c, '/' | '\\' ) ) ;
708
700
if slashes_count >= 2 {
709
- self . violation_fn . call_if ( SyntaxViolation :: ExpectedDoubleSlash , || {
701
+ self . syntax_violation_if ( SyntaxViolation :: ExpectedDoubleSlash , || {
710
702
input. clone ( ) . take_while ( |& c| matches ! ( c, '/' | '\\' ) )
711
703
. collect :: < String > ( ) != "//"
712
704
} ) ;
@@ -770,9 +762,9 @@ impl<'a> Parser<'a> {
770
762
match c {
771
763
'@' => {
772
764
if last_at. is_some ( ) {
773
- self . violation_fn . call ( SyntaxViolation :: UnencodedAtSign )
765
+ self . syntax_violation ( SyntaxViolation :: UnencodedAtSign )
774
766
} else {
775
- self . violation_fn . call ( SyntaxViolation :: EmbeddedCredentials )
767
+ self . syntax_violation ( SyntaxViolation :: EmbeddedCredentials )
776
768
}
777
769
last_at = Some ( ( char_count, remaining. clone ( ) ) )
778
770
} ,
@@ -970,7 +962,7 @@ impl<'a> Parser<'a> {
970
962
match input. split_first ( ) {
971
963
( Some ( '/' ) , remaining) => input = remaining,
972
964
( Some ( '\\' ) , remaining) => if scheme_type. is_special ( ) {
973
- self . violation_fn . call ( SyntaxViolation :: Backslash ) ;
965
+ self . syntax_violation ( SyntaxViolation :: Backslash ) ;
974
966
input = remaining
975
967
} ,
976
968
_ => { }
@@ -998,7 +990,7 @@ impl<'a> Parser<'a> {
998
990
} ,
999
991
'\\' if self . context != Context :: PathSegmentSetter &&
1000
992
scheme_type. is_special ( ) => {
1001
- self . violation_fn . call ( SyntaxViolation :: Backslash ) ;
993
+ self . syntax_violation ( SyntaxViolation :: Backslash ) ;
1002
994
ends_with_slash = true ;
1003
995
break
1004
996
} ,
@@ -1039,7 +1031,7 @@ impl<'a> Parser<'a> {
1039
1031
self . serialization . push ( ':' ) ;
1040
1032
}
1041
1033
if * has_host {
1042
- self . violation_fn . call ( SyntaxViolation :: FileWithHostAndWindowsDrive ) ;
1034
+ self . syntax_violation ( SyntaxViolation :: FileWithHostAndWindowsDrive ) ;
1043
1035
* has_host = false ; // FIXME account for this in callers
1044
1036
}
1045
1037
}
@@ -1181,7 +1173,7 @@ impl<'a> Parser<'a> {
1181
1173
pub fn parse_fragment ( & mut self , mut input : Input ) {
1182
1174
while let Some ( ( c, utf8_c) ) = input. next_utf8 ( ) {
1183
1175
if c == '\0' {
1184
- self . violation_fn . call ( SyntaxViolation :: NullInFragment )
1176
+ self . syntax_violation ( SyntaxViolation :: NullInFragment )
1185
1177
} else {
1186
1178
self . check_url_code_point ( c, & input) ;
1187
1179
self . serialization . extend ( utf8_percent_encode ( utf8_c,
@@ -1191,8 +1183,7 @@ impl<'a> Parser<'a> {
1191
1183
}
1192
1184
1193
1185
fn check_url_code_point ( & self , c : char , input : & Input ) {
1194
- let vfn = self . violation_fn ;
1195
- if vfn. is_set ( ) {
1186
+ if let Some ( vfn) = self . violation_fn {
1196
1187
if c == '%' {
1197
1188
let mut input = input. clone ( ) ;
1198
1189
if !matches ! ( ( input. next( ) , input. next( ) ) , ( Some ( a) , Some ( b) )
0 commit comments