use super::percent_decode::PercentDecode;
use std::borrow::Cow;
pub struct PathIterator<'buf> {
remainder: &'buf str,
}
impl<'buf> PathIterator<'buf> {
pub fn new(input: &'buf str) -> Self {
Self { remainder: input }
}
}
impl<'buf> Iterator for PathIterator<'buf> {
type Item = Cow<'buf, str>;
fn next(&mut self) -> Option<Self::Item> {
if self.remainder.is_empty() {
return None;
}
let mut chars = self.remainder.char_indices();
chars.next();
let index = match chars.find(|&(_, c)| c == '/') {
Some((index, _)) => index,
None => self.remainder.len(),
};
let (part, rest) = self.remainder.split_at(index);
self.remainder = rest;
Some(part.percent_decode())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_path_iterator() {
let cases = vec![
("/", vec!["/"]),
("//", vec!["/", "/"]),
("/path", vec!["/path"]),
("path", vec!["path"]),
("/path/to/somewhere", vec!["/path", "/to", "/somewhere"]),
("", vec![]),
("/path/", vec!["/path", "/"]),
("/path//", vec!["/path", "/", "/"]),
("/path//to", vec!["/path", "/", "/to"]),
("/path/./to", vec!["/path", "/.", "/to"]),
("/path/../to", vec!["/path", "/..", "/to"]),
("/path%20with%20space", vec!["/path with space"]),
];
for (input, expected) in cases {
let actual: Vec<_> = PathIterator::new(input).collect();
assert_eq!(actual, expected, "Failed on input: {}", input);
}
}
}