Use standard Read/Write traits in sys::stdio

This commit is contained in:
Paul Dicker
2019-02-20 08:18:29 +01:00
parent b09803e869
commit 6464e32ea9
6 changed files with 115 additions and 76 deletions

View File

@@ -9,8 +9,10 @@ impl Stdin {
pub fn new() -> io::Result<Stdin> {
Ok(Stdin(()))
}
}
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
impl io::Read for Stdin {
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
Ok(0)
}
}
@@ -19,15 +21,17 @@ impl Stdout {
pub fn new() -> io::Result<Stdout> {
Ok(Stdout(()))
}
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
impl io::Write for Stdout {
fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
Err(io::Error::new(
io::ErrorKind::BrokenPipe,
"Stdout is not connected to any output in this environment",
))
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
@@ -36,15 +40,17 @@ impl Stderr {
pub fn new() -> io::Result<Stderr> {
Ok(Stderr(()))
}
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
impl io::Write for Stderr {
fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
Err(io::Error::new(
io::ErrorKind::BrokenPipe,
"Stderr is not connected to any output in this environment",
))
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

View File

@@ -8,10 +8,12 @@ pub struct Stderr(());
impl Stdin {
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
}
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let fd = FileDesc::new(0);
let ret = fd.read(data);
let ret = fd.read(buf);
fd.into_raw();
ret
}
@@ -19,30 +21,34 @@ impl Stdin {
impl Stdout {
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(1);
let ret = fd.write(data);
let ret = fd.write(buf);
fd.into_raw();
ret
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
cvt(syscall::fsync(1)).and(Ok(()))
}
}
impl Stderr {
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
impl io::Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(2);
let ret = fd.write(data);
let ret = fd.write(buf);
fd.into_raw();
ret
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
cvt(syscall::fsync(2)).and(Ok(()))
}
}

View File

@@ -16,32 +16,38 @@ fn with_std_fd<F: FnOnce(&FileDesc) -> R, R>(fd: abi::Fd, f: F) -> R {
impl Stdin {
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
}
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
with_std_fd(abi::FD_STDIN, |fd| fd.read(data))
impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
with_std_fd(abi::FD_STDIN, |fd| fd.read(buf))
}
}
impl Stdout {
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
with_std_fd(abi::FD_STDOUT, |fd| fd.write(data))
impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
with_std_fd(abi::FD_STDOUT, |fd| fd.write(buf))
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
with_std_fd(abi::FD_STDOUT, |fd| fd.flush())
}
}
impl Stderr {
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
with_std_fd(abi::FD_STDERR, |fd| fd.write(data))
impl io::Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
with_std_fd(abi::FD_STDERR, |fd| fd.write(buf))
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
with_std_fd(abi::FD_STDERR, |fd| fd.flush())
}
}

View File

