#[derive(Clone, Debug)]
pub struct QueryIter<'a> {
rest: &'a [u8],
}
impl<'a> Iterator for QueryIter<'a> {
type Item = (&'a [u8], &'a [u8]);
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.rest.is_empty() {
return None;
}
if self.rest[0] == b'&' {
self.rest = &self.rest[1..];
continue;
}
break;
}
let (segment, tail) = self.rest.iter().position(|&b| b == b'&').map_or_else(
|| (self.rest, &b""[..]),
|amp| (&self.rest[..amp], &self.rest[amp + 1..]),
);
self.rest = tail;
let (name, value) = segment.iter().position(|&b| b == b'=').map_or_else(
|| (segment, &b""[..]),
|eq| (&segment[..eq], &segment[eq + 1..]),
);
Some((name, value))
}
}
#[inline]
#[must_use]
pub const fn parse(query: &[u8]) -> QueryIter<'_> {
QueryIter { rest: query }
}
#[cfg(test)]
mod tests {
use super::*;
fn collect(input: &[u8]) -> Vec<(&[u8], &[u8])> {
parse(input).collect()
}
#[test]
fn empty_input() {
assert!(collect(b"").is_empty());
}
#[test]
fn single_pair() {
assert_eq!(collect(b"a=1"), &[(&b"a"[..], &b"1"[..])]);
}
#[test]
fn multiple_pairs() {
assert_eq!(
collect(b"a=1&b=2&c=3"),
&[
(&b"a"[..], &b"1"[..]),
(&b"b"[..], &b"2"[..]),
(&b"c"[..], &b"3"[..]),
]
);
}
#[test]
fn name_without_value() {
assert_eq!(collect(b"flag"), &[(&b"flag"[..], &b""[..])]);
assert_eq!(
collect(b"a=1&flag&b=2"),
&[
(&b"a"[..], &b"1"[..]),
(&b"flag"[..], &b""[..]),
(&b"b"[..], &b"2"[..]),
]
);
}
#[test]
fn empty_value() {
assert_eq!(collect(b"a="), &[(&b"a"[..], &b""[..])]);
}
#[test]
fn empty_name() {
assert_eq!(collect(b"=v"), &[(&b""[..], &b"v"[..])]);
}
#[test]
fn skip_empty_segments() {
assert_eq!(collect(b"&&a=1"), &[(&b"a"[..], &b"1"[..])]);
assert_eq!(
collect(b"a=1&&b=2"),
&[(&b"a"[..], &b"1"[..]), (&b"b"[..], &b"2"[..])]
);
assert!(collect(b"&&&").is_empty());
}
#[test]
fn value_contains_equals() {
assert_eq!(collect(b"a=1=2"), &[(&b"a"[..], &b"1=2"[..])]);
}
#[test]
fn raw_undecoded_output() {
assert_eq!(
collect(b"q=hello+world&n=foo%20bar"),
&[
(&b"q"[..], &b"hello+world"[..]),
(&b"n"[..], &b"foo%20bar"[..]),
]
);
}
#[test]
fn iterator_is_lazy_and_clone() {
let iter = parse(b"a=1&b=2");
let mut a = iter.clone();
let mut b = iter;
assert_eq!(a.next(), Some((&b"a"[..], &b"1"[..])));
assert_eq!(b.next(), Some((&b"a"[..], &b"1"[..])));
}
#[test]
fn integrates_with_pct_form_decode() {
use crate::pct::{Mode, decode};
let pairs: Vec<_> = parse(b"q=hello+world").collect();
let (name, value) = pairs[0];
let mut nbuf = [0u8; 16];
let mut vbuf = [0u8; 16];
assert_eq!(decode(name, Mode::Form, &mut nbuf).unwrap(), b"q");
assert_eq!(
decode(value, Mode::Form, &mut vbuf).unwrap(),
b"hello world"
);
}
}