libpna 0.33.0

PNA(Portable-Network-Archive) decoding and encoding library
Documentation
//! UTF-8 path normalization helpers.

use camino::{Utf8Component, Utf8Path, Utf8PathBuf};

#[inline]
pub(crate) fn normalize_utf8path(path: impl AsRef<Utf8Path>) -> Utf8PathBuf {
    let path = path.as_ref();
    let mut components = path.components().peekable();
    let mut buf = if let Some(p @ Utf8Component::Prefix(..)) = components.peek() {
        let buf = Utf8PathBuf::from(p);
        components.next();
        buf
    } else {
        Utf8PathBuf::new()
    };
    for c in components {
        match c {
            Utf8Component::Prefix(_) => unreachable!(),
            Utf8Component::RootDir => buf.push(c),
            Utf8Component::CurDir => (),
            Utf8Component::ParentDir => match buf.components().next_back() {
                Some(Utf8Component::Normal(_)) => {
                    buf.pop();
                }
                Some(Utf8Component::ParentDir) | None => buf.push(c),
                Some(Utf8Component::RootDir | Utf8Component::Prefix(_)) => {}
                Some(Utf8Component::CurDir) => unreachable!("normalized path must not contain '.'"),
            },
            Utf8Component::Normal(_) => buf.push(c),
        }
    }
    buf
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn normalize() {
        assert_eq!("", normalize_utf8path(""));
        assert_eq!("a.txt", normalize_utf8path("a.txt"));
        assert_eq!("/a.txt", normalize_utf8path("/a.txt"));
        assert_eq!("a.txt", normalize_utf8path("./a.txt"));
        assert_eq!("a.txt", normalize_utf8path("a/../a.txt"));
        assert_eq!("a.txt", normalize_utf8path("a/b/../../a.txt"));
        assert_eq!("../a.txt", normalize_utf8path("../a.txt"));
        assert_eq!("../..", normalize_utf8path("../.."));
        assert_eq!("../../a.txt", normalize_utf8path("../../a.txt"));
        assert_eq!("../a.txt", normalize_utf8path("a/../../a.txt"));
        assert_eq!("a/a.txt", normalize_utf8path("a/b/./../a.txt"));
        assert_eq!("/", normalize_utf8path("/"));
        assert_eq!("/a/b", normalize_utf8path("/a//b///"));
        assert_eq!("a/b", normalize_utf8path("a//b///"));
        assert_eq!("a/b", normalize_utf8path("a/b/"));
        assert_eq!("a", normalize_utf8path("a/."));
        assert_eq!("", normalize_utf8path("."));
        assert_eq!("..", normalize_utf8path(".."));
        assert_eq!("/", normalize_utf8path("/.."));
    }
}