/// Base of the HexaDecimal Number system static BASE16_HEXA_DECIMAL: u8 = 0x10; /// Highest possible Value per digit static BASE16_HEXA_DECIMAL_POSSIBLE_VALUE_PER_DIGIT: u8 = 0xF; /// Bits of a hexa decimal number static BASE16_HEXA_DECIMAL_DIGIT_BITS: u8 = 4; pub trait EnCodable { /// Encodes the give data into a Percent Encoded [String] fn encode(&self) -> String; } pub trait DeCodable { /// Decodes the given data into a [`Vec<u8>`] /// /// # Errors /// Errors if the encoding isn't right fn decode(&self) -> Result<Vec<u8>, ()>; } impl<T: AsRef<[u8]>> EnCodable for T { fn encode(&self) -> String { self.as_ref().encode() } } impl EnCodable for [u8] { fn encode(self: &[u8]) -> String { let mut result = String::with_capacity(self.len()); let result_vec = unsafe { result.as_mut_vec() }; self.iter().for_each(|byte| { if !matches!(byte, b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' | b'-' | b'_' | b'.' | b'~') { result_vec.push(b'%'); result_vec.push(hex_to_digit(byte >> BASE16_HEXA_DECIMAL_DIGIT_BITS)); result_vec.push(hex_to_digit( byte & BASE16_HEXA_DECIMAL_POSSIBLE_VALUE_PER_DIGIT, )); } else { result_vec.push(*byte) } }); result } } impl DeCodable for &str { fn decode(&self) -> Result<Vec<u8>, ()> { let mut first = true; let mut result = Vec::with_capacity(self.len()); for i in self.split('%') { if first { first = false; result.extend_from_slice(i.as_bytes()); continue; } let Ok(char) = u8::from_str_radix(i[0..=1].as_ref(), BASE16_HEXA_DECIMAL.into()) else { return Err(()); }; result.push(char); result.extend_from_slice(i[2..].as_bytes()); } Ok(result) } } /// converts a [u8] digit into the ascii code of its counterpart. The digit shouldn't be bigger /// than [BASE16_HEXA_DECIMAL_POSSIBLE_VALUE_PER_DIGIT] fn hex_to_digit(digit: u8) -> u8 { match digit { 0..=9 => b'0' + digit, 10..=255 => b'A' + digit - 10, } } #[cfg(test)] mod test { use crate::utils::urlencoded::endecode::DeCodable; use crate::utils::urlencoded::endecode::EnCodable; #[test] fn urlencoded_test() { assert_eq!( "Darius%20is%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire", b"Darius is the biggest genius/Genie/Human extraordin\xC3\xA4ire".encode() ); } #[test] fn urldecoded_test() { assert_eq!( "Darius is the biggest genius/Genie/Human extraordinäire", String::from_utf8( "Darius%20is%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire" .decode() .unwrap() ) .unwrap() ); assert_eq!( Err(()), "Darius%2iis%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire".decode() ); assert_eq!( "hi?asdf=sadf%%&jkl=s", String::from_utf8("hi?asdf=sadf%25%25&jkl=s".decode().unwrap()).unwrap() ) } }