#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct SearchParams {
pairs: Vec<(String, String)>,
}
impl SearchParams {
pub fn new() -> SearchParams {
SearchParams::default()
}
pub fn parse(text: &str) -> SearchParams {
let text = text.strip_prefix('?').unwrap_or(text);
SearchParams { pairs: url::form_urlencoded::parse(text.as_bytes()).into_owned().collect() }
}
pub fn parse_bytes(bytes: &[u8]) -> SearchParams {
SearchParams { pairs: url::form_urlencoded::parse(bytes).into_owned().collect() }
}
pub fn from_pairs<K: Into<String>, V: Into<String>>(pairs: impl IntoIterator<Item = (K, V)>) -> SearchParams {
SearchParams { pairs: pairs.into_iter().map(|(k, v)| (k.into(), v.into())).collect() }
}
pub fn get(&self, name: &str) -> Option<&str> {
self.pairs.iter().find(|(k, _)| k == name).map(|(_, v)| v.as_str())
}
pub fn get_all(&self, name: &str) -> Vec<String> {
self.pairs.iter().filter(|(k, _)| k == name).map(|(_, v)| v.clone()).collect()
}
pub fn has(&self, name: &str) -> bool {
self.pairs.iter().any(|(k, _)| k == name)
}
pub fn set(&mut self, name: &str, value: &str) {
let mut found = false;
self.pairs.retain_mut(|(k, v)| {
if k != name {
return true;
}
if found {
return false;
}
found = true;
*v = value.to_string();
true
});
if !found {
self.pairs.push((name.to_string(), value.to_string()));
}
}
pub fn append(&mut self, name: &str, value: &str) {
self.pairs.push((name.to_string(), value.to_string()));
}
pub fn delete(&mut self, name: &str) {
self.pairs.retain(|(k, _)| k != name);
}
pub fn pairs(&self) -> &[(String, String)] {
&self.pairs
}
pub fn is_empty(&self) -> bool {
self.pairs.is_empty()
}
}
impl std::fmt::Display for SearchParams {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut s = url::form_urlencoded::Serializer::new(String::new());
for (k, v) in &self.pairs {
s.append_pair(k, v);
}
f.write_str(&s.finish())
}
}