use parser::{self, SchemeType, to_u32};
use std::str;
use Url;
#[derive(Debug)]
pub struct PathSegmentsMut<'a> {
url: &'a mut Url,
after_first_slash: usize,
after_path: String,
old_after_path_position: u32,
}
pub fn new(url: &mut Url) -> PathSegmentsMut {
let after_path = url.take_after_path();
let old_after_path_position = to_u32(url.serialization.len()).unwrap();
debug_assert!(url.byte_at(url.path_start) == b'/');
PathSegmentsMut {
after_first_slash: url.path_start as usize + "/".len(),
url: url,
old_after_path_position: old_after_path_position,
after_path: after_path,
}
}
impl<'a> Drop for PathSegmentsMut<'a> {
fn drop(&mut self) {
self.url.restore_after_path(self.old_after_path_position, &self.after_path)
}
}
impl<'a> PathSegmentsMut<'a> {
pub fn clear(&mut self) -> &mut Self {
self.url.serialization.truncate(self.after_first_slash);
self
}
pub fn pop_if_empty(&mut self) -> &mut Self {
if self.url.serialization[self.after_first_slash..].ends_with('/') {
self.url.serialization.pop();
}
self
}
pub fn pop(&mut self) -> &mut Self {
let last_slash = self.url.serialization[self.after_first_slash..].rfind('/').unwrap_or(0);
self.url.serialization.truncate(self.after_first_slash + last_slash);
self
}
pub fn push(&mut self, segment: &str) -> &mut Self {
self.extend(Some(segment))
}
pub fn extend<I>(&mut self, segments: I) -> &mut Self
where I: IntoIterator, I::Item: AsRef<str> {
let scheme_type = SchemeType::from(self.url.scheme());
let path_start = self.url.path_start as usize;
self.url.mutate(|parser| {
parser.context = parser::Context::PathSegmentSetter;
for segment in segments {
let segment = segment.as_ref();
if matches!(segment, "." | "..") {
continue
}
if parser.serialization.len() > path_start + 1 {
parser.serialization.push('/');
}
let mut has_host = true; parser.parse_path(scheme_type, &mut has_host, path_start,
parser::Input::new(segment));
}
});
self
}
}