1use std::borrow::Cow;
6
7use encoding_rs::{EncoderResult, Encoding, UTF_8};
8
9pub fn encode_as_url_query_string<'a>(
13 mut string: &'a str,
14 encoding: &'static Encoding,
15) -> Cow<'a, [u8]> {
16 let output_encoding = encoding.output_encoding();
17 if output_encoding == UTF_8 {
18 return Cow::Borrowed(string.as_bytes());
19 }
20
21 let bytes = string.as_bytes();
22 let valid_up_to = if output_encoding == encoding_rs::ISO_2022_JP {
23 Encoding::iso_2022_jp_ascii_valid_up_to(bytes)
24 } else {
25 Encoding::ascii_valid_up_to(bytes)
26 };
27
28 if valid_up_to == bytes.len() {
29 return Cow::Borrowed(bytes);
31 }
32
33 let mut encoder = encoding.new_encoder();
34 let mut output = Vec::with_capacity(
35 encoder
36 .max_buffer_length_from_utf8_if_no_unmappables(string.len())
37 .expect("string size would overflow `usize`"),
38 );
39 loop {
40 match encoder.encode_from_utf8_to_vec_without_replacement(string, &mut output, true) {
41 (EncoderResult::InputEmpty, _) => break,
42 (EncoderResult::OutputFull, consumed) => {
43 output.reserve(
44 encoder
45 .max_buffer_length_from_utf8_if_no_unmappables(string.len())
46 .expect("string size would overflow `usize`"),
47 );
48 string = &string[consumed..];
49 },
50 (EncoderResult::Unmappable(character), consumed) => {
51 use std::io::Write;
52 write!(&mut output, "%26%23{}%3B", character as u32).unwrap();
53 string = &string[consumed..];
54 },
55 };
56 }
57
58 Cow::Owned(output)
59}