Repository: kkawakam/rustyline
Pull request #237 (2019-06-04 18:08:39)

Avoid dynamic dispatch


Patch:
diff --git a/src/edit.rs b/src/edit.rs
index b419b25..5cef2eb 100644
--- a/src/edit.rs
+++ b/src/edit.rs
@@ -12,13 +12,13 @@ use crate::history::Direction;
 use crate::keymap::{Anchor, At, CharSearch, Cmd, Movement, RepeatCount, Word};
 use crate::keymap::{InputState, Refresher};
 use crate::line_buffer::{LineBuffer, WordAction, MAX_LINE};
-use crate::tty::{Position, RawReader, Renderer};
+use crate::tty::{Position, Renderer, Term, Terminal};
 use crate::undo::Changeset;
 
 /// Represent the state during line editing.
 /// Implement rendering.
 pub struct State<'out, 'prompt, H: Helper> {
-    pub out: &'out mut dyn Renderer,
+    pub out: &'out mut <Terminal as Term>::Writer,
     prompt: &'prompt str,  // Prompt to display (rl_prompt)
     prompt_size: Position, // Prompt Unicode/visible width and height
     pub line: LineBuffer,  // Edited line buffer
@@ -42,7 +42,7 @@ enum Info<'m> {
 
 impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
     pub fn new(
-        out: &'out mut dyn Renderer,
+        out: &'out mut <Terminal as Term>::Writer,
         prompt: &'prompt str,
         helper: Option<&'out H>,
         ctx: Context<'out>,
@@ -74,10 +74,10 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
         }
     }
 
