diff --git a/examples/example.rs b/examples/example.rs
index 9bd3ccbdd2cd3e4f98808a34af0344689e0e570b..745bff1b5fc9b669c6f16c348a6db1b278216a9e 100644
--- a/examples/example.rs
+++ b/examples/example.rs
@@ -1,9 +1,7 @@
 extern crate log;
 extern crate rustyline;
 
-use std::cell::RefCell;
 use std::io::{self, Write};
-use std::rc::Rc;
 use log::{LogLevel, LogLevelFilter, LogMetadata, LogRecord, SetLoggerError};
 
 use rustyline::completion::FilenameCompleter;
@@ -23,7 +21,7 @@ static PROMPT: &'static str = ">> ";
 struct Hints {}
 
 impl Hinter for Hints {
-    fn hint(&mut self, line: &str, _pos: usize) -> Option<String> {
+    fn hint(&self, line: &str, _pos: usize) -> Option<String> {
         if line == "hello" {
             Some(" \x1b[1mWorld\x1b[m".to_owned())
         } else {
@@ -41,8 +39,7 @@ fn main() {
         .build();
     let c = FilenameCompleter::new();
     let mut rl = Editor::with_config(config);
-    rl.set_completer(Some(Rc::new(RefCell::new(c))));
-    rl.set_hinter(Some(Rc::new(RefCell::new(Hints {}))));
+    rl.set_helper(Some((c, Hints {})));
     rl.bind_sequence(KeyPress::Meta('N'), Cmd::HistorySearchForward);
     rl.bind_sequence(KeyPress::Meta('P'), Cmd::HistorySearchBackward);
     if rl.load_history("history.txt").is_err() {
diff --git a/src/completion.rs b/src/completion.rs
index 677d3a3d5002e867e0ffed6614decfa6a163cacb..95f610107c89fee56e00d4322624b258a5e84b4b 100644
--- a/src/completion.rs
+++ b/src/completion.rs
@@ -19,7 +19,7 @@ pub trait Completer {
     /// partial word to be completed.
     ///
     /// "ls /usr/loc" => Ok((3, vec!["/usr/local/"]))
-    fn complete(&mut self, line: &str, pos: usize) -> Result<(usize, Vec<String>)>;
+    fn complete(&self, line: &str, pos: usize) -> Result<(usize, Vec<String>)>;
     /// Updates the edited `line` with the `elected` candidate.
     fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
         let end = line.pos();
@@ -27,6 +27,42 @@ pub trait Completer {
     }
 }
 
+impl Completer for () {
+    fn complete(&self, _line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
+        Ok((0, Vec::with_capacity(0)))
+    }
+    fn update(&self, _line: &mut LineBuffer, _start: usize, _elected: &str) {
+        unreachable!()
+    }
+}
+
+impl<'c, C: ?Sized + Completer> Completer for &'c C {
+    fn complete(&self, line: &str, pos: usize) -> Result<(usize, Vec<String>)> {
+        (**self).complete(line, pos)
+    }
+    fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
+        (**self).update(line, start, elected)
+    }
+}
+macro_rules! box_completer {
+    ($($id: ident)*) => {
+        $(
+            impl<C: ?Sized + Completer> Completer for $id<C> {
+                fn complete(&self, line: &str, pos: usize) -> Result<(usize, Vec<String>)> {
+                    (**self).complete(line, pos)
+                }
+                fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
+                    (**self).update(line, start, elected)
+                }
+            }
+        )*
+    }
+}
+
+use std::rc::Rc;
+use std::sync::Arc;
+box_completer! { Box Rc Arc }
+
 /// A `Completer` for file and folder names.
 pub struct FilenameCompleter {
     break_chars: BTreeSet<char>,
@@ -94,7 +130,7 @@ impl Default for FilenameCompleter {
 }
 
 impl Completer for FilenameCompleter {
-    fn complete(&mut self, line: &str, pos: usize) -> Result<(usize, Vec<String>)> {
+    fn complete(&self, line: &str, pos: usize) -> Result<(usize, Vec<String>)> {
         let (start, path) = extract_word(line, pos, ESCAPE_CHAR, &self.break_chars);
         let path = unescape(path, ESCAPE_CHAR);
         let matches = try!(filename_complete(&path, ESCAPE_CHAR, &self.break_chars));
@@ -250,8 +286,8 @@ pub fn longest_common_prefix(candidates: &[String]) -> Option<&str> {
         for (i, c1) in candidates.iter().enumerate().take(candidates.len() - 1) {
             let b1 = c1.as_bytes();
             let b2 = candidates[i + 1].as_bytes();
-            if b1.len() <= longest_common_prefix || b2.len() <= longest_common_prefix ||
-                b1[longest_common_prefix] != b2[longest_common_prefix]
+            if b1.len() <= longest_common_prefix || b2.len() <= longest_common_prefix
+                || b1[longest_common_prefix] != b2[longest_common_prefix]
             {
                 break 'o;
             }
diff --git a/src/hint.rs b/src/hint.rs
index 84342dcc67148fc35e264b74dfbba8ff6a7aae5f..c15db9c82d7bdb3195849852de9c36bdef6e3845 100644
--- a/src/hint.rs
+++ b/src/hint.rs
@@ -5,5 +5,11 @@ pub trait Hinter {
     /// Takes the currently edited `line` with the cursor `pos`ition and
     /// returns the string that should be displayed or `None`
     /// if no hint is available for the text the user currently typed.
-    fn hint(&mut self, line: &str, pos: usize) -> Option<String>;
+    fn hint(&self, line: &str, pos: usize) -> Option<String>;
+}
+
+impl Hinter for () {
+    fn hint(&self, _line: &str, _pos: usize) -> Option<String> {
+        None
+    }
 }
diff --git a/src/history.rs b/src/history.rs
index e26b60bc0adcfc5d821798a2d52a495e7cc5cc17..14af49e3e76f21a410f20a7d2fb0769321513e1a 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -56,9 +56,9 @@ impl History {
         if self.max_len == 0 {
             return false;
         }
-        if line.as_ref().is_empty() ||
-            (self.ignore_space &&
-                line.as_ref()
+        if line.as_ref().is_empty()
+            || (self.ignore_space
+                && line.as_ref()
                     .chars()
                     .next()
                     .map_or(true, |c| c.is_whitespace()))
diff --git a/src/lib.rs b/src/lib.rs
index 31011eb1bc2862518db824717ede74c3193eefe2..6116ca442931846240fc7abab4edeb0abc9e4e12 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,7 +8,7 @@
 //! Usage
 //!
 //! ```
-//! let mut rl = rustyline::Editor::new();
+//! let mut rl = rustyline::Editor::<()>::new();
 //! let readline = rl.readline(">> ");
 //! match readline {
 //!     Ok(line) => println!("Line: {:?}",line),
@@ -86,7 +86,7 @@ struct State<'out, 'prompt> {
     byte_buffer: [u8; 4],
     edit_state: EditState,
     changes: Rc<RefCell<Changeset>>,
-    hinter: Option<Rc<RefCell<Hinter>>>,
+    hinter: Option<&'out Hinter>,
 }
 
 impl<'out, 'prompt> State<'out, 'prompt> {
@@ -96,7 +96,7 @@ impl<'out, 'prompt> State<'out, 'prompt> {
         prompt: &'prompt str,
         history_index: usize,
         custom_bindings: Rc<RefCell<HashMap<KeyPress, Cmd>>>,
-        hinter: Option<Rc<RefCell<Hinter>>>,
+        hinter: Option<&'out Hinter>,
     ) -> State<'out, 'prompt> {
         let capacity = MAX_LINE;
         let prompt_size = out.calculate_position(prompt, Position::default());
@@ -181,10 +181,8 @@ impl<'out, 'prompt> State<'out, 'prompt> {
     }
 
     fn hint(&self) -> Option<String> {
-        if let Some(ref hinter) = self.hinter {
-            hinter
-                .borrow_mut()
-                .hint(self.line.as_str(), self.line.pos())
+        if let Some(hinter) = self.hinter {
+            hinter.hint(self.line.as_str(), self.line.pos())
         } else {
             None
         }
@@ -212,8 +210,8 @@ fn edit_insert(s: &mut State, ch: char, n: RepeatCount) -> Result<()> {
         if push {
             let prompt_size = s.prompt_size;
             let hint = s.hint();
-            if n == 1 && s.cursor.col + ch.width().unwrap_or(0) < s.out.get_columns() &&
-                hint.is_none()
+            if n == 1 && s.cursor.col + ch.width().unwrap_or(0) < s.out.get_columns()
+                && hint.is_none()
             {
                 // Avoid a full update of the line in the trivial case.
                 let cursor = s.out
@@ -541,10 +539,10 @@ fn edit_history(s: &mut State, history: &History, first: bool) -> Result<()> {
 }
 
 /// Completes the line/word
-fn complete_line<R: RawReader, C: Completer + ?Sized>(
+fn complete_line<R: RawReader, C: Completer>(
     rdr: &mut R,
     s: &mut State,
-    completer: &mut C,
+    completer: &C,
     config: &Config,
 ) -> Result<Option<Cmd>> {
     // get a list of completions
@@ -623,10 +621,10 @@ fn complete_line<R: RawReader, C: Completer + ?Sized>(
             let msg = format!("\nDisplay all {} possibilities? (y or n)", candidates.len());
             try!(s.out.write_and_flush(msg.as_bytes()));
             s.old_rows += 1;
-            while cmd != Cmd::SelfInsert(1, 'y') && cmd != Cmd::SelfInsert(1, 'Y') &&
-                cmd != Cmd::SelfInsert(1, 'n') &&
-                cmd != Cmd::SelfInsert(1, 'N') &&
-                cmd != Cmd::Kill(Movement::BackwardChar(1))
+            while cmd != Cmd::SelfInsert(1, 'y') && cmd != Cmd::SelfInsert(1, 'Y')
+                && cmd != Cmd::SelfInsert(1, 'n')
+                && cmd != Cmd::SelfInsert(1, 'N')
+                && cmd != Cmd::Kill(Movement::BackwardChar(1))
             {
                 cmd = try!(s.next_cmd(rdr));
             }
@@ -674,14 +672,14 @@ fn page_completions<R: RawReader>(
         if row == pause_row {
             try!(s.out.write_and_flush(b"\n--More--"));
             let mut cmd = Cmd::Noop;
-            while cmd != Cmd::SelfInsert(1, 'y') && cmd != Cmd::SelfInsert(1, 'Y') &&
-                cmd != Cmd::SelfInsert(1, 'n') &&
-                cmd != Cmd::SelfInsert(1, 'N') &&
-                cmd != Cmd::SelfInsert(1, 'q') &&
-                cmd != Cmd::SelfInsert(1, 'Q') &&
-                cmd != Cmd::SelfInsert(1, ' ') &&
-                cmd != Cmd::Kill(Movement::BackwardChar(1)) &&
-                cmd != Cmd::AcceptLine
+            while cmd != Cmd::SelfInsert(1, 'y') && cmd != Cmd::SelfInsert(1, 'Y')
+                && cmd != Cmd::SelfInsert(1, 'n')
+                && cmd != Cmd::SelfInsert(1, 'N')
+                && cmd != Cmd::SelfInsert(1, 'q')
+                && cmd != Cmd::SelfInsert(1, 'Q')
+                && cmd != Cmd::SelfInsert(1, ' ')
+                && cmd != Cmd::Kill(Movement::BackwardChar(1))
+                && cmd != Cmd::AcceptLine
             {
                 cmd = try!(s.next_cmd(rdr));
             }
@@ -804,14 +802,14 @@ fn reverse_incremental_search<R: RawReader>(
 /// It will also handle special inputs in an appropriate fashion
 /// (e.g., C-c will exit readline)
 #[allow(let_unit_value)]
-fn readline_edit(
+fn readline_edit<H: Helper>(
     prompt: &str,
     initial: Option<(&str, &str)>,
-    editor: &mut Editor,
+    editor: &mut Editor<H>,
     original_mode: tty::Mode,
 ) -> Result<String> {
-    let completer = editor.completer.as_ref();
-    let hinter = editor.hinter.as_ref().cloned();
+    let completer = editor.helper.as_ref().map(|h| h.completer());
+    let hinter = editor.helper.as_ref().map(|h| h.hinter() as &Hinter);
 
     let mut stdout = editor.term.create_writer();
 
@@ -821,7 +819,7 @@ fn readline_edit(
         &editor.config,
         prompt,
         editor.history.len(),
-        editor.custom_bindings.clone(),
+        Rc::clone(&editor.custom_bindings),
         hinter,
     );
 
@@ -847,11 +845,10 @@ fn readline_edit(
 
         // autocomplete
         if cmd == Cmd::Complete && completer.is_some() {
-            use std::ops::DerefMut;
             let next = try!(complete_line(
                 &mut rdr,
                 &mut s,
-                completer.unwrap().borrow_mut().deref_mut(),
+                completer.unwrap(),
                 &editor.config,
             ));
             if next.is_some() {
@@ -1093,10 +1090,10 @@ impl Drop for Guard {
 
 /// Readline method that will enable RAW mode, call the `readline_edit()`
 /// method and disable raw mode
-fn readline_raw(
+fn readline_raw<H: Helper>(
     prompt: &str,
     initial: Option<(&str, &str)>,
-    editor: &mut Editor,
+    editor: &mut Editor<H>,
 ) -> Result<String> {
     let original_mode = try!(editor.term.enable_raw_mode());
     let guard = Guard(original_mode);
@@ -1120,34 +1117,64 @@ fn readline_direct() -> Result<String> {
     }
 }
 
+pub trait Helper {
+    type Completer: Completer;
+    type Hinter: Hinter;
+
+    fn completer(&self) -> &Self::Completer;
+    fn hinter(&self) -> &Self::Hinter;
+}
+
+impl<C: Completer, H: Hinter> Helper for (C, H) {
+    type Completer = C;
+    type Hinter = H;
+
+    fn completer(&self) -> &C {
+        &self.0
+    }
+    fn hinter(&self) -> &H {
+        &self.1
+    }
+}
+impl<C: Completer> Helper for C {
+    type Completer = C;
+    type Hinter = ();
+
+
+    fn completer(&self) -> &C {
+        self
+    }
+    fn hinter(&self) -> &() {
+        &()
+    }
+}
+
 /// Line editor
-pub struct Editor {
+pub struct Editor<H: Helper> {
     term: Terminal,
     history: History,
-    completer: Option<Rc<RefCell<Completer>>>,
+    helper: Option<H>,
     kill_ring: Rc<RefCell<KillRing>>,
     config: Config,
     custom_bindings: Rc<RefCell<HashMap<KeyPress, Cmd>>>,
-    hinter: Option<Rc<RefCell<Hinter>>>,
 }
 
-impl Editor {
+impl<H: Helper> Editor<H> {
     /// Create an editor with the default configuration
-    pub fn new() -> Editor {
+    pub fn new() -> Editor<H> {
         Self::with_config(Config::default())
     }
 
     /// Create an editor with a specific configuration.
-    pub fn with_config(config: Config) -> Editor {
+    pub fn with_config(config: Config) -> Editor<H> {
         let term = Terminal::new();
         Editor {
             term: term,
             history: History::with_config(config),
-            completer: None,
+            helper: None,
             kill_ring: Rc::new(RefCell::new(KillRing::new(60))),
             config: config,
             custom_bindings: Rc::new(RefCell::new(HashMap::new())),
-            hinter: None,
         }
     }
 
@@ -1215,15 +1242,10 @@ impl Editor {
         &self.history
     }
 
-    /// Register a callback function to be called for tab-completion.
-    pub fn set_completer(&mut self, completer: Option<Rc<RefCell<Completer>>>) {
-        self.completer = completer;
-    }
-
-    /// Register a hints function to be called to show hints to the uer at the
-    /// right of the prompt.
-    pub fn set_hinter(&mut self, hinter: Option<Rc<RefCell<Hinter>>>) {
-        self.hinter = hinter;
+    /// Register a callback function to be called for tab-completion
+    /// or to show hints to the user at the right of the prompt.
+    pub fn set_helper(&mut self, helper: Option<H>) {
+        self.helper = helper;
     }
 
     /// Bind a sequence to a command.
@@ -1236,7 +1258,7 @@ impl Editor {
     }
 
     /// ```
-    /// let mut rl = rustyline::Editor::new();
+    /// let mut rl = rustyline::Editor::<()>::new();
     /// for readline in rl.iter("> ") {
     ///     match readline {
     ///         Ok(line) => {
@@ -1249,7 +1271,7 @@ impl Editor {
     ///     }
     /// }
     /// ```
-    pub fn iter<'a>(&'a mut self, prompt: &'a str) -> Iter {
+    pub fn iter<'a>(&'a mut self, prompt: &'a str) -> Iter<H> {
         Iter {
             editor: self,
             prompt: prompt,
@@ -1261,7 +1283,7 @@ impl Editor {
     }
 }
 
-impl fmt::Debug for Editor {
+impl<H: Helper> fmt::Debug for Editor<H> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_struct("Editor")
             .field("term", &self.term)
@@ -1271,12 +1293,15 @@ impl fmt::Debug for Editor {
 }
 
 /// Edited lines iterator
-pub struct Iter<'a> {
-    editor: &'a mut Editor,
+pub struct Iter<'a, H: Helper>
+where
+    H: 'a,
+{
+    editor: &'a mut Editor<H>,
     prompt: &'a str,
 }
 
-impl<'a> Iterator for Iter<'a> {
+impl<'a, H: Helper> Iterator for Iter<'a, H> {
     type Item = Result<String>;
 
     fn next(&mut self) -> Option<Result<String>> {
@@ -1322,8 +1347,8 @@ mod test {
         }
     }
 
-    fn init_editor(keys: &[KeyPress]) -> Editor {
-        let mut editor = Editor::new();
+    fn init_editor(keys: &[KeyPress]) -> Editor<()> {
+        let mut editor = Editor::<()>::new();
         editor.term.keys.extend(keys.iter().cloned());
         editor
     }
@@ -1368,7 +1393,7 @@ mod test {
 
     struct SimpleCompleter;
     impl Completer for SimpleCompleter {
-        fn complete(&mut self, line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
+        fn complete(&self, line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
             Ok((0, vec![line.to_owned() + "t"]))
         }
     }
@@ -1379,9 +1404,8 @@ mod test {
         let mut s = init_state(&mut out, "rus", 3);
         let keys = &[KeyPress::Enter];
         let mut rdr = keys.iter();
-        let mut completer = SimpleCompleter;
-        let cmd =
-            super::complete_line(&mut rdr, &mut s, &mut completer, &Config::default()).unwrap();
+        let completer = SimpleCompleter;
+        let cmd = super::complete_line(&mut rdr, &mut s, &completer, &Config::default()).unwrap();
         assert_eq!(Some(Cmd::AcceptLine), cmd);
         assert_eq!("rust", s.line.as_str());
         assert_eq!(4, s.line.pos());
diff --git a/src/line_buffer.rs b/src/line_buffer.rs
index 703790395d0187d8c1d18bba1f53c290990b7557..4c09c23822dc53ce176fd4941e1d3b88e02a16cd 100644
--- a/src/line_buffer.rs
+++ b/src/line_buffer.rs
@@ -500,8 +500,8 @@ impl LineBuffer {
                 CharSearch::BackwardAfter(c) => pos + c.len_utf8(),
                 CharSearch::Forward(_) => shift + pos,
                 CharSearch::ForwardBefore(_) => {
-                    shift + pos -
-                        self.buf[..shift + pos]
+                    shift + pos
+                        - self.buf[..shift + pos]
                             .chars()
                             .next_back()
                             .unwrap()
@@ -759,12 +759,12 @@ impl Deref for LineBuffer {
 }
 
 fn is_start_of_word(word_def: Word, previous: &str, grapheme: &str) -> bool {
-    (!is_word_char(word_def, previous) && is_word_char(word_def, grapheme)) ||
-        (word_def == Word::Vi && !is_other_char(previous) && is_other_char(grapheme))
+    (!is_word_char(word_def, previous) && is_word_char(word_def, grapheme))
+        || (word_def == Word::Vi && !is_other_char(previous) && is_other_char(grapheme))
 }
 fn is_end_of_word(word_def: Word, grapheme: &str, next: &str) -> bool {
-    (!is_word_char(word_def, next) && is_word_char(word_def, grapheme)) ||
-        (word_def == Word::Vi && !is_other_char(next) && is_other_char(grapheme))
+    (!is_word_char(word_def, next) && is_word_char(word_def, grapheme))
+        || (word_def == Word::Vi && !is_other_char(next) && is_other_char(grapheme))
 }
 
 fn is_word_char(word_def: Word, grapheme: &str) -> bool {
diff --git a/src/tty/mod.rs b/src/tty/mod.rs
index a33f081aecbce97fa3103a0e0d02841bdd653bfc..95cd762bd86c17830f454bdd6cd540e2ffa6f596 100644
--- a/src/tty/mod.rs
+++ b/src/tty/mod.rs
@@ -13,7 +13,7 @@ pub trait RawMode: Copy + Sized {
 }
 
 /// Translate bytes read from stdin to keys.
-pub trait RawReader: Sized {
+pub trait RawReader {
     /// Blocking read of key pressed.
     fn next_key(&mut self) -> Result<KeyPress>;
     /// For CTRL-V support
diff --git a/src/tty/windows.rs b/src/tty/windows.rs
index 0dba4c59f71ffdcd44e0d9d0af22facef9e22c92..fcdb8eb246d2c65eca44a39373bebadcca09249f 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -120,8 +120,8 @@ impl RawReader for ConsoleRawReader {
             }
             let key_event = unsafe { rec.KeyEvent() };
             // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
-            if key_event.bKeyDown == 0 &&
-                key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD
+            if key_event.bKeyDown == 0
+                && key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD
             {
                 continue;
             }
@@ -450,9 +450,9 @@ impl Term for Console {
         }
         let original_mode = try!(get_console_mode(self.stdin_handle));
         // Disable these modes
-        let raw = original_mode &
-            !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
-                winapi::wincon::ENABLE_PROCESSED_INPUT);
+        let raw = original_mode
+            & !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT
+                | winapi::wincon::ENABLE_PROCESSED_INPUT);
         // Enable these modes
         let raw = raw | winapi::wincon::ENABLE_EXTENDED_FLAGS;
         let raw = raw | winapi::wincon::ENABLE_INSERT_MODE;
diff --git a/src/undo.rs b/src/undo.rs
index 910aa1d1026ea8d2d60224ff686cd833b5a3ccee..14a540a787a97cbbb2d520c18eb0894d4c0f8392 100644
--- a/src/undo.rs
+++ b/src/undo.rs
@@ -162,8 +162,8 @@ impl Changeset {
         debug!(target: "rustyline", "Changeset::delete({}, {:?})", indx, string);
         self.redos.clear();
 
-        if !Self::single_char(string.as_ref()) ||
-            !self.undos
+        if !Self::single_char(string.as_ref())
+            || !self.undos
                 .last()
                 .map_or(false, |lc| lc.delete_seq(indx, string.as_ref().len()))
         {
@@ -196,8 +196,8 @@ impl Changeset {
         let mut graphemes = s.graphemes(true);
         graphemes
             .next()
-            .map_or(false, |grapheme| grapheme.is_alphanumeric()) &&
-            graphemes.next().is_none()
+            .map_or(false, |grapheme| grapheme.is_alphanumeric())
+            && graphemes.next().is_none()
     }
 
     pub fn replace<S: AsRef<str> + Into<String> + Debug>(&mut self, indx: usize, old_: S, new_: S) {