diff --git a/Cargo.lock b/Cargo.lock
index 2de48ccb53a9be13a368bf0ffe910643c776b988..d52e93c7c2086a5c82a09da06679f07504ba1c03 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -41,7 +41,7 @@ name = "backtrace-sys"
 version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -68,7 +68,7 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -104,7 +104,7 @@ version = "2.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
  "ord_subset 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -176,7 +176,7 @@ dependencies = [
  "liner 0.4.5 (git+https://gitlab.redox-os.org/redox-os/liner)",
  "rand 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallstring 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)",
  "smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -188,6 +188,7 @@ name = "ion_braces"
 version = "0.1.0"
 dependencies = [
  "permutate 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)",
  "smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -198,7 +199,7 @@ dependencies = [
  "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "calculate 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallstring 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)",
  "smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -213,7 +214,7 @@ dependencies = [
 name = "ion_ranges"
 version = "0.1.0"
 dependencies = [
- "smallstring 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)",
 ]
 
 [[package]]
@@ -246,7 +247,7 @@ name = "libloading"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -349,17 +350,9 @@ version = "1.0.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
-name = "smallstring"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "smallvec"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+name = "small"
+version = "0.1.0"
+source = "git+https://gitlab.redox-os.org/redox-os/small#9ecee66b5ce315236afb7062b36b608cb4e3dca2"
 
 [[package]]
 name = "smallvec"
@@ -514,7 +507,7 @@ source = "git+https://github.com/whitequark/rust-xdg#090afef2509d746e48d6bfa9b2e
 "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
 "checksum bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "882585cd7ec84e902472df34a5e01891202db3bf62614e1f0afe459c1afcf744"
 "checksum calculate 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dfe3fe310e5858ba47beb9443acec7fb39b90ea5677d35636306fe7b495a547c"
-"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d"
+"checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275"
 "checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e"
 "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
 "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
@@ -543,8 +536,7 @@ source = "git+https://github.com/whitequark/rust-xdg#090afef2509d746e48d6bfa9b2e
 "checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
 "checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920"
-"checksum smallstring 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30950abdb5b38f56a0e181ae56ed64a539b64fa77ea6325147203dc7faeb087f"
-"checksum smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f8266519bc1d17d0b5b16f6c21295625d562841c708f6376f49028a43e9c11e"
+"checksum small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)" = "<none>"
 "checksum smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "312a7df010092e73d6bbaf141957e868d4f30efd2bfd9bb1028ad91abec58514"
 "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
diff --git a/Cargo.toml b/Cargo.toml
index 953cf887750a295e22bc6c2c1f79ad14a52baf35..a483624b294dccca2dec56aff02efa0e37511b38 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -42,7 +42,7 @@ lazy_static = "1.0"
 liner = { git = "https://gitlab.redox-os.org/redox-os/liner" }
 rand = "0.5"
 regex = "1.0"
-smallstring = "0.1"
+small = { git = "https://gitlab.redox-os.org/redox-os/small", features = ["std"] }
 smallvec = "0.6"
 unicode-segmentation = "1.2"
 xdg = { git = "https://github.com/whitequark/rust-xdg" }
diff --git a/members/braces/Cargo.toml b/members/braces/Cargo.toml
index 97800764897ca59ffcb64c9ff173f83d67624533..9a345265af703d470279f035e30c5fbc52410c2a 100644
--- a/members/braces/Cargo.toml
+++ b/members/braces/Cargo.toml
@@ -6,3 +6,4 @@ authors = ["Michael Murphy <mmstickman@gmail.com>"]
 [dependencies]
 permutate = "0.3"
 smallvec = "0.6"
+small = { git = "https://gitlab.redox-os.org/redox-os/small", features = ["std"] }
diff --git a/members/braces/src/lib.rs b/members/braces/src/lib.rs
index a3029aba25c96b331b0dd8e3efc79ad1346dc002..b9ef13b4c417eb848ff8edee8103cdd7d038a8db 100644
--- a/members/braces/src/lib.rs
+++ b/members/braces/src/lib.rs
@@ -1,5 +1,6 @@
 extern crate permutate;
 extern crate smallvec;
+extern crate small;
 
 use permutate::Permutator;
 use smallvec::SmallVec;
@@ -7,14 +8,14 @@ use smallvec::SmallVec;
 #[derive(Debug)]
 /// A token primitive for the `expand_braces` function.
 pub enum BraceToken {
-    Normal(String),
+    Normal(small::String),
     Expander,
 }
 
 pub fn expand<'a>(
     tokens: &'a [BraceToken],
     expanders: &'a [&'a [&'a str]],
-) -> Box<Iterator<Item = String> + 'a> {
+) -> Box<Iterator<Item = small::String> + 'a> {
     if expanders.len() > 1 {
         let multiple_brace_expand = MultipleBraceExpand::new(tokens, expanders);
         Box::new(multiple_brace_expand)
@@ -70,7 +71,7 @@ impl<'a> MultipleBraceExpand<'a> {
 }
 
 impl<'a> Iterator for MultipleBraceExpand<'a> {
-    type Item = String;
+    type Item = small::String;
 
     fn next(&mut self) -> Option<Self::Item> {
         if self.permutator.next_with_buffer(&mut self.buffer) {
@@ -88,7 +89,7 @@ impl<'a> Iterator for MultipleBraceExpand<'a> {
                     }
                 },
             );
-            Some(unsafe { String::from_utf8_unchecked(small_vec.to_vec()) })
+            Some(unsafe { small::String::from_utf8_unchecked(small_vec.to_vec()) })
         } else {
             None
         }
@@ -108,7 +109,7 @@ impl<'a, 'b, I> Iterator for SingleBraceExpand<'a, 'b, I>
 where
     I: Iterator<Item = &'a str>,
 {
-    type Item = String;
+    type Item = small::String;
 
     fn next(&mut self) -> Option<Self::Item> {
         match self.loop_count {
@@ -127,7 +128,7 @@ where
                     },
                 );
                 self.loop_count = 1;
-                Some(unsafe { String::from_utf8_unchecked(small_vec.to_vec()) })
+                Some(unsafe { small::String::from_utf8_unchecked(small_vec.to_vec()) })
             }
             _ => {
                 if let Some(element) = self.elements.next() {
@@ -144,7 +145,7 @@ where
                             }
                         },
                     );
-                    Some(unsafe { String::from_utf8_unchecked(small_vec.to_vec()) })
+                    Some(unsafe { small::String::from_utf8_unchecked(small_vec.to_vec()) })
                 } else {
                     None
                 }
@@ -161,25 +162,25 @@ mod tests {
     fn test_multiple_brace_expand() {
         let expanders: &[&[&str]] = &[&["1", "2"][..], &["3", "4"][..], &["5", "6"][..]];
         let tokens: &[BraceToken] = &[
-            BraceToken::Normal("AB".to_owned()),
+            BraceToken::Normal("AB".into()),
             BraceToken::Expander,
-            BraceToken::Normal("CD".to_owned()),
+            BraceToken::Normal("CD".into()),
             BraceToken::Expander,
-            BraceToken::Normal("EF".to_owned()),
+            BraceToken::Normal("EF".into()),
             BraceToken::Expander,
-            BraceToken::Normal("GH".to_owned()),
+            BraceToken::Normal("GH".into()),
         ];
         assert_eq!(
-            MultipleBraceExpand::new(tokens, expanders).collect::<Vec<String>>(),
+            MultipleBraceExpand::new(tokens, expanders).collect::<Vec<small::String>>(),
             vec![
-                "AB1CD3EF5GH".to_owned(),
-                "AB1CD3EF6GH".to_owned(),
-                "AB1CD4EF5GH".to_owned(),
-                "AB1CD4EF6GH".to_owned(),
-                "AB2CD3EF5GH".to_owned(),
-                "AB2CD3EF6GH".to_owned(),
-                "AB2CD4EF5GH".to_owned(),
-                "AB2CD4EF6GH".to_owned(),
+                small::String::from("AB1CD3EF5GH"),
+                small::String::from("AB1CD3EF6GH"),
+                small::String::from("AB1CD4EF5GH"),
+                small::String::from("AB1CD4EF6GH"),
+                small::String::from("AB2CD3EF5GH"),
+                small::String::from("AB2CD3EF6GH"),
+                small::String::from("AB2CD4EF5GH"),
+                small::String::from("AB2CD4EF6GH"),
             ]
         );
     }
@@ -187,14 +188,18 @@ mod tests {
     #[test]
     fn test_single_brace_expand() {
         let elements = &["one", "two", "three"];
-        let tokens: &[BraceToken] = &[BraceToken::Normal("A=".to_owned()), BraceToken::Expander];
+        let tokens: &[BraceToken] = &[BraceToken::Normal("A=".into()), BraceToken::Expander];
         assert_eq!(
             SingleBraceExpand {
                 elements: elements.iter().map(|element| *element),
                 tokens,
                 loop_count: 0,
-            }.collect::<Vec<String>>(),
-            vec!["A=one".to_owned(), "A=two".to_owned(), "A=three".to_owned()]
+            }.collect::<Vec<small::String>>(),
+            vec![
+                small::String::from("A=one"),
+                small::String::from("A=two"),
+                small::String::from("A=three"),
+            ]
         );
     }
 }
diff --git a/members/builtins/Cargo.toml b/members/builtins/Cargo.toml
index 25a796d14a2994d3544804f6cd8c25c345806b2c..a1e15a27b4482f0fdbe565ed7572ea45ad4d1759 100644
--- a/members/builtins/Cargo.toml
+++ b/members/builtins/Cargo.toml
@@ -8,5 +8,5 @@ publish = false
 bitflags = "1.0"
 calculate = "0.5"
 rand = "0.5"
-smallstring = "0.1"
+small = { git = "https://gitlab.redox-os.org/redox-os/small", features = ["std"] }
 smallvec = "0.6"
diff --git a/members/builtins/src/calc.rs b/members/builtins/src/calc.rs
index 074e23bc281d4ef86b0fda91043c65f75d680727..537e767ad3df97075a769ae60c823443b145010e 100644
--- a/members/builtins/src/calc.rs
+++ b/members/builtins/src/calc.rs
@@ -1,5 +1,6 @@
 use calculate::{eval, eval_polish, CalcError, Value};
 use std::io::{self, Write};
+use small;
 
 const REPL_GUIDE: &'static str = r#"ion-calc
 Type in expressions to have them evaluated.
@@ -49,7 +50,7 @@ fn calc_or_polish_calc(args: &str) -> Result<Value, CalcError> {
     }
 }
 
