summaryrefslogtreecommitdiff
path: root/dhall_syntax/src/core/import.rs
diff options
context:
space:
mode:
Diffstat (limited to 'dhall_syntax/src/core/import.rs')
-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() }
+ }
+}