@@ -165,17 +165,17 @@ pub struct Input<'i> {
165
165
166
166
impl < ' i > Input < ' i > {
167
167
pub fn new ( input : & ' i str ) -> Self {
168
- Input :: with_log ( input, ViolationFn :: NoOp )
168
+ Input :: with_log ( input, None )
169
169
}
170
170
171
- pub fn with_log ( original_input : & ' i str , vfn : ViolationFn ) -> Self {
171
+ pub fn with_log ( original_input : & ' i str , vfn : Option < & dyn Fn ( SyntaxViolation ) > ) -> Self {
172
172
let input = original_input. trim_matches ( c0_control_or_space) ;
173
- if vfn . is_set ( ) {
173
+ if let Some ( vfn ) = vfn {
174
174
if input. len ( ) < original_input. len ( ) {
175
- vfn. call ( SyntaxViolation :: C0SpaceIgnored )
175
+ vfn ( SyntaxViolation :: C0SpaceIgnored )
176
176
}
177
177
if input. chars ( ) . any ( |c| matches ! ( c, '\t' | '\n' | '\r' ) ) {
178
- vfn. call ( SyntaxViolation :: TabOrNewlineIgnored )
178
+ vfn ( SyntaxViolation :: TabOrNewlineIgnored )
179
179
}
180
180
}
181
181
Input { chars : input. chars ( ) }
@@ -268,56 +268,11 @@ impl<'i> Iterator for Input<'i> {
268
268
}
269
269
}
270
270
271
- /// Wrapper for syntax violation callback functions.
272
- #[ derive( Copy , Clone ) ]
273
- pub enum ViolationFn < ' a > {
274
- NewFn ( & ' a ( dyn Fn ( SyntaxViolation ) + ' a ) ) ,
275
- NoOp
276
- }
277
-
278
- impl < ' a > ViolationFn < ' a > {
279
- /// Call with a violation.
280
- pub fn call ( self , v : SyntaxViolation ) {
281
- match self {
282
- ViolationFn :: NewFn ( f) => f ( v) ,
283
- ViolationFn :: NoOp => { }
284
- }
285
- }
286
-
287
- /// Call with a violation, if provided test returns true. Avoids
288
- /// the test entirely if `NoOp`.
289
- pub fn call_if < F > ( self , v : SyntaxViolation , test : F )
290
- where F : Fn ( ) -> bool
291
- {
292
- match self {
293
- ViolationFn :: NewFn ( f) => if test ( ) { f ( v) } ,
294
- ViolationFn :: NoOp => { } // avoid test
295
- }
296
- }
297
-
298
- /// True if not `NoOp`
299
- pub fn is_set ( self ) -> bool {
300
- match self {
301
- ViolationFn :: NoOp => false ,
302
- _ => true
303
- }
304
- }
305
- }
306
-
307
- impl < ' a > fmt:: Debug for ViolationFn < ' a > {
308
- fn fmt ( & self , f : & mut Formatter ) -> fmt:: Result {
309
- match * self {
310
- ViolationFn :: NewFn ( _) => write ! ( f, "NewFn(Fn(SyntaxViolation))" ) ,
311
- ViolationFn :: NoOp => write ! ( f, "NoOp" )
312
- }
313
- }
314
- }
315
-
316
271
pub struct Parser < ' a > {
317
272
pub serialization : String ,
318
273
pub base_url : Option < & ' a Url > ,
319
274
pub query_encoding_override : EncodingOverride ,
320
- pub violation_fn : ViolationFn < ' a > ,
275
+ pub violation_fn : Option < & ' a dyn Fn ( SyntaxViolation ) > ,
321
276
pub context : Context ,
322
277
}
323
278
@@ -329,12 +284,26 @@ pub enum Context {
329
284
}
330
285
331
286
impl < ' a > Parser < ' a > {
287
+ fn log_violation ( & self , v : SyntaxViolation ) {
288
+ if let Some ( f) = self . violation_fn {
289
+ f ( v)
290
+ }
291
+ }
292
+
293
+ fn log_violation_if ( & self , v : SyntaxViolation , test : impl FnOnce ( ) -> bool ) {
294
+ if let Some ( f) = self . violation_fn {
295
+ if test ( ) {
296
+ f ( v)
297
+ }
298
+ }
299
+ }
300
+
332
301
pub fn for_setter ( serialization : String ) -> Parser < ' a > {
333
302
Parser {
334
303
serialization : serialization,
335
304
base_url : None ,
336
305
query_encoding_override : EncodingOverride :: utf8 ( ) ,
337
- violation_fn : ViolationFn :: NoOp ,
306
+ violation_fn : None ,
338
307
context : Context :: Setter ,
339
308
}
340
309
}
@@ -398,7 +367,7 @@ impl<'a> Parser<'a> {
398
367
self . serialization . push ( ':' ) ;
399
368
match scheme_type {
400
369
SchemeType :: File => {
401
- self . violation_fn . call_if ( ExpectedFileDoubleSlash , || !input. starts_with ( "//" ) ) ;
370
+ self . log_violation_if ( ExpectedFileDoubleSlash , || !input. starts_with ( "//" ) ) ;
402
371
let base_file_url = self . base_url . and_then ( |base| {
403
372
if base. scheme ( ) == "file" { Some ( base) } else { None }
404
373
} ) ;
@@ -418,7 +387,7 @@ impl<'a> Parser<'a> {
418
387
}
419
388
}
420
389
// special authority slashes state
421
- self . violation_fn . call_if ( ExpectedDoubleSlash , || {
390
+ self . log_violation_if ( ExpectedDoubleSlash , || {
422
391
input. clone ( ) . take_while ( |& c| matches ! ( c, '/' | '\\' ) )
423
392
. collect :: < String > ( ) != "//"
424
393
} ) ;
@@ -552,10 +521,10 @@ impl<'a> Parser<'a> {
552
521
}
553
522
}
554
523
Some ( '/' ) | Some ( '\\' ) => {
555
- self . violation_fn . call_if ( Backslash , || first_char == Some ( '\\' ) ) ;
524
+ self . log_violation_if ( Backslash , || first_char == Some ( '\\' ) ) ;
556
525
// file slash state
557
526
let ( next_char, input_after_next_char) = input_after_first_char. split_first ( ) ;
558
- self . violation_fn . call_if ( Backslash , || next_char == Some ( '\\' ) ) ;
527
+ self . log_violation_if ( Backslash , || next_char == Some ( '\\' ) ) ;
559
528
if matches ! ( next_char, Some ( '/' ) | Some ( '\\' ) ) {
560
529
// file host state
561
530
self . serialization . push_str ( "file://" ) ;
@@ -707,7 +676,7 @@ impl<'a> Parser<'a> {
707
676
Some ( '/' ) | Some ( '\\' ) => {
708
677
let ( slashes_count, remaining) = input. count_matching ( |c| matches ! ( c, '/' | '\\' ) ) ;
709
678
if slashes_count >= 2 {
710
- self . violation_fn . call_if ( SyntaxViolation :: ExpectedDoubleSlash , || {
679
+ self . log_violation_if ( SyntaxViolation :: ExpectedDoubleSlash , || {
711
680
input. clone ( ) . take_while ( |& c| matches ! ( c, '/' | '\\' ) )
712
681
. collect :: < String > ( ) != "//"
713
682
} ) ;
@@ -771,9 +740,9 @@ impl<'a> Parser<'a> {
771
740
match c {
772
741
'@' => {
773
742
if last_at. is_some ( ) {
774
- self . violation_fn . call ( SyntaxViolation :: UnencodedAtSign )
743
+ self . log_violation ( SyntaxViolation :: UnencodedAtSign )
775
744
} else {
776
- self . violation_fn . call ( SyntaxViolation :: EmbeddedCredentials )
745
+ self . log_violation ( SyntaxViolation :: EmbeddedCredentials )
777
746
}
778
747
last_at = Some ( ( char_count, remaining. clone ( ) ) )
779
748
} ,
@@ -971,7 +940,7 @@ impl<'a> Parser<'a> {
971
940
match input. split_first ( ) {
972
941
( Some ( '/' ) , remaining) => input = remaining,
973
942
( Some ( '\\' ) , remaining) => if scheme_type. is_special ( ) {
974
- self . violation_fn . call ( SyntaxViolation :: Backslash ) ;
943
+ self . log_violation ( SyntaxViolation :: Backslash ) ;
975
944
input = remaining
976
945
} ,
977
946
_ => { }
@@ -999,7 +968,7 @@ impl<'a> Parser<'a> {
999
968
} ,
1000
969
'\\' if self . context != Context :: PathSegmentSetter &&
1001
970
scheme_type. is_special ( ) => {
1002
- self . violation_fn . call ( SyntaxViolation :: Backslash ) ;
971
+ self . log_violation ( SyntaxViolation :: Backslash ) ;
1003
972
ends_with_slash = true ;
1004
973
break
1005
974
} ,
@@ -1045,7 +1014,7 @@ impl<'a> Parser<'a> {
1045
1014
self . serialization . push ( ':' ) ;
1046
1015
}
1047
1016
if * has_host {
1048
- self . violation_fn . call ( SyntaxViolation :: FileWithHostAndWindowsDrive ) ;
1017
+ self . log_violation ( SyntaxViolation :: FileWithHostAndWindowsDrive ) ;
1049
1018
* has_host = false ; // FIXME account for this in callers
1050
1019
}
1051
1020
}
@@ -1187,7 +1156,7 @@ impl<'a> Parser<'a> {
1187
1156
pub fn parse_fragment ( & mut self , mut input : Input ) {
1188
1157
while let Some ( ( c, utf8_c) ) = input. next_utf8 ( ) {
1189
1158
if c == '\0' {
1190
- self . violation_fn . call ( SyntaxViolation :: NullInFragment )
1159
+ self . log_violation ( SyntaxViolation :: NullInFragment )
1191
1160
} else {
1192
1161
self . check_url_code_point ( c, & input) ;
1193
1162
self . serialization . extend ( utf8_percent_encode ( utf8_c,
@@ -1197,16 +1166,15 @@ impl<'a> Parser<'a> {
1197
1166
}
1198
1167
1199
1168
fn check_url_code_point ( & self , c : char , input : & Input ) {
1200
- let vfn = self . violation_fn ;
1201
- if vfn. is_set ( ) {
1169
+ if let Some ( vfn) = self . violation_fn {
1202
1170
if c == '%' {
1203
1171
let mut input = input. clone ( ) ;
1204
1172
if !matches ! ( ( input. next( ) , input. next( ) ) , ( Some ( a) , Some ( b) )
1205
1173
if is_ascii_hex_digit( a) && is_ascii_hex_digit( b) ) {
1206
- vfn. call ( SyntaxViolation :: PercentDecode )
1174
+ vfn ( SyntaxViolation :: PercentDecode )
1207
1175
}
1208
1176
} else if !is_url_code_point ( c) {
1209
- vfn. call ( SyntaxViolation :: NonUrlCodePoint )
1177
+ vfn ( SyntaxViolation :: NonUrlCodePoint )
1210
1178
}
1211
1179
}
1212
1180
}
0 commit comments