From c61c85a7985358d726cc0ba0649ce9b269b62d5c Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 11 Nov 2019 05:00:49 -0500 Subject: stop using formats at all they are too slow --- Cargo.toml | 1 + src/attrs.rs | 7 ++--- src/grid.rs | 20 ++++--------- src/row.rs | 70 ++++++++++----------------------------------- src/screen.rs | 17 +++-------- src/term.rs | 91 +++++++++++++++++++++++++++++++++-------------------------- 6 files changed, 80 insertions(+), 126 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1b955ed..1d2e329 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ categories = ["command-line-interface", "encoding"] license = "MIT" [dependencies] +itoa = "0.4" enumset = "0.4" log = "0.4" unicode-normalization = "0.1" diff --git a/src/attrs.rs b/src/attrs.rs index 8ba4e7c..08ec857 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -1,4 +1,4 @@ -use std::io::Write as _; +use crate::term::BufWrite as _; /// Represents a foreground or background color for cells. #[derive(Eq, PartialEq, Debug, Copy, Clone)] @@ -95,8 +95,7 @@ impl Attrs { other: &Self, ) { if self != other && self == &Self::default() { - write!(contents, "{}", crate::term::ClearAttrs::default()) - .unwrap(); + crate::term::ClearAttrs::default().write_buf(contents); return; } @@ -133,6 +132,6 @@ impl Attrs { attrs.inverse(self.inverse()) }; - write!(contents, "{}", attrs).unwrap(); + attrs.write_buf(contents); } } diff --git a/src/grid.rs b/src/grid.rs index 2d515ac..242a152 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -1,6 +1,5 @@ +use crate::term::BufWrite as _; use std::convert::TryInto as _; -use std::fmt::Write as _; -use std::io::Write as _; #[derive(Clone, Debug)] pub struct Grid { @@ -170,7 +169,7 @@ impl Grid { for row in self.visible_rows() { row.write_contents(contents, 0, self.size.cols); if !row.wrapped() { - writeln!(contents).unwrap(); + contents.push_str("\n"); } } @@ -183,13 +182,8 @@ impl Grid { &self, contents: &mut Vec, ) -> crate::attrs::Attrs { - write!( - contents, - "{}{}", - crate::term::ClearAttrs::default(), - crate::term::ClearScreen::default() - ) - .unwrap(); + crate::term::ClearAttrs::default().write_buf(contents); + crate::term::ClearScreen::default().write_buf(contents); let mut prev_attrs = crate::attrs::Attrs::default(); let mut prev_pos = Pos::default(); @@ -211,8 +205,7 @@ impl Grid { } if prev_pos != self.pos { - write!(contents, "{}", crate::term::MoveTo::new(self.pos)) - .unwrap(); + crate::term::MoveTo::new(self.pos).write_buf(contents); } prev_attrs @@ -246,8 +239,7 @@ impl Grid { } if prev_pos != self.pos { - write!(contents, "{}", crate::term::MoveTo::new(self.pos)) - .unwrap(); + crate::term::MoveTo::new(self.pos).write_buf(contents); } prev_attrs diff --git a/src/row.rs b/src/row.rs index ff855eb..26e117b 100644 --- a/src/row.rs +++ b/src/row.rs @@ -1,5 +1,5 @@ +use crate::term::BufWrite as _; use std::convert::TryInto as _; -use std::io::Write as _; #[derive(Clone, Debug)] pub struct Row { @@ -87,8 +87,6 @@ impl Row { } if cell.has_contents() { - // using write! here is significantly slower, for some reason - // write!(contents, "{}", cell.contents()).unwrap(); contents.push_str(&cell.contents()); } else { contents.push(' '); @@ -135,26 +133,15 @@ impl Row { || prev_pos.col != self.cols() || pos.col != 0 { - write!( - contents, - "{}{}", - crate::term::CRLF::default(), - crate::term::MoveRight::new(pos.col) - ) - .unwrap(); + crate::term::CRLF::default().write_buf(contents); + crate::term::MoveRight::new(pos.col) + .write_buf(contents); } } else if prev_pos.row == pos.row { - write!( - contents, - "{}", - crate::term::MoveRight::new( - pos.col - prev_pos.col - ) - ) - .unwrap(); + crate::term::MoveRight::new(pos.col - prev_pos.col) + .write_buf(contents); } else { - write!(contents, "{}", crate::term::MoveTo::new(pos)) - .unwrap(); + crate::term::MoveTo::new(pos).write_buf(contents); } prev_pos = pos; } @@ -167,9 +154,6 @@ impl Row { prev_attrs = *attrs; } - // using write! here is significantly slower, for some - // reason - // write!(contents, "{}", cell.contents()).unwrap(); contents.extend(cell.contents().as_bytes()); prev_pos.col += if cell.is_wide() { 2 } else { 1 }; } else { @@ -178,12 +162,7 @@ impl Row { prev_attrs = *attrs; } - write!( - contents, - "{}", - crate::term::EraseChar::default(), - ) - .unwrap(); + crate::term::EraseChar::default().write_buf(contents); } } } @@ -228,28 +207,17 @@ impl Row { || prev_pos.col != self.cols() || pos.col != 0 { - write!( - contents, - "{}{}", - crate::term::CRLF::default(), - crate::term::MoveRight::new(pos.col) - ) - .unwrap(); + crate::term::CRLF::default().write_buf(contents); + crate::term::MoveRight::new(pos.col) + .write_buf(contents); } } else if prev_pos.row == pos.row && prev_pos.col < pos.col { - write!( - contents, - "{}", - crate::term::MoveRight::new( - pos.col - prev_pos.col - ) - ) - .unwrap(); + crate::term::MoveRight::new(pos.col - prev_pos.col) + .write_buf(contents); } else { - write!(contents, "{}", crate::term::MoveTo::new(pos)) - .unwrap(); + crate::term::MoveTo::new(pos).write_buf(contents); } prev_pos = pos; } @@ -262,9 +230,6 @@ impl Row { prev_attrs = *attrs; } - // using write! here is significantly slower, for some - // reason - // write!(contents, "{}", cell.contents()).unwrap(); contents.extend(cell.contents().as_bytes()); prev_pos.col += if cell.is_wide() { 2 } else { 1 }; } else { @@ -273,12 +238,7 @@ impl Row { prev_attrs = *attrs; } - write!( - contents, - "{}", - crate::term::EraseChar::default(), - ) - .unwrap(); + crate::term::EraseChar::default().write_buf(contents); } } } diff --git a/src/screen.rs b/src/screen.rs index 57b37fb..ce86312 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1,5 +1,5 @@ +use crate::term::BufWrite as _; use std::convert::TryInto as _; -use std::io::Write as _; use unicode_width::UnicodeWidthChar as _; const DEFAULT_MULTI_PARAMS: &[i64] = &[0]; @@ -198,12 +198,7 @@ impl Screen { } fn write_contents_formatted(&self, contents: &mut Vec) { - write!( - contents, - "{}", - crate::term::HideCursor::new(self.hide_cursor()) - ) - .unwrap(); + crate::term::HideCursor::new(self.hide_cursor()).write_buf(contents); let prev_attrs = self.grid().write_contents_formatted(contents); self.attrs.write_escape_code_diff(contents, &prev_attrs); } @@ -256,12 +251,8 @@ impl Screen { fn write_contents_diff(&self, contents: &mut Vec, prev: &Self) { if self.hide_cursor() != prev.hide_cursor() { - write!( - contents, - "{}", - crate::term::HideCursor::new(self.hide_cursor()) - ) - .unwrap(); + crate::term::HideCursor::new(self.hide_cursor()) + .write_buf(contents); } let prev_attrs = self.grid().write_contents_diff( contents, diff --git a/src/term.rs b/src/term.rs index 54dfa1d..d353d35 100644 --- a/src/term.rs +++ b/src/term.rs @@ -1,20 +1,24 @@ // TODO: read all of this from terminfo +pub trait BufWrite { + fn write_buf(&self, buf: &mut Vec); +} + #[derive(Default, Debug)] pub struct ClearScreen; -impl std::fmt::Display for ClearScreen { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("\x1b[H\x1b[J") +impl BufWrite for ClearScreen { + fn write_buf(&self, buf: &mut Vec) { + buf.extend_from_slice(b"\x1b[H\x1b[J"); } } #[derive(Default, Debug)] pub struct CRLF; -impl std::fmt::Display for CRLF { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("\r\n") +impl BufWrite for CRLF { + fn write_buf(&self, buf: &mut Vec) { + buf.extend_from_slice(b"\r\n"); } } @@ -33,12 +37,16 @@ impl MoveTo { } } -impl std::fmt::Display for MoveTo { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl BufWrite for MoveTo { + fn write_buf(&self, buf: &mut Vec) { if self.row == 0 && self.col == 0 { - f.write_str("\x1b[H") + buf.extend_from_slice(b"\x1b[H"); } else { - write!(f, "\x1b[{};{}H", self.row + 1, self.col + 1) + buf.extend_from_slice(b"\x1b["); + itoa::write(&mut *buf, self.row + 1).unwrap(); + buf.push(b';'); + itoa::write(&mut *buf, self.col + 1).unwrap(); + buf.push(b'H'); } } } @@ -46,9 +54,9 @@ impl std::fmt::Display for MoveTo { #[derive(Default, Debug)] pub struct ClearAttrs; -impl std::fmt::Display for ClearAttrs { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("\x1b[m") +impl BufWrite for ClearAttrs { + fn write_buf(&self, buf: &mut Vec) { + buf.extend_from_slice(b"\x1b[m") } } @@ -94,13 +102,9 @@ impl Attrs { } } -impl std::fmt::Display for Attrs { - #[allow( - unused_assignments, - clippy::cognitive_complexity, - clippy::too_many_lines - )] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl BufWrite for Attrs { + #[allow(unused_assignments, clippy::cognitive_complexity)] + fn write_buf(&self, buf: &mut Vec) { if self.fgcolor.is_none() && self.bgcolor.is_none() && self.bold.is_none() @@ -108,10 +112,10 @@ impl std::fmt::Display for Attrs { && self.underline.is_none() && self.inverse.is_none() { - return Ok(()); + return; } - f.write_str("\x1b[")?; + buf.extend_from_slice(b"\x1b["); let mut first = true; macro_rules! write_param { @@ -119,9 +123,9 @@ impl std::fmt::Display for Attrs { if first { first = false; } else { - f.write_str(";")?; + buf.push(b';'); } - write!(f, "{}", $i)?; + itoa::write(&mut *buf, $i).unwrap(); }; } @@ -209,8 +213,7 @@ impl std::fmt::Display for Attrs { } } - f.write_str("m")?; - Ok(()) + buf.push(b'm'); } } @@ -231,12 +234,16 @@ impl Default for MoveRight { } } -impl std::fmt::Display for MoveRight { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl BufWrite for MoveRight { + fn write_buf(&self, buf: &mut Vec) { match self.count { - 0 => Ok(()), - 1 => f.write_str("\x1b[C"), - n => write!(f, "\x1b[{}C", n), + 0 => {} + 1 => buf.extend_from_slice(b"\x1b[C"), + n => { + buf.extend_from_slice(b"\x1b["); + itoa::write(&mut *buf, n).unwrap(); + buf.push(b'C'); + } } } } @@ -252,12 +259,16 @@ impl Default for EraseChar { } } -impl std::fmt::Display for EraseChar { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl BufWrite for EraseChar { + fn write_buf(&self, buf: &mut Vec) { match self.count { - 0 => Ok(()), - 1 => f.write_str("\x1b[X"), - n => write!(f, "\x1b[{}X", n), + 0 => {} + 1 => buf.extend_from_slice(b"\x1b[X"), + n => { + buf.extend_from_slice(b"\x1b["); + itoa::write(&mut *buf, n).unwrap(); + buf.push(b'X'); + } } } } @@ -273,12 +284,12 @@ impl HideCursor { } } -impl std::fmt::Display for HideCursor { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl BufWrite for HideCursor { + fn write_buf(&self, buf: &mut Vec) { if self.hide { - f.write_str("\x1b[?25l") + buf.extend_from_slice(b"\x1b[?25l") } else { - f.write_str("\x1b[?25h") + buf.extend_from_slice(b"\x1b[?25h") } } } -- cgit v1.2.3-54-g00ecf