use crate::utils::{Also, Apply};
use std::str::FromStr;
use smallvec::SmallVec;
#[derive(Debug)]
pub struct OrderedQs {
qs: SmallVec<[(String, String); 16]>,
}
impl OrderedQs {
#[cfg(test)]
pub fn from_vec_unchecked(mut v: Vec<(String, String)>) -> Self {
v.sort();
Self { qs: v.into() }
}
pub fn from_query(query: &str) -> Result<Self, serde_urlencoded::de::Error> {
serde_urlencoded::from_str::<Vec<(String, String)>>(query)?
.also(|v| v.sort())
.apply(|qs| Ok(Self { qs: qs.into() }))
}
pub fn get(&self, name: &str) -> Option<&str> {
let qs = self.qs.as_ref();
match qs.binary_search_by_key(&name, |&(ref n, _)| n.as_str()) {
Ok(idx) => qs.get(idx).map(|&(_, ref v)| v.as_str()),
Err(_) => None,
}
}
pub fn assign<T: FromStr>(&self, name: &str, opt: &mut Option<T>) -> Result<(), T::Err> {
if let Some(s) = self.get(name) {
let v = s.parse()?;
*opt = Some(v);
}
Ok(())
}
pub fn assign_str(&self, name: &str, opt: &mut Option<String>) {
if let Some(s) = self.get(name) {
*opt = Some(s.to_owned());
}
}
}
impl AsRef<[(String, String)]> for OrderedQs {
fn as_ref(&self) -> &[(String, String)] {
self.qs.as_ref()
}
}