summary refs log tree commit diff
path: root/src/path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/path.rs')
-rw-r--r--src/path.rs145
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,
   })
 }