summaryrefslogtreecommitdiff
path: root/dhall_syntax/src/core/import.rs
diff options
context:
space:
mode:
authorFintanH2019-08-12 22:22:24 +0100
committerFintanH2019-08-12 22:22:24 +0100
commit405bc3d80c0e169ea74dd12422b9504b7383dab3 (patch)
treef1f71797b0470375b12717a4663c1ea2ca1f96fd /dhall_syntax/src/core/import.rs
parent8ec422f2319360f986950fcb9aae4bcf65a9c1e2 (diff)
Refactor of File to be the combination of Directory and the file name,
where Directory is the Vector of component paths. The refactor meant changing some sections of the code where we were parsing and manipulating Files/Directories. This also includes a new trait Canonicalization which is needed for import logic.
Diffstat (limited to '')
-rw-r--r--dhall_syntax/src/core/import.rs122
1 files changed, 120 insertions, 2 deletions
diff --git a/dhall_syntax/src/core/import.rs b/dhall_syntax/src/core/import.rs
index c328e34..ea42dbc 100644
--- a/dhall_syntax/src/core/import.rs
+++ b/dhall_syntax/src/core/import.rs
@@ -11,10 +11,41 @@ pub enum FilePrefix {
Home,
}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Directory {
+ pub components: Vec<String>,
+}
+
+impl IntoIterator for Directory {
+ type Item = String;
+ type IntoIter = ::std::vec::IntoIter<Self::Item>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.components.into_iter()
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct File {
+ pub directory: Directory,
+ pub file: String,
+}
+
+impl IntoIterator for File {
+ type Item = String;
+ type IntoIter = ::std::vec::IntoIter<Self::Item>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ let mut paths = self.directory.components;
+ paths.push(self.file);
+ paths.into_iter()
+ }
+}
+
/// The location of import (i.e. local vs. remote vs. environment)
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ImportLocation {
- Local(FilePrefix, Vec<String>),
+ Local(FilePrefix, File),
Remote(URL),
Env(String),
Missing,
@@ -24,7 +55,7 @@ pub enum ImportLocation {
pub struct URL {
pub scheme: Scheme,
pub authority: String,
- pub path: Vec<String>,
+ pub path: File,
pub query: Option<String>,
pub headers: Option<Box<ImportHashed>>,
}
@@ -59,3 +90,90 @@ pub struct Import {
pub mode: ImportMode,
pub location_hashed: ImportHashed,
}
+
+pub trait Canonicalize {
+ fn canonicalize(&self) -> Self;
+}
+
+impl Canonicalize for Directory {
+ fn canonicalize(&self) -> Directory {
+ let mut components = Vec::new();
+ let mut dir_components = self.clone().into_iter();
+
+ loop {
+ let component = dir_components.next();
+ match component.as_ref() {
+ // ───────────────────
+ // canonicalize(ε) = ε
+ None => break,
+
+ // canonicalize(directory₀) = directory₁
+ // ───────────────────────────────────────
+ // canonicalize(directory₀/.) = directory₁
+ Some(c) if c == "." => continue,
+
+ Some(c) if c == ".." => match dir_components.next() {
+ // canonicalize(directory₀) = ε
+ // ────────────────────────────
+ // canonicalize(directory₀/..) = /..
+ None => components.push("..".to_string()),
+
+ // canonicalize(directory₀) = directory₁/..
+ // ──────────────────────────────────────────────
+ // canonicalize(directory₀/..) = directory₁/../..
+ Some(ref c) if c == ".." => {
+ components.push("..".to_string());
+ components.push("..".to_string());
+ },
+
+ // canonicalize(directory₀) = directory₁/component
+ // ─────────────────────────────────────────────── ; If "component" is not
+ // canonicalize(directory₀/..) = directory₁ ; ".."
+ Some(_) => continue,
+ },
+
+ // canonicalize(directory₀) = directory₁
+ // ───────────────────────────────────────────────────────── ; If no other
+ // canonicalize(directory₀/component) = directory₁/component ; rule matches
+ Some(c) => components.push(c.clone()),
+ }
+ }
+
+ Directory { components: components }
+ }
+}
+
+impl Canonicalize for File {
+ fn canonicalize(&self) -> File {
+ File { directory: self.directory.canonicalize(), file: self.file.clone() }
+ }
+}
+
+impl Canonicalize for ImportLocation {
+ fn canonicalize(&self) -> ImportLocation {
+ match self {
+ ImportLocation::Local(prefix, file) => ImportLocation::Local(*prefix, file.canonicalize()),
+ ImportLocation::Remote(url) => ImportLocation::Remote(URL {
+ scheme: url.scheme,
+ authority: url.authority.clone(),
+ path: url.path.canonicalize(),
+ query: url.query.clone(),
+ headers: url.headers.clone().map(|boxed_hash| Box::new(boxed_hash.canonicalize())),
+ }),
+ ImportLocation::Env(name) => ImportLocation::Env(name.to_string()),
+ ImportLocation::Missing => ImportLocation::Missing,
+ }
+ }
+}
+
+impl Canonicalize for ImportHashed {
+ fn canonicalize(&self) -> ImportHashed {
+ ImportHashed { hash: self.hash.clone(), location: self.location.canonicalize() }
+ }
+}
+
+impl Canonicalize for Import {
+ fn canonicalize(&self) -> Import {
+ Import { mode: self.mode, location_hashed: self.location_hashed.canonicalize() }
+ }
+}