use std::borrow::Cow;
use crate::encode::OutputEncoder;
#[derive(Clone, Copy, Debug, Default)]
pub struct UrlEncoder;
fn is_unreserved(b: u8) -> bool {
b.is_ascii_alphanumeric() || matches!(b, b'-' | b'_' | b'.' | b'~')
}
impl OutputEncoder for UrlEncoder {
fn encode<'a>(&self, input: &'a str) -> Cow<'a, str> {
let needs = input.bytes().any(|b| !is_unreserved(b));
if !needs {
return Cow::Borrowed(input);
}
let mut out = String::with_capacity(input.len() * 2);
for b in input.bytes() {
if b == 0 {
continue;
}
if is_unreserved(b) {
out.push(b as char);
} else {
let hi = char::from_digit(u32::from(b >> 4), 16)
.unwrap_or('0')
.to_ascii_uppercase();
let lo = char::from_digit(u32::from(b & 0xF), 16)
.unwrap_or('0')
.to_ascii_uppercase();
out.push('%');
out.push(hi);
out.push(lo);
}
}
Cow::Owned(out)
}
}
#[must_use]
pub fn encode(input: &str) -> Cow<'_, str> {
UrlEncoder.encode(input)
}