use super::percent_decode;
use std::borrow::Cow;
pub struct Params<'a> {
params: Cow<'a, str>,
}
impl<'a> Params<'a> {
pub fn new(params: &'a str) -> Self {
Params {
params: percent_decode::decode_query(params),
}
}
pub fn into_inner(self) -> Cow<'a, str> {
self.params
}
pub fn find<'b>(&self, param: &'b str) -> ParamIter<'_, 'b> {
ParamIter::new(&self.params, param)
}
pub fn iter(&self) -> AllParamIter<'_> {
AllParamIter {
remaining: &self.params,
}
}
}
pub struct AllParamIter<'a> {
remaining: &'a str,
}
impl<'a> Iterator for AllParamIter<'a> {
type Item = (&'a str, &'a str);
fn next(&mut self) -> Option<Self::Item> {
if self.remaining.is_empty() {
return None;
}
let (current_param, rest) = self
.remaining
.split_once('&')
.unwrap_or((self.remaining, ""));
self.remaining = rest;
if let Some((k, v)) = current_param.split_once('=') {
Some((k, v))
} else {
Some((current_param, ""))
}
}
}
impl<'a> AllParamIter<'a> {
pub fn new(params: &'a str) -> Self {
Self { remaining: params }
}
}
pub struct ParamIter<'a, 'b> {
remaining: &'a str,
filter: &'b str,
}
impl<'a, 'b> Iterator for ParamIter<'a, 'b> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
while !self.remaining.is_empty() {
let (current_param, rest) = self
.remaining
.split_once('&')
.unwrap_or((self.remaining, ""));
self.remaining = rest;
if let Some((k, v)) = current_param.split_once('=')
&& k == self.filter
{
return Some(v);
}
}
None
}
}
impl<'a, 'b> ParamIter<'a, 'b> {
pub fn new(params: &'a str, filter: &'b str) -> Self {
Self {
remaining: params,
filter,
}
}
pub fn name(&self) -> &'b str {
self.filter
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_find_param() {
let params = Params::new("foo=bar&baz=qux&foo=baz");
let mut p = params.find("foo");
assert_eq!(p.next(), Some("bar"));
assert_eq!(p.next(), Some("baz"));
assert_eq!(p.next(), None);
p = params.find("baz");
assert_eq!(p.next(), Some("qux"));
assert_eq!(p.next(), None);
assert_eq!(params.find("qux").next(), None);
}
#[test]
fn test_into_inner() {
let params = Params::new("foo=bar");
let cow = params.into_inner();
assert_eq!(cow, Cow::Borrowed("foo=bar"));
let params = Params::new("foo%20bar=baz");
let cow = params.into_inner();
assert!(matches!(cow, Cow::Owned(_)));
assert_eq!(cow, Cow::Owned::<str>("foo bar=baz".to_string()));
}
#[test]
fn test_all_param() {
let params = Params::new("foo=bar&baz=qux&foo=baz");
let mut it = params.iter();
assert_eq!(it.next(), Some(("foo", "bar")));
assert_eq!(it.next(), Some(("baz", "qux")));
assert_eq!(it.next(), Some(("foo", "baz")));
assert_eq!(it.next(), None);
}
}