product-os-request 0.0.55

Product OS : Request provides a fully featured HTTP request library combining elements of reqwest and hyper for async requests with a series of helper methods to allow for easier usage depending upon your needs for one-time or repeat usage.
Documentation
//! Minimal percent-encoding for query string parameters (RFC 3986)

use alloc::string::String;

fn is_unreserved(b: u8) -> bool {
    b.is_ascii_alphanumeric() || b == b'-' || b == b'_' || b == b'.' || b == b'~'
}

const HEX: &[u8; 16] = b"0123456789ABCDEF";

/// Percent-encode a string for use in a URI query parameter.
///
/// Encodes all characters except unreserved characters per RFC 3986:
/// `ALPHA / DIGIT / "-" / "." / "_" / "~"`
pub(crate) fn percent_encode(input: &str) -> String {
    let mut out = String::with_capacity(input.len());
    for &b in input.as_bytes() {
        if is_unreserved(b) {
            out.push(b as char);
        } else {
            out.push('%');
            out.push(HEX[(b >> 4) as usize] as char);
            out.push(HEX[(b & 0x0F) as usize] as char);
        }
    }
    out
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_unreserved_passthrough() {
        assert_eq!(percent_encode("abc123"), "abc123");
        assert_eq!(percent_encode("a-b_c.d~e"), "a-b_c.d~e");
    }

    #[test]
    fn test_space() {
        assert_eq!(percent_encode("hello world"), "hello%20world");
    }

    #[test]
    fn test_special_chars() {
        assert_eq!(percent_encode("a@b"), "a%40b");
        assert_eq!(percent_encode("key=val"), "key%3Dval");
        assert_eq!(percent_encode("a&b"), "a%26b");
    }

    #[test]
    fn test_empty() {
        assert_eq!(percent_encode(""), "");
    }

    #[test]
    fn test_unicode() {
        assert_eq!(percent_encode("café"), "caf%C3%A9");
    }
}