diff --git a/src/env.rs b/src/env.rs index 94dfabf..9f95fa5 100644 --- a/src/env.rs +++ b/src/env.rs @@ -13,7 +13,10 @@ pub trait Env { fn args (&self) -> Args; /// Bind a value to a name. - fn bind (&mut self, name: &str, value: &str); + fn bind (&mut self, name: N, value: V) + where + N: AsRef, + V: AsRef; /// Get a bound value from the env. fn get (&self, name: &str) -> Option; @@ -22,14 +25,21 @@ pub trait Env { fn working_dir (&self) -> Result; /// Change the working directory. - fn set_working_dir (&mut self, path: &std::path::Path) -> Result<()>; + fn set_working_dir

(&mut self, path: P) -> Result<()> + where + P: AsRef; /// Write to stdout. - fn stdout (&mut self, data: &str) -> Result<()>; + fn stdout (&mut self, data: R) -> Result<()> + where + R: ToString; /// Search the `PATH` variable for the `query`. The default implementation /// is derived from [`Env::get`]. - fn search (&self, query: &str) -> Option { + fn search (&self, query: S) -> Option + where + S: AsRef + { self.get("PATH")? .split(':') .filter_map(|path| { @@ -40,7 +50,7 @@ pub trait Env { }) .map(|file| file.path()) .find_map(|path| { - if path.file_name()? == query { + if path.file_name()? == query.as_ref() { Some (path) } else { None @@ -64,13 +74,14 @@ pub trait Env { /// Create a new environment that inherits this environments' /// behavior, except the args of this env are overwritten with /// `args`. - fn set_args (self, args: Args) -> SetArgs + fn set_args (self, args: A) -> SetArgs where - Self: Sized + Self: Sized, + A: IntoIterator, { SetArgs { parent: self, - args, + args: Args::from_iter(args), } } @@ -88,15 +99,24 @@ impl Env for SetArgs { self.parent.working_dir() } - fn set_working_dir (&mut self, path: &std::path::Path) -> Result<()> { + fn set_working_dir

(&mut self, path: P) -> Result<()> + where + P: AsRef + { self.parent.set_working_dir(path) } - fn search (&self, query: &str) -> Option { + fn search (&self, query: S) -> Option + where + S: AsRef + { self.parent.search(query) } - fn stdout (&mut self, data: &str) -> Result<()> { + fn stdout (&mut self, data: R) -> Result<()> + where + R: ToString + { self.parent.stdout(data) } @@ -104,7 +124,11 @@ impl Env for SetArgs { self.args.clone() } - fn bind (&mut self, name: &str, value: &str) { + fn bind (&mut self, name: N, value: V) + where + N: AsRef, + V: AsRef, + { self.parent.bind(name, value); } @@ -128,15 +152,24 @@ impl Env for Scope<'_, E> { self.parent.working_dir() } - fn set_working_dir (&mut self, path: &std::path::Path) -> Result<()> { + fn set_working_dir

(&mut self, path: P) -> Result<()> + where + P: AsRef + { self.parent.set_working_dir(path) } - fn search (&self, query: &str) -> Option { + fn search (&self, query: S) -> Option + where + S: AsRef + { self.parent.search(query) } - fn stdout (&mut self, data: &str) -> Result<()> { + fn stdout (&mut self, data: R) -> Result<()> + where + R: ToString + { self.parent.stdout(data) } @@ -144,8 +177,15 @@ impl Env for Scope<'_, E> { self.parent.args() } - fn bind (&mut self, name: &str, value: &str) { - self.bindings.insert(name.to_string(), value.to_string()); + fn bind (&mut self, name: N, value: V) + where + N: AsRef, + V: AsRef, + { + self.bindings.insert( + name.as_ref().to_string(), + value.as_ref().to_string() + ); } fn get (&self, name: &str) -> Option { @@ -206,16 +246,26 @@ impl Env for Pure { std::iter::empty::().collect() } - fn bind (&mut self, name: &str, value: &str) { - self.bindings.insert(name.to_string(), value.to_string()); + fn bind (&mut self, name: N, value: V) + where + N: AsRef, + V: AsRef, + { + self.bindings.insert( + name.as_ref().to_string(), + value.as_ref().to_string() + ); } fn get (&self, name: &str) -> Option { self.bindings.get(name).cloned() } - fn stdout (&mut self, data: &str) -> Result<()> { - self.buf += data; + fn stdout (&mut self, data: R) -> Result<()> + where + R: ToString + { + self.buf += &data.to_string(); Ok (()) } @@ -228,7 +278,12 @@ impl Env for Pure { } } - fn set_working_dir (&mut self, path: &std::path::Path) -> Result<()> { + fn set_working_dir

(&mut self, path: P) -> Result<()> + where + P: AsRef + { + let path = path.as_ref(); + if path.is_dir() && path.exists() { Ok (self.cwd = path.to_owned()) } else { @@ -247,8 +302,12 @@ impl Env for Inherit { std::env::args().skip(1).collect() } - fn bind (&mut self, name: &str, value: &str) { - std::env::set_var(name, value); + fn bind (&mut self, name: N, value: V) + where + N: AsRef, + V: AsRef, + { + std::env::set_var(name.as_ref(), value.as_ref()); } fn get (&self, name: &str) -> Option { @@ -260,13 +319,24 @@ impl Env for Inherit { .map_err(Error::Io) } - fn set_working_dir (&mut self, path: &std::path::Path) -> Result<()> { + fn set_working_dir

(&mut self, path: P) -> Result<()> + where + P: AsRef + { + let path = path.as_ref(); + std::env::set_current_dir(path) .map_err(Error::Io) } - fn stdout (&mut self, data: &str) -> Result<()> { - std::io::stdout().write(data.as_bytes())?; + fn stdout (&mut self, data: R) -> Result<()> + where + R: ToString + { + std::io::stdout().write( + data.to_string().as_bytes() + )?; + Ok (()) } } diff --git a/src/exec.rs b/src/exec.rs index 9c2a21d..d3a7732 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -15,18 +15,6 @@ pub trait Exec { } -impl Exec for F -where - F: Fn (&mut dyn Env) -> Result<()> -{ - fn exec (&self, env: &mut E) -> Result<()> - where - E: Env - { - self (env) - } -} - /// A shell command. pub enum Command { Program (Program), @@ -130,20 +118,30 @@ pub struct NotFound; /// ``` /// /// [`FromStr`]: std::str::FromStr -pub struct Builtin (fn (&mut dyn Env) -> Result<()>); +pub struct Builtin (BuiltinName); + +enum BuiltinName { + Disown, + Type, + Exit, + Pwd, + Fg, + Bg, + Cd, +} impl std::str::FromStr for Builtin { type Err = NotFound; fn from_str (s: &str) -> Result { let ret = Builtin (match s { - "disown" => builtin::disown, - "type" => builtin::r#type, - "exit" => builtin::exit, - "pwd" => builtin::pwd, - "fg" => builtin::fg, - "bg" => builtin::bg, - "cd" => builtin::cd, + "disown" => BuiltinName::Disown, + "type" => BuiltinName::Type, + "exit" => BuiltinName::Exit, + "pwd" => BuiltinName::Pwd, + "fg" => BuiltinName::Fg, + "bg" => BuiltinName::Bg, + "cd" => BuiltinName::Cd, _ => return Err (NotFound) }); @@ -156,7 +154,19 @@ impl Exec for Builtin { where E: Env { - self.0.exec(env) + use BuiltinName::*; + + let f = match self.0 { + Disown => builtin::disown, + Type => builtin::r#type, + Exit => builtin::exit, + Pwd => builtin::pwd, + Fg => builtin::fg, + Bg => builtin::bg, + Cd => builtin::cd, + }; + + f (env) } } @@ -167,20 +177,20 @@ pub mod builtin { use super::{ Env, Result, }; /// Change the current working directory. - pub fn cd (env: &mut dyn Env) -> Result<()> { + pub fn cd (env: &mut impl Env) -> Result<()> { let arg = env.args().next().unwrap(); - env.set_working_dir(arg.as_ref()) + env.set_working_dir(arg) } /// Print the current working directory. - pub fn pwd (env: &mut dyn Env) -> Result<()> { + pub fn pwd (env: &mut impl Env) -> Result<()> { let cwd = env.working_dir()?; env.stdout(format!("{}", cwd.display()).as_str()); Ok (()) } /// Stop the program. Optionally takes an exit code. - pub fn exit (env: &mut dyn Env) -> Result<()> { + pub fn exit (env: &mut impl Env) -> Result<()> { if let Some (code) = env.args().next().and_then(|s| s.parse::().ok()) { std::process::exit(code) } else { @@ -189,7 +199,7 @@ pub mod builtin { } /// Display information about the type of a command. - pub fn r#type (env: &mut dyn Env) -> Result<()> { + pub fn r#type (env: &mut impl Env) -> Result<()> { use crate::exec::Builtin; for arg in env.args() { @@ -210,19 +220,19 @@ pub mod builtin { /// Send a job to the background. See also [`Job::bg`]. /// /// [`Job::bg`]: crate::job::Job::bg - pub fn bg (_: &mut dyn Env) -> Result<()> { + pub fn bg (_: &mut impl Env) -> Result<()> { todo!() } /// Bring a job to the foreground. See also [`Job::fg`]. /// /// [`Job::fg`]: crate::job::Job::fg - pub fn fg (_: &mut dyn Env) -> Result<()> { + pub fn fg (_: &mut impl Env) -> Result<()> { todo!() } /// Disown all background jobs. - pub fn disown (_: &mut dyn Env) -> Result<()> { + pub fn disown (_: &mut impl Env) -> Result<()> { todo!() }