ok/jj
1
0
Fork 0
forked from mirrors/jj

cli: leverage Stdout/errLock in place of Mutex<Box<dyn Write>>

Since stdout/stderr has its own locking mechanism, we don't need yet
another Mutex.
This commit is contained in:
Yuya Nishihara 2022-10-07 14:24:35 +09:00
parent 536cab4cd7
commit 6a126bc033

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::io::Write; use std::io::{Stderr, Stdout, Write};
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Mutex, MutexGuard}; use std::sync::{Mutex, MutexGuard};
@ -27,8 +27,7 @@ use crate::formatter::{Formatter, FormatterFactory};
pub struct Ui<'a> { pub struct Ui<'a> {
cwd: PathBuf, cwd: PathBuf,
formatter_factory: FormatterFactory, formatter_factory: FormatterFactory,
stdout: Mutex<Box<dyn Write + 'a>>, output_pair: UiOutputPair<'a>,
stderr: Mutex<Box<dyn Write + 'a>>,
settings: UserSettings, settings: UserSettings,
} }
@ -87,18 +86,27 @@ impl<'stdout> Ui<'stdout> {
Ui { Ui {
cwd, cwd,
formatter_factory, formatter_factory,
stdout: Mutex::new(stdout), output_pair: UiOutputPair::Dyn {
stderr: Mutex::new(stderr), stdout: Mutex::new(stdout),
stderr: Mutex::new(stderr),
},
settings, settings,
} }
} }
pub fn for_terminal(settings: UserSettings) -> Ui<'static> { pub fn for_terminal(settings: UserSettings) -> Ui<'static> {
let cwd = std::env::current_dir().unwrap(); let cwd = std::env::current_dir().unwrap();
let stdout: Box<dyn Write + 'static> = Box::new(io::stdout());
let stderr: Box<dyn Write + 'static> = Box::new(io::stderr());
let color = use_color(color_setting(&settings)); let color = use_color(color_setting(&settings));
Ui::new(cwd, stdout, stderr, color, settings) let formatter_factory = FormatterFactory::prepare(&settings, color);
Ui {
cwd,
formatter_factory,
output_pair: UiOutputPair::Terminal {
stdout: io::stdout(),
stderr: io::stderr(),
},
settings,
}
} }
/// Reconfigures the underlying outputs with the new color choice. /// Reconfigures the underlying outputs with the new color choice.
@ -129,22 +137,39 @@ impl<'stdout> Ui<'stdout> {
/// Labels added to the returned formatter should be removed by caller. /// Labels added to the returned formatter should be removed by caller.
/// Otherwise the last color would persist. /// Otherwise the last color would persist.
pub fn stdout_formatter<'a>(&'a self) -> Box<dyn Formatter + 'a> { pub fn stdout_formatter<'a>(&'a self) -> Box<dyn Formatter + 'a> {
let output = DynWriteLock(self.stdout.lock().unwrap()); match &self.output_pair {
self.new_formatter(output) UiOutputPair::Dyn { stdout, .. } => {
let output = DynWriteLock(stdout.lock().unwrap());
self.new_formatter(output)
}
UiOutputPair::Terminal { stdout, .. } => self.new_formatter(stdout.lock()),
}
} }
/// Creates a formatter for the locked stderr stream. /// Creates a formatter for the locked stderr stream.
pub fn stderr_formatter<'a>(&'a self) -> Box<dyn Formatter + 'a> { pub fn stderr_formatter<'a>(&'a self) -> Box<dyn Formatter + 'a> {
let output = DynWriteLock(self.stderr.lock().unwrap()); match &self.output_pair {
self.new_formatter(output) UiOutputPair::Dyn { stderr, .. } => {
let output = DynWriteLock(stderr.lock().unwrap());
self.new_formatter(output)
}
UiOutputPair::Terminal { stderr, .. } => self.new_formatter(stderr.lock()),
}
} }
pub fn write(&mut self, text: &str) -> io::Result<()> { pub fn write(&mut self, text: &str) -> io::Result<()> {
self.stdout.get_mut().unwrap().write_all(text.as_bytes()) let data = text.as_bytes();
match &mut self.output_pair {
UiOutputPair::Dyn { stdout, .. } => stdout.get_mut().unwrap().write_all(data),
UiOutputPair::Terminal { stdout, .. } => stdout.write_all(data),
}
} }
pub fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { pub fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
self.stdout.get_mut().unwrap().write_fmt(fmt) match &mut self.output_pair {
UiOutputPair::Dyn { stdout, .. } => stdout.get_mut().unwrap().write_fmt(fmt),
UiOutputPair::Terminal { stdout, .. } => stdout.write_fmt(fmt),
}
} }
pub fn write_hint(&mut self, text: impl AsRef<str>) -> io::Result<()> { pub fn write_hint(&mut self, text: impl AsRef<str>) -> io::Result<()> {
@ -201,6 +226,17 @@ impl<'stdout> Ui<'stdout> {
} }
} }
enum UiOutputPair<'output> {
Dyn {
stdout: Mutex<Box<dyn Write + 'output>>,
stderr: Mutex<Box<dyn Write + 'output>>,
},
Terminal {
stdout: Stdout,
stderr: Stderr,
},
}
/// Wrapper to implement `Write` for locked `Box<dyn Write>`. /// Wrapper to implement `Write` for locked `Box<dyn Write>`.
struct DynWriteLock<'a, 'output>(MutexGuard<'a, Box<dyn Write + 'output>>); struct DynWriteLock<'a, 'output>(MutexGuard<'a, Box<dyn Write + 'output>>);