use super::percent_decode::PercentDecode;
use std::borrow::Cow;
pub struct Params<'buf> {
params: &'buf str,
}
impl<'buf> Params<'buf> {
pub fn new(params: &'buf str) -> Self {
Params { params }
}
pub fn find<'p>(&self, param: &'p str) -> ParamIter<'buf, 'p> {
ParamIter::new(self.params, param)
}
pub fn iter(&self) -> AllParamIter<'buf> {
AllParamIter {
remaining: self.params,
}
}
}
pub struct AllParamIter<'buf> {
remaining: &'buf str,
}
impl<'buf> Iterator for AllParamIter<'buf> {
type Item = (Cow<'buf, str>, Cow<'buf, 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.percent_decode_query(), v.percent_decode_query()))
} else {
Some((current_param.percent_decode_query(), Cow::Borrowed("")))
}
}
}
impl<'buf> AllParamIter<'buf> {
pub fn new(params: &'buf str) -> Self {
Self { remaining: params }
}
}
pub struct ParamIter<'buf, 'param> {
remaining: &'buf str,
filter: &'param str,
}
impl<'buf, 'param> Iterator for ParamIter<'buf, 'param> {
type Item = Cow<'buf, 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('=') {
if k.percent_decode_query() == self.filter {
return Some(v.percent_decode_query());
}
} else if current_param.percent_decode_query() == self.filter {
return Some(Cow::Borrowed(""));
}
}
None
}
}
impl<'buf, 'param> ParamIter<'buf, 'param> {
pub fn new(params: &'buf str, filter: &'param str) -> Self {
Self {
remaining: params,
filter,
}
}
pub fn name(&self) -> &'param 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(Cow::Borrowed("bar")));
assert_eq!(p.next(), Some(Cow::Borrowed("baz")));
assert_eq!(p.next(), None);
p = params.find("baz");
assert_eq!(p.next(), Some(Cow::Borrowed("qux")));
assert_eq!(p.next(), None);
assert_eq!(params.find("qux").next(), None);
}
#[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((Cow::Borrowed("foo"), Cow::Borrowed("bar")))
);
assert_eq!(
it.next(),
Some((Cow::Borrowed("baz"), Cow::Borrowed("qux")))
);
assert_eq!(
it.next(),
Some((Cow::Borrowed("foo"), Cow::Borrowed("baz")))
);
assert_eq!(it.next(), None);
}
#[test]
fn test_encoded_delimiter() {
let params = Params::new("a=foo%26b=bar");
let mut p = params.find("a");
assert_eq!(p.next(), Some(Cow::Owned::<str>("foo&b=bar".to_string())));
assert_eq!(p.next(), None);
let mut p_b = params.find("b");
assert_eq!(p_b.next(), None);
}
}