annotate rust/rhg/src/ui.rs @ 45382:eb55274d3650

rhg: add buffered stdout writing possibility Improve batch stdout writing performance. At some point line buffered output should be introduced. Differential Revision: https://phab.mercurial-scm.org/D8866
author Antoine Cezar <antoine.cezar@octobus.net>
date Wed, 29 Jul 2020 10:26:17 +0200
parents 513b3ef277a3
children 10c36ead86f8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
45050
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
1 use std::io;
45382
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
2 use std::io::{ErrorKind, Write};
45050
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
3
45382
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
4 #[derive(Debug)]
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
5 pub struct Ui {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
6 stdout: std::io::Stdout,
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
7 stderr: std::io::Stderr,
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
8 }
45050
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
9
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
10 /// The kind of user interface error
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
11 pub enum UiError {
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
12 /// The standard output stream cannot be written to
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
13 StdoutError(io::Error),
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
14 /// The standard error stream cannot be written to
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
15 StderrError(io::Error),
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
16 }
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
17
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
18 /// The commandline user interface
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
19 impl Ui {
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
20 pub fn new() -> Self {
45382
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
21 Ui {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
22 stdout: std::io::stdout(),
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
23 stderr: std::io::stderr(),
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
24 }
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
25 }
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
26
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
27 /// Returns a buffered handle on stdout for faster batch printing
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
28 /// operations.
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
29 pub fn stdout_buffer(&self) -> StdoutBuffer<std::io::StdoutLock> {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
30 StdoutBuffer::new(self.stdout.lock())
45050
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
31 }
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
32
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
33 /// Write bytes to stdout
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
34 pub fn write_stdout(&self, bytes: &[u8]) -> Result<(), UiError> {
45382
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
35 let mut stdout = self.stdout.lock();
45050
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
36
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
37 self.write_stream(&mut stdout, bytes)
45382
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
38 .or_else(|e| self.handle_stdout_error(e))?;
45050
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
39
45382
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
40 stdout.flush().or_else(|e| self.handle_stdout_error(e))
45050
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
41 }
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
42
45382
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
43 /// Sometimes writing to stdout is not possible, try writing to stderr to
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
44 /// signal that failure, otherwise just bail.
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
45 fn handle_stdout_error(&self, error: io::Error) -> Result<(), UiError> {
45050
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
46 self.write_stderr(
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
47 &[b"abort: ", error.to_string().as_bytes(), b"\n"].concat(),
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
48 )?;
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
49 Err(UiError::StdoutError(error))
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
50 }
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
51
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
52 /// Write bytes to stderr
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
53 pub fn write_stderr(&self, bytes: &[u8]) -> Result<(), UiError> {
45382
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
54 let mut stderr = self.stderr.lock();
45050
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
55
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
56 self.write_stream(&mut stderr, bytes)
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
57 .or_else(|e| Err(UiError::StderrError(e)))?;
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
58
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
59 stderr.flush().or_else(|e| Err(UiError::StderrError(e)))
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
60 }
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
61
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
62 fn write_stream(
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
63 &self,
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
64 stream: &mut impl Write,
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
65 bytes: &[u8],
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
66 ) -> Result<(), io::Error> {
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
67 stream.write_all(bytes)
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
68 }
513b3ef277a3 rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
69 }
45382
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
70
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
71 /// A buffered stdout writer for faster batch printing operations.
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
72 pub struct StdoutBuffer<W: Write> {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
73 buf: io::BufWriter<W>,
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
74 }
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
75
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
76 impl<W: Write> StdoutBuffer<W> {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
77 pub fn new(writer: W) -> Self {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
78 let buf = io::BufWriter::new(writer);
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
79 Self { buf }
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
80 }
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
81
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
82 /// Write bytes to stdout buffer
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
83 pub fn write_all(&mut self, bytes: &[u8]) -> Result<(), UiError> {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
84 self.buf.write_all(bytes).or_else(|e| self.io_err(e))
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
85 }
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
86
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
87 /// Flush bytes to stdout
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
88 pub fn flush(&mut self) -> Result<(), UiError> {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
89 self.buf.flush().or_else(|e| self.io_err(e))
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
90 }
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
91
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
92 fn io_err(&self, error: io::Error) -> Result<(), UiError> {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
93 if let ErrorKind::BrokenPipe = error.kind() {
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
94 // This makes `| head` work for example
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
95 return Ok(());
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
96 }
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
97 let mut stderr = io::stderr();
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
98
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
99 stderr
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
100 .write_all(
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
101 &[b"abort: ", error.to_string().as_bytes(), b"\n"].concat(),
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
102 )
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
103 .map_err(|e| UiError::StderrError(e))?;
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
104
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
105 stderr.flush().map_err(|e| UiError::StderrError(e))?;
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
106
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
107 Err(UiError::StdoutError(error))
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
108 }
eb55274d3650 rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45050
diff changeset
109 }