aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-11-13 07:20:33 -0500
committerJesse Luehrs <doy@tozt.net>2019-11-13 07:20:33 -0500
commit6c439e27c47d0e2d4da9c2d253a57156bf32e5d8 (patch)
tree4c4f137ae707146fa8e4de93b8ca811162b4ba5d
parente85e57949df612e22463c06fc31fb0b7957ea3c7 (diff)
downloadvt100-rust-direct-write.tar.gz
vt100-rust-direct-write.zip
attempt to avoid copies by writing directly to a std::io::Writedirect-write
this turns out to be slower, i think because it ends up doing a much larger number of small writes, and the copying overhead isn't as high as going through all of the machinery involved in stdout locking/buffering/syscalls/etc.
-rw-r--r--examples/process_diff.rs12
-rw-r--r--examples/process_full.rs11
-rw-r--r--src/attrs.rs14
-rw-r--r--src/grid.rs52
-rw-r--r--src/row.rs68
-rw-r--r--src/screen.rs132
-rw-r--r--src/term.rs212
7 files changed, 274 insertions, 227 deletions
diff --git a/examples/process_diff.rs b/examples/process_diff.rs
index c141269..55ebbf2 100644
--- a/examples/process_diff.rs
+++ b/examples/process_diff.rs
@@ -1,4 +1,4 @@
-use std::io::{Read as _, Write as _};
+use std::io::Read as _;
fn read_frames() -> impl Iterator<Item = Vec<u8>> {
(1..=7625).map(|i| {
@@ -14,13 +14,13 @@ fn read_frames() -> impl Iterator<Item = Vec<u8>> {
fn draw_frames(frames: &[Vec<u8>]) {
let mut stdout = std::io::stdout();
let mut parser = vt100::Parser::default();
- let mut screen = parser.screen().clone();
for frame in frames {
+ let screen = parser.screen().clone();
parser.process(&frame);
- let new_screen = parser.screen().clone();
- let diff = new_screen.contents_diff(&screen);
- stdout.write_all(&diff).unwrap();
- screen = new_screen;
+ parser
+ .screen()
+ .write_contents_diff(&mut stdout, &screen)
+ .unwrap();
}
}
diff --git a/examples/process_full.rs b/examples/process_full.rs
index 5aa5422..3be0ec0 100644
--- a/examples/process_full.rs
+++ b/examples/process_full.rs
@@ -1,4 +1,4 @@
-use std::io::{Read as _, Write as _};
+use std::io::Read as _;
fn read_frames() -> impl Iterator<Item = Vec<u8>> {
(1..=7625).map(|i| {
@@ -12,12 +12,15 @@ fn read_frames() -> impl Iterator<Item = Vec<u8>> {
}
fn draw_frames(frames: &[Vec<u8>]) {
- let mut stdout = std::io::stdout();
+ let stdout = std::io::stdout();
+ let mut stdout = stdout.lock();
let mut parser = vt100::Parser::default();
for frame in frames {
parser.process(&frame);
- let contents = parser.screen().contents_formatted();
- stdout.write_all(&contents).unwrap();
+ parser
+ .screen()
+ .write_contents_formatted(&mut stdout)
+ .unwrap();
}
}
diff --git a/src/attrs.rs b/src/attrs.rs
index eab752c..8e6b44f 100644
--- a/src/attrs.rs
+++ b/src/attrs.rs
@@ -1,4 +1,4 @@
-use crate::term::BufWrite as _;
+use crate::term::WriteTo as _;
/// Represents a foreground or background color for cells.
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
@@ -83,14 +83,14 @@ impl Attrs {
}
}
- pub fn write_escape_code_diff(
+ pub fn write_escape_code_diff<W: std::io::Write>(
&self,
- contents: &mut Vec<u8>,
+ w: &mut W,
other: &Self,
- ) {
+ ) -> std::io::Result<()> {
if self != other && self == &Self::default() {
- crate::term::ClearAttrs::default().write_buf(contents);
- return;
+ crate::term::ClearAttrs::default().write_to(w)?;
+ return Ok(());
}
let attrs = crate::term::Attrs::default();
@@ -126,6 +126,6 @@ impl Attrs {
attrs.inverse(self.inverse())
};
- attrs.write_buf(contents);
+ attrs.write_to(w)
}
}
diff --git a/src/grid.rs b/src/grid.rs
index 80d44ba..4248b1c 100644
--- a/src/grid.rs
+++ b/src/grid.rs
@@ -1,4 +1,4 @@
-use crate::term::BufWrite as _;
+use crate::term::WriteTo as _;
use std::convert::TryInto as _;
#[derive(Clone, Debug)]
@@ -173,25 +173,31 @@ impl Grid {
self.scrollback_offset = rows.min(self.scrollback.len());
}
- pub fn write_contents(&self, contents: &mut String) {
+ pub fn write_contents<W: std::io::Write>(
+ &self,
+ w: &mut W,
+ ) -> std::io::Result<()> {
for row in self.visible_rows() {
- row.write_contents(contents, 0, self.size.cols);
+ row.write_contents(w, 0, self.size.cols)?;
if !row.wrapped() {
- contents.push_str("\n");
+ w.write_all(b"\n")?;
}
}
- while contents.ends_with('\n') {
- contents.truncate(contents.len() - 1);
- }
+ // XXX
+ // while contents.ends_with('\n') {
+ // contents.truncate(contents.len() - 1);
+ // }
+
+ Ok(())
}
- pub fn write_contents_formatted(
+ pub fn write_contents_formatted<W: std::io::Write>(
&self,
- contents: &mut Vec<u8>,
- ) -> crate::attrs::Attrs {
- crate::term::ClearAttrs::default().write_buf(contents);
- crate::term::ClearScreen::default().write_buf(contents);
+ w: &mut W,
+ ) -> std::io::Result<crate::attrs::Attrs> {
+ crate::term::ClearAttrs::default().write_to(w)?;
+ crate::term::ClearScreen::default().write_to(w)?;
let mut prev_attrs = crate::attrs::Attrs::default();
let mut prev_pos = Pos::default();
@@ -199,30 +205,30 @@ impl Grid {
for (i, row) in self.visible_rows().enumerate() {
let i = i.try_into().unwrap();
let (new_pos, new_attrs) = row.write_contents_formatted(
- contents,
+ w,
0,
self.size.cols,
i,
wrapping,
prev_pos,
prev_attrs,
- );
+ )?;
prev_pos = new_pos;
prev_attrs = new_attrs;
wrapping = row.wrapped();
}
- crate::term::MoveFromTo::new(prev_pos, self.pos).write_buf(contents);
+ crate::term::MoveFromTo::new(prev_pos, self.pos).write_to(w)?;
- prev_attrs
+ Ok(prev_attrs)
}
- pub fn write_contents_diff(
+ pub fn write_contents_diff<W: std::io::Write>(
&self,
- contents: &mut Vec<u8>,
+ w: &mut W,
prev: &Self,
mut prev_attrs: crate::attrs::Attrs,
- ) -> crate::attrs::Attrs {
+ ) -> std::io::Result<crate::attrs::Attrs> {
let mut prev_pos = prev.pos;
let mut wrapping = false;
for (i, (row, prev_row)) in
@@ -230,7 +236,7 @@ impl Grid {
{
let i = i.try_into().unwrap();
let (new_pos, new_attrs) = row.write_contents_diff(
- contents,
+ w,
prev_row,
0,
self.size.cols,
@@ -238,15 +244,15 @@ impl Grid {
wrapping,
prev_pos,
prev_attrs,
- );
+ )?;
prev_pos = new_pos;
prev_attrs = new_attrs;
wrapping = row.wrapped();
}
- crate::term::MoveFromTo::new(prev_pos, self.pos).write_buf(contents);
+ crate::term::MoveFromTo::new(prev_pos, self.pos).write_to(w)?;
- prev_attrs
+ Ok(prev_attrs)
}
pub fn erase_all(&mut self, attrs: crate::attrs::Attrs) {
diff --git a/src/row.rs b/src/row.rs
index 52b6823..87e2544 100644
--- a/src/row.rs
+++ b/src/row.rs
@@ -1,4 +1,4 @@
-use crate::term::BufWrite as _;
+use crate::term::WriteTo as _;
use std::convert::TryInto as _;
#[derive(Clone, Debug)]
@@ -68,12 +68,12 @@ impl Row {
self.wrapped
}
- pub fn write_contents(
+ pub fn write_contents<W: std::io::Write>(
&self,
- contents: &mut String,
+ w: &mut W,
start: u16,
width: u16,
- ) {
+ ) -> std::io::Result<()> {
let mut prev_was_wide = false;
let mut prev_col = start;
@@ -92,26 +92,28 @@ impl Row {
let col: u16 = col.try_into().unwrap();
if cell.has_contents() {
for _ in 0..(col - prev_col) {
- contents.push(' ');
+ w.write_all(b" ")?;
}
prev_col += col - prev_col;
- contents.push_str(&cell.contents());
+ w.write_all(cell.contents().as_bytes())?;
prev_col += if cell.is_wide() { 2 } else { 1 };
}
}
+
+ Ok(())
}
- pub fn write_contents_formatted(
+ pub fn write_contents_formatted<W: std::io::Write>(
&self,
- contents: &mut Vec<u8>,
+ w: &mut W,
start: u16,
width: u16,
row: u16,
wrapping: bool,
mut prev_pos: crate::grid::Pos,
mut prev_attrs: crate::attrs::Attrs,
- ) -> (crate::grid::Pos, crate::attrs::Attrs) {
+ ) -> std::io::Result<(crate::grid::Pos, crate::attrs::Attrs)> {
let mut prev_was_wide = false;
let default_cell = crate::cell::Cell::default();
@@ -137,14 +139,14 @@ impl Row {
if cell.has_contents() || cell.attrs() != attrs {
let new_pos = crate::grid::Pos { row, col: prev_col };
crate::term::MoveFromTo::new(prev_pos, new_pos)
- .write_buf(contents);
+ .write_to(w)?;
prev_pos = new_pos;
if &prev_attrs != attrs {
- attrs.write_escape_code_diff(contents, &prev_attrs);
+ attrs.write_escape_code_diff(w, &prev_attrs)?;
prev_attrs = *attrs;
}
crate::term::EraseChar::new(pos.col - prev_col)
- .write_buf(contents);
+ .write_to(w)?;
erase = None;
}
}
@@ -159,17 +161,17 @@ impl Row {
|| pos.col != 0
{
crate::term::MoveFromTo::new(prev_pos, pos)
- .write_buf(contents);
+ .write_to(w)?;
}
prev_pos = pos;
}
if &prev_attrs != attrs {
- attrs.write_escape_code_diff(contents, &prev_attrs);
+ attrs.write_escape_code_diff(w, &prev_attrs)?;
prev_attrs = *attrs;
}
- contents.extend(cell.contents().as_bytes());
+ w.write_all(cell.contents().as_bytes())?;
prev_pos.col += if cell.is_wide() { 2 } else { 1 };
} else if erase.is_none() {
erase = Some((pos.col, attrs));
@@ -178,25 +180,24 @@ impl Row {
}
if let Some((prev_col, attrs)) = erase {
let new_pos = crate::grid::Pos { row, col: prev_col };
- crate::term::MoveFromTo::new(prev_pos, new_pos)
- .write_buf(contents);
+ crate::term::MoveFromTo::new(prev_pos, new_pos).write_to(w)?;
prev_pos = new_pos;
if &prev_attrs != attrs {
- attrs.write_escape_code_diff(contents, &prev_attrs);
+ attrs.write_escape_code_diff(w, &prev_attrs)?;
prev_attrs = *attrs;
}
- crate::term::ClearRowForward::default().write_buf(contents);
+ crate::term::ClearRowForward::default().write_to(w)?;
}
- (prev_pos, prev_attrs)
+ Ok((prev_pos, prev_attrs))
}
// while it's true that most of the logic in this is identical to
// write_contents_formatted, i can't figure out how to break out the
// common parts without making things noticeably slower.
- pub fn write_contents_diff(
+ pub fn write_contents_diff<W: std::io::Write>(
&self,
- contents: &mut Vec<u8>,
+ w: &mut W,
prev: &Self,
start: u16,
width: u16,
@@ -204,7 +205,7 @@ impl Row {
wrapping: bool,
mut prev_pos: crate::grid::Pos,
mut prev_attrs: crate::attrs::Attrs,
- ) -> (crate::grid::Pos, crate::attrs::Attrs) {
+ ) -> std::io::Result<(crate::grid::Pos, crate::attrs::Attrs)> {
let mut prev_was_wide = false;
let mut erase: Option<(u16, &crate::attrs::Attrs)> = None;
@@ -230,14 +231,14 @@ impl Row {
if cell.has_contents() || cell.attrs() != attrs {
let new_pos = crate::grid::Pos { row, col: prev_col };
crate::term::MoveFromTo::new(prev_pos, new_pos)
- .write_buf(contents);
+ .write_to(w)?;
prev_pos = new_pos;
if &prev_attrs != attrs {
- attrs.write_escape_code_diff(contents, &prev_attrs);
+ attrs.write_escape_code_diff(w, &prev_attrs)?;
prev_attrs = *attrs;
}
crate::term::EraseChar::new(pos.col - prev_col)
- .write_buf(contents);
+ .write_to(w)?;
erase = None;
}
}
@@ -252,17 +253,17 @@ impl Row {
|| pos.col != 0
{
crate::term::MoveFromTo::new(prev_pos, pos)
- .write_buf(contents);
+ .write_to(w)?;
}
prev_pos = pos;
}
if &prev_attrs != attrs {
- attrs.write_escape_code_diff(contents, &prev_attrs);
+ attrs.write_escape_code_diff(w, &prev_attrs)?;
prev_attrs = *attrs;
}
- contents.extend(cell.contents().as_bytes());
+ w.write_all(cell.contents().as_bytes())?;
prev_pos.col += if cell.is_wide() { 2 } else { 1 };
} else if erase.is_none() {
erase = Some((pos.col, attrs));
@@ -271,16 +272,15 @@ impl Row {
}
if let Some((prev_col, attrs)) = erase {
let new_pos = crate::grid::Pos { row, col: prev_col };
- crate::term::MoveFromTo::new(prev_pos, new_pos)
- .write_buf(contents);
+ crate::term::MoveFromTo::new(prev_pos, new_pos).write_to(w)?;
prev_pos = new_pos;
if &prev_attrs != attrs {
- attrs.write_escape_code_diff(contents, &prev_attrs);
+ attrs.write_escape_code_diff(w, &prev_attrs)?;
prev_attrs = *attrs;
}
- crate::term::ClearRowForward::default().write_buf(contents);
+ crate::term::ClearRowForward::default().write_to(w)?;
}
- (prev_pos, prev_attrs)
+ Ok((prev_pos, prev_attrs))
}
}
diff --git a/src/screen.rs b/src/screen.rs
index 3128f78..750f090 100644
--- a/src/screen.rs
+++ b/src/screen.rs
@@ -1,4 +1,4 @@
-use crate::term::BufWrite as _;
+use crate::term::WriteTo as _;
use std::convert::TryInto as _;
use unicode_width::UnicodeWidthChar as _;
@@ -141,13 +141,16 @@ impl Screen {
/// This will not include any formatting information, and will be in plain
/// text format.
pub fn contents(&self) -> String {
- let mut contents = String::new();
- self.write_contents(&mut contents);
- contents
+ let mut contents = vec![];
+ self.write_contents(&mut contents).unwrap();
+ String::from_utf8(contents).unwrap()
}
- fn write_contents(&self, contents: &mut String) {
- self.grid().write_contents(contents);
+ pub fn write_contents<W: std::io::Write>(
+ &self,
+ w: &mut W,
+ ) -> std::io::Result<()> {
+ self.grid().write_contents(w)
}
/// Returns the text contents of the terminal by row, restricted to the
@@ -163,9 +166,9 @@ impl Screen {
width: u16,
) -> impl Iterator<Item = String> + '_ {
self.grid().visible_rows().map(move |row| {
- let mut contents = String::new();
- row.write_contents(&mut contents, start, width);
- contents
+ let mut contents = vec![];
+ row.write_contents(&mut contents, start, width).unwrap();
+ String::from_utf8(contents).unwrap()
})
}
@@ -176,14 +179,18 @@ impl Screen {
/// terminal parser, and will result in the same visual output.
pub fn contents_formatted(&self) -> Vec<u8> {
let mut contents = vec![];
- self.write_contents_formatted(&mut contents);
+ self.write_contents_formatted(&mut contents).unwrap();
contents
}
- fn write_contents_formatted(&self, contents: &mut Vec<u8>) {
- 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);
+ pub fn write_contents_formatted<W: std::io::Write>(
+ &self,
+ w: &mut W,
+ ) -> std::io::Result<()> {
+ crate::term::HideCursor::new(self.hide_cursor()).write_to(w)?;
+ let prev_attrs = self.grid().write_contents_formatted(w)?;
+ self.attrs.write_escape_code_diff(w, &prev_attrs)?;
+ Ok(())
}
/// Returns the formatted visible contents of the terminal by row,
@@ -212,7 +219,8 @@ impl Screen {
false,
crate::grid::Pos { row: i, col: start },
crate::attrs::Attrs::default(),
- );
+ )
+ .unwrap();
contents
})
}
@@ -229,21 +237,23 @@ impl Screen {
/// flickering than redrawing the entire screen contents.
pub fn contents_diff(&self, prev: &Self) -> Vec<u8> {
let mut contents = vec![];
- self.write_contents_diff(&mut contents, prev);
+ self.write_contents_diff(&mut contents, prev).unwrap();
contents
}
- fn write_contents_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
+ pub fn write_contents_diff<W: std::io::Write>(
+ &self,
+ w: &mut W,
+ prev: &Self,
+ ) -> std::io::Result<()> {
if self.hide_cursor() != prev.hide_cursor() {
- crate::term::HideCursor::new(self.hide_cursor())
- .write_buf(contents);
+ crate::term::HideCursor::new(self.hide_cursor()).write_to(w)?;
}
- let prev_attrs = self.grid().write_contents_diff(
- contents,
- prev.grid(),
- prev.attrs,
- );
- self.attrs.write_escape_code_diff(contents, &prev_attrs);
+ let prev_attrs =
+ self.grid()
+ .write_contents_diff(w, prev.grid(), prev.attrs)?;
+ self.attrs.write_escape_code_diff(w, &prev_attrs)?;
+ Ok(())
}
/// Returns a sequence of terminal byte streams sufficient to turn the
@@ -276,54 +286,63 @@ impl Screen {
false,
crate::grid::Pos { row: i, col: start },
crate::attrs::Attrs::default(),
- );
+ )
+ .unwrap();
contents
})
}
pub fn input_mode_formatted(&self) -> Vec<u8> {
let mut contents = vec![];
- self.write_input_mode_formatted(&mut contents);
+ self.write_input_mode_formatted(&mut contents).unwrap();
contents
}
- fn write_input_mode_formatted(&self, contents: &mut Vec<u8>) {
+ pub fn write_input_mode_formatted<W: std::io::Write>(
+ &self,
+ w: &mut W,
+ ) -> std::io::Result<()> {
crate::term::ApplicationKeypad::new(
self.mode(Mode::ApplicationKeypad),
)
- .write_buf(contents);
+ .write_to(w)?;
crate::term::ApplicationCursor::new(
self.mode(Mode::ApplicationCursor),
)
- .write_buf(contents);
+ .write_to(w)?;
crate::term::BracketedPaste::new(self.mode(Mode::BracketedPaste))
- .write_buf(contents);
+ .write_to(w)?;
crate::term::MouseProtocolMode::new(
self.mouse_protocol_mode,
MouseProtocolMode::None,
)
- .write_buf(contents);
+ .write_to(w)?;
crate::term::MouseProtocolEncoding::new(
self.mouse_protocol_encoding,
MouseProtocolEncoding::Default,
)
- .write_buf(contents);
+ .write_to(w)?;
+ Ok(())
}
pub fn input_mode_diff(&self, prev: &Self) -> Vec<u8> {
let mut contents = vec![];
- self.write_input_mode_diff(&mut contents, prev);
+ self.write_input_mode_diff(&mut contents, prev).unwrap();
contents
}
- fn write_input_mode_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
+ pub fn write_input_mode_diff<W: std::io::Write>(
+ &self,
+ w: &mut W,
+ prev: &Self,
+ ) -> std::io::Result<()> {
if self.mode(Mode::ApplicationKeypad)
!= prev.mode(Mode::ApplicationKeypad)
{
crate::term::ApplicationKeypad::new(
self.mode(Mode::ApplicationKeypad),
)
- .write_buf(contents);
+ .write_to(w)?;
}
if self.mode(Mode::ApplicationCursor)
!= prev.mode(Mode::ApplicationCursor)
@@ -331,65 +350,78 @@ impl Screen {
crate::term::ApplicationCursor::new(
self.mode(Mode::ApplicationCursor),
)
- .write_buf(contents);
+ .write_to(w)?;
}
if self.mode(Mode::BracketedPaste) != prev.mode(Mode::BracketedPaste)
{
crate::term::BracketedPaste::new(self.mode(Mode::BracketedPaste))
- .write_buf(contents);
+ .write_to(w)?;
}
crate::term::MouseProtocolMode::new(
self.mouse_protocol_mode,
prev.mouse_protocol_mode,
)
- .write_buf(contents);
+ .write_to(w)?;
crate::term::MouseProtocolEncoding::new(
self.mouse_protocol_encoding,
prev.mouse_protocol_encoding,
)
- .write_buf(contents);
+ .write_to(w)?;
+ Ok(())
}
pub fn title_formatted(&self) -> Vec<u8> {
let mut contents = vec![];
- self.write_title_formatted(&mut contents);
+ self.write_title_formatted(&mut contents).unwrap();
contents
}
- fn write_title_formatted(&self, contents: &mut Vec<u8>) {
+ pub fn write_title_formatted<W: std::io::Write>(
+ &self,
+ w: &mut W,
+ ) -> std::io::Result<()> {
crate::term::ChangeTitle::new(&self.icon_name, &self.title, "", "")
- .write_buf(contents);
+ .write_to(w)
}
pub fn title_diff(&self, prev: &Self) -> Vec<u8> {
let mut contents = vec![];
- self.write_title_diff(&mut contents, prev);
+ self.write_title_diff(&mut contents, prev).unwrap();
contents
}
- fn write_title_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
+ pub fn write_title_diff<W: std::io::Write>(
+ &self,
+ w: &mut W,
+ prev: &Self,
+ ) -> std::io::Result<()> {
crate::term::ChangeTitle::new(
&self.icon_name,
&self.title,
&prev.icon_name,
&prev.title,
)
- .write_buf(contents);
+ .write_to(w)
}
pub fn bells_diff(&self, prev: &Self) -> Vec<u8> {
let mut contents = vec![];
- self.write_bells_diff(&mut contents, prev);
+ self.write_bells_diff(&mut contents, prev).unwrap();
contents
}
- fn write_bells_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
+ pub fn write_bells_diff<W: std::io::Write>(
+ &self,
+ w: &mut W,
+ prev: &Self,
+ ) -> std::io::Result<()> {
if self.audible_bell_count != prev.audible_bell_count {
- crate::term::AudibleBell::default().write_buf(contents);
+ crate::term::AudibleBell::default().write_to(w)?;
}
if self.visual_bell_count != prev.visual_bell_count {
- crate::term::VisualBell::default().write_buf(contents);
+ crate::term::VisualBell::default().write_to(w)?;
}
+ Ok(())
}
/// Returns the `Cell` object at the given location in the terminal, if it
diff --git a/src/term.rs b/src/term.rs
index d2f7c9b..3c6623b 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -1,16 +1,16 @@
// TODO: read all of this from terminfo
-pub trait BufWrite {
- fn write_buf(&self, buf: &mut Vec<u8>);
+pub trait WriteTo<W: std::io::Write> {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()>;
}
#[derive(Default, Debug)]
-#[must_use = "this struct does nothing unless you call write_buf"]
+#[must_use = "this struct does nothing unless you call write_to"]
pub struct ClearScreen;
-impl BufWrite for ClearScreen {
- fn write_buf(&self, buf: &mut Vec<u8>) {
- buf.extend_from_slice(b"\x1b[H\x1b[J");
+impl<W: std::io::Write> WriteTo<W> for ClearScreen {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
+ w.write_all(b"\x1b[H\x1b[J")
}
}
@@ -18,9 +18,9 @@ impl BufWrite for ClearScreen {
#[must_use = "this struct does nothing unless you call write_buf"]
pub struct ClearRowForward;
-impl BufWrite for ClearRowForward {
- fn write_buf(&self, buf: &mut Vec<u8>) {
- buf.extend_from_slice(b"\x1b[K");
+impl<W: std::io::Write> WriteTo<W> for ClearRowForward {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
+ w.write_all(b"\x1b[K")
}
}
@@ -28,9 +28,9 @@ impl BufWrite for ClearRowForward {
#[must_use = "this struct does nothing unless you call write_buf"]
pub struct CRLF;
-impl BufWrite for CRLF {
- fn write_buf(&self, buf: &mut Vec<u8>) {
- buf.extend_from_slice(b"\r\n");
+impl<W: std::io::Write> WriteTo<W> for CRLF {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
+ w.write_all(b"\r\n")
}
}
@@ -50,17 +50,18 @@ impl MoveTo {
}
}
-impl BufWrite for MoveTo {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<W: std::io::Write> WriteTo<W> for MoveTo {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
if self.row == 0 && self.col == 0 {
- buf.extend_from_slice(b"\x1b[H");
+ w.write_all(b"\x1b[H")?;
} else {
- 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');
+ w.write_all(b"\x1b[")?;
+ itoa::write(&mut *w, self.row + 1)?;
+ w.write_all(b";")?;
+ itoa::write(&mut *w, self.col + 1)?;
+ w.write_all(b"H")?;
}
+ Ok(())
}
}
@@ -68,9 +69,9 @@ impl BufWrite for MoveTo {
#[must_use = "this struct does nothing unless you call write_buf"]
pub struct ClearAttrs;
-impl BufWrite for ClearAttrs {
- fn write_buf(&self, buf: &mut Vec<u8>) {
- buf.extend_from_slice(b"\x1b[m")
+impl<W: std::io::Write> WriteTo<W> for ClearAttrs {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
+ w.write_all(b"\x1b[m")
}
}
@@ -117,9 +118,9 @@ impl Attrs {
}
}
-impl BufWrite for Attrs {
+impl<W: std::io::Write> WriteTo<W> for Attrs {
#[allow(unused_assignments)]
- fn write_buf(&self, buf: &mut Vec<u8>) {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
if self.fgcolor.is_none()
&& self.bgcolor.is_none()
&& self.bold.is_none()
@@ -127,10 +128,10 @@ impl BufWrite for Attrs {
&& self.underline.is_none()
&& self.inverse.is_none()
{
- return;
+ return Ok(());
}
- buf.extend_from_slice(b"\x1b[");
+ w.write_all(b"\x1b[")?;
let mut first = true;
macro_rules! write_param {
@@ -138,9 +139,9 @@ impl BufWrite for Attrs {
if first {
first = false;
} else {
- buf.push(b';');
+ w.write_all(b";")?;
}
- itoa::write(&mut *buf, $i).unwrap();
+ itoa::write(&mut *w, $i).unwrap();
};
}
@@ -228,7 +229,7 @@ impl BufWrite for Attrs {
}
}
- buf.push(b'm');
+ w.write_all(b"m")
}
}
@@ -250,17 +251,18 @@ impl Default for MoveRight {
}
}
-impl BufWrite for MoveRight {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<W: std::io::Write> WriteTo<W> for MoveRight {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
match self.count {
0 => {}
- 1 => buf.extend_from_slice(b"\x1b[C"),
+ 1 => w.write_all(b"\x1b[C")?,
n => {
- buf.extend_from_slice(b"\x1b[");
- itoa::write(&mut *buf, n).unwrap();
- buf.push(b'C');
+ w.write_all(b"\x1b[")?;
+ itoa::write(&mut *w, n)?;
+ w.write_all(b"C")?;
}
}
+ Ok(())
}
}
@@ -282,17 +284,18 @@ impl Default for EraseChar {
}
}
-impl BufWrite for EraseChar {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<W: std::io::Write> WriteTo<W> for EraseChar {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
match self.count {
0 => {}
- 1 => buf.extend_from_slice(b"\x1b[X"),
+ 1 => w.write_all(b"\x1b[X")?,
n => {
- buf.extend_from_slice(b"\x1b[");
- itoa::write(&mut *buf, n).unwrap();
- buf.push(b'X');
+ w.write_all(b"\x1b[")?;
+ itoa::write(&mut *w, n)?;
+ w.write_all(b"X")?;
}
}
+ Ok(())
}
}
@@ -308,12 +311,12 @@ impl HideCursor {
}
}
-impl BufWrite for HideCursor {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<W: std::io::Write> WriteTo<W> for HideCursor {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
if self.state {
- buf.extend_from_slice(b"\x1b[?25l")
+ w.write_all(b"\x1b[?25l")
} else {
- buf.extend_from_slice(b"\x1b[?25h")
+ w.write_all(b"\x1b[?25h")
}
}
}
@@ -331,16 +334,18 @@ impl MoveFromTo {
}
}
-impl BufWrite for MoveFromTo {
- fn write_buf(&self, buf: &mut Vec<u8>) {
- if self.to.row == self.from.row + 1 && self.to.col == 0 {
- crate::term::CRLF::default().write_buf(buf);
- } else if self.from.row == self.to.row && self.from.col < self.to.col
+impl<W: std::io::Write> WriteTo<W> for MoveFromTo {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
+ if self.to == self.from {
+ Ok(())
+ } else if self.to.row == self.from.row + 1 && self.to.col == 0 {
+ crate::term::CRLF::default().write_to(w)
+ } else if self.to.row == self.from.row && self.to.col > self.from.col
{
crate::term::MoveRight::new(self.to.col - self.from.col)
- .write_buf(buf);
- } else if self.to != self.from {
- crate::term::MoveTo::new(self.to).write_buf(buf);
+ .write_to(w)
+ } else {
+ crate::term::MoveTo::new(self.to).write_to(w)
}
}
}
@@ -349,9 +354,9 @@ impl BufWrite for MoveFromTo {
#[must_use = "this struct does nothing unless you call write_buf"]
pub struct AudibleBell;
-impl BufWrite for AudibleBell {
- fn write_buf(&self, buf: &mut Vec<u8>) {
- buf.push(b'\x07');
+impl<W: std::io::Write> WriteTo<W> for AudibleBell {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
+ w.write_all(b"\x07")
}
}
@@ -359,9 +364,9 @@ impl BufWrite for AudibleBell {
#[must_use = "this struct does nothing unless you call write_buf"]
pub struct VisualBell;
-impl BufWrite for VisualBell {
- fn write_buf(&self, buf: &mut Vec<u8>) {
- buf.extend_from_slice(b"\x1bg");
+impl<W: std::io::Write> WriteTo<W> for VisualBell {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
+ w.write_all(b"\x1bg")
}
}
@@ -389,27 +394,28 @@ impl<'a> ChangeTitle<'a> {
}
}
-impl<'a> BufWrite for ChangeTitle<'a> {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<'a, W: std::io::Write> WriteTo<W> for ChangeTitle<'a> {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
if self.icon_name == self.title
&& (self.icon_name != self.prev_icon_name
|| self.title != self.prev_title)
{
- buf.extend_from_slice(b"\x1b]0;");
- buf.extend_from_slice(self.icon_name.as_bytes());
- buf.push(b'\x07');
+ w.write_all(b"\x1b]0;")?;
+ w.write_all(self.icon_name.as_bytes())?;
+ w.write_all(b"\x07")?;
} else {
if self.icon_name != self.prev_icon_name {
- buf.extend_from_slice(b"\x1b]1;");
- buf.extend_from_slice(self.icon_name.as_bytes());
- buf.push(b'\x07');
+ w.write_all(b"\x1b]1;")?;
+ w.write_all(self.icon_name.as_bytes())?;
+ w.write_all(b"\x07")?;
}
if self.title != self.prev_title {
- buf.extend_from_slice(b"\x1b]2;");
- buf.extend_from_slice(self.title.as_bytes());
- buf.push(b'\x07');
+ w.write_all(b"\x1b]2;")?;
+ w.write_all(self.icon_name.as_bytes())?;
+ w.write_all(b"\x07")?;
}
}
+ Ok(())
}
}
@@ -425,12 +431,12 @@ impl ApplicationKeypad {
}
}
-impl BufWrite for ApplicationKeypad {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<W: std::io::Write> WriteTo<W> for ApplicationKeypad {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
if self.state {
- buf.extend_from_slice(b"\x1b=")
+ w.write_all(b"\x1b=")
} else {
- buf.extend_from_slice(b"\x1b>")
+ w.write_all(b"\x1b>")
}
}
}
@@ -447,12 +453,12 @@ impl ApplicationCursor {
}
}
-impl BufWrite for ApplicationCursor {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<W: std::io::Write> WriteTo<W> for ApplicationCursor {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
if self.state {
- buf.extend_from_slice(b"\x1b[?1h")
+ w.write_all(b"\x1b[?1h")
} else {
- buf.extend_from_slice(b"\x1b[?1l")
+ w.write_all(b"\x1b[?1l")
}
}
}
@@ -469,12 +475,12 @@ impl BracketedPaste {
}
}
-impl BufWrite for BracketedPaste {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<W: std::io::Write> WriteTo<W> for BracketedPaste {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
if self.state {
- buf.extend_from_slice(b"\x1b[?2004h")
+ w.write_all(b"\x1b[?2004h")
} else {
- buf.extend_from_slice(b"\x1b[?2004l")
+ w.write_all(b"\x1b[?2004l")
}
}
}
@@ -495,39 +501,39 @@ impl MouseProtocolMode {
}
}
-impl BufWrite for MouseProtocolMode {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<W: std::io::Write> WriteTo<W> for MouseProtocolMode {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
if self.mode == self.prev {
- return;
+ return Ok(());
}
match self.mode {
crate::screen::MouseProtocolMode::None => match self.prev {
- crate::screen::MouseProtocolMode::None => {}
+ crate::screen::MouseProtocolMode::None => Ok(()),
crate::screen::MouseProtocolMode::Press => {
- buf.extend_from_slice(b"\x1b[?9l");
+ w.write_all(b"\x1b[?9l")
}
crate::screen::MouseProtocolMode::PressRelease => {
- buf.extend_from_slice(b"\x1b[?1000l");
+ w.write_all(b"\x1b[?1000l")
}
crate::screen::MouseProtocolMode::ButtonMotion => {
- buf.extend_from_slice(b"\x1b[?1002l");
+ w.write_all(b"\x1b[?1002l")
}
crate::screen::MouseProtocolMode::AnyMotion => {
- buf.extend_from_slice(b"\x1b[?1003l");
+ w.write_all(b"\x1b[?1003l")
}
},
crate::screen::MouseProtocolMode::Press => {
- buf.extend_from_slice(b"\x1b[?9h");
+ w.write_all(b"\x1b[?9h")
}
crate::screen::MouseProtocolMode::PressRelease => {
- buf.extend_from_slice(b"\x1b[?1000h");
+ w.write_all(b"\x1b[?1000h")
}
crate::screen::MouseProtocolMode::ButtonMotion => {
- buf.extend_from_slice(b"\x1b[?1002h");
+ w.write_all(b"\x1b[?1002h")
}
crate::screen::MouseProtocolMode::AnyMotion => {
- buf.extend_from_slice(b"\x1b[?1003h");
+ w.write_all(b"\x1b[?1003h")
}
}
}
@@ -549,29 +555,29 @@ impl MouseProtocolEncoding {
}
}
-impl BufWrite for MouseProtocolEncoding {
- fn write_buf(&self, buf: &mut Vec<u8>) {
+impl<W: std::io::Write> WriteTo<W> for MouseProtocolEncoding {
+ fn write_to(&self, w: &mut W) -> std::io::Result<()> {
if self.encoding == self.prev {
- return;
+ return Ok(());
}
match self.encoding {
crate::screen::MouseProtocolEncoding::Default => {
match self.prev {
- crate::screen::MouseProtocolEncoding::Default => {}
+ crate::screen::MouseProtocolEncoding::Default => Ok(()),
crate::screen::MouseProtocolEncoding::Utf8 => {
- buf.extend_from_slice(b"\x1b[?1005l");
+ w.write_all(b"\x1b[?1005l")
}
crate::screen::MouseProtocolEncoding::Sgr => {
- buf.extend_from_slice(b"\x1b[?1006l");
+ w.write_all(b"\x1b[?1006l")
}
}
}
crate::screen::MouseProtocolEncoding::Utf8 => {
- buf.extend_from_slice(b"\x1b[?1005h");
+ w.write_all(b"\x1b[?1005h")
}
crate::screen::MouseProtocolEncoding::Sgr => {
- buf.extend_from_slice(b"\x1b[?1006h");
+ w.write_all(b"\x1b[?1006h")
}
}
}