paved 0.6.0

A simple platform agnostic path representation
Documentation
use std::{ffi::OsString, path::PathBuf};

use crate::{PathPrefix, PathType, PavedPath, UNIX_PATH_SEPARATOR, WINDOWS_PATH_SEPARATOR};

impl PavedPath {
    pub(crate) fn push_dir_raw(&mut self, dir: OsString) {
        if dir == "." || dir.is_empty() {
            return;
        }

        if dir == ".." {
            if self.directories.is_empty() || self.directories.last().unwrap() == ".." {
                self.directories.push(dir.to_os_string());
            } else {
                self.directories.pop();
            }

            return;
        }

        let lossy_dir = dir.to_string_lossy();
        let pattern = [WINDOWS_PATH_SEPARATOR, UNIX_PATH_SEPARATOR];

        if lossy_dir.find(pattern).is_some() {
            for d in lossy_dir.split(pattern) {
                self.push_dir_raw(OsString::from(d));
            }
        } else {
            self.directories.push(dir);
        }
    }

    pub(crate) fn build_windows_pathbuf(&self) -> PathBuf {
        let mut buf = OsString::new();

        match self.path_type {
            PathType::Absolute => match &self.path_prefix {
                Some(drv) => match drv {
                    PathPrefix::Drive(chr) => {
                        buf.push(format!("{chr}:{sep}", sep = WINDOWS_PATH_SEPARATOR))
                    }
                    PathPrefix::UNC(s1, s2) => {
                        buf.push(format!("{sep}{sep}", sep = WINDOWS_PATH_SEPARATOR));
                        buf.push(s1);
                        buf.push(WINDOWS_PATH_SEPARATOR.to_string());
                        buf.push(s2);
                        buf.push(WINDOWS_PATH_SEPARATOR.to_string());
                    }
                },
                None => buf.push(WINDOWS_PATH_SEPARATOR.to_string()),
            },
            PathType::Relative => buf.push(format!(".{sep}", sep = WINDOWS_PATH_SEPARATOR)),
        };

        for d in &self.directories {
            buf.push(d);
            buf.push(WINDOWS_PATH_SEPARATOR.to_string());
        }

        if let Some(f) = &self.file {
            buf.push(f);
        }

        PathBuf::from(buf)
    }

    pub(crate) fn build_unix_pathbuf(&self) -> PathBuf {
        let mut buf = OsString::new();

        match self.path_type {
            PathType::Absolute => buf.push(UNIX_PATH_SEPARATOR.to_string()),
            PathType::Relative => buf.push(format!(".{}", UNIX_PATH_SEPARATOR)),
        }

        for d in &self.directories {
            buf.push(d);
            buf.push(UNIX_PATH_SEPARATOR.to_string());
        }

        if let Some(f) = &self.file {
            buf.push(f);
        }

        PathBuf::from(buf)
    }

    pub(crate) fn rebuild_inner(&mut self) {
        let new_pathbuf = if cfg!(windows) {
            self.build_windows_pathbuf()
        } else {
            self.build_unix_pathbuf()
        };

        self.inner = new_pathbuf;
    }
}