1use alloc::{borrow::Cow, string::String};
2
3use crate::Result;
4
5pub fn encode(url: &str) -> Result<Cow<str>> {
7 let is_ascii = |c: &u8| {
8 matches!(c, b'0'..=b'9' | b'A'..=b'Z'
9 | b'a'..=b'z' | b'-' | b'.'
10 | b'_' | b'~')
11 };
12 let len = url.as_bytes().iter().take_while(|c| is_ascii(c)).count();
13 if len >= url.len() {
14 return Ok(url.into());
15 }
16 let mut buf = String::new();
17 for byte in url.as_bytes() {
18 if is_ascii(byte) {
19 buf.push(*byte as char);
20 } else {
21 buf.push('%');
22 buf.push(to_hex_digit(byte >> 4));
23 buf.push(to_hex_digit(byte & 0b1111));
24 }
25 }
26 Ok(buf.into())
27}
28
29#[inline(always)]
30fn to_hex_digit(digit: u8) -> char {
31 (match digit {
32 0..=9 => b'0' + digit,
33 10..=255 => b'A' - 10 + digit,
34 } as char)
35}