use url::{
Url,
form_urlencoded::Parse,
percent_encoding::percent_decode,
};
use std::{
str::Utf8Error,
borrow::Cow,
collections::BTreeMap,
fmt::Debug,
};
use hyper::Uri;
#[derive(Debug,Clone)]
pub struct QueryString {
parsed: Url,
}
pub struct QueryStringIterator<'t,I>
where I: Iterator<Item = (Cow<'t,str>,Cow<'t,str>)>
{
iter: I,
key: String,
}
impl<'t,I> Iterator for QueryStringIterator<'t,I>
where I: Iterator<Item = (Cow<'t,str>,Cow<'t,str>)>
{
type Item = Cow<'t,str>;
fn next(&mut self) -> Option<Self::Item> {
loop {
return match self.iter.next() {
None => None,
Some((k,v)) => if k == self.key {
Some(v)
} else {
continue
}
};
}
}
}
impl QueryString {
pub fn from_uri(uri: &Uri) -> Result<QueryString,UrlParseError> {
let decoded = match uri.clone().into_parts().path_and_query {
Some(pq) => percent_decode(pq.as_str().as_bytes()).decode_utf8().map_err(UrlParseError::Utf8)?.to_string(),
None => "/".to_string(),
};
let parsed_data = std::rc::Rc::new(format!("http://localhost{}",decoded));
let parsed = Url::parse(&parsed_data).map_err(UrlParseError::Url)?;
Ok(QueryString{
parsed: parsed,
})
}
pub fn iter(&self) -> Parse {
self.parsed.query_pairs()
}
pub fn key<'t>(&'t self, key: &str) -> QueryStringIterator<'t,Parse<'t>> {
QueryStringIterator {
iter: self.parsed.query_pairs().into_iter(),
key: key.to_string(),
}
}
pub fn into_map<'t>(&self) -> QueryMap {
let mut hash = BTreeMap::new();
for (k,v) in self.parsed.query_pairs() {
hash.entry(k.to_string()).or_insert(Value::None).push(v.to_string());
}
hash
}
}
pub type QueryMap = BTreeMap<String,Value<String>>;
#[derive(Debug)]
pub enum Value<T> {
None,
One(T),
Vec(Vec<T>),
}
impl<T> Value<T> {
pub fn push(&mut self, value: T) {
let mut tmp = Value::None;
std::mem::swap(&mut tmp,self);
*self = match tmp {
Value::None => Value::One(value),
Value::One(v) => Value::Vec(vec![v,value]),
Value::Vec(mut v) => {
v.push(value);
Value::Vec(v)
},
};
}
pub fn try_map<Q,F,E>(&self, func: F) -> Result<Value<Q>,E>
where F: Fn(&T) -> Result<Q,E>,
E: Debug
{
Ok(match self {
Value::None => Value::None,
Value::One(v) => Value::One(func(v)?),
Value::Vec(vs) => Value::Vec({
let mut nv = Vec::with_capacity(vs.len());
for v in vs.iter() {
nv.push(func(v)?);
}
nv
}),
})
}
}
#[derive(Debug)]
pub enum UrlParseError {
Url(url::ParseError),
Utf8(Utf8Error),
}