1use std::{2 any::Any,3 fs,4 io::Read,5 path::{Path, PathBuf},6};78use fs::File;910use crate::{11 error::{Error::*, Result},12 throw,13};141516pub trait ImportResolver {17 18 19 20 fn resolve_file(&self, from: &Path, path: &str) -> Result<PathBuf>;2122 fn load_file_contents(&self, resolved: &Path) -> Result<Vec<u8>>;2324 25 26 27 28 29 unsafe fn as_any(&self) -> &dyn Any;30}313233pub struct DummyImportResolver;34impl ImportResolver for DummyImportResolver {35 fn resolve_file(&self, from: &Path, path: &str) -> Result<PathBuf> {36 throw!(ImportNotSupported(from.into(), path.into()))37 }3839 fn load_file_contents(&self, _resolved: &Path) -> Result<Vec<u8>> {40 panic!("dummy resolver can't load any file")41 }4243 unsafe fn as_any(&self) -> &dyn Any {44 panic!("`as_any(&self)` is not supported by dummy resolver")45 }46}47#[allow(clippy::use_self)]48impl Default for Box<dyn ImportResolver> {49 fn default() -> Self {50 Box::new(DummyImportResolver)51 }52}535455#[derive(Default)]56pub struct FileImportResolver {57 58 59 pub library_paths: Vec<PathBuf>,60}61impl ImportResolver for FileImportResolver {62 fn resolve_file(&self, from: &Path, path: &str) -> Result<PathBuf> {63 let mut direct = from.to_path_buf();64 direct.push(path);65 if direct.exists() {66 Ok(direct.canonicalize().map_err(|e| ImportIo(e.to_string()))?)67 } else {68 for library_path in &self.library_paths {69 let mut cloned = library_path.clone();70 cloned.push(path);71 if cloned.exists() {72 return Ok(cloned.canonicalize().map_err(|e| ImportIo(e.to_string()))?);73 }74 }75 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))76 }77 }7879 fn load_file_contents(&self, id: &Path) -> Result<Vec<u8>> {80 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;81 let mut out = Vec::new();82 file.read_to_end(&mut out)83 .map_err(|e| ImportIo(e.to_string()))?;84 Ok(out)85 }86 unsafe fn as_any(&self) -> &dyn Any {87 panic!("this resolver can't be used as any")88 }89}