1pub fn encode(input: &str) -> String {
4 let mut out = String::with_capacity(input.len());
5 for &b in input.as_bytes() {
6 match b {
7 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
8 out.push(b as char);
9 }
10 _ => {
11 out.push('%');
12 out.push_str(&format!("{:02X}", b));
13 }
14 }
15 }
16 out
17}
18
19#[cfg(test)]
20mod tests {
21 use super::encode;
22
23 #[test]
24 fn unreserved_passthrough() {
25 assert_eq!(encode("abcXYZ123-_.~"), "abcXYZ123-_.~");
26 }
27
28 #[test]
29 fn slash_encoded() {
30 assert_eq!(encode("owner/repo"), "owner%2Frepo");
31 }
32
33 #[test]
34 fn space_and_special() {
35 assert_eq!(encode("a b/c"), "a%20b%2Fc");
36 }
37
38 #[test]
39 fn utf8_multibyte() {
40 assert_eq!(encode("ñ"), "%C3%B1");
41 }
42}