-    pub fn next_cmd<R: RawReader>(
+    pub fn next_cmd(
         &mut self,
         input_state: &mut InputState,
-        rdr: &mut R,
+        rdr: &mut <Terminal as Term>::Reader,
         single_esc_abort: bool,
     ) -> Result<Cmd> {
         loop {
@@ -124,7 +124,7 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
         Ok(())
     }
 
-    pub fn move_cursor_at_leftmost<R: RawReader>(&mut self, rdr: &mut R) -> Result<()> {
+    pub fn move_cursor_at_leftmost(&mut self, rdr: &mut <Terminal as Term>::Reader) -> Result<()> {
         self.out.move_cursor_at_leftmost(rdr)
     }
 
@@ -567,7 +567,7 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
 
 #[cfg(test)]
 pub fn init_state<'out, H: Helper>(
-    out: &'out mut dyn Renderer,
+    out: &'out mut <Terminal as Term>::Writer,
     line: &str,
     pos: usize,
     helper: Option<&'out H>,
diff --git a/src/keymap.rs b/src/keymap.rs
index b9063cd..9d497f4 100644
--- a/src/keymap.rs
+++ b/src/keymap.rs
@@ -6,7 +6,7 @@ use super::Result;
 use crate::config::Config;
 use crate::config::EditMode;
 use crate::keys::KeyPress;
-use crate::tty::RawReader;
+use crate::tty::{RawReader, Term, Terminal};
 
 /// The number of times one command should be repeated.
 pub type RepeatCount = usize;
@@ -323,9 +323,9 @@ impl InputState {
     /// Parse user input into one command
     /// `single_esc_abort` is used in emacs mode on unix platform when a single
     /// esc key is expected to abort current action.
-    pub fn next_cmd<R: RawReader>(
+    pub fn next_cmd(
         &mut self,
-        rdr: &mut R,
+        rdr: &mut <Terminal as Term>::Reader,
         wrt: &mut dyn Refresher,
         single_esc_abort: bool,
     ) -> Result<Cmd> {
diff --git a/src/lib.rs b/src/lib.rs
index 3f336b0..1d4b8ca 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -66,8 +66,8 @@ use crate::line_buffer::WordAction;
 pub type Result<T> = result::Result<T, error::ReadlineError>;
 
 /// Completes the line/word
-fn complete_line<R: RawReader, H: Helper>(
-    rdr: &mut R,
+fn complete_line<H: Helper>(
+    rdr: &mut <Terminal as Term>::Reader,
     s: &mut State<'_, '_, H>,
     input_state: &mut InputState,
     config: &Config,
@@ -197,8 +197,8 @@ fn complete_hint_line<H: Helper>(s: &mut State<'_, '_, H>) -> Result<()> {
     Ok(())
 }
 
-fn page_completions<R: RawReader, C: Candidate, H: Helper>(
-    rdr: &mut R,
+fn page_completions<C: Candidate, H: Helper>(
+    rdr: &mut <Terminal as Term>::Reader,
     s: &mut State<'_, '_, H>,
     input_state: &mut InputState,
     candidates: &[C],
@@ -276,8 +276,8 @@ fn page_completions<R: RawReader, C: Candidate, H: Helper>(
 }
 
 /// Incremental search
-fn reverse_incremental_search<R: RawReader, H: Helper>(
-    rdr: &mut R,
+fn reverse_incremental_search<H: Helper>(
+    rdr: &mut <Terminal as Term>::Reader,
     s: &mut State<'_, '_, H>,
     input_state: &mut InputState,
     history: &History,
diff --git a/src/tty/mod.rs b/src/tty/mod.rs
index 94fddd2..ac9aac0 100644
--- a/src/tty/mod.rs
+++ b/src/tty/mod.rs
@@ -34,6 +34,8 @@ pub struct Position {
 
 /// Display prompt, line and cursor in terminal output
 pub trait Renderer {
+    type Reader: RawReader;
+
     fn move_cursor(&mut self, old: Position, new: Position) -> Result<()>;
 
     /// Display `prompt`, line and cursor in terminal output
@@ -80,10 +82,12 @@ pub trait Renderer {
     fn colors_enabled(&self) -> bool;
 
     /// Make sure prompt is at the leftmost edge of the screen
-    fn move_cursor_at_leftmost(&mut self, rdr: &mut dyn RawReader) -> Result<()>;
+    fn move_cursor_at_leftmost(&mut self, rdr: &mut Self::Reader) -> Result<()>;
 }
 
 impl<'a, R: Renderer + ?Sized> Renderer for &'a mut R {
+    type Reader = R::Reader;
+
     fn move_cursor(&mut self, old: Position, new: Position) -> Result<()> {
         (**self).move_cursor(old, new)
     }
@@ -147,7 +151,7 @@ impl<'a, R: Renderer + ?Sized> Renderer for &'a mut R {
         (**self).colors_enabled()
     }
 
-    fn move_cursor_at_leftmost(&mut self, rdr: &mut dyn RawReader) -> Result<()> {
+    fn move_cursor_at_leftmost(&mut self, rdr: &mut R::Reader) -> Result<()> {
         (**self).move_cursor_at_leftmost(rdr)
     }
 }
@@ -155,7 +159,7 @@ impl<'a, R: Renderer + ?Sized> Renderer for &'a mut R {
 /// Terminal contract
 pub trait Term {
     type Reader: RawReader; // rl_instream
-    type Writer: Renderer; // rl_outstream
+    type Writer: Renderer<Reader = Self::Reader>; // rl_outstream
     type Mode: RawMode;
 
     fn new(color_mode: ColorMode, stream: OutputStreamType, tab_stop: usize) -> Self;
diff --git a/src/tty/unix.rs b/src/tty/unix.rs
index 07eb951..2bd3cdc 100644
--- a/src/tty/unix.rs
+++ b/src/tty/unix.rs
@@ -464,6 +464,8 @@ impl PosixRenderer {
 }
 
 impl Renderer for PosixRenderer {
+    type Reader = PosixRawReader;
+
     fn move_cursor(&mut self, old: Position, new: Position) -> Result<()> {
         use std::fmt::Write;
         self.buffer.clear();
@@ -644,7 +646,7 @@ impl Renderer for PosixRenderer {
         self.colors_enabled
     }
 
-    fn move_cursor_at_leftmost(&mut self, rdr: &mut dyn RawReader) -> Result<()> {
+    fn move_cursor_at_leftmost(&mut self, rdr: &mut PosixRawReader) -> Result<()> {
         /* Report cursor location */
         self.write_and_flush(b"\x1b[6n")?;
         /* Read the response: ESC [ rows ; cols R */
@@ -664,7 +666,7 @@ impl Renderer for PosixRenderer {
     }
 }
 
-fn read_digits_until(rdr: &mut dyn RawReader, sep: char) -> Result<u32> {
+fn read_digits_until(rdr: &mut PosixRawReader, sep: char) -> Result<u32> {
     let mut num: u32 = 0;
     loop {
         match rdr.next_char()? {
diff --git a/src/tty/windows.rs b/src/tty/windows.rs
index e909a1f..b296aaa 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -289,6 +289,8 @@ impl ConsoleRenderer {
 }
 
 impl Renderer for ConsoleRenderer {
+    type Reader = ConsoleRawReader;
+
     fn move_cursor(&mut self, old: Position, new: Position) -> Result<()> {
         let mut info = self.get_console_screen_buffer_info()?;
         if new.row > old.row {
@@ -438,7 +440,7 @@ impl Renderer for ConsoleRenderer {
         self.colors_enabled
     }
 
-    fn move_cursor_at_leftmost(&mut self, _: &mut dyn RawReader) -> Result<()> {
+    fn move_cursor_at_leftmost(&mut self, _: &mut ConsoleRawReader) -> Result<()> {
         self.write_and_flush(b"")?; // we must do this otherwise the cursor position is not reported correctly
         let mut info = self.get_console_screen_buffer_info()?;
         if info.dwCursorPosition.X == 0 {


Test patch:
diff --git a/src/test/mod.rs b/src/test/mod.rs
index 375dc43..395fa72 100644
--- a/src/test/mod.rs
+++ b/src/test/mod.rs
@@ -1,5 +1,6 @@
 use std::collections::HashMap;
 use std::sync::{Arc, RwLock};
+use std::vec::IntoIter;
 
 use crate::completion::Completer;
 use crate::config::{Config, EditMode};
@@ -50,8 +51,8 @@ fn complete_line() {
     let mut s = init_state(&mut out, "rus", 3, helper.as_ref(), &history);
     let config = Config::default();
     let mut input_state = InputState::new(&config, Arc::new(RwLock::new(HashMap::new())));
-    let keys = &[KeyPress::Enter];
-    let mut rdr = keys.iter();
+    let keys = vec![KeyPress::Enter];
+    let mut rdr: IntoIter<KeyPress> = keys.into_iter();
     let cmd = super::complete_line(&mut rdr, &mut s, &mut input_state, &Config::default()).unwrap();
     assert_eq!(Some(Cmd::AcceptLine), cmd);
     assert_eq!("rust", s.line.as_str());
diff --git a/src/tty/test.rs b/src/tty/test.rs
index ce0bfd5..bb968e7 100644
--- a/src/tty/test.rs
+++ b/src/tty/test.rs
@@ -68,6 +68,8 @@ impl Sink {
 }
 
 impl Renderer for Sink {
+    type Reader = IntoIter<KeyPress>;
+
     fn move_cursor(&mut self, _: Position, _: Position) -> Result<()> {
         Ok(())
     }
@@ -127,7 +129,7 @@ impl Renderer for Sink {
         false
     }
 
-    fn move_cursor_at_leftmost(&mut self, _: &mut dyn RawReader) -> Result<()> {
+    fn move_cursor_at_leftmost(&mut self, _: &mut IntoIter<KeyPress>) -> Result<()> {
         Ok(())
     }
 }