@@ -8,10 +8,12 @@ pub struct Stderr(());
impl Stdin {
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
}
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDIN_FILENO);
let ret = fd.read(data);
let ret = fd.read(buf);
fd.into_raw(); // do not close this FD
ret
}
@@ -19,30 +21,34 @@ impl Stdin {
impl Stdout {
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDOUT_FILENO);
let ret = fd.write(data);
let ret = fd.write(buf);
fd.into_raw(); // do not close this FD
ret
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Stderr {
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
impl io::Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDERR_FILENO);
let ret = fd.write(data);
let ret = fd.write(buf);
fd.into_raw(); // do not close this FD
ret
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

View File

@@ -9,9 +9,11 @@ impl Stdin {
pub fn new() -> io::Result<Stdin> {
Ok(Stdin)
}
}
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
Ok(ReadSysCall::perform(0, data))
impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
Ok(ReadSysCall::perform(0, buf))
}
}
@@ -19,13 +21,15 @@ impl Stdout {
pub fn new() -> io::Result<Stdout> {
Ok(Stdout)
}
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
WriteSysCall::perform(1, data);
Ok(data.len())
impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
WriteSysCall::perform(1, buf);
Ok(buf.len())
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
@@ -34,13 +38,15 @@ impl Stderr {
pub fn new() -> io::Result<Stderr> {
Ok(Stderr)
}
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
WriteSysCall::perform(2, data);
Ok(data.len())
impl io::Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
WriteSysCall::perform(2, buf);
Ok(buf.len())
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

View File

@@ -1,6 +1,5 @@
#![unstable(issue = "0", feature = "windows_stdio")]
use cell::Cell;
use char::decode_utf16;
use cmp;
use io;
@@ -13,7 +12,7 @@ use sys::handle::Handle;
// Don't cache handles but get them fresh for every read/write. This allows us to track changes to
// the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490.
pub struct Stdin {
high_surrogate: Cell<u16>,
surrogate: u16,
}
pub struct Stdout;
pub struct Stderr;
@@ -128,10 +127,12 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
impl Stdin {
pub fn new() -> io::Result<Stdin> {
Ok(Stdin { high_surrogate: Cell::new(0) })
Ok(Stdin { surrogate: 0 })
}
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let handle = get_handle(c::STD_INPUT_HANDLE)?;
if !is_console(handle) {
let handle = Handle::new(handle);
@@ -153,40 +154,44 @@ impl Stdin {
// we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
// lost.
let amount = cmp::min(buf.len() / 3, utf16_buf.len());
let read = self.read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount)?;
let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?;
utf16_to_utf8(&utf16_buf[..read], buf)
}
}
// We assume that if the last `u16` is an unpaired surrogate they got sliced apart by our
// buffer size, and keep it around for the next read hoping to put them together.
// This is a best effort, and may not work if we are not the only reader on Stdin.
fn read_u16s_fixup_surrogates(&self, handle: c::HANDLE, buf: &mut [u16], mut amount: usize)
-> io::Result<usize>
{
// Insert possibly remaining unpaired surrogate from last read.
let mut start = 0;
if self.high_surrogate.get() != 0 {
buf[0] = self.high_surrogate.replace(0);
start = 1;
if amount == 1 {
// Special case: `Stdin::read` guarantees we can always read at least one new `u16`
// and combine it with an unpaired surrogate, because the UTF-8 buffer is at least
// 4 bytes.
amount = 2;
}
}
let mut amount = read_u16s(handle, &mut buf[start..amount])? + start;
if amount > 0 {
let last_char = buf[amount - 1];
if last_char >= 0xD800 && last_char <= 0xDBFF { // high surrogate
self.high_surrogate.set(last_char);
amount -= 1;
}
// We assume that if the last `u16` is an unpaired surrogate they got sliced apart by our
// buffer size, and keep it around for the next read hoping to put them together.
// This is a best effort, and may not work if we are not the only reader on Stdin.
fn read_u16s_fixup_surrogates(handle: c::HANDLE,
buf: &mut [u16],
mut amount: usize,
surrogate: &mut u16) -> io::Result<usize>
{
// Insert possibly remaining unpaired surrogate from last read.
let mut start = 0;
if *surrogate != 0 {
buf[0] = *surrogate;
*surrogate = 0;
start = 1;
if amount == 1 {
// Special case: `Stdin::read` guarantees we can always read at least one new `u16`
// and combine it with an unpaired surrogate, because the UTF-8 buffer is at least
// 4 bytes.
amount = 2;
}
Ok(amount)
}
let mut amount = read_u16s(handle, &mut buf[start..amount])? + start;
if amount > 0 {
let last_char = buf[amount - 1];
if last_char >= 0xD800 && last_char <= 0xDBFF { // high surrogate
*surrogate = last_char;
amount -= 1;
}
}
Ok(amount)
}
fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result<usize> {
@@ -241,12 +246,14 @@ impl Stdout {
pub fn new() -> io::Result<Stdout> {
Ok(Stdout)
}
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
write(c::STD_OUTPUT_HANDLE, data)
impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
write(c::STD_OUTPUT_HANDLE, buf)
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
@@ -255,12 +262,14 @@ impl Stderr {
pub fn new() -> io::Result<Stderr> {
Ok(Stderr)
}
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
write(c::STD_ERROR_HANDLE, data)
impl io::Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
write(c::STD_ERROR_HANDLE, buf)
}
pub fn flush(&self) -> io::Result<()> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}