From 7c672adbe60fd5b22251b5d4a01add12af401bbb Mon Sep 17 00:00:00 2001 From: azjezz Date: Sun, 1 Jan 2023 14:05:08 +0100 Subject: [PATCH] chore: use path reference instead of string Signed-off-by: azjezz --- README.md | 10 +-- src/loader.rs | 170 +++++++++++++++++++++----------------------------- 2 files changed, 72 insertions(+), 108 deletions(-) diff --git a/README.md b/README.md index 836df49..c87b357 100644 --- a/README.md +++ b/README.md @@ -26,15 +26,7 @@ fn main() { std::env::var("CARGO_MANIFEST_DIR").unwrap() ); - let map = loader::load_directories( - root.clone(), - vec![ - format!("{}src", root), - format!("{}vendor/foo", root), - format!("{}vendor/bar", root), - ], - ) - .unwrap(); + let result = loader::load_directories(root, vec!["src", "vendor/foo", "vendor/bar"])?; println!("{:#?}", map); } diff --git a/src/loader.rs b/src/loader.rs index f618d8c..66d8b62 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -1,3 +1,6 @@ +use std::path::Path; +use std::path::PathBuf; + use crate::error::Error; use crate::source::Source; use crate::source::SourceKind; @@ -7,16 +10,16 @@ pub const ARA_SCRIPT_EXTENSION: &str = "ara"; pub const ARA_DEFINTION_EXTENSION: &str = "d.ara"; /// Load a source map from the given directories. -pub fn load_directories, C: Into>( +pub fn load_directories, C: AsRef>( root: T, directories: Vec, ) -> Result { let mut map = SourceMap::new(vec![]); - let loader = DirectorySourceLoader::new(root.into()); + let loader = DirectorySourceLoader::new(&root); for directory in directories { - loader.load_into(&directory.into(), &mut map)?; + loader.load_into(&directory, &mut map)?; } Ok(map) @@ -26,17 +29,17 @@ pub trait SourceLoader: std::fmt::Debug { /// Check if the given name is supported by this loader. /// /// If `true` is returned, `load` *MUST NOT* return `Error::InvalidSource`. - fn supports(&self, name: &str) -> bool; + fn supports>(&self, name: &T) -> bool; /// Load a source map from the given name. /// /// The source name can contain a path, directory, or any other information. /// /// If the source name is not valid, `Error::InvalidSource` is returned. - fn load(&self, name: &str) -> Result; + fn load>(&self, name: &T) -> Result; /// Load a source from the given name and merge it into the given source map. - fn load_into(&self, name: &str, map: &mut SourceMap) -> Result<(), Error> { + fn load_into>(&self, name: &T, map: &mut SourceMap) -> Result<(), Error> { let mut source = self.load(name)?; map.merge(&mut source); @@ -47,28 +50,31 @@ pub trait SourceLoader: std::fmt::Debug { #[derive(Debug)] pub struct FileSourceLoader { - pub root: String, + pub root: PathBuf, } impl FileSourceLoader { - pub fn new(root: String) -> FileSourceLoader { - FileSourceLoader { root } + pub fn new>(root: &T) -> FileSourceLoader { + FileSourceLoader { + root: root.as_ref().to_path_buf(), + } } } impl SourceLoader for FileSourceLoader { - fn supports(&self, name: &str) -> bool { - if !name.starts_with(&self.root) { - return false; - } - - let path = std::path::Path::new(name); + fn supports>(&self, file: &T) -> bool { + let file = file.as_ref(); + let file = if file.is_relative() { + self.root.join(file) + } else { + file.to_path_buf() + }; - if !path.is_file() { + if !file.is_file() { return false; } - match path.extension() { + match file.extension() { Some(extension) => { let extension = match extension.to_str() { Some(extension) => extension, @@ -87,127 +93,100 @@ impl SourceLoader for FileSourceLoader { } } - fn load(&self, name: &str) -> Result { - if !self.supports(name) { + fn load>(&self, file: &T) -> Result { + let file = file.as_ref(); + + if !self.supports(&file) { return Err(Error::InvalidSource(format!( "source `{}` is not supported.", - name + file.to_string_lossy() ))); } - let kind = if name.ends_with(ARA_DEFINTION_EXTENSION) { + let file = if file.is_relative() { + self.root.join(file) + } else { + file.to_path_buf() + }; + + let content = std::fs::read_to_string(&file)?; + let origin = file + .strip_prefix(&self.root) + .map(|path| path.to_string_lossy()) + .unwrap(); + let kind = if origin.ends_with(ARA_DEFINTION_EXTENSION) { SourceKind::Definition } else { SourceKind::Script }; - let path = std::path::Path::new(&name); - - std::fs::read_to_string(path) - .map_err(Error::IoError) - .map(|content| { - SourceMap::new(vec![Source::new( - kind, - name.strip_prefix(&self.root).unwrap(), - content, - )]) - }) + Ok(SourceMap::new(vec![Source::new(kind, origin, content)])) } } #[derive(Debug)] pub struct DirectorySourceLoader { - pub root: String, - pub loaders: Vec>, + pub root: PathBuf, + + loader: FileSourceLoader, } impl DirectorySourceLoader { - pub fn new>(root: T) -> DirectorySourceLoader { - let root = root.into(); - + pub fn new>(root: &T) -> DirectorySourceLoader { DirectorySourceLoader { - root: root.clone(), - loaders: vec![Box::new(FileSourceLoader::new(root))], + root: root.as_ref().to_path_buf(), + loader: FileSourceLoader::new(root), } } - - pub fn add_loader(&mut self, loader: Box) { - self.loaders.push(loader); - } } impl SourceLoader for DirectorySourceLoader { - fn supports(&self, name: &str) -> bool { - if !name.starts_with(&self.root) { - return false; - } - - let path = std::path::Path::new(name); + fn supports>(&self, directory: &T) -> bool { + let directory = directory.as_ref(); + let directory = if directory.is_relative() { + self.root.join(directory) + } else { + directory.to_path_buf() + }; - if !path.is_dir() { + if !directory.starts_with(&self.root) { return false; } - let entries = match std::fs::read_dir(path) { - Ok(entries) => entries, - Err(_) => { - return false; - } - }; - - for entry in entries { - let entry = match entry { - Ok(entry) => entry, - Err(_) => { - return false; - } - }; - - let path = entry.path(); - let name = match path.to_str() { - Some(name) => name, - None => { - return false; - } - }; - - if path.is_dir() && !self.supports(name) { - return false; - } + if !directory.is_dir() { + return false; } true } - fn load(&self, name: &str) -> Result { - if !self.supports(name) { + fn load>(&self, directory: &T) -> Result { + let directory = directory.as_ref(); + if !self.supports(&directory) { return Err(Error::InvalidSource(format!( "source `{}` is not supported.", - name + directory.to_string_lossy() ))); } - let path = std::path::Path::new(&name); + let directory = if directory.is_relative() { + self.root.join(directory) + } else { + directory.to_path_buf() + }; let mut map = SourceMap::new(vec![]); - let entries = std::fs::read_dir(path).unwrap(); + let entries = std::fs::read_dir(directory)?; for entry in entries { let entry = entry.unwrap(); let path = entry.path(); - let name = path.to_str().unwrap(); if path.is_dir() { - self.load_into(name, &mut map)?; - } else { - for loader in &self.loaders { - if loader.supports(name) { - loader.load_into(name, &mut map)?; - - break; - } - } + self.load_into(&path, &mut map)?; + } else if self.loader.supports(&path) { + self.loader.load_into(&path, &mut map)?; } } @@ -226,14 +205,7 @@ mod tests { std::env::var("CARGO_MANIFEST_DIR").unwrap() ); - let result = load_directories( - root.clone(), - vec![ - format!("{}src", root), - format!("{}vendor/foo", root), - format!("{}vendor/bar", root), - ], - ); + let result = load_directories(root, vec!["src", "vendor/foo", "vendor/bar"]); let map = result.unwrap();