@@ -1191,32 +1191,96 @@ impl<'a> Parser<'a> {
1191
1191
path_start : usize ,
1192
1192
mut input : Input < ' i > ,
1193
1193
) -> Input < ' i > {
1194
+ // it's much faster to call utf8_percent_encode in bulk
1195
+ fn push_pending (
1196
+ serialization : & mut String ,
1197
+ start_str : & str ,
1198
+ remaining_len : usize ,
1199
+ context : Context ,
1200
+ scheme_type : SchemeType ,
1201
+ ) {
1202
+ let text = & start_str[ ..start_str. len ( ) - remaining_len] ;
1203
+ if text. is_empty ( ) {
1204
+ return ;
1205
+ }
1206
+ if context == Context :: PathSegmentSetter {
1207
+ if scheme_type. is_special ( ) {
1208
+ serialization. extend ( utf8_percent_encode ( text, SPECIAL_PATH_SEGMENT ) ) ;
1209
+ } else {
1210
+ serialization. extend ( utf8_percent_encode ( text, PATH_SEGMENT ) ) ;
1211
+ }
1212
+ } else {
1213
+ serialization. extend ( utf8_percent_encode ( text, PATH ) ) ;
1214
+ }
1215
+ }
1216
+
1194
1217
// Relative path state
1195
1218
loop {
1196
1219
let mut segment_start = self . serialization . len ( ) ;
1197
1220
let mut ends_with_slash = false ;
1221
+ let mut start_str = input. chars . as_str ( ) ;
1198
1222
loop {
1199
1223
let input_before_c = input. clone ( ) ;
1200
- let ( c, utf8_c) = if let Some ( x) = input. next_utf8 ( ) {
1201
- x
1224
+ // bypass input.next() and manually handle ascii_tab_or_new_line
1225
+ // in order to encode string slices in bulk
1226
+ let c = if let Some ( c) = input. chars . next ( ) {
1227
+ c
1202
1228
} else {
1229
+ push_pending (
1230
+ & mut self . serialization ,
1231
+ start_str,
1232
+ 0 ,
1233
+ self . context ,
1234
+ scheme_type,
1235
+ ) ;
1203
1236
break ;
1204
1237
} ;
1205
1238
match c {
1239
+ ascii_tab_or_new_line_pattern ! ( ) => {
1240
+ push_pending (
1241
+ & mut self . serialization ,
1242
+ start_str,
1243
+ input_before_c. chars . as_str ( ) . len ( ) ,
1244
+ self . context ,
1245
+ scheme_type,
1246
+ ) ;
1247
+ start_str = input. chars . as_str ( ) ;
1248
+ }
1206
1249
'/' if self . context != Context :: PathSegmentSetter => {
1250
+ push_pending (
1251
+ & mut self . serialization ,
1252
+ start_str,
1253
+ input_before_c. chars . as_str ( ) . len ( ) ,
1254
+ self . context ,
1255
+ scheme_type,
1256
+ ) ;
1207
1257
self . serialization . push ( c) ;
1208
1258
ends_with_slash = true ;
1209
1259
break ;
1210
1260
}
1211
1261
'\\' if self . context != Context :: PathSegmentSetter
1212
1262
&& scheme_type. is_special ( ) =>
1213
1263
{
1264
+ push_pending (
1265
+ & mut self . serialization ,
1266
+ start_str,
1267
+ input_before_c. chars . as_str ( ) . len ( ) ,
1268
+ self . context ,
1269
+ scheme_type,
1270
+ ) ;
1214
1271
self . log_violation ( SyntaxViolation :: Backslash ) ;
1215
1272
self . serialization . push ( '/' ) ;
1216
1273
ends_with_slash = true ;
1217
1274
break ;
1218
1275
}
1219
1276
'?' | '#' if self . context == Context :: UrlParser => {
1277
+ push_pending (
1278
+ & mut self . serialization ,
1279
+ start_str,
1280
+ input_before_c. chars . as_str ( ) . len ( ) ,
1281
+ self . context ,
1282
+ scheme_type,
1283
+ ) ;
1220
1284
input = input_before_c;
1221
1285
break ;
1222
1286
}
@@ -1228,23 +1292,21 @@ impl<'a> Parser<'a> {
1228
1292
& self . serialization [ path_start + 1 ..] ,
1229
1293
)
1230
1294
{
1295
+ push_pending (
1296
+ & mut self . serialization ,
1297
+ start_str,
1298
+ input_before_c. chars . as_str ( ) . len ( ) ,
1299
+ self . context ,
1300
+ scheme_type,
1301
+ ) ;
1302
+ start_str = input_before_c. chars . as_str ( ) ;
1231
1303
self . serialization . push ( '/' ) ;
1232
1304
segment_start += 1 ;
1233
1305
}
1234
- if self . context == Context :: PathSegmentSetter {
1235
- if scheme_type. is_special ( ) {
1236
- self . serialization
1237
- . extend ( utf8_percent_encode ( utf8_c, SPECIAL_PATH_SEGMENT ) ) ;
1238
- } else {
1239
- self . serialization
1240
- . extend ( utf8_percent_encode ( utf8_c, PATH_SEGMENT ) ) ;
1241
- }
1242
- } else {
1243
- self . serialization . extend ( utf8_percent_encode ( utf8_c, PATH ) ) ;
1244
- }
1245
1306
}
1246
1307
}
1247
1308
}
1309
+
1248
1310
let segment_before_slash = if ends_with_slash {
1249
1311
& self . serialization [ segment_start..self . serialization . len ( ) - 1 ]
1250
1312
} else {
0 commit comments