From e95c0ffe952c504839f924b504fa7c235375cb3b Mon Sep 17 00:00:00 2001 From: Basile Henry Date: Fri, 12 Apr 2019 09:32:56 +0200 Subject: Cache imports --- dhall/src/imports.rs | 46 ++++++++++++++++++++++++++++++++++------------ dhall_core/src/import.rs | 16 ++++++++-------- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/dhall/src/imports.rs b/dhall/src/imports.rs index ff28ab2..0078040 100644 --- a/dhall/src/imports.rs +++ b/dhall/src/imports.rs @@ -1,6 +1,7 @@ use crate::error::Error; use crate::expr::*; use dhall_core::*; +use std::collections::HashMap; use std::fs::File; use std::io::Read; use std::path::Path; @@ -18,9 +19,12 @@ pub enum ImportRoot { LocalDir(PathBuf), } +type ImportCache = HashMap>; + fn resolve_import( import: &Import, root: &ImportRoot, + import_cache: &mut ImportCache, ) -> Result, ImportError> { use self::ImportRoot::*; use dhall_core::FilePrefix::*; @@ -36,7 +40,7 @@ fn resolve_import( Here => cwd.join(path), _ => unimplemented!("{:?}", import), }; - Ok(load_import(&path).map_err(|e| { + Ok(load_import(&path, import_cache).map_err(|e| { ImportError::Recursive(import.clone(), Box::new(e)) })?) } @@ -44,23 +48,41 @@ fn resolve_import( } } -fn load_import(f: &Path) -> Result, Error> { - Ok(Parsed::parse_file(f)?.resolve()?.typecheck()?.normalize()) +fn load_import( + f: &Path, + import_cache: &mut ImportCache, +) -> Result, Error> { + Ok(resolve_expr_imports(Parsed::parse_file(f)?, import_cache)? + .typecheck()? + .normalize()) } -fn resolve_expr<'a>( +fn resolve_expr_imports<'a>( Parsed(expr, root): Parsed<'a>, - allow_imports: bool, + import_cache: &mut ImportCache, ) -> Result, ImportError> { let resolve = |import: &Import| -> Result, ImportError> { - if allow_imports { - let expr = resolve_import(import, &root)?; - Ok(expr) - } else { - Err(ImportError::UnexpectedImport(import.clone())) + match import_cache.get(import) { + Some(expr) => Ok(expr.clone()), + None => { + let expr = resolve_import(import, &root, import_cache)?; + import_cache.insert(import.clone(), expr.clone()); + Ok(expr) + } } }; + let expr = expr.as_ref().traverse_embed(resolve)?; + Ok(Resolved(rc(expr))) +} + +fn resolve_expr<'a>( + Parsed(expr, _root): Parsed<'a>, +) -> Result, ImportError> { + let resolve = + |import: &Import| -> Result, ImportError> { + Err(ImportError::UnexpectedImport(import.clone())) + }; let expr = expr.as_ref().traverse_embed(&resolve)?; Ok(Resolved(rc(expr))) } @@ -90,11 +112,11 @@ impl<'a> Parsed<'a> { } pub fn resolve(self) -> Result, ImportError> { - crate::imports::resolve_expr(self, true) + crate::imports::resolve_expr_imports(self, &mut HashMap::new()) } #[allow(dead_code)] pub fn skip_resolve(self) -> Result, ImportError> { - crate::imports::resolve_expr(self, false) + crate::imports::resolve_expr(self) } } diff --git a/dhall_core/src/import.rs b/dhall_core/src/import.rs index f039953..00f293c 100644 --- a/dhall_core/src/import.rs +++ b/dhall_core/src/import.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; /// The beginning of a file path which anchors subsequent path components -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum FilePrefix { /// Absolute path Absolute, @@ -14,7 +14,7 @@ pub enum FilePrefix { } /// The location of import (i.e. local vs. remote vs. environment) -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ImportLocation { Local(FilePrefix, PathBuf), Remote(URL), @@ -22,7 +22,7 @@ pub enum ImportLocation { Missing, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct URL { pub scheme: Scheme, pub authority: String, @@ -31,33 +31,33 @@ pub struct URL { pub headers: Option>, } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Scheme { HTTP, HTTPS, } /// How to interpret the import's contents (i.e. as Dhall code or raw text) -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ImportMode { Code, RawText, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Hash { pub protocol: String, pub hash: String, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ImportHashed { pub location: ImportLocation, pub hash: Option, } /// Reference to an external resource -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Import { pub mode: ImportMode, pub location_hashed: ImportHashed, -- cgit v1.2.3