Replace the Rust URL form-encoding callback bridge into C++ TextCodec
with a direct encoding_rs encoder.
This keeps percent-encode-after-encoding entirely in Rust and removes
liburl_rust's dependency on LibTextCodec.
It also happens to fix ISO-2022-JP URL encoding of literal U+FFFD.
The LibTextCodec reverse lookup treats generated 0xFFFD table holes as
real JIS0208 mappings, so literal U+FFFD skipped the encoder-error
path. encoding_rs treats U+FFFD as unmappable, so URL encoding emits
the required numeric character reference.
After batch-processing the userinfo, the authority state advanced the
parse pointer onto the '@' and relied on the end-of-loop increment to
step past it. That increment uses the byte length of the authority's
first code point, not the delimiter's. When the first code point was
multi-byte, the pointer overshot into the middle of a code point and
the next iteration sliced the string at a non-char boundary causing the
process to panic. We now step past the delimiter explicitly so we don't
need to rely on the end of loop increment to do so.
The Rust URL FFI used String::from_utf8_lossy() on raw bytes from C++.
That was not equivalent to the old C++ parser behavior for WTF-8 encoded
surrogates. For example a byte sequence such as ED A0 80 was treated as
three invalid UTF-8 bytes, producing three U+FFFD replacement
characters.
Instead use String::from_utf8_with_replacement_character and let Rust
borrow the input as &str.
Copy contiguous ASCII path/query runs in one slice append, instead of
processing each code point individually. Fall back to the normal state
machine for delimiters, percent escapes, non-ASCII input, and validation
cases.
This gives a 2.4x speedup on a benchmark parsing common web URLs.