From 49ee1a6a67d9cc0c908fcdcfcd369d6bf911bc67 Mon Sep 17 00:00:00 2001
From: Michael Aaron Murphy <mmstickman@gmail.com>
Date: Sat, 18 Mar 2017 11:50:04 -0400
Subject: [PATCH] Build Builtin Map Once

This change will build the builtin map at the beginning of the program instead of building it every time a command is executed.
---
 src/main.rs          |  5 +++--
 src/shell/flow.rs    |  2 +-
 src/shell/history.rs |  2 +-
 src/shell/mod.rs     | 19 ++++++++++---------
 4 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 62c0a4d9..d8435f7c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -18,11 +18,12 @@ mod parser;
 mod shell;
 
 use std::io::{stderr, Write, ErrorKind};
-
+use builtins::Builtin;
 use shell::Shell;
 
 fn main() {
-    let mut shell = Shell::default();
+    let builtins = Builtin::map();
+    let mut shell = Shell::new(&builtins);
     shell.evaluate_init_file();
 
     if "1" == shell.variables.get_var_or_empty("HISTORY_FILE_ENABLED") {
diff --git a/src/shell/flow.rs b/src/shell/flow.rs
index 10e50327..80a1abf5 100644
--- a/src/shell/flow.rs
+++ b/src/shell/flow.rs
@@ -18,7 +18,7 @@ pub trait FlowLogic {
     fn execute_statements(&mut self, statements: Vec<Statement>) -> bool;
 }
 
-impl FlowLogic for Shell {
+impl<'a> FlowLogic for Shell<'a> {
     fn on_command(&mut self, command_string: &str) {
         let mut iterator = StatementSplitter::new(command_string).map(parse);
 
diff --git a/src/shell/history.rs b/src/shell/history.rs
index 25e322df..b2a41c74 100644
--- a/src/shell/history.rs
+++ b/src/shell/history.rs
@@ -20,7 +20,7 @@ pub trait ShellHistory {
     fn set_context_history_from_vars(&mut self);
 }
 
-impl ShellHistory for Shell {
+impl<'a> ShellHistory for Shell<'a> {
     fn print_history(&self, _arguments: &[String]) -> i32 {
         let mut buffer = Vec::with_capacity(8*1024);
         for command in &self.context.history.buffers {
diff --git a/src/shell/mod.rs b/src/shell/mod.rs
index ce9e6ba7..9b76840b 100644
--- a/src/shell/mod.rs
+++ b/src/shell/mod.rs
@@ -30,7 +30,8 @@ use parser::peg::{parse, Pipeline};
 
 /// This struct will contain all of the data structures related to this
 /// instance of the shell.
-pub struct Shell {
+pub struct Shell<'a> {
+    pub builtins: &'a HashMap<&'static str, Builtin>,
     pub context: Context,
     pub variables: Variables,
     flow_control: FlowControl,
@@ -39,10 +40,11 @@ pub struct Shell {
     pub previous_status: i32,
 }
 
-impl Default for Shell {
+impl<'a> Shell<'a> {
     /// Panics if DirectoryStack construction fails
-    fn default() -> Shell {
+    pub fn new(builtins: &'a HashMap<&'static str, Builtin>) -> Shell<'a> {
         Shell {
+            builtins: builtins,
             context: Context::new(),
             variables: Variables::default(),
             flow_control: FlowControl::default(),
@@ -51,13 +53,11 @@ impl Default for Shell {
             previous_status: 0,
         }
     }
-}
-
-impl Shell {
     fn readln(&mut self) -> Option<String> {
         let prompt = self.prompt();
         let funcs = &self.functions;
         let vars = &self.variables;
+        let builtins = self.builtins;
 
         // Collects the current list of values from history for completion.
         let history = &self.context.history.buffers.iter()
@@ -108,9 +108,9 @@ impl Shell {
 
                     // Creates a list of definitions from the shell environment that will be used
                     // in the creation of a custom completer.
-                    let words = Builtin::map().into_iter()
+                    let words = builtins.iter()
                         // Add built-in commands to the completer's definitions.
-                        .map(|(s, _)| String::from(s))
+                        .map(|(&s, _)| String::from(s))
                         // Add the history list to the completer's definitions.
                         .chain(history.iter().cloned())
                         // Add the aliases to the completer's definitions.
@@ -283,6 +283,7 @@ impl Shell {
 
         let mut exit_status = None;
         let mut branched = false;
+        let builtins = self.builtins;
 
         if !noalias {
             if let Some(mut alias) = self.variables.aliases.get(pipeline.jobs[0].command.as_str()).cloned() {
@@ -311,7 +312,7 @@ impl Shell {
 
         if !branched {
             // Branch if -> input == shell command i.e. echo
-            exit_status = if let Some(command) = Builtin::map().get(pipeline.jobs[0].command.as_str()) {
+            exit_status = if let Some(command) = builtins.get(pipeline.jobs[0].command.as_str()) {
                 // Run the 'main' of the command and set exit_status
                 Some((*command.main)(pipeline.jobs[0].args.as_slice(), self))
             // Branch else if -> input == shell function and set the exit_status
-- 
GitLab