Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(filesource): replace repetitive #[cfg()] usages with a new mod #3833

Merged
merged 1 commit into from
May 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 100 additions & 109 deletions src/currentprocess/filesource.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
use std::io::{self, BufRead, Read, Result, Write};
#[cfg(feature = "test")]
use std::{
io::Cursor,
sync::{Arc, Mutex, MutexGuard},
};

use enum_dispatch::enum_dispatch;

Expand Down Expand Up @@ -45,58 +40,6 @@ impl StdinSource for super::OSProcess {
}
}

// ----------------------- test support for stdin ------------------

#[cfg(feature = "test")]
struct TestStdinLock<'a> {
inner: MutexGuard<'a, Cursor<String>>,
}

#[cfg(feature = "test")]
impl StdinLock for TestStdinLock<'_> {}

#[cfg(feature = "test")]
impl Read for TestStdinLock<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}

#[cfg(feature = "test")]
impl BufRead for TestStdinLock<'_> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.inner.fill_buf()
}
fn consume(&mut self, n: usize) {
self.inner.consume(n)
}
}

#[cfg(feature = "test")]
pub(crate) type TestStdinInner = Arc<Mutex<Cursor<String>>>;

#[cfg(feature = "test")]
struct TestStdin(TestStdinInner);

#[cfg(feature = "test")]
impl Stdin for TestStdin {
fn lock(&self) -> Box<dyn StdinLock + '_> {
Box::new(TestStdinLock {
inner: self.0.lock().unwrap_or_else(|e| e.into_inner()),
})
}
fn read_line(&self, buf: &mut String) -> Result<usize> {
self.lock().read_line(buf)
}
}

#[cfg(feature = "test")]
impl StdinSource for super::TestProcess {
fn stdin(&self) -> Box<dyn Stdin> {
Box::new(TestStdin(self.stdin.clone()))
}
}

// -------------- stdout -------------------------------

/// This is a stand-in for [`std::io::StdoutLock`] and [`std::io::StderrLock`].
Expand Down Expand Up @@ -187,81 +130,129 @@ impl StderrSource for super::OSProcess {
}
}

// ----------------------- test support for writers ------------------

#[cfg(feature = "test")]
pub(super) struct TestWriterLock<'a> {
inner: MutexGuard<'a, Vec<u8>>,
}
pub(crate) use self::test_support::*;

#[cfg(feature = "test")]
impl WriterLock for TestWriterLock<'_> {}
mod test_support {
use std::{
io::Cursor,
sync::{Arc, Mutex, MutexGuard},
};

#[cfg(feature = "test")]
impl Write for TestWriterLock<'_> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.inner.write(buf)
use super::{super::TestProcess, *};

// ----------------------- test support for stdin ------------------

struct TestStdinLock<'a> {
inner: MutexGuard<'a, Cursor<String>>,
}

fn flush(&mut self) -> Result<()> {
Ok(())
impl StdinLock for TestStdinLock<'_> {}

impl Read for TestStdinLock<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}
}

#[cfg(feature = "test")]
pub(super) type TestWriterInner = Arc<Mutex<Vec<u8>>>;
/// A thread-safe test file handle that pretends to be e.g. stdout.
#[derive(Clone, Default)]
#[cfg(feature = "test")]
pub(super) struct TestWriter(TestWriterInner);
impl BufRead for TestStdinLock<'_> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.inner.fill_buf()
}
fn consume(&mut self, n: usize) {
self.inner.consume(n)
}
}

#[cfg(feature = "test")]
impl TestWriter {
pub(super) fn lock(&self) -> TestWriterLock<'_> {
// The stream can be locked even if a test thread panicked: its state
// will be ok
TestWriterLock {
inner: self.0.lock().unwrap_or_else(|e| e.into_inner()),
pub(crate) type TestStdinInner = Arc<Mutex<Cursor<String>>>;

struct TestStdin(TestStdinInner);

impl Stdin for TestStdin {
fn lock(&self) -> Box<dyn StdinLock + '_> {
Box::new(TestStdinLock {
inner: self.0.lock().unwrap_or_else(|e| e.into_inner()),
})
}
fn read_line(&self, buf: &mut String) -> Result<usize> {
self.lock().read_line(buf)
}
}
}

#[cfg(feature = "test")]
impl Writer for TestWriter {
fn is_a_tty(&self) -> bool {
false
impl StdinSource for TestProcess {
fn stdin(&self) -> Box<dyn Stdin> {
Box::new(TestStdin(self.stdin.clone()))
}
}

fn lock(&self) -> Box<dyn WriterLock + '_> {
Box::new(self.lock())
// ----------------------- test support for writers ------------------

pub(in super::super) struct TestWriterLock<'a> {
inner: MutexGuard<'a, Vec<u8>>,
}

fn terminal(&self) -> ColorableTerminal {
ColorableTerminal::new(StreamSelector::TestWriter(self.clone()))
impl WriterLock for TestWriterLock<'_> {}

impl Write for TestWriterLock<'_> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.inner.write(buf)
}

fn flush(&mut self) -> Result<()> {
Ok(())
}
}
}

#[cfg(feature = "test")]
impl Write for TestWriter {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.lock().write(buf)
pub(in super::super) type TestWriterInner = Arc<Mutex<Vec<u8>>>;

/// A thread-safe test file handle that pretends to be e.g. stdout.
#[derive(Clone, Default)]
pub(in super::super) struct TestWriter(TestWriterInner);

impl TestWriter {
pub(in super::super) fn lock(&self) -> TestWriterLock<'_> {
// The stream can be locked even if a test thread panicked: its state
// will be ok
TestWriterLock {
inner: self.0.lock().unwrap_or_else(|e| e.into_inner()),
}
}
}

fn flush(&mut self) -> Result<()> {
Ok(())
impl Writer for TestWriter {
fn is_a_tty(&self) -> bool {
false
}

fn lock(&self) -> Box<dyn WriterLock + '_> {
Box::new(self.lock())
}

fn terminal(&self) -> ColorableTerminal {
ColorableTerminal::new(StreamSelector::TestWriter(self.clone()))
}
}
}

#[cfg(feature = "test")]
impl StdoutSource for super::TestProcess {
fn stdout(&self) -> Box<dyn Writer> {
Box::new(TestWriter(self.stdout.clone()))
impl Write for TestWriter {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.lock().write(buf)
}

fn flush(&mut self) -> Result<()> {
Ok(())
}
}
}

#[cfg(feature = "test")]
impl StderrSource for super::TestProcess {
fn stderr(&self) -> Box<dyn Writer> {
Box::new(TestWriter(self.stderr.clone()))
impl StdoutSource for TestProcess {
fn stdout(&self) -> Box<dyn Writer> {
Box::new(TestWriter(self.stdout.clone()))
}
}

impl StderrSource for TestProcess {
fn stderr(&self) -> Box<dyn Writer> {
Box::new(TestWriter(self.stderr.clone()))
}
}
}
Loading