diff options
Diffstat (limited to 'src/path.rs')
-rw-r--r-- | src/path.rs | 145 |
1 files changed, 131 insertions, 14 deletions
diff --git a/src/path.rs b/src/path.rs index 56855ac..2e599bf 100644 --- a/src/path.rs +++ b/src/path.rs @@ -7,29 +7,37 @@ */ use crate::prelude::*; +use crate::path::error::*; lalrpop_mod!(pub parser, "/path/parser.rs"); +pub mod error; -#[derive(Debug)] +#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] pub struct AbsoluteDirectoryPath { - components: Vec<DirectoryName>, + directory_names: Vec<DirectoryName>, } -#[derive(Debug)] +#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] +pub struct AbsoluteFilePath { + directory_names: Vec<DirectoryName>, + file_name: FileName, +} + +#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] pub struct FileName(String); -#[derive(Debug)] +#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] pub struct DirectoryName(String); -#[derive(Debug)] +#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] pub struct GenericPath { components: Vec<GenericPathComponent>, starts_with_slash: bool, ends_with_slash: bool, } -#[derive(Debug)] +#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] pub enum GenericPathComponent { FileOrDirectoryName(String), CurrentDirectory, @@ -39,13 +47,29 @@ pub enum GenericPathComponent { impl std::fmt::Display for AbsoluteDirectoryPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for component in &self.components { + for directory_name in &self.directory_names { f.write_str("/")?; - component.fmt(f)?; + directory_name.fmt(f)?; + } + + f.write_str("/")?; + + Ok(()) + } +} + + +impl std::fmt::Display for AbsoluteFilePath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for directory_name in &self.directory_names { + f.write_str("/")?; + directory_name.fmt(f)?; } f.write_str("/")?; + self.file_name.fmt(f)?; + Ok(()) } } @@ -125,6 +149,57 @@ impl std::fmt::Display for GenericPathComponent { } +impl std::str::FromStr for FileName { + type Err = FileNameError; + + fn from_str(input: &str) -> std::result::Result<Self, Self::Err> { + if input.find('/').is_some() { + Err(FileNameError::ContainsSlash(input.to_string())) + } else { + Ok(FileName(input.to_string())) + } + } +} + + +impl std::str::FromStr for DirectoryName { + type Err = DirectoryNameError; + + fn from_str(input: &str) -> std::result::Result<Self, Self::Err> { + if input.find('/').is_some() { + Err(DirectoryNameError::ContainsSlash(input.to_string())) + } else { + Ok(DirectoryName(input.to_string())) + } + } +} + + +impl AbsoluteDirectoryPath { + pub fn to_sys_path(&self) -> std::path::PathBuf { + let mut result = std::path::PathBuf::new(); + result.push(format!("{}", self)); + result + } + + pub fn concat_file_name(&self, file_name: &FileName) -> AbsoluteFilePath { + AbsoluteFilePath { + directory_names: self.directory_names.clone(), + file_name: file_name.clone(), + } + } +} + + +impl AbsoluteFilePath { + pub fn to_sys_path(&self) -> std::path::PathBuf { + let mut result = std::path::PathBuf::new(); + result.push(format!("{}", self)); + result + } +} + + pub fn parse_path_list(path_list: &str) -> Result<Vec<AbsoluteDirectoryPath>> { @@ -157,7 +232,7 @@ pub fn absolute_directory_path(generic_path: GenericPath) -> Result<AbsoluteDirectoryPath> { if !generic_path.starts_with_slash { - return Err(Error::PathIsRelative(generic_path)); + return Err(Error::PathLexicallyRelative(generic_path)); } let mut flattened_components = Vec::new(); @@ -168,7 +243,7 @@ pub fn absolute_directory_path(generic_path: GenericPath) if flattened_components.len() > 0 { flattened_components.pop(); } else { - return Err(Error::PathInvalid(generic_path)); + return Err(Error::PathLexicallyInvalid(generic_path)); } }, GenericPathComponent::FileOrDirectoryName(name) => { @@ -177,12 +252,54 @@ pub fn absolute_directory_path(generic_path: GenericPath) } } - if flattened_components.len() == 0 { - return Err(Error::PathInvalid(generic_path)); + Ok(AbsoluteDirectoryPath { + directory_names: flattened_components, + }) +} + + +pub fn absolute_file_path(generic_path: GenericPath) + -> Result<AbsoluteFilePath> +{ + if !generic_path.starts_with_slash { + return Err(Error::PathLexicallyRelative(generic_path)); } - Ok(AbsoluteDirectoryPath { - components: flattened_components, + if generic_path.ends_with_slash { + return Err(Error::PathLexicallyDirectory(generic_path)); + } + + let mut iterator = generic_path.components.iter(); + + let file_name = match iterator.next_back() { + Some(GenericPathComponent::FileOrDirectoryName(name)) => { + FileName(name.to_string()) + } + _ => { + return Err(Error::PathLexicallyInvalid(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::PathLexicallyInvalid(generic_path)); + } + }, + GenericPathComponent::FileOrDirectoryName(name) => { + flattened_components.push(DirectoryName(name.to_string())); + }, + } + } + + Ok(AbsoluteFilePath { + directory_names: flattened_components, + file_name: file_name, }) } |