From efc68f54e3476de0bd209995c36043c26131b8df Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Fri, 25 Dec 2020 21:10:37 -0800 Subject: refactor path parsing into a separate file, implement some Display traits, etc --- src/path.rs | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 161 insertions(+), 8 deletions(-) (limited to 'src/path.rs') diff --git a/src/path.rs b/src/path.rs index bfb5719..7a81873 100644 --- a/src/path.rs +++ b/src/path.rs @@ -1,15 +1,24 @@ +use crate::prelude::*; + lalrpop_mod!(pub parser, "/path/parser.rs"); #[derive(Debug)] -pub struct DirectoryName(String); +pub struct AbsoluteDirectoryPath { + components: Vec, +} #[derive(Debug)] pub struct FileName(String); #[derive(Debug)] -pub struct AbsoluteDirectoryPath { - components: Vec, +pub struct DirectoryName(String); + +#[derive(Debug)] +pub struct GenericPath { + components: Vec, + starts_with_slash: bool, + ends_with_slash: bool, } #[derive(Debug)] @@ -19,9 +28,153 @@ pub enum GenericPathComponent { ParentDirectory, } -#[derive(Debug)] -pub struct GenericPath { - components: Vec, - starts_with_slash: bool, - ends_with_slash: bool, + +impl std::fmt::Display for AbsoluteDirectoryPath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for component in &self.components { + f.write_str("/")?; + component.fmt(f)?; + } + + f.write_str("/")?; + + Ok(()) + } +} + + +impl std::fmt::Display for FileName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + FileName(name) => { + let std_path = std::path::Path::new(&name); + f.write_fmt(format_args!("{}", std_path.display()))?; + }, + } + + Ok(()) + } } + + +impl std::fmt::Display for DirectoryName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DirectoryName(name) => { + let std_path = std::path::Path::new(&name); + f.write_fmt(format_args!("{}", std_path.display()))?; + }, + } + + Ok(()) + } +} + + +impl std::fmt::Display for GenericPath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.starts_with_slash { + f.write_str("/")?; + } + + let mut is_first = true; + for component in &self.components { + if !is_first { + f.write_str("/")?; + } + + component.fmt(f)?; + + is_first = false; + } + + if self.ends_with_slash { + f.write_str("/")?; + } + + Ok(()) + } +} + + +impl std::fmt::Display for GenericPathComponent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + GenericPathComponent::FileOrDirectoryName(name) => { + let std_path = std::path::Path::new(&name); + f.write_fmt(format_args!("{}", std_path.display()))?; + }, + GenericPathComponent::CurrentDirectory => { + f.write_str(".")?; + }, + GenericPathComponent::ParentDirectory => { + f.write_str("..")?; + }, + } + + Ok(()) + } +} + + +pub fn parse_path_list(path_list: &str) + -> Result> +{ + match parser::PathListParser::new().parse(path_list) { + Ok(parsed_paths) => { + let mut result = Vec::new(); + for generic_path in parsed_paths { + let path = absolute_directory_path(generic_path)?; + result.push(path); + } + Ok(result) + }, + Err(original_error) => { + match parser::PathListAllowingEmptyPathsParser::new() + .parse(path_list) + { + Ok(_) => { + Err(Error::PathListHasEmptyComponents(path_list.to_string())) + }, + Err(_) => { + Err(Error::Parse(original_error.to_string())) + }, + } + }, + } +} + + +pub fn absolute_directory_path(generic_path: GenericPath) + -> Result +{ + if !generic_path.starts_with_slash { + return Err(Error::PathIsRelative(generic_path)); + } + + let mut flattened_components = Vec::new(); + for component in &generic_path.components { + match component { + GenericPathComponent::CurrentDirectory => { }, + GenericPathComponent::ParentDirectory => { + if flattened_components.len() > 0 { + flattened_components.pop(); + } else { + return Err(Error::PathInvalid(generic_path)); + } + }, + GenericPathComponent::FileOrDirectoryName(name) => { + flattened_components.push(DirectoryName(name.to_string())); + }, + } + } + + if flattened_components.len() == 0 { + return Err(Error::PathInvalid(generic_path)); + } + + Ok(AbsoluteDirectoryPath { + components: flattened_components, + }) +} + -- cgit 1.4.1