path helper fix
- remove directory segment and instead just have "file" for directories and files and other kinds of files since we cant know just based on the path what it is - segmetns are stored as vecdeque in normalized path to allow for hopefully more efficient poping in FIFO order (but definitely more ergonomic) - test for trailing seperators, the last trailing seperator is ignored, multiple trailing seperators are turned into noops because i parse paths left to right (regex?) in the simplest way possible. in normalized paths noops are completely ignored/removed
This commit is contained in:
parent
2af01747e7
commit
5a9918285f
|
@ -1,4 +1,4 @@
|
||||||
use alloc::vec::Vec;
|
use alloc::{collections::VecDeque, vec::Vec};
|
||||||
|
|
||||||
const SEPERATOR: u8 = b'/';
|
const SEPERATOR: u8 = b'/';
|
||||||
|
|
||||||
|
@ -31,15 +31,15 @@ pub trait Path: AsRef<[u8]> {
|
||||||
let iter = self.segment_iter();
|
let iter = self.segment_iter();
|
||||||
|
|
||||||
let mut segments =
|
let mut segments =
|
||||||
Vec::with_capacity(self.as_ref().iter().filter(|&b| b == &SEPERATOR).count());
|
VecDeque::with_capacity(self.as_ref().iter().filter(|&b| b == &SEPERATOR).count());
|
||||||
|
|
||||||
for segment in iter {
|
for segment in iter {
|
||||||
match segment {
|
match segment {
|
||||||
Segment::NoOp | Segment::CurrentDir => {}
|
Segment::NoOp | Segment::CurrentDir => {}
|
||||||
Segment::Root | Segment::Directory(_) | Segment::File(_) => segments.push(segment),
|
Segment::Root | Segment::File(_) => segments.push_back(segment),
|
||||||
Segment::ParentDir => {
|
Segment::ParentDir => {
|
||||||
if segments.last() != Some(&Segment::Root) {
|
if segments.back() != Some(&Segment::Root) {
|
||||||
segments.pop();
|
segments.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,20 +55,26 @@ pub enum Segment<'a> {
|
||||||
NoOp,
|
NoOp,
|
||||||
CurrentDir,
|
CurrentDir,
|
||||||
ParentDir,
|
ParentDir,
|
||||||
Directory(&'a [u8]),
|
|
||||||
File(&'a [u8]),
|
File(&'a [u8]),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Path for T where T: AsRef<[u8]> {}
|
impl<T> Path for T where T: AsRef<[u8]> {}
|
||||||
|
|
||||||
pub struct NormalizedPath<'a> {
|
pub struct NormalizedPath<'a> {
|
||||||
segments: Vec<Segment<'a>>,
|
segments: VecDeque<Segment<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> NormalizedPath<'a> {
|
impl<'a> NormalizedPath<'a> {
|
||||||
pub fn iter(&self) -> core::slice::Iter<Segment> {
|
pub fn into_iter(self) -> alloc::collections::vec_deque::IntoIter<Segment<'a>> {
|
||||||
|
self.segments.into_iter()
|
||||||
|
}
|
||||||
|
pub fn iter(&self) -> alloc::collections::vec_deque::Iter<Segment> {
|
||||||
self.segments.iter()
|
self.segments.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pop_segment(&mut self) -> Option<Segment<'a>> {
|
||||||
|
self.segments.pop_front()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PathSegmentIter<'a> {
|
pub struct PathSegmentIter<'a> {
|
||||||
|
@ -95,6 +101,9 @@ impl<'a> Iterator for PathSegmentIter<'a> {
|
||||||
if self.offset == 0 {
|
if self.offset == 0 {
|
||||||
// handle root segment
|
// handle root segment
|
||||||
Some(Segment::Root)
|
Some(Segment::Root)
|
||||||
|
} else if bytes.is_empty() {
|
||||||
|
// trailign seperator
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
// noop
|
// noop
|
||||||
Some(Segment::NoOp)
|
Some(Segment::NoOp)
|
||||||
|
@ -104,11 +113,7 @@ impl<'a> Iterator for PathSegmentIter<'a> {
|
||||||
} else if segment == &b".."[..] {
|
} else if segment == &b".."[..] {
|
||||||
Some(Segment::ParentDir)
|
Some(Segment::ParentDir)
|
||||||
} else {
|
} else {
|
||||||
if next == bytes.len() {
|
|
||||||
Some(Segment::File(segment))
|
Some(Segment::File(segment))
|
||||||
} else {
|
|
||||||
Some(Segment::Directory(segment))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
self.offset += bytes.len().min(next + 1);
|
self.offset += bytes.len().min(next + 1);
|
||||||
|
|
||||||
|
@ -174,11 +179,11 @@ mod segment_iter_tests {
|
||||||
fn test_noop() {
|
fn test_noop() {
|
||||||
let mut iter = b"this//a//path//some.file".segment_iter();
|
let mut iter = b"this//a//path//some.file".segment_iter();
|
||||||
|
|
||||||
assert_eq!(iter.next(), Some(Segment::Directory(&b"this"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"this"[..])));
|
||||||
assert_eq!(iter.next(), Some(Segment::NoOp));
|
assert_eq!(iter.next(), Some(Segment::NoOp));
|
||||||
assert_eq!(iter.next(), Some(Segment::Directory(&b"a"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"a"[..])));
|
||||||
assert_eq!(iter.next(), Some(Segment::NoOp));
|
assert_eq!(iter.next(), Some(Segment::NoOp));
|
||||||
assert_eq!(iter.next(), Some(Segment::Directory(&b"path"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"path"[..])));
|
||||||
assert_eq!(iter.next(), Some(Segment::NoOp));
|
assert_eq!(iter.next(), Some(Segment::NoOp));
|
||||||
assert_eq!(iter.next(), Some(Segment::File(&b"some.file"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"some.file"[..])));
|
||||||
assert_eq!(iter.next(), None);
|
assert_eq!(iter.next(), None);
|
||||||
|
@ -203,17 +208,60 @@ mod segment_iter_tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trailing_seperator() {
|
||||||
|
let mut iter = b"/this//".segment_iter();
|
||||||
|
|
||||||
|
assert_eq!(iter.next(), Some(Segment::Root));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::File(&b"this"[..])));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::NoOp));
|
||||||
|
assert_eq!(iter.next(), None);
|
||||||
|
|
||||||
|
let mut iter = b"this//".segment_iter();
|
||||||
|
|
||||||
|
assert_eq!(iter.next(), Some(Segment::File(&b"this"[..])));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::NoOp));
|
||||||
|
assert_eq!(iter.next(), None);
|
||||||
|
|
||||||
|
let mut iter = b"/this////".segment_iter();
|
||||||
|
|
||||||
|
assert_eq!(iter.next(), Some(Segment::Root));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::File(&b"this"[..])));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::NoOp));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::NoOp));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::NoOp));
|
||||||
|
assert_eq!(iter.next(), None);
|
||||||
|
|
||||||
|
let mut iter = b"/this////".normalize().into_iter();
|
||||||
|
|
||||||
|
assert_eq!(iter.next(), Some(Segment::Root));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::File(&b"this"[..])));
|
||||||
|
assert_eq!(iter.next(), None);
|
||||||
|
|
||||||
|
let mut iter = b"/this/".normalize().into_iter();
|
||||||
|
|
||||||
|
assert_eq!(iter.next(), Some(Segment::Root));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::File(&b"this"[..])));
|
||||||
|
assert_eq!(iter.next(), None);
|
||||||
|
|
||||||
|
let mut iter = b"/this".normalize().into_iter();
|
||||||
|
|
||||||
|
assert_eq!(iter.next(), Some(Segment::Root));
|
||||||
|
assert_eq!(iter.next(), Some(Segment::File(&b"this"[..])));
|
||||||
|
assert_eq!(iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iter() {
|
fn test_iter() {
|
||||||
let mut iter = b"/this/is/a//path/to/some.file".segment_iter();
|
let mut iter = b"/this/is/a//path/to/some.file".segment_iter();
|
||||||
|
|
||||||
assert_eq!(iter.next(), Some(Segment::Root));
|
assert_eq!(iter.next(), Some(Segment::Root));
|
||||||
assert_eq!(iter.next(), Some(Segment::Directory(&b"this"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"this"[..])));
|
||||||
assert_eq!(iter.next(), Some(Segment::Directory(&b"is"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"is"[..])));
|
||||||
assert_eq!(iter.next(), Some(Segment::Directory(&b"a"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"a"[..])));
|
||||||
assert_eq!(iter.next(), Some(Segment::NoOp));
|
assert_eq!(iter.next(), Some(Segment::NoOp));
|
||||||
assert_eq!(iter.next(), Some(Segment::Directory(&b"path"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"path"[..])));
|
||||||
assert_eq!(iter.next(), Some(Segment::Directory(&b"to"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"to"[..])));
|
||||||
assert_eq!(iter.next(), Some(Segment::File(&b"some.file"[..])));
|
assert_eq!(iter.next(), Some(Segment::File(&b"some.file"[..])));
|
||||||
assert_eq!(iter.next(), None);
|
assert_eq!(iter.next(), None);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue