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> {
|
impl<T> Arc<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inner(&self) -> &ArcInner<T> {
|
fn inner(&self) -> &ArcInner<T> {
|
||||||
// This unsafety is ok because while this arc is alive we're guaranteed that the inner
|
// This unsafety is ok because while this arc is alive we're guaranteed
|
||||||
// pointer is valid. Furthermore, we know that the `ArcInner` structure itself is `Sync`
|
// that the inner pointer is valid. Furthermore, we know that the
|
||||||
// because the inner data is `Sync` as well, so we're ok loaning out an immutable pointer
|
// `ArcInner` structure itself is `Sync` because the inner data is
|
||||||
// to these contents.
|
// `Sync` as well, so we're ok loaning out an immutable pointer to these
|
||||||
|
// contents.
|
||||||
unsafe { &**self._ptr }
|
unsafe { &**self._ptr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,13 +237,15 @@ impl<T> Clone for Arc<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Arc<T> {
|
fn clone(&self) -> Arc<T> {
|
||||||
// Using a relaxed ordering is alright here, as knowledge of the original reference
|
// Using a relaxed ordering is alright here, as knowledge of the
|
||||||
// prevents other threads from erroneously deleting the object.
|
// original reference prevents other threads from erroneously deleting
|
||||||
|
// the object.
|
||||||
//
|
//
|
||||||
// As explained in the [Boost documentation][1], Increasing the reference counter can
|
// As explained in the [Boost documentation][1], Increasing the
|
||||||
// always be done with memory_order_relaxed: New references to an object can only be formed
|
// reference counter can always be done with memory_order_relaxed: New
|
||||||
// from an existing reference, and passing an existing reference from one thread to another
|
// references to an object can only be formed from an existing
|
||||||
// must already provide any required synchronization.
|
// 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)
|
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
|
||||||
self.inner().strong.fetch_add(1, Relaxed);
|
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::cursor::Cursor;
|
||||||
pub use self::error::{Result, Error, ErrorKind};
|
pub use self::error::{Result, Error, ErrorKind};
|
||||||
pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
|
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;
|
pub mod prelude;
|
||||||
mod buffered;
|
mod buffered;
|
||||||
|
@ -46,6 +50,7 @@ mod cursor;
|
||||||
mod error;
|
mod error;
|
||||||
mod impls;
|
mod impls;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod stdio;
|
||||||
|
|
||||||
const DEFAULT_BUF_SIZE: usize = 64 * 1024;
|
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 {
|
unsafe {
|
||||||
ONCE.call_once(|| {
|
ONCE.call_once(|| {
|
||||||
// The default buffer capacity is 64k, but apparently windows doesn't like
|
// The default buffer capacity is 64k, but apparently windows
|
||||||
// 64k reads on stdin. See #13304 for details, but the idea is that on
|
// doesn't like 64k reads on stdin. See #13304 for details, but the
|
||||||
// windows we use a slightly smaller buffer that's been seen to be
|
// idea is that on windows we use a slightly smaller buffer that's
|
||||||
// acceptable.
|
// been seen to be acceptable.
|
||||||
let stdin = if cfg!(windows) {
|
let stdin = if cfg!(windows) {
|
||||||
BufferedReader::with_capacity(8 * 1024, stdin_raw())
|
BufferedReader::with_capacity(8 * 1024, stdin_raw())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -63,6 +63,7 @@ pub mod time;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod tty;
|
pub mod tty;
|
||||||
pub mod udp;
|
pub mod udp;
|
||||||
|
pub mod stdio;
|
||||||
|
|
||||||
pub mod addrinfo {
|
pub mod addrinfo {
|
||||||
pub use sys_common::net::get_host_addresses;
|
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 ERROR_NO_MORE_FILES: libc::DWORD = 18;
|
||||||
pub const TOKEN_READ: libc::DWORD = 0x20008;
|
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)]
|
#[repr(C)]
|
||||||
#[cfg(target_arch = "x86")]
|
#[cfg(target_arch = "x86")]
|
||||||
pub struct WSADATA {
|
pub struct WSADATA {
|
||||||
|
@ -427,6 +432,7 @@ extern "system" {
|
||||||
DesiredAccess: libc::DWORD,
|
DesiredAccess: libc::DWORD,
|
||||||
TokenHandle: *mut libc::HANDLE) -> libc::BOOL;
|
TokenHandle: *mut libc::HANDLE) -> libc::BOOL;
|
||||||
pub fn GetCurrentProcess() -> libc::HANDLE;
|
pub fn GetCurrentProcess() -> libc::HANDLE;
|
||||||
|
pub fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[link(name = "userenv")]
|
#[link(name = "userenv")]
|
||||||
|
|
|
@ -10,9 +10,10 @@
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use libc::{self, HANDLE};
|
|
||||||
use io;
|
|
||||||
use io::ErrorKind;
|
use io::ErrorKind;
|
||||||
|
use io;
|
||||||
|
use libc::{self, HANDLE};
|
||||||
|
use mem;
|
||||||
use ptr;
|
use ptr;
|
||||||
use sys::cvt;
|
use sys::cvt;
|
||||||
|
|
||||||
|
@ -28,6 +29,12 @@ impl Handle {
|
||||||
|
|
||||||
pub fn raw(&self) -> HANDLE { self.0 }
|
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> {
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
read(self.0, buf)
|
read(self.0, buf)
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ pub mod time;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod tty;
|
pub mod tty;
|
||||||
pub mod udp;
|
pub mod udp;
|
||||||
|
pub mod stdio;
|
||||||
|
|
||||||
pub mod addrinfo {
|
pub mod addrinfo {
|
||||||
pub use sys_common::net::get_host_addresses;
|
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)]
|
#![feature(box_syntax)]
|
||||||
|
|
||||||
use std::ascii::OwnedAsciiExt;
|
use std::ascii::OwnedAsciiExt;
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
static TABLE: [u8;4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
|
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] = [
|
static OCCURRENCES: [&'static str;5] = [
|
||||||
"GGT",
|
"GGT",
|
||||||
|
@ -73,7 +77,7 @@ impl Code {
|
||||||
Code((self.hash() << 2) + (pack_symbol(c) as u64))
|
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))
|
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))
|
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 key = self.hash();
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for _ in 0..frame {
|
for _ in 0..frame {
|
||||||
|
@ -113,13 +117,13 @@ struct PrintCallback(&'static str);
|
||||||
impl TableCallback for PrintCallback {
|
impl TableCallback for PrintCallback {
|
||||||
fn f(&self, entry: &mut Entry) {
|
fn f(&self, entry: &mut Entry) {
|
||||||
let PrintCallback(s) = *self;
|
let PrintCallback(s) = *self;
|
||||||
println!("{}\t{}", entry.count as int, s);
|
println!("{}\t{}", entry.count, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
code: Code,
|
code: Code,
|
||||||
count: uint,
|
count: usize,
|
||||||
next: Option<Box<Entry>>,
|
next: Option<Box<Entry>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,20 +169,20 @@ impl Table {
|
||||||
let index = key.hash() % (TABLE_SIZE as u64);
|
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 {
|
let mut entry = box Entry {
|
||||||
code: key,
|
code: key,
|
||||||
count: 0,
|
count: 0,
|
||||||
next: None,
|
next: None,
|
||||||
};
|
};
|
||||||
c.f(&mut *entry);
|
c.f(&mut *entry);
|
||||||
self.items[index as uint] = Some(entry);
|
self.items[index as usize] = Some(entry);
|
||||||
return;
|
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 {
|
if entry.code == key {
|
||||||
c.f(&mut **entry);
|
c.f(&mut **entry);
|
||||||
return;
|
return;
|
||||||
|
@ -233,10 +237,10 @@ fn pack_symbol(c: u8) -> u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unpack_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();
|
let mut frequencies = Table::new();
|
||||||
if input.len() < frame { return frequencies; }
|
if input.len() < frame { return frequencies; }
|
||||||
let mut code = Code(0);
|
let mut code = Code(0);
|
||||||
|
@ -256,7 +260,7 @@ fn generate_frequencies(mut input: &[u8], frame: uint) -> Table {
|
||||||
frequencies
|
frequencies
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_frequencies(frequencies: &Table, frame: uint) {
|
fn print_frequencies(frequencies: &Table, frame: usize) {
|
||||||
let mut vector = Vec::new();
|
let mut vector = Vec::new();
|
||||||
for entry in frequencies.iter() {
|
for entry in frequencies.iter() {
|
||||||
vector.push((entry.count, entry.code));
|
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))
|
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();
|
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)
|
.skip_while(|l| key != &l[..key.len()]).skip(1)
|
||||||
{
|
{
|
||||||
res.push_all(l.trim().as_bytes());
|
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() {
|
fn main() {
|
||||||
let input = if std::env::var_os("RUST_BENCH").is_some() {
|
let input = if env::var_os("RUST_BENCH").is_some() {
|
||||||
let fd = std::old_io::File::open(&Path::new("shootout-k-nucleotide.data"));
|
let f = File::open("shootout-k-nucleotide.data").unwrap();
|
||||||
get_sequence(&mut std::old_io::BufferedReader::new(fd), ">THREE")
|
get_sequence(&mut io::BufReader::new(f), ">THREE")
|
||||||
} else {
|
} else {
|
||||||
let mut stdin = std::old_io::stdin();
|
let stdin = io::stdin();
|
||||||
let mut stdin = stdin.lock();
|
let mut stdin = stdin.lock();
|
||||||
get_sequence(&mut *stdin, ">THREE")
|
get_sequence(&mut stdin, ">THREE")
|
||||||
};
|
};
|
||||||
let input = Arc::new(input);
|
let input = Arc::new(input);
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,8 @@
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use std::old_io::BufferedReader;
|
use std::io::prelude::*;
|
||||||
use std::old_io::stdio::StdReader;
|
use std::io;
|
||||||
use std::old_io;
|
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::num::Int;
|
use std::num::Int;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -37,7 +36,7 @@ use std::env;
|
||||||
//
|
//
|
||||||
|
|
||||||
// internal type of sudoku grids
|
// internal type of sudoku grids
|
||||||
type grid = Vec<Vec<u8> > ;
|
type grid = Vec<Vec<u8>>;
|
||||||
|
|
||||||
struct Sudoku {
|
struct Sudoku {
|
||||||
grid: grid
|
grid: grid
|
||||||
|
@ -55,9 +54,11 @@ impl Sudoku {
|
||||||
return Sudoku::new(g)
|
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 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])
|
let mut g = repeat(vec![0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8])
|
||||||
.take(10).collect::<Vec<_>>();
|
.take(10).collect::<Vec<_>>();
|
||||||
|
@ -71,7 +72,7 @@ impl Sudoku {
|
||||||
if comps.len() == 3 {
|
if comps.len() == 3 {
|
||||||
let row = comps[0].parse::<u8>().unwrap();
|
let row = comps[0].parse::<u8>().unwrap();
|
||||||
let col = comps[1].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 {
|
else {
|
||||||
panic!("Invalid sudoku file");
|
panic!("Invalid sudoku file");
|
||||||
|
@ -80,11 +81,11 @@ impl Sudoku {
|
||||||
return Sudoku::new(g)
|
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 {
|
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 {
|
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");
|
write!(writer, "\n");
|
||||||
}
|
}
|
||||||
|
@ -95,7 +96,7 @@ impl Sudoku {
|
||||||
let mut work: Vec<(u8, u8)> = Vec::new(); /* queue of uncolored fields */
|
let mut work: Vec<(u8, u8)> = Vec::new(); /* queue of uncolored fields */
|
||||||
for row in 0u8..9u8 {
|
for row in 0u8..9u8 {
|
||||||
for col 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 {
|
if color == 0u8 {
|
||||||
work.push((row, col));
|
work.push((row, col));
|
||||||
}
|
}
|
||||||
|
@ -107,7 +108,7 @@ impl Sudoku {
|
||||||
while ptr < end {
|
while ptr < end {
|
||||||
let (row, col) = work[ptr];
|
let (row, col) = work[ptr];
|
||||||
// is there another color to try?
|
// 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);
|
(1 as u8);
|
||||||
if self.next_color(row, col, the_color) {
|
if self.next_color(row, col, the_color) {
|
||||||
// yes: advance work list
|
// yes: advance work list
|
||||||
|
@ -130,10 +131,10 @@ impl Sudoku {
|
||||||
|
|
||||||
// find first remaining color that is available
|
// find first remaining color that is available
|
||||||
let next = avail.next();
|
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;
|
return 0u8 != next;
|
||||||
}
|
}
|
||||||
self.grid[row as uint][col as uint] = 0u8;
|
self.grid[row as usize][col as usize] = 0u8;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,9 +142,9 @@ impl Sudoku {
|
||||||
fn drop_colors(&mut self, avail: &mut Colors, row: u8, col: u8) {
|
fn drop_colors(&mut self, avail: &mut Colors, row: u8, col: u8) {
|
||||||
for idx in 0u8..9u8 {
|
for idx in 0u8..9u8 {
|
||||||
/* check same column fields */
|
/* 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 */
|
/* 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
|
// check same block fields
|
||||||
|
@ -151,7 +152,7 @@ impl Sudoku {
|
||||||
let col0 = (col / 3u8) * 3u8;
|
let col0 = (col / 3u8) * 3u8;
|
||||||
for alt_row in row0..row0 + 3u8 {
|
for alt_row in row0..row0 + 3u8 {
|
||||||
for alt_col in col0..col0 + 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 {
|
impl Colors {
|
||||||
fn new(start_color: u8) -> Colors {
|
fn new(start_color: u8) -> Colors {
|
||||||
// Sets bits 9..start_color
|
// Sets bits 9..start_color
|
||||||
let tails = !0u16 << start_color as uint;
|
let tails = !0u16 << start_color as usize;
|
||||||
return Colors(HEADS & tails);
|
return Colors(HEADS & tails);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +183,7 @@ impl Colors {
|
||||||
fn remove(&mut self, color: u8) {
|
fn remove(&mut self, color: u8) {
|
||||||
if color != 0u8 {
|
if color != 0u8 {
|
||||||
let Colors(val) = *self;
|
let Colors(val) = *self;
|
||||||
let mask = !(1u16 << color as uint);
|
let mask = !(1u16 << color as usize);
|
||||||
*self = Colors(val & mask);
|
*self = Colors(val & mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,10 +275,11 @@ fn main() {
|
||||||
let mut sudoku = if use_default {
|
let mut sudoku = if use_default {
|
||||||
Sudoku::from_vec(&DEFAULT_SUDOKU)
|
Sudoku::from_vec(&DEFAULT_SUDOKU)
|
||||||
} else {
|
} else {
|
||||||
let mut stdin = old_io::stdin();
|
let stdin = io::stdin();
|
||||||
let mut stdin = stdin.lock();
|
let mut locked = stdin.lock();
|
||||||
Sudoku::read(&mut *stdin)
|
Sudoku::read(&mut locked)
|
||||||
};
|
};
|
||||||
sudoku.solve();
|
sudoku.solve();
|
||||||
sudoku.write(&mut old_io::stdout());
|
let out = io::stdout();
|
||||||
|
sudoku.write(&mut out.lock());
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,4 +10,5 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = std::old_io::stdin();
|
let _ = std::old_io::stdin();
|
||||||
|
let _ = std::io::stdin();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// ignore-fast
|
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::old_io;
|
use std::io::prelude::*;
|
||||||
|
use std::io;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -25,17 +25,19 @@ fn main() {
|
||||||
|
|
||||||
fn parent() {
|
fn parent() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let mut p = old_io::process::Command::new(&args[0])
|
let mut p = Command::new(&args[0]).arg("child")
|
||||||
.arg("child").spawn().unwrap();
|
.stdout(Stdio::capture())
|
||||||
p.stdin.as_mut().unwrap().write_str("test1\ntest2\ntest3").unwrap();
|
.stdin(Stdio::capture())
|
||||||
|
.spawn().unwrap();
|
||||||
|
p.stdin.as_mut().unwrap().write_all(b"test1\ntest2\ntest3").unwrap();
|
||||||
let out = p.wait_with_output().unwrap();
|
let out = p.wait_with_output().unwrap();
|
||||||
assert!(out.status.success());
|
assert!(out.status.success());
|
||||||
let s = str::from_utf8(&out.output).unwrap();
|
let s = str::from_utf8(&out.stdout).unwrap();
|
||||||
assert_eq!(s, "test1\n\ntest2\n\ntest3\n");
|
assert_eq!(s, "test1\ntest2\ntest3\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn child() {
|
fn child() {
|
||||||
let mut stdin = old_io::stdin();
|
let mut stdin = io::stdin();
|
||||||
for line in stdin.lock().lines() {
|
for line in stdin.lock().lines() {
|
||||||
println!("{}", line.unwrap());
|
println!("{}", line.unwrap());
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,10 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
|
||||||
use std::old_io::process;
|
|
||||||
use std::old_io::Command;
|
|
||||||
use std::old_io;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
@ -21,22 +20,23 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
test();
|
test();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn child() {
|
fn child() {
|
||||||
old_io::stdout().write_line("foo").unwrap();
|
writeln!(&mut io::stdout(), "foo").unwrap();
|
||||||
old_io::stderr().write_line("bar").unwrap();
|
writeln!(&mut io::stderr(), "bar").unwrap();
|
||||||
let mut stdin = old_io::stdin();
|
let mut stdin = io::stdin();
|
||||||
assert_eq!(stdin.lock().read_line().err().unwrap().kind, old_io::EndOfFile);
|
let mut s = String::new();
|
||||||
|
stdin.lock().read_line(&mut s).unwrap();
|
||||||
|
assert_eq!(s.len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let mut p = Command::new(&args[0]).arg("child")
|
let mut p = Command::new(&args[0]).arg("child")
|
||||||
.stdin(process::Ignored)
|
.stdin(Stdio::capture())
|
||||||
.stdout(process::Ignored)
|
.stdout(Stdio::capture())
|
||||||
.stderr(process::Ignored)
|
.stderr(Stdio::capture())
|
||||||
.spawn().unwrap();
|
.spawn().unwrap();
|
||||||
assert!(p.wait().unwrap().success());
|
assert!(p.wait().unwrap().success());
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,13 @@
|
||||||
// A var moved into a proc, that has a mutable loan path should
|
// A var moved into a proc, that has a mutable loan path should
|
||||||
// not trigger a misleading unused_mut warning.
|
// not trigger a misleading unused_mut warning.
|
||||||
|
|
||||||
|
use std::io::prelude::*;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let mut stdin = std::old_io::stdin();
|
let mut stdin = std::io::stdin();
|
||||||
thread::spawn(move|| {
|
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)]
|
#![allow(unknown_features)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
|
||||||
use std::old_io;
|
use std::io::{self, Write};
|
||||||
|
|
||||||
fn f(wr: &mut Writer) {
|
fn f(wr: &mut Write) {
|
||||||
wr.write_str("hello").ok().expect("failed");
|
wr.write_all(b"hello").ok().expect("failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
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);
|
f(&mut wr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use std::old_io;
|
use std::io;
|
||||||
|
|
||||||
pub fn main() {
|
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!");
|
stdout.write(b"Hello!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,30 +16,31 @@
|
||||||
// non-ASCII characters. The child process ensures all the strings are
|
// non-ASCII characters. The child process ensures all the strings are
|
||||||
// intact.
|
// intact.
|
||||||
|
|
||||||
use std::old_io;
|
use std::io::prelude::*;
|
||||||
use std::old_io::fs;
|
use std::io;
|
||||||
use std::old_io::Command;
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
use std::os;
|
use std::os;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::old_path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let my_args = env::args().collect::<Vec<_>>();
|
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_env = env::vars().collect::<Vec<_>>();
|
||||||
let my_path = Path::new(os::self_exe_name().unwrap());
|
let my_path = PathBuf::new(os::self_exe_name().unwrap().as_str().unwrap());
|
||||||
let my_dir = my_path.dir_path();
|
let my_dir = my_path.parent().unwrap();
|
||||||
let my_ext = my_path.extension_str().unwrap_or("");
|
let my_ext = my_path.extension().and_then(|s| s.to_str()).unwrap_or("");
|
||||||
|
|
||||||
// some non-ASCII characters
|
// 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_name = "child";
|
||||||
let child_dir = format!("process-spawn-with-unicode-params-{}", blah);
|
let child_dir = format!("process-spawn-with-unicode-params-{}", blah);
|
||||||
|
|
||||||
// parameters sent to child / expected to be received from parent
|
// parameters sent to child / expected to be received from parent
|
||||||
let arg = blah;
|
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());
|
let env = ("RUST_TEST_PROC_SPAWN_UNICODE".to_string(), blah.to_string());
|
||||||
|
|
||||||
// am I the parent or the child?
|
// am I the parent or the child?
|
||||||
|
@ -47,24 +48,22 @@ fn main() {
|
||||||
|
|
||||||
let child_filestem = Path::new(child_name);
|
let child_filestem = Path::new(child_name);
|
||||||
let child_filename = child_filestem.with_extension(my_ext);
|
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
|
// make a separate directory for the child
|
||||||
drop(fs::mkdir(&cwd, old_io::USER_RWX).is_ok());
|
let _ = fs::create_dir(&cwd);
|
||||||
assert!(fs::copy(&my_path, &child_path).is_ok());
|
fs::copy(&my_path, &child_path).unwrap();
|
||||||
let mut my_env = my_env;
|
|
||||||
my_env.push(env);
|
|
||||||
|
|
||||||
// run child
|
// run child
|
||||||
let p = Command::new(&child_path)
|
let p = Command::new(&child_path)
|
||||||
.arg(arg)
|
.arg(arg)
|
||||||
.cwd(&cwd)
|
.current_dir(&cwd)
|
||||||
.env_set_all(&my_env)
|
.env(&env.0, &env.1)
|
||||||
.spawn().unwrap().wait_with_output().unwrap();
|
.spawn().unwrap().wait_with_output().unwrap();
|
||||||
|
|
||||||
// display the output
|
// display the output
|
||||||
assert!(old_io::stdout().write(&p.output).is_ok());
|
io::stdout().write_all(&p.stdout).unwrap();
|
||||||
assert!(old_io::stderr().write(&p.error).is_ok());
|
io::stderr().write_all(&p.stderr).unwrap();
|
||||||
|
|
||||||
// make sure the child succeeded
|
// make sure the child succeeded
|
||||||
assert!(p.status.success());
|
assert!(p.status.success());
|
||||||
|
@ -72,7 +71,7 @@ fn main() {
|
||||||
} else { // child
|
} else { // child
|
||||||
|
|
||||||
// check working directory (don't try to compare with `cwd` here!)
|
// 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
|
// check arguments
|
||||||
assert_eq!(&*my_args[1], arg);
|
assert_eq!(&*my_args[1], arg);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue