use percent_encoding::{percent_decode_str, utf8_percent_encode, NON_ALPHANUMERIC};
use std::borrow::Cow;
#[cfg(feature = "url")]
pub trait UrlExt {
fn mt_query_pairs(&self) -> MtQueryPairsParse;
fn mt_query_pairs_mut(&mut self) -> UrlMtQuery;
}
#[cfg(feature = "url")]
impl UrlExt for url::Url {
fn mt_query_pairs(&self) -> MtQueryPairsParse {
MtQueryPairsParse::new(self.query().unwrap_or(""))
}
fn mt_query_pairs_mut(&mut self) -> UrlMtQuery {
let input = self.query().unwrap_or("").to_string();
let pairs = MtQueryPairsSerializer { input };
UrlMtQuery { url: self, pairs }
}
}
#[cfg(feature = "url")]
#[derive(Debug)]
pub struct UrlMtQuery<'url> {
url: &'url mut url::Url,
pairs: MtQueryPairsSerializer,
}
#[cfg(feature = "url")]
impl<'url> UrlMtQuery<'url> {
pub fn clear(&mut self) -> &mut Self {
self.pairs.clear();
self
}
pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self {
self.pairs.append_pair(name, value);
self
}
}
#[cfg(feature = "url")]
impl<'url> Drop for UrlMtQuery<'url> {
fn drop(&mut self) {
self.url.set_query(Some(&self.pairs.input));
}
}
#[derive(Debug, Copy, Clone)]
pub struct MtQueryPairsParse<'input> {
input: &'input str,
}
impl<'input> MtQueryPairsParse<'input> {
pub fn new(input: &'input str) -> Self {
Self { input }
}
}
impl<'input> Iterator for MtQueryPairsParse<'input> {
type Item = (Cow<'input, str>, Cow<'input, str>);
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.input.is_empty() {
return None;
}
let (pair, tail) = self.input.split_once(';').unwrap_or((self.input, ""));
self.input = tail;
if pair.is_empty() {
continue;
}
let (key, value) = pair.split_once('=').unwrap_or((pair, ""));
return Some((decode(key), decode(value)));
}
}
}
fn decode(raw: &str) -> Cow<str> {
percent_decode_str(raw).decode_utf8_lossy()
}
#[derive(Debug, Clone)]
pub struct MtQueryPairsSerializer {
input: String,
}
impl MtQueryPairsSerializer {
pub fn clear(&mut self) -> &mut Self {
self.input.clear();
self
}
pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self {
if !self.input.is_empty() {
self.input.push(';');
}
self.input.extend(utf8_percent_encode(name, NON_ALPHANUMERIC));
self.input.push('=');
self.input.extend(utf8_percent_encode(value, NON_ALPHANUMERIC));
self
}
}