std: Implement stdio for std::io
This is an implementation of RFC 899 and adds stdio functionality to the new `std::io` module. Details of the API can be found on the RFC, but from a high level: * `io::{stdin, stdout, stderr}` constructors are now available. There are also `*_raw` variants for unbuffered and unlocked access. * All handles are globally shared (excluding raw variants). * The stderr handle is no longer buffered. * All handles can be explicitly locked (excluding the raw variants). The `print!` and `println!` machinery has not yet been hooked up to these streams just yet. The `std::fmt::output` module has also not yet been implemented as part of this commit.
This commit is contained in:
parent
8a69110c3b
commit
94d71f8836
20 changed files with 732 additions and 108 deletions
|
@ -201,10 +201,11 @@ impl<T> Arc<T> {
|
|||
impl<T> Arc<T> {
|
||||
#[inline]
|
||||
fn inner(&self) -> &ArcInner<T> {
|
||||
// This unsafety is ok because while this arc is alive we're guaranteed that the inner
|
||||
// pointer is valid. Furthermore, we know that the `ArcInner` structure itself is `Sync`
|
||||
// because the inner data is `Sync` as well, so we're ok loaning out an immutable pointer
|
||||
// to these contents.
|
||||
// This unsafety is ok because while this arc is alive we're guaranteed
|
||||
// that the inner pointer is valid. Furthermore, we know that the
|
||||
// `ArcInner` structure itself is `Sync` because the inner data is
|
||||
// `Sync` as well, so we're ok loaning out an immutable pointer to these
|
||||
// contents.
|
||||
unsafe { &**self._ptr }
|
||||
}
|
||||
}
|
||||
|
@ -236,13 +237,15 @@ impl<T> Clone for Arc<T> {
|
|||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Arc<T> {
|
||||
// Using a relaxed ordering is alright here, as knowledge of the original reference
|
||||
// prevents other threads from erroneously deleting the object.
|
||||
// Using a relaxed ordering is alright here, as knowledge of the
|
||||
// original reference prevents other threads from erroneously deleting
|
||||
// the object.
|
||||
//
|
||||
// As explained in the [Boost documentation][1], Increasing the reference counter can
|
||||
// always be done with memory_order_relaxed: New references to an object can only be formed
|
||||
// from an existing reference, and passing an existing reference from one thread to another
|
||||
// must already provide any required synchronization.
|
||||
// As explained in the [Boost documentation][1], Increasing the
|
||||
// reference counter can always be done with memory_order_relaxed: New
|
||||
// references to an object can only be formed from an existing
|
||||
// reference, and passing an existing reference from one thread to
|
||||
// another must already provide any required synchronization.
|
||||
//
|
||||
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
|
||||
self.inner().strong.fetch_add(1, Relaxed);
|
||||
|
|
59
src/libstd/io/lazy.rs
Normal file
59
src/libstd/io/lazy.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use boxed;
|
||||
use cell::UnsafeCell;
|
||||
use rt;
|
||||
use sync::{StaticMutex, Arc};
|
||||
|
||||
pub struct Lazy<T> {
|
||||
pub lock: StaticMutex,
|
||||
pub ptr: UnsafeCell<*mut Arc<T>>,
|
||||
pub init: fn() -> Arc<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T> Sync for Lazy<T> {}
|
||||
|
||||
macro_rules! lazy_init {
|
||||
($init:expr) => (::io::lazy::Lazy {
|
||||
lock: ::sync::MUTEX_INIT,
|
||||
ptr: ::cell::UnsafeCell { value: 0 as *mut _ },
|
||||
init: $init,
|
||||
})
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> Lazy<T> {
|
||||
pub fn get(&'static self) -> Option<Arc<T>> {
|
||||
let _g = self.lock.lock();
|
||||
unsafe {
|
||||
let mut ptr = *self.ptr.get();
|
||||
if ptr.is_null() {
|
||||
ptr = boxed::into_raw(self.init());
|
||||
*self.ptr.get() = ptr;
|
||||
} else if ptr as usize == 1 {
|
||||
return None
|
||||
}
|
||||
Some((*ptr).clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn init(&'static self) -> Box<Arc<T>> {
|
||||
rt::at_exit(move || unsafe {
|
||||
let g = self.lock.lock();
|
||||
let ptr = *self.ptr.get();
|
||||
*self.ptr.get() = 1 as *mut _;
|
||||
drop(g);
|
||||
drop(Box::from_raw(ptr))
|
||||
});
|
||||
Box::new((self.init)())
|
||||
}
|
||||
}
|
|
@ -39,6 +39,10 @@ pub use self::buffered::IntoInnerError;
|
|||
pub use self::cursor::Cursor;
|
||||
pub use self::error::{Result, Error, ErrorKind};
|
||||
pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
|
||||
pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr};
|
||||
pub use self::stdio::{StdoutLock, StderrLock, StdinLock};
|
||||
|
||||
#[macro_use] mod lazy;
|
||||
|
||||
pub mod prelude;
|
||||
mod buffered;
|
||||
|
@ -46,6 +50,7 @@ mod cursor;
|
|||
mod error;
|
||||
mod impls;
|
||||
mod util;
|
||||
mod stdio;
|
||||
|
||||
const DEFAULT_BUF_SIZE: usize = 64 * 1024;
|
||||
|
||||
|
|
325
src/libstd/io/stdio.rs
Normal file
325
src/libstd/io/stdio.rs
Normal file
|
@ -0,0 +1,325 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::v1::*;
|
||||
use io::prelude::*;
|
||||
|
||||
use cmp;
|
||||
use fmt;
|
||||
use io::lazy::Lazy;
|
||||
use io::{self, BufReader, LineWriter};
|
||||
use sync::{Arc, Mutex, MutexGuard};
|
||||
use sys::stdio;
|
||||
|
||||
/// A handle to a raw instance of the standard input stream of this process.
|
||||
///
|
||||
/// This handle is not synchronized or buffered in any fashion. Constructed via
|
||||
/// the `std::io::stdin_raw` function.
|
||||
pub struct StdinRaw(stdio::Stdin);
|
||||
|
||||
/// A handle to a raw instance of the standard output stream of this process.
|
||||
///
|
||||
/// This handle is not synchronized or buffered in any fashion. Constructed via
|
||||
/// the `std::io::stdout_raw` function.
|
||||
pub struct StdoutRaw(stdio::Stdout);
|
||||
|
||||
/// A handle to a raw instance of the standard output stream of this process.
|
||||
///
|
||||
/// This handle is not synchronized or buffered in any fashion. Constructed via
|
||||
/// the `std::io::stderr_raw` function.
|
||||
pub struct StderrRaw(stdio::Stderr);
|
||||
|
||||
/// Construct a new raw handle to the standard input of this process.
|
||||
///
|
||||
/// The returned handle does not interact with any other handles created nor
|
||||
/// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin`
|
||||
/// handles is **not** available to raw handles returned from this function.
|
||||
///
|
||||
/// The returned handle has no external synchronization or buffering.
|
||||
pub fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) }
|
||||
|
||||
/// Construct a new raw handle to the standard input stream of this process.
|
||||
///
|
||||
/// The returned handle does not interact with any other handles created nor
|
||||
/// handles returned by `std::io::stdout`. Note that data is buffered by the
|
||||
/// `std::io::stdin` handles so writes which happen via this raw handle may
|
||||
/// appear before previous writes.
|
||||
///
|
||||
/// The returned handle has no external synchronization or buffering layered on
|
||||
/// top.
|
||||
pub fn stdout_raw() -> StdoutRaw { StdoutRaw(stdio::Stdout::new()) }
|
||||
|
||||
/// Construct a new raw handle to the standard input stream of this process.
|
||||
///
|
||||
/// The returned handle does not interact with any other handles created nor
|
||||
/// handles returned by `std::io::stdout`.
|
||||
///
|
||||
/// The returned handle has no external synchronization or buffering layered on
|
||||
/// top.
|
||||
pub fn stderr_raw() -> StderrRaw { StderrRaw(stdio::Stderr::new()) }
|
||||
|
||||
impl Read for StdinRaw {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
|
||||
}
|
||||
impl Write for StdoutRaw {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
|
||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
impl Write for StderrRaw {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
|
||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
/// A handle to the standard input stream of a process.
|
||||
///
|
||||
/// Each handle is a shared reference to a global buffer of input data to this
|
||||
/// process. A handle can be `lock`'d to gain full access to `BufRead` methods
|
||||
/// (e.g. `.lines()`). Writes to this handle are otherwise locked with respect
|
||||
/// to other writes.
|
||||
///
|
||||
/// This handle implements the `Read` trait, but beware that concurrent reads
|
||||
/// of `Stdin` must be executed with care.
|
||||
pub struct Stdin {
|
||||
inner: Arc<Mutex<BufReader<StdinRaw>>>,
|
||||
}
|
||||
|
||||
/// A locked reference to the a `Stdin` handle.
|
||||
///
|
||||
/// This handle implements both the `Read` and `BufRead` traits and is
|
||||
/// constructed via the `lock` method on `Stdin`.
|
||||
pub struct StdinLock<'a> {
|
||||
inner: MutexGuard<'a, BufReader<StdinRaw>>,
|
||||
}
|
||||
|
||||
/// Create a new handle to the global standard input stream of this process.
|
||||
///
|
||||
/// The handle returned refers to a globally shared buffer between all threads.
|
||||
/// Access is synchronized and can be explicitly controlled with the `lock()`
|
||||
/// method.
|
||||
///
|
||||
/// The `Read` trait is implemented for the returned value but the `BufRead`
|
||||
/// trait is not due to the global nature of the standard input stream. The
|
||||
/// locked version, `StdinLock`, implements both `Read` and `BufRead`, however.
|
||||
///
|
||||
/// To avoid locking and buffering altogether, it is recommended to use the
|
||||
/// `stdin_raw` constructor.
|
||||
pub fn stdin() -> Stdin {
|
||||
static INSTANCE: Lazy<Mutex<BufReader<StdinRaw>>> = lazy_init!(stdin_init);
|
||||
return Stdin {
|
||||
inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
|
||||
};
|
||||
|
||||
fn stdin_init() -> Arc<Mutex<BufReader<StdinRaw>>> {
|
||||
// The default buffer capacity is 64k, but apparently windows
|
||||
// doesn't like 64k reads on stdin. See #13304 for details, but the
|
||||
// idea is that on windows we use a slightly smaller buffer that's
|
||||
// been seen to be acceptable.
|
||||
Arc::new(Mutex::new(if cfg!(windows) {
|
||||
BufReader::with_capacity(8 * 1024, stdin_raw())
|
||||
} else {
|
||||
BufReader::new(stdin_raw())
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdin {
|
||||
/// Lock this handle to the standard input stream, returning a readable
|
||||
/// guard.
|
||||
///
|
||||
/// The lock is released when the returned lock goes out of scope. The
|
||||
/// returned guard also implements the `Read` and `BufRead` traits for
|
||||
/// accessing the underlying data.
|
||||
pub fn lock(&self) -> StdinLock {
|
||||
StdinLock { inner: self.inner.lock().unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Stdin {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.lock().read(buf)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<()> {
|
||||
self.lock().read_to_end(buf)
|
||||
}
|
||||
|
||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<()> {
|
||||
self.lock().read_to_string(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Read for StdinLock<'a> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// Flush stdout so that weird issues like a print!'d prompt not being
|
||||
// shown until after the user hits enter.
|
||||
drop(stdout().flush());
|
||||
self.inner.read(buf)
|
||||
}
|
||||
}
|
||||
impl<'a> BufRead for StdinLock<'a> {
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
|
||||
fn consume(&mut self, n: usize) { self.inner.consume(n) }
|
||||
}
|
||||
|
||||
// As with stdin on windows, stdout often can't handle writes of large
|
||||
// sizes. For an example, see #14940. For this reason, don't try to
|
||||
// write the entire output buffer on windows. On unix we can just
|
||||
// write the whole buffer all at once.
|
||||
//
|
||||
// For some other references, it appears that this problem has been
|
||||
// encountered by others [1] [2]. We choose the number 8KB just because
|
||||
// libuv does the same.
|
||||
//
|
||||
// [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232
|
||||
// [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html
|
||||
#[cfg(windows)]
|
||||
const OUT_MAX: usize = 8192;
|
||||
#[cfg(unix)]
|
||||
const OUT_MAX: usize = ::usize::MAX;
|
||||
|
||||
/// A handle to the global standard output stream of the current process.
|
||||
///
|
||||
/// Each handle shares a global buffer of data to be written to the standard
|
||||
/// output stream. Access is also synchronized via a lock and explicit control
|
||||
/// over locking is available via the `lock` method.
|
||||
pub struct Stdout {
|
||||
// FIXME: this should be LineWriter or BufWriter depending on the state of
|
||||
// stdout (tty or not). Note that if this is not line buffered it
|
||||
// should also flush-on-panic or some form of flush-on-abort.
|
||||
inner: Arc<Mutex<LineWriter<StdoutRaw>>>,
|
||||
}
|
||||
|
||||
/// A locked reference to the a `Stdout` handle.
|
||||
///
|
||||
/// This handle implements the `Write` trait and is constructed via the `lock`
|
||||
/// method on `Stdout`.
|
||||
pub struct StdoutLock<'a> {
|
||||
inner: MutexGuard<'a, LineWriter<StdoutRaw>>,
|
||||
}
|
||||
|
||||
/// Constructs a new reference to the standard output of the current process.
|
||||
///
|
||||
/// Each handle returned is a reference to a shared global buffer whose access
|
||||
/// is synchronized via a mutex. Explicit control over synchronization is
|
||||
/// provided via the `lock` method.
|
||||
///
|
||||
/// The returned handle implements the `Write` trait.
|
||||
///
|
||||
/// To avoid locking and buffering altogether, it is recommended to use the
|
||||
/// `stdout_raw` constructor.
|
||||
pub fn stdout() -> Stdout {
|
||||
static INSTANCE: Lazy<Mutex<LineWriter<StdoutRaw>>> = lazy_init!(stdout_init);
|
||||
return Stdout {
|
||||
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
|
||||
};
|
||||
|
||||
fn stdout_init() -> Arc<Mutex<LineWriter<StdoutRaw>>> {
|
||||
Arc::new(Mutex::new(LineWriter::new(stdout_raw())))
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
/// Lock this handle to the standard output stream, returning a writable
|
||||
/// guard.
|
||||
///
|
||||
/// The lock is released when the returned lock goes out of scope. The
|
||||
/// returned guard also implements the `Write` trait for writing data.
|
||||
pub fn lock(&self) -> StdoutLock {
|
||||
StdoutLock { inner: self.inner.lock().unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Stdout {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.lock().write(buf)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.lock().flush()
|
||||
}
|
||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
self.lock().write_all(buf)
|
||||
}
|
||||
fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
|
||||
self.lock().write_fmt(fmt)
|
||||
}
|
||||
}
|
||||
impl<'a> Write for StdoutLock<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)])
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
|
||||
}
|
||||
|
||||
/// A handle to the standard error stream of a process.
|
||||
///
|
||||
/// For more information, see `stderr`
|
||||
pub struct Stderr {
|
||||
inner: Arc<Mutex<StderrRaw>>,
|
||||
}
|
||||
|
||||
/// A locked reference to the a `Stderr` handle.
|
||||
///
|
||||
/// This handle implements the `Write` trait and is constructed via the `lock`
|
||||
/// method on `Stderr`.
|
||||
pub struct StderrLock<'a> {
|
||||
inner: MutexGuard<'a, StderrRaw>,
|
||||
}
|
||||
|
||||
/// Constructs a new reference to the standard error stream of a process.
|
||||
///
|
||||
/// Each returned handle is synchronized amongst all other handles created from
|
||||
/// this function. No handles are buffered, however.
|
||||
///
|
||||
/// The returned handle implements the `Write` trait.
|
||||
///
|
||||
/// To avoid locking altogether, it is recommended to use the `stderr_raw`
|
||||
/// constructor.
|
||||
pub fn stderr() -> Stderr {
|
||||
static INSTANCE: Lazy<Mutex<StderrRaw>> = lazy_init!(stderr_init);
|
||||
return Stderr {
|
||||
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
|
||||
};
|
||||
|
||||
fn stderr_init() -> Arc<Mutex<StderrRaw>> {
|
||||
Arc::new(Mutex::new(stderr_raw()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Stderr {
|
||||
/// Lock this handle to the standard error stream, returning a writable
|
||||
/// guard.
|
||||
///
|
||||
/// The lock is released when the returned lock goes out of scope. The
|
||||
/// returned guard also implements the `Write` trait for writing data.
|
||||
pub fn lock(&self) -> StderrLock {
|
||||
StderrLock { inner: self.inner.lock().unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Stderr {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.lock().write(buf)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.lock().flush()
|
||||
}
|
||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
self.lock().write_all(buf)
|
||||
}
|
||||
fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
|
||||
self.lock().write_fmt(fmt)
|
||||
}
|
||||
}
|
||||
impl<'a> Write for StderrLock<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)])
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
|
||||
}
|
|
@ -224,10 +224,10 @@ pub fn stdin() -> StdinReader {
|
|||
|
||||
unsafe {
|
||||
ONCE.call_once(|| {
|
||||
// The default buffer capacity is 64k, but apparently windows doesn't like
|
||||
// 64k reads on stdin. See #13304 for details, but the idea is that on
|
||||
// windows we use a slightly smaller buffer that's been seen to be
|
||||
// acceptable.
|
||||
// The default buffer capacity is 64k, but apparently windows
|
||||
// doesn't like 64k reads on stdin. See #13304 for details, but the
|
||||
// idea is that on windows we use a slightly smaller buffer that's
|
||||
// been seen to be acceptable.
|
||||
let stdin = if cfg!(windows) {
|
||||
BufferedReader::with_capacity(8 * 1024, stdin_raw())
|
||||
} else {
|
||||
|
|
|
@ -63,6 +63,7 @@ pub mod time;
|
|||
pub mod timer;
|
||||
pub mod tty;
|
||||
pub mod udp;
|
||||
pub mod stdio;
|
||||
|
||||
pub mod addrinfo {
|
||||
pub use sys_common::net::get_host_addresses;
|
||||
|
|
52
src/libstd/sys/unix/stdio.rs
Normal file
52
src/libstd/sys/unix/stdio.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use io;
|
||||
use libc;
|
||||
use sys::fd::FileDesc;
|
||||
|
||||
pub struct Stdin(());
|
||||
pub struct Stdout(());
|
||||
pub struct Stderr(());
|
||||
|
||||
impl Stdin {
|
||||
pub fn new() -> Stdin { Stdin(()) }
|
||||
|
||||
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
|
||||
let fd = FileDesc::new(libc::STDIN_FILENO);
|
||||
let ret = fd.read(data);
|
||||
fd.into_raw();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
pub fn new() -> Stdout { Stdout(()) }
|
||||
|
||||
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
||||
let fd = FileDesc::new(libc::STDOUT_FILENO);
|
||||
let ret = fd.write(data);
|
||||
fd.into_raw();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
impl Stderr {
|
||||
pub fn new() -> Stderr { Stderr(()) }
|
||||
|
||||
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
||||
let fd = FileDesc::new(libc::STDERR_FILENO);
|
||||
let ret = fd.write(data);
|
||||
fd.into_raw();
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -48,6 +48,11 @@ pub const WSAESHUTDOWN: libc::c_int = 10058;
|
|||
pub const ERROR_NO_MORE_FILES: libc::DWORD = 18;
|
||||
pub const TOKEN_READ: libc::DWORD = 0x20008;
|
||||
|
||||
// Note that these are not actually HANDLEs, just values to pass to GetStdHandle
|
||||
pub const STD_INPUT_HANDLE: libc::DWORD = -10;
|
||||
pub const STD_OUTPUT_HANDLE: libc::DWORD = -11;
|
||||
pub const STD_ERROR_HANDLE: libc::DWORD = -12;
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub struct WSADATA {
|
||||
|
@ -427,6 +432,7 @@ extern "system" {
|
|||
DesiredAccess: libc::DWORD,
|
||||
TokenHandle: *mut libc::HANDLE) -> libc::BOOL;
|
||||
pub fn GetCurrentProcess() -> libc::HANDLE;
|
||||
pub fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
|
||||
}
|
||||
|
||||
#[link(name = "userenv")]
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
|
||||
use prelude::v1::*;
|
||||
|
||||
use libc::{self, HANDLE};
|
||||
use io;
|
||||
use io::ErrorKind;
|
||||
use io;
|
||||
use libc::{self, HANDLE};
|
||||
use mem;
|
||||
use ptr;
|
||||
use sys::cvt;
|
||||
|
||||
|
@ -28,6 +29,12 @@ impl Handle {
|
|||
|
||||
pub fn raw(&self) -> HANDLE { self.0 }
|
||||
|
||||
pub fn into_raw(self) -> HANDLE {
|
||||
let ret = self.0;
|
||||
unsafe { mem::forget(self) }
|
||||
return ret;
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
read(self.0, buf)
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ pub mod time;
|
|||
pub mod timer;
|
||||
pub mod tty;
|
||||
pub mod udp;
|
||||
pub mod stdio;
|
||||
|
||||
pub mod addrinfo {
|
||||
pub use sys_common::net::get_host_addresses;
|
||||
|
|
155
src/libstd/sys/windows/stdio.rs
Normal file
155
src/libstd/sys/windows/stdio.rs
Normal file
|
@ -0,0 +1,155 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::v1::*;
|
||||
use io::prelude::*;
|
||||
|
||||
use io::{self, Cursor};
|
||||
use iter::repeat;
|
||||
use libc;
|
||||
use ptr;
|
||||
use str;
|
||||
use sync::Mutex;
|
||||
use sys::c;
|
||||
use sys::cvt;
|
||||
use sys::handle::Handle;
|
||||
|
||||
struct NoClose(Option<Handle>);
|
||||
|
||||
enum Output {
|
||||
Console(NoClose),
|
||||
Pipe(NoClose),
|
||||
}
|
||||
|
||||
pub struct Stdin {
|
||||
handle: Output,
|
||||
utf8: Mutex<io::Cursor<Vec<u8>>>,
|
||||
}
|
||||
pub struct Stdout(Output);
|
||||
pub struct Stderr(Output);
|
||||
|
||||
fn get(handle: libc::DWORD) -> io::Result<Output> {
|
||||
let handle = unsafe { c::GetStdHandle(handle) };
|
||||
if handle == libc::INVALID_HANDLE_VALUE {
|
||||
Err(io::Error::last_os_error())
|
||||
} else if handle.is_null() {
|
||||
Err(io::Error::new(io::ErrorKind::Other,
|
||||
"no stdio handle available for this process", None))
|
||||
} else {
|
||||
let ret = NoClose::new(handle);
|
||||
let mut out = 0;
|
||||
match unsafe { c::GetConsoleMode(handle, &mut out) } {
|
||||
0 => Ok(Output::Pipe(ret)),
|
||||
_ => Ok(Output::Console(ret)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
|
||||
let handle = match *out {
|
||||
Output::Console(ref c) => c.get().raw(),
|
||||
Output::Pipe(ref p) => return p.get().write(data),
|
||||
};
|
||||
let utf16 = match str::from_utf8(data).ok() {
|
||||
Some(utf8) => utf8.utf16_units().collect::<Vec<u16>>(),
|
||||
None => return Err(invalid_encoding()),
|
||||
};
|
||||
let mut written = 0;
|
||||
try!(cvt(unsafe {
|
||||
c::WriteConsoleW(handle,
|
||||
utf16.as_ptr() as libc::LPCVOID,
|
||||
utf16.len() as u32,
|
||||
&mut written,
|
||||
ptr::null_mut())
|
||||
}));
|
||||
|
||||
// FIXME if this only partially writes the utf16 buffer then we need to
|
||||
// figure out how many bytes of `data` were actually written
|
||||
assert_eq!(written as usize, utf16.len());
|
||||
Ok(data.len())
|
||||
}
|
||||
|
||||
impl Stdin {
|
||||
pub fn new() -> Stdin {
|
||||
Stdin {
|
||||
handle: get(c::STD_INPUT_HANDLE).unwrap(),
|
||||
utf8: Mutex::new(Cursor::new(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let handle = match self.handle {
|
||||
Output::Console(ref c) => c.get().raw(),
|
||||
Output::Pipe(ref p) => return p.get().read(buf),
|
||||
};
|
||||
let mut utf8 = self.utf8.lock().unwrap();
|
||||
// Read more if the buffer is empty
|
||||
if utf8.position() as usize == utf8.get_ref().len() {
|
||||
let mut utf16: Vec<u16> = repeat(0u16).take(0x1000).collect();
|
||||
let mut num = 0;
|
||||
try!(cvt(unsafe {
|
||||
c::ReadConsoleW(handle,
|
||||
utf16.as_mut_ptr() as libc::LPVOID,
|
||||
utf16.len() as u32,
|
||||
&mut num,
|
||||
ptr::null_mut())
|
||||
}));
|
||||
utf16.truncate(num as usize);
|
||||
// FIXME: what to do about this data that has already been read?
|
||||
let data = match String::from_utf16(&utf16) {
|
||||
Ok(utf8) => utf8.into_bytes(),
|
||||
Err(..) => return Err(invalid_encoding()),
|
||||
};
|
||||
*utf8 = Cursor::new(data);
|
||||
}
|
||||
|
||||
// MemReader shouldn't error here since we just filled it
|
||||
utf8.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
pub fn new() -> Stdout {
|
||||
Stdout(get(c::STD_OUTPUT_HANDLE).unwrap())
|
||||
}
|
||||
|
||||
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
||||
write(&self.0, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl Stderr {
|
||||
pub fn new() -> Stderr {
|
||||
Stderr(get(c::STD_ERROR_HANDLE).unwrap())
|
||||
}
|
||||
|
||||
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
||||
write(&self.0, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl NoClose {
|
||||
fn new(handle: libc::HANDLE) -> NoClose {
|
||||
NoClose(Some(Handle::new(handle)))
|
||||
}
|
||||
|
||||
fn get(&self) -> &Handle { self.0.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
impl Drop for NoClose {
|
||||
fn drop(&mut self) {
|
||||
self.0.take().unwrap().into_raw();
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid_encoding() -> io::Error {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "text was not valid unicode",
|
||||
None)
|
||||
}
|
|
@ -43,12 +43,16 @@
|
|||
#![feature(box_syntax)]
|
||||
|
||||
use std::ascii::OwnedAsciiExt;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
static TABLE: [u8;4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
|
||||
static TABLE_SIZE: uint = 2 << 16;
|
||||
static TABLE_SIZE: usize = 2 << 16;
|
||||
|
||||
static OCCURRENCES: [&'static str;5] = [
|
||||
"GGT",
|
||||
|
@ -73,7 +77,7 @@ impl Code {
|
|||
Code((self.hash() << 2) + (pack_symbol(c) as u64))
|
||||
}
|
||||
|
||||
fn rotate(&self, c: u8, frame: uint) -> Code {
|
||||
fn rotate(&self, c: u8, frame: usize) -> Code {
|
||||
Code(self.push_char(c).hash() & ((1u64 << (2 * frame)) - 1))
|
||||
}
|
||||
|
||||
|
@ -81,7 +85,7 @@ impl Code {
|
|||
string.bytes().fold(Code(0u64), |a, b| a.push_char(b))
|
||||
}
|
||||
|
||||
fn unpack(&self, frame: uint) -> String {
|
||||
fn unpack(&self, frame: usize) -> String {
|
||||
let mut key = self.hash();
|
||||
let mut result = Vec::new();
|
||||
for _ in 0..frame {
|
||||
|
@ -113,13 +117,13 @@ struct PrintCallback(&'static str);
|
|||
impl TableCallback for PrintCallback {
|
||||
fn f(&self, entry: &mut Entry) {
|
||||
let PrintCallback(s) = *self;
|
||||
println!("{}\t{}", entry.count as int, s);
|
||||
println!("{}\t{}", entry.count, s);
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
code: Code,
|
||||
count: uint,
|
||||
count: usize,
|
||||
next: Option<Box<Entry>>,
|
||||
}
|
||||
|
||||
|
@ -165,20 +169,20 @@ impl Table {
|
|||
let index = key.hash() % (TABLE_SIZE as u64);
|
||||
|
||||
{
|
||||
if self.items[index as uint].is_none() {
|
||||
if self.items[index as usize].is_none() {
|
||||
let mut entry = box Entry {
|
||||
code: key,
|
||||
count: 0,
|
||||
next: None,
|
||||
};
|
||||
c.f(&mut *entry);
|
||||
self.items[index as uint] = Some(entry);
|
||||
self.items[index as usize] = Some(entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let entry = self.items[index as uint].as_mut().unwrap();
|
||||
let entry = self.items[index as usize].as_mut().unwrap();
|
||||
if entry.code == key {
|
||||
c.f(&mut **entry);
|
||||
return;
|
||||
|
@ -233,10 +237,10 @@ fn pack_symbol(c: u8) -> u8 {
|
|||
}
|
||||
|
||||
fn unpack_symbol(c: u8) -> u8 {
|
||||
TABLE[c as uint]
|
||||
TABLE[c as usize]
|
||||
}
|
||||
|
||||
fn generate_frequencies(mut input: &[u8], frame: uint) -> Table {
|
||||
fn generate_frequencies(mut input: &[u8], frame: usize) -> Table {
|
||||
let mut frequencies = Table::new();
|
||||
if input.len() < frame { return frequencies; }
|
||||
let mut code = Code(0);
|
||||
|
@ -256,7 +260,7 @@ fn generate_frequencies(mut input: &[u8], frame: uint) -> Table {
|
|||
frequencies
|
||||
}
|
||||
|
||||
fn print_frequencies(frequencies: &Table, frame: uint) {
|
||||
fn print_frequencies(frequencies: &Table, frame: usize) {
|
||||
let mut vector = Vec::new();
|
||||
for entry in frequencies.iter() {
|
||||
vector.push((entry.count, entry.code));
|
||||
|
@ -280,9 +284,9 @@ fn print_occurrences(frequencies: &mut Table, occurrence: &'static str) {
|
|||
frequencies.lookup(Code::pack(occurrence), PrintCallback(occurrence))
|
||||
}
|
||||
|
||||
fn get_sequence<R: Buffer>(r: &mut R, key: &str) -> Vec<u8> {
|
||||
fn get_sequence<R: BufRead>(r: &mut R, key: &str) -> Vec<u8> {
|
||||
let mut res = Vec::new();
|
||||
for l in r.lines().map(|l| l.ok().unwrap())
|
||||
for l in r.lines().map(|l| l.unwrap())
|
||||
.skip_while(|l| key != &l[..key.len()]).skip(1)
|
||||
{
|
||||
res.push_all(l.trim().as_bytes());
|
||||
|
@ -291,13 +295,13 @@ fn get_sequence<R: Buffer>(r: &mut R, key: &str) -> Vec<u8> {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let input = if std::env::var_os("RUST_BENCH").is_some() {
|
||||
let fd = std::old_io::File::open(&Path::new("shootout-k-nucleotide.data"));
|
||||
get_sequence(&mut std::old_io::BufferedReader::new(fd), ">THREE")
|
||||
let input = if env::var_os("RUST_BENCH").is_some() {
|
||||
let f = File::open("shootout-k-nucleotide.data").unwrap();
|
||||
get_sequence(&mut io::BufReader::new(f), ">THREE")
|
||||
} else {
|
||||
let mut stdin = std::old_io::stdin();
|
||||
let stdin = io::stdin();
|
||||
let mut stdin = stdin.lock();
|
||||
get_sequence(&mut *stdin, ">THREE")
|
||||
get_sequence(&mut stdin, ">THREE")
|
||||
};
|
||||
let input = Arc::new(input);
|
||||
|
||||
|
|
|
@ -13,9 +13,8 @@
|
|||
#![feature(box_syntax)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::old_io::BufferedReader;
|
||||
use std::old_io::stdio::StdReader;
|
||||
use std::old_io;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::iter::repeat;
|
||||
use std::num::Int;
|
||||
use std::env;
|
||||
|
@ -55,9 +54,11 @@ impl Sudoku {
|
|||
return Sudoku::new(g)
|
||||
}
|
||||
|
||||
pub fn read(mut reader: &mut BufferedReader<StdReader>) -> Sudoku {
|
||||
pub fn read(reader: &mut BufRead) -> Sudoku {
|
||||
/* assert first line is exactly "9,9" */
|
||||
assert!(reader.read_line().unwrap() == "9,9".to_string());
|
||||
let mut s = String::new();
|
||||
reader.read_line(&mut s).unwrap();
|
||||
assert_eq!(s, "9,9\n");
|
||||
|
||||
let mut g = repeat(vec![0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8])
|
||||
.take(10).collect::<Vec<_>>();
|
||||
|
@ -71,7 +72,7 @@ impl Sudoku {
|
|||
if comps.len() == 3 {
|
||||
let row = comps[0].parse::<u8>().unwrap();
|
||||
let col = comps[1].parse::<u8>().unwrap();
|
||||
g[row as uint][col as uint] = comps[2].parse().unwrap();
|
||||
g[row as usize][col as usize] = comps[2].parse().unwrap();
|
||||
}
|
||||
else {
|
||||
panic!("Invalid sudoku file");
|
||||
|
@ -80,11 +81,11 @@ impl Sudoku {
|
|||
return Sudoku::new(g)
|
||||
}
|
||||
|
||||
pub fn write(&self, writer: &mut old_io::Writer) {
|
||||
pub fn write(&self, writer: &mut Write) {
|
||||
for row in 0u8..9u8 {
|
||||
write!(writer, "{}", self.grid[row as uint][0]);
|
||||
write!(writer, "{}", self.grid[row as usize][0]);
|
||||
for col in 1u8..9u8 {
|
||||
write!(writer, " {}", self.grid[row as uint][col as uint]);
|
||||
write!(writer, " {}", self.grid[row as usize][col as usize]);
|
||||
}
|
||||
write!(writer, "\n");
|
||||
}
|
||||
|
@ -95,7 +96,7 @@ impl Sudoku {
|
|||
let mut work: Vec<(u8, u8)> = Vec::new(); /* queue of uncolored fields */
|
||||
for row in 0u8..9u8 {
|
||||
for col in 0u8..9u8 {
|
||||
let color = self.grid[row as uint][col as uint];
|
||||
let color = self.grid[row as usize][col as usize];
|
||||
if color == 0u8 {
|
||||
work.push((row, col));
|
||||
}
|
||||
|
@ -107,7 +108,7 @@ impl Sudoku {
|
|||
while ptr < end {
|
||||
let (row, col) = work[ptr];
|
||||
// is there another color to try?
|
||||
let the_color = self.grid[row as uint][col as uint] +
|
||||
let the_color = self.grid[row as usize][col as usize] +
|
||||
(1 as u8);
|
||||
if self.next_color(row, col, the_color) {
|
||||
// yes: advance work list
|
||||
|
@ -130,10 +131,10 @@ impl Sudoku {
|
|||
|
||||
// find first remaining color that is available
|
||||
let next = avail.next();
|
||||
self.grid[row as uint][col as uint] = next;
|
||||
self.grid[row as usize][col as usize] = next;
|
||||
return 0u8 != next;
|
||||
}
|
||||
self.grid[row as uint][col as uint] = 0u8;
|
||||
self.grid[row as usize][col as usize] = 0u8;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -141,9 +142,9 @@ impl Sudoku {
|
|||
fn drop_colors(&mut self, avail: &mut Colors, row: u8, col: u8) {
|
||||
for idx in 0u8..9u8 {
|
||||
/* check same column fields */
|
||||
avail.remove(self.grid[idx as uint][col as uint]);
|
||||
avail.remove(self.grid[idx as usize][col as usize]);
|
||||
/* check same row fields */
|
||||
avail.remove(self.grid[row as uint][idx as uint]);
|
||||
avail.remove(self.grid[row as usize][idx as usize]);
|
||||
}
|
||||
|
||||
// check same block fields
|
||||
|
@ -151,7 +152,7 @@ impl Sudoku {
|
|||
let col0 = (col / 3u8) * 3u8;
|
||||
for alt_row in row0..row0 + 3u8 {
|
||||
for alt_col in col0..col0 + 3u8 {
|
||||
avail.remove(self.grid[alt_row as uint][alt_col as uint]);
|
||||
avail.remove(self.grid[alt_row as usize][alt_col as usize]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +166,7 @@ static HEADS: u16 = (1u16 << 10) - 1; /* bits 9..0 */
|
|||
impl Colors {
|
||||
fn new(start_color: u8) -> Colors {
|
||||
// Sets bits 9..start_color
|
||||
let tails = !0u16 << start_color as uint;
|
||||
let tails = !0u16 << start_color as usize;
|
||||
return Colors(HEADS & tails);
|
||||
}
|
||||
|
||||
|
@ -182,7 +183,7 @@ impl Colors {
|
|||
fn remove(&mut self, color: u8) {
|
||||
if color != 0u8 {
|
||||
let Colors(val) = *self;
|
||||
let mask = !(1u16 << color as uint);
|
||||
let mask = !(1u16 << color as usize);
|
||||
*self = Colors(val & mask);
|
||||
}
|
||||
}
|
||||
|
@ -274,10 +275,11 @@ fn main() {
|
|||
let mut sudoku = if use_default {
|
||||
Sudoku::from_vec(&DEFAULT_SUDOKU)
|
||||
} else {
|
||||
let mut stdin = old_io::stdin();
|
||||
let mut stdin = stdin.lock();
|
||||
Sudoku::read(&mut *stdin)
|
||||
let stdin = io::stdin();
|
||||
let mut locked = stdin.lock();
|
||||
Sudoku::read(&mut locked)
|
||||
};
|
||||
sudoku.solve();
|
||||
sudoku.write(&mut old_io::stdout());
|
||||
let out = io::stdout();
|
||||
sudoku.write(&mut out.lock());
|
||||
}
|
||||
|
|
|
@ -10,4 +10,5 @@
|
|||
|
||||
fn main() {
|
||||
let _ = std::old_io::stdin();
|
||||
let _ = std::io::stdin();
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-fast
|
||||
|
||||
use std::env;
|
||||
use std::old_io;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::str;
|
||||
|
||||
fn main() {
|
||||
|
@ -25,17 +25,19 @@ fn main() {
|
|||
|
||||
fn parent() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let mut p = old_io::process::Command::new(&args[0])
|
||||
.arg("child").spawn().unwrap();
|
||||
p.stdin.as_mut().unwrap().write_str("test1\ntest2\ntest3").unwrap();
|
||||
let mut p = Command::new(&args[0]).arg("child")
|
||||
.stdout(Stdio::capture())
|
||||
.stdin(Stdio::capture())
|
||||
.spawn().unwrap();
|
||||
p.stdin.as_mut().unwrap().write_all(b"test1\ntest2\ntest3").unwrap();
|
||||
let out = p.wait_with_output().unwrap();
|
||||
assert!(out.status.success());
|
||||
let s = str::from_utf8(&out.output).unwrap();
|
||||
assert_eq!(s, "test1\n\ntest2\n\ntest3\n");
|
||||
let s = str::from_utf8(&out.stdout).unwrap();
|
||||
assert_eq!(s, "test1\ntest2\ntest3\n");
|
||||
}
|
||||
|
||||
fn child() {
|
||||
let mut stdin = old_io::stdin();
|
||||
let mut stdin = io::stdin();
|
||||
for line in stdin.lock().lines() {
|
||||
println!("{}", line.unwrap());
|
||||
}
|
||||
|
|
|
@ -8,11 +8,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use std::old_io::process;
|
||||
use std::old_io::Command;
|
||||
use std::old_io;
|
||||
use std::env;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
@ -21,22 +20,23 @@ fn main() {
|
|||
}
|
||||
|
||||
test();
|
||||
|
||||
}
|
||||
|
||||
fn child() {
|
||||
old_io::stdout().write_line("foo").unwrap();
|
||||
old_io::stderr().write_line("bar").unwrap();
|
||||
let mut stdin = old_io::stdin();
|
||||
assert_eq!(stdin.lock().read_line().err().unwrap().kind, old_io::EndOfFile);
|
||||
writeln!(&mut io::stdout(), "foo").unwrap();
|
||||
writeln!(&mut io::stderr(), "bar").unwrap();
|
||||
let mut stdin = io::stdin();
|
||||
let mut s = String::new();
|
||||
stdin.lock().read_line(&mut s).unwrap();
|
||||
assert_eq!(s.len(), 0);
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let mut p = Command::new(&args[0]).arg("child")
|
||||
.stdin(process::Ignored)
|
||||
.stdout(process::Ignored)
|
||||
.stderr(process::Ignored)
|
||||
.stdin(Stdio::capture())
|
||||
.stdout(Stdio::capture())
|
||||
.stderr(Stdio::capture())
|
||||
.spawn().unwrap();
|
||||
assert!(p.wait().unwrap().success());
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
// A var moved into a proc, that has a mutable loan path should
|
||||
// not trigger a misleading unused_mut warning.
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::thread;
|
||||
|
||||
pub fn main() {
|
||||
let mut stdin = std::old_io::stdin();
|
||||
let mut stdin = std::io::stdin();
|
||||
thread::spawn(move|| {
|
||||
let _ = stdin.read_to_end();
|
||||
});
|
||||
let mut v = Vec::new();
|
||||
let _ = stdin.read_to_end(&mut v);
|
||||
}).join().ok().unwrap();
|
||||
}
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
#![allow(unknown_features)]
|
||||
#![feature(box_syntax)]
|
||||
|
||||
use std::old_io;
|
||||
use std::io::{self, Write};
|
||||
|
||||
fn f(wr: &mut Writer) {
|
||||
wr.write_str("hello").ok().expect("failed");
|
||||
fn f(wr: &mut Write) {
|
||||
wr.write_all(b"hello").ok().expect("failed");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut wr = box old_io::stdout() as Box<Writer + 'static>;
|
||||
let mut wr = box io::stdout() as Box<Write>;
|
||||
f(&mut wr);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::old_io;
|
||||
use std::io;
|
||||
|
||||
pub fn main() {
|
||||
let stdout = &mut old_io::stdout() as &mut old_io::Writer;
|
||||
let stdout = &mut io::stdout() as &mut io::Write;
|
||||
stdout.write(b"Hello!");
|
||||
}
|
||||
|
|
|
@ -16,30 +16,31 @@
|
|||
// non-ASCII characters. The child process ensures all the strings are
|
||||
// intact.
|
||||
|
||||
use std::old_io;
|
||||
use std::old_io::fs;
|
||||
use std::old_io::Command;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use std::os;
|
||||
use std::env;
|
||||
use std::old_path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn main() {
|
||||
let my_args = env::args().collect::<Vec<_>>();
|
||||
let my_cwd = os::getcwd().unwrap();
|
||||
let my_cwd = PathBuf::new(os::getcwd().unwrap().as_str().unwrap());
|
||||
let my_env = env::vars().collect::<Vec<_>>();
|
||||
let my_path = Path::new(os::self_exe_name().unwrap());
|
||||
let my_dir = my_path.dir_path();
|
||||
let my_ext = my_path.extension_str().unwrap_or("");
|
||||
let my_path = PathBuf::new(os::self_exe_name().unwrap().as_str().unwrap());
|
||||
let my_dir = my_path.parent().unwrap();
|
||||
let my_ext = my_path.extension().and_then(|s| s.to_str()).unwrap_or("");
|
||||
|
||||
// some non-ASCII characters
|
||||
let blah = "\u03c0\u042f\u97f3\u00e6\u221e";
|
||||
let blah = "\u{3c0}\u{42f}\u{97f3}\u{e6}\u{221e}";
|
||||
|
||||
let child_name = "child";
|
||||
let child_dir = format!("process-spawn-with-unicode-params-{}", blah);
|
||||
|
||||
// parameters sent to child / expected to be received from parent
|
||||
let arg = blah;
|
||||
let cwd = my_dir.join(Path::new(child_dir.clone()));
|
||||
let cwd = my_dir.join(&child_dir);
|
||||
let env = ("RUST_TEST_PROC_SPAWN_UNICODE".to_string(), blah.to_string());
|
||||
|
||||
// am I the parent or the child?
|
||||
|
@ -47,24 +48,22 @@ fn main() {
|
|||
|
||||
let child_filestem = Path::new(child_name);
|
||||
let child_filename = child_filestem.with_extension(my_ext);
|
||||
let child_path = cwd.join(child_filename);
|
||||
let child_path = cwd.join(&child_filename);
|
||||
|
||||
// make a separate directory for the child
|
||||
drop(fs::mkdir(&cwd, old_io::USER_RWX).is_ok());
|
||||
assert!(fs::copy(&my_path, &child_path).is_ok());
|
||||
let mut my_env = my_env;
|
||||
my_env.push(env);
|
||||
let _ = fs::create_dir(&cwd);
|
||||
fs::copy(&my_path, &child_path).unwrap();
|
||||
|
||||
// run child
|
||||
let p = Command::new(&child_path)
|
||||
.arg(arg)
|
||||
.cwd(&cwd)
|
||||
.env_set_all(&my_env)
|
||||
.current_dir(&cwd)
|
||||
.env(&env.0, &env.1)
|
||||
.spawn().unwrap().wait_with_output().unwrap();
|
||||
|
||||
// display the output
|
||||
assert!(old_io::stdout().write(&p.output).is_ok());
|
||||
assert!(old_io::stderr().write(&p.error).is_ok());
|
||||
io::stdout().write_all(&p.stdout).unwrap();
|
||||
io::stderr().write_all(&p.stderr).unwrap();
|
||||
|
||||
// make sure the child succeeded
|
||||
assert!(p.status.success());
|
||||
|
@ -72,7 +71,7 @@ fn main() {
|
|||
} else { // child
|
||||
|
||||
// check working directory (don't try to compare with `cwd` here!)
|
||||
assert!(my_cwd.ends_with_path(&Path::new(child_dir)));
|
||||
assert!(my_cwd.ends_with(&child_dir));
|
||||
|
||||
// check arguments
|
||||
assert_eq!(&*my_args[1], arg);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue