use std::{ops::Deref, sync::Arc};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct PercentDecodedStr(Arc<str>);
impl PercentDecodedStr {
pub(crate) fn new<S: AsRef<str>>(s: S) -> Option<Self> {
percent_encoding::percent_decode(s.as_ref().as_bytes())
.decode_utf8()
.ok()
.map(|decoded| Self(decoded.as_ref().into()))
}
pub(crate) fn as_str(&self) -> &str {
&self.0
}
}
impl Deref for PercentDecodedStr {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_percent_decoded_str_invalid_utf8() {
let encoded = "Invalid%FF";
let decoded = PercentDecodedStr::new(encoded);
assert!(decoded.is_none());
}
#[test]
fn test_percent_decoded_str() {
let encoded = "Hello%20World%21";
let decoded = PercentDecodedStr::new(encoded);
assert!(decoded.is_some());
let decoded = decoded.unwrap();
assert_eq!(&*decoded, "Hello World!");
}
}