-pub fn calc(args: &[String]) -> Result<(), String> {
+pub fn calc(args: &[small::String]) -> Result<(), String> {
     let stdout = io::stdout();
     let mut stdout = stdout.lock();
     match args.first() {
diff --git a/members/builtins/src/conditionals.rs b/members/builtins/src/conditionals.rs
index 677342c0d46897754c8e5ecf34c882b89a9df1ef..0dc83bad26938a492e9275848f060e9e744fb232 100644
--- a/members/builtins/src/conditionals.rs
+++ b/members/builtins/src/conditionals.rs
@@ -1,17 +1,19 @@
+use small;
+
 macro_rules! string_function {
     ($method:tt) => {
-        pub fn $method(args: &[String]) -> i32 {
+        pub fn $method(args: &[small::String]) -> i32 {
             match args.len() {
                 0...2 => {
                     eprintln!("ion: {}: two arguments must be supplied", args[0]);
                     return 2;
                 }
-                3 => if args[1].$method(&args[2]) {
+                3 => if args[1].$method(args[2].as_str()) {
                     0
                 } else {
                     1
                 },
-                _ => if args[2..].iter().any(|arg| args[1].$method(arg)) {
+                _ => if args[2..].iter().any(|arg| args[1].$method(arg.as_str())) {
                     0
                 } else {
                     1
diff --git a/members/builtins/src/echo.rs b/members/builtins/src/echo.rs
index 2aa8b5c26c32609fee9f98d55dadba93ae217029..0911a3e98e186f2ec5c1f3daa457e1d6fcf065cf 100644
--- a/members/builtins/src/echo.rs
+++ b/members/builtins/src/echo.rs
@@ -1,3 +1,4 @@
+use small;
 use smallvec::SmallVec;
 use std::io::{self, BufWriter, Write};
 
@@ -9,7 +10,7 @@ bitflags! {
     }
 }
 
-pub fn echo(args: &[String]) -> Result<(), io::Error> {
+pub fn echo(args: &[small::String]) -> Result<(), io::Error> {
     let mut flags = Flags::empty();
     let mut data: SmallVec<[&str; 16]> = SmallVec::with_capacity(16);
 
diff --git a/members/builtins/src/lib.rs b/members/builtins/src/lib.rs
index a2cce04c833c78d00bea496e73920b257050ff85..95fac1bd7916526d2294c92b1d0aa3ef892290ac 100644
--- a/members/builtins/src/lib.rs
+++ b/members/builtins/src/lib.rs
@@ -2,7 +2,7 @@
 extern crate bitflags;
 extern crate calc as calculate;
 extern crate rand;
-extern crate smallstring;
+extern crate small;
 extern crate smallvec;
 
 pub mod calc;
diff --git a/members/builtins/src/random.rs b/members/builtins/src/random.rs
index fade40ba64eadd59e7a31d5a9e6d6c6d164d3a54..63219b2583e302bcf09e83ea118f36bd40615eed 100644
--- a/members/builtins/src/random.rs
+++ b/members/builtins/src/random.rs
@@ -1,14 +1,15 @@
 use rand::{thread_rng, Rng};
 use std::io::{self, Write};
+use small;
 
 #[allow(unused_must_use)]
-fn rand_list(args: &[String]) -> Result<(), String> {
+fn rand_list(args: &[small::String]) -> Result<(), small::String> {
     let stdout = io::stdout();
     let mut stdout = stdout.lock();
     let mut output = Vec::new();
     let arg1 = match args[0].parse::<usize>() {
         Ok(v) => v,
-        Err(_) => return Err(String::from("Invalid argument for random")),
+        Err(_) => return Err("Invalid argument for random".into()),
     };
     while output.len() < arg1 {
         let rand_num = thread_rng().gen_range(1, args.len());
@@ -21,8 +22,9 @@ fn rand_list(args: &[String]) -> Result<(), String> {
     writeln!(stdout);
     Ok(())
 }
+
 #[allow(unused_must_use)]
-pub fn random(args: &[String]) -> Result<(), String> {
+pub fn random(args: &[small::String]) -> Result<(), small::String> {
     let stdout = io::stdout();
     let mut stdout = stdout.lock();
     match args.len() {
@@ -39,14 +41,14 @@ pub fn random(args: &[String]) -> Result<(), String> {
         2 => {
             let arg1 = match args[0].parse::<u64>() {
                 Ok(v) => v,
-                Err(_) => return Err(String::from("Invalid argument for random")),
+                Err(_) => return Err("Invalid argument for random".into()),
             };
             let arg2 = match args[1].parse::<u64>() {
                 Ok(v) => v,
-                Err(_) => return Err(String::from("Invalid argument for random")),
+                Err(_) => return Err("Invalid argument for random".into()),
             };
             if arg2 <= arg1 {
-                return Err(String::from("END must be greater than START"));
+                return Err("END must be greater than START".into());
             }
             let rand_num = thread_rng().gen_range(arg1, arg2);
             writeln!(stdout, "{}", rand_num);
@@ -54,7 +56,7 @@ pub fn random(args: &[String]) -> Result<(), String> {
         3 => {
             let arg1 = match args[0].parse::<u64>() {
                 Ok(v) => v,
-                Err(_) => return Err(String::from("Invalid argument for random")),
+                Err(_) => return Err("Invalid argument for random".into()),
             };
             let arg2 = match args[1].parse::<u64>() {
                 Ok(v) => v,
@@ -63,7 +65,7 @@ pub fn random(args: &[String]) -> Result<(), String> {
             match args[2].parse::<u64>() {
                 Ok(v) => {
                     if arg2 <= arg1 {
-                        return Err(String::from("END must be greater than START"));
+                        return Err("END must be greater than START".into());
                     }
                     let mut end = v / arg2 + 1;
                     if arg1 / arg2 >= end {
diff --git a/members/builtins/src/test.rs b/members/builtins/src/test.rs
index 63c9a0d29c7b83f7cfb727241ed4e2181b445c5d..8b931f475fdbe85b7b16f6186cb2baf0a2b94934 100644
--- a/members/builtins/src/test.rs
+++ b/members/builtins/src/test.rs
@@ -1,4 +1,4 @@
-use smallstring::SmallString;
+use small;
 use std::{
     fs,
     os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt},
@@ -118,12 +118,12 @@ const QUICK_GUIDE: &'static str =
 r#"Usage: test [EXPRESSION]
 Try 'test --help' for more information."#;
 
-pub fn test(args: &[String]) -> Result<bool, String> {
+pub fn test(args: &[small::String]) -> Result<bool, small::String> {
     let arguments = &args[1..];
     evaluate_arguments(arguments)
 }
 
-fn evaluate_arguments(arguments: &[String]) -> Result<bool, String> {
+fn evaluate_arguments(arguments: &[small::String]) -> Result<bool, small::String> {
     match arguments.first() {
         Some(ref s) if s.starts_with('-') && s[1..].starts_with(char::is_alphabetic) => {
             // Access the second character in the flag string: this will be type of the
@@ -151,7 +151,7 @@ fn evaluate_arguments(arguments: &[String]) -> Result<bool, String> {
                     // If there is no right hand argument, a condition was expected
                     let right_arg = arguments
                         .get(2)
-                        .ok_or_else(|| SmallString::from("parse error: condition expected"))?;
+                        .ok_or_else(|| small::String::from("parse error: condition expected"))?;
                     evaluate_expression(arg, operator, right_arg)
                 })
         }
@@ -162,7 +162,7 @@ fn evaluate_arguments(arguments: &[String]) -> Result<bool, String> {
     }
 }
 
-fn evaluate_expression(first: &str, operator: &str, second: &str) -> Result<bool, String> {
+fn evaluate_expression(first: &str, operator: &str, second: &str) -> Result<bool, small::String> {
     match operator {
         "=" | "==" => Ok(first == second),
         "!=" => Ok(first != second),
@@ -178,7 +178,7 @@ fn evaluate_expression(first: &str, operator: &str, second: &str) -> Result<bool
                 "-le" => Ok(left <= right),
                 "-lt" => Ok(left < right),
                 "-ne" => Ok(left != right),
-                _ => Err(format!("test: unknown condition: {:?}", operator)),
+                _ => Err(format!("test: unknown condition: {:?}", operator).into()),
             }
         }
     }
@@ -223,13 +223,13 @@ fn get_modified_file_time(filename: &str) -> Option<SystemTime> {
 }
 
 /// Attempt to parse a &str as a usize.
-fn parse_integers(left: &str, right: &str) -> Result<(Option<isize>, Option<isize>), String> {
-    let parse_integer = |input: &str| -> Result<Option<isize>, String> {
+fn parse_integers(left: &str, right: &str) -> Result<(Option<isize>, Option<isize>), small::String> {
+    let parse_integer = |input: &str| -> Result<Option<isize>, small::String> {
         match input
             .parse::<isize>()
             .map_err(|_| format!("test: integer expression expected: {:?}", input))
         {
-            Err(why) => Err(why),
+            Err(why) => Err(why.into()),
             Ok(res) => Ok(Some(res)),
         }
     };
@@ -383,20 +383,20 @@ fn test_strings() {
 
 #[test]
 fn test_empty_str() {
-    let eval = |args: Vec<String>| evaluate_arguments(&args);
-    assert_eq!(eval(vec!["".to_owned()]), Ok(false));
+    let eval = |args: Vec<small::String>| evaluate_arguments(&args);
+    assert_eq!(eval(vec!["".into()]), Ok(false));
     assert_eq!(
-        eval(vec!["c".to_owned(), "=".to_owned(), "".to_owned()]),
+        eval(vec!["c".into(), "=".into(), "".into()]),
         Ok(false)
     );
 }
 
 #[test]
 fn test_integers_arguments() {
-    fn vec_string(args: &[&str]) -> Vec<String> {
+    fn vec_string(args: &[&str]) -> Vec<small::String> {
         args.iter()
-            .map(|s| (*s).to_owned())
-            .collect::<Vec<String>>()
+            .map(|s| (*s).into())
+            .collect()
     }
     // Equal To
     assert_eq!(
diff --git a/members/ranges/Cargo.toml b/members/ranges/Cargo.toml
index bdedec443ce673becbbf0078fb2e312d6a15154e..7a625af75cd70d537fec241c03a0fc5b0015243a 100644
--- a/members/ranges/Cargo.toml
+++ b/members/ranges/Cargo.toml
@@ -4,4 +4,4 @@ version = "0.1.0"
 authors = ["Michael Murphy <mmstickman@gmail.com>"]
 
 [dependencies]
-smallstring = "0.1"
+small = { git = "https://gitlab.redox-os.org/redox-os/small", features = ["std"] }
diff --git a/members/ranges/src/lib.rs b/members/ranges/src/lib.rs
index c2b5997ab7903f9ab10e5d91d4a7b4dc5574839b..730a0dc341ec74ceb2fe2884477762aa1f7d7e61 100644
--- a/members/ranges/src/lib.rs
+++ b/members/ranges/src/lib.rs
@@ -1,4 +1,4 @@
-extern crate smallstring;
+extern crate small;
 
 mod index;
 mod parse;
@@ -65,150 +65,150 @@ mod tests {
             panic!("parse_range() failed");
         }
 
-        let actual: Vec<String> = parse_range("-3...3").unwrap().collect();
-        let expected: Vec<String> = vec![
-            "-3".to_owned(),
-            "-2".to_owned(),
-            "-1".to_owned(),
-            "0".to_owned(),
-            "1".to_owned(),
-            "2".to_owned(),
-            "3".to_owned(),
+        let actual: Vec<small::String> = parse_range("-3...3").unwrap().collect();
+        let expected: Vec<small::String> = vec![
+            "-3".into(),
+            "-2".into(),
+            "-1".into(),
+            "0".into(),
+            "1".into(),
+            "2".into(),
+            "3".into(),
         ];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("07...12").unwrap().collect();
-        let expected: Vec<String> = vec![
-            "07".to_owned(),
-            "08".to_owned(),
-            "09".to_owned(),
-            "10".to_owned(),
-            "11".to_owned(),
-            "12".to_owned(),
+        let actual: Vec<small::String> = parse_range("07...12").unwrap().collect();
+        let expected: Vec<small::String> = vec![
+            "07".into(),
+            "08".into(),
+            "09".into(),
+            "10".into(),
+            "11".into(),
+            "12".into(),
         ];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("-3...10").unwrap().collect();
-        let expected: Vec<String> = vec![
-            "-3".to_owned(),
-            "-2".to_owned(),
-            "-1".to_owned(),
-            "0".to_owned(),
-            "1".to_owned(),
-            "2".to_owned(),
-            "3".to_owned(),
-            "4".to_owned(),
-            "5".to_owned(),
-            "6".to_owned(),
-            "7".to_owned(),
-            "8".to_owned(),
-            "9".to_owned(),
-            "10".to_owned(),
+        let actual: Vec<small::String> = parse_range("-3...10").unwrap().collect();
+        let expected: Vec<small::String> = vec![
+            "-3".into(),
+            "-2".into(),
+            "-1".into(),
+            "0".into(),
+            "1".into(),
+            "2".into(),
+            "3".into(),
+            "4".into(),
+            "5".into(),
+            "6".into(),
+            "7".into(),
+            "8".into(),
+            "9".into(),
+            "10".into(),
         ];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("3...-3").unwrap().collect();
-        let expected: Vec<String> = vec![
-            "3".to_owned(),
-            "2".to_owned(),
-            "1".to_owned(),
-            "0".to_owned(),
-            "-1".to_owned(),
-            "-2".to_owned(),
-            "-3".to_owned(),
+        let actual: Vec<small::String> = parse_range("3...-3").unwrap().collect();
+        let expected: Vec<small::String> = vec![
+            "3".into(),
+            "2".into(),
+            "1".into(),
+            "0".into(),
+            "-1".into(),
+            "-2".into(),
+            "-3".into(),
         ];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("03...-3").unwrap().collect();
-        let expected: Vec<String> = vec![
-            "03".to_owned(),
-            "02".to_owned(),
-            "01".to_owned(),
-            "00".to_owned(),
-            "-1".to_owned(),
-            "-2".to_owned(),
-            "-3".to_owned(),
+        let actual: Vec<small::String> = parse_range("03...-3").unwrap().collect();
+        let expected: Vec<small::String> = vec![
+            "03".into(),
+            "02".into(),
+            "01".into(),
+            "00".into(),
+            "-1".into(),
+            "-2".into(),
+            "-3".into(),
         ];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("3...-03").unwrap().collect();
-        let expected: Vec<String> = vec![
-            "003".to_owned(),
-            "002".to_owned(),
-            "001".to_owned(),
-            "000".to_owned(),
-            "-01".to_owned(),
-            "-02".to_owned(),
-            "-03".to_owned(),
+        let actual: Vec<small::String> = parse_range("3...-03").unwrap().collect();
+        let expected: Vec<small::String> = vec![
+            "003".into(),
+            "002".into(),
+            "001".into(),
+            "000".into(),
+            "-01".into(),
+            "-02".into(),
+            "-03".into(),
         ];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("a...c").unwrap().collect();
-        let expected: Vec<String> = vec!["a".to_owned(), "b".to_owned(), "c".to_owned()];
+        let actual: Vec<small::String> = parse_range("a...c").unwrap().collect();
+        let expected: Vec<small::String> = vec!["a".into(), "b".into(), "c".into()];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("c...a").unwrap().collect();
-        let expected: Vec<String> = vec!["c".to_owned(), "b".to_owned(), "a".to_owned()];
+        let actual: Vec<small::String> = parse_range("c...a").unwrap().collect();
+        let expected: Vec<small::String> = vec!["c".into(), "b".into(), "a".into()];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("A...C").unwrap().collect();
-        let expected: Vec<String> = vec!["A".to_owned(), "B".to_owned(), "C".to_owned()];
+        let actual: Vec<small::String> = parse_range("A...C").unwrap().collect();
+        let expected: Vec<small::String> = vec!["A".into(), "B".into(), "C".into()];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("C...A").unwrap().collect();
-        let expected: Vec<String> = vec!["C".to_owned(), "B".to_owned(), "A".to_owned()];
+        let actual: Vec<small::String> = parse_range("C...A").unwrap().collect();
+        let expected: Vec<small::String> = vec!["C".into(), "B".into(), "A".into()];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("C..A").unwrap().collect();
-        let expected: Vec<String> = vec!["C".to_owned(), "B".to_owned()];
+        let actual: Vec<small::String> = parse_range("C..A").unwrap().collect();
+        let expected: Vec<small::String> = vec!["C".into(), "B".into()];
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("c..a").unwrap().collect();
-        let expected: Vec<String> = vec!["c".to_owned(), "b".to_owned()];
+        let actual: Vec<small::String> = parse_range("c..a").unwrap().collect();
+        let expected: Vec<small::String> = vec!["c".into(), "b".into()];
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("-3..4").unwrap().collect();
-        let expected: Vec<String> = vec![
-            "-3".to_owned(),
-            "-2".to_owned(),
-            "-1".to_owned(),
-            "0".to_owned(),
-            "1".to_owned(),
-            "2".to_owned(),
-            "3".to_owned(),
+        let actual: Vec<small::String> = parse_range("-3..4").unwrap().collect();
+        let expected: Vec<small::String> = vec![
+            "-3".into(),
+            "-2".into(),
+            "-1".into(),
+            "0".into(),
+            "1".into(),
+            "2".into(),
+            "3".into(),
         ];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("3..-4").unwrap().collect();
-        let expected: Vec<String> = vec![
-            "3".to_owned(),
-            "2".to_owned(),
-            "1".to_owned(),
-            "0".to_owned(),
-            "-1".to_owned(),
-            "-2".to_owned(),
-            "-3".to_owned(),
+        let actual: Vec<small::String> = parse_range("3..-4").unwrap().collect();
+        let expected: Vec<small::String> = vec![
+            "3".into(),
+            "2".into(),
+            "1".into(),
+            "0".into(),
+            "-1".into(),
+            "-2".into(),
+            "-3".into(),
         ];
 
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("-3...0").unwrap().collect();
-        let expected: Vec<String> = vec!["-3".into(), "-2".into(), "-1".into(), "0".into()];
+        let actual: Vec<small::String> = parse_range("-3...0").unwrap().collect();
+        let expected: Vec<small::String> = vec!["-3".into(), "-2".into(), "-1".into(), "0".into()];
         assert_eq!(actual, expected);
 
-        let actual: Vec<String> = parse_range("-3..0").unwrap().collect();
-        let expected: Vec<String> = vec!["-3".into(), "-2".into(), "-1".into()];
+        let actual: Vec<small::String> = parse_range("-3..0").unwrap().collect();
+        let expected: Vec<small::String> = vec!["-3".into(), "-2".into(), "-1".into()];
         assert_eq!(actual, expected);
     }
 }
diff --git a/members/ranges/src/parse.rs b/members/ranges/src/parse.rs
index de7312a28398ced2a21b5362828a2f8cc4b701d1..5d36191001ffb6b6b0229e9c0dc4f131f9dc7774 100644
--- a/members/ranges/src/parse.rs
+++ b/members/ranges/src/parse.rs
@@ -1,4 +1,5 @@
 use super::{Index, Range};
+use small;
 use std::cmp::Ordering;
 
 fn stepped_range_numeric<'a>(
@@ -6,7 +7,7 @@ fn stepped_range_numeric<'a>(
     end: isize,
     step: isize,
     nb_digits: usize,
-) -> Option<Box<Iterator<Item = String> + 'a>> {
+) -> Option<Box<Iterator<Item = small::String> + 'a>> {
     if step == 0 {
         None
     } else if start < end && step < 0 {
@@ -24,7 +25,7 @@ fn stepped_range_numeric<'a>(
             if end.cmp(index) == ordering {
                 let index_holder = *index;
                 *index += step; // This step adds
-                Some(format!("{:0width$}", index_holder, width = nb_digits))
+                Some(format!("{:0width$}", index_holder, width = nb_digits).into())
             } else {
                 None
             }
@@ -38,7 +39,7 @@ fn stepped_range_chars<'a>(
     start: u8,
     end: u8,
     step: u8,
-) -> Option<Box<Iterator<Item = String> + 'a>> {
+) -> Option<Box<Iterator<Item = small::String> + 'a>> {
     if step == 0 {
         None
     } else {
@@ -56,7 +57,7 @@ fn stepped_range_chars<'a>(
                     Ordering::Less => index.wrapping_sub(step),
                     _ => unreachable!(),
                 };
-                Some((index_holder as char).to_string())
+                Some((index_holder as char).to_string().into())
             } else {
                 None
             }
@@ -72,7 +73,7 @@ fn numeric_range<'a>(
     step: isize,
     inclusive: bool,
     nb_digits: usize,
-) -> Option<Box<Iterator<Item = String> + 'a>> {
+) -> Option<Box<Iterator<Item = small::String> + 'a>> {
     if start < end {
         if inclusive {
             end += 1;
@@ -84,7 +85,7 @@ fn numeric_range<'a>(
         }
         stepped_range_numeric(start, end, step, nb_digits)
     } else {
-        Some(Box::new(Some(start.to_string()).into_iter()))
+        Some(Box::new(Some(start.to_string().into()).into_iter()))
     }
 }
 
@@ -97,7 +98,7 @@ fn char_range<'a>(
     mut end: u8,
     step: isize,
     inclusive: bool,
-) -> Option<Box<Iterator<Item = String> + 'a>> {
+) -> Option<Box<Iterator<Item = small::String> + 'a>> {
     if !byte_is_valid_range(start) || !byte_is_valid_range(end) {
         return None;
     }
@@ -121,7 +122,7 @@ fn char_range<'a>(
         }
         stepped_range_chars(start, end, char_step)
     } else {
-        Some(Box::new(Some((start as char).to_string()).into_iter()))
+        Some(Box::new(Some((start as char).to_string().into()).into_iter()))
     }
 }
 
@@ -163,7 +164,7 @@ fn strings_to_isizes(a: &str, b: &str) -> Option<(isize, isize, usize)> {
 //      Inclusive nonstepped: {start...end}
 //      Exclusive stepped: {start..step..end}
 //      Inclusive stepped: {start..step...end}
-pub fn parse_range<'a>(input: &str) -> Option<Box<Iterator<Item = String> + 'a>> {
+pub fn parse_range<'a>(input: &str) -> Option<Box<Iterator<Item = small::String> + 'a>> {
     let mut read = 0;
     let mut bytes_iterator = input.bytes();
     while let Some(byte) = bytes_iterator.next() {
diff --git a/members/ranges/src/select.rs b/members/ranges/src/select.rs
index 083f1e7898b1382d39f9e7008ee0d0f834339e13..d5b98055066e4e7cb255bed19f434ab788ab5f9c 100644
--- a/members/ranges/src/select.rs
+++ b/members/ranges/src/select.rs
@@ -1,5 +1,5 @@
 use super::{parse_index_range, Index, Range};
-use smallstring::SmallString;
+use small;
 use std::{
     iter::{empty, FromIterator},
     str::FromStr,
@@ -17,7 +17,7 @@ pub enum Select {
     /// Select a range of elements
     Range(Range),
     /// Select an element by mapped key
-    Key(SmallString),
+    Key(small::String),
 }
 
 pub trait SelectWithSize {
diff --git a/src/lib/builtins/command_info.rs b/src/lib/builtins/command_info.rs
index 9892bff392cfbf096dade907a3566a27e3a5614f..b6a124241fa00002871f32dce83049e011108268 100644
--- a/src/lib/builtins/command_info.rs
+++ b/src/lib/builtins/command_info.rs
@@ -1,11 +1,12 @@
 use builtins::man_pages::*;
 use shell::{status::*, flow_control::Function, Shell};
+use small;
 use sys;
 use types;
 
 use std::{borrow::Cow, env, path::Path};
 
-pub(crate) fn which(args: &[String], shell: &mut Shell) -> Result<i32, ()> {
+pub(crate) fn which(args: &[small::String], shell: &mut Shell) -> Result<i32, ()> {
     if check_help(args, MAN_WHICH) {
         return Ok(SUCCESS);
     }
@@ -33,7 +34,7 @@ pub(crate) fn which(args: &[String], shell: &mut Shell) -> Result<i32, ()> {
     Ok(result)
 }
 
-pub(crate) fn find_type(args: &[String], shell: &mut Shell) -> Result<i32, ()> {
+pub(crate) fn find_type(args: &[small::String], shell: &mut Shell) -> Result<i32, ()> {
     // Type does not accept help flags, aka "--help".
     if args.len() == 1 {
         eprintln!("type: Expected at least 1 args, got only 0");
diff --git a/src/lib/builtins/exec.rs b/src/lib/builtins/exec.rs
index eef34dfd75e54d60c061f45aa72512e4c5db2bcd..b91593e960a5c279c7f2bc051bdd9af3af58ccb5 100644
--- a/src/lib/builtins/exec.rs
+++ b/src/lib/builtins/exec.rs
@@ -1,10 +1,11 @@
 use builtins::man_pages::{check_help, MAN_EXEC};
+use small;
 use shell::Shell;
 use std::error::Error;
 use sys::execve;
 
 /// Executes the givent commmand.
-pub(crate) fn exec(shell: &mut Shell, args: &[String]) -> Result<(), String> {
+pub(crate) fn exec(shell: &mut Shell, args: &[small::String]) -> Result<(), small::String> {
     const CLEAR_ENV: u8 = 1;
 
     let mut flags = 0u8;
@@ -30,8 +31,8 @@ pub(crate) fn exec(shell: &mut Shell, args: &[String]) -> Result<(), String> {
             shell.prep_for_exit();
             Err(execve(argument, args, (flags & CLEAR_ENV) == 1)
                 .description()
-                .to_owned())
+                .into())
         }
-        None => Err("no command provided".to_owned()),
+        None => Err("no command provided".into()),
     }
 }
diff --git a/src/lib/builtins/exists.rs b/src/lib/builtins/exists.rs
index e555196d5f97e7067c800dc321047139c0cf8025..fcd166185f4087c5011d300161b1ce43281acdfb 100644
--- a/src/lib/builtins/exists.rs
+++ b/src/lib/builtins/exists.rs
@@ -1,5 +1,3 @@
-#[cfg(test)]
-use smallstring::SmallString;
 use std::{fs, os::unix::fs::PermissionsExt};
 
 #[cfg(test)]
@@ -11,14 +9,15 @@ use shell::{
     flow_control::Function,
     Shell,
 };
+use small;
 use types;
 
-pub(crate) fn exists(args: &[String], shell: &Shell) -> Result<bool, String> {
+pub(crate) fn exists(args: &[small::String], shell: &Shell) -> Result<bool, small::String> {
     let arguments = &args[1..];
     evaluate_arguments(arguments, shell)
 }
 
-fn evaluate_arguments(arguments: &[String], shell: &Shell) -> Result<bool, String> {
+fn evaluate_arguments(arguments: &[small::String], shell: &Shell) -> Result<bool, small::String> {
     match arguments.first() {
         Some(ref s) if s.starts_with("--") => {
             let (_, option) = s.split_at(2);
@@ -90,7 +89,7 @@ fn binary_is_in_path(binaryname: &str, shell: &Shell) -> bool {
     // TODO: Right now they use an entirely different logic which means that it
     // *might* be possible TODO: that `exists` reports a binary to be in the
     // path, while the shell cannot find it or TODO: vice-versa
-    if let Some(path) = shell.get::<types::Value>("PATH") {
+    if let Some(path) = shell.get::<types::Str>("PATH") {
         for dir in path.split(':') {
             let fname = format!("{}/{}", dir, binaryname);
             if let Ok(metadata) = fs::metadata(&fname) {
@@ -134,7 +133,7 @@ fn array_var_is_not_empty(arrayvar: &str, shell: &Shell) -> bool {
 
 /// Returns true if the variable is a string and the string is not empty
 fn string_var_is_not_empty(stringvar: &str, shell: &Shell) -> bool {
-    match shell.variables.get::<types::Value>(stringvar) {
+    match shell.variables.get::<types::Str>(stringvar) {
         Some(string) => !string.is_empty(),
         None => false,
     }
@@ -158,42 +157,42 @@ fn test_evaluate_arguments() {
     assert_eq!(evaluate_arguments(&[], &shell), Ok(false));
     // multiple arguments
     // ignores all but the first argument
-    assert_eq!(evaluate_arguments(&["foo".to_owned(), "bar".to_owned()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["foo".into(), "bar".into()], &shell), Ok(true));
 
     // check `exists STRING`
-    assert_eq!(evaluate_arguments(&["".to_owned()], &shell), Ok(false));
-    assert_eq!(evaluate_arguments(&["string".to_owned()], &shell), Ok(true));
-    assert_eq!(evaluate_arguments(&["string with space".to_owned()], &shell), Ok(true));
-    assert_eq!(evaluate_arguments(&["-startswithdash".to_owned()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["".into()], &shell), Ok(false));
+    assert_eq!(evaluate_arguments(&["string".into()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["string with space".into()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["-startswithdash".into()], &shell), Ok(true));
 
     // check `exists -a`
     // no argument means we treat it as a string
-    assert_eq!(evaluate_arguments(&["-a".to_owned()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["-a".into()], &shell), Ok(true));
     shell
         .variables
         .set("emptyarray", types::Array::new());
-    assert_eq!(evaluate_arguments(&["-a".to_owned(), "emptyarray".to_owned()], &shell), Ok(false));
+    assert_eq!(evaluate_arguments(&["-a".into(), "emptyarray".into()], &shell), Ok(false));
     let mut array = types::Array::new();
-    array.push("element".to_owned());
+    array.push("element".into());
     shell.variables.set("array", array);
-    assert_eq!(evaluate_arguments(&["-a".to_owned(), "array".to_owned()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["-a".into(), "array".into()], &shell), Ok(true));
     shell.variables.remove_variable("array");
-    assert_eq!(evaluate_arguments(&["-a".to_owned(), "array".to_owned()], &shell), Ok(false));
+    assert_eq!(evaluate_arguments(&["-a".into(), "array".into()], &shell), Ok(false));
 
     // check `exists -b`
     // TODO: see test_binary_is_in_path()
     // no argument means we treat it as a string
-    assert_eq!(evaluate_arguments(&["-b".to_owned()], &shell), Ok(true));
-    let oldpath = shell.get::<types::Value>("PATH").unwrap_or("/usr/bin".to_owned());
-    shell.set("PATH", "testing/".to_string());
+    assert_eq!(evaluate_arguments(&["-b".into()], &shell), Ok(true));
+    let oldpath = shell.get::<types::Str>("PATH").unwrap_or("/usr/bin".into());
+    shell.set("PATH", "testing/");
 
     assert_eq!(
-        evaluate_arguments(&["-b".to_owned(), "executable_file".to_owned()], &shell),
+        evaluate_arguments(&["-b".into(), "executable_file".into()], &shell),
         Ok(true)
     );
-    assert_eq!(evaluate_arguments(&["-b".to_owned(), "empty_file".to_owned()], &shell), Ok(false));
+    assert_eq!(evaluate_arguments(&["-b".into(), "empty_file".into()], &shell), Ok(false));
     assert_eq!(
-        evaluate_arguments(&["-b".to_owned(), "file_does_not_exist".to_owned()], &shell),
+        evaluate_arguments(&["-b".into(), "file_does_not_exist".into()], &shell),
         Ok(false)
     );
 
@@ -203,49 +202,49 @@ fn test_evaluate_arguments() {
 
     // check `exists -d`
     // no argument means we treat it as a string
-    assert_eq!(evaluate_arguments(&["-d".to_owned()], &shell), Ok(true));
-    assert_eq!(evaluate_arguments(&["-d".to_owned(), "testing/".to_owned()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["-d".into()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["-d".into(), "testing/".into()], &shell), Ok(true));
     assert_eq!(
-        evaluate_arguments(&["-d".to_owned(), "testing/empty_file".to_owned()], &shell),
+        evaluate_arguments(&["-d".into(), "testing/empty_file".into()], &shell),
         Ok(false)
     );
     assert_eq!(
-        evaluate_arguments(&["-d".to_owned(), "does/not/exist/".to_owned()], &shell),
+        evaluate_arguments(&["-d".into(), "does/not/exist/".into()], &shell),
         Ok(false)
     );
 
     // check `exists -f`
     // no argument means we treat it as a string
-    assert_eq!(evaluate_arguments(&["-f".to_owned()], &shell), Ok(true));
-    assert_eq!(evaluate_arguments(&["-f".to_owned(), "testing/".to_owned()], &shell), Ok(false));
+    assert_eq!(evaluate_arguments(&["-f".into()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["-f".into(), "testing/".into()], &shell), Ok(false));
     assert_eq!(
-        evaluate_arguments(&["-f".to_owned(), "testing/empty_file".to_owned()], &shell),
+        evaluate_arguments(&["-f".into(), "testing/empty_file".into()], &shell),
         Ok(true)
     );
     assert_eq!(
-        evaluate_arguments(&["-f".to_owned(), "does-not-exist".to_owned()], &shell),
+        evaluate_arguments(&["-f".into(), "does-not-exist".into()], &shell),
         Ok(false)
     );
 
     // check `exists -s`
     // no argument means we treat it as a string
-    assert_eq!(evaluate_arguments(&["-s".to_owned()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["-s".into()], &shell), Ok(true));
     shell.set("emptyvar", "".to_string());
-    assert_eq!(evaluate_arguments(&["-s".to_owned(), "emptyvar".to_owned()], &shell), Ok(false));
+    assert_eq!(evaluate_arguments(&["-s".into(), "emptyvar".into()], &shell), Ok(false));
     shell.set("testvar", "foobar".to_string());
-    assert_eq!(evaluate_arguments(&["-s".to_owned(), "testvar".to_owned()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["-s".into(), "testvar".into()], &shell), Ok(true));
     shell.variables.remove_variable("testvar");
-    assert_eq!(evaluate_arguments(&["-s".to_owned(), "testvar".to_owned()], &shell), Ok(false));
+    assert_eq!(evaluate_arguments(&["-s".into(), "testvar".into()], &shell), Ok(false));
     // also check that it doesn't trigger on arrays
     let mut array = types::Array::new();
-    array.push("element".to_owned());
+    array.push("element".into());
     shell.variables.remove_variable("array");
     shell.variables.set("array", array);
-    assert_eq!(evaluate_arguments(&["-s".to_owned(), "array".to_owned()], &shell), Ok(false));
+    assert_eq!(evaluate_arguments(&["-s".into(), "array".into()], &shell), Ok(false));
 
     // check `exists --fn`
     let name_str = "test_function";
-    let name = SmallString::from_str(name_str);
+    let name = small::String::from(name_str);
     let mut args = Vec::new();
     args.push(KeyBuf {
         name: "testy".into(),
@@ -253,21 +252,21 @@ fn test_evaluate_arguments() {
     });
     let mut statements = Vec::new();
     statements.push(Statement::End);
-    let description = "description".to_owned();
+    let description: small::String = "description".into();
 
     shell.variables.set(
         &name,
         Function::new(Some(description), name.clone(), args, statements),
     );
 
-    assert_eq!(evaluate_arguments(&["--fn".to_owned(), name_str.to_owned()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["--fn".into(), name_str.into()], &shell), Ok(true));
     shell.variables.remove_variable(name_str);
-    assert_eq!(evaluate_arguments(&["--fn".to_owned(), name_str.to_owned()], &shell), Ok(false));
+    assert_eq!(evaluate_arguments(&["--fn".into(), name_str.into()], &shell), Ok(false));
 
     // check invalid flags / parameters (should all be treated as strings and
     // therefore succeed)
-    assert_eq!(evaluate_arguments(&["--foo".to_owned()], &shell), Ok(true));
-    assert_eq!(evaluate_arguments(&["-x".to_owned()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["--foo".into()], &shell), Ok(true));
+    assert_eq!(evaluate_arguments(&["-x".into()], &shell), Ok(true));
 }
 
 #[test]
@@ -367,7 +366,7 @@ fn test_array_var_is_not_empty() {
     assert_eq!(array_var_is_not_empty("EMPTY_ARRAY", &shell), false);
 
     let mut not_empty_array = types::Array::new();
-    not_empty_array.push("array not empty".to_owned());
+    not_empty_array.push("array not empty".into());
     shell.variables.set("NOT_EMPTY_ARRAY", not_empty_array);
     assert_eq!(array_var_is_not_empty("NOT_EMPTY_ARRAY", &shell), true);
 
@@ -377,7 +376,7 @@ fn test_array_var_is_not_empty() {
 
     // array_var_is_not_empty should NOT match for non-array variables with the
     // same name
-    shell.set("VARIABLE", "notempty-variable".to_string());
+    shell.set("VARIABLE", "notempty-variable");
     assert_eq!(array_var_is_not_empty("VARIABLE", &shell), false);
 }
 
@@ -385,15 +384,15 @@ fn test_array_var_is_not_empty() {
 fn test_string_var_is_not_empty() {
     let mut shell = shell::ShellBuilder::new().as_library();
 
-    shell.set("EMPTY", "".to_string());
+    shell.set("EMPTY", "");
     assert_eq!(string_var_is_not_empty("EMPTY", &shell), false);
 
-    shell.set("NOT_EMPTY", "notempty".to_string());
+    shell.set("NOT_EMPTY", "notempty");
     assert_eq!(string_var_is_not_empty("NOT_EMPTY", &shell), true);
 
     // string_var_is_not_empty should NOT match for arrays with the same name
     let mut array = types::Array::new();
-    array.push("not-empty".to_owned());
+    array.push("not-empty".into());
     shell.variables.set("ARRAY_NOT_EMPTY", array);
     assert_eq!(string_var_is_not_empty("ARRAY_NOT_EMPTY", &shell), false);
 
@@ -409,7 +408,7 @@ fn test_function_is_defined() {
 
     // create a simple dummy function
     let name_str = "test_function";
-    let name = SmallString::from_str(name_str);
+    let name: small::String = name_str.into();
     let mut args = Vec::new();
     args.push(KeyBuf {
         name: "testy".into(),
@@ -417,7 +416,7 @@ fn test_function_is_defined() {
     });
     let mut statements = Vec::new();
     statements.push(Statement::End);
-    let description = "description".to_owned();
+    let description: small::String = "description".into();
 
     shell.variables.set(
         &name,
diff --git a/src/lib/builtins/is.rs b/src/lib/builtins/is.rs
index b191e970870577eda4332702bf8edeacee49d01d..5712753b86a349497d31fa5ac94a0c949c65678c 100644
--- a/src/lib/builtins/is.rs
+++ b/src/lib/builtins/is.rs
@@ -1,7 +1,8 @@
 use shell::Shell;
 use types;
+use small;
 
-pub(crate) fn is(args: &[String], shell: &mut Shell) -> Result<(), String> {
+pub(crate) fn is(args: &[small::String], shell: &mut Shell) -> Result<(), String> {
     match args.len() {
         4 => if args[1] != "not" {
             return Err(format!("Expected 'not' instead found '{}'\n", args[1]).to_string());
@@ -17,35 +18,35 @@ pub(crate) fn is(args: &[String], shell: &mut Shell) -> Result<(), String> {
     Ok(())
 }
 
-fn eval_arg(arg: &str, shell: &mut Shell) -> String {
+fn eval_arg(arg: &str, shell: &mut Shell) -> types::Str {
     let value = get_var_string(arg, shell);
-    if value != "" {
+    if &*value != "" {
         return value;
     }
-    arg.to_string()
+    arg.into()
 }
 
 // On error returns an empty String.
-fn get_var_string(name: &str, shell: &mut Shell) -> String {
+fn get_var_string(name: &str, shell: &mut Shell) -> types::Str {
     if name.chars().nth(0).unwrap() != '$' {
-        return String::new();
+        return "".into();
     }
 
-    match shell.variables.get::<types::Value>(&name[1..]) {
+    match shell.variables.get::<types::Str>(&name[1..]) {
         Some(s) => s,
-        None => String::new(),
+        None => "".into(),
     }
 }
 
 #[test]
 fn test_is() {
-    fn vec_string(args: &[&str]) -> Vec<String> {
-        args.iter().map(|s| (*s).to_owned()).collect::<Vec<String>>()
+    fn vec_string(args: &[&str]) -> Vec<small::String> {
+        args.iter().map(|s| (*s).into()).collect()
     }
     use shell::ShellBuilder;
     let mut shell = ShellBuilder::new().as_library();
-    shell.set("x", "value".to_string());
-    shell.set("y", "0".to_string());
+    shell.set("x", "value");
+    shell.set("y", "0");
 
     // Four arguments
     assert_eq!(
diff --git a/src/lib/builtins/job_control.rs b/src/lib/builtins/job_control.rs
index 423ca273a91f3b36f3650e283723547887c9aa84..ed318b130646882148ef8a42a7f28315d3cc9fd6 100644
--- a/src/lib/builtins/job_control.rs
+++ b/src/lib/builtins/job_control.rs
@@ -4,12 +4,13 @@
 use shell::{
     job_control::{JobControl, ProcessState}, signals, status::*, Shell,
 };
+use small;
 use smallvec::SmallVec;
 
 /// Disowns given process job IDs, and optionally marks jobs to not receive SIGHUP signals.
 /// The `-a` flag selects all jobs, `-r` selects all running jobs, and `-h` specifies to mark
 /// SIGHUP ignoral.
-pub(crate) fn disown(shell: &mut Shell, args: &[String]) -> Result<(), String> {
+pub(crate) fn disown(shell: &mut Shell, args: &[small::String]) -> Result<(), String> {
     // Specifies that a process should be set to not receive SIGHUP signals.
     const NO_SIGHUP: u8 = 1;
     // Specifies that all jobs in the process table should be manipulated.
@@ -97,7 +98,7 @@ pub(crate) fn jobs(shell: &mut Shell) {
 /// Hands control of the foreground process to the specified jobs, recording their exit status.
 /// If the job is stopped, the job will be resumed.
 /// If multiple jobs are given, then only the last job's exit status will be returned.
-pub(crate) fn fg(shell: &mut Shell, args: &[String]) -> i32 {
+pub(crate) fn fg(shell: &mut Shell, args: &[small::String]) -> i32 {
     fn fg_job(shell: &mut Shell, njob: u32) -> i32 {
         let job = if let Some(borrowed_job) =
             shell.background.lock().unwrap().iter().nth(njob as usize)
@@ -146,7 +147,7 @@ pub(crate) fn fg(shell: &mut Shell, args: &[String]) -> i32 {
 }
 
 /// Resumes a stopped background process, if it was stopped.
-pub(crate) fn bg(shell: &mut Shell, args: &[String]) -> i32 {
+pub(crate) fn bg(shell: &mut Shell, args: &[small::String]) -> i32 {
     fn bg_job(shell: &mut Shell, njob: u32) -> bool {
         if let Some(job) = shell
             .background
diff --git a/src/lib/builtins/man_pages.rs b/src/lib/builtins/man_pages.rs
index b0cabcd76700f92773d2f9bd622dafe109308a37..33a93f5c8f49f5d944fc998530e3e2b501f2c535 100644
--- a/src/lib/builtins/man_pages.rs
+++ b/src/lib/builtins/man_pages.rs
@@ -1,6 +1,8 @@
-pub(crate) fn check_help(args: &[String], man_page: &'static str) -> bool {
+use small;
+
+pub(crate) fn check_help(args: &[small::String], man_page: &'static str) -> bool {
     for arg in args {
-        if &**arg == "-h" || &**arg == "--help" {
+        if arg == "-h" || arg == "--help" {
             println!("{}", man_page);
             return true;
         }
diff --git a/src/lib/builtins/mod.rs b/src/lib/builtins/mod.rs
index a482b9d8d0762c47dcf1b0611ff7e97c541abac5..7d6d63939d817a3d47da69a6794eb391927e2965 100644
--- a/src/lib/builtins/mod.rs
+++ b/src/lib/builtins/mod.rs
@@ -26,6 +26,7 @@ use shell::{
     self, fork_function::fork_function, job_control::{JobControl, ProcessState}, status::*,
     FlowLogic, Shell, ShellHistory,
 };
+use small;
 use sys;
 use types;
 
@@ -37,7 +38,7 @@ const SOURCE_DESC: &str = "Evaluate the file following the command or re-initial
 const DISOWN_DESC: &str =
     "Disowning a process removes that process from the shell's background process table.";
 
-pub type BuiltinFunction = fn(&[String], &mut Shell) -> i32;
+pub type BuiltinFunction = fn(&[small::String], &mut Shell) -> i32;
 
 macro_rules! map {
     ($($name:expr => $func:ident: $help:expr),+) => {{
@@ -130,12 +131,12 @@ impl BuiltinMap {
     }
 }
 
-fn starts_with(args: &[String], _: &mut Shell) -> i32 { conditionals::starts_with(args) }
-fn ends_with(args: &[String], _: &mut Shell) -> i32 { conditionals::ends_with(args) }
-fn contains(args: &[String], _: &mut Shell) -> i32 { conditionals::contains(args) }
+fn starts_with(args: &[small::String], _: &mut Shell) -> i32 { conditionals::starts_with(args) }
+fn ends_with(args: &[small::String], _: &mut Shell) -> i32 { conditionals::ends_with(args) }
+fn contains(args: &[small::String], _: &mut Shell) -> i32 { conditionals::contains(args) }
 
 // Definitions of simple builtins go here
-fn builtin_status(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_status(args: &[small::String], shell: &mut Shell) -> i32 {
     match status(args, shell) {
         Ok(()) => SUCCESS,
         Err(why) => {
@@ -147,7 +148,7 @@ fn builtin_status(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-pub fn builtin_cd(args: &[String], shell: &mut Shell) -> i32 {
+pub fn builtin_cd(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_CD) {
         return SUCCESS;
     }
@@ -164,7 +165,7 @@ pub fn builtin_cd(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_bool(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_bool(args: &[small::String], shell: &mut Shell) -> i32 {
     if args.len() != 2 {
         let stderr = io::stderr();
         let mut stderr = stderr.lock();
@@ -172,7 +173,7 @@ fn builtin_bool(args: &[String], shell: &mut Shell) -> i32 {
         return FAILURE;
     }
 
-    let opt = shell.variables.get::<types::Value>(&args[1][1..]);
+    let opt = shell.variables.get::<types::Str>(&args[1][1..]);
     let sh_var: &str = match opt.as_ref() {
         Some(s) => s,
         None => "",
@@ -192,7 +193,7 @@ fn builtin_bool(args: &[String], shell: &mut Shell) -> i32 {
     SUCCESS
 }
 
-fn builtin_is(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_is(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_IS) {
         return SUCCESS;
     }
@@ -208,7 +209,7 @@ fn builtin_is(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_dirs(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_dirs(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_DIRS) {
         return SUCCESS;
     }
@@ -216,7 +217,7 @@ fn builtin_dirs(args: &[String], shell: &mut Shell) -> i32 {
     shell.directory_stack.dirs(args)
 }
 
-fn builtin_pushd(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_pushd(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_PUSHD) {
         return SUCCESS;
     }
@@ -231,7 +232,7 @@ fn builtin_pushd(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_popd(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_popd(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_POPD) {
         return SUCCESS;
     }
@@ -246,27 +247,27 @@ fn builtin_popd(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_alias(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_alias(args: &[small::String], shell: &mut Shell) -> i32 {
     let args_str = args[1..].join(" ");
     alias(&mut shell.variables, &args_str)
 }
 
-fn builtin_unalias(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_unalias(args: &[small::String], shell: &mut Shell) -> i32 {
     drop_alias(&mut shell.variables, args)
 }
 
 // TODO There is a man page for fn however the -h and --help flags are not
 // checked for.
-fn builtin_fn(_: &[String], shell: &mut Shell) -> i32 { fn_(&mut shell.variables) }
+fn builtin_fn(_: &[small::String], shell: &mut Shell) -> i32 { fn_(&mut shell.variables) }
 
-fn builtin_read(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_read(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_READ) {
         return SUCCESS;
     }
     shell.variables.read(args)
 }
 
-fn builtin_drop(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_drop(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_DROP) {
         return SUCCESS;
     }
@@ -277,14 +278,14 @@ fn builtin_drop(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_set(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_set(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_SET) {
         return SUCCESS;
     }
     set::set(args, shell)
 }
 
-fn builtin_eq(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_eq(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_EQ) {
         return SUCCESS;
     }
@@ -300,7 +301,7 @@ fn builtin_eq(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_eval(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_eval(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_EVAL) {
         return SUCCESS;
     }
@@ -315,14 +316,14 @@ fn builtin_eval(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_history(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_history(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_HISTORY) {
         return SUCCESS;
     }
     shell.print_history(args)
 }
 
-fn builtin_source(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_source(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_SOURCE) {
         return SUCCESS;
     }
@@ -337,7 +338,7 @@ fn builtin_source(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_echo(args: &[String], _: &mut Shell) -> i32 {
+fn builtin_echo(args: &[small::String], _: &mut Shell) -> i32 {
     if check_help(args, MAN_ECHO) {
         return SUCCESS;
     }
@@ -352,7 +353,7 @@ fn builtin_echo(args: &[String], _: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_test(args: &[String], _: &mut Shell) -> i32 {
+fn builtin_test(args: &[small::String], _: &mut Shell) -> i32 {
     // Do not use `check_help` for the `test` builtin. The
     // `test` builtin contains a "-h" option.
     match test(args) {
@@ -366,7 +367,7 @@ fn builtin_test(args: &[String], _: &mut Shell) -> i32 {
 }
 
 // TODO create manpage.
-fn builtin_calc(args: &[String], _: &mut Shell) -> i32 {
+fn builtin_calc(args: &[small::String], _: &mut Shell) -> i32 {
     match calc::calc(&args[1..]) {
         Ok(()) => SUCCESS,
         Err(why) => {
@@ -376,7 +377,7 @@ fn builtin_calc(args: &[String], _: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_random(args: &[String], _: &mut Shell) -> i32 {
+fn builtin_random(args: &[small::String], _: &mut Shell) -> i32 {
     if check_help(args, MAN_RANDOM) {
         return SUCCESS;
     }
@@ -389,12 +390,12 @@ fn builtin_random(args: &[String], _: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_true(args: &[String], _: &mut Shell) -> i32 {
+fn builtin_true(args: &[small::String], _: &mut Shell) -> i32 {
     check_help(args, MAN_TRUE);
     SUCCESS
 }
 
-fn builtin_false(args: &[String], _: &mut Shell) -> i32 {
+fn builtin_false(args: &[small::String], _: &mut Shell) -> i32 {
     if check_help(args, MAN_FALSE) {
         return SUCCESS;
     }
@@ -402,32 +403,32 @@ fn builtin_false(args: &[String], _: &mut Shell) -> i32 {
 }
 
 // TODO create a manpage
-fn builtin_wait(_: &[String], shell: &mut Shell) -> i32 {
+fn builtin_wait(_: &[small::String], shell: &mut Shell) -> i32 {
     shell.wait_for_background();
     SUCCESS
 }
 
-fn builtin_jobs(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_jobs(args: &[small::String], shell: &mut Shell) -> i32 {
     check_help(args, MAN_JOBS);
     job_control::jobs(shell);
     SUCCESS
 }
 
-fn builtin_bg(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_bg(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_BG) {
         return SUCCESS;
     }
     job_control::bg(shell, &args[1..])
 }
 
-fn builtin_fg(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_fg(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_FG) {
         return SUCCESS;
     }
     job_control::fg(shell, &args[1..])
 }
 
-fn builtin_suspend(args: &[String], _: &mut Shell) -> i32 {
+fn builtin_suspend(args: &[small::String], _: &mut Shell) -> i32 {
     if check_help(args, MAN_SUSPEND) {
         return SUCCESS;
     }
@@ -435,7 +436,7 @@ fn builtin_suspend(args: &[String], _: &mut Shell) -> i32 {
     SUCCESS
 }
 
-fn builtin_disown(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_disown(args: &[small::String], shell: &mut Shell) -> i32 {
     for arg in args {
         if *arg == "--help" {
             println!("{}", MAN_DISOWN);
@@ -451,7 +452,7 @@ fn builtin_disown(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_help(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_help(args: &[small::String], shell: &mut Shell) -> i32 {
     let builtins = shell.builtins;
     let stdout = io::stdout();
     let mut stdout = stdout.lock();
@@ -477,7 +478,7 @@ fn builtin_help(args: &[String], shell: &mut Shell) -> i32 {
     SUCCESS
 }
 
-fn builtin_exit(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_exit(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_EXIT) {
         return SUCCESS;
     }
@@ -495,7 +496,7 @@ fn builtin_exit(args: &[String], shell: &mut Shell) -> i32 {
     )
 }
 
-fn builtin_exec(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_exec(args: &[small::String], shell: &mut Shell) -> i32 {
     match exec(shell, &args[1..]) {
         // Shouldn't ever hit this case.
         Ok(()) => SUCCESS,
@@ -509,7 +510,7 @@ fn builtin_exec(args: &[String], shell: &mut Shell) -> i32 {
 }
 
 use regex::Regex;
-fn builtin_matches(args: &[String], _: &mut Shell) -> i32 {
+fn builtin_matches(args: &[small::String], _: &mut Shell) -> i32 {
     if check_help(args, MAN_MATCHES) {
         return SUCCESS;
     }
@@ -538,7 +539,7 @@ fn builtin_matches(args: &[String], _: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_exists(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_exists(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_EXISTS) {
         return SUCCESS;
     }
@@ -552,21 +553,21 @@ fn builtin_exists(args: &[String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_which(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_which(args: &[small::String], shell: &mut Shell) -> i32 {
     match which(args, shell) {
         Ok(result) => result,
         Err(()) => FAILURE,
     }
 }
 
-fn builtin_type(args: &[String], shell: &mut Shell) -> i32 {
+fn builtin_type(args: &[small::String], shell: &mut Shell) -> i32 {
     match find_type(args, shell) {
         Ok(result) => result,
         Err(()) => FAILURE,
     }
 }
 
-fn builtin_isatty(args: &[String], _: &mut Shell) -> i32 {
+fn builtin_isatty(args: &[small::String], _: &mut Shell) -> i32 {
     if check_help(args, MAN_ISATTY) {
         return SUCCESS;
     }
diff --git a/src/lib/builtins/set.rs b/src/lib/builtins/set.rs
index 98446b69dc98e9db1c115b6aceacb5e0b86c31af..38e41a8e493b9e3212896abd668a7848e18416ea 100644
--- a/src/lib/builtins/set.rs
+++ b/src/lib/builtins/set.rs
@@ -1,6 +1,7 @@
 use liner::KeyBindings;
 use shell::{flags::*, Shell};
 use types;
+use small;
 use std::iter;
 
 enum PositionalArgs {
@@ -10,7 +11,7 @@ enum PositionalArgs {
 
 use self::PositionalArgs::*;
 
-pub(crate) fn set(args: &[String], shell: &mut Shell) -> i32 {
+pub(crate) fn set(args: &[small::String], shell: &mut Shell) -> i32 {
     let mut args_iter = args.iter();
     let mut positionals = None;
 
@@ -75,12 +76,12 @@ pub(crate) fn set(args: &[String], shell: &mut Shell) -> i32 {
     match positionals {
         None => (),
         Some(kind) => {
-            let command: String = shell.variables.get::<types::Array>("args").unwrap()[0].to_owned();
+            let command = shell.variables.get::<types::Array>("args").unwrap()[0].clone();
             // This used to take a `&[String]` but cloned them all, so although
             // this is non-ideal and could probably be better done with `Rc`, it
             // hasn't got any slower.
             let arguments: types::Array = iter::once(command)
-                .chain(args_iter.map(|i| i.to_string()))
+                .chain(args_iter.cloned())
                 .collect();
             match kind {
                 UnsetIfNone => { shell.variables.set("args", arguments); }
diff --git a/src/lib/builtins/source.rs b/src/lib/builtins/source.rs
index 9a52ea480677c20f1a26c72081e9530b27a3ce02..85a7ca23753b36592fb1c8a90e966d458a641eaa 100644
--- a/src/lib/builtins/source.rs
+++ b/src/lib/builtins/source.rs
@@ -1,10 +1,11 @@
 use shell::{FlowLogic, Shell};
 use std::{fs::File, io::Read};
+use small;
 
 /// Evaluates the given file and returns 'SUCCESS' if it succeeds.
-pub(crate) fn source(shell: &mut Shell, arguments: &[String]) -> Result<(), String> {
+pub(crate) fn source(shell: &mut Shell, arguments: &[small::String]) -> Result<(), String> {
     match arguments.get(1) {
-        Some(argument) => if let Ok(mut file) = File::open(&argument) {
+        Some(argument) => if let Ok(mut file) = File::open(argument.as_str()) {
             let capacity = file.metadata().map(|x| x.len()).unwrap_or(0) as usize;
             let mut command_list = String::with_capacity(capacity);
             file.read_to_string(&mut command_list)
diff --git a/src/lib/builtins/status.rs b/src/lib/builtins/status.rs
index 3063f7165a02cb9014810459e370eca454ee3f5a..ea28e5368f06805f1a459ea43fcbda3e992435c4 100644
--- a/src/lib/builtins/status.rs
+++ b/src/lib/builtins/status.rs
@@ -1,5 +1,6 @@
 use builtins::man_pages::{MAN_STATUS};
 use shell::Shell;
+use small;
 
 use std::env;
 
@@ -12,7 +13,7 @@ bitflags! {
     }
 }
 
-pub(crate) fn status(args: &[String], shell: &mut Shell) -> Result<(), String> {
+pub(crate) fn status(args: &[small::String], shell: &mut Shell) -> Result<(), String> {
     let mut flags = Flags::empty();
     let shell_args: Vec<_> = env::args().collect();
 
diff --git a/src/lib/builtins/variables.rs b/src/lib/builtins/variables.rs
index 98fc23a0c93a7d92d3f3e1b124be3a6e5fa302a0..7018ff7f4cac5b52b063dc4b8aaa330c4293a51a 100644
--- a/src/lib/builtins/variables.rs
+++ b/src/lib/builtins/variables.rs
@@ -3,7 +3,7 @@
 use std::io::{self, Write};
 
 use shell::{status::*, variables::Variables};
-use types::*;
+use types;
 
 fn print_list(vars: &Variables) {
     let stdout = io::stdout();
@@ -19,10 +19,10 @@ fn print_list(vars: &Variables) {
 }
 
 enum Binding {
-    InvalidKey(Identifier),
+    InvalidKey(types::Str),
     ListEntries,
-    KeyOnly(Identifier),
-    KeyValue(Identifier, Value),
+    KeyOnly(types::Str),
+    KeyValue(types::Str, types::Str),
 }
 
 /// Parses alias as a `(key, value)` tuple.
@@ -49,18 +49,18 @@ fn parse_alias(args: &str) -> Binding {
         }
     }
 
-    let key: Identifier = key.into();
+    let key: types::Str = key.into();
 
     if !found_key && key.is_empty() {
         Binding::ListEntries
     } else {
-        let value: Value = char_iter.skip_while(|&x| x == ' ').collect();
+        let value: String = char_iter.skip_while(|&x| x == ' ').collect();
         if value.is_empty() {
             Binding::KeyOnly(key)
         } else if !Variables::is_valid_variable_name(&key) {
             Binding::InvalidKey(key)
         } else {
-            Binding::KeyValue(key, value)
+            Binding::KeyValue(key, value.into())
         }
     }
 }
@@ -74,7 +74,7 @@ pub(crate) fn alias(vars: &mut Variables, args: &str) -> i32 {
             return FAILURE;
         }
         Binding::KeyValue(key, value) => {
-            vars.set(&key, Alias(value));
+            vars.set(&key, types::Alias(value));
         }
         Binding::ListEntries => print_list(&vars),
         Binding::KeyOnly(key) => {
@@ -143,11 +143,12 @@ mod test {
     use super::*;
     use parser::{expand_string, Expander};
     use shell::status::{FAILURE, SUCCESS};
+    use types::Array;
 
     struct VariableExpander(pub Variables);
 
     impl Expander for VariableExpander {
-        fn string(&self, var: &str, _: bool) -> Option<Value> { self.0.get::<Value>(var) }
+        fn string(&self, var: &str, _: bool) -> Option<types::Str> { self.0.get::<types::Str>(var) }
     }
 
     // TODO: Rewrite tests now that let is part of the grammar.
@@ -177,7 +178,7 @@ mod test {
     #[test]
     fn drop_deletes_variable() {
         let mut variables = Variables::default();
-        variables.set("FOO", "BAR".to_string());
+        variables.set("FOO", "BAR");
         let return_status = drop_variable(&mut variables, &["drop", "FOO"]);
         assert_eq!(SUCCESS, return_status);
         let expanded = expand_string("$FOO", &VariableExpander(variables), false).join("");
diff --git a/src/lib/lib.rs b/src/lib/lib.rs
index 759a71b3db7754d9eb48cace0a03a4274b4d03ad..13e57505b55bafd9b377489e57e873b67fa90008 100644
--- a/src/lib/lib.rs
+++ b/src/lib/lib.rs
@@ -18,7 +18,7 @@ extern crate lazy_static;
 extern crate libloading;
 extern crate liner;
 extern crate regex;
-extern crate smallstring;
+extern crate small;
 extern crate smallvec;
 extern crate unicode_segmentation;
 extern crate xdg;
diff --git a/src/lib/parser/assignments/checker.rs b/src/lib/parser/assignments/checker.rs
index 84fe2e51134636daec58225d5a88fb185bd03a92..1589d2b1c02c509efeddc389c63df58281629ed2 100644
--- a/src/lib/parser/assignments/checker.rs
+++ b/src/lib/parser/assignments/checker.rs
@@ -1,7 +1,7 @@
 use super::super::{expand_string, Expander};
 use lexers::assignments::{Primitive, TypeError};
 use shell::variables::VariableType;
-use types::*;
+use types;
 use std::iter::Iterator;
 
 #[derive(PartialEq, Clone, Copy, Debug)]
@@ -143,7 +143,7 @@ fn is_float_array(value: VariableType) -> Result<VariableType, ()> {
 }
 
 fn get_string<E: Expander>(shell: &E, value: &str) -> VariableType {
-    VariableType::Str(expand_string(value, shell, false).join(" "))
+    VariableType::Str(types::Str::from(expand_string(value, shell, false).join(" ")))
 }
 
 fn get_array<E: Expander>(shell: &E, value: &str) -> VariableType {
@@ -152,7 +152,7 @@ fn get_array<E: Expander>(shell: &E, value: &str) -> VariableType {
 
 fn get_hash_map<E: Expander>(shell: &E, expression: &str, inner_kind: &Primitive) -> Result<VariableType, TypeError> {
     let array = expand_string(expression, shell, false);
-    let mut hmap: HashMap = HashMap::with_capacity_and_hasher(array.len(), Default::default());
+    let mut hmap = types::HashMap::with_capacity_and_hasher(array.len(), Default::default());
 
     for string in array {
         if let Some(found) = string.find('=') {
@@ -185,7 +185,7 @@ fn get_hash_map<E: Expander>(shell: &E, expression: &str, inner_kind: &Primitive
 
 fn get_btree_map<E: Expander>(shell: &E, expression: &str, inner_kind: &Primitive) -> Result<VariableType, TypeError> {
     let array = expand_string(expression, shell, false);
-    let mut bmap: BTreeMap = BTreeMap::new();
+    let mut bmap = types::BTreeMap::new();
 
     for string in array {
         if let Some(found) = string.find('=') {
@@ -241,7 +241,7 @@ pub(crate) fn value_check<E: Expander>(
         Primitive::Boolean if !is_array => {
             let value = get_string!();
             let value = is_boolean_string(&value).map_err(|_| TypeError::BadValue(expected.clone()))?;
-            Ok(VariableType::Str(value.to_owned()))
+            Ok(VariableType::Str(value.into()))
         }
         Primitive::BooleanArray if is_array => {
             let mut values = get_array!();
@@ -273,6 +273,7 @@ pub(crate) fn value_check<E: Expander>(
 #[cfg(test)]
 mod test {
     use super::*;
+    use types::Array;
 
     #[test]
     fn is_array_() {
diff --git a/src/lib/parser/loops.rs b/src/lib/parser/loops.rs
index 6161a3ed4e67cad22d448f750a1766e0754fb54d..d1e24aece136b4726c43f6e8a471964b4d76d505 100644
--- a/src/lib/parser/loops.rs
+++ b/src/lib/parser/loops.rs
@@ -1,15 +1,15 @@
 use parser::{expand_string, Expander};
-use types::Value;
+use types;
 
 #[derive(Debug, PartialEq)]
 pub(crate) enum ForExpression {
-    Multiple(Vec<Value>),
-    Normal(Value),
+    Multiple(Vec<types::Str>),
+    Normal(types::Str),
     Range(usize, usize),
 }
 
 impl ForExpression {
-    pub(crate) fn new<E: Expander>(expression: &[String], expanders: &E) -> ForExpression {
+    pub(crate) fn new<E: Expander>(expression: &[types::Str], expanders: &E) -> ForExpression {
         let output: Vec<_> = expression
             .iter()
             .flat_map(|expression| expand_string(expression, expanders, true))
@@ -70,13 +70,13 @@ mod tests {
     struct VariableExpander(pub Variables);
 
     impl Expander for VariableExpander {
-        fn string(&self, var: &str, _: bool) -> Option<Value> { self.0.get::<Value>(var) }
+        fn string(&self, var: &str, _: bool) -> Option<types::Str> { self.0.get::<types::Str>(var) }
     }
 
     #[test]
     fn for_inclusive_range() {
         let variables = Variables::default();
-        let input = &["1...10".to_owned()];
+        let input = &["1...10".into()];
         assert_eq!(
             ForExpression::new(input, &VariableExpander(variables)),
             ForExpression::Range(1, 11)
@@ -86,7 +86,7 @@ mod tests {
     #[test]
     fn for_exclusive_range() {
         let variables = Variables::default();
-        let input = &["1..10".to_owned()];
+        let input = &["1..10".into()];
         assert_eq!(
             ForExpression::new(input, &VariableExpander(variables)),
             ForExpression::Range(1, 10)
@@ -97,11 +97,11 @@ mod tests {
     fn for_normal() {
         let variables = Variables::default();
         let output = vec![
-            "1".to_owned(),
-            "2".to_owned(),
-            "3".to_owned(),
-            "4".to_owned(),
-            "5".to_owned(),
+            "1".into(),
+            "2".into(),
+            "3".into(),
+            "4".into(),
+            "5".into(),
         ];
         assert_eq!(
             ForExpression::new(&output.clone(), &VariableExpander(variables)),
@@ -114,8 +114,8 @@ mod tests {
         let mut variables = Variables::default();
         variables.set("A", "1 2 3 4 5".to_string());
         assert_eq!(
-            ForExpression::new(&["$A".to_owned()], &VariableExpander(variables)),
-            ForExpression::Normal("1 2 3 4 5".to_owned())
+            ForExpression::new(&["$A".into()], &VariableExpander(variables)),
+            ForExpression::Normal("1 2 3 4 5".into())
         );
     }
 }
diff --git a/src/lib/parser/pipelines/collector.rs b/src/lib/parser/pipelines/collector.rs
index b8259ce238d5c9dce18250e87c5216fdb4616d99..8393bbe433efad4fbedc6aec7a762322030782e7 100644
--- a/src/lib/parser/pipelines/collector.rs
+++ b/src/lib/parser/pipelines/collector.rs
@@ -163,7 +163,7 @@ impl<'a> Collector<'a> {
                             let heredoc = heredoc.lines().skip(1).collect::<Vec<&str>>();
                             if heredoc.len() > 1 {
                                 let herestring =
-                                    Input::HereString(heredoc[..heredoc.len() - 1].join("\n"));
+                                    Input::HereString(heredoc[..heredoc.len() - 1].join("\n").into());
                                 if let Some(x) = inputs.as_mut() { x.push(herestring.clone()) };
                             }
                         }
@@ -403,14 +403,14 @@ mod tests {
     fn stderr_redirection() {
         if let Statement::Pipeline(pipeline) = parse("git rev-parse --abbrev-ref HEAD ^> /dev/null")
         {
-            assert_eq!("git", pipeline.items[0].job.args[0]);
-            assert_eq!("rev-parse", pipeline.items[0].job.args[1]);
-            assert_eq!("--abbrev-ref", pipeline.items[0].job.args[2]);
-            assert_eq!("HEAD", pipeline.items[0].job.args[3]);
+            assert_eq!("git", pipeline.items[0].job.args[0].as_str());
+            assert_eq!("rev-parse", pipeline.items[0].job.args[1].as_str());
+            assert_eq!("--abbrev-ref", pipeline.items[0].job.args[2].as_str());
+            assert_eq!("HEAD", pipeline.items[0].job.args[3].as_str());
 
             let expected = vec![Redirection {
                 from:   RedirectFrom::Stderr,
-                file:   "/dev/null".to_owned(),
+                file:   "/dev/null".into(),
                 append: false,
             }];
 
@@ -424,8 +424,8 @@ mod tests {
     fn braces() {
         if let Statement::Pipeline(pipeline) = parse("echo {a b} {a {b c}}") {
             let items = pipeline.items;
-            assert_eq!("{a b}", items[0].job.args[1]);
-            assert_eq!("{a {b c}}", items[0].job.args[2]);
+            assert_eq!("{a b}", items[0].job.args[1].as_str());
+            assert_eq!("{a {b c}}", items[0].job.args[2].as_str());
         } else {
             assert!(false);
         }
@@ -435,9 +435,9 @@ mod tests {
     fn methods() {
         if let Statement::Pipeline(pipeline) = parse("echo @split(var, ', ') $join(array, ',')") {
             let items = pipeline.items;
-            assert_eq!("echo", items[0].job.args[0]);
-            assert_eq!("@split(var, ', ')", items[0].job.args[1]);
-            assert_eq!("$join(array, ',')", items[0].job.args[2]);
+            assert_eq!("echo", items[0].job.args[0].as_str());
+            assert_eq!("@split(var, ', ')", items[0].job.args[1].as_str());
+            assert_eq!("$join(array, ',')", items[0].job.args[2].as_str());
         } else {
             assert!(false);
         }
@@ -447,8 +447,8 @@ mod tests {
     fn nested_process() {
         if let Statement::Pipeline(pipeline) = parse("echo $(echo one $(echo two) three)") {
             let items = pipeline.items;
-            assert_eq!("echo", items[0].job.args[0]);
-            assert_eq!("$(echo one $(echo two) three)", items[0].job.args[1]);
+            assert_eq!("echo", items[0].job.args[0].as_str());
+            assert_eq!("$(echo one $(echo two) three)", items[0].job.args[1].as_str());
         } else {
             assert!(false);
         }
@@ -458,8 +458,8 @@ mod tests {
     fn nested_array_process() {
         if let Statement::Pipeline(pipeline) = parse("echo @(echo one @(echo two) three)") {
             let items = pipeline.items;
-            assert_eq!("echo", items[0].job.args[0]);
-            assert_eq!("@(echo one @(echo two) three)", items[0].job.args[1]);
+            assert_eq!("echo", items[0].job.args[0].as_str());
+            assert_eq!("@(echo one @(echo two) three)", items[0].job.args[1].as_str());
         } else {
             assert!(false);
         }
@@ -469,8 +469,8 @@ mod tests {
     fn quoted_process() {
         if let Statement::Pipeline(pipeline) = parse("echo \"$(seq 1 10)\"") {
             let items = pipeline.items;
-            assert_eq!("echo", items[0].job.args[0]);
-            assert_eq!("\"$(seq 1 10)\"", items[0].job.args[1]);
+            assert_eq!("echo", items[0].job.args[0].as_str());
+            assert_eq!("\"$(seq 1 10)\"", items[0].job.args[1].as_str());
             assert_eq!(2, items[0].job.args.len());
         } else {
             assert!(false);
@@ -481,8 +481,8 @@ mod tests {
     fn process() {
         if let Statement::Pipeline(pipeline) = parse("echo $(seq 1 10 | head -1)") {
             let items = pipeline.items;
-            assert_eq!("echo", items[0].job.args[0]);
-            assert_eq!("$(seq 1 10 | head -1)", items[0].job.args[1]);
+            assert_eq!("echo", items[0].job.args[0].as_str());
+            assert_eq!("$(seq 1 10 | head -1)", items[0].job.args[1].as_str());
             assert_eq!(2, items[0].job.args.len());
         } else {
             assert!(false);
@@ -493,8 +493,8 @@ mod tests {
     fn array_process() {
         if let Statement::Pipeline(pipeline) = parse("echo @(seq 1 10 | head -1)") {
             let items = pipeline.items;
-            assert_eq!("echo", items[0].job.args[0]);
-            assert_eq!("@(seq 1 10 | head -1)", items[0].job.args[1]);
+            assert_eq!("echo", items[0].job.args[0].as_str());
+            assert_eq!("@(seq 1 10 | head -1)", items[0].job.args[1].as_str());
             assert_eq!(2, items[0].job.args.len());
         } else {
             assert!(false);
@@ -506,7 +506,7 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("cat") {
             let items = pipeline.items;
             assert_eq!(1, items.len());
-            assert_eq!("cat", items[0].job.command);
+            assert_eq!("cat", items[0].job.command.as_str());
             assert_eq!(1, items[0].job.args.len());
         } else {
             assert!(false);
@@ -518,10 +518,10 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("echo a b c") {
             let items = pipeline.items;
             assert_eq!(1, items.len());
-            assert_eq!("echo", items[0].job.args[0]);
-            assert_eq!("a", items[0].job.args[1]);
-            assert_eq!("b", items[0].job.args[2]);
-            assert_eq!("c", items[0].job.args[3]);
+            assert_eq!("echo", items[0].job.args[0].as_str());
+            assert_eq!("a", items[0].job.args[1].as_str());
+            assert_eq!("b", items[0].job.args[2].as_str());
+            assert_eq!("c", items[0].job.args[3].as_str());
             assert_eq!(4, items[0].job.args.len());
         } else {
             assert!(false);
@@ -533,9 +533,9 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("ls -al dir") {
             let items = pipeline.items;
             assert_eq!(1, items.len());
-            assert_eq!("ls", items[0].job.command);
-            assert_eq!("-al", items[0].job.args[1]);
-            assert_eq!("dir", items[0].job.args[2]);
+            assert_eq!("ls", items[0].job.command.as_str());
+            assert_eq!("-al", items[0].job.args[1].as_str());
+            assert_eq!("dir", items[0].job.args[2].as_str());
         } else {
             assert!(false);
         }
@@ -555,9 +555,9 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("ls \t -al\t\tdir") {
             let items = pipeline.items;
             assert_eq!(1, items.len());
-            assert_eq!("ls", items[0].job.command);
-            assert_eq!("-al", items[0].job.args[1]);
-            assert_eq!("dir", items[0].job.args[2]);
+            assert_eq!("ls", items[0].job.command.as_str());
+            assert_eq!("-al", items[0].job.args[1].as_str());
+            assert_eq!("dir", items[0].job.args[2].as_str());
         } else {
             assert!(false);
         }
@@ -567,8 +567,8 @@ mod tests {
     fn trailing_whitespace() {
         if let Statement::Pipeline(pipeline) = parse("ls -al\t ") {
             assert_eq!(1, pipeline.items.len());
-            assert_eq!("ls", pipeline.items[0].job.command);
-            assert_eq!("-al", pipeline.items[0].job.args[1]);
+            assert_eq!("ls", pipeline.items[0].job.command.as_str());
+            assert_eq!("-al", pipeline.items[0].job.args[1].as_str());
         } else {
             assert!(false);
         }
@@ -578,8 +578,8 @@ mod tests {
     fn double_quoting() {
         if let Statement::Pipeline(pipeline) = parse("echo \"a > 10\" \"a < 10\"") {
             let items = pipeline.items;
-            assert_eq!("\"a > 10\"", items[0].job.args[1]);
-            assert_eq!("\"a < 10\"", items[0].job.args[2]);
+            assert_eq!("\"a > 10\"", items[0].job.args[1].as_str());
+            assert_eq!("\"a < 10\"", items[0].job.args[2].as_str());
             assert_eq!(3, items[0].job.args.len());
         } else {
             assert!(false)
@@ -591,7 +591,7 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("echo \"Hello 'Rusty' World\"") {
             let items = pipeline.items;
             assert_eq!(2, items[0].job.args.len());
-            assert_eq!("\"Hello \'Rusty\' World\"", items[0].job.args[1]);
+            assert_eq!("\"Hello \'Rusty\' World\"", items[0].job.args[1].as_str());
         } else {
             assert!(false)
         }
@@ -602,7 +602,7 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("echo \"Hello \"Rusty\" World\"") {
             let items = pipeline.items;
             assert_eq!(2, items[0].job.args.len());
-            assert_eq!("\"Hello \"Rusty\" World\"", items[0].job.args[1]);
+            assert_eq!("\"Hello \"Rusty\" World\"", items[0].job.args[1].as_str());
         } else {
             assert!(false)
         }
@@ -610,7 +610,7 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("echo \'Hello \'Rusty\' World\'") {
             let items = pipeline.items;
             assert_eq!(2, items[0].job.args.len());
-            assert_eq!("\'Hello \'Rusty\' World\'", items[0].job.args[1]);
+            assert_eq!("\'Hello \'Rusty\' World\'", items[0].job.args[1].as_str());
         } else {
             assert!(false)
         }
@@ -676,7 +676,7 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("    \techo") {
             let items = pipeline.items;
             assert_eq!(1, items.len());
-            assert_eq!("echo", items[0].job.command);
+            assert_eq!("echo", items[0].job.command.as_str());
         } else {
             assert!(false);
         }
@@ -686,7 +686,7 @@ mod tests {
     fn single_quoting() {
         if let Statement::Pipeline(pipeline) = parse("echo '#!!;\"\\'") {
             let items = pipeline.items;
-            assert_eq!("'#!!;\"\\'", items[0].job.args[1]);
+            assert_eq!("'#!!;\"\\'", items[0].job.args[1].as_str());
         } else {
             assert!(false);
         }
@@ -698,11 +698,11 @@ mod tests {
             parse("echo 123 456 \"ABC 'DEF' GHI\" 789 one'  'two")
         {
             let items = pipeline.items;
-            assert_eq!("123", items[0].job.args[1]);
-            assert_eq!("456", items[0].job.args[2]);
-            assert_eq!("\"ABC 'DEF' GHI\"", items[0].job.args[3]);
-            assert_eq!("789", items[0].job.args[4]);
-            assert_eq!("one'  'two", items[0].job.args[5]);
+            assert_eq!("123", items[0].job.args[1].as_str());
+            assert_eq!("456", items[0].job.args[2].as_str());
+            assert_eq!("\"ABC 'DEF' GHI\"", items[0].job.args[3].as_str());
+            assert_eq!("789", items[0].job.args[4].as_str());
+            assert_eq!("one'  'two", items[0].job.args[5].as_str());
         } else {
             assert!(false);
         }
@@ -724,12 +724,12 @@ mod tests {
         let input = "cat | echo hello | cat < stuff > other";
         if let Statement::Pipeline(pipeline) = parse(input) {
             assert_eq!(3, pipeline.items.len());
-            assert_eq!("cat", &pipeline.clone().items[0].job.args[0]);
-            assert_eq!("echo", &pipeline.clone().items[1].job.args[0]);
-            assert_eq!("hello", &pipeline.clone().items[1].job.args[1]);
-            assert_eq!("cat", &pipeline.clone().items[2].job.args[0]);
+            assert_eq!("cat", pipeline.clone().items[0].job.args[0].as_str());
+            assert_eq!("echo", pipeline.clone().items[1].job.args[0].as_str());
+            assert_eq!("hello", pipeline.clone().items[1].job.args[1].as_str());
+            assert_eq!("cat", pipeline.clone().items[2].job.args[0].as_str());
             assert_eq!(vec![Input::File("stuff".into())], pipeline.items[2].inputs);
-            assert_eq!("other", &pipeline.clone().items[2].outputs[0].file);
+            assert_eq!("other", pipeline.clone().items[2].outputs[0].file.as_str());
             assert!(!pipeline.clone().items[2].outputs[0].append);
             assert_eq!(input.to_owned(), pipeline.to_string());
         } else {
@@ -744,7 +744,7 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("cat | echo hello | cat < stuff >> other") {
             assert_eq!(3, pipeline.items.len());
             assert_eq!(Input::File("stuff".into()), pipeline.items[2].inputs[0]);
-            assert_eq!("other", pipeline.items[2].outputs[0].file);
+            assert_eq!("other", pipeline.items[2].outputs[0].file.as_str());
             assert!(pipeline.items[2].outputs[0].append);
         } else {
             assert!(false);
@@ -756,8 +756,8 @@ mod tests {
     // '^' while not in the top level
     fn args_loop_terminates() {
         if let Statement::Pipeline(pipeline) = parse("$(^) '$(^)'") {
-            assert_eq!("$(^)", pipeline.items[0].job.args[0]);
-            assert_eq!("\'$(^)\'", pipeline.items[0].job.args[1]);
+            assert_eq!("$(^)", pipeline.items[0].job.args[0].as_str());
+            assert_eq!("\'$(^)\'", pipeline.items[0].job.args[1].as_str());
         } else {
             assert!(false);
         }
@@ -873,7 +873,7 @@ mod tests {
         if let Statement::Pipeline(pipeline) = parse("cat | echo hello | cat > stuff < other") {
             assert_eq!(3, pipeline.items.len());
             assert_eq!(vec![Input::File("other".into())], pipeline.items[2].inputs);
-            assert_eq!("stuff", pipeline.items[2].outputs[0].file);
+            assert_eq!("stuff", pipeline.items[2].outputs[0].file.as_str());
         } else {
             assert!(false);
         }
@@ -883,19 +883,19 @@ mod tests {
     fn var_meets_quote() {
         if let Statement::Pipeline(pipeline) = parse("echo $x '{()}' test") {
             assert_eq!(1, pipeline.items.len());
-            assert_eq!("echo", &pipeline.clone().items[0].job.args[0]);
-            assert_eq!("$x", &pipeline.clone().items[0].job.args[1]);
-            assert_eq!("'{()}'", &pipeline.clone().items[0].job.args[2]);
-            assert_eq!("test", &pipeline.clone().items[0].job.args[3]);
+            assert_eq!("echo", pipeline.clone().items[0].job.args[0].as_str());
+            assert_eq!("$x", pipeline.clone().items[0].job.args[1].as_str());
+            assert_eq!("'{()}'", pipeline.clone().items[0].job.args[2].as_str());
+            assert_eq!("test", pipeline.clone().items[0].job.args[3].as_str());
         } else {
             assert!(false);
         }
 
         if let Statement::Pipeline(pipeline) = parse("echo $x'{()}' test") {
             assert_eq!(1, pipeline.items.len());
-            assert_eq!("echo", &pipeline.clone().items[0].job.args[0]);
-            assert_eq!("$x'{()}'", &pipeline.clone().items[0].job.args[1]);
-            assert_eq!("test", &pipeline.clone().items[0].job.args[2]);
+            assert_eq!("echo", pipeline.clone().items[0].job.args[0].as_str());
+            assert_eq!("$x'{()}'", pipeline.clone().items[0].job.args[1].as_str());
+            assert_eq!("test", pipeline.clone().items[0].job.args[2].as_str());
         } else {
             assert!(false);
         }
@@ -957,14 +957,14 @@ mod tests {
     fn awk_tests() {
         if let Statement::Pipeline(pipeline) = parse("awk -v x=$x '{ if (1) print $1 }' myfile") {
             assert_eq!(1, pipeline.items.len());
-            assert_eq!("awk", &pipeline.clone().items[0].job.args[0]);
-            assert_eq!("-v", &pipeline.clone().items[0].job.args[1]);
-            assert_eq!("x=$x", &pipeline.clone().items[0].job.args[2]);
+            assert_eq!("awk", pipeline.clone().items[0].job.args[0].as_str());
+            assert_eq!("-v", pipeline.clone().items[0].job.args[1].as_str());
+            assert_eq!("x=$x", pipeline.clone().items[0].job.args[2].as_str());
             assert_eq!(
                 "'{ if (1) print $1 }'",
-                &pipeline.clone().items[0].job.args[3]
+                pipeline.clone().items[0].job.args[3].as_str()
             );
-            assert_eq!("myfile", &pipeline.clone().items[0].job.args[4]);
+            assert_eq!("myfile", pipeline.clone().items[0].job.args[4].as_str());
         } else {
             assert!(false);
         }
diff --git a/src/lib/parser/pipelines/mod.rs b/src/lib/parser/pipelines/mod.rs
index 87f03ffec2c1e573a34862f06fb0717bb135fc8a..107be704eab2bcf259ccb1cc249178acd42a1f23 100644
--- a/src/lib/parser/pipelines/mod.rs
+++ b/src/lib/parser/pipelines/mod.rs
@@ -4,6 +4,7 @@ pub(crate) use self::collector::*;
 
 use super::expand_string;
 use shell::{Job, JobKind, Shell};
+use small;
 use std::fmt;
 
 #[derive(Debug, PartialEq, Clone, Copy)]
@@ -16,7 +17,7 @@ pub(crate) enum RedirectFrom {
 #[derive(Debug, PartialEq, Clone)]
 pub(crate) struct Redirection {
     pub from:   RedirectFrom,
-    pub file:   String,
+    pub file:   small::String,
     pub append: bool,
 }
 
@@ -25,10 +26,10 @@ pub(crate) struct Redirection {
 pub(crate) enum Input {
     /// A file; the contents of said file will be written to the `stdin` of a
     /// process
-    File(String),
+    File(small::String),
     /// A string literal that is written to the `stdin` of a process.
     /// If there is a second string, that second string is the EOF phrase for the heredoc.
-    HereString(String),
+    HereString(small::String),
 }
 
 #[derive(Debug, PartialEq, Clone)]
@@ -49,13 +50,13 @@ impl PipeItem {
 
         for input in &mut self.inputs {
             *input = match input {
-                Input::File(ref s) => Input::File(expand_string(s, shell, false).join(" ")),
-                Input::HereString(ref s) => Input::HereString(expand_string(s, shell, true).join(" ")),
+                Input::File(ref s) => Input::File(expand_string(s, shell, false).join(" ").into()),
+                Input::HereString(ref s) => Input::HereString(expand_string(s, shell, true).join(" ").into()),
             };
         }
 
         for output in &mut self.outputs {
-            output.file = expand_string(output.file.as_str(), shell, false).join(" ");
+            output.file = expand_string(output.file.as_str(), shell, false).join(" ").into();
         }
     }
 
@@ -86,7 +87,7 @@ impl Pipeline {
 
 impl fmt::Display for Pipeline {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let mut tokens: Vec<String> = Vec::with_capacity(self.items.len());
+        let mut tokens: Vec<small::String> = Vec::with_capacity(self.items.len());
         for item in &self.items {
             let job = &item.job;
             let kind = job.kind;
diff --git a/src/lib/parser/shell_expand/mod.rs b/src/lib/parser/shell_expand/mod.rs
index 4e4e367db618d8ca03727707905f382ff497b0bc..8e4c468fc9309b2fbffd90b158d6d042585244c3 100644
--- a/src/lib/parser/shell_expand/mod.rs
+++ b/src/lib/parser/shell_expand/mod.rs
@@ -7,8 +7,9 @@ pub(crate) use self::words::{Select, WordIterator, WordToken};
 use braces::{self, BraceToken};
 use ranges::{parse_range, Index, Range};
 use glob::glob;
+use small;
 use std::{ptr, str};
-use types::*;
+use types::{self, Array};
 use unicode_segmentation::UnicodeSegmentation;
 
 /// Determines whether an input string is expression-like as compared to a
@@ -27,15 +28,15 @@ pub(crate) trait Expander {
     /// Expand a tilde form to the correct directory
     fn tilde(&self, &str) -> Option<String> { None }
     /// Expand an array variable with some selection
-    fn array(&self, &str, Select) -> Option<Array> { None }
+    fn array(&self, &str, Select) -> Option<types::Array> { None }
     /// Expand a string variable given if its quoted / unquoted
-    fn string(&self, &str, bool) -> Option<Value> { None }
+    fn string(&self, &str, bool) -> Option<types::Str> { None }
     /// Expand a subshell expression
-    fn command(&self, &str) -> Option<Value> { None }
+    fn command(&self, &str) -> Option<types::Str> { None }
 }
 
 fn expand_process<E: Expander>(
-    current: &mut String,
+    current: &mut small::String,
     command: &str,
     selection: Select,
     expander: &E,
@@ -85,8 +86,8 @@ fn expand_process<E: Expander>(
 }
 
 fn expand_brace<E: Expander>(
-    current: &mut String,
-    expanders: &mut Vec<Vec<String>>,
+    current: &mut small::String,
+    expanders: &mut Vec<Vec<small::String>>,
     tokens: &mut Vec<BraceToken>,
     nodes: &[&str],
     expand_func: &E,
@@ -116,9 +117,9 @@ fn expand_brace<E: Expander>(
     }
 }
 
-fn array_expand<E: Expander>(elements: &[&str], expand_func: &E, selection: Select) -> Array {
+fn array_expand<E: Expander>(elements: &[&str], expand_func: &E, selection: Select) -> types::Array {
     match selection {
-        Select::None => Array::new(),
+        Select::None => types::Array::new(),
         Select::All => elements
             .iter()
             .flat_map(|e| expand_string(e, expand_func, false))
@@ -127,11 +128,11 @@ fn array_expand<E: Expander>(elements: &[&str], expand_func: &E, selection: Sele
             .into_iter()
             .collect(),
         Select::Range(range) => array_range(elements, expand_func, range),
-        Select::Key(_) => Array::new(),
+        Select::Key(_) => types::Array::new(),
     }
 }
 
-fn array_nth<E: Expander>(elements: &[&str], expand_func: &E, index: Index) -> Option<Value> {
+fn array_nth<E: Expander>(elements: &[&str], expand_func: &E, index: Index) -> Option<types::Str> {
     let mut expanded = elements
         .iter()
         .flat_map(|e| expand_string(e, expand_func, false));
@@ -141,20 +142,20 @@ fn array_nth<E: Expander>(elements: &[&str], expand_func: &E, index: Index) -> O
     }
 }
 
-fn array_range<E: Expander>(elements: &[&str], expand_func: &E, range: Range) -> Array {
+fn array_range<E: Expander>(elements: &[&str], expand_func: &E, range: Range) -> types::Array {
     let expanded = elements
         .iter()
         .flat_map(|e| expand_string(e, expand_func, false))
-        .collect::<Array>();
+        .collect::<types::Array>();
     let len = expanded.len();
     if let Some((start, length)) = range.bounds(len) {
         expanded.into_iter().skip(start).take(length).collect()
     } else {
-        Array::new()
+        types::Array::new()
     }
 }
 
-fn slice<S: AsRef<str>>(output: &mut String, expanded: S, selection: Select) {
+fn slice<S: AsRef<str>>(output: &mut small::String, expanded: S, selection: Select) {
     match selection {
         Select::None => (),
         Select::All => output.push_str(expanded.as_ref()),
@@ -192,7 +193,7 @@ pub(crate) fn expand_string<E: Expander>(
     original: &str,
     expand_func: &E,
     reverse_quoting: bool,
-) -> Array {
+) -> types::Array {
     let mut token_buffer = Vec::new();
     let mut contains_brace = false;
     let mut word_iterator = WordIterator::new(original, expand_func, true);
@@ -244,7 +245,7 @@ fn expand_string_no_glob<E: Expander>(
     original: &str,
     expand_func: &E,
     reverse_quoting: bool,
-) -> Array {
+) -> types::Array {
     let mut token_buffer = Vec::new();
     let mut contains_brace = false;
     let mut word_iterator = WordIterator::new(original, expand_func, false);
@@ -271,11 +272,11 @@ fn expand_braces<E: Expander>(
     word_tokens: &[WordToken],
     expand_func: &E,
     reverse_quoting: bool,
-) -> Array {
-    let mut expanded_words = Array::new();
-    let mut output = String::new();
+) -> types::Array {
+    let mut expanded_words = types::Array::new();
+    let mut output = small::String::new();
     let tokens: &mut Vec<BraceToken> = &mut Vec::new();
-    let mut expanders: Vec<Vec<String>> = Vec::new();
+    let mut expanders: Vec<Vec<small::String>> = Vec::new();
 
     for word in word_tokens {
         match *word {
@@ -290,23 +291,23 @@ fn expand_braces<E: Expander>(
             WordToken::ArrayProcess(command, _, ref index) => match *index {
                 Select::None => (),
                 Select::All => {
-                    let mut temp = String::new();
+                    let mut temp = small::String::new();
                     expand_process(&mut temp, command, Select::All, expand_func, false);
                     let temp = temp.split_whitespace().collect::<Vec<&str>>();
                     output.push_str(&temp.join(" "));
                 }
                 Select::Index(Index::Forward(id)) => {
-                    let mut temp = String::new();
+                    let mut temp = small::String::new();
                     expand_process(&mut temp, command, Select::All, expand_func, false);
                     output.push_str(temp.split_whitespace().nth(id).unwrap_or_default());
                 }
                 Select::Index(Index::Backward(id)) => {
-                    let mut temp = String::new();
+                    let mut temp = small::String::new();
                     expand_process(&mut temp, command, Select::All, expand_func, false);
                     output.push_str(temp.split_whitespace().rev().nth(id).unwrap_or_default());
                 }
                 Select::Range(range) => {
-                    let mut temp = String::new();
+                    let mut temp = small::String::new();
                     expand_process(&mut temp, command, Select::All, expand_func, false);
                     let len = temp.split_whitespace().count();
                     if let Some((start, length)) = range.bounds(len) {
@@ -362,7 +363,7 @@ fn expand_braces<E: Expander>(
         }
     }
     if expanders.is_empty() {
-        expanded_words.push(output);
+        expanded_words.push(output.into());
     } else {
         if !output.is_empty() {
             tokens.push(BraceToken::Normal(output));
@@ -377,22 +378,22 @@ fn expand_braces<E: Expander>(
         }
     }
 
-    expanded_words.into_iter().fold(Array::new(), |mut array, word| {
+    expanded_words.into_iter().fold(types::Array::new(), |mut array, word| {
         if word.find('*').is_some() {
             if let Ok(mut paths) = glob(&word) {
                 match paths.next() {
                     Some(path) => if let Ok(path_buf) = path {
-                        array.push(path_buf.to_string_lossy().to_string());
+                        array.push((*path_buf.to_string_lossy()).into());
                     } else {
-                        array.push(String::new());
+                        array.push("".into());
                     },
                     None => array.push(word),
                 }
                 for path in paths {
                     if let Ok(path_buf) = path {
-                        array.push(path_buf.to_string_lossy().to_string());
+                        array.push((*path_buf.to_string_lossy()).into());
                     } else {
-                        array.push(String::new());
+                        array.push("".into());
                     }
                 }
             } else {
@@ -406,24 +407,24 @@ fn expand_braces<E: Expander>(
     })
 }
 
-fn expand_single_array_token<E: Expander>(token: &WordToken, expand_func: &E) -> Option<Array> {
-    let mut output = String::new();
+fn expand_single_array_token<E: Expander>(token: &WordToken, expand_func: &E) -> Option<types::Array> {
+    let mut output = small::String::new();
     match *token {
         WordToken::Array(ref elements, ref index) => {
             Some(array_expand(elements, expand_func, index.clone()))
         }
         WordToken::ArrayVariable(array, quoted, ref index) => {
             match expand_func.array(array, index.clone()) {
-                Some(ref array) if quoted => Some(array.join(" ").into()).into_iter().collect(),
+                Some(ref array) if quoted => ::std::iter::once(Some(small::String::from(array.join(" ")))).collect(),
                 Some(array) => Some(array),
-                None => Some(Array::new()),
+                None => Some(types::Array::new()),
             }
         }
         WordToken::ArrayProcess(command, _, ref index) => match *index {
-            Select::None => Some(Array::new()),
+            Select::None => Some(types::Array::new()),
             Select::All => {
                 expand_process(&mut output, command, Select::All, expand_func, false);
-                Some(output.split_whitespace().map(From::from).collect::<Array>())
+                Some(output.split_whitespace().map(From::from).collect::<types::Array>())
             }
             Select::Index(Index::Forward(id)) => {
                 expand_process(&mut output, command, Select::All, expand_func, false);
@@ -460,10 +461,10 @@ fn expand_single_array_token<E: Expander>(token: &WordToken, expand_func: &E) ->
                             .collect(),
                     )
                 } else {
-                    Some(Array::new())
+                    Some(types::Array::new())
                 }
             }
-            Select::Key(_) => Some(Array::new()),
+            Select::Key(_) => Some(types::Array::new()),
         },
         WordToken::ArrayMethod(ref array_method) => Some(array_method.handle_as_array(expand_func)),
         _ => None,
@@ -474,9 +475,9 @@ fn expand_single_string_token<E: Expander>(
     token: &WordToken,
     expand_func: &E,
     reverse_quoting: bool,
-) -> Array {
-    let mut output = String::new();
-    let mut expanded_words = Array::new();
+) -> types::Array {
+    let mut output = small::String::new();
+    let mut expanded_words = types::Array::new();
 
     match *token {
         WordToken::StringMethod(ref method) => method.handle(&mut output, expand_func),
@@ -500,7 +501,7 @@ fn expand_single_string_token<E: Expander>(
             let expanded = match expand_func.string(text, quoted) {
                 Some(var) => var,
                 None => {
-                    if output != "" {
+                    if output.as_str() != "" {
                         expanded_words.push(output);
                     }
                     return expanded_words;
@@ -513,23 +514,23 @@ fn expand_single_string_token<E: Expander>(
         _ => unreachable!(),
     }
 
-    if output != "" {
+    if output.as_str() != "" {
         expanded_words.push(output.into());
     }
     expanded_words
 }
 
 fn expand<E: Expander>(
-    output: &mut String,
-    expanded_words: &mut Array,
+    output: &mut small::String,
+    expanded_words: &mut types::Array,
     expand_func: &E,
     text: &str,
     do_glob: bool,
     tilde: bool,
 ) {
-    let expanded: String = if tilde {
+    let expanded: small::String = if tilde {
         match expand_func.tilde(text) {
-            Some(s) => s,
+            Some(s) => s.into(),
             None => text.into(),
         }
     } else {
@@ -542,7 +543,7 @@ fn expand<E: Expander>(
                 let mut globs_found = false;
                 for path in var.filter_map(Result::ok) {
                     globs_found = true;
-                    expanded_words.push(path.to_string_lossy().into_owned());
+                    expanded_words.push(path.to_string_lossy().as_ref().into());
                 }
                 if !globs_found {
                     expanded_words.push(expanded);
@@ -560,7 +561,7 @@ pub(crate) fn expand_tokens<E: Expander>(
     expand_func: &E,
     reverse_quoting: bool,
     contains_brace: bool,
-) -> Array {
+) -> types::Array {
     if !token_buffer.is_empty() {
         if contains_brace {
             return expand_braces(&token_buffer, expand_func, reverse_quoting);
@@ -572,8 +573,8 @@ pub(crate) fn expand_tokens<E: Expander>(
             };
         }
 
-        let mut output = String::new();
-        let mut expanded_words = Array::new();
+        let mut output = small::String::new();
+        let mut expanded_words = types::Array::new();
 
         for word in token_buffer {
             match *word {
@@ -588,23 +589,23 @@ pub(crate) fn expand_tokens<E: Expander>(
                 WordToken::ArrayProcess(command, _, ref index) => match index.clone() {
                     Select::None => (),
                     Select::All => {
-                        let mut temp = String::new();
+                        let mut temp = small::String::new();
                         expand_process(&mut temp, command, Select::All, expand_func, false);
                         let temp = temp.split_whitespace().collect::<Vec<&str>>();
                         output.push_str(&temp.join(" "));
                     }
                     Select::Index(Index::Forward(id)) => {
-                        let mut temp = String::new();
+                        let mut temp = small::String::new();
                         expand_process(&mut temp, command, Select::All, expand_func, false);
                         output.push_str(temp.split_whitespace().nth(id).unwrap_or_default());
                     }
                     Select::Index(Index::Backward(id)) => {
-                        let mut temp = String::new();
+                        let mut temp = small::String::new();
                         expand_process(&mut temp, command, Select::All, expand_func, false);
                         output.push_str(temp.split_whitespace().rev().nth(id).unwrap_or_default());
                     }
                     Select::Range(range) => {
-                        let mut temp = String::new();
+                        let mut temp = small::String::new();
                         expand_process(&mut temp, command, Select::All, expand_func, false);
                         if let Some((start, length)) = range.bounds(temp.split_whitespace().count())
                         {
@@ -655,7 +656,7 @@ pub(crate) fn expand_tokens<E: Expander>(
             }
         }
         // I'm not entirely sure if empty strings are valid in any case- maarten
-        if output != "" {
+        if output.as_str() != "" {
             expanded_words.push(output);
         }
         expanded_words
@@ -669,10 +670,10 @@ pub(crate) fn expand_tokens<E: Expander>(
 /// x * 5 + y => 22
 /// ```
 /// if `x=5` and `y=7`
-fn expand_arithmetic<E: Expander>(output: &mut String, input: &str, expander: &E) {
-    let mut intermediate = String::with_capacity(input.as_bytes().len());
-    let mut varbuf = String::new();
-    let flush = |var: &mut String, out: &mut String| {
+fn expand_arithmetic<E: Expander>(output: &mut small::String, input: &str, expander: &E) {
+    let mut intermediate = small::String::with_capacity(input.as_bytes().len());
+    let mut varbuf = small::String::new();
+    let flush = |var: &mut small::String, out: &mut small::String| {
         if !var.is_empty() {
             // We have reached the end of a potential variable, so we expand it and push
             // it onto the result
@@ -714,14 +715,14 @@ mod test {
     struct VariableExpander;
 
     impl Expander for VariableExpander {
-        fn string(&self, variable: &str, _: bool) -> Option<Value> {
+        fn string(&self, variable: &str, _: bool) -> Option<types::Str> {
             match variable {
-                "A" => Some("1".to_owned()),
-                "B" => Some("test".to_owned()),
-                "C" => Some("ing".to_owned()),
-                "D" => Some("1 2 3".to_owned()),
-                "FOO" => Some("FOO".to_owned()),
-                "BAR" => Some("BAR".to_owned()),
+                "A" => Some("1".into()),
+                "B" => Some("test".into()),
+                "C" => Some("ing".into()),
+                "D" => Some("1 2 3".into()),
+                "FOO" => Some("FOO".into()),
+                "BAR" => Some("BAR".into()),
                 _ => None,
             }
         }
@@ -730,23 +731,23 @@ mod test {
     struct CommandExpander;
 
     impl Expander for CommandExpander {
-        fn command(&self, cmd: &str) -> Option<Value> { Some(cmd.to_owned()) }
+        fn command(&self, cmd: &str) -> Option<types::Str> { Some(cmd.into()) }
     }
 
     #[test]
     fn expand_process_quoted() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let line = " Mary   had\ta little  \n\t lamb\t";
         expand_process(&mut output, line, Select::All, &CommandExpander, true);
-        assert_eq!(output, line);
+        assert_eq!(output.as_str(), line);
     }
 
     #[test]
     fn expand_process_unquoted() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let line = " Mary   had\ta little  \n\t lamb\t";
         expand_process(&mut output, line, Select::All, &CommandExpander, false);
-        assert_eq!(output, "Mary had a little lamb");
+        assert_eq!(output.as_str(), "Mary had a little lamb");
     }
 
     #[test]
@@ -766,8 +767,8 @@ mod test {
         assert_eq!(
             expected
                 .split_whitespace()
-                .map(|x| x.to_owned())
-                .collect::<Array>(),
+                .map(|x| x.into())
+                .collect::<types::Array>(),
             expanded
         );
     }
@@ -780,8 +781,8 @@ mod test {
         assert_eq!(
             expected
                 .split_whitespace()
-                .map(|x| x.to_owned())
-                .collect::<Array>(),
+                .map(|x| x.into())
+                .collect::<types::Array>(),
             expanded
         );
     }
@@ -833,7 +834,7 @@ mod test {
             }
         }
         {
-            let expected = Array::new();
+            let expected = types::Array::new();
             let idxs = vec!["-17", "4..-4"];
             for idx in idxs {
                 assert_eq!(expected, expand_string(&base(idx), &expander, false));
diff --git a/src/lib/parser/shell_expand/words/methods/arrays.rs b/src/lib/parser/shell_expand/words/methods/arrays.rs
index ad12232c95c6d759fd85d1835a3515cae595e893..77428336f40765a193dd499ac2f19b1eddfd6876 100644
--- a/src/lib/parser/shell_expand/words/methods/arrays.rs
+++ b/src/lib/parser/shell_expand/words/methods/arrays.rs
@@ -5,9 +5,9 @@ use super::{
     strings::unescape, Pattern,
 };
 use ranges::Index;
-use smallstring::SmallString;
+use small;
 use std::char;
-use types::Array;
+use types::{self, Array};
 use unicode_segmentation::UnicodeSegmentation;
 
 #[derive(Debug, PartialEq, Clone)]
@@ -30,8 +30,7 @@ impl<'a> ArrayMethod<'a> {
         Ok(variable
             .lines()
             .into_iter()
-            .map(|line| line.to_string())
-            .collect())
+            .map(|line| types::Str::from(line)) .collect())
     }
 
     fn chars<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> {
@@ -39,7 +38,7 @@ impl<'a> ArrayMethod<'a> {
         let len = variable.chars().count();
         Ok(variable
             .chars()
-            .map(|c| c.to_string())
+            .map(|c| types::Str::from(c.to_string()))
             .select(self.selection.clone(), len))
     }
 
@@ -48,13 +47,13 @@ impl<'a> ArrayMethod<'a> {
         let len = variable.as_bytes().len();
         Ok(variable
             .bytes()
-            .map(|b| b.to_string())
+            .map(|b| types::Str::from(b.to_string()))
             .select(self.selection.clone(), len))
     }
 
     fn graphemes<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> {
         let variable = self.resolve_var(expand_func);
-        let graphemes: Vec<String> = UnicodeSegmentation::graphemes(variable.as_str(), true)
+        let graphemes: Vec<types::Str> = UnicodeSegmentation::graphemes(variable.as_str(), true)
             .map(From::from)
             .collect();
         let len = graphemes.len();
@@ -71,7 +70,7 @@ impl<'a> ArrayMethod<'a> {
             {
                 if value < variable.len() {
                     let (l, r) = variable.split_at(value);
-                    Ok(array![SmallString::from(l), SmallString::from(r)])
+                    Ok(array![types::Str::from(l), types::Str::from(r)])
                 } else {
                     Err("value is out of bounds")
                 }
@@ -87,9 +86,9 @@ impl<'a> ArrayMethod<'a> {
         let res = match (&self.pattern, self.selection.clone()) {
             (_, Select::None) => Some("".into()).into_iter().collect(),
             (&Pattern::StringPattern(pattern), Select::All) => variable
-                .split(&unescape(
+                .split(unescape(
                     &expand_string(pattern, expand_func, false).join(" ")
-                )?)
+                )?.as_str())
                 .map(From::from)
                 .collect(),
             (&Pattern::Whitespace, Select::All) => variable
@@ -100,7 +99,7 @@ impl<'a> ArrayMethod<'a> {
             (&Pattern::StringPattern(pattern), Select::Index(Index::Forward(id))) => variable
                 .split(&unescape(
                     &expand_string(pattern, expand_func, false).join(" ")
-                )?)
+                )?.as_str())
                 .nth(id)
                 .map(From::from)
                 .into_iter()
@@ -115,7 +114,7 @@ impl<'a> ArrayMethod<'a> {
             (&Pattern::StringPattern(pattern), Select::Index(Index::Backward(id))) => variable
                 .rsplit(&unescape(
                     &expand_string(pattern, expand_func, false).join(" ")
-                )?)
+                )?.as_str())
                 .nth(id)
                 .map(From::from)
                 .into_iter()
@@ -129,7 +128,7 @@ impl<'a> ArrayMethod<'a> {
                 .collect(),
             (&Pattern::StringPattern(pattern), Select::Range(range)) => {
                 let expansion = unescape(&expand_string(pattern, expand_func, false).join(" "))?;
-                let iter = variable.split(&expansion);
+                let iter = variable.split(expansion.as_str());
                 if let Some((start, length)) = range.bounds(iter.clone().count()) {
                     iter.skip(start).take(length).map(From::from).collect()
                 } else {
@@ -170,11 +169,11 @@ impl<'a> ArrayMethod<'a> {
     }
 
     #[inline]
-    fn resolve_var<E: Expander>(&self, expand_func: &E) -> String {
+    fn resolve_var<E: Expander>(&self, expand_func: &E) -> types::Str {
         if let Some(variable) = expand_func.string(self.variable, false) {
             variable
         } else if is_expression(self.variable) {
-            expand_string(self.variable, expand_func, false).join(" ")
+            types::Str::from_string(expand_string(self.variable, expand_func, false).join(" "))
         } else {
             "".into()
         }
@@ -198,7 +197,7 @@ impl<'a> ArrayMethod<'a> {
         })
     }
 
-    pub(crate) fn handle<E: Expander>(&self, current: &mut String, expand_func: &E) {
+    pub(crate) fn handle<E: Expander>(&self, current: &mut small::String, expand_func: &E) {
         let res = match self.method {
             "split" => self.split(expand_func).map(|r| r.join(" ")),
             _ => Err("invalid array method"),
@@ -214,23 +213,23 @@ impl<'a> ArrayMethod<'a> {
 mod test {
     use super::*;
     use ranges::Range;
-    use types::Value;
+    use types;
 
     struct VariableExpander;
 
     impl Expander for VariableExpander {
-        fn array(&self, variable: &str, _: Select) -> Option<Array> {
+        fn array(&self, variable: &str, _: Select) -> Option<types::Array> {
             match variable {
                 "ARRAY" => Some(array!["a", "b", "c"].to_owned()),
                 _ => None,
             }
         }
 
-        fn string(&self, variable: &str, _: bool) -> Option<Value> {
+        fn string(&self, variable: &str, _: bool) -> Option<types::Str> {
             match variable {
-                "FOO" => Some("FOOBAR".to_owned()),
-                "SPACEDFOO" => Some("FOO BAR".to_owned()),
-                "MULTILINE" => Some("FOO\nBAR".to_owned()),
+                "FOO" => Some("FOOBAR".into()),
+                "SPACEDFOO" => Some("FOO BAR".into()),
+                "MULTILINE" => Some("FOO\nBAR".into()),
                 _ => None,
             }
         }
@@ -238,7 +237,7 @@ mod test {
 
     #[test]
     fn test_split_string_all() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$FOO",
@@ -246,12 +245,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FO AR");
+        assert_eq!(&*output, "FO AR");
     }
 
     #[test]
     fn test_split_whitespace_all() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$SPACEDFOO",
@@ -259,12 +258,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FOO BAR");
+        assert_eq!(&*output, "FOO BAR");
     }
 
     #[test]
     fn test_split_string_index_forward() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$FOO",
@@ -272,12 +271,12 @@ mod test {
             selection: Select::Index(Index::Forward(1)),
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "AR");
+        assert_eq!(&*output, "AR");
     }
 
     #[test]
     fn test_split_whitespace_index_forward() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$SPACEDFOO",
@@ -285,12 +284,12 @@ mod test {
             selection: Select::Index(Index::Forward(1)),
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "BAR");
+        assert_eq!(&*output, "BAR");
     }
 
     #[test]
     fn test_split_string_index_backward() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$FOO",
@@ -298,12 +297,12 @@ mod test {
             selection: Select::Index(Index::Backward(1)),
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FO");
+        assert_eq!(&*output, "FO");
     }
 
     #[test]
     fn test_split_whitespace_index_backward() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$SPACEDFOO",
@@ -311,12 +310,12 @@ mod test {
             selection: Select::Index(Index::Backward(1)),
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FOO");
+        assert_eq!(&*output, "FOO");
     }
 
     #[test]
     fn test_split_string_range() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$FOO",
@@ -324,12 +323,12 @@ mod test {
             selection: Select::Range(Range::from(Index::Forward(0))),
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FO AR");
+        assert_eq!(&*output, "FO AR");
     }
 
     #[test]
     fn test_split_whitespace_range() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$SPACEDFOO",
@@ -337,12 +336,12 @@ mod test {
             selection: Select::Range(Range::from(Index::Forward(0))),
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FOO BAR");
+        assert_eq!(&*output, "FOO BAR");
     }
 
     #[test]
     fn test_split_none() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$SPACEDFOO",
@@ -350,12 +349,12 @@ mod test {
             selection: Select::None,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "");
+        assert_eq!(&*output, "");
     }
 
     #[test]
     fn test_split_key() {
-        let mut output = String::new();
+        let mut output = types::Str::new();
         let method = ArrayMethod {
             method:    "split",
             variable:  "$SPACEDFOO",
@@ -363,7 +362,7 @@ mod test {
             selection: Select::Key("1".into()),
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "");
+        assert_eq!(&*output, "");
     }
 
     #[test]
diff --git a/src/lib/parser/shell_expand/words/methods/mod.rs b/src/lib/parser/shell_expand/words/methods/mod.rs
index 23de3a8b5f6eaf89f1f011b5d0e80652364b9ba1..2068be11738c2367323cff6d9ac6ab0dbb2d50b4 100644
--- a/src/lib/parser/shell_expand/words/methods/mod.rs
+++ b/src/lib/parser/shell_expand/words/methods/mod.rs
@@ -6,6 +6,7 @@ use self::strings::unescape;
 
 use lexers::ArgumentSplitter;
 use super::{expand_string, Expander};
+use small;
 
 #[derive(Debug, PartialEq, Clone)]
 pub(crate) enum Pattern<'a> {
@@ -20,15 +21,15 @@ pub(crate) struct MethodArgs<'a, 'b, E: 'b + Expander> {
 }
 
 impl<'a, 'b, E: 'b + Expander> MethodArgs<'a, 'b, E> {
-    pub(crate) fn array<'c>(&'c self) -> impl Iterator<Item = String> + 'c {
+    pub(crate) fn array<'c>(&'c self) -> impl Iterator<Item = small::String> + 'c {
         ArgumentSplitter::new(self.args)
             .flat_map(move |x| expand_string(x, self.expand, false).into_iter())
-            .map(|s| unescape(&s).unwrap_or_else(|_| String::from("")))
+            .map(|s| unescape(&s).unwrap_or_else(|_| small::String::from("")))
     }
 
-    pub(crate) fn join(self, pattern: &str) -> String {
+    pub(crate) fn join(self, pattern: &str) -> small::String {
         unescape(&expand_string(self.args, self.expand, false).join(pattern))
-            .unwrap_or_else(|_| String::from(""))
+            .unwrap_or_else(|_| small::String::from(""))
     }
 
     pub(crate) fn new(args: &'a str, expand: &'b E) -> MethodArgs<'a, 'b, E> {
diff --git a/src/lib/parser/shell_expand/words/methods/strings.rs b/src/lib/parser/shell_expand/words/methods/strings.rs
index e8f0685281a855613652b0362b26fcd7dca6e084..e6e3c62facedf64932bcf07c41bffa3b7164c65a 100644
--- a/src/lib/parser/shell_expand/words/methods/strings.rs
+++ b/src/lib/parser/shell_expand/words/methods/strings.rs
@@ -8,6 +8,7 @@ use parser::assignments::is_array;
 use regex::Regex;
 use shell::plugins::methods::{self, MethodArguments, StringMethodPlugins};
 use std::path::Path;
+use small;
 use sys;
 use unicode_segmentation::UnicodeSegmentation;
 
@@ -15,10 +16,10 @@ lazy_static! {
     static ref STRING_METHODS: StringMethodPlugins = methods::collect();
 }
 
-pub(crate) fn unescape(input: &str) -> Result<String, &'static str> {
+pub(crate) fn unescape(input: &str) -> Result<small::String, &'static str> {
     let mut check = false;
-    let mut out = String::with_capacity(input.len());
-    let add_char = |out: &mut String, check: &mut bool, c| {
+    let mut out = small::String::with_capacity(input.len());
+    let add_char = |out: &mut small::String, check: &mut bool, c| {
         out.push(c);
         *check = false;
     };
@@ -33,7 +34,7 @@ pub(crate) fn unescape(input: &str) -> Result<String, &'static str> {
             'a' if check => add_char(&mut out, &mut check, '\u{0007}'),
             'b' if check => add_char(&mut out, &mut check, '\u{0008}'),
             'c' if check => {
-                out = String::from("");
+                out = small::String::from("");
                 break;
             }
             'e' if check => add_char(&mut out, &mut check, '\u{001B}'),
@@ -97,7 +98,7 @@ pub(crate) struct StringMethod<'a> {
 }
 
 impl<'a> StringMethod<'a> {
-    pub(crate) fn handle<E: Expander>(&self, output: &mut String, expand: &E) {
+    pub(crate) fn handle<E: Expander>(&self, output: &mut small::String, expand: &E) {
         let variable = self.variable;
         let pattern = MethodArgs::new(self.pattern, expand);
 
@@ -105,11 +106,11 @@ impl<'a> StringMethod<'a> {
             ($variable:ident $method:tt) => {{
                 let pattern = pattern.join(" ");
                 let is_true = if let Some(value) = expand.string($variable, false) {
-                    value.$method(&pattern)
+                    value.$method(pattern.as_str())
                 } else if is_expression($variable) {
                     expand_string($variable, expand, false)
                         .join(" ")
-                        .$method(&pattern)
+                        .$method(pattern.as_str())
                 } else {
                     false
                 };
@@ -121,7 +122,7 @@ impl<'a> StringMethod<'a> {
             ($method:tt) => {{
                 if let Some(value) = expand.string(variable, false) {
                     output.push_str(
-                        Path::new(&value)
+                        Path::new(&*value)
                             .$method()
                             .and_then(|os_str| os_str.to_str())
                             .unwrap_or(value.as_str()),
@@ -154,7 +155,7 @@ impl<'a> StringMethod<'a> {
                 if let Some(value) = expand.string(variable, false) {
                     value
                 } else {
-                    expand_string(variable, expand, false).join(" ")
+                    small::String::from(expand_string(variable, expand, false).join(" "))
                 }
             }};
         }
@@ -179,7 +180,7 @@ impl<'a> StringMethod<'a> {
                 let mut args = pattern.array();
                 match (args.next(), args.next()) {
                     (Some(replace), Some(with)) => {
-                        let res = &get_var!().replace(&replace, &with);
+                        let res = &get_var!().replace(replace.as_str(), &with);
                         output.push_str(res);
                     }
                     _ => eprintln!("ion: replace: two arguments are required"),
@@ -190,7 +191,7 @@ impl<'a> StringMethod<'a> {
                 match (args.next(), args.next(), args.next()) {
                     (Some(replace), Some(with), Some(nth)) => if let Ok(nth) = nth.parse::<usize>()
                     {
-                        let res = &get_var!().replacen(&replace, &with, nth);
+                        let res = &get_var!().replacen(replace.as_str(), &with, nth);
                         output.push_str(res);
                     } else {
                         eprintln!("ion: replacen: third argument isn't a valid integer");
@@ -254,11 +255,11 @@ impl<'a> StringMethod<'a> {
             },
             "find" => {
                 let out = if let Some(value) = expand.string(variable, false) {
-                    value.find(&pattern.join(" "))
+                    value.find(pattern.join(" ").as_str())
                 } else if is_expression(variable) {
                     expand_string(variable, expand, false)
                         .join(" ")
-                        .find(&pattern.join(" "))
+                        .find(pattern.join(" ").as_str())
                 } else {
                     None
                 };
@@ -268,7 +269,7 @@ impl<'a> StringMethod<'a> {
                 let out = if let Some(value) = expand.string(variable, false) {
                     value
                 } else if is_expression(variable) {
-                    expand_string(variable, expand, false).join(" ")
+                    expand_string(variable, expand, false).join(" ").into()
                 } else {
                     return;
                 };
@@ -281,7 +282,7 @@ impl<'a> StringMethod<'a> {
                 let word = if let Some(value) = expand.string(variable, false) {
                     value
                 } else if is_expression(variable) {
-                    expand_string(variable, expand, false).join(" ")
+                    expand_string(variable, expand, false).join(" ").into()
                 } else {
                     return;
                 };
@@ -328,14 +329,14 @@ impl<'a> StringMethod<'a> {
 #[cfg(test)]
 mod test {
     use super::*;
-    use types::Value;
+    use types;
 
     struct VariableExpander;
 
     impl Expander for VariableExpander {
-        fn string(&self, variable: &str, _: bool) -> Option<Value> {
+        fn string(&self, variable: &str, _: bool) -> Option<types::Str> {
             match variable {
-                "FOO" => Some("FOOBAR".to_owned()),
+                "FOO" => Some("FOOBAR".into()),
                 _ => None,
             }
         }
@@ -357,7 +358,7 @@ mod test {
 
     #[test]
     fn test_ends_with_succeeding() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "ends_with",
             variable:  "$FOO",
@@ -365,12 +366,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "1");
+        assert_eq!(&*output, "1");
     }
 
     #[test]
     fn test_ends_with_failing() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "ends_with",
             variable:  "$FOO",
@@ -378,12 +379,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "0");
+        assert_eq!(&*output, "0");
     }
 
     #[test]
     fn test_contains_succeeding() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "contains",
             variable:  "$FOO",
@@ -391,12 +392,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "1");
+        assert_eq!(&*output, "1");
     }
 
     #[test]
     fn test_contains_failing() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "contains",
             variable:  "$FOO",
@@ -404,12 +405,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "0");
+        assert_eq!(&*output, "0");
     }
 
     #[test]
     fn test_starts_with_succeeding() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "starts_with",
             variable:  "$FOO",
@@ -417,12 +418,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "1");
+        assert_eq!(&*output, "1");
     }
 
     #[test]
     fn test_starts_with_failing() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "starts_with",
             variable:  "$FOO",
@@ -430,12 +431,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "0");
+        assert_eq!(&*output, "0");
     }
 
     #[test]
     fn test_basename() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "basename",
             variable:  "\"/home/redox/file.txt\"",
@@ -443,12 +444,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "file.txt");
+        assert_eq!(&*output, "file.txt");
     }
 
     #[test]
     fn test_extension() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "extension",
             variable:  "\"/home/redox/file.txt\"",
@@ -456,12 +457,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "txt");
+        assert_eq!(&*output, "txt");
     }
 
     #[test]
     fn test_filename() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "filename",
             variable:  "\"/home/redox/file.txt\"",
@@ -469,12 +470,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "file");
+        assert_eq!(&*output, "file");
     }
 
     #[test]
     fn test_parent() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "parent",
             variable:  "\"/home/redox/file.txt\"",
@@ -482,12 +483,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "/home/redox");
+        assert_eq!(&*output, "/home/redox");
     }
 
     #[test]
     fn test_to_lowercase() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "to_lowercase",
             variable:  "\"Ford Prefect\"",
@@ -495,12 +496,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "ford prefect");
+        assert_eq!(&*output, "ford prefect");
     }
 
     #[test]
     fn test_to_uppercase() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "to_uppercase",
             variable:  "\"Ford Prefect\"",
@@ -508,12 +509,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FORD PREFECT");
+        assert_eq!(&*output, "FORD PREFECT");
     }
 
     #[test]
     fn test_repeat_succeeding() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "repeat",
             variable:  "$FOO",
@@ -521,12 +522,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FOOBARFOOBAR");
+        assert_eq!(&*output, "FOOBARFOOBAR");
     }
 
     #[test]
     fn test_repeat_failing() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "repeat",
             variable:  "$FOO",
@@ -534,12 +535,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "");
+        assert_eq!(&*output, "");
     }
 
     #[test]
     fn test_replace_succeeding() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "replace",
             variable:  "$FOO",
@@ -547,12 +548,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "BARBAR");
+        assert_eq!(&*output, "BARBAR");
     }
 
     #[test]
     fn test_replace_failing() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "replace",
             variable:  "$FOO",
@@ -560,12 +561,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "");
+        assert_eq!(&*output, "");
     }
 
     #[test]
     fn test_replacen_succeeding() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "replacen",
             variable:  "\"FOO$FOO\"",
@@ -573,12 +574,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "BARFOOBAR");
+        assert_eq!(&*output, "BARFOOBAR");
     }
 
     #[test]
     fn test_replacen_failing() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "replacen",
             variable:  "$FOO",
@@ -586,12 +587,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "");
+        assert_eq!(&*output, "");
     }
 
     #[test]
     fn test_regex_replace_succeeding() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "regex_replace",
             variable:  "$FOO",
@@ -599,12 +600,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "fOOBAR");
+        assert_eq!(&*output, "fOOBAR");
     }
 
     #[test]
     fn test_regex_replace_failing() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "regex_replace",
             variable:  "$FOO",
@@ -612,12 +613,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FOOBAR");
+        assert_eq!(&*output, "FOOBAR");
     }
 
     #[test]
     fn test_join_with_string() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "join",
             variable:  "[\"FOO\" \"BAR\"]",
@@ -625,12 +626,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FOO BAR");
+        assert_eq!(&*output, "FOO BAR");
     }
 
     #[test]
     fn test_join_with_array() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "join",
             variable:  "[\"FOO\" \"BAR\"]",
@@ -638,12 +639,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "FOO- -BAR");
+        assert_eq!(&*output, "FOO- -BAR");
     }
 
     #[test]
     fn test_len_with_array() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "len",
             variable:  "[\"1\"]",
@@ -651,12 +652,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "1");
+        assert_eq!(&*output, "1");
     }
 
     #[test]
     fn test_len_with_string() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "len",
             variable:  "\"FOO\"",
@@ -664,12 +665,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "3");
+        assert_eq!(&*output, "3");
     }
 
     #[test]
     fn test_len_with_variable() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "len",
             variable:  "$FOO",
@@ -677,12 +678,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "6");
+        assert_eq!(&*output, "6");
     }
 
     #[test]
     fn test_len_bytes_with_variable() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "len_bytes",
             variable:  "$FOO",
@@ -690,12 +691,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "6");
+        assert_eq!(&*output, "6");
     }
 
     #[test]
     fn test_len_bytes_with_string() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "len_bytes",
             variable:  "\"oh là là\"",
@@ -703,12 +704,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "10");
+        assert_eq!(&*output, "10");
     }
 
     #[test]
     fn test_reverse_with_variable() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "reverse",
             variable:  "$FOO",
@@ -716,12 +717,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "RABOOF");
+        assert_eq!(&*output, "RABOOF");
     }
 
     #[test]
     fn test_reverse_with_string() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "reverse",
             variable:  "\"FOOBAR\"",
@@ -729,12 +730,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "RABOOF");
+        assert_eq!(&*output, "RABOOF");
     }
 
     #[test]
     fn test_find_succeeding() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "find",
             variable:  "$FOO",
@@ -742,12 +743,12 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "1");
+        assert_eq!(&*output, "1");
     }
 
     #[test]
     fn test_find_failing() {
-        let mut output = String::new();
+        let mut output = small::String::new();
         let method = StringMethod {
             method:    "find",
             variable:  "$FOO",
@@ -755,6 +756,6 @@ mod test {
             selection: Select::All,
         };
         method.handle(&mut output, &VariableExpander);
-        assert_eq!(output, "-1");
+        assert_eq!(&*output, "-1");
     }
 }
diff --git a/src/lib/parser/shell_expand/words/tests.rs b/src/lib/parser/shell_expand/words/tests.rs
index 02dea66f1e5214e4f82b993eac3e415d29bdea51..b4ac797ed4f95400204dd06e8706bc9c5de7d789 100644
--- a/src/lib/parser/shell_expand/words/tests.rs
+++ b/src/lib/parser/shell_expand/words/tests.rs
@@ -1,5 +1,5 @@
 use super::*;
-use types::{Array, Value};
+use types::{self, Array};
 use ranges::{Index, Range};
 
 struct Empty;
@@ -264,10 +264,10 @@ fn test_braces() {
 struct WithVars;
 
 impl Expander for WithVars {
-    fn string(&self, var: &str, _: bool) -> Option<Value> {
+    fn string(&self, var: &str, _: bool) -> Option<types::Str> {
         match var {
-            "pkmn1" => "Pokémon".to_owned().into(),
-            "pkmn2" => "Poke\u{0301}mon".to_owned().into(),
+            "pkmn1" => Some("Pokémon".into()),
+            "pkmn2" => Some("Poke\u{0301}mon".into()),
             _ => None,
         }
     }
diff --git a/src/lib/parser/statement/parse.rs b/src/lib/parser/statement/parse.rs
index 35750efc5cd619cadc9932414772aafa9fd2c052..33b3153599f4ff07aaa36789b6d024a93891482a 100644
--- a/src/lib/parser/statement/parse.rs
+++ b/src/lib/parser/statement/parse.rs
@@ -4,6 +4,7 @@ use super::{
     case, functions::{collect_arguments, parse_function},
 };
 use shell::flow_control::{Case, ElseIf, ExportAction, LocalAction, Statement};
+use small;
 use std::char;
 
 fn collect<F>(arguments: &str, statement: F) -> Statement
@@ -128,7 +129,7 @@ pub(crate) fn parse(code: &str) -> Statement {
             return Statement::For {
                 variable:   variable.into(),
                 values:     ArgumentSplitter::new(cmd[3..].trim_left())
-                    .map(String::from)
+                    .map(small::String::from)
                     .collect(),
                 statements: Vec::new(),
             };
@@ -183,7 +184,7 @@ pub(crate) fn parse(code: &str) -> Statement {
             match collect_arguments(args) {
                 Ok(args) => {
                     return Statement::Function {
-                        description: description.map(String::from),
+                        description: description.map(small::String::from),
                         name: name.into(),
                         args,
                         statements: Vec::new(),
@@ -233,12 +234,12 @@ mod tests {
         let correct_parse = Statement::If {
             expression: Pipeline {
                 items: vec![PipeItem {
-                    job:     Job::new(
+                    job: Job::new(
                         vec![
-                            "test".to_owned(),
-                            "1".to_owned(),
-                            "-eq".to_owned(),
-                            "2".to_owned(),
+                            "test".into(),
+                            "1".into(),
+                            "-eq".into(),
+                            "2".into(),
                         ].into_iter()
                             .collect(),
                         JobKind::Last,
@@ -337,7 +338,7 @@ mod tests {
 
         let parsed_if = parse("fn bob a b --bob is a nice function");
         let correct_parse = Statement::Function {
-            description: Some("bob is a nice function".to_string()),
+            description: Some("bob is a nice function".into()),
             name:        "bob".into(),
             args:        vec![
                 KeyBuf {
diff --git a/src/lib/shell/assignments.rs b/src/lib/shell/assignments.rs
index 9f4c798ed5571a6e2eb3f718c2ac25f826e96740..fa751cec036cb93772f14110d699f9a958ab0cb3 100644
--- a/src/lib/shell/assignments.rs
+++ b/src/lib/shell/assignments.rs
@@ -4,7 +4,7 @@ use super::{
 use itoa;
 use lexers::assignments::{Operator, Primitive};
 use parser::assignments::*;
-use smallstring::SmallString;
+use small;
 use smallvec::SmallVec;
 use shell::{
     history::ShellHistory,
@@ -22,7 +22,7 @@ fn list_vars(shell: &Shell) {
     let mut buffer = BufWriter::new(stdout.lock());
 
     // Small function for formatting and append an array entry to a string buffer.
-    fn print_array<W: Write>(buffer: &mut W, key: &str, array: &[String]) {
+    fn print_array<W: Write>(buffer: &mut W, key: &str, array: &[small::String]) {
         let _ = buffer.write([key, " = [ "].concat().as_bytes());
         if array.len() > 1 {
             let mut vars = array.iter();
@@ -47,7 +47,7 @@ fn list_vars(shell: &Shell) {
     // Then immediately follow that with a list of array variables.
     let _ = buffer.write(b"\n# Array Variables\n");
     for (key, val) in shell.variables.arrays() {
-        print_array(&mut buffer, &key, &val)
+        print_array(&mut buffer, &key, &**val)
     }
 }
 
@@ -64,9 +64,9 @@ impl VariableStore for Shell {
     fn export(&mut self, action: ExportAction) -> i32 {
         let actions = match action {
             ExportAction::Assign(ref keys, op, ref vals) => AssignmentActions::new(keys, op, vals),
-            ExportAction::LocalExport(ref key) => match self.get::<types::Value>(key) {
+            ExportAction::LocalExport(ref key) => match self.get::<types::Str>(key) {
                 Some(var) => {
-                    env::set_var(key, &var);
+                    env::set_var(key, &*var);
                     return SUCCESS;
                 }
                 None => {
@@ -106,10 +106,10 @@ impl VariableStore for Shell {
                     match value_check(self, &expression, &key.kind) {
                         Ok(VariableType::Str(value)) => {
                             let key_name: &str = &key.name;
-                            let lhs: String = self
+                            let lhs: types::Str = self
                                 .variables
-                                .get::<types::Value>(key_name)
-                                .unwrap_or_else(|| String::from("0"));
+                                .get::<types::Str>(key_name)
+                                .unwrap_or_else(|| "0".into());
 
                             let result = math(&lhs, &key.kind, operator, &value, |value| {
                                 env::set_var(key_name, &OsStr::from_bytes(value))
@@ -219,7 +219,7 @@ impl VariableStore for Shell {
                             Ok(VariableType::Array(values)) => {
                                 match self.variables.get_mut(key.name) {
                                     Some(VariableType::Array(ref mut array)) => {
-                                        let mut iterator: Box<Iterator<Item=&String>> = Box::new(array.iter());
+                                        let mut iterator: Box<Iterator<Item=&types::Str>> = Box::new(array.iter());
                                         for value in &values {
                                             iterator = Box::new(iterator.filter(move |item| *item != value));
                                         }
@@ -300,7 +300,7 @@ impl VariableStore for Shell {
                                     let result = math(&lhs, &key.kind, operator, &value, |value| {
                                         collected.insert(key.name, VariableType::Str(unsafe {
                                             str::from_utf8_unchecked(value)
-                                        }.to_owned()));
+                                        }.into()));
                                     });
 
                                     if let Err(why) = result {
@@ -344,7 +344,7 @@ impl VariableStore for Shell {
                                         }
 
                                         for i in 0..part.len() {
-                                            output.push(vec.extract(i).to_string());
+                                            output.push(vec.extract(i).to_string().into());
                                         }
                                     }
 
@@ -404,7 +404,7 @@ impl VariableStore for Shell {
                                     Ok(VariableType::Str(ref index)) => {
                                         match self.variables.get_mut(key.name) {
                                             Some(VariableType::HashMap(hmap)) => {
-                                                hmap.entry(SmallString::from_str(index)).or_insert(VariableType::Str(value));
+                                                hmap.entry(index.clone()).or_insert(VariableType::Str(value));
                                             }
                                             Some(VariableType::BTreeMap(bmap)) => {
                                                 bmap.entry(index.clone()).or_insert(VariableType::Str(value));
diff --git a/src/lib/shell/binary/mod.rs b/src/lib/shell/binary/mod.rs
index 03bce01ed8de7f7bc7dbfce236e696bb7e5ebd35..96c41862f349ea941153011e042ff0a5abc542a7 100644
--- a/src/lib/shell/binary/mod.rs
+++ b/src/lib/shell/binary/mod.rs
@@ -98,11 +98,11 @@ impl Binary for Shell {
             let mut context = Context::new();
             context.word_divider_fn = Box::new(word_divide);
             if "1" == self.get_str_or_empty("HISTFILE_ENABLED") {
-                let path = self.get::<types::Value>("HISTFILE").expect("shell didn't set HISTFILE");
-                context.history.set_file_name(Some(path.clone()));
+                let path = self.get::<types::Str>("HISTFILE").expect("shell didn't set HISTFILE");
+                context.history.set_file_name(Some(path.to_string()));
                 if !Path::new(path.as_str()).exists() {
                     eprintln!("ion: creating history file at \"{}\"", path);
-                    if let Err(why) = File::create(path) {
+                    if let Err(why) = File::create(&*path) {
                         eprintln!("ion: could not create history file: {}", why);
                     }
                 }
@@ -128,7 +128,7 @@ impl Binary for Shell {
         self.evaluate_init_file();
 
         self.variables
-            .set("args", iter::once(env::args().next().unwrap()).collect::<types::Array>());
+            .set("args", iter::once(env::args().next().unwrap().into()).collect::<types::Array>());
 
         loop {
             if let Some(command) = self.readln() {
diff --git a/src/lib/shell/binary/readln.rs b/src/lib/shell/binary/readln.rs
index 8d9498495185bb2d38a9170487bca869753bffe8..e2e2610e7aa6d478c409aeff4f69b94764758891 100644
--- a/src/lib/shell/binary/readln.rs
+++ b/src/lib/shell/binary/readln.rs
@@ -1,11 +1,10 @@
 use super::super::{completer::*, Binary, DirectoryStack, Shell, Variables};
 use liner::{BasicCompleter, CursorPosition, Event, EventKind};
-use smallstring::SmallString;
 use std::{
     env, io::{self, ErrorKind, Write}, mem, path::PathBuf,
 };
 use sys;
-use types::*;
+use types;
 
 pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
     {
@@ -17,7 +16,7 @@ pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
                 // Map each underlying `liner::Buffer` into a `String`.
                 .map(|x| x.chars().cloned().collect())
                 // Collect each result into a vector to avoid borrowing issues.
-                .collect::<Vec<SmallString>>();
+                .collect::<Vec<types::Str>>();
 
         loop {
             let prompt = handle_prompt(shell.prompt()).unwrap();
@@ -64,17 +63,17 @@ pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
                             // in the creation of a custom completer.
                             let words = builtins.keys().iter()
                                 // Add built-in commands to the completer's definitions.
-                                .map(|&s| Identifier::from(s))
+                                .map(|&s| s.to_string())
                                 // Add the history list to the completer's definitions.
-                                .chain(history.iter().cloned())
+                                .chain(history.iter().map(|s| s.to_string()))
                                 // Add the aliases to the completer's definitions.
-                                .chain(vars.aliases().map(|(key, _)| key.clone()))
+                                .chain(vars.aliases().map(|(key, _)| key.to_string()))
                                 // Add the list of available functions to the completer's definitions.
-                                .chain(vars.functions().map(|(key, _)| key.clone()))
+                                .chain(vars.functions().map(|(key, _)| key.to_string()))
                                 // Add the list of available variables to the completer's definitions.
                                 // TODO: We should make it free to do String->SmallString
                                 //       and mostly free to go back (free if allocated)
-                                .chain(vars.string_vars().map(|(s, _)| ["$", &s].concat().into()))
+                                .chain(vars.string_vars().map(|(s, _)| ["$", &s].concat()))
                                 .collect();
 
                             // Initialize a new completer from the definitions collected.
diff --git a/src/lib/shell/flow.rs b/src/lib/shell/flow.rs
index 5a6df96df07bf6c3acb02afed325ea2f74cee40e..7da5dd095281545a3b64e1a967cb6de4a96d65f2 100644
--- a/src/lib/shell/flow.rs
+++ b/src/lib/shell/flow.rs
@@ -11,7 +11,7 @@ use shell::{
     assignments::VariableStore,
     variables::VariableType,
 };
-
+use small;
 use std::{
     io::{stdout, Write}, iter, mem,
 };
@@ -48,7 +48,7 @@ pub(crate) trait FlowLogic {
     fn execute_for(
         &mut self,
         variable: &str,
-        values: &[String],
+        values: &[small::String],
         statements: Vec<Statement>,
     ) -> Condition;
 
@@ -72,7 +72,7 @@ pub(crate) trait FlowLogic {
 
     /// Expand an expression and run a branch based on the value of the
     /// expanded expression
-    fn execute_match(&mut self, expression: String, cases: Vec<Case>) -> Condition;
+    fn execute_match(&mut self, expression: small::String, cases: Vec<Case>) -> Condition;
 }
 
 impl FlowLogic for Shell {
@@ -357,7 +357,7 @@ impl FlowLogic for Shell {
     fn execute_for(
         &mut self,
         variable: &str,
-        values: &[String],
+        values: &[small::String],
         statements: Vec<Statement>,
     ) -> Condition {
         let ignore_variable = variable == "_";
@@ -385,7 +385,7 @@ impl FlowLogic for Shell {
                 }
             },
             ForExpression::Normal(values) => for value in values.lines() {
-                self.set(variable, value.to_string());
+                self.set(variable, value);
                 match self.execute_statements(statements.clone()) {
                     Condition::Break => break,
                     Condition::SigInt => return Condition::SigInt,
@@ -625,7 +625,7 @@ impl FlowLogic for Shell {
         condition.unwrap_or(Condition::NoOp)
     }
 
-    fn execute_match(&mut self, expression: String, cases: Vec<Case>) -> Condition {
+    fn execute_match(&mut self, expression: small::String, cases: Vec<Case>) -> Condition {
         // Logic for determining if the LHS of a match-case construct (the value we are
         // matching against) matches the RHS of a match-case construct (a value
         // in a case statement). For example, checking to see if the value
@@ -661,9 +661,9 @@ impl FlowLogic for Shell {
                         } else {
                             previous_bind = self
                                 .variables
-                                .get::<types::Value>(bind)
+                                .get::<types::Str>(bind)
                                 .map(|x| VariableType::Str(x));
-                            self.set(&bind, value.join(" ").to_string());
+                            self.set(&bind, value.join(" "));
                         }
                     }
 
@@ -701,9 +701,9 @@ impl FlowLogic for Shell {
                         } else {
                             previous_bind = self
                                 .variables
-                                .get::<types::Value>(bind)
+                                .get::<types::Str>(bind)
                                 .map(|x| VariableType::Str(x));
-                            self.set(&bind, value.join(" ").to_string());
+                            self.set(&bind, value.join(" "));
                         }
                     }
 
diff --git a/src/lib/shell/flow_control.rs b/src/lib/shell/flow_control.rs
index 2515fb557f9509367aac695723e7d7618920857c..f6831ba464bfc6bda7a92c17d4a5879eb9c44b99 100644
--- a/src/lib/shell/flow_control.rs
+++ b/src/lib/shell/flow_control.rs
@@ -1,8 +1,9 @@
 use shell::{flow::FlowLogic, Shell};
 use parser::{assignments::*, pipelines::Pipeline};
+use small;
 use smallvec::SmallVec;
 use std::fmt::{self, Display, Formatter};
-use types::Identifier;
+use types;
 use lexers::assignments::{KeyBuf, Operator, Primitive};
 
 #[derive(Debug, PartialEq, Clone)]
@@ -69,14 +70,14 @@ pub(crate) enum Statement {
     },
     ElseIf(ElseIf),
     Function {
-        name:        Identifier,
-        description: Option<String>,
+        name:        types::Str,
+        description: Option<small::String>,
         args:        Vec<KeyBuf>,
         statements:  Vec<Statement>,
     },
     For {
-        variable:   Identifier,
-        values:     Vec<String>,
+        variable:   types::Str,
+        values:     Vec<small::String>,
         statements: Vec<Statement>,
     },
     While {
@@ -84,7 +85,7 @@ pub(crate) enum Statement {
         statements: Vec<Statement>,
     },
     Match {
-        expression: String,
+        expression: small::String,
         cases:      Vec<Case>,
     },
     Else,
@@ -146,8 +147,8 @@ impl Default for FlowControl {
 
 #[derive(Clone, Debug, PartialEq)]
 pub struct Function {
-    description: Option<String>,
-    name:        Identifier,
+    description: Option<small::String>,
+    name:        types::Str,
     args:        Vec<KeyBuf>,
     statements:  Vec<Statement>,
 }
@@ -201,7 +202,7 @@ impl Function {
         shell.variables.new_scope(true);
 
         for (type_, value) in values {
-            shell.variables.shadow(type_.name.into(), value);
+            shell.variables.shadow(&type_.name, value);
         }
 
         shell.execute_statements(self.statements);
@@ -211,11 +212,11 @@ impl Function {
         Ok(())
     }
 
-    pub(crate) fn get_description<'a>(&'a self) -> Option<&'a String> { self.description.as_ref() }
+    pub(crate) fn get_description<'a>(&'a self) -> Option<&'a small::String> { self.description.as_ref() }
 
     pub(crate) fn new(
-        description: Option<String>,
-        name: Identifier,
+        description: Option<small::String>,
+        name: types::Str,
         args: Vec<KeyBuf>,
         statements: Vec<Statement>,
     ) -> Function {
diff --git a/src/lib/shell/history.rs b/src/lib/shell/history.rs
index f50e8ae1dbb9df3b0f6df7f83994461fc1328a18..a88ef353d0689e4657a8d697457384ead4a4f21c 100644
--- a/src/lib/shell/history.rs
+++ b/src/lib/shell/history.rs
@@ -2,6 +2,7 @@ use shell::{status::*, Shell};
 
 use regex::Regex;
 use std::io::{self, Write};
+use small;
 use types;
 
 bitflags! {
@@ -40,7 +41,7 @@ impl IgnoreSetting {
 pub(crate) trait ShellHistory {
     /// Prints the commands contained within the history buffers to standard
     /// output.
-    fn print_history(&self, _arguments: &[String]) -> i32;
+    fn print_history(&self, _arguments: &[small::String]) -> i32;
 
     /// Sets the history size for the shell context equal to the HISTORY_SIZE shell variable if
     /// it
@@ -125,7 +126,7 @@ impl ShellHistory for Shell {
         context.history.set_max_size(max_history_size);
 
         if &*variables.get_str_or_empty("HISTFILE_ENABLED") == "1" {
-            context.history.set_file_name(variables.get::<types::Value>("HISTFILE"));
+            context.history.set_file_name(variables.get::<types::Str>("HISTFILE").map(|v| v.to_string()));
 
             let max_histfile_size = variables
                 .get_str_or_empty("HISTFILE_SIZE")
@@ -137,7 +138,7 @@ impl ShellHistory for Shell {
         }
     }
 
-    fn print_history(&self, _arguments: &[String]) -> i32 {
+    fn print_history(&self, _arguments: &[small::String]) -> i32 {
         if let Some(context) = self.context.as_ref() {
             let mut buffer = Vec::with_capacity(8 * 1024);
             for command in &context.lock().unwrap().history.buffers {
diff --git a/src/lib/shell/job.rs b/src/lib/shell/job.rs
index 88d64ac2b6ac53e63ae6b0f99eab9ca44afa11f3..4a4b663552a5f6dd75cca596250ec16fbc4324ec 100644
--- a/src/lib/shell/job.rs
+++ b/src/lib/shell/job.rs
@@ -2,9 +2,8 @@ use super::Shell;
 use builtins::{BuiltinFunction, BUILTINS};
 use parser::{expand_string, pipelines::RedirectFrom};
 use shell::pipe_exec::PipelineExecution;
-use smallstring::SmallString;
 use std::{fmt, fs::File, str};
-use types::*;
+use types::{self, Array};
 
 #[derive(Debug, PartialEq, Clone, Copy)]
 pub(crate) enum JobKind {
@@ -16,8 +15,8 @@ pub(crate) enum JobKind {
 
 #[derive(Clone)]
 pub(crate) struct Job {
-    pub command: Identifier,
-    pub args:    Array,
+    pub command: types::Str,
+    pub args:    types::Array,
     pub kind:    JobKind,
     pub builtin: Option<BuiltinFunction>,
 }
@@ -26,14 +25,14 @@ impl Job {
     /// Takes the current job's arguments and expands them, one argument at a
     /// time, returning a new `Job` with the expanded arguments.
     pub(crate) fn expand(&mut self, shell: &Shell) {
-        let mut expanded = Array::new();
+        let mut expanded = types::Array::new();
         expanded.grow(self.args.len());
         expanded.extend(self.args.drain().flat_map(|arg| expand_arg(&arg, shell)));
         self.args = expanded;
     }
 
-    pub(crate) fn new(args: Array, kind: JobKind) -> Self {
-        let command = SmallString::from_str(&args[0]);
+    pub(crate) fn new(args: types::Array, kind: JobKind) -> Self {
+        let command = args[0].clone();
         let builtin = BUILTINS.get(command.as_ref()).map(|b| b.main);
         Job {
             command,
@@ -61,7 +60,7 @@ impl fmt::Debug for Job {
 }
 
 /// Expands a given argument and returns it as an `Array`.
-fn expand_arg(arg: &str, shell: &Shell) -> Array {
+fn expand_arg(arg: &str, shell: &Shell) -> types::Array {
     let res = expand_string(&arg, shell, false);
     if res.is_empty() {
         array![""]
@@ -75,8 +74,8 @@ fn expand_arg(arg: &str, shell: &Shell) -> Array {
 pub(crate) enum RefinedJob {
     /// An external program that is executed by this shell
     External {
-        name:   Identifier,
-        args:   Array,
+        name:   types::Str,
+        args:   types::Array,
         stdin:  Option<File>,
         stdout: Option<File>,
         stderr: Option<File>,
@@ -84,15 +83,15 @@ pub(crate) enum RefinedJob {
     /// A procedure embedded into Ion
     Builtin {
         main:   BuiltinFunction,
-        args:   Array,
+        args:   types::Array,
         stdin:  Option<File>,
         stdout: Option<File>,
         stderr: Option<File>,
     },
     /// Functions can act as commands too!
     Function {
-        name:   Identifier,
-        args:   Array,
+        name:   types::Str,
+        args:   types::Array,
         stdin:  Option<File>,
         stdout: Option<File>,
         stderr: Option<File>,
@@ -236,7 +235,7 @@ impl RefinedJob {
                 ref stdout,
                 ref stderr,
             } => {
-                shell.exec_builtin(main, args, stdout, stderr, stdin)
+                shell.exec_builtin(main, &**args, stdout, stderr, stdin)
             }
             RefinedJob::Function {
                 ref name,
@@ -288,7 +287,7 @@ impl RefinedJob {
         }
     }
 
-    pub(crate) fn function(name: Identifier, args: Array) -> Self {
+    pub(crate) fn function(name: types::Str, args: types::Array) -> Self {
         RefinedJob::Function {
             name,
             args,
@@ -298,7 +297,7 @@ impl RefinedJob {
         }
     }
 
-    pub(crate) fn builtin(main: BuiltinFunction, args: Array) -> Self {
+    pub(crate) fn builtin(main: BuiltinFunction, args: types::Array) -> Self {
         RefinedJob::Builtin {
             main,
             args,
@@ -308,7 +307,7 @@ impl RefinedJob {
         }
     }
 
-    pub(crate) fn external(name: Identifier, args: Array) -> Self {
+    pub(crate) fn external(name: types::Str, args: types::Array) -> Self {
         RefinedJob::External {
             name,
             args,
diff --git a/src/lib/shell/mod.rs b/src/lib/shell/mod.rs
index 29b0bb02571249c02b644a0ce40dfe31de918eff..c06c75b94fd05124aed646026e5de26c9f936d62 100644
--- a/src/lib/shell/mod.rs
+++ b/src/lib/shell/mod.rs
@@ -34,7 +34,6 @@ use self::{
         VariableType,
     }
 };
-use types;
 use builtins::{BuiltinMap, BUILTINS};
 use lexers::ArgumentSplitter;
 use liner::Context;
@@ -49,7 +48,7 @@ use std::{
     sync::{atomic::Ordering, Arc, Mutex}, time::SystemTime,
 };
 use sys;
-use types::*;
+use types::{self, Array};
 use xdg::BaseDirectories;
 
 #[derive(Debug, Fail)]
@@ -226,7 +225,7 @@ impl Shell {
     }
 
     /// Obtains a variable, returning an empty string if it does not exist.
-    pub(crate) fn get_str_or_empty(&self, name: &str) -> String {
+    pub(crate) fn get_str_or_empty(&self, name: &str) -> types::Str {
         self.variables.get_str_or_empty(name)
     }
 
@@ -260,9 +259,9 @@ impl Shell {
 
                 if let Some(alias) = possible_alias {
                     let new_args = ArgumentSplitter::new(&alias)
-                        .map(String::from)
+                        .map(types::Str::from)
                         .chain(item.job.args.drain().skip(1))
-                        .collect::<Array>();
+                        .collect::<types::Array>();
                     if let Some(builtin) = BUILTINS.get(&new_args[0]) {
                         item.job.builtin = Some(builtin.main);
                     } else {
@@ -285,7 +284,7 @@ impl Shell {
                     Some(SUCCESS)
                 } else {
                     let borrowed = &pipeline.items[0].job.args;
-                    Some(main(&borrowed, self))
+                    Some(main(borrowed, self))
                 }
             } else {
                 Some(self.execute_pipeline(pipeline))
@@ -293,7 +292,7 @@ impl Shell {
         // Branch else if -> input == shell function and set the exit_status
         } else if let Some(function) = self.variables.get::<Function>(&pipeline.items[0].job.command) {
             if !pipeline.requires_piping() {
-                let args: &[String] = pipeline.items[0].job.args.deref();
+                let args = pipeline.items[0].job.args.deref();
                 match function.execute(self, args) {
                     Ok(()) => None,
                     Err(FunctionError::InvalidArgumentCount) => {
@@ -321,7 +320,7 @@ impl Shell {
         // pipline just executed to the the file and context histories. At the
         // moment, this means record how long it took.
         if let Some(context) = self.context.as_mut() {
-            if "1" == self.variables.get_str_or_empty("RECORD_SUMMARY") {
+            if "1" == &*self.variables.get_str_or_empty("RECORD_SUMMARY") {
                 if let Ok(elapsed_time) = command_start_time.elapsed() {
                     let summary = format!(
                         "#summary# elapsed real time: {}.{:09} seconds",
@@ -419,7 +418,7 @@ impl Shell {
 
 impl<'a> Expander for Shell {
     /// Uses a subshell to expand a given command.
-    fn command(&self, command: &str) -> Option<Value> {
+    fn command(&self, command: &str) -> Option<types::Str> {
         let mut output = None;
         match self.fork(Capture::StdoutThenIgnoreStderr, move |shell| {
             shell.on_command(command)
@@ -440,28 +439,28 @@ impl<'a> Expander for Shell {
 
         // Ensure that the parent retains ownership of the terminal before exiting.
         let _ = sys::tcsetpgrp(sys::STDIN_FILENO, process::id());
-        output
+        output.map(|s| s.into())
     }
 
     /// Expand a string variable given if its quoted / unquoted
-    fn string(&self, name: &str, quoted: bool) -> Option<Value> {
+    fn string(&self, name: &str, quoted: bool) -> Option<types::Str> {
         use ascii_helpers::AsciiReplace;
         if quoted {
-            self.get::<Value>(name)
+            self.get::<types::Str>(name)
         } else {
-            self.get::<Value>(name).map(|x| x.ascii_replace('\n', ' '))
+            self.get::<types::Str>(name).map(|x| x.ascii_replace('\n', ' '))
         }
     }
 
     /// Expand an array variable with some selection
-    fn array(&self, name: &str, selection: Select) -> Option<Array> {
-        if let Some(array) = self.variables.get::<Array>(name) {
+    fn array(&self, name: &str, selection: Select) -> Option<types::Array> {
+        if let Some(array) = self.variables.get::<types::Array>(name) {
             match selection {
                 Select::All => return Some(array.clone()),
                 Select::Index(id) => return id
                     .resolve(array.len())
                     .and_then(|n| array.get(n))
-                    .map(|x| Array::from_iter(Some(x.to_owned()))),
+                    .map(|x| types::Array::from_iter(Some(x.to_owned()))),
                 Select::Range(range) => if let Some((start, length)) = range.bounds(array.len()) {
                     if array.len() > start {
                         return Some(
@@ -470,23 +469,23 @@ impl<'a> Expander for Shell {
                                 .skip(start)
                                 .take(length)
                                 .map(|x| x.to_owned())
-                                .collect::<Array>(),
+                                .collect::<types::Array>(),
                         )
                     }
                 }
                 _ => (),
             }
-        } else if let Some(hmap) = self.variables.get::<HashMap>(name) {
+        } else if let Some(hmap) = self.variables.get::<types::HashMap>(name) {
             match selection {
                 Select::All => {
-                    let mut array = Array::new();
+                    let mut array = types::Array::new();
                     for (_, value) in hmap.iter() {
                         let f = format!("{}", value);
                         match *value {
-                            VariableType::Str(_) => array.push(f),
+                            VariableType::Str(_) => array.push(f.into()),
                             VariableType::Array(_) | VariableType::HashMap(_) | VariableType::BTreeMap(_) => {
                                 for split in f.split_whitespace() {
-                                    array.push(split.to_owned());
+                                    array.push(split.into());
                                 }
                             }
                             _ => (),
@@ -494,22 +493,22 @@ impl<'a> Expander for Shell {
                     }
                     return Some(array)
                 }
-                Select::Key(ref key) => {
-                    return Some(array![format!("{}", hmap.get(key).unwrap_or(&VariableType::Str("".into())))])
+                Select::Key(key) => {
+                    return Some(array![format!("{}", hmap.get(&*key).unwrap_or(&VariableType::Str("".into())))])
                 }
                 _ => (),
             }
-        } else if let Some(bmap) = self.variables.get::<BTreeMap>(name) {
+        } else if let Some(bmap) = self.variables.get::<types::BTreeMap>(name) {
             match selection {
                 Select::All => {
-                    let mut array = Array::new();
+                    let mut array = types::Array::new();
                     for (_, value) in bmap.iter() {
                         let f = format!("{}", value);
                         match *value {
-                            VariableType::Str(_) => array.push(f),
+                            VariableType::Str(_) => array.push(f.into()),
                             VariableType::Array(_) | VariableType::HashMap(_) | VariableType::BTreeMap(_) => {
                                 for split in f.split_whitespace() {
-                                    array.push(split.to_owned());
+                                    array.push(split.into());
                                 }
                             }
                             _ => (),
@@ -517,8 +516,8 @@ impl<'a> Expander for Shell {
                     }
                     return Some(array)
                 }
-                Select::Key(ref key) => {
-                    return Some(array![format!("{}", bmap.get(&(&*key).to_string()).unwrap_or(&VariableType::Str("".into())))])
+                Select::Key(key) => {
+                    return Some(array![format!("{}", bmap.get(&*key).unwrap_or(&VariableType::Str("".into())))])
                 }
                 _ => (),
             }
diff --git a/src/lib/shell/pipe_exec/mod.rs b/src/lib/shell/pipe_exec/mod.rs
index 06f47d41b2cf32744da08245cbbf8b6ac02f749a..99c38d2b9848aabe0400b29431adc8fdaa9296ef 100644
--- a/src/lib/shell/pipe_exec/mod.rs
+++ b/src/lib/shell/pipe_exec/mod.rs
@@ -26,6 +26,7 @@ use super::{
 };
 use builtins::{self, BuiltinFunction};
 use parser::pipelines::{Input, PipeItem, Pipeline, RedirectFrom, Redirection};
+use small;
 use smallvec::SmallVec;
 use std::{
     fs::{File, OpenOptions},
@@ -94,7 +95,7 @@ fn do_redirection(
     macro_rules! get_infile {
         ($input:expr) => {
             match $input {
-                Input::File(ref filename) => match File::open(filename) {
+                Input::File(ref filename) => match File::open(filename.as_str()) {
                     Ok(file) => Some(file),
                     Err(e) => {
                         eprintln!("ion: failed to redirect '{}' to stdin: {}", filename, e);
@@ -157,9 +158,9 @@ fn do_redirection(
                         .create(true)
                         .write(true)
                         .append(true)
-                        .open(&output.file)
+                        .open(output.file.as_str())
                 } else {
-                    File::create(&output.file)
+                    File::create(output.file.as_str())
                 } {
                     Ok(f) => match output.from {
                         RedirectFrom::Stderr => $job.stderr(f),
@@ -200,9 +201,9 @@ fn do_redirection(
                         .create(true)
                         .write(true)
                         .append(true)
-                        .open(&output.file)
+                        .open(output.file.as_str())
                 } else {
-                    File::create(&output.file)
+                    File::create(output.file.as_str())
                 } {
                     Ok(f) => match output.from {
                         RedirectFrom::$teed => tee.sinks.push(f),
@@ -306,9 +307,9 @@ fn do_redirection(
                             .create(true)
                             .write(true)
                             .append(true)
-                            .open(&output.file)
+                            .open(output.file.as_str())
                     } else {
-                        File::create(&output.file)
+                        File::create(output.file.as_str())
                     } {
                         Ok(f) => match output.from {
                             RedirectFrom::Stdout => tee_out.sinks.push(f),
@@ -392,7 +393,7 @@ pub(crate) trait PipelineExecution {
     fn exec_builtin(
         &mut self,
         main: BuiltinFunction,
-        args: &[String],
+        args: &[small::String],
         stdout: &Option<File>,
         stderr: &Option<File>,
         stdin: &Option<File>,
@@ -612,7 +613,7 @@ impl PipelineExecution for Shell {
     fn exec_builtin(
         &mut self,
         main: BuiltinFunction,
-        args: &[String],
+        args: &[small::String],
         stdout: &Option<File>,
         stderr: &Option<File>,
         stdin: &Option<File>,
@@ -987,7 +988,7 @@ fn spawn_proc(
         } => match unsafe { sys::fork() } {
             Ok(0) => {
                 prepare_child(block_child, pgid);
-                let ret = shell.exec_builtin(main, &args, stdout, stderr, stdin);
+                let ret = shell.exec_builtin(main, args, stdout, stderr, stdin);
                 close(stdout);
                 close(stderr);
                 close(stdin);
diff --git a/src/lib/shell/plugins/library_iter/redox.rs b/src/lib/shell/plugins/library_iter/redox.rs
index 61fed872efafc8999de48645b17372e2241b6945..72745aab3365f273ddbdb3b88b7ef258083507b5 100644
--- a/src/lib/shell/plugins/library_iter/redox.rs
+++ b/src/lib/shell/plugins/library_iter/redox.rs
@@ -1,5 +1,5 @@
 use std::fs::ReadDir;
-use types::Identifier;
+use types;
 
 pub(crate) struct Library;
 
@@ -15,7 +15,7 @@ impl LibraryIterator {
 impl Iterator for LibraryIterator {
     // The `Identifier` is the name of the namespace for which values may be pulled.
     // The `Library` is a handle to dynamic library loaded into memory.
-    type Item = (Identifier, Library);
+    type Item = (types::Str, Library);
 
-    fn next(&mut self) -> Option<(Identifier, Library)> { None }
+    fn next(&mut self) -> Option<(types::Str, Library)> { None }
 }
diff --git a/src/lib/shell/plugins/library_iter/unix.rs b/src/lib/shell/plugins/library_iter/unix.rs
index 79e9a37de72f707f1de9d715902ca06f747944e6..45b985bf29cd84b165ee2b7016eb464e5e851ded 100644
--- a/src/lib/shell/plugins/library_iter/unix.rs
+++ b/src/lib/shell/plugins/library_iter/unix.rs
@@ -1,6 +1,6 @@
 use libloading::Library;
 use std::fs::ReadDir;
-use types::Identifier;
+use types;
 
 /// Grabs all `Library` entries found within a given directory
 pub(crate) struct LibraryIterator {
@@ -14,9 +14,9 @@ impl LibraryIterator {
 impl Iterator for LibraryIterator {
     // The `Identifier` is the name of the namespace for which values may be pulled.
     // The `Library` is a handle to dynamic library loaded into memory.
-    type Item = (Identifier, Library);
+    type Item = (types::Str, Library);
 
-    fn next(&mut self) -> Option<(Identifier, Library)> {
+    fn next(&mut self) -> Option<(types::Str, Library)> {
         while let Some(entry) = self.directory.next() {
             let entry = if let Ok(entry) = entry {
                 entry
@@ -28,7 +28,7 @@ impl Iterator for LibraryIterator {
             if path.is_file() && path.extension().map_or(false, |ext| ext == "so") {
                 // The identifier will be the file name of that file, without the extension.
                 let identifier = match path.file_stem().unwrap().to_str() {
-                    Some(filename) => Identifier::from(filename),
+                    Some(filename) => types::Str::from(filename),
                     None => {
                         eprintln!("ion: namespace plugin has invalid filename");
                         continue;
diff --git a/src/lib/shell/plugins/methods/redox.rs b/src/lib/shell/plugins/methods/redox.rs
index 01ed5c6609fad39f96c2f09fe7b9d6e61b27d448..655c2d143038346d29867ddf608d12cc637904f7 100644
--- a/src/lib/shell/plugins/methods/redox.rs
+++ b/src/lib/shell/plugins/methods/redox.rs
@@ -1,8 +1,9 @@
 use super::super::StringError;
+use small;
 
 pub(crate) enum MethodArguments {
-    StringArg(String, Vec<String>),
-    Array(Vec<String>, Vec<String>),
+    StringArg(small::String, Vec<small::String>),
+    Array(Vec<small::String>, Vec<small::String>),
     NoArgs,
 }
 
@@ -13,7 +14,7 @@ impl StringMethodPlugins {
         &self,
         _function: &str,
         _arguments: MethodArguments,
-    ) -> Result<Option<String>, StringError> {
+    ) -> Result<Option<small::String>, StringError> {
         Ok(None)
     }
 
diff --git a/src/lib/shell/plugins/methods/unix.rs b/src/lib/shell/plugins/methods/unix.rs
index 4fb3b000984917b7ae090b778a2663ba71e95a74..65720c35f3d0ab4b5f44408813dc38bb08871ad2 100644
--- a/src/lib/shell/plugins/methods/unix.rs
+++ b/src/lib/shell/plugins/methods/unix.rs
@@ -1,8 +1,9 @@
 use super::super::{config_dir, LibraryIterator, StringError};
 use fnv::FnvHashMap;
 use libloading::{os::unix::Symbol as RawSymbol, Library, Symbol};
+use small;
 use std::{ffi::CString, fs::read_dir, mem::forget, os::raw::c_char, ptr, slice, str};
-use types::Identifier;
+use types;
 
 /// Either one or the other will be set. Optional status can be conveyed by setting the
 /// corresponding field to `NULL`. Libraries importing this structure should check for nullness.
@@ -16,8 +17,8 @@ pub(crate) struct RawMethodArguments {
 }
 
 pub(crate) enum MethodArguments {
-    StringArg(String, Vec<String>),
-    Array(Vec<String>, Vec<String>),
+    StringArg(small::String, Vec<small::String>),
+    Array(Vec<small::String>, Vec<small::String>),
     NoArgs,
 }
 
@@ -100,7 +101,7 @@ pub(crate) struct StringMethodPlugins {
     libraries: Vec<Library>,
     /// A map of all the symbols that were collected from the above libraries.
     pub symbols:
-        FnvHashMap<Identifier, RawSymbol<unsafe extern "C" fn(RawMethodArguments) -> *mut c_char>>,
+        FnvHashMap<types::Str, RawSymbol<unsafe extern "C" fn(RawMethodArguments) -> *mut c_char>>,
 }
 
 impl StringMethodPlugins {
@@ -162,7 +163,7 @@ impl StringMethodPlugins {
                             // Grab a slice and ensure that the name of the function is UTF-8.
                             let slice = &symbol_list[start..counter];
                             let identifier = str::from_utf8(slice)
-                                .map(Identifier::from)
+                                .map(types::Str::from)
                                 .map_err(|_| StringError::UTF8Function)?;
 
                             // To obtain the symbol, we need to create a new `\0`-ended byte array.
@@ -193,7 +194,7 @@ impl StringMethodPlugins {
                 if counter != start {
                     let slice = &symbol_list[start..];
                     let identifier = str::from_utf8(slice)
-                        .map(Identifier::from)
+                        .map(types::Str::from)
                         .map_err(|_| StringError::UTF8Function)?;
                     let mut symbol = Vec::new();
                     symbol.reserve_exact(slice.len() + 1);
diff --git a/src/lib/shell/plugins/namespaces/redox.rs b/src/lib/shell/plugins/namespaces/redox.rs
index b6667b31f65115af43583b0bb75d1a8318d42383..787565379d67e003d15990da133565c612d30b29 100644
--- a/src/lib/shell/plugins/namespaces/redox.rs
+++ b/src/lib/shell/plugins/namespaces/redox.rs
@@ -1,19 +1,19 @@
 use fnv::FnvHashMap;
 
 use super::super::StringError;
-use types::Identifier;
+use types;
 
 pub(crate) struct StringNamespace;
 
 impl StringNamespace {
-    pub(crate) fn execute(&self, _function: Identifier) -> Result<Option<String>, StringError> {
+    pub(crate) fn execute(&self, _function: types::Str) -> Result<Option<types::Str>, StringError> {
         Ok(None)
     }
 
     pub(crate) fn new() -> Result<StringNamespace, StringError> { Ok(StringNamespace) }
 }
 
-pub(crate) fn collect() -> FnvHashMap<Identifier, StringNamespace> {
+pub(crate) fn collect() -> FnvHashMap<types::Str, StringNamespace> {
     eprintln!("ion: Redox doesn't support plugins yet");
     FnvHashMap::default()
 }
diff --git a/src/lib/shell/plugins/namespaces/unix.rs b/src/lib/shell/plugins/namespaces/unix.rs
index 53e091cef7464ddff46d36b5a0aaba23a28eb696..9e4d5e33853ad2bc646a595c31b00ba5777cc357 100644
--- a/src/lib/shell/plugins/namespaces/unix.rs
+++ b/src/lib/shell/plugins/namespaces/unix.rs
@@ -2,7 +2,7 @@ use super::super::{config_dir, LibraryIterator, StringError};
 use fnv::FnvHashMap;
 use libloading::{os::unix::Symbol as RawSymbol, Library, Symbol};
 use std::{ffi::CString, fs::read_dir, os::raw::c_char, slice, str};
-use types::Identifier;
+use types;
 
 /// A dynamically-loaded string namespace from an external library.
 ///
@@ -18,7 +18,7 @@ pub(crate) struct StringNamespace {
     library: Library,
     /// A hash map of symbols collected from the `Library` stored in the `library` field.
     /// These are considered raw because they have their lifetimes erased.
-    symbols: FnvHashMap<Identifier, RawSymbol<unsafe extern "C" fn() -> *mut c_char>>,
+    symbols: FnvHashMap<types::Str, RawSymbol<unsafe extern "C" fn() -> *mut c_char>>,
 }
 
 impl StringNamespace {
@@ -26,7 +26,7 @@ impl StringNamespace {
     ///
     /// If the function exists, it is executed, and it's return value is then converted into a
     /// proper Rusty type.
-    pub(crate) fn execute(&self, function: Identifier) -> Result<Option<String>, StringError> {
+    pub(crate) fn execute(&self, function: types::Str) -> Result<Option<String>, StringError> {
         let func = self
             .symbols
             .get(&function)
@@ -77,7 +77,7 @@ impl StringNamespace {
                             // Grab a slice and ensure that the name of the function is UTF-8.
                             let slice = &symbol_list[start..counter];
                             let identifier = str::from_utf8(slice)
-                                .map(Identifier::from)
+                                .map(types::Str::from)
                                 .map_err(|_| StringError::UTF8Function)?;
 
                             // To obtain the symbol, we need to create a new `\0`-ended byte array.
@@ -108,7 +108,7 @@ impl StringNamespace {
                 if counter != start {
                     let slice = &symbol_list[start..];
                     let identifier = str::from_utf8(slice)
-                        .map(Identifier::from)
+                        .map(types::Str::from)
                         .map_err(|_| StringError::UTF8Function)?;
                     let mut symbol = Vec::new();
                     symbol.reserve_exact(slice.len() + 1);
@@ -130,7 +130,7 @@ impl StringNamespace {
 ///
 /// This function is meant to be called with `lazy_static` to ensure that there isn't a
 /// cost to collecting all this information when the shell never uses it in the first place!
-pub(crate) fn collect() -> FnvHashMap<Identifier, StringNamespace> {
+pub(crate) fn collect() -> FnvHashMap<types::Str, StringNamespace> {
     let mut hashmap = FnvHashMap::default();
     if let Some(mut path) = config_dir() {
         path.push("namespaces");
diff --git a/src/lib/shell/plugins/string.rs b/src/lib/shell/plugins/string.rs
index 656d64252138bd3a2ef1b59d4da99632b0ae3c5e..20b90efbe2e4a08debd96f35e3b349bfda04493b 100644
--- a/src/lib/shell/plugins/string.rs
+++ b/src/lib/shell/plugins/string.rs
@@ -1,7 +1,7 @@
 use std::{
     fmt::{self, Display, Formatter}, io,
 };
-use types::Identifier;
+use types;
 
 #[derive(Debug)]
 /// A possible error that can be caused when attempting to obtain or execute a
@@ -18,7 +18,7 @@ pub(crate) enum StringError {
     UTF8Result,
     /// This infers that the user called a function that doesn't exist in the library. Bad
     /// user, bad.
-    FunctionMissing(Identifier),
+    FunctionMissing(types::Str),
 }
 
 impl Display for StringError {
diff --git a/src/lib/shell/variables/mod.rs b/src/lib/shell/variables/mod.rs
index a8290780aabc6601e037d1ad431a4b2cb6011ddf..c1b7adf7e6247ab0272cd96e315294976d141844 100644
--- a/src/lib/shell/variables/mod.rs
+++ b/src/lib/shell/variables/mod.rs
@@ -7,7 +7,6 @@ use super::{
 };
 use fnv::FnvHashMap;
 use liner::Context;
-use smallstring::SmallString;
 use std::{
     any::TypeId,
     env,
@@ -17,68 +16,66 @@ use std::{
     ops::{Deref, DerefMut}
 };
 use sys::{self, geteuid, getpid, getuid, is_root, variables as self_sys, env as sys_env};
-use types::{
-    self, Alias, Array, BTreeMap, HashMap, Identifier, Key, Value,
-};
+use types::{self, Array};
 use unicode_segmentation::UnicodeSegmentation;
 use xdg::BaseDirectories;
 
 lazy_static! {
-    static ref STRING_NAMESPACES: FnvHashMap<Identifier, StringNamespace> = namespaces::collect();
+    static ref STRING_NAMESPACES: FnvHashMap<types::Str, StringNamespace> = namespaces::collect();
 }
 
 #[derive(Clone, Debug, PartialEq)]
 pub enum VariableType {
-    Str(Value),
-    Alias(Alias),
-    Array(Array),
-    HashMap(HashMap),
-    BTreeMap(BTreeMap),
+    Str(types::Str),
+    Alias(types::Alias),
+    Array(types::Array),
+    HashMap(types::HashMap),
+    BTreeMap(types::BTreeMap),
     Function(Function),
     None,
 }
 
-impl From<VariableType> for String {
+impl From<VariableType> for types::Str {
     fn from(var: VariableType) -> Self {
         match var {
             VariableType::Str(string) => string,
-            _ => String::with_capacity(0),
+            _ => types::Str::with_capacity(0),
         }
     }
 }
 
-impl From<VariableType> for Alias {
+impl From<VariableType> for types::Alias {
     fn from(var: VariableType) -> Self {
         match var {
             VariableType::Alias(alias) => alias,
-            _ => Alias::empty(),
+            _ => types::Alias::empty(),
         }
     }
 }
 
-impl From<VariableType> for Array {
+impl From<VariableType> for types::Array {
     fn from(var: VariableType) -> Self {
         match var {
             VariableType::Array(array) => array,
-            _ => Array::with_capacity(0),
+            _ => types::Array::with_capacity(0),
         }
     }
 }
 
-impl From<VariableType> for HashMap {
+impl From<VariableType> for types::HashMap {
     fn from(var: VariableType) -> Self {
         match var {
             VariableType::HashMap(hash_map) => hash_map,
-            _ => HashMap::with_capacity_and_hasher(0, Default::default()),
+            _ => types::HashMap::with_capacity_and_hasher(0, Default::default()),
         }
     }
 }
 
-impl From<VariableType> for BTreeMap {
+impl From<VariableType> for types::BTreeMap {
     fn from(var: VariableType) -> Self {
         match var {
             VariableType::BTreeMap(btree_map) => btree_map,
-            _ => BTreeMap::new(),
+            _ => types::BTreeMap::new(),
         }
     }
 }
@@ -92,33 +89,45 @@ impl From<VariableType> for Function {
     }
 }
 
+impl<'a> From<&'a str> for VariableType {
+    fn from(string: &'a str) -> Self {
+        VariableType::Str(string.into())
+    }
+}
+
+impl From<types::Str> for VariableType {
+    fn from(string: types::Str) -> Self {
+        VariableType::Str(string)
+    }
+}
+
 impl From<String> for VariableType {
     fn from(string: String) -> Self {
-        VariableType::Str(string)
+        VariableType::Str(string.into())
     }
 }
 
-impl From<Alias> for VariableType {
-    fn from(alias: Alias) -> Self {
+impl From<types::Alias> for VariableType {
+    fn from(alias: types::Alias) -> Self {
         VariableType::Alias(alias)
     }
 }
 
-impl From<Array> for VariableType {
-    fn from(array: Array) -> Self {
+impl From<types::Array> for VariableType {
+    fn from(array: types::Array) -> Self {
         VariableType::Array(array)
     }
 }
 
-impl From<HashMap> for VariableType {
-    fn from(hash_map: HashMap) -> Self {
-        VariableType::HashMap(hash_map)
+impl From<types::HashMap> for VariableType {
+    fn from(hmap: types::HashMap) -> Self {
+        VariableType::HashMap(hmap)
     }
 }
 
-impl From<BTreeMap> for VariableType {
-    fn from(btree_map: BTreeMap) -> Self {
-        VariableType::BTreeMap(btree_map)
+impl From<types::BTreeMap> for VariableType {
+    fn from(bmap: types::BTreeMap) -> Self {
+        VariableType::BTreeMap(bmap)
     }
 }
 
@@ -159,14 +168,14 @@ impl fmt::Display for VariableType {
 
 #[derive(Clone, Debug)]
 pub struct Scope {
-    vars: FnvHashMap<Identifier, VariableType>,
+    vars: FnvHashMap<types::Str, VariableType>,
     /// This scope is on a namespace boundary.
     /// Any previous scopes need to be accessed through `super::`.
     namespace: bool
 }
 
 impl Deref for Scope {
-    type Target = FnvHashMap<Identifier, VariableType>;
+    type Target = FnvHashMap<types::Str, VariableType>;
     fn deref(&self) -> &Self::Target {
         &self.vars
     }
@@ -187,7 +196,7 @@ pub struct Variables {
 
 impl Default for Variables {
     fn default() -> Self {
-        let mut map: FnvHashMap<Identifier, VariableType> = FnvHashMap::with_capacity_and_hasher(64, Default::default());
+        let mut map: FnvHashMap<types::Str, VariableType> = FnvHashMap::with_capacity_and_hasher(64, Default::default());
         map.insert("DIRECTORY_STACK_SIZE".into(), VariableType::Str("1000".into()));
         map.insert("HISTORY_SIZE".into(), VariableType::Str("1000".into()));
         map.insert("HISTFILE_SIZE".into(), VariableType::Str("100000".into()));
@@ -204,15 +213,15 @@ impl Default for Variables {
         // Set the PID, UID, and EUID variables.
         map.insert(
             "PID".into(),
-            VariableType::Str(getpid().ok().map_or("?".into(), |id| id.to_string())),
+            VariableType::Str(getpid().ok().map_or("?".into(), |id| id.to_string().into())),
         );
         map.insert(
             "UID".into(),
-            VariableType::Str(getuid().ok().map_or("?".into(), |id| id.to_string())),
+            VariableType::Str(getuid().ok().map_or("?".into(), |id| id.to_string().into())),
         );
         map.insert(
             "EUID".into(),
-            VariableType::Str(geteuid().ok().map_or("?".into(), |id| id.to_string())),
+            VariableType::Str(geteuid().ok().map_or("?".into(), |id| id.to_string().into())),
         );
 
         // Initialize the HISTFILE variable
@@ -296,8 +305,8 @@ impl Variables {
         None
     }
 
-    pub fn shadow(&mut self, name: SmallString, value: VariableType) -> Option<VariableType> {
-        self.scopes[self.current].insert(name, value)
+    pub fn shadow(&mut self, name: &str, value: VariableType) -> Option<VariableType> {
+        self.scopes[self.current].insert(name.into(), value)
     }
 
     pub fn get_ref(&self, mut name: &str) -> Option<&VariableType> {
@@ -353,24 +362,6 @@ impl Variables {
         None
     }
 
-    #[allow(dead_code)]
-    pub(crate) fn is_hashmap_reference(key: &str) -> Option<(Identifier, Key)> {
-        let mut key_iter = key.split('[');
-
-        if let Some(map_name) = key_iter.next() {
-            if Variables::is_valid_variable_name(map_name) {
-                if let Some(mut inner_key) = key_iter.next() {
-                    if inner_key.ends_with(']') {
-                        inner_key = inner_key.split(']').next().unwrap_or("");
-                        inner_key = inner_key.trim_matches(|c| c == '\'' || c == '\"');
-                        return Some((map_name.into(), inner_key.into()));
-                    }
-                }
-            }
-        }
-        None
-    }
-
     pub(crate) fn tilde_expansion(&self, word: &str, dir_stack: &DirectoryStack) -> Option<String> {
         let mut chars = word.char_indices();
 
@@ -399,8 +390,8 @@ impl Variables {
                 Ok(var) => var + remainder,
                 _ => ["?", remainder].concat()
             }),
-            "-" => if let Some(oldpwd) = self.get::<Value>("OLDPWD") {
-                return Some(oldpwd.clone() + remainder);
+            "-" => if let Some(oldpwd) = self.get::<types::Str>("OLDPWD") {
+                return Some(oldpwd.to_string() + remainder);
             },
             _ => {
                 let neg;
@@ -446,7 +437,7 @@ impl Variables {
         c.is_alphanumeric() || c == '_' || c == '?' || c == '.' || c == '-' || c == '+'
     }
 
-    pub fn string_vars(&self) -> impl Iterator<Item = (&SmallString, &Value)> {
+    pub fn string_vars(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
         self.scopes()
             .map(|map| {
                 map.iter()
@@ -459,14 +450,14 @@ impl Variables {
             .flat_map(|f| f)
     }
 
-    pub fn get_str_or_empty(&self, name: &str) -> String {
-        self.get::<String>(name).unwrap_or_default()
+    pub fn get_str_or_empty(&self, name: &str) -> types::Str {
+        self.get::<types::Str>(name).unwrap_or_default()
     }
 
     pub fn get<T: Clone + From<VariableType> + 'static>(&self, name: &str) -> Option<T> {
         let specified_type = TypeId::of::<T>();
 
-        if specified_type == TypeId::of::<types::Value>() {
+        if specified_type == TypeId::of::<types::Str>() {
             match name {
                 "MWD" => return Some(T::from(VariableType::Str(self.get_minimal_directory()))),
                 "SWD" => return Some(T::from(VariableType::Str(self.get_simplified_directory()))),
@@ -475,9 +466,9 @@ impl Variables {
             // If the parsed name contains the '::' pattern, then a namespace was
             // designated. Find it.
             match name.find("::").map(|pos| (&name[..pos], &name[pos + 2..])) {
-                Some(("c", variable)) | Some(("color", variable)) => Colors::collect(variable).into_string().map(|s| T::from(VariableType::Str(s))),
+                Some(("c", variable)) | Some(("color", variable)) => Colors::collect(variable).into_string().map(|s| T::from(VariableType::Str(s.into()))),
                 Some(("x", variable)) | Some(("hex", variable)) => match u8::from_str_radix(variable, 16) {
-                    Ok(c) => Some(T::from(VariableType::Str((c as char).to_string()))),
+                    Ok(c) => Some(T::from(VariableType::Str((c as char).to_string().into()))),
                     Err(why) => {
                         eprintln!("ion: hex parse error: {}: {}", variable, why);
                         None
@@ -488,7 +479,7 @@ impl Variables {
                     // Otherwise, it's just a simple variable name.
                     match self.get_ref(name) {
                         Some(VariableType::Str(val)) => Some(T::from(VariableType::Str(val.clone()))),
-                        _ => env::var(name).ok().map(|s| T::from(VariableType::Str(s))),
+                        _ => env::var(name).ok().map(|s| T::from(VariableType::Str(s.into()))),
                     }
                 },
                 Some((_, variable)) => {
@@ -511,7 +502,7 @@ impl Variables {
                         // Attempt to execute the given function from that namespace, and map it's
                         // results.
                         match namespace.execute(variable.into()) {
-                            Ok(value) => value.map(|s| T::from(VariableType::Str(s))),
+                            Ok(value) => value.map(|s| T::from(VariableType::Str(s.into()))),
                             Err(why) => {
                                 eprintln!("ion: string namespace error: {}: {}", name, why);
                                 None
@@ -627,7 +618,7 @@ impl Variables {
         }
     }
 
-    pub fn aliases(&self) -> impl Iterator<Item = (&SmallString, &Value)> {
+    pub fn aliases(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
         self.scopes.iter().rev()
             .map(|map| {
                 map.iter()
@@ -640,7 +631,7 @@ impl Variables {
             .flat_map(|f| f)
     }
 
-    pub fn functions(&self) -> impl Iterator<Item = (&SmallString, &Function)> {
+    pub fn functions(&self) -> impl Iterator<Item = (&types::Str, &Function)> {
         self.scopes.iter().rev()
             .map(|map| {
                 map.iter()
@@ -658,7 +649,7 @@ impl Variables {
     /// Further minimizes the directory path in the same manner that Fish does by default.
     /// That is, if more than two parents are visible in the path, all parent directories
     /// of the current directory will be reduced to a single character.
-    fn get_minimal_directory(&self) -> Value {
+    fn get_minimal_directory(&self) -> types::Str {
         let swd = self.get_simplified_directory();
 
         {
@@ -670,7 +661,7 @@ impl Variables {
                 .filter(|s| !s.is_empty())
                 .collect::<Vec<&str>>();
             if elements.len() > 2 {
-                let mut output = String::new();
+                let mut output = types::Str::new();
                 for element in &elements[0..elements.len() - 1] {
                     let mut segmenter = UnicodeSegmentation::graphemes(*element, true);
                     let grapheme = segmenter.next().unwrap();
@@ -692,17 +683,16 @@ impl Variables {
     ///
     /// Useful for getting smaller prompts, this will produce a simplified variant of the
     /// working directory which the leading `HOME` prefix replaced with a tilde character.
-    fn get_simplified_directory(&self) -> Value {
-        let home = match self.get::<Value>("HOME") {
+    fn get_simplified_directory(&self) -> types::Str {
+        let home = match self.get::<types::Str>("HOME") {
             Some(string) => string,
-            None => String::from("?"),
+            None => "?".into(),
         };
-        env::var("PWD")
-            .unwrap()
-            .replace(&home, "~")
+
+        env::var("PWD").unwrap().replace(&*home, "~").into()
     }
 
-    pub fn arrays(&self) -> impl Iterator<Item = (&SmallString, &Array)> {
+    pub fn arrays(&self) -> impl Iterator<Item = (&types::Str, &types::Array)> {
         self.scopes.iter().rev()
             .map(|map| {
                 map.iter()
@@ -724,7 +714,7 @@ impl Variables {
             for arg in args.into_iter().skip(1) {
                 match con.read_line(format!("{}=", arg.as_ref().trim()), None, &mut |_| {}) {
                     Ok(buffer) => {
-                        self.set(arg.as_ref(), buffer.trim().to_string());
+                        self.set(arg.as_ref(), buffer.trim());
                     }
                     Err(_) => return FAILURE,
                 }
@@ -735,7 +725,7 @@ impl Variables {
             let mut lines = handle.lines();
             for arg in args.into_iter().skip(1) {
                 if let Some(Ok(line)) = lines.next() {
-                    self.set(arg.as_ref(), line.trim().to_string());
+                    self.set(arg.as_ref(), line.trim());
                 }
             }
         }
@@ -757,8 +747,8 @@ mod tests {
     struct VariableExpander(pub Variables);
 
     impl Expander for VariableExpander {
-        fn string(&self, var: &str, _: bool) -> Option<Value> {
-            self.0.get::<Value>(var)
+        fn string(&self, var: &str, _: bool) -> Option<types::Str> {
+            self.0.get::<types::Str>(var)
         }
     }
 
@@ -772,28 +762,18 @@ mod tests {
     #[test]
     fn set_var_and_expand_a_variable() {
         let mut variables = Variables::default();
-        variables.set("FOO", "BAR".to_string());
+        variables.set("FOO", "BAR");
         let expanded = expand_string("$FOO", &VariableExpander(variables), false).join("");
         assert_eq!("BAR", &expanded);
     }
 
-    #[test]
-    fn decompose_map_reference() {
-        if let Some((map_name, inner_key)) = Variables::is_hashmap_reference("map[\'key\']") {
-            assert!(map_name == "map".into());
-            assert!(inner_key == "key".into());
-        } else {
-            assert!(false);
-        }
-    }
-
     #[test]
     fn minimal_directory_var_should_compact_path() {
         let variables = Variables::default();
         env::set_var("PWD", "/var/log/nix");
         assert_eq!(
-            "v/l/nix",
-            match variables.get::<Value>("MWD") {
+            types::Str::from("v/l/nix"),
+            match variables.get::<types::Str>("MWD") {
                 Some(string) => string,
                 None => panic!("no value returned")
             }
@@ -805,8 +785,8 @@ mod tests {
         let variables = Variables::default();
         env::set_var("PWD", "/var/log");
         assert_eq!(
-            "/var/log",
-            match variables.get::<Value>("MWD") {
+            types::Str::from("/var/log"),
+            match variables.get::<types::Str>("MWD") {
                 Some(string) => string,
                 None => panic!("no value returned")
             }
diff --git a/src/lib/types.rs b/src/lib/types.rs
index 3a5b6944f99d190ee8941033c58f13253bc59c68..643c57a2093fe8b135884892bcca19fa57c77909 100644
--- a/src/lib/types.rs
+++ b/src/lib/types.rs
@@ -1,27 +1,25 @@
 use fnv::FnvHashMap;
-use smallstring::SmallString;
+use small;
 use smallvec::SmallVec;
 use shell::variables::VariableType;
 use std::{collections::BTreeMap as StdBTreeMap, ops::{Deref, DerefMut}};
 
-pub type Array = SmallVec<[Value; 4]>;
-pub type HashMap = FnvHashMap<Key, VariableType>;
-pub type BTreeMap = StdBTreeMap<String, VariableType>;
-pub type Identifier = SmallString;
-pub type Key = SmallString;
-pub type Value = String;
+pub type Array = SmallVec<[Str; 4]>;
+pub type HashMap = FnvHashMap<Str, VariableType>;
+pub type BTreeMap = StdBTreeMap<Str, VariableType>;
+pub type Str = small::String;
 
 #[derive(Clone, Debug, PartialEq)]
-pub struct Alias(pub String);
+pub struct Alias(pub Str);
 
 impl Alias {
     pub fn empty() -> Self {
-        Alias(String::with_capacity(0))
+        Alias(Str::with_capacity(0))
     }
 }
 
 impl Deref for Alias {
-    type Target = String;
+    type Target = Str;
 
     fn deref(&self) -> &Self::Target {
         &self.0
@@ -34,8 +32,8 @@ impl DerefMut for Alias {
     }
 }
 
-impl Into<String> for Alias {
-    fn into(self) -> String {
+impl Into<Str> for Alias {
+    fn into(self) -> Str {
         self.0
     }
 }