summary refs log tree commit diff
path: root/src/path.rs
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@gmail.com>2020-12-25 21:10:37 -0800
committerIrene Knapp <ireneista@gmail.com>2020-12-25 21:10:37 -0800
commitefc68f54e3476de0bd209995c36043c26131b8df (patch)
tree676d6915d9daa336586aeb50fb46dcaf09622efb /src/path.rs
parentf5ec40b8fbbe7d4409d94dafcbfcdd41b8a6202b (diff)
refactor path parsing into a separate file, implement some Display traits, etc
Diffstat (limited to 'src/path.rs')
-rw-r--r--src/path.rs169
1 files changed, 161 insertions, 8 deletions
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<DirectoryName>,
+}
 
 #[derive(Debug)]
 pub struct FileName(String);
 
 #[derive(Debug)]
-pub struct AbsoluteDirectoryPath {
-  components: Vec<DirectoryName>,
+pub struct DirectoryName(String);
+
+#[derive(Debug)]
+pub struct GenericPath {
+  components: Vec<GenericPathComponent>,
+  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<GenericPathComponent>,
-  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<Vec<AbsoluteDirectoryPath>>
+{
+  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<AbsoluteDirectoryPath>
+{
+  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,
+  })
+}
+