From b9f3007d9eca3ecb42a2d05fe44f9cae9a795cc1 Mon Sep 17 00:00:00 2001 From: fdai7451 Date: Thu, 19 Jan 2023 14:20:26 +0100 Subject: [PATCH] feat: use trait to define builtins --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/builtins/cd.rs | 14 +++++++++++--- src/builtins/exit.rs | 9 +++++++-- src/builtins/mod.rs | 20 ++++++++++++++------ 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd9af18..aab23d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -169,10 +169,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + [[package]] name = "pmuw-project" version = "0.1.0" dependencies = [ + "once_cell", "rustyline", "shlex", ] diff --git a/Cargo.toml b/Cargo.toml index c097580..91d07aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +once_cell = "1.17" rustyline = "10.1.0" shlex = "1.1" diff --git a/src/builtins/cd.rs b/src/builtins/cd.rs index 14230fa..c840d80 100644 --- a/src/builtins/cd.rs +++ b/src/builtins/cd.rs @@ -1,8 +1,16 @@ +use crate::builtins::Builtin; use std::env::set_current_dir; use crate::error::ShellError; -pub fn run(args: Vec) -> Result<(), ShellError> { - set_current_dir(args.get(0).unwrap()); - Ok(()) +pub struct Cd; + +impl Builtin for Cd { + fn execute(&mut self, args: Vec) -> Result<(), ShellError> { + let Some(first) = args.get(0) else { + return Err(ShellError::ExecuteFailure("no argument given".to_string())) + }; + + set_current_dir(first).map_err(|e| ShellError::ExecuteFailure(e.to_string())) + } } diff --git a/src/builtins/exit.rs b/src/builtins/exit.rs index 8bf4196..c71586a 100644 --- a/src/builtins/exit.rs +++ b/src/builtins/exit.rs @@ -1,5 +1,10 @@ +use crate::builtins::Builtin; use crate::error::ShellError; -pub fn run() -> Result<(), ShellError> { - Err(ShellError::Exit) +pub struct Exit; + +impl Builtin for Exit { + fn execute(&mut self, _: Vec) -> Result<(), ShellError> { + Err(ShellError::Exit) + } } diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index c02da93..ac07bb9 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -1,18 +1,26 @@ use crate::error::ShellError; +use once_cell::unsync::Lazy; mod cd; mod exit; -const BUILTINS: &[&str] = &["exit", "cd"]; +trait Builtin: Sync + Send { + fn execute(&mut self, args: Vec) -> Result<(), ShellError>; +} + +const BUILTINS: Lazy)>> = + Lazy::new(|| vec![("cd", Box::new(cd::Cd)), ("exit", Box::new(exit::Exit))]); pub fn is_builtin(keyword: &str) -> bool { - BUILTINS.contains(&keyword) + BUILTINS.iter().find(|(k, _)| k == &keyword).is_some() } +#[allow(const_item_mutation)] pub fn execute_builtin(keyword: &str, args: Vec) -> Result<(), ShellError> { - match keyword { - "exit" => exit::run()?, - "cd" => cd::run(args)?, - _ => {} + if let Some(builtin) = BUILTINS + .iter_mut() + .find_map(|(k, c)| if k == &keyword { Some(c) } else { None }) + { + builtin.execute(args)? } Ok(()) }