pub(crate) fn join<T>(items: &[T], f: impl Fn(&T) -> String) -> String {
items.iter().map(f).collect::<Vec<_>>().join(",")
}
pub(crate) fn path_escape(value: &str) -> String {
let mut out = String::with_capacity(value.len());
for &byte in value.as_bytes() {
match byte {
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'.' | b'_' | b'~' => {
out.push(byte as char);
}
_ => {
out.push('%');
out.push_str(&format!("{byte:02X}"));
}
}
}
out
}
pub(crate) fn form_encode(pairs: &[(&str, String)]) -> String {
let mut out = String::new();
for (index, (key, value)) in pairs.iter().enumerate() {
if index > 0 {
out.push('&');
}
out.push_str(&path_escape(key));
out.push('=');
out.push_str(&path_escape(value));
}
out
}