use std::collections::btree_map::{BTreeMap, IntoIter};
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use crate::http::Error;
use crate::http::{urldecode, urlencode};
#[derive(Debug, Clone)]
pub struct Query {
query: BTreeMap<String, String>,
}
impl Query {
pub fn new() -> Self {
Self {
query: BTreeMap::new(),
}
}
pub fn parse(data: &str) -> Self {
let mut query = Self::new();
let without_anchor = data.split("#").next().expect("path anchor");
let query_parts = without_anchor.split("&");
for part in query_parts {
let mut key_value = part.split("=").collect::<Vec<_>>().into_iter();
if key_value.len() > 2 {
continue;
}
let key = urldecode(&key_value.next().expect("path query key"));
let value = urldecode(&key_value.next().unwrap_or(&""));
query.insert(key, value);
}
query
}
pub fn get<T: FromStr>(&self, name: &str) -> Option<T> {
match self.query.get(name) {
Some(value) => match urldecode(value).parse::<T>() {
Ok(value) => Some(value),
Err(_) => None,
},
None => None,
}
}
pub fn get_required<T: FromStr>(&self, name: &str) -> Result<T, Error> {
match self.get(name) {
Some(value) => Ok(value),
None => Err(Error::MissingParameter),
}
}
pub fn to_json(&self) -> serde_json::Value {
serde_json::to_value(&self.query).unwrap_or(serde_json::Value::default())
}
pub fn into_iter(self) -> IntoIter<String, String> {
self.query.into_iter()
}
}
impl std::fmt::Display for Query {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut params = vec![];
for (key, value) in &self.query {
params.push(format!("{}={}", urlencode(key), urlencode(value)));
}
write!(f, "{}", params.join("&"))
}
}
impl Deref for Query {
type Target = BTreeMap<String, String>;
fn deref(&self) -> &Self::Target {
&self.query
}
}
impl DerefMut for Query {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.query
}
}