std: Remove old_io/old_path/rand modules

This commit entirely removes the old I/O, path, and rand modules. All
functionality has been deprecated and unstable for quite some time now!
This commit is contained in:
Alex Crichton 2015-04-09 17:42:22 -07:00
parent dabf0c6371
commit bf4e77d4b5
57 changed files with 60 additions and 22827 deletions

View File

@ -24,15 +24,13 @@
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(no_std)]
#![no_std]
#![unstable(feature = "rand")]
#![feature(staged_api)]
#![staged_api]
#![unstable(feature = "rand")]
#![feature(core)]
#![feature(no_std)]
#![feature(staged_api)]
#![feature(step_by)]
#![deprecated(reason = "use the crates.io `rand` library instead",
since = "1.0.0-alpha")]
#![cfg_attr(test, feature(test, rand, rustc_private))]

View File

@ -30,7 +30,6 @@ Core encoding and decoding interfaces.
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(old_path)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(std_misc)]

View File

@ -14,8 +14,6 @@
Core encoding and decoding interfaces.
*/
#[allow(deprecated)]
use std::old_path::{self, GenericPath};
use std::path;
use std::rc::Rc;
use std::cell::{Cell, RefCell};
@ -540,36 +538,6 @@ macro_rules! tuple {
tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
#[allow(deprecated)]
impl Encodable for old_path::posix::Path {
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
self.as_vec().encode(e)
}
}
#[allow(deprecated)]
impl Decodable for old_path::posix::Path {
fn decode<D: Decoder>(d: &mut D) -> Result<old_path::posix::Path, D::Error> {
let bytes: Vec<u8> = try!(Decodable::decode(d));
Ok(old_path::posix::Path::new(bytes))
}
}
#[allow(deprecated)]
impl Encodable for old_path::windows::Path {
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
self.as_vec().encode(e)
}
}
#[allow(deprecated)]
impl Decodable for old_path::windows::Path {
fn decode<D: Decoder>(d: &mut D) -> Result<old_path::windows::Path, D::Error> {
let bytes: Vec<u8> = try!(Decodable::decode(d));
Ok(old_path::windows::Path::new(bytes))
}
}
impl Encodable for path::PathBuf {
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
self.to_str().unwrap().encode(e)

View File

@ -18,8 +18,6 @@ use io;
use iter::Iterator;
use libc;
use mem;
#[allow(deprecated)]
use old_io;
use ops::Deref;
use option::Option::{self, Some, None};
use result::Result::{self, Ok, Err};
@ -245,18 +243,6 @@ impl From<NulError> for io::Error {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl From<NulError> for old_io::IoError {
fn from(_: NulError) -> old_io::IoError {
old_io::IoError {
kind: old_io::IoErrorKind::InvalidInput,
desc: "data provided contains a nul byte",
detail: None
}
}
}
impl CStr {
/// Cast a raw C string to a safe C string wrapper.
///

View File

@ -42,7 +42,6 @@ use string::String;
use ops;
use cmp;
use hash::{Hash, Hasher};
use old_path::{Path, GenericPath};
use vec::Vec;
use sys::os_str::{Buf, Slice};
@ -447,21 +446,6 @@ impl AsRef<OsStr> for String {
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
impl AsOsStr for Path {
#[cfg(unix)]
fn as_os_str(&self) -> &OsStr {
unsafe { mem::transmute(self.as_vec()) }
}
#[cfg(windows)]
fn as_os_str(&self) -> &OsStr {
// currently .as_str() is actually infallible on windows
OsStr::from_str(self.as_str().unwrap())
}
}
impl FromInner<Buf> for OsString {
fn from_inner(buf: Buf) -> OsString {
OsString { inner: buf }

View File

@ -262,12 +262,9 @@ pub mod ffi;
pub mod fs;
pub mod io;
pub mod net;
pub mod old_io;
pub mod old_path;
pub mod os;
pub mod path;
pub mod process;
pub mod rand;
pub mod sync;
pub mod time;
@ -281,6 +278,7 @@ pub mod time;
pub mod rt;
mod panicking;
mod rand;
// Modules that exist purely to document + host impl docs for primitive types
@ -297,8 +295,6 @@ mod std {
pub use sync; // used for select!()
pub use error; // used for try!()
pub use fmt; // used for any formatting strings
#[allow(deprecated)]
pub use old_io; // used for println!()
pub use option; // used for bitflags!{}
pub use rt; // used for panic!()
pub use vec; // used for vec![]

View File

@ -1,702 +0,0 @@
// Copyright 2013 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.
//
// ignore-lexer-test FIXME #15883
//! Buffering wrappers for I/O traits
use cmp;
use fmt;
use old_io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult};
use iter::{Iterator, ExactSizeIterator, repeat};
use ops::Drop;
use option::Option;
use option::Option::{Some, None};
use result::Result::Ok;
use slice;
use vec::Vec;
/// Wraps a Reader and buffers input from it
///
/// It can be excessively inefficient to work directly with a `Reader`. For
/// example, every call to `read` on `TcpStream` results in a system call. A
/// `BufferedReader` performs large, infrequent reads on the underlying
/// `Reader` and maintains an in-memory buffer of the results.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, old_path)]
/// use std::old_io::*;
/// use std::old_path::Path;
///
/// let file = File::open(&Path::new("message.txt"));
/// let mut reader = BufferedReader::new(file);
///
/// let mut buf = [0; 100];
/// match reader.read(&mut buf) {
/// Ok(nread) => println!("Read {} bytes", nread),
/// Err(e) => println!("error reading: {}", e)
/// }
/// ```
pub struct BufferedReader<R> {
inner: R,
buf: Vec<u8>,
pos: usize,
cap: usize,
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<R> fmt::Debug for BufferedReader<R> where R: fmt::Debug {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "BufferedReader {{ reader: {:?}, buffer: {}/{} }}",
self.inner, self.cap - self.pos, self.buf.len())
}
}
impl<R: Reader> BufferedReader<R> {
/// Creates a new `BufferedReader` with the specified buffer capacity
pub fn with_capacity(cap: usize, inner: R) -> BufferedReader<R> {
BufferedReader {
inner: inner,
// We can't use the same trick here as we do for BufferedWriter,
// since this memory is visible to the inner Reader.
buf: repeat(0).take(cap).collect(),
pos: 0,
cap: 0,
}
}
/// Creates a new `BufferedReader` with a default buffer capacity
pub fn new(inner: R) -> BufferedReader<R> {
BufferedReader::with_capacity(DEFAULT_BUF_SIZE, inner)
}
/// Gets a reference to the underlying reader.
pub fn get_ref<'a>(&self) -> &R { &self.inner }
/// Gets a mutable reference to the underlying reader.
///
/// # Warning
///
/// It is inadvisable to directly read from the underlying reader.
pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
/// Unwraps this `BufferedReader`, returning the underlying reader.
///
/// Note that any leftover data in the internal buffer is lost.
pub fn into_inner(self) -> R { self.inner }
}
impl<R: Reader> Buffer for BufferedReader<R> {
fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
if self.pos == self.cap {
self.cap = try!(self.inner.read(&mut self.buf));
self.pos = 0;
}
Ok(&self.buf[self.pos..self.cap])
}
fn consume(&mut self, amt: usize) {
self.pos += amt;
assert!(self.pos <= self.cap);
}
}
impl<R: Reader> Reader for BufferedReader<R> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
if self.pos == self.cap && buf.len() >= self.buf.len() {
return self.inner.read(buf);
}
let nread = {
let available = try!(self.fill_buf());
let nread = cmp::min(available.len(), buf.len());
slice::bytes::copy_memory(&available[..nread], buf);
nread
};
self.pos += nread;
Ok(nread)
}
}
/// Wraps a Writer and buffers output to it
///
/// It can be excessively inefficient to work directly with a `Writer`. For
/// example, every call to `write` on `TcpStream` results in a system call. A
/// `BufferedWriter` keeps an in memory buffer of data and writes it to the
/// underlying `Writer` in large, infrequent batches.
///
/// This writer will be flushed when it is dropped.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, old_path)]
/// use std::old_io::*;
/// use std::old_path::Path;
///
/// let file = File::create(&Path::new("message.txt")).unwrap();
/// let mut writer = BufferedWriter::new(file);
///
/// writer.write_str("hello, world").unwrap();
/// writer.flush().unwrap();
/// ```
pub struct BufferedWriter<W: Writer> {
inner: Option<W>,
buf: Vec<u8>,
pos: usize
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Writer> fmt::Debug for BufferedWriter<W> where W: fmt::Debug {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "BufferedWriter {{ writer: {:?}, buffer: {}/{} }}",
self.inner.as_ref().unwrap(), self.pos, self.buf.len())
}
}
impl<W: Writer> BufferedWriter<W> {
/// Creates a new `BufferedWriter` with the specified buffer capacity
pub fn with_capacity(cap: usize, inner: W) -> BufferedWriter<W> {
// It's *much* faster to create an uninitialized buffer than it is to
// fill everything in with 0. This buffer is entirely an implementation
// detail and is never exposed, so we're safe to not initialize
// everything up-front. This allows creation of BufferedWriter instances
// to be very cheap (large mallocs are not nearly as expensive as large
// callocs).
let mut buf = Vec::with_capacity(cap);
unsafe { buf.set_len(cap); }
BufferedWriter {
inner: Some(inner),
buf: buf,
pos: 0
}
}
/// Creates a new `BufferedWriter` with a default buffer capacity
pub fn new(inner: W) -> BufferedWriter<W> {
BufferedWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
}
fn flush_buf(&mut self) -> IoResult<()> {
if self.pos != 0 {
let ret = self.inner.as_mut().unwrap().write_all(&self.buf[..self.pos]);
self.pos = 0;
ret
} else {
Ok(())
}
}
/// Gets a reference to the underlying writer.
pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() }
/// Gets a mutable reference to the underlying write.
///
/// # Warning
///
/// It is inadvisable to directly read from the underlying writer.
pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() }
/// Unwraps this `BufferedWriter`, returning the underlying writer.
///
/// The buffer is flushed before returning the writer.
pub fn into_inner(mut self) -> W {
// FIXME(#12628): is panicking the right thing to do if flushing panicks?
self.flush_buf().unwrap();
self.inner.take().unwrap()
}
}
impl<W: Writer> Writer for BufferedWriter<W> {
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
if self.pos + buf.len() > self.buf.len() {
try!(self.flush_buf());
}
if buf.len() > self.buf.len() {
self.inner.as_mut().unwrap().write_all(buf)
} else {
let dst = &mut self.buf[self.pos..];
slice::bytes::copy_memory(buf, dst);
self.pos += buf.len();
Ok(())
}
}
fn flush(&mut self) -> IoResult<()> {
self.flush_buf().and_then(|()| self.inner.as_mut().unwrap().flush())
}
}
#[unsafe_destructor]
impl<W: Writer> Drop for BufferedWriter<W> {
fn drop(&mut self) {
if self.inner.is_some() {
// dtors should not panic, so we ignore a panicked flush
let _ = self.flush_buf();
}
}
}
/// Wraps a Writer and buffers output to it, flushing whenever a newline (`0x0a`,
/// `'\n'`) is detected.
///
/// This writer will be flushed when it is dropped.
pub struct LineBufferedWriter<W: Writer> {
inner: BufferedWriter<W>,
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Writer> fmt::Debug for LineBufferedWriter<W> where W: fmt::Debug {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "LineBufferedWriter {{ writer: {:?}, buffer: {}/{} }}",
self.inner.inner, self.inner.pos, self.inner.buf.len())
}
}
impl<W: Writer> LineBufferedWriter<W> {
/// Creates a new `LineBufferedWriter`
pub fn new(inner: W) -> LineBufferedWriter<W> {
// Lines typically aren't that long, don't use a giant buffer
LineBufferedWriter {
inner: BufferedWriter::with_capacity(1024, inner)
}
}
/// Gets a reference to the underlying writer.
///
/// This type does not expose the ability to get a mutable reference to the
/// underlying reader because that could possibly corrupt the buffer.
pub fn get_ref<'a>(&'a self) -> &'a W { self.inner.get_ref() }
/// Unwraps this `LineBufferedWriter`, returning the underlying writer.
///
/// The internal buffer is flushed before returning the writer.
pub fn into_inner(self) -> W { self.inner.into_inner() }
}
impl<W: Writer> Writer for LineBufferedWriter<W> {
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
match buf.iter().rposition(|&b| b == b'\n') {
Some(i) => {
try!(self.inner.write_all(&buf[..i + 1]));
try!(self.inner.flush());
try!(self.inner.write_all(&buf[i + 1..]));
Ok(())
}
None => self.inner.write_all(buf),
}
}
fn flush(&mut self) -> IoResult<()> { self.inner.flush() }
}
struct InternalBufferedWriter<W: Writer>(BufferedWriter<W>);
impl<W: Writer> InternalBufferedWriter<W> {
fn get_mut<'a>(&'a mut self) -> &'a mut BufferedWriter<W> {
let InternalBufferedWriter(ref mut w) = *self;
return w;
}
}
impl<W: Reader + Writer> Reader for InternalBufferedWriter<W> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
self.get_mut().inner.as_mut().unwrap().read(buf)
}
}
/// Wraps a Stream and buffers input and output to and from it.
///
/// It can be excessively inefficient to work directly with a `Stream`. For
/// example, every call to `read` or `write` on `TcpStream` results in a system
/// call. A `BufferedStream` keeps in memory buffers of data, making large,
/// infrequent calls to `read` and `write` on the underlying `Stream`.
///
/// The output half will be flushed when this stream is dropped.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, old_path)]
/// # #![allow(unused_must_use)]
/// use std::old_io::*;
/// use std::old_path::Path;
///
/// let file = File::open(&Path::new("message.txt"));
/// let mut stream = BufferedStream::new(file);
///
/// stream.write_all("hello, world".as_bytes());
/// stream.flush();
///
/// let mut buf = [0; 100];
/// match stream.read(&mut buf) {
/// Ok(nread) => println!("Read {} bytes", nread),
/// Err(e) => println!("error reading: {}", e)
/// }
/// ```
pub struct BufferedStream<S: Writer> {
inner: BufferedReader<InternalBufferedWriter<S>>
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<S: Writer> fmt::Debug for BufferedStream<S> where S: fmt::Debug {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let reader = &self.inner;
let writer = &self.inner.inner.0;
write!(fmt, "BufferedStream {{ stream: {:?}, write_buffer: {}/{}, read_buffer: {}/{} }}",
writer.inner,
writer.pos, writer.buf.len(),
reader.cap - reader.pos, reader.buf.len())
}
}
impl<S: Stream> BufferedStream<S> {
/// Creates a new buffered stream with explicitly listed capacities for the
/// reader/writer buffer.
pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S)
-> BufferedStream<S> {
let writer = BufferedWriter::with_capacity(writer_cap, inner);
let internal_writer = InternalBufferedWriter(writer);
let reader = BufferedReader::with_capacity(reader_cap,
internal_writer);
BufferedStream { inner: reader }
}
/// Creates a new buffered stream with the default reader/writer buffer
/// capacities.
pub fn new(inner: S) -> BufferedStream<S> {
BufferedStream::with_capacities(DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE,
inner)
}
/// Gets a reference to the underlying stream.
pub fn get_ref(&self) -> &S {
let InternalBufferedWriter(ref w) = self.inner.inner;
w.get_ref()
}
/// Gets a mutable reference to the underlying stream.
///
/// # Warning
///
/// It is inadvisable to read directly from or write directly to the
/// underlying stream.
pub fn get_mut(&mut self) -> &mut S {
let InternalBufferedWriter(ref mut w) = self.inner.inner;
w.get_mut()
}
/// Unwraps this `BufferedStream`, returning the underlying stream.
///
/// The internal buffer is flushed before returning the stream. Any leftover
/// data in the read buffer is lost.
pub fn into_inner(self) -> S {
let InternalBufferedWriter(w) = self.inner.inner;
w.into_inner()
}
}
impl<S: Stream> Buffer for BufferedStream<S> {
fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { self.inner.fill_buf() }
fn consume(&mut self, amt: usize) { self.inner.consume(amt) }
}
impl<S: Stream> Reader for BufferedStream<S> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
self.inner.read(buf)
}
}
impl<S: Stream> Writer for BufferedStream<S> {
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
self.inner.inner.get_mut().write_all(buf)
}
fn flush(&mut self) -> IoResult<()> {
self.inner.inner.get_mut().flush()
}
}
#[cfg(test)]
mod test {
extern crate test;
use old_io::{self, Reader, Writer, Buffer, BufferPrelude};
use prelude::v1::*;
use super::*;
use super::super::{IoResult, EndOfFile};
use super::super::mem::MemReader;
use self::test::Bencher;
/// A type, free to create, primarily intended for benchmarking creation of
/// wrappers that, just for construction, don't need a Reader/Writer that
/// does anything useful. Is equivalent to `/dev/null` in semantics.
#[derive(Clone,PartialEq,PartialOrd)]
pub struct NullStream;
impl Reader for NullStream {
fn read(&mut self, _: &mut [u8]) -> old_io::IoResult<usize> {
Err(old_io::standard_error(old_io::EndOfFile))
}
}
impl Writer for NullStream {
fn write_all(&mut self, _: &[u8]) -> old_io::IoResult<()> { Ok(()) }
}
/// A dummy reader intended at testing short-reads propagation.
pub struct ShortReader {
lengths: Vec<usize>,
}
impl Reader for ShortReader {
fn read(&mut self, _: &mut [u8]) -> old_io::IoResult<usize> {
if self.lengths.is_empty() {
Err(old_io::standard_error(old_io::EndOfFile))
} else {
Ok(self.lengths.remove(0))
}
}
}
#[test]
fn test_buffered_reader() {
let inner = MemReader::new(vec!(5, 6, 7, 0, 1, 2, 3, 4));
let mut reader = BufferedReader::with_capacity(2, inner);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(Ok(3), nread);
let b: &[_] = &[5, 6, 7];
assert_eq!(buf, b);
let mut buf = [0, 0];
let nread = reader.read(&mut buf);
assert_eq!(Ok(2), nread);
let b: &[_] = &[0, 1];
assert_eq!(buf, b);
let mut buf = [0];
let nread = reader.read(&mut buf);
assert_eq!(Ok(1), nread);
let b: &[_] = &[2];
assert_eq!(buf, b);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(Ok(1), nread);
let b: &[_] = &[3, 0, 0];
assert_eq!(buf, b);
let nread = reader.read(&mut buf);
assert_eq!(Ok(1), nread);
let b: &[_] = &[4, 0, 0];
assert_eq!(buf, b);
assert!(reader.read(&mut buf).is_err());
}
#[test]
fn test_buffered_writer() {
let inner = Vec::new();
let mut writer = BufferedWriter::with_capacity(2, inner);
writer.write_all(&[0, 1]).unwrap();
let b: &[_] = &[];
assert_eq!(&writer.get_ref()[..], b);
writer.write_all(&[2]).unwrap();
let b: &[_] = &[0, 1];
assert_eq!(&writer.get_ref()[..], b);
writer.write_all(&[3]).unwrap();
assert_eq!(&writer.get_ref()[..], b);
writer.flush().unwrap();
let a: &[_] = &[0, 1, 2, 3];
assert_eq!(a, &writer.get_ref()[..]);
writer.write_all(&[4]).unwrap();
writer.write_all(&[5]).unwrap();
assert_eq!(a, &writer.get_ref()[..]);
writer.write_all(&[6]).unwrap();
let a: &[_] = &[0, 1, 2, 3, 4, 5];
assert_eq!(a, &writer.get_ref()[..]);
writer.write_all(&[7, 8]).unwrap();
let a: &[_] = &[0, 1, 2, 3, 4, 5, 6];
assert_eq!(a, &writer.get_ref()[..]);
writer.write_all(&[9, 10, 11]).unwrap();
let a: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
assert_eq!(a, &writer.get_ref()[..]);
writer.flush().unwrap();
assert_eq!(a, &writer.get_ref()[..]);
}
#[test]
fn test_buffered_writer_inner_flushes() {
let mut w = BufferedWriter::with_capacity(3, Vec::new());
w.write_all(&[0, 1]).unwrap();
let a: &[_] = &[];
assert_eq!(&w.get_ref()[..], a);
let w = w.into_inner();
let a: &[_] = &[0, 1];
assert_eq!(a, &w[..]);
}
// This is just here to make sure that we don't infinite loop in the
// newtype struct autoderef weirdness
#[test]
fn test_buffered_stream() {
struct S;
impl old_io::Writer for S {
fn write_all(&mut self, _: &[u8]) -> old_io::IoResult<()> { Ok(()) }
}
impl old_io::Reader for S {
fn read(&mut self, _: &mut [u8]) -> old_io::IoResult<usize> {
Err(old_io::standard_error(old_io::EndOfFile))
}
}
let mut stream = BufferedStream::new(S);
let mut buf = [];
assert!(stream.read(&mut buf).is_err());
stream.write_all(&buf).unwrap();
stream.flush().unwrap();
}
#[test]
fn test_read_until() {
let inner = MemReader::new(vec!(0, 1, 2, 1, 0));
let mut reader = BufferedReader::with_capacity(2, inner);
assert_eq!(reader.read_until(0), Ok(vec!(0)));
assert_eq!(reader.read_until(2), Ok(vec!(1, 2)));
assert_eq!(reader.read_until(1), Ok(vec!(1)));
assert_eq!(reader.read_until(8), Ok(vec!(0)));
assert!(reader.read_until(9).is_err());
}
#[test]
fn test_line_buffer() {
let mut writer = LineBufferedWriter::new(Vec::new());
writer.write_all(&[0]).unwrap();
let b: &[_] = &[];
assert_eq!(&writer.get_ref()[..], b);
writer.write_all(&[1]).unwrap();
assert_eq!(&writer.get_ref()[..], b);
writer.flush().unwrap();
let b: &[_] = &[0, 1];
assert_eq!(&writer.get_ref()[..], b);
writer.write_all(&[0, b'\n', 1, b'\n', 2]).unwrap();
let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n'];
assert_eq!(&writer.get_ref()[..], b);
writer.flush().unwrap();
let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2];
assert_eq!(&writer.get_ref()[..], b);
writer.write_all(&[3, b'\n']).unwrap();
let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n'];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn test_read_line() {
let in_buf = MemReader::new(b"a\nb\nc".to_vec());
let mut reader = BufferedReader::with_capacity(2, in_buf);
assert_eq!(reader.read_line(), Ok("a\n".to_string()));
assert_eq!(reader.read_line(), Ok("b\n".to_string()));
assert_eq!(reader.read_line(), Ok("c".to_string()));
assert!(reader.read_line().is_err());
}
#[test]
fn test_lines() {
let in_buf = MemReader::new(b"a\nb\nc".to_vec());
let mut reader = BufferedReader::with_capacity(2, in_buf);
let mut it = reader.lines();
assert_eq!(it.next(), Some(Ok("a\n".to_string())));
assert_eq!(it.next(), Some(Ok("b\n".to_string())));
assert_eq!(it.next(), Some(Ok("c".to_string())));
assert_eq!(it.next(), None);
}
#[test]
fn test_short_reads() {
let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]};
let mut reader = BufferedReader::new(inner);
let mut buf = [0, 0];
assert_eq!(reader.read(&mut buf), Ok(0));
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.read(&mut buf), Ok(2));
assert_eq!(reader.read(&mut buf), Ok(0));
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.read(&mut buf), Ok(0));
assert!(reader.read(&mut buf).is_err());
}
#[test]
fn read_char_buffered() {
let buf = [195, 159];
let mut reader = BufferedReader::with_capacity(1, &buf[..]);
assert_eq!(reader.read_char(), Ok('ß'));
}
#[test]
fn test_chars() {
let buf = [195, 159, b'a'];
let mut reader = BufferedReader::with_capacity(1, &buf[..]);
let mut it = reader.chars();
assert_eq!(it.next(), Some(Ok('ß')));
assert_eq!(it.next(), Some(Ok('a')));
assert_eq!(it.next(), None);
}
#[test]
#[should_panic]
fn dont_panic_in_drop_on_panicked_flush() {
struct FailFlushWriter;
impl Writer for FailFlushWriter {
fn write_all(&mut self, _buf: &[u8]) -> IoResult<()> { Ok(()) }
fn flush(&mut self) -> IoResult<()> { Err(old_io::standard_error(EndOfFile)) }
}
let writer = FailFlushWriter;
let _writer = BufferedWriter::new(writer);
// If writer panics *again* due to the flush error then the process will abort.
panic!();
}
#[bench]
fn bench_buffered_reader(b: &mut Bencher) {
b.iter(|| {
BufferedReader::new(NullStream)
});
}
#[bench]
fn bench_buffered_writer(b: &mut Bencher) {
b.iter(|| {
BufferedWriter::new(NullStream)
});
}
#[bench]
fn bench_buffered_stream(b: &mut Bencher) {
b.iter(|| {
BufferedStream::new(NullStream);
});
}
}

View File

@ -1,247 +0,0 @@
// Copyright 2013 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 clone::Clone;
use cmp;
use sync::mpsc::{Sender, Receiver};
use old_io;
use option::Option::{None, Some};
use result::Result::{Ok, Err};
use slice::bytes;
use super::{Buffer, Reader, Writer, IoResult};
use vec::Vec;
/// Allows reading from a rx.
///
/// # Examples
///
/// ```
/// # #![feature(old_io)]
/// use std::sync::mpsc::channel;
/// use std::old_io::*;
///
/// let (tx, rx) = channel();
/// # drop(tx);
/// let mut reader = ChanReader::new(rx);
///
/// let mut buf = [0; 100];
/// match reader.read(&mut buf) {
/// Ok(nread) => println!("Read {} bytes", nread),
/// Err(e) => println!("read error: {}", e),
/// }
/// ```
pub struct ChanReader {
buf: Vec<u8>, // A buffer of bytes received but not consumed.
pos: usize, // How many of the buffered bytes have already be consumed.
rx: Receiver<Vec<u8>>, // The Receiver to pull data from.
closed: bool, // Whether the channel this Receiver connects to has been closed.
}
impl ChanReader {
/// Wraps a `Port` in a `ChanReader` structure
pub fn new(rx: Receiver<Vec<u8>>) -> ChanReader {
ChanReader {
buf: Vec::new(),
pos: 0,
rx: rx,
closed: false,
}
}
}
impl Buffer for ChanReader {
fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
if self.pos >= self.buf.len() {
self.pos = 0;
match self.rx.recv() {
Ok(bytes) => {
self.buf = bytes;
},
Err(..) => {
self.closed = true;
self.buf = Vec::new();
}
}
}
if self.closed {
Err(old_io::standard_error(old_io::EndOfFile))
} else {
Ok(&self.buf[self.pos..])
}
}
fn consume(&mut self, amt: usize) {
self.pos += amt;
assert!(self.pos <= self.buf.len());
}
}
impl Reader for ChanReader {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
let mut num_read = 0;
loop {
let count = match self.fill_buf().ok() {
Some(src) => {
let dst = &mut buf[num_read..];
let count = cmp::min(src.len(), dst.len());
bytes::copy_memory(&src[..count], dst);
count
},
None => 0,
};
self.consume(count);
num_read += count;
if num_read == buf.len() || self.closed {
break;
}
}
if self.closed && num_read == 0 {
Err(old_io::standard_error(old_io::EndOfFile))
} else {
Ok(num_read)
}
}
}
/// Allows writing to a tx.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, io)]
/// # #![allow(unused_must_use)]
/// use std::sync::mpsc::channel;
/// use std::old_io::*;
///
/// let (tx, rx) = channel();
/// # drop(rx);
/// let mut writer = ChanWriter::new(tx);
/// writer.write("hello, world".as_bytes());
/// ```
pub struct ChanWriter {
tx: Sender<Vec<u8>>,
}
impl ChanWriter {
/// Wraps a channel in a `ChanWriter` structure
pub fn new(tx: Sender<Vec<u8>>) -> ChanWriter {
ChanWriter { tx: tx }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for ChanWriter {
fn clone(&self) -> ChanWriter {
ChanWriter { tx: self.tx.clone() }
}
}
impl Writer for ChanWriter {
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
self.tx.send(buf.to_vec()).map_err(|_| {
old_io::IoError {
kind: old_io::BrokenPipe,
desc: "Pipe closed",
detail: None
}
})
}
}
#[cfg(test)]
mod test {
use prelude::v1::*;
use sync::mpsc::channel;
use super::*;
use old_io::{self, Reader, Writer, Buffer};
use thread;
#[test]
fn test_rx_reader() {
let (tx, rx) = channel();
thread::spawn(move|| {
tx.send(vec![1, 2]).unwrap();
tx.send(vec![]).unwrap();
tx.send(vec![3, 4]).unwrap();
tx.send(vec![5, 6]).unwrap();
tx.send(vec![7, 8]).unwrap();
});
let mut reader = ChanReader::new(rx);
let mut buf = [0; 3];
assert_eq!(Ok(0), reader.read(&mut []));
assert_eq!(Ok(3), reader.read(&mut buf));
let a: &[u8] = &[1,2,3];
assert_eq!(a, buf);
assert_eq!(Ok(3), reader.read(&mut buf));
let a: &[u8] = &[4,5,6];
assert_eq!(a, buf);
assert_eq!(Ok(2), reader.read(&mut buf));
let a: &[u8] = &[7,8,6];
assert_eq!(a, buf);
match reader.read(&mut buf) {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind, old_io::EndOfFile),
}
assert_eq!(a, buf);
// Ensure it continues to panic in the same way.
match reader.read(&mut buf) {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind, old_io::EndOfFile),
}
assert_eq!(a, buf);
}
#[test]
fn test_rx_buffer() {
let (tx, rx) = channel();
thread::spawn(move|| {
tx.send(b"he".to_vec()).unwrap();
tx.send(b"llo wo".to_vec()).unwrap();
tx.send(b"".to_vec()).unwrap();
tx.send(b"rld\nhow ".to_vec()).unwrap();
tx.send(b"are you?".to_vec()).unwrap();
tx.send(b"".to_vec()).unwrap();
});
let mut reader = ChanReader::new(rx);
assert_eq!(Ok("hello world\n".to_string()), reader.read_line());
assert_eq!(Ok("how are you?".to_string()), reader.read_line());
match reader.read_line() {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind, old_io::EndOfFile),
}
}
#[test]
fn test_chan_writer() {
let (tx, rx) = channel();
let mut writer = ChanWriter::new(tx);
writer.write_be_u32(42).unwrap();
let wanted = vec![0, 0, 0, 42];
let got = thread::scoped(move|| { rx.recv().unwrap() }).join();
assert_eq!(wanted, got);
match writer.write_u8(1) {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind, old_io::BrokenPipe),
}
}
}

View File

@ -1,564 +0,0 @@
// Copyright 2013-2014 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.
//! Utility mixins that apply to all Readers and Writers
#![allow(missing_docs)]
#![unstable(feature = "old_io")]
#![deprecated(since = "1.0.0",
reason = "functionality will be removed with no immediate \
replacement")]
// FIXME: Not sure how this should be structured
// FIXME: Iteration should probably be considered separately
use old_io::{IoError, IoResult, Reader};
use old_io;
use iter::Iterator;
use num::Int;
use ops::FnOnce;
use option::Option;
use option::Option::{Some, None};
use result::Result::{Ok, Err};
/// An iterator that reads a single byte on each iteration,
/// until `.read_byte()` returns `EndOfFile`.
///
/// # Notes about the Iteration Protocol
///
/// The `Bytes` may yield `None` and thus terminate
/// an iteration, but continue to yield elements if iteration
/// is attempted again.
///
/// # Error
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
pub struct Bytes<'r, T:'r> {
reader: &'r mut T,
}
impl<'r, R: Reader> Bytes<'r, R> {
/// Constructs a new byte iterator from the given Reader instance.
pub fn new(r: &'r mut R) -> Bytes<'r, R> {
Bytes {
reader: r,
}
}
}
impl<'r, R: Reader> Iterator for Bytes<'r, R> {
type Item = IoResult<u8>;
#[inline]
fn next(&mut self) -> Option<IoResult<u8>> {
match self.reader.read_byte() {
Ok(x) => Some(Ok(x)),
Err(IoError { kind: old_io::EndOfFile, .. }) => None,
Err(e) => Some(Err(e))
}
}
}
/// Converts an 8-bit to 64-bit unsigned value to a little-endian byte
/// representation of the given size. If the size is not big enough to
/// represent the value, then the high-order bytes are truncated.
///
/// Arguments:
///
/// * `n`: The value to convert.
/// * `size`: The size of the value, in bytes. This must be 8 or less, or task
/// panic occurs. If this is less than 8, then a value of that
/// many bytes is produced. For example, if `size` is 4, then a
/// 32-bit byte representation is produced.
/// * `f`: A callback that receives the value.
///
/// This function returns the value returned by the callback, for convenience.
pub fn u64_to_le_bytes<T, F>(n: u64, size: usize, f: F) -> T where
F: FnOnce(&[u8]) -> T,
{
use mem::transmute;
// LLVM fails to properly optimize this when using shifts instead of the to_le* intrinsics
assert!(size <= 8);
match size {
1 => f(&[n as u8]),
2 => f(unsafe { & transmute::<_, [u8; 2]>((n as u16).to_le()) }),
4 => f(unsafe { & transmute::<_, [u8; 4]>((n as u32).to_le()) }),
8 => f(unsafe { & transmute::<_, [u8; 8]>(n.to_le()) }),
_ => {
let mut bytes = vec!();
let mut i = size;
let mut n = n;
while i > 0 {
bytes.push((n & 255) as u8);
n >>= 8;
i -= 1;
}
f(&bytes)
}
}
}
/// Converts an 8-bit to 64-bit unsigned value to a big-endian byte
/// representation of the given size. If the size is not big enough to
/// represent the value, then the high-order bytes are truncated.
///
/// Arguments:
///
/// * `n`: The value to convert.
/// * `size`: The size of the value, in bytes. This must be 8 or less, or task
/// panic occurs. If this is less than 8, then a value of that
/// many bytes is produced. For example, if `size` is 4, then a
/// 32-bit byte representation is produced.
/// * `f`: A callback that receives the value.
///
/// This function returns the value returned by the callback, for convenience.
pub fn u64_to_be_bytes<T, F>(n: u64, size: usize, f: F) -> T where
F: FnOnce(&[u8]) -> T,
{
use mem::transmute;
// LLVM fails to properly optimize this when using shifts instead of the to_be* intrinsics
assert!(size <= 8);
match size {
1 => f(&[n as u8]),
2 => f(unsafe { & transmute::<_, [u8; 2]>((n as u16).to_be()) }),
4 => f(unsafe { & transmute::<_, [u8; 4]>((n as u32).to_be()) }),
8 => f(unsafe { & transmute::<_, [u8; 8]>(n.to_be()) }),
_ => {
let mut bytes = vec!();
let mut i = size;
while i > 0 {
let shift = (i - 1) * 8;
bytes.push((n >> shift) as u8);
i -= 1;
}
f(&bytes)
}
}
}
/// Extracts an 8-bit to 64-bit unsigned big-endian value from the given byte
/// buffer and returns it as a 64-bit value.
///
/// Arguments:
///
/// * `data`: The buffer in which to extract the value.
/// * `start`: The offset at which to extract the value.
/// * `size`: The size of the value in bytes to extract. This must be 8 or
/// less, or task panic occurs. If this is less than 8, then only
/// that many bytes are parsed. For example, if `size` is 4, then a
/// 32-bit value is parsed.
pub fn u64_from_be_bytes(data: &[u8], start: usize, size: usize) -> u64 {
use ptr::{copy_nonoverlapping};
assert!(size <= 8);
if data.len() - start < size {
panic!("index out of bounds");
}
let mut buf = [0; 8];
unsafe {
let ptr = data.as_ptr().offset(start as isize);
let out = buf.as_mut_ptr();
copy_nonoverlapping(ptr, out.offset((8 - size) as isize), size);
(*(out as *const u64)).to_be()
}
}
#[cfg(test)]
mod test {
use prelude::v1::*;
use old_io::{self, Reader, Writer};
use old_io::{MemReader, BytesReader};
struct InitialZeroByteReader {
count: isize,
}
impl Reader for InitialZeroByteReader {
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
if self.count == 0 {
self.count = 1;
Ok(0)
} else {
buf[0] = 10;
Ok(1)
}
}
}
struct EofReader;
impl Reader for EofReader {
fn read(&mut self, _: &mut [u8]) -> old_io::IoResult<usize> {
Err(old_io::standard_error(old_io::EndOfFile))
}
}
struct ErroringReader;
impl Reader for ErroringReader {
fn read(&mut self, _: &mut [u8]) -> old_io::IoResult<usize> {
Err(old_io::standard_error(old_io::InvalidInput))
}
}
struct PartialReader {
count: isize,
}
impl Reader for PartialReader {
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
if self.count == 0 {
self.count = 1;
buf[0] = 10;
buf[1] = 11;
Ok(2)
} else {
buf[0] = 12;
buf[1] = 13;
Ok(2)
}
}
}
struct ErroringLaterReader {
count: isize,
}
impl Reader for ErroringLaterReader {
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
if self.count == 0 {
self.count = 1;
buf[0] = 10;
Ok(1)
} else {
Err(old_io::standard_error(old_io::InvalidInput))
}
}
}
struct ThreeChunkReader {
count: isize,
}
impl Reader for ThreeChunkReader {
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
if self.count == 0 {
self.count = 1;
buf[0] = 10;
buf[1] = 11;
Ok(2)
} else if self.count == 1 {
self.count = 2;
buf[0] = 12;
buf[1] = 13;
Ok(2)
} else {
Err(old_io::standard_error(old_io::EndOfFile))
}
}
}
#[test]
fn read_byte() {
let mut reader = MemReader::new(vec!(10));
let byte = reader.read_byte();
assert!(byte == Ok(10));
}
#[test]
fn read_byte_0_bytes() {
let mut reader = InitialZeroByteReader {
count: 0,
};
let byte = reader.read_byte();
assert!(byte == Ok(10));
}
#[test]
fn read_byte_eof() {
let mut reader = EofReader;
let byte = reader.read_byte();
assert!(byte.is_err());
}
#[test]
fn read_byte_error() {
let mut reader = ErroringReader;
let byte = reader.read_byte();
assert!(byte.is_err());
}
#[test]
fn bytes_0_bytes() {
let mut reader = InitialZeroByteReader {
count: 0,
};
let byte = reader.bytes().next();
assert!(byte == Some(Ok(10)));
}
#[test]
fn bytes_eof() {
let mut reader = EofReader;
let byte = reader.bytes().next();
assert!(byte.is_none());
}
#[test]
fn bytes_error() {
let mut reader = ErroringReader;
let mut it = reader.bytes();
let byte = it.next();
assert!(byte.unwrap().is_err());
}
#[test]
fn read_bytes() {
let mut reader = MemReader::new(vec!(10, 11, 12, 13));
let bytes = reader.read_exact(4).unwrap();
assert_eq!(bytes, [10, 11, 12, 13]);
}
#[test]
fn read_bytes_partial() {
let mut reader = PartialReader {
count: 0,
};
let bytes = reader.read_exact(4).unwrap();
assert_eq!(bytes, [10, 11, 12, 13]);
}
#[test]
fn read_bytes_eof() {
let mut reader = MemReader::new(vec!(10, 11));
assert!(reader.read_exact(4).is_err());
}
#[test]
fn push_at_least() {
let mut reader = MemReader::new(vec![10, 11, 12, 13]);
let mut buf = vec![8, 9];
assert!(reader.push_at_least(4, 4, &mut buf).is_ok());
assert_eq!(buf, [8, 9, 10, 11, 12, 13]);
}
#[test]
fn push_at_least_partial() {
let mut reader = PartialReader {
count: 0,
};
let mut buf = vec![8, 9];
assert!(reader.push_at_least(4, 4, &mut buf).is_ok());
assert_eq!(buf, [8, 9, 10, 11, 12, 13]);
}
#[test]
fn push_at_least_eof() {
let mut reader = MemReader::new(vec![10, 11]);
let mut buf = vec![8, 9];
assert!(reader.push_at_least(4, 4, &mut buf).is_err());
assert_eq!(buf, [8, 9, 10, 11]);
}
#[test]
fn push_at_least_error() {
let mut reader = ErroringLaterReader {
count: 0,
};
let mut buf = vec![8, 9];
assert!(reader.push_at_least(4, 4, &mut buf).is_err());
assert_eq!(buf, [8, 9, 10]);
}
#[test]
fn read_to_end() {
let mut reader = ThreeChunkReader {
count: 0,
};
let buf = reader.read_to_end().unwrap();
assert_eq!(buf, [10, 11, 12, 13]);
}
#[test]
#[should_panic]
fn read_to_end_error() {
let mut reader = ThreeChunkReader {
count: 0,
};
let buf = reader.read_to_end().unwrap();
assert_eq!(buf, [10, 11]);
}
#[test]
fn test_read_write_le_mem() {
let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::MAX];
let mut writer = Vec::new();
for i in &uints {
writer.write_le_u64(*i).unwrap();
}
let mut reader = MemReader::new(writer);
for i in &uints {
assert!(reader.read_le_u64().unwrap() == *i);
}
}
#[test]
fn test_read_write_be() {
let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::MAX];
let mut writer = Vec::new();
for i in &uints {
writer.write_be_u64(*i).unwrap();
}
let mut reader = MemReader::new(writer);
for i in &uints {
assert!(reader.read_be_u64().unwrap() == *i);
}
}
#[test]
fn test_read_be_int_n() {
let ints = [::i32::MIN, -123456, -42, -5, 0, 1, ::i32::MAX];
let mut writer = Vec::new();
for i in &ints {
writer.write_be_i32(*i).unwrap();
}
let mut reader = MemReader::new(writer);
for i in &ints {
// this tests that the sign extension is working
// (comparing the values as i32 would not test this)
assert!(reader.read_be_int_n(4).unwrap() == *i as i64);
}
}
#[test]
fn test_read_f32() {
//big-endian floating-point 8.1250
let buf = vec![0x41, 0x02, 0x00, 0x00];
let mut writer = Vec::new();
writer.write(&buf).unwrap();
let mut reader = MemReader::new(writer);
let f = reader.read_be_f32().unwrap();
assert!(f == 8.1250);
}
#[test]
fn test_read_write_f32() {
let f:f32 = 8.1250;
let mut writer = Vec::new();
writer.write_be_f32(f).unwrap();
writer.write_le_f32(f).unwrap();
let mut reader = MemReader::new(writer);
assert!(reader.read_be_f32().unwrap() == 8.1250);
assert!(reader.read_le_f32().unwrap() == 8.1250);
}
#[test]
fn test_u64_from_be_bytes() {
use super::u64_from_be_bytes;
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09];
// Aligned access
assert_eq!(u64_from_be_bytes(&buf, 0, 0), 0);
assert_eq!(u64_from_be_bytes(&buf, 0, 1), 0x01);
assert_eq!(u64_from_be_bytes(&buf, 0, 2), 0x0102);
assert_eq!(u64_from_be_bytes(&buf, 0, 3), 0x010203);
assert_eq!(u64_from_be_bytes(&buf, 0, 4), 0x01020304);
assert_eq!(u64_from_be_bytes(&buf, 0, 5), 0x0102030405);
assert_eq!(u64_from_be_bytes(&buf, 0, 6), 0x010203040506);
assert_eq!(u64_from_be_bytes(&buf, 0, 7), 0x01020304050607);
assert_eq!(u64_from_be_bytes(&buf, 0, 8), 0x0102030405060708);
// Unaligned access
assert_eq!(u64_from_be_bytes(&buf, 1, 0), 0);
assert_eq!(u64_from_be_bytes(&buf, 1, 1), 0x02);
assert_eq!(u64_from_be_bytes(&buf, 1, 2), 0x0203);
assert_eq!(u64_from_be_bytes(&buf, 1, 3), 0x020304);
assert_eq!(u64_from_be_bytes(&buf, 1, 4), 0x02030405);
assert_eq!(u64_from_be_bytes(&buf, 1, 5), 0x0203040506);
assert_eq!(u64_from_be_bytes(&buf, 1, 6), 0x020304050607);
assert_eq!(u64_from_be_bytes(&buf, 1, 7), 0x02030405060708);
assert_eq!(u64_from_be_bytes(&buf, 1, 8), 0x0203040506070809);
}
}
#[cfg(test)]
mod bench {
extern crate test;
use prelude::v1::*;
use self::test::Bencher;
// why is this a macro? wouldn't an inlined function work just as well?
macro_rules! u64_from_be_bytes_bench_impl {
($b:expr, $size:expr, $stride:expr, $start_index:expr) =>
({
use super::u64_from_be_bytes;
let len = ($stride as u8).wrapping_mul(100).wrapping_add($start_index);
let data = (0..len).collect::<Vec<_>>();
let mut sum = 0;
$b.iter(|| {
let mut i = $start_index;
while i < data.len() {
sum += u64_from_be_bytes(&data, i, $size);
i += $stride;
}
});
})
}
#[bench]
fn u64_from_be_bytes_4_aligned(b: &mut Bencher) {
u64_from_be_bytes_bench_impl!(b, 4, 4, 0);
}
#[bench]
fn u64_from_be_bytes_4_unaligned(b: &mut Bencher) {
u64_from_be_bytes_bench_impl!(b, 4, 4, 1);
}
#[bench]
fn u64_from_be_bytes_7_aligned(b: &mut Bencher) {
u64_from_be_bytes_bench_impl!(b, 7, 8, 0);
}
#[bench]
fn u64_from_be_bytes_7_unaligned(b: &mut Bencher) {
u64_from_be_bytes_bench_impl!(b, 7, 8, 1);
}
#[bench]
fn u64_from_be_bytes_8_aligned(b: &mut Bencher) {
u64_from_be_bytes_bench_impl!(b, 8, 8, 0);
}
#[bench]
fn u64_from_be_bytes_8_unaligned(b: &mut Bencher) {
u64_from_be_bytes_bench_impl!(b, 8, 8, 1);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,765 +0,0 @@
// Copyright 2013 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.
//
// ignore-lexer-test FIXME #15679
//! Readers and Writers for in-memory buffers
use cmp::min;
use option::Option::None;
use result::Result::{Err, Ok};
use old_io;
use old_io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult};
use slice;
use vec::Vec;
const BUF_CAPACITY: usize = 128;
fn combine(seek: SeekStyle, cur: usize, end: usize, offset: i64) -> IoResult<u64> {
// compute offset as signed and clamp to prevent overflow
let pos = match seek {
old_io::SeekSet => 0,
old_io::SeekEnd => end,
old_io::SeekCur => cur,
} as i64;
if offset + pos < 0 {
Err(IoError {
kind: old_io::InvalidInput,
desc: "invalid seek to a negative offset",
detail: None
})
} else {
Ok((offset + pos) as u64)
}
}
impl Writer for Vec<u8> {
#[inline]
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
self.push_all(buf);
Ok(())
}
}
/// Writes to an owned, growable byte vector
///
/// # Examples
///
/// ```
/// # #![feature(old_io, io)]
/// # #![allow(unused_must_use)]
/// use std::old_io::*;
///
/// let mut w = MemWriter::new();
/// w.write(&[0, 1, 2]);
///
/// assert_eq!(w.into_inner(), [0, 1, 2]);
/// ```
#[unstable(feature = "io")]
#[deprecated(since = "1.0.0",
reason = "use the Vec<u8> Writer implementation directly")]
#[derive(Clone)]
#[allow(deprecated)]
pub struct MemWriter {
buf: Vec<u8>,
}
#[allow(deprecated)]
impl MemWriter {
/// Create a new `MemWriter`.
#[inline]
pub fn new() -> MemWriter {
MemWriter::with_capacity(BUF_CAPACITY)
}
/// Create a new `MemWriter`, allocating at least `n` bytes for
/// the internal buffer.
#[inline]
pub fn with_capacity(n: usize) -> MemWriter {
MemWriter::from_vec(Vec::with_capacity(n))
}
/// Create a new `MemWriter` that will append to an existing `Vec`.
#[inline]
pub fn from_vec(buf: Vec<u8>) -> MemWriter {
MemWriter { buf: buf }
}
/// Acquires an immutable reference to the underlying buffer of this
/// `MemWriter`.
#[inline]
pub fn get_ref<'a>(&'a self) -> &'a [u8] { &self.buf }
/// Unwraps this `MemWriter`, returning the underlying buffer
#[inline]
pub fn into_inner(self) -> Vec<u8> { self.buf }
}
impl Writer for MemWriter {
#[inline]
#[allow(deprecated)]
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
self.buf.push_all(buf);
Ok(())
}
}
/// Reads from an owned byte vector
///
/// # Examples
///
/// ```
/// # #![feature(old_io)]
/// # #![allow(unused_must_use)]
/// use std::old_io::*;
///
/// let mut r = MemReader::new(vec!(0, 1, 2));
///
/// assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]);
/// ```
pub struct MemReader {
buf: Vec<u8>,
pos: usize
}
impl MemReader {
/// Creates a new `MemReader` which will read the buffer given. The buffer
/// can be re-acquired through `unwrap`
#[inline]
pub fn new(buf: Vec<u8>) -> MemReader {
MemReader {
buf: buf,
pos: 0
}
}
/// Tests whether this reader has read all bytes in its buffer.
///
/// If `true`, then this will no longer return bytes from `read`.
#[inline]
pub fn eof(&self) -> bool { self.pos >= self.buf.len() }
/// Acquires an immutable reference to the underlying buffer of this
/// `MemReader`.
///
/// No method is exposed for acquiring a mutable reference to the buffer
/// because it could corrupt the state of this `MemReader`.
#[inline]
pub fn get_ref<'a>(&'a self) -> &'a [u8] { &self.buf }
/// Unwraps this `MemReader`, returning the underlying buffer
#[inline]
pub fn into_inner(self) -> Vec<u8> { self.buf }
}
impl Reader for MemReader {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
if self.eof() { return Err(old_io::standard_error(old_io::EndOfFile)) }
let write_len = min(buf.len(), self.buf.len() - self.pos);
{
let input = &self.buf[self.pos.. self.pos + write_len];
let output = &mut buf[..write_len];
assert_eq!(input.len(), output.len());
slice::bytes::copy_memory(input, output);
}
self.pos += write_len;
assert!(self.pos <= self.buf.len());
return Ok(write_len);
}
}
impl Seek for MemReader {
#[inline]
fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
#[inline]
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
let new = try!(combine(style, self.pos, self.buf.len(), pos));
self.pos = new as usize;
Ok(())
}
}
impl Buffer for MemReader {
#[inline]
fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
if self.pos < self.buf.len() {
Ok(&self.buf[self.pos..])
} else {
Err(old_io::standard_error(old_io::EndOfFile))
}
}
#[inline]
fn consume(&mut self, amt: usize) { self.pos += amt; }
}
impl<'a> Reader for &'a [u8] {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
if self.is_empty() { return Err(old_io::standard_error(old_io::EndOfFile)); }
let write_len = min(buf.len(), self.len());
{
let input = &self[..write_len];
let output = &mut buf[.. write_len];
slice::bytes::copy_memory(input, output);
}
*self = &self[write_len..];
Ok(write_len)
}
}
impl<'a> Buffer for &'a [u8] {
#[inline]
fn fill_buf(&mut self) -> IoResult<&[u8]> {
if self.is_empty() {
Err(old_io::standard_error(old_io::EndOfFile))
} else {
Ok(*self)
}
}
#[inline]
fn consume(&mut self, amt: usize) {
*self = &self[amt..];
}
}
/// Writes to a fixed-size byte slice
///
/// If a write will not fit in the buffer, it returns an error and does not
/// write any data.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, io)]
/// # #![allow(unused_must_use)]
/// use std::old_io::*;
///
/// let mut buf = [0; 4];
/// {
/// let mut w = BufWriter::new(&mut buf);
/// w.write(&[0, 1, 2]);
/// }
/// assert!(buf == [0, 1, 2, 0]);
/// ```
pub struct BufWriter<'a> {
buf: &'a mut [u8],
pos: usize
}
impl<'a> BufWriter<'a> {
/// Creates a new `BufWriter` which will wrap the specified buffer. The
/// writer initially starts at position 0.
#[inline]
pub fn new(buf: &'a mut [u8]) -> BufWriter<'a> {
BufWriter {
buf: buf,
pos: 0
}
}
}
impl<'a> Writer for BufWriter<'a> {
#[inline]
fn write_all(&mut self, src: &[u8]) -> IoResult<()> {
let dst = &mut self.buf[self.pos..];
let dst_len = dst.len();
if dst_len == 0 {
return Err(old_io::standard_error(old_io::EndOfFile));
}
let src_len = src.len();
if dst_len >= src_len {
slice::bytes::copy_memory(src, dst);
self.pos += src_len;
Ok(())
} else {
slice::bytes::copy_memory(&src[..dst_len], dst);
self.pos += dst_len;
Err(old_io::standard_error(old_io::ShortWrite(dst_len)))
}
}
}
impl<'a> Seek for BufWriter<'a> {
#[inline]
fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
#[inline]
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
let new = try!(combine(style, self.pos, self.buf.len(), pos));
self.pos = min(new as usize, self.buf.len());
Ok(())
}
}
/// Reads from a fixed-size byte slice
///
/// # Examples
///
/// ```
/// # #![feature(old_io)]
/// # #![allow(unused_must_use)]
/// use std::old_io::*;
///
/// let buf = [0, 1, 2, 3];
/// let mut r = BufReader::new(&buf);
///
/// assert_eq!(r.read_to_end().unwrap(), [0, 1, 2, 3]);
/// ```
pub struct BufReader<'a> {
buf: &'a [u8],
pos: usize
}
impl<'a> BufReader<'a> {
/// Creates a new buffered reader which will read the specified buffer
#[inline]
pub fn new(buf: &'a [u8]) -> BufReader<'a> {
BufReader {
buf: buf,
pos: 0
}
}
/// Tests whether this reader has read all bytes in its buffer.
///
/// If `true`, then this will no longer return bytes from `read`.
#[inline]
pub fn eof(&self) -> bool { self.pos >= self.buf.len() }
}
impl<'a> Reader for BufReader<'a> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
if self.eof() { return Err(old_io::standard_error(old_io::EndOfFile)) }
let write_len = min(buf.len(), self.buf.len() - self.pos);
{
let input = &self.buf[self.pos.. self.pos + write_len];
let output = &mut buf[..write_len];
assert_eq!(input.len(), output.len());
slice::bytes::copy_memory(input, output);
}
self.pos += write_len;
assert!(self.pos <= self.buf.len());
return Ok(write_len);
}
}
impl<'a> Seek for BufReader<'a> {
#[inline]
fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
#[inline]
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
let new = try!(combine(style, self.pos, self.buf.len(), pos));
self.pos = new as usize;
Ok(())
}
}
impl<'a> Buffer for BufReader<'a> {
#[inline]
fn fill_buf(&mut self) -> IoResult<&[u8]> {
if self.pos < self.buf.len() {
Ok(&self.buf[self.pos..])
} else {
Err(old_io::standard_error(old_io::EndOfFile))
}
}
#[inline]
fn consume(&mut self, amt: usize) { self.pos += amt; }
}
#[cfg(test)]
mod test {
extern crate test as test_crate;
use old_io::{SeekSet, SeekCur, SeekEnd, Reader, Writer, Seek, Buffer};
use prelude::v1::{Ok, Err, Vec};
use prelude::v1::Iterator;
use old_io;
use iter::repeat;
use self::test_crate::Bencher;
use super::*;
#[test]
fn test_vec_writer() {
let mut writer = Vec::new();
writer.write(&[0]).unwrap();
writer.write(&[1, 2, 3]).unwrap();
writer.write(&[4, 5, 6, 7]).unwrap();
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(writer, b);
}
#[test]
fn test_mem_writer() {
let mut writer = MemWriter::new();
writer.write(&[0]).unwrap();
writer.write(&[1, 2, 3]).unwrap();
writer.write(&[4, 5, 6, 7]).unwrap();
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(writer.get_ref(), b);
}
#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
{
let mut writer = BufWriter::new(&mut buf);
assert_eq!(writer.tell(), Ok(0));
writer.write(&[0]).unwrap();
assert_eq!(writer.tell(), Ok(1));
writer.write(&[1, 2, 3]).unwrap();
writer.write(&[4, 5, 6, 7]).unwrap();
assert_eq!(writer.tell(), Ok(8));
writer.write(&[]).unwrap();
assert_eq!(writer.tell(), Ok(8));
assert_eq!(writer.write(&[8, 9]).err().unwrap().kind, old_io::ShortWrite(1));
assert_eq!(writer.write(&[10]).err().unwrap().kind, old_io::EndOfFile);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_seek() {
let mut buf = [0 as u8; 8];
{
let mut writer = BufWriter::new(&mut buf);
assert_eq!(writer.tell(), Ok(0));
writer.write(&[1]).unwrap();
assert_eq!(writer.tell(), Ok(1));
writer.seek(2, SeekSet).unwrap();
assert_eq!(writer.tell(), Ok(2));
writer.write(&[2]).unwrap();
assert_eq!(writer.tell(), Ok(3));
writer.seek(-2, SeekCur).unwrap();
assert_eq!(writer.tell(), Ok(1));
writer.write(&[3]).unwrap();
assert_eq!(writer.tell(), Ok(2));
writer.seek(-1, SeekEnd).unwrap();
assert_eq!(writer.tell(), Ok(7));
writer.write(&[4]).unwrap();
assert_eq!(writer.tell(), Ok(8));
}
let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_error() {
let mut buf = [0 as u8; 2];
let mut writer = BufWriter::new(&mut buf);
writer.write(&[0]).unwrap();
match writer.write(&[0, 0]) {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind, old_io::ShortWrite(1)),
}
}
#[test]
fn test_mem_reader() {
let mut reader = MemReader::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
let mut buf = [];
assert_eq!(reader.read(&mut buf), Ok(0));
assert_eq!(reader.tell(), Ok(0));
let mut buf = [0];
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.tell(), Ok(1));
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf), Ok(4));
assert_eq!(reader.tell(), Ok(5));
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf), Ok(3));
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert!(reader.read(&mut buf).is_err());
let mut reader = MemReader::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
assert_eq!(reader.read_until(3).unwrap(), [0, 1, 2, 3]);
assert_eq!(reader.read_until(3).unwrap(), [4, 5, 6, 7]);
assert!(reader.read(&mut buf).is_err());
}
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = &mut &*in_buf;
let mut buf = [];
assert_eq!(reader.read(&mut buf), Ok(0));
let mut buf = [0];
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf), Ok(4));
assert_eq!(reader.len(), 3);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf), Ok(3));
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert!(reader.read(&mut buf).is_err());
let mut reader = &mut &*in_buf;
assert_eq!(reader.read_until(3).unwrap(), [0, 1, 2, 3]);
assert_eq!(reader.read_until(3).unwrap(), [4, 5, 6, 7]);
assert!(reader.read(&mut buf).is_err());
}
#[test]
fn test_buf_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = BufReader::new(&in_buf);
let mut buf = [];
assert_eq!(reader.read(&mut buf), Ok(0));
assert_eq!(reader.tell(), Ok(0));
let mut buf = [0];
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.tell(), Ok(1));
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf), Ok(4));
assert_eq!(reader.tell(), Ok(5));
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf), Ok(3));
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert!(reader.read(&mut buf).is_err());
let mut reader = BufReader::new(&in_buf);
assert_eq!(reader.read_until(3).unwrap(), [0, 1, 2, 3]);
assert_eq!(reader.read_until(3).unwrap(), [4, 5, 6, 7]);
assert!(reader.read(&mut buf).is_err());
}
#[test]
fn test_read_char() {
let b = b"Vi\xE1\xBB\x87t";
let mut r = BufReader::new(b);
assert_eq!(r.read_char(), Ok('V'));
assert_eq!(r.read_char(), Ok('i'));
assert_eq!(r.read_char(), Ok('ệ'));
assert_eq!(r.read_char(), Ok('t'));
assert!(r.read_char().is_err());
}
#[test]
fn test_read_bad_char() {
let b = b"\x80";
let mut r = BufReader::new(b);
assert!(r.read_char().is_err());
}
#[test]
fn test_write_strings() {
let mut writer = MemWriter::new();
writer.write_str("testing").unwrap();
writer.write_line("testing").unwrap();
writer.write_str("testing").unwrap();
let mut r = BufReader::new(writer.get_ref());
assert_eq!(r.read_to_string().unwrap(), "testingtesting\ntesting");
}
#[test]
fn test_write_char() {
let mut writer = MemWriter::new();
writer.write_char('a').unwrap();
writer.write_char('\n').unwrap();
writer.write_char('ệ').unwrap();
let mut r = BufReader::new(writer.get_ref());
assert_eq!(r.read_to_string().unwrap(), "a\n");
}
#[test]
fn test_read_whole_string_bad() {
let buf = [0xff];
let mut r = BufReader::new(&buf);
match r.read_to_string() {
Ok(..) => panic!(),
Err(..) => {}
}
}
#[test]
fn seek_past_end() {
let buf = [0xff];
let mut r = BufReader::new(&buf);
r.seek(10, SeekSet).unwrap();
assert!(r.read(&mut []).is_err());
let mut r = MemReader::new(vec!(10));
r.seek(10, SeekSet).unwrap();
assert!(r.read(&mut []).is_err());
let mut buf = [0];
let mut r = BufWriter::new(&mut buf);
r.seek(10, SeekSet).unwrap();
assert!(r.write(&[3]).is_err());
}
#[test]
fn seek_before_0() {
let buf = [0xff];
let mut r = BufReader::new(&buf);
assert!(r.seek(-1, SeekSet).is_err());
let mut r = MemReader::new(vec!(10));
assert!(r.seek(-1, SeekSet).is_err());
let mut buf = [0];
let mut r = BufWriter::new(&mut buf);
assert!(r.seek(-1, SeekSet).is_err());
}
#[test]
fn io_read_at_least() {
let mut r = MemReader::new(vec![1, 2, 3, 4, 5, 6, 7, 8]);
let mut buf = [0; 3];
assert!(r.read_at_least(buf.len(), &mut buf).is_ok());
let b: &[_] = &[1, 2, 3];
assert_eq!(buf, b);
assert!(r.read_at_least(0, &mut buf[..0]).is_ok());
assert_eq!(buf, b);
assert!(r.read_at_least(buf.len(), &mut buf).is_ok());
let b: &[_] = &[4, 5, 6];
assert_eq!(buf, b);
assert!(r.read_at_least(buf.len(), &mut buf).is_err());
let b: &[_] = &[7, 8, 6];
assert_eq!(buf, b);
}
fn do_bench_mem_writer(b: &mut Bencher, times: usize, len: usize) {
let src: Vec<u8> = repeat(5).take(len).collect();
b.bytes = (times * len) as u64;
b.iter(|| {
let mut wr = MemWriter::new();
for _ in 0..times {
wr.write(&src).unwrap();
}
let v = wr.into_inner();
assert_eq!(v.len(), times * len);
assert!(v.iter().all(|x| *x == 5));
});
}
#[bench]
fn bench_mem_writer_001_0000(b: &mut Bencher) {
do_bench_mem_writer(b, 1, 0)
}
#[bench]
fn bench_mem_writer_001_0010(b: &mut Bencher) {
do_bench_mem_writer(b, 1, 10)
}
#[bench]
fn bench_mem_writer_001_0100(b: &mut Bencher) {
do_bench_mem_writer(b, 1, 100)
}
#[bench]
fn bench_mem_writer_001_1000(b: &mut Bencher) {
do_bench_mem_writer(b, 1, 1000)
}
#[bench]
fn bench_mem_writer_100_0000(b: &mut Bencher) {
do_bench_mem_writer(b, 100, 0)
}
#[bench]
fn bench_mem_writer_100_0010(b: &mut Bencher) {
do_bench_mem_writer(b, 100, 10)
}
#[bench]
fn bench_mem_writer_100_0100(b: &mut Bencher) {
do_bench_mem_writer(b, 100, 100)
}
#[bench]
fn bench_mem_writer_100_1000(b: &mut Bencher) {
do_bench_mem_writer(b, 100, 1000)
}
#[bench]
fn bench_mem_reader(b: &mut Bencher) {
b.iter(|| {
let buf = [5 as u8; 100].to_vec();
{
let mut rdr = MemReader::new(buf);
for _i in 0..10 {
let mut buf = [0 as u8; 10];
rdr.read(&mut buf).unwrap();
assert_eq!(buf, [5; 10]);
}
}
});
}
#[bench]
fn bench_buf_writer(b: &mut Bencher) {
b.iter(|| {
let mut buf = [0 as u8; 100];
{
let mut wr = BufWriter::new(&mut buf);
for _i in 0..10 {
wr.write(&[5; 10]).unwrap();
}
}
assert_eq!(&buf[..], &[5; 100][..]);
});
}
#[bench]
fn bench_buf_reader(b: &mut Bencher) {
b.iter(|| {
let buf = [5 as u8; 100];
{
let mut rdr = BufReader::new(&buf);
for _i in 0..10 {
let mut buf = [0 as u8; 10];
rdr.read(&mut buf).unwrap();
assert_eq!(buf, [5; 10]);
}
}
});
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,136 +0,0 @@
// Copyright 2013 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.
//! Synchronous DNS Resolution
//!
//! Contains the functionality to perform DNS resolution or reverse lookup,
//! in a style related to `getaddrinfo()` and `getnameinfo()`, respectively.
#![allow(missing_docs)]
pub use self::SocketType::*;
pub use self::Flag::*;
pub use self::Protocol::*;
use iter::Iterator;
use old_io::IoResult;
use old_io::net::ip::{SocketAddr, IpAddr};
use option::Option;
use option::Option::{Some, None};
use string::String;
use sys;
use vec::Vec;
/// Hints to the types of sockets that are desired when looking up hosts
#[derive(Copy, Clone, Debug)]
pub enum SocketType {
Stream, Datagram, Raw
}
/// Flags which can be or'd into the `flags` field of a `Hint`. These are used
/// to manipulate how a query is performed.
///
/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo`
#[derive(Copy, Clone, Debug)]
pub enum Flag {
AddrConfig,
All,
CanonName,
NumericHost,
NumericServ,
Passive,
V4Mapped,
}
/// A transport protocol associated with either a hint or a return value of
/// `lookup`
#[derive(Copy, Clone, Debug)]
pub enum Protocol {
TCP, UDP
}
/// This structure is used to provide hints when fetching addresses for a
/// remote host to control how the lookup is performed.
///
/// For details on these fields, see their corresponding definitions via
/// `man -s 3 getaddrinfo`
#[derive(Copy, Clone, Debug)]
pub struct Hint {
pub family: usize,
pub socktype: Option<SocketType>,
pub protocol: Option<Protocol>,
pub flags: usize,
}
#[derive(Copy, Clone, Debug)]
pub struct Info {
pub address: SocketAddr,
pub family: usize,
pub socktype: Option<SocketType>,
pub protocol: Option<Protocol>,
pub flags: usize,
}
/// Easy name resolution. Given a hostname, returns the list of IP addresses for
/// that hostname.
pub fn get_host_addresses(host: &str) -> IoResult<Vec<IpAddr>> {
lookup(Some(host), None, None).map(|a| a.into_iter().map(|i| i.address.ip).collect())
}
/// Reverse name resolution. Given an address, returns the corresponding
/// hostname.
pub fn get_address_name(addr: IpAddr) -> IoResult<String> {
sys::addrinfo::get_address_name(addr)
}
/// Full-fledged resolution. This function will perform a synchronous call to
/// getaddrinfo, controlled by the parameters
///
/// # Arguments
///
/// * hostname - an optional hostname to lookup against
/// * servname - an optional service name, listed in the system services
/// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this
/// controls lookup
///
/// FIXME: this is not public because the `Hint` structure is not ready for public
/// consumption just yet.
#[allow(unused_variables)]
fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option<Hint>)
-> IoResult<Vec<Info>> {
sys::addrinfo::get_host_addresses(hostname, servname, hint)
}
// Ignored on android since we cannot give tcp/ip
// permission without help of apk
#[cfg(all(test, not(target_os = "android")))]
mod test {
use prelude::v1::*;
use super::*;
use old_io::net::ip::*;
#[test]
fn dns_smoke_test() {
let ipaddrs = get_host_addresses("localhost").unwrap();
let mut found_local = false;
let local_addr = &Ipv4Addr(127, 0, 0, 1);
for addr in &ipaddrs {
found_local = found_local || addr == local_addr;
}
assert!(found_local);
}
#[test]
fn issue_10663() {
// Something should happen here, but this certainly shouldn't cause
// everything to die. The actual outcome we don't care too much about.
let _ = get_host_addresses("example.com");
}
}

View File

@ -1,710 +0,0 @@
// Copyright 2013 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.
//! Internet Protocol (IP) addresses.
//!
//! This module contains functions useful for parsing, formatting, and
//! manipulating IP addresses.
#![allow(missing_docs)]
pub use self::IpAddr::*;
use boxed::Box;
use fmt;
use old_io::{self, IoResult, IoError};
use old_io::net;
use iter::Iterator;
use ops::{FnOnce, FnMut};
use option::Option;
use option::Option::{None, Some};
use result::Result::{self, Ok, Err};
use str::FromStr;
use vec::Vec;
pub type Port = u16;
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
pub enum IpAddr {
Ipv4Addr(u8, u8, u8, u8),
Ipv6Addr(u16, u16, u16, u16, u16, u16, u16, u16)
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for IpAddr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
Ipv4Addr(a, b, c, d) =>
write!(fmt, "{}.{}.{}.{}", a, b, c, d),
// Ipv4 Compatible address
Ipv6Addr(0, 0, 0, 0, 0, 0, g, h) => {
write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8,
(h >> 8) as u8, h as u8)
}
// Ipv4-Mapped address
Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, g, h) => {
write!(fmt, "::FFFF:{}.{}.{}.{}", (g >> 8) as u8, g as u8,
(h >> 8) as u8, h as u8)
}
Ipv6Addr(a, b, c, d, e, f, g, h) =>
write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
a, b, c, d, e, f, g, h)
}
}
}
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
pub struct SocketAddr {
pub ip: IpAddr,
pub port: Port,
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for SocketAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.ip {
Ipv4Addr(..) => write!(f, "{}:{}", self.ip, self.port),
Ipv6Addr(..) => write!(f, "[{}]:{}", self.ip, self.port),
}
}
}
struct Parser<'a> {
// parsing as ASCII, so can use byte array
s: &'a [u8],
pos: usize,
}
impl<'a> Parser<'a> {
fn new(s: &'a str) -> Parser<'a> {
Parser {
s: s.as_bytes(),
pos: 0,
}
}
fn is_eof(&self) -> bool {
self.pos == self.s.len()
}
// Commit only if parser returns Some
fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where
F: FnOnce(&mut Parser) -> Option<T>,
{
let pos = self.pos;
let r = cb(self);
if r.is_none() {
self.pos = pos;
}
r
}
// Commit only if parser read till EOF
fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where
F: FnOnce(&mut Parser) -> Option<T>,
{
self.read_atomically(move |p| {
match cb(p) {
Some(x) => if p.is_eof() {Some(x)} else {None},
None => None,
}
})
}
// Return result of first successful parser
fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T>>])
-> Option<T> {
for pf in parsers {
match self.read_atomically(|p: &mut Parser| pf.call_mut((p,))) {
Some(r) => return Some(r),
None => {}
}
}
None
}
// Apply 3 parsers sequentially
fn read_seq_3<A, B, C, PA, PB, PC>(&mut self,
pa: PA,
pb: PB,
pc: PC)
-> Option<(A, B, C)> where
PA: FnOnce(&mut Parser) -> Option<A>,
PB: FnOnce(&mut Parser) -> Option<B>,
PC: FnOnce(&mut Parser) -> Option<C>,
{
self.read_atomically(move |p| {
let a = pa(p);
let b = if a.is_some() { pb(p) } else { None };
let c = if b.is_some() { pc(p) } else { None };
match (a, b, c) {
(Some(a), Some(b), Some(c)) => Some((a, b, c)),
_ => None
}
})
}
// Read next char
fn read_char(&mut self) -> Option<char> {
if self.is_eof() {
None
} else {
let r = self.s[self.pos] as char;
self.pos += 1;
Some(r)
}
}
// Return char and advance iff next char is equal to requested
fn read_given_char(&mut self, c: char) -> Option<char> {
self.read_atomically(|p| {
match p.read_char() {
Some(next) if next == c => Some(next),
_ => None,
}
})
}
// Read digit
fn read_digit(&mut self, radix: u8) -> Option<u8> {
fn parse_digit(c: char, radix: u8) -> Option<u8> {
let c = c as u8;
// assuming radix is either 10 or 16
if c >= b'0' && c <= b'9' {
Some(c - b'0')
} else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
Some(c - b'a' + 10)
} else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
Some(c - b'A' + 10)
} else {
None
}
}
self.read_atomically(|p| {
p.read_char().and_then(|c| parse_digit(c, radix))
})
}
fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
let mut r = 0;
let mut digit_count = 0;
loop {
match self.read_digit(radix) {
Some(d) => {
r = r * (radix as u32) + (d as u32);
digit_count += 1;
if digit_count > max_digits || r >= upto {
return None
}
}
None => {
if digit_count == 0 {
return None
} else {
return Some(r)
}
}
};
}
}
// Read number, failing if max_digits of number value exceeded
fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
}
fn read_ipv4_addr_impl(&mut self) -> Option<IpAddr> {
let mut bs = [0; 4];
let mut i = 0;
while i < 4 {
if i != 0 && self.read_given_char('.').is_none() {
return None;
}
let octet = self.read_number(10, 3, 0x100).map(|n| n as u8);
match octet {
Some(d) => bs[i] = d,
None => return None,
};
i += 1;
}
Some(Ipv4Addr(bs[0], bs[1], bs[2], bs[3]))
}
// Read IPv4 address
fn read_ipv4_addr(&mut self) -> Option<IpAddr> {
self.read_atomically(|p| p.read_ipv4_addr_impl())
}
fn read_ipv6_addr_impl(&mut self) -> Option<IpAddr> {
fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> IpAddr {
assert!(head.len() + tail.len() <= 8);
let mut gs = [0; 8];
gs.clone_from_slice(head);
gs[(8 - tail.len()) .. 8].clone_from_slice(tail);
Ipv6Addr(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
}
fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize) -> (usize, bool) {
let mut i = 0;
while i < limit {
if i < limit - 1 {
let ipv4 = p.read_atomically(|p| {
if i == 0 || p.read_given_char(':').is_some() {
p.read_ipv4_addr()
} else {
None
}
});
match ipv4 {
Some(Ipv4Addr(a, b, c, d)) => {
groups[i + 0] = ((a as u16) << 8) | (b as u16);
groups[i + 1] = ((c as u16) << 8) | (d as u16);
return (i + 2, true);
}
_ => {}
}
}
let group = p.read_atomically(|p| {
if i == 0 || p.read_given_char(':').is_some() {
p.read_number(16, 4, 0x10000).map(|n| n as u16)
} else {
None
}
});
match group {
Some(g) => groups[i] = g,
None => return (i, false)
}
i += 1;
}
(i, false)
}
let mut head = [0; 8];
let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
if head_size == 8 {
return Some(Ipv6Addr(
head[0], head[1], head[2], head[3],
head[4], head[5], head[6], head[7]))
}
// IPv4 part is not allowed before `::`
if head_ipv4 {
return None
}
// read `::` if previous code parsed less than 8 groups
if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
return None;
}
let mut tail = [0; 8];
let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
}
fn read_ipv6_addr(&mut self) -> Option<IpAddr> {
self.read_atomically(|p| p.read_ipv6_addr_impl())
}
fn read_ip_addr(&mut self) -> Option<IpAddr> {
let ipv4_addr: Box<_> = box |p: &mut Parser| p.read_ipv4_addr();
let ipv6_addr: Box<_> = box |p: &mut Parser| p.read_ipv6_addr();
self.read_or(&mut [ipv4_addr, ipv6_addr])
}
fn read_socket_addr(&mut self) -> Option<SocketAddr> {
let ip_addr = |p: &mut Parser| {
let ipv4_p: Box<_> = box |p: &mut Parser| p.read_ip_addr();
let ipv6_p: Box<_> = box |p: &mut Parser| {
let open_br = |p: &mut Parser| p.read_given_char('[');
let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
let clos_br = |p: &mut Parser| p.read_given_char(']');
p.read_seq_3::<char, IpAddr, char, _, _, _>(open_br, ip_addr, clos_br)
.map(|t| match t { (_, ip, _) => ip })
};
p.read_or(&mut [ipv4_p, ipv6_p])
};
let colon = |p: &mut Parser| p.read_given_char(':');
let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);
// host, colon, port
self.read_seq_3::<IpAddr, char, u16, _, _, _>(ip_addr, colon, port)
.map(|t| match t { (ip, _, port) => SocketAddr { ip: ip, port: port } })
}
}
impl FromStr for IpAddr {
type Err = ParseError;
fn from_str(s: &str) -> Result<IpAddr, ParseError> {
match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
Some(s) => Ok(s),
None => Err(ParseError),
}
}
}
impl FromStr for SocketAddr {
type Err = ParseError;
fn from_str(s: &str) -> Result<SocketAddr, ParseError> {
match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) {
Some(s) => Ok(s),
None => Err(ParseError),
}
}
}
#[derive(Debug, Clone, PartialEq, Copy)]
pub struct ParseError;
/// A trait for objects which can be converted or resolved to one or more `SocketAddr` values.
///
/// Implementing types minimally have to implement either `to_socket_addr` or `to_socket_addr_all`
/// method, and its trivial counterpart will be available automatically.
///
/// This trait is used for generic address resolution when constructing network objects.
/// By default it is implemented for the following types:
///
/// * `SocketAddr` - `to_socket_addr` is identity function.
///
/// * `(IpAddr, u16)` - `to_socket_addr` constructs `SocketAddr` trivially.
///
/// * `(&str, u16)` - the string should be either a string representation of an IP address
/// expected by `FromStr` implementation for `IpAddr` or a host name.
///
/// For the former, `to_socket_addr_all` returns a vector with a single element corresponding
/// to that IP address joined with the given port.
///
/// For the latter, it tries to resolve the host name and returns a vector of all IP addresses
/// for the host name, each joined with the given port.
///
/// * `&str` - the string should be either a string representation of a `SocketAddr` as
/// expected by its `FromStr` implementation or a string like `<host_name>:<port>` pair
/// where `<port>` is a `u16` value.
///
/// For the former, `to_socket_addr_all` returns a vector with a single element corresponding
/// to that socket address.
///
/// For the latter, it tries to resolve the host name and returns a vector of all IP addresses
/// for the host name, each joined with the port.
///
///
/// This trait allows constructing network objects like `TcpStream` or `UdpSocket` easily with
/// values of various types for the bind/connection address. It is needed because sometimes
/// one type is more appropriate than the other: for simple uses a string like `"localhost:12345"`
/// is much nicer than manual construction of the corresponding `SocketAddr`, but sometimes
/// `SocketAddr` value is *the* main source of the address, and converting it to some other type
/// (e.g. a string) just for it to be converted back to `SocketAddr` in constructor methods
/// is pointless.
///
/// Some examples:
///
/// ```rust,no_run
/// # #![feature(old_io)]
/// # #![allow(unused_must_use)]
///
/// use std::old_io::{TcpStream, TcpListener};
/// use std::old_io::net::udp::UdpSocket;
/// use std::old_io::net::ip::{Ipv4Addr, SocketAddr};
///
/// fn main() {
/// // The following lines are equivalent modulo possible "localhost" name resolution
/// // differences
/// let tcp_s = TcpStream::connect(SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 12345 });
/// let tcp_s = TcpStream::connect((Ipv4Addr(127, 0, 0, 1), 12345));
/// let tcp_s = TcpStream::connect(("127.0.0.1", 12345));
/// let tcp_s = TcpStream::connect(("localhost", 12345));
/// let tcp_s = TcpStream::connect("127.0.0.1:12345");
/// let tcp_s = TcpStream::connect("localhost:12345");
///
/// // TcpListener::bind(), UdpSocket::bind() and UdpSocket::send_to() behave similarly
/// let tcp_l = TcpListener::bind("localhost:12345");
///
/// let mut udp_s = UdpSocket::bind(("127.0.0.1", 23451)).unwrap();
/// udp_s.send_to([7, 7, 7].as_ref(), (Ipv4Addr(127, 0, 0, 1), 23451));
/// }
/// ```
pub trait ToSocketAddr {
/// Converts this object to single socket address value.
///
/// If more than one value is available, this method returns the first one. If no
/// values are available, this method returns an `IoError`.
///
/// By default this method delegates to `to_socket_addr_all` method, taking the first
/// item from its result.
fn to_socket_addr(&self) -> IoResult<SocketAddr> {
self.to_socket_addr_all()
.and_then(|v| v.into_iter().next().ok_or_else(|| IoError {
kind: old_io::InvalidInput,
desc: "no address available",
detail: None
}))
}
/// Converts this object to all available socket address values.
///
/// Some values like host name string naturally correspond to multiple IP addresses.
/// This method tries to return all available addresses corresponding to this object.
///
/// By default this method delegates to `to_socket_addr` method, creating a singleton
/// vector from its result.
#[inline]
fn to_socket_addr_all(&self) -> IoResult<Vec<SocketAddr>> {
self.to_socket_addr().map(|a| vec![a])
}
}
impl ToSocketAddr for SocketAddr {
#[inline]
fn to_socket_addr(&self) -> IoResult<SocketAddr> { Ok(*self) }
}
impl ToSocketAddr for (IpAddr, u16) {
#[inline]
fn to_socket_addr(&self) -> IoResult<SocketAddr> {
let (ip, port) = *self;
Ok(SocketAddr { ip: ip, port: port })
}
}
fn resolve_socket_addr(s: &str, p: u16) -> IoResult<Vec<SocketAddr>> {
net::get_host_addresses(s)
.map(|v| v.into_iter().map(|a| SocketAddr { ip: a, port: p }).collect())
}
fn parse_and_resolve_socket_addr(s: &str) -> IoResult<Vec<SocketAddr>> {
macro_rules! try_opt {
($e:expr, $msg:expr) => (
match $e {
Some(r) => r,
None => return Err(IoError {
kind: old_io::InvalidInput,
desc: $msg,
detail: None
})
}
)
}
// split the string by ':' and convert the second part to u16
let mut parts_iter = s.rsplitn(2, ':');
let port_str = try_opt!(parts_iter.next(), "invalid socket address");
let host = try_opt!(parts_iter.next(), "invalid socket address");
let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
resolve_socket_addr(host, port)
}
impl<'a> ToSocketAddr for (&'a str, u16) {
fn to_socket_addr_all(&self) -> IoResult<Vec<SocketAddr>> {
let (host, port) = *self;
// try to parse the host as a regular IpAddr first
match host.parse().ok() {
Some(addr) => return Ok(vec![SocketAddr {
ip: addr,
port: port
}]),
None => {}
}
resolve_socket_addr(host, port)
}
}
// accepts strings like 'localhost:12345'
impl<'a> ToSocketAddr for &'a str {
fn to_socket_addr(&self) -> IoResult<SocketAddr> {
// try to parse as a regular SocketAddr first
match self.parse().ok() {
Some(addr) => return Ok(addr),
None => {}
}
parse_and_resolve_socket_addr(*self)
.and_then(|v| v.into_iter().next()
.ok_or_else(|| IoError {
kind: old_io::InvalidInput,
desc: "no address available",
detail: None
})
)
}
fn to_socket_addr_all(&self) -> IoResult<Vec<SocketAddr>> {
// try to parse as a regular SocketAddr first
match self.parse().ok() {
Some(addr) => return Ok(vec![addr]),
None => {}
}
parse_and_resolve_socket_addr(*self)
}
}
#[cfg(test)]
mod test {
use prelude::v1::*;
use super::*;
use str::FromStr;
#[test]
fn test_from_str_ipv4() {
assert_eq!(Ok(Ipv4Addr(127, 0, 0, 1)), "127.0.0.1".parse());
assert_eq!(Ok(Ipv4Addr(255, 255, 255, 255)), "255.255.255.255".parse());
assert_eq!(Ok(Ipv4Addr(0, 0, 0, 0)), "0.0.0.0".parse());
// out of range
let none: Option<IpAddr> = "256.0.0.1".parse().ok();
assert_eq!(None, none);
// too short
let none: Option<IpAddr> = "255.0.0".parse().ok();
assert_eq!(None, none);
// too long
let none: Option<IpAddr> = "255.0.0.1.2".parse().ok();
assert_eq!(None, none);
// no number between dots
let none: Option<IpAddr> = "255.0..1".parse().ok();
assert_eq!(None, none);
}
#[test]
fn test_from_str_ipv6() {
assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
assert_eq!(Ok(Ipv6Addr(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)),
"2a02:6b8::11:11".parse());
// too long group
let none: Option<IpAddr> = "::00000".parse().ok();
assert_eq!(None, none);
// too short
let none: Option<IpAddr> = "1:2:3:4:5:6:7".parse().ok();
assert_eq!(None, none);
// too long
let none: Option<IpAddr> = "1:2:3:4:5:6:7:8:9".parse().ok();
assert_eq!(None, none);
// triple colon
let none: Option<IpAddr> = "1:2:::6:7:8".parse().ok();
assert_eq!(None, none);
// two double colons
let none: Option<IpAddr> = "1:2::6::8".parse().ok();
assert_eq!(None, none);
}
#[test]
fn test_from_str_ipv4_in_ipv6() {
assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 49152, 545)),
"::192.0.2.33".parse());
assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)),
"::FFFF:192.0.2.33".parse());
assert_eq!(Ok(Ipv6Addr(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
"64:ff9b::192.0.2.33".parse());
assert_eq!(Ok(Ipv6Addr(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
"2001:db8:122:c000:2:2100:192.0.2.33".parse());
// colon after v4
let none: Option<IpAddr> = "::127.0.0.1:".parse().ok();
assert_eq!(None, none);
// not enough groups
let none: Option<IpAddr> = "1.2.3.4.5:127.0.0.1".parse().ok();
assert_eq!(None, none);
// too many groups
let none: Option<IpAddr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
assert_eq!(None, none);
}
#[test]
fn test_from_str_socket_addr() {
assert_eq!(Ok(SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 80 }),
"77.88.21.11:80".parse());
assert_eq!(Ok(SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }),
"[2a02:6b8:0:1::1]:53".parse());
assert_eq!(Ok(SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0x7F00, 1), port: 22 }),
"[::127.0.0.1]:22".parse());
// without port
let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
assert_eq!(None, none);
// without port
let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
assert_eq!(None, none);
// wrong brackets around v4
let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
assert_eq!(None, none);
// port out of range
let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
assert_eq!(None, none);
}
#[test]
fn ipv6_addr_to_string() {
let a1 = Ipv6Addr(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
assert!(a1.to_string() == "::ffff:192.0.2.128" ||
a1.to_string() == "::FFFF:192.0.2.128");
assert_eq!(Ipv6Addr(8, 9, 10, 11, 12, 13, 14, 15).to_string(),
"8:9:a:b:c:d:e:f");
}
#[test]
fn to_socket_addr_socketaddr() {
let a = SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 12345 };
assert_eq!(Ok(a), a.to_socket_addr());
assert_eq!(Ok(vec![a]), a.to_socket_addr_all());
}
#[test]
fn to_socket_addr_ipaddr_u16() {
let a = Ipv4Addr(77, 88, 21, 11);
let p = 12345;
let e = SocketAddr { ip: a, port: p };
assert_eq!(Ok(e), (a, p).to_socket_addr());
assert_eq!(Ok(vec![e]), (a, p).to_socket_addr_all());
}
#[test]
fn to_socket_addr_str_u16() {
let a = SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 24352 };
assert_eq!(Ok(a), ("77.88.21.11", 24352).to_socket_addr());
assert_eq!(Ok(vec![a]), ("77.88.21.11", 24352).to_socket_addr_all());
let a = SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 };
assert_eq!(Ok(a), ("2a02:6b8:0:1::1", 53).to_socket_addr());
assert_eq!(Ok(vec![a]), ("2a02:6b8:0:1::1", 53).to_socket_addr_all());
let a = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 23924 };
assert!(("localhost", 23924).to_socket_addr_all().unwrap().contains(&a));
}
#[test]
fn to_socket_addr_str() {
let a = SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 24352 };
assert_eq!(Ok(a), "77.88.21.11:24352".to_socket_addr());
assert_eq!(Ok(vec![a]), "77.88.21.11:24352".to_socket_addr_all());
let a = SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 };
assert_eq!(Ok(a), "[2a02:6b8:0:1::1]:53".to_socket_addr());
assert_eq!(Ok(vec![a]), "[2a02:6b8:0:1::1]:53".to_socket_addr_all());
let a = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 23924 };
assert!("localhost:23924".to_socket_addr_all().unwrap().contains(&a));
}
}

View File

@ -1,50 +0,0 @@
// Copyright 2013 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.
//! Networking I/O
#![deprecated(since = "1.0.0",
reason = "replaced with new I/O primitives in `std::net`")]
#![unstable(feature = "old_io")]
use old_io::{IoError, IoResult, InvalidInput};
use ops::FnMut;
use option::Option::None;
use result::Result::{Ok, Err};
use self::ip::{SocketAddr, ToSocketAddr};
pub use self::addrinfo::get_host_addresses;
pub mod addrinfo;
pub mod tcp;
pub mod udp;
pub mod ip;
pub mod pipe;
fn with_addresses<A, T, F>(addr: A, mut action: F) -> IoResult<T> where
A: ToSocketAddr,
F: FnMut(SocketAddr) -> IoResult<T>,
{
const DEFAULT_ERROR: IoError = IoError {
kind: InvalidInput,
desc: "no addresses found for hostname",
detail: None
};
let addresses = try!(addr.to_socket_addr_all());
let mut err = DEFAULT_ERROR;
for addr in addresses {
match action(addr) {
Ok(r) => return Ok(r),
Err(e) => err = e
}
}
Err(err)
}

View File

@ -1,883 +0,0 @@
// Copyright 2013 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.
//! Named pipes
//!
//! This module contains the ability to communicate over named pipes with
//! synchronous I/O. On windows, this corresponds to talking over a Named Pipe,
//! while on Unix it corresponds to UNIX domain sockets.
//!
//! These pipes are similar to TCP in the sense that you can have both a stream to a
//! server and a server itself. The server provided accepts other `UnixStream`
//! instances as clients.
#![allow(missing_docs)]
#![deprecated(since = "1.0.0",
reason = "will be removed to be reintroduced at a later date; \
in the meantime consider using the `unix_socket` crate \
for unix sockets; there is currently no replacement \
for named pipes")]
#![unstable(feature = "old_io")]
use prelude::v1::*;
use ffi::CString;
use old_path::BytesContainer;
use old_io::{Listener, Acceptor, IoResult, TimedOut, standard_error};
use old_io::{Reader, Writer};
use sys::pipe::UnixAcceptor as UnixAcceptorImp;
use sys::pipe::UnixListener as UnixListenerImp;
use sys::pipe::UnixStream as UnixStreamImp;
use time::Duration;
use sys_common;
/// A stream which communicates over a named pipe.
pub struct UnixStream {
inner: UnixStreamImp,
}
impl UnixStream {
/// Connect to a pipe named by `path`. This will attempt to open a
/// connection to the underlying socket.
///
/// The returned stream will be closed when the object falls out of scope.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, old_path, io)]
/// # #![allow(unused_must_use)]
/// use std::old_io::net::pipe::UnixStream;
/// use std::old_io::*;
/// use std::old_path::Path;
///
/// let server = Path::new("path/to/my/socket");
/// let mut stream = UnixStream::connect(&server);
/// stream.write(&[1, 2, 3]);
/// ```
pub fn connect<P: BytesContainer>(path: P) -> IoResult<UnixStream> {
let path = try!(CString::new(path.container_as_bytes()));
UnixStreamImp::connect(&path, None)
.map(|inner| UnixStream { inner: inner })
}
/// Connect to a pipe named by `path`, timing out if the specified number of
/// milliseconds.
///
/// This function is similar to `connect`, except that if `timeout`
/// elapses the function will return an error of kind `TimedOut`.
///
/// If a `timeout` with zero or negative duration is specified then
/// the function returns `Err`, with the error kind set to `TimedOut`.
#[unstable(feature = "io",
reason = "the timeout argument is likely to change types")]
pub fn connect_timeout<P>(path: P, timeout: Duration)
-> IoResult<UnixStream>
where P: BytesContainer {
if timeout <= Duration::milliseconds(0) {
return Err(standard_error(TimedOut));
}
let path = try!(CString::new(path.container_as_bytes()));
UnixStreamImp::connect(&path, Some(timeout.num_milliseconds() as u64))
.map(|inner| UnixStream { inner: inner })
}
/// Closes the reading half of this connection.
///
/// This method will close the reading portion of this connection, causing
/// all pending and future reads to immediately return with an error.
///
/// Note that this method affects all cloned handles associated with this
/// stream, not just this one handle.
pub fn close_read(&mut self) -> IoResult<()> {
self.inner.close_read()
}
/// Closes the writing half of this connection.
///
/// This method will close the writing portion of this connection, causing
/// all pending and future writes to immediately return with an error.
///
/// Note that this method affects all cloned handles associated with this
/// stream, not just this one handle.
pub fn close_write(&mut self) -> IoResult<()> {
self.inner.close_write()
}
/// Sets the read/write timeout for this socket.
///
/// For more information, see `TcpStream::set_timeout`
#[unstable(feature = "io",
reason = "the timeout argument may change in type and value")]
pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
self.inner.set_timeout(timeout_ms)
}
/// Sets the read timeout for this socket.
///
/// For more information, see `TcpStream::set_timeout`
#[unstable(feature = "io",
reason = "the timeout argument may change in type and value")]
pub fn set_read_timeout(&mut self, timeout_ms: Option<u64>) {
self.inner.set_read_timeout(timeout_ms)
}
/// Sets the write timeout for this socket.
///
/// For more information, see `TcpStream::set_timeout`
#[unstable(feature = "io",
reason = "the timeout argument may change in type and value")]
pub fn set_write_timeout(&mut self, timeout_ms: Option<u64>) {
self.inner.set_write_timeout(timeout_ms)
}
}
impl Clone for UnixStream {
fn clone(&self) -> UnixStream {
UnixStream { inner: self.inner.clone() }
}
}
impl Reader for UnixStream {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
self.inner.read(buf)
}
}
impl Writer for UnixStream {
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
self.inner.write(buf)
}
}
impl sys_common::AsInner<UnixStreamImp> for UnixStream {
fn as_inner(&self) -> &UnixStreamImp {
&self.inner
}
}
/// A value that can listen for incoming named pipe connection requests.
pub struct UnixListener {
/// The internal, opaque runtime Unix listener.
inner: UnixListenerImp,
}
impl UnixListener {
/// Creates a new listener, ready to receive incoming connections on the
/// specified socket. The server will be named by `path`.
///
/// This listener will be closed when it falls out of scope.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, io, old_path)]
/// # fn foo() {
/// use std::old_io::net::pipe::UnixListener;
/// use std::old_io::*;
/// use std::old_path::Path;
///
/// let server = Path::new("/path/to/my/socket");
/// let stream = UnixListener::bind(&server);
/// for mut client in stream.listen().incoming() {
/// let _ = client.write(&[1, 2, 3, 4]);
/// }
/// # }
/// ```
pub fn bind<P: BytesContainer>(path: P) -> IoResult<UnixListener> {
let path = try!(CString::new(path.container_as_bytes()));
UnixListenerImp::bind(&path)
.map(|inner| UnixListener { inner: inner })
}
}
impl Listener<UnixAcceptor> for UnixListener {
fn listen(self) -> IoResult<UnixAcceptor> {
self.inner.listen()
.map(|inner| UnixAcceptor { inner: inner })
}
}
impl sys_common::AsInner<UnixListenerImp> for UnixListener {
fn as_inner(&self) -> &UnixListenerImp {
&self.inner
}
}
/// A value that can accept named pipe connections, returned from `listen()`.
pub struct UnixAcceptor {
/// The internal, opaque runtime Unix acceptor.
inner: UnixAcceptorImp
}
impl UnixAcceptor {
/// Sets a timeout for this acceptor, after which accept() will no longer
/// block indefinitely.
///
/// The argument specified is the amount of time, in milliseconds, into the
/// future after which all invocations of accept() will not block (and any
/// pending invocation will return). A value of `None` will clear any
/// existing timeout.
///
/// When using this method, it is likely necessary to reset the timeout as
/// appropriate, the timeout specified is specific to this object, not
/// specific to the next request.
#[unstable(feature = "io",
reason = "the name and arguments to this function are likely \
to change")]
pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
self.inner.set_timeout(timeout_ms)
}
/// Closes the accepting capabilities of this acceptor.
///
/// This function has the same semantics as `TcpAcceptor::close_accept`, and
/// more information can be found in that documentation.
#[unstable(feature = "io")]
pub fn close_accept(&mut self) -> IoResult<()> {
self.inner.close_accept()
}
}
impl Acceptor for UnixAcceptor {
type Connection = UnixStream;
fn accept(&mut self) -> IoResult<UnixStream> {
self.inner.accept().map(|s| {
UnixStream { inner: s }
})
}
}
impl Clone for UnixAcceptor {
/// Creates a new handle to this unix acceptor, allowing for simultaneous
/// accepts.
///
/// The underlying unix acceptor will not be closed until all handles to the
/// acceptor have been deallocated. Incoming connections will be received on
/// at most once acceptor, the same connection will not be accepted twice.
///
/// The `close_accept` method will shut down *all* acceptors cloned from the
/// same original acceptor, whereas the `set_timeout` method only affects
/// the selector that it is called on.
///
/// This function is useful for creating a handle to invoke `close_accept`
/// on to wake up any other task blocked in `accept`.
fn clone(&self) -> UnixAcceptor {
UnixAcceptor { inner: self.inner.clone() }
}
}
impl sys_common::AsInner<UnixAcceptorImp> for UnixAcceptor {
fn as_inner(&self) -> &UnixAcceptorImp {
&self.inner
}
}
#[cfg(test)]
mod tests {
use prelude::v1::*;
use old_io::fs::PathExtensions;
use old_io::{EndOfFile, TimedOut, ShortWrite, IoError, ConnectionReset};
use old_io::{NotConnected, BrokenPipe, FileNotFound, InvalidInput, OtherIoError};
use old_io::{PermissionDenied, Acceptor, Listener};
use old_io::{Reader, Writer};
use old_io::test::*;
use super::*;
use sync::mpsc::channel;
use thread;
use time::Duration;
pub fn smalltest<F,G>(server: F, client: G)
where F : FnOnce(UnixStream), F : Send,
G : FnOnce(UnixStream), G : Send + 'static
{
let path1 = next_test_unix();
let path2 = path1.clone();
let mut acceptor = UnixListener::bind(&path1).listen();
let _t = thread::spawn(move|| {
match UnixStream::connect(&path2) {
Ok(c) => client(c),
Err(e) => panic!("failed connect: {}", e),
}
});
match acceptor.accept() {
Ok(c) => server(c),
Err(e) => panic!("failed accept: {}", e),
}
}
#[test]
fn bind_error() {
let path = "path/to/nowhere";
match UnixListener::bind(&path) {
Ok(..) => panic!(),
Err(e) => {
assert!(e.kind == PermissionDenied || e.kind == FileNotFound ||
e.kind == InvalidInput);
}
}
}
#[test]
fn connect_error() {
let path = if cfg!(windows) {
r"\\.\pipe\this_should_not_exist_ever"
} else {
"path/to/nowhere"
};
match UnixStream::connect(&path) {
Ok(..) => panic!(),
Err(e) => {
assert!(e.kind == FileNotFound || e.kind == OtherIoError);
}
}
}
#[test]
fn smoke() {
smalltest(move |mut server| {
let mut buf = [0];
server.read(&mut buf).unwrap();
assert!(buf[0] == 99);
}, move|mut client| {
client.write(&[99]).unwrap();
})
}
#[cfg_attr(windows, ignore)] // FIXME(#12516)
#[test]
fn read_eof() {
smalltest(move|mut server| {
let mut buf = [0];
assert!(server.read(&mut buf).is_err());
assert!(server.read(&mut buf).is_err());
}, move|_client| {
// drop the client
})
}
#[test]
fn write_begone() {
smalltest(move|mut server| {
let buf = [0];
loop {
match server.write(&buf) {
Ok(..) => {}
Err(e) => {
assert!(e.kind == BrokenPipe ||
e.kind == NotConnected ||
e.kind == ConnectionReset,
"unknown error {}", e);
break;
}
}
}
}, move|_client| {
// drop the client
})
}
#[test]
fn accept_lots() {
let times = 10;
let path1 = next_test_unix();
let path2 = path1.clone();
let mut acceptor = match UnixListener::bind(&path1).listen() {
Ok(a) => a,
Err(e) => panic!("failed listen: {}", e),
};
let _t = thread::spawn(move|| {
for _ in 0..times {
let mut stream = UnixStream::connect(&path2);
match stream.write(&[100]) {
Ok(..) => {}
Err(e) => panic!("failed write: {}", e)
}
}
});
for _ in 0..times {
let mut client = acceptor.accept();
let mut buf = [0];
match client.read(&mut buf) {
Ok(..) => {}
Err(e) => panic!("failed read/accept: {}", e),
}
assert_eq!(buf[0], 100);
}
}
#[cfg(unix)]
#[test]
fn path_exists() {
let path = next_test_unix();
let _acceptor = UnixListener::bind(&path).listen();
assert!(path.exists());
}
#[test]
fn unix_clone_smoke() {
let addr = next_test_unix();
let mut acceptor = UnixListener::bind(&addr).listen();
let _t = thread::spawn(move|| {
let mut s = UnixStream::connect(&addr);
let mut buf = [0, 0];
debug!("client reading");
assert_eq!(s.read(&mut buf), Ok(1));
assert_eq!(buf[0], 1);
debug!("client writing");
s.write(&[2]).unwrap();
debug!("client dropping");
});
let mut s1 = acceptor.accept().unwrap();
let s2 = s1.clone();
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move|| {
let mut s2 = s2;
rx1.recv().unwrap();
debug!("writer writing");
s2.write(&[1]).unwrap();
debug!("writer done");
tx2.send(()).unwrap();
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
debug!("reader reading");
assert_eq!(s1.read(&mut buf), Ok(1));
debug!("reader done");
rx2.recv().unwrap();
}
#[test]
fn unix_clone_two_read() {
let addr = next_test_unix();
let mut acceptor = UnixListener::bind(&addr).listen();
let (tx1, rx) = channel();
let tx2 = tx1.clone();
let _t = thread::spawn(move|| {
let mut s = UnixStream::connect(&addr);
s.write(&[1]).unwrap();
rx.recv().unwrap();
s.write(&[2]).unwrap();
rx.recv().unwrap();
});
let mut s1 = acceptor.accept().unwrap();
let s2 = s1.clone();
let (done, rx) = channel();
let _t = thread::spawn(move|| {
let mut s2 = s2;
let mut buf = [0, 0];
s2.read(&mut buf).unwrap();
tx2.send(()).unwrap();
done.send(()).unwrap();
});
let mut buf = [0, 0];
s1.read(&mut buf).unwrap();
tx1.send(()).unwrap();
rx.recv().unwrap();
}
#[test]
fn unix_clone_two_write() {
let addr = next_test_unix();
let mut acceptor = UnixListener::bind(&addr).listen();
let _t = thread::spawn(move|| {
let mut s = UnixStream::connect(&addr);
let buf = &mut [0, 1];
s.read(buf).unwrap();
s.read(buf).unwrap();
});
let mut s1 = acceptor.accept().unwrap();
let s2 = s1.clone();
let (tx, rx) = channel();
let _t = thread::spawn(move|| {
let mut s2 = s2;
s2.write(&[1]).unwrap();
tx.send(()).unwrap();
});
s1.write(&[2]).unwrap();
rx.recv().unwrap();
}
#[cfg(not(windows))]
#[test]
fn drop_removes_listener_path() {
let path = next_test_unix();
let l = UnixListener::bind(&path).unwrap();
assert!(path.exists());
drop(l);
assert!(!path.exists());
}
#[cfg(not(windows))]
#[test]
fn drop_removes_acceptor_path() {
let path = next_test_unix();
let l = UnixListener::bind(&path).unwrap();
assert!(path.exists());
drop(l.listen().unwrap());
assert!(!path.exists());
}
#[test]
fn accept_timeout() {
let addr = next_test_unix();
let mut a = UnixListener::bind(&addr).unwrap().listen().unwrap();
a.set_timeout(Some(10));
// Make sure we time out once and future invocations also time out
let err = a.accept().err().unwrap();
assert_eq!(err.kind, TimedOut);
let err = a.accept().err().unwrap();
assert_eq!(err.kind, TimedOut);
// Also make sure that even though the timeout is expired that we will
// continue to receive any pending connections.
let (tx, rx) = channel();
let addr2 = addr.clone();
let _t = thread::spawn(move|| {
tx.send(UnixStream::connect(&addr2).unwrap()).unwrap();
});
let l = rx.recv().unwrap();
for i in 0..1001 {
match a.accept() {
Ok(..) => break,
Err(ref e) if e.kind == TimedOut => {}
Err(e) => panic!("error: {}", e),
}
::thread::yield_now();
if i == 1000 { panic!("should have a pending connection") }
}
drop(l);
// Unset the timeout and make sure that this always blocks.
a.set_timeout(None);
let addr2 = addr.clone();
let _t = thread::spawn(move|| {
drop(UnixStream::connect(&addr2).unwrap());
});
a.accept().unwrap();
}
#[test]
fn connect_timeout_error() {
let addr = next_test_unix();
assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(100)).is_err());
}
#[test]
fn connect_timeout_success() {
let addr = next_test_unix();
let _a = UnixListener::bind(&addr).unwrap().listen().unwrap();
assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(100)).is_ok());
}
#[test]
fn connect_timeout_zero() {
let addr = next_test_unix();
let _a = UnixListener::bind(&addr).unwrap().listen().unwrap();
assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(0)).is_err());
}
#[test]
fn connect_timeout_negative() {
let addr = next_test_unix();
let _a = UnixListener::bind(&addr).unwrap().listen().unwrap();
assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(-1)).is_err());
}
#[test]
fn close_readwrite_smoke() {
let addr = next_test_unix();
let a = UnixListener::bind(&addr).listen().unwrap();
let (_tx, rx) = channel::<()>();
thread::spawn(move|| {
let mut a = a;
let _s = a.accept().unwrap();
let _ = rx.recv();
});
let mut b = [0];
let mut s = UnixStream::connect(&addr).unwrap();
let mut s2 = s.clone();
// closing should prevent reads/writes
s.close_write().unwrap();
assert!(s.write(&[0]).is_err());
s.close_read().unwrap();
assert!(s.read(&mut b).is_err());
// closing should affect previous handles
assert!(s2.write(&[0]).is_err());
assert!(s2.read(&mut b).is_err());
// closing should affect new handles
let mut s3 = s.clone();
assert!(s3.write(&[0]).is_err());
assert!(s3.read(&mut b).is_err());
// make sure these don't die
let _ = s2.close_read();
let _ = s2.close_write();
let _ = s3.close_read();
let _ = s3.close_write();
}
#[test]
fn close_read_wakes_up() {
let addr = next_test_unix();
let a = UnixListener::bind(&addr).listen().unwrap();
let (_tx, rx) = channel::<()>();
thread::spawn(move|| {
let mut a = a;
let _s = a.accept().unwrap();
let _ = rx.recv();
});
let mut s = UnixStream::connect(&addr).unwrap();
let s2 = s.clone();
let (tx, rx) = channel();
let _t = thread::spawn(move|| {
let mut s2 = s2;
assert!(s2.read(&mut [0]).is_err());
tx.send(()).unwrap();
});
// this should wake up the child task
s.close_read().unwrap();
// this test will never finish if the child doesn't wake up
rx.recv().unwrap();
}
#[test]
fn readwrite_timeouts() {
let addr = next_test_unix();
let mut a = UnixListener::bind(&addr).listen().unwrap();
let (tx, rx) = channel::<()>();
thread::spawn(move|| {
let mut s = UnixStream::connect(&addr).unwrap();
rx.recv().unwrap();
assert!(s.write(&[0]).is_ok());
let _ = rx.recv();
});
let mut s = a.accept().unwrap();
s.set_timeout(Some(20));
assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut);
assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut);
s.set_timeout(Some(20));
for i in 0..1001 {
match s.write(&[0; 128 * 1024]) {
Ok(()) | Err(IoError { kind: ShortWrite(..), .. }) => {},
Err(IoError { kind: TimedOut, .. }) => break,
Err(e) => panic!("{}", e),
}
if i == 1000 { panic!("should have filled up?!"); }
}
// I'm not sure as to why, but apparently the write on windows always
// succeeds after the previous timeout. Who knows?
if !cfg!(windows) {
assert_eq!(s.write(&[0]).err().unwrap().kind, TimedOut);
}
tx.send(()).unwrap();
s.set_timeout(None);
assert_eq!(s.read(&mut [0, 0]), Ok(1));
}
#[test]
fn read_timeouts() {
let addr = next_test_unix();
let mut a = UnixListener::bind(&addr).listen().unwrap();
let (tx, rx) = channel::<()>();
thread::spawn(move|| {
let mut s = UnixStream::connect(&addr).unwrap();
rx.recv().unwrap();
let mut amt = 0;
while amt < 100 * 128 * 1024 {
match s.read(&mut [0;128 * 1024]) {
Ok(n) => { amt += n; }
Err(e) => panic!("{}", e),
}
}
let _ = rx.recv();
});
let mut s = a.accept().unwrap();
s.set_read_timeout(Some(20));
assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut);
assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut);
tx.send(()).unwrap();
for _ in 0..100 {
assert!(s.write(&[0;128 * 1024]).is_ok());
}
}
#[test]
fn write_timeouts() {
let addr = next_test_unix();
let mut a = UnixListener::bind(&addr).listen().unwrap();
let (tx, rx) = channel::<()>();
thread::spawn(move|| {
let mut s = UnixStream::connect(&addr).unwrap();
rx.recv().unwrap();
assert!(s.write(&[0]).is_ok());
let _ = rx.recv();
});
let mut s = a.accept().unwrap();
s.set_write_timeout(Some(20));
for i in 0..1001 {
match s.write(&[0; 128 * 1024]) {
Ok(()) | Err(IoError { kind: ShortWrite(..), .. }) => {},
Err(IoError { kind: TimedOut, .. }) => break,
Err(e) => panic!("{}", e),
}
if i == 1000 { panic!("should have filled up?!"); }
}
tx.send(()).unwrap();
assert!(s.read(&mut [0]).is_ok());
}
#[test]
fn timeout_concurrent_read() {
let addr = next_test_unix();
let mut a = UnixListener::bind(&addr).listen().unwrap();
let (tx, rx) = channel::<()>();
thread::spawn(move|| {
let mut s = UnixStream::connect(&addr).unwrap();
rx.recv().unwrap();
assert!(s.write(&[0]).is_ok());
let _ = rx.recv();
});
let mut s = a.accept().unwrap();
let s2 = s.clone();
let (tx2, rx2) = channel();
let _t = thread::spawn(move|| {
let mut s2 = s2;
assert!(s2.read(&mut [0]).is_ok());
tx2.send(()).unwrap();
});
s.set_read_timeout(Some(20));
assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut);
tx.send(()).unwrap();
rx2.recv().unwrap();
}
#[cfg(not(windows))]
#[test]
fn clone_accept_smoke() {
let addr = next_test_unix();
let l = UnixListener::bind(&addr);
let mut a = l.listen().unwrap();
let mut a2 = a.clone();
let addr2 = addr.clone();
let _t = thread::spawn(move|| {
let _ = UnixStream::connect(&addr2);
});
let _t = thread::spawn(move|| {
let _ = UnixStream::connect(&addr);
});
assert!(a.accept().is_ok());
drop(a);
assert!(a2.accept().is_ok());
}
#[cfg(not(windows))] // FIXME #17553
#[test]
fn clone_accept_concurrent() {
let addr = next_test_unix();
let l = UnixListener::bind(&addr);
let a = l.listen().unwrap();
let a2 = a.clone();
let (tx, rx) = channel();
let tx2 = tx.clone();
let _t = thread::spawn(move|| {
let mut a = a;
tx.send(a.accept()).unwrap()
});
let _t = thread::spawn(move|| {
let mut a = a2;
tx2.send(a.accept()).unwrap()
});
let addr2 = addr.clone();
let _t = thread::spawn(move|| {
let _ = UnixStream::connect(&addr2);
});
let _t = thread::spawn(move|| {
let _ = UnixStream::connect(&addr);
});
assert!(rx.recv().unwrap().is_ok());
assert!(rx.recv().unwrap().is_ok());
}
#[test]
fn close_accept_smoke() {
let addr = next_test_unix();
let l = UnixListener::bind(&addr);
let mut a = l.listen().unwrap();
a.close_accept().unwrap();
assert_eq!(a.accept().err().unwrap().kind, EndOfFile);
}
#[test]
fn close_accept_concurrent() {
let addr = next_test_unix();
let l = UnixListener::bind(&addr);
let a = l.listen().unwrap();
let mut a2 = a.clone();
let (tx, rx) = channel();
let _t = thread::spawn(move|| {
let mut a = a;
tx.send(a.accept()).unwrap();
});
a2.close_accept().unwrap();
assert_eq!(rx.recv().unwrap().err().unwrap().kind, EndOfFile);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,459 +0,0 @@
// Copyright 2013 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.
//! UDP (User Datagram Protocol) network connections.
//!
//! This module contains the ability to open a UDP stream to a socket address.
//! The destination and binding addresses can either be an IPv4 or IPv6
//! address. There is no corresponding notion of a server because UDP is a
//! datagram protocol.
use clone::Clone;
use old_io::net::ip::{SocketAddr, IpAddr, ToSocketAddr};
use old_io::IoResult;
use option::Option;
use sys::udp::UdpSocket as UdpSocketImp;
use sys_common;
/// A User Datagram Protocol socket.
///
/// This is an implementation of a bound UDP socket. This supports both IPv4 and
/// IPv6 addresses, and there is no corresponding notion of a server because UDP
/// is a datagram protocol.
///
/// # Examples
///
/// ```rust,no_run
/// # #![feature(old_io)]
/// # #![allow(unused_must_use)]
///
/// use std::old_io::net::udp::UdpSocket;
/// use std::old_io::net::ip::{Ipv4Addr, SocketAddr};
/// fn main() {
/// let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 34254 };
/// let mut socket = match UdpSocket::bind(addr) {
/// Ok(s) => s,
/// Err(e) => panic!("couldn't bind socket: {}", e),
/// };
///
/// let mut buf = [0; 10];
/// match socket.recv_from(&mut buf) {
/// Ok((amt, src)) => {
/// // Send a reply to the socket we received data from
/// let buf = &mut buf[..amt];
/// buf.reverse();
/// socket.send_to(buf, src);
/// }
/// Err(e) => println!("couldn't receive a datagram: {}", e)
/// }
/// drop(socket); // close the socket
/// }
/// ```
pub struct UdpSocket {
inner: UdpSocketImp,
}
impl UdpSocket {
/// Creates a UDP socket from the given address.
///
/// Address type can be any implementor of `ToSocketAddr` trait. See its
/// documentation for concrete examples.
pub fn bind<A: ToSocketAddr>(addr: A) -> IoResult<UdpSocket> {
super::with_addresses(addr, |addr| {
UdpSocketImp::bind(addr).map(|s| UdpSocket { inner: s })
})
}
/// Receives data from the socket. On success, returns the number of bytes
/// read and the address from whence the data came.
pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(usize, SocketAddr)> {
self.inner.recv_from(buf)
}
/// Sends data on the socket to the given address. Returns nothing on
/// success.
///
/// Address type can be any implementer of `ToSocketAddr` trait. See its
/// documentation for concrete examples.
pub fn send_to<A: ToSocketAddr>(&mut self, buf: &[u8], addr: A) -> IoResult<()> {
super::with_addresses(addr, |addr| self.inner.send_to(buf, addr))
}
/// Returns the socket address that this socket was created from.
pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
self.inner.socket_name()
}
/// Joins a multicast IP address (becomes a member of it)
#[unstable(feature = "io")]
pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> {
self.inner.join_multicast(multi)
}
/// Leaves a multicast IP address (drops membership from it)
#[unstable(feature = "io")]
pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> {
self.inner.leave_multicast(multi)
}
/// Set the multicast loop flag to the specified value
///
/// This lets multicast packets loop back to local sockets (if enabled)
#[unstable(feature = "io")]
pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> {
self.inner.set_multicast_loop(on)
}
/// Sets the multicast TTL
#[unstable(feature = "io")]
pub fn set_multicast_ttl(&mut self, ttl: isize) -> IoResult<()> {
self.inner.multicast_time_to_live(ttl)
}
/// Sets this socket's TTL
#[unstable(feature = "io")]
pub fn set_ttl(&mut self, ttl: isize) -> IoResult<()> {
self.inner.time_to_live(ttl)
}
/// Sets the broadcast flag on or off
#[unstable(feature = "io")]
pub fn set_broadcast(&mut self, broadcast: bool) -> IoResult<()> {
self.inner.set_broadcast(broadcast)
}
/// Sets the read/write timeout for this socket.
///
/// For more information, see `TcpStream::set_timeout`
#[unstable(feature = "io",
reason = "the timeout argument may change in type and value")]
pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
self.inner.set_timeout(timeout_ms)
}
/// Sets the read timeout for this socket.
///
/// For more information, see `TcpStream::set_timeout`
#[unstable(feature = "io",
reason = "the timeout argument may change in type and value")]
pub fn set_read_timeout(&mut self, timeout_ms: Option<u64>) {
self.inner.set_read_timeout(timeout_ms)
}
/// Sets the write timeout for this socket.
///
/// For more information, see `TcpStream::set_timeout`
#[unstable(feature = "io",
reason = "the timeout argument may change in type and value")]
pub fn set_write_timeout(&mut self, timeout_ms: Option<u64>) {
self.inner.set_write_timeout(timeout_ms)
}
}
impl Clone for UdpSocket {
/// Creates a new handle to this UDP socket, allowing for simultaneous
/// reads and writes of the socket.
///
/// The underlying UDP socket will not be closed until all handles to the
/// socket have been deallocated. Two concurrent reads will not receive
/// the same data. Instead, the first read will receive the first packet
/// received, and the second read will receive the second packet.
fn clone(&self) -> UdpSocket {
UdpSocket {
inner: self.inner.clone(),
}
}
}
impl sys_common::AsInner<UdpSocketImp> for UdpSocket {
fn as_inner(&self) -> &UdpSocketImp {
&self.inner
}
}
#[cfg(test)]
mod test {
use prelude::v1::*;
use sync::mpsc::channel;
use old_io::net::ip::*;
use old_io::test::*;
use old_io::{IoError, TimedOut, PermissionDenied, ShortWrite};
use super::*;
use thread;
// FIXME #11530 this fails on android because tests are run as root
#[cfg_attr(any(windows, target_os = "android"), ignore)]
#[test]
fn bind_error() {
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
match UdpSocket::bind(addr) {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind, PermissionDenied),
}
}
#[test]
fn socket_smoke_test_ip4() {
let server_ip = next_test_ip4();
let client_ip = next_test_ip4();
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move|| {
match UdpSocket::bind(client_ip) {
Ok(ref mut client) => {
rx1.recv().unwrap();
client.send_to(&[99], server_ip).unwrap()
}
Err(..) => panic!()
}
tx2.send(()).unwrap();
});
match UdpSocket::bind(server_ip) {
Ok(ref mut server) => {
tx1.send(()).unwrap();
let mut buf = [0];
match server.recv_from(&mut buf) {
Ok((nread, src)) => {
assert_eq!(nread, 1);
assert_eq!(buf[0], 99);
assert_eq!(src, client_ip);
}
Err(..) => panic!()
}
}
Err(..) => panic!()
}
rx2.recv().unwrap();
}
#[test]
fn socket_smoke_test_ip6() {
let server_ip = next_test_ip6();
let client_ip = next_test_ip6();
let (tx, rx) = channel::<()>();
let _t = thread::spawn(move|| {
match UdpSocket::bind(client_ip) {
Ok(ref mut client) => {
rx.recv().unwrap();
client.send_to(&[99], server_ip).unwrap()
}
Err(..) => panic!()
}
});
match UdpSocket::bind(server_ip) {
Ok(ref mut server) => {
tx.send(()).unwrap();
let mut buf = [0];
match server.recv_from(&mut buf) {
Ok((nread, src)) => {
assert_eq!(nread, 1);
assert_eq!(buf[0], 99);
assert_eq!(src, client_ip);
}
Err(..) => panic!()
}
}
Err(..) => panic!()
}
}
pub fn socket_name(addr: SocketAddr) {
let server = UdpSocket::bind(addr);
assert!(server.is_ok());
let mut server = server.unwrap();
// Make sure socket_name gives
// us the socket we binded to.
let so_name = server.socket_name();
assert!(so_name.is_ok());
assert_eq!(addr, so_name.unwrap());
}
#[test]
fn socket_name_ip4() {
socket_name(next_test_ip4());
}
#[test]
fn socket_name_ip6() {
socket_name(next_test_ip6());
}
#[test]
fn udp_clone_smoke() {
let addr1 = next_test_ip4();
let addr2 = next_test_ip4();
let mut sock1 = UdpSocket::bind(addr1).unwrap();
let sock2 = UdpSocket::bind(addr2).unwrap();
let _t = thread::spawn(move|| {
let mut sock2 = sock2;
let mut buf = [0, 0];
assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1)));
assert_eq!(buf[0], 1);
sock2.send_to(&[2], addr1).unwrap();
});
let sock3 = sock1.clone();
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move|| {
let mut sock3 = sock3;
rx1.recv().unwrap();
sock3.send_to(&[1], addr2).unwrap();
tx2.send(()).unwrap();
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
assert_eq!(sock1.recv_from(&mut buf), Ok((1, addr2)));
rx2.recv().unwrap();
}
#[test]
fn udp_clone_two_read() {
let addr1 = next_test_ip4();
let addr2 = next_test_ip4();
let mut sock1 = UdpSocket::bind(addr1).unwrap();
let sock2 = UdpSocket::bind(addr2).unwrap();
let (tx1, rx) = channel();
let tx2 = tx1.clone();
let _t = thread::spawn(move|| {
let mut sock2 = sock2;
sock2.send_to(&[1], addr1).unwrap();
rx.recv().unwrap();
sock2.send_to(&[2], addr1).unwrap();
rx.recv().unwrap();
});
let sock3 = sock1.clone();
let (done, rx) = channel();
let _t = thread::spawn(move|| {
let mut sock3 = sock3;
let mut buf = [0, 0];
sock3.recv_from(&mut buf).unwrap();
tx2.send(()).unwrap();
done.send(()).unwrap();
});
let mut buf = [0, 0];
sock1.recv_from(&mut buf).unwrap();
tx1.send(()).unwrap();
rx.recv().unwrap();
}
#[test]
fn udp_clone_two_write() {
let addr1 = next_test_ip4();
let addr2 = next_test_ip4();
let mut sock1 = UdpSocket::bind(addr1).unwrap();
let sock2 = UdpSocket::bind(addr2).unwrap();
let (tx, rx) = channel();
let (serv_tx, serv_rx) = channel();
let _t = thread::spawn(move|| {
let mut sock2 = sock2;
let mut buf = [0, 1];
rx.recv().unwrap();
match sock2.recv_from(&mut buf) {
Ok(..) => {}
Err(e) => panic!("failed receive: {}", e),
}
serv_tx.send(()).unwrap();
});
let sock3 = sock1.clone();
let (done, rx) = channel();
let tx2 = tx.clone();
let _t = thread::spawn(move|| {
let mut sock3 = sock3;
match sock3.send_to(&[1], addr2) {
Ok(..) => { let _ = tx2.send(()); }
Err(..) => {}
}
done.send(()).unwrap();
});
match sock1.send_to(&[2], addr2) {
Ok(..) => { let _ = tx.send(()); }
Err(..) => {}
}
drop(tx);
rx.recv().unwrap();
serv_rx.recv().unwrap();
}
#[cfg(not(windows))] // FIXME #17553
#[test]
fn recv_from_timeout() {
let addr1 = next_test_ip4();
let addr2 = next_test_ip4();
let mut a = UdpSocket::bind(addr1).unwrap();
let a2 = UdpSocket::bind(addr2).unwrap();
let (tx, rx) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move|| {
let mut a = a2;
assert_eq!(a.recv_from(&mut [0]), Ok((1, addr1)));
assert_eq!(a.send_to(&[0], addr1), Ok(()));
rx.recv().unwrap();
assert_eq!(a.send_to(&[0], addr1), Ok(()));
tx2.send(()).unwrap();
});
// Make sure that reads time out, but writes can continue
a.set_read_timeout(Some(20));
assert_eq!(a.recv_from(&mut [0]).err().unwrap().kind, TimedOut);
assert_eq!(a.recv_from(&mut [0]).err().unwrap().kind, TimedOut);
assert_eq!(a.send_to(&[0], addr2), Ok(()));
// Cloned handles should be able to block
let mut a2 = a.clone();
assert_eq!(a2.recv_from(&mut [0]), Ok((1, addr2)));
// Clearing the timeout should allow for receiving
a.set_timeout(None);
tx.send(()).unwrap();
assert_eq!(a2.recv_from(&mut [0]), Ok((1, addr2)));
// Make sure the child didn't die
rx2.recv().unwrap();
}
#[test]
fn send_to_timeout() {
let addr1 = next_test_ip4();
let addr2 = next_test_ip4();
let mut a = UdpSocket::bind(addr1).unwrap();
let _b = UdpSocket::bind(addr2).unwrap();
a.set_write_timeout(Some(1000));
for _ in 0..100 {
match a.send_to(&[0;4*1024], addr2) {
Ok(()) | Err(IoError { kind: ShortWrite(..), .. }) => {},
Err(IoError { kind: TimedOut, .. }) => break,
Err(e) => panic!("other error: {}", e),
}
}
}
}

View File

@ -1,141 +0,0 @@
// Copyright 2013 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.
//! Synchronous, in-memory pipes.
//!
//! Currently these aren't particularly useful, there only exists bindings
//! enough so that pipes can be created to child processes.
#![allow(missing_docs)]
use prelude::v1::*;
use old_io::{IoResult, Reader, Writer};
use libc;
use sync::Arc;
use sys_common;
use sys;
use sys::fs::FileDesc as FileDesc;
/// A synchronous, in-memory pipe.
pub struct PipeStream {
inner: Arc<FileDesc>
}
pub struct PipePair {
pub reader: PipeStream,
pub writer: PipeStream,
}
impl PipeStream {
/// Consumes a file descriptor to return a pipe stream that will have
/// synchronous, but non-blocking reads/writes. This is useful if the file
/// descriptor is acquired via means other than the standard methods.
///
/// This operation consumes ownership of the file descriptor and it will be
/// closed once the object is deallocated.
///
/// # Examples
///
/// ```{rust,no_run}
/// # #![feature(old_io, libc, io)]
/// # #![allow(unused_must_use)]
/// extern crate libc;
///
/// use std::old_io::*;
///
/// fn main() {
/// let mut pipe = PipeStream::open(libc::STDERR_FILENO);
/// pipe.write(b"Hello, stderr!");
/// }
/// ```
pub fn open(fd: libc::c_int) -> IoResult<PipeStream> {
Ok(PipeStream::from_filedesc(FileDesc::new(fd, true)))
}
// FIXME: expose this some other way
/// Wrap a FileDesc directly, taking ownership.
#[doc(hidden)]
pub fn from_filedesc(fd: FileDesc) -> PipeStream {
PipeStream { inner: Arc::new(fd) }
}
/// Creates a pair of in-memory OS pipes for a unidirectional communication
/// stream.
///
/// The structure returned contains a reader and writer I/O object. Data
/// written to the writer can be read from the reader.
///
/// # Errors
///
/// This function can fail to succeed if the underlying OS has run out of
/// available resources to allocate a new pipe.
pub fn pair() -> IoResult<PipePair> {
let (reader, writer) = try!(unsafe { sys::os::pipe() });
Ok(PipePair {
reader: PipeStream::from_filedesc(reader),
writer: PipeStream::from_filedesc(writer),
})
}
}
impl sys_common::AsInner<sys::fs::FileDesc> for PipeStream {
fn as_inner(&self) -> &sys::fs::FileDesc {
&*self.inner
}
}
impl Clone for PipeStream {
fn clone(&self) -> PipeStream {
PipeStream { inner: self.inner.clone() }
}
}
impl Reader for PipeStream {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
self.inner.read(buf)
}
}
impl Writer for PipeStream {
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
self.inner.write(buf)
}
}
#[cfg(test)]
mod test {
use prelude::v1::*;
use old_io::{Writer, Reader};
use sync::mpsc::channel;
use thread;
#[test]
fn partial_read() {
use os;
use old_io::pipe::PipeStream;
let (reader, writer) = unsafe { ::sys::os::pipe().unwrap() };
let out = PipeStream::open(writer.unwrap());
let mut input = PipeStream::open(reader.unwrap());
let (tx, rx) = channel();
let _t = thread::spawn(move|| {
let mut out = out;
out.write(&[10]).unwrap();
rx.recv().unwrap(); // don't close the pipe until the other read has finished
});
let mut buf = [0; 10];
input.read(&mut buf).unwrap();
tx.send(()).unwrap();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,130 +0,0 @@
// Copyright 2013 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.
//! Implementations of I/O traits for the IoResult type
//!
//! I/O constructors return option types to allow errors to be handled.
//! These implementations allow e.g. `IoResult<File>` to be used
//! as a `Reader` without unwrapping the result first.
use clone::Clone;
use result::Result::{Ok, Err};
use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle, IoResult};
impl<W: Writer> Writer for IoResult<W> {
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
match *self {
Ok(ref mut writer) => writer.write_all(buf),
Err(ref e) => Err((*e).clone())
}
}
fn flush(&mut self) -> IoResult<()> {
match *self {
Ok(ref mut writer) => writer.flush(),
Err(ref e) => Err(e.clone()),
}
}
}
impl<R: Reader> Reader for IoResult<R> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
match *self {
Ok(ref mut reader) => reader.read(buf),
Err(ref e) => Err(e.clone()),
}
}
}
impl<S: Seek> Seek for IoResult<S> {
fn tell(&self) -> IoResult<u64> {
match *self {
Ok(ref seeker) => seeker.tell(),
Err(ref e) => Err(e.clone()),
}
}
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
match *self {
Ok(ref mut seeker) => seeker.seek(pos, style),
Err(ref e) => Err(e.clone())
}
}
}
impl<A: Acceptor, L: Listener<A>> Listener<A> for IoResult<L> {
fn listen(self) -> IoResult<A> {
match self {
Ok(listener) => listener.listen(),
Err(e) => Err(e),
}
}
}
impl<A: Acceptor> Acceptor for IoResult<A> {
type Connection = A::Connection;
fn accept(&mut self) -> IoResult<A::Connection> {
match *self {
Ok(ref mut acceptor) => acceptor.accept(),
Err(ref e) => Err(e.clone()),
}
}
}
#[cfg(test)]
mod test {
use prelude::v1::*;
use super::super::mem::*;
use old_io::{self, Reader, Writer};
#[test]
fn test_option_writer() {
let mut writer: old_io::IoResult<Vec<u8>> = Ok(Vec::new());
writer.write_all(&[0, 1, 2]).unwrap();
writer.flush().unwrap();
assert_eq!(writer.unwrap(), [0, 1, 2]);
}
#[test]
fn test_option_writer_error() {
let mut writer: old_io::IoResult<Vec<u8>> =
Err(old_io::standard_error(old_io::EndOfFile));
match writer.write_all(&[0, 0, 0]) {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind, old_io::EndOfFile),
}
match writer.flush() {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind, old_io::EndOfFile),
}
}
#[test]
fn test_option_reader() {
let mut reader: old_io::IoResult<MemReader> =
Ok(MemReader::new(vec!(0, 1, 2, 3)));
let mut buf = [0, 0];
reader.read(&mut buf).unwrap();
let b: &[_] = &[0, 1];
assert_eq!(buf, b);
}
#[test]
fn test_option_reader_error() {
let mut reader: old_io::IoResult<MemReader> =
Err(old_io::standard_error(old_io::EndOfFile));
let mut buf = [];
match reader.read(&mut buf) {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind, old_io::EndOfFile),
}
}
}

View File

@ -1,540 +0,0 @@
// Copyright 2013 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.
//! Non-blocking access to stdin, stdout, and stderr.
//!
//! This module provides bindings to the local event loop's TTY interface, using it
//! to offer synchronous but non-blocking versions of stdio. These handles can be
//! inspected for information about terminal dimensions or for related information
//! about the stream or terminal to which it is attached.
//!
//! # Examples
//!
//! ```rust
//! # #![feature(old_io)]
//! # #![allow(unused_must_use)]
//! use std::old_io;
//! use std::old_io::*;
//!
//! let mut out = old_io::stdout();
//! out.write_all(b"Hello, world!");
//! ```
use self::StdSource::*;
use boxed;
use boxed::Box;
use cell::RefCell;
use clone::Clone;
use fmt;
use old_io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer,
standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
use marker::{Sync, Send};
use libc;
use mem;
use option::Option;
use option::Option::{Some, None};
use ops::{Deref, DerefMut, FnOnce};
use ptr;
use result::Result::{Ok, Err};
use rt;
use string::String;
use sys::{fs, tty};
use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT};
use usize;
use vec::Vec;
// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
// case pipe also doesn't work, but magically file does!
enum StdSource {
TTY(tty::TTY),
File(fs::FileDesc),
}
fn src<T, F>(fd: libc::c_int, _readable: bool, f: F) -> T where
F: FnOnce(StdSource) -> T,
{
match tty::TTY::new(fd) {
Ok(tty) => f(TTY(tty)),
Err(_) => f(File(fs::FileDesc::new(fd, false))),
}
}
thread_local! {
static LOCAL_STDOUT: RefCell<Option<Box<Writer + Send>>> = {
RefCell::new(None)
}
}
struct RaceBox(BufferedReader<StdReader>);
unsafe impl Send for RaceBox {}
unsafe impl Sync for RaceBox {}
/// A synchronized wrapper around a buffered reader from stdin
#[derive(Clone)]
pub struct StdinReader {
inner: Arc<Mutex<RaceBox>>,
}
unsafe impl Send for StdinReader {}
unsafe impl Sync for StdinReader {}
/// A guard for exclusive access to `StdinReader`'s internal `BufferedReader`.
pub struct StdinReaderGuard<'a> {
inner: MutexGuard<'a, RaceBox>,
}
impl<'a> Deref for StdinReaderGuard<'a> {
type Target = BufferedReader<StdReader>;
fn deref(&self) -> &BufferedReader<StdReader> {
&self.inner.0
}
}
impl<'a> DerefMut for StdinReaderGuard<'a> {
fn deref_mut(&mut self) -> &mut BufferedReader<StdReader> {
&mut self.inner.0
}
}
impl StdinReader {
/// Locks the `StdinReader`, granting the calling thread exclusive access
/// to the underlying `BufferedReader`.
///
/// This provides access to methods like `chars` and `lines`.
///
/// # Examples
///
/// ```
/// # #![feature(old_io)]
/// use std::old_io;
/// use std::old_io::*;
///
/// let mut stdin = old_io::stdin();
/// for line in stdin.lock().lines() {
/// println!("{}", line.unwrap());
/// }
/// ```
pub fn lock<'a>(&'a mut self) -> StdinReaderGuard<'a> {
StdinReaderGuard {
inner: self.inner.lock().unwrap()
}
}
/// Like `Buffer::read_line`.
///
/// The read is performed atomically - concurrent read calls in other
/// threads will not interleave with this one.
pub fn read_line(&mut self) -> IoResult<String> {
self.inner.lock().unwrap().0.read_line()
}
/// Like `Buffer::read_until`.
///
/// The read is performed atomically - concurrent read calls in other
/// threads will not interleave with this one.
pub fn read_until(&mut self, byte: u8) -> IoResult<Vec<u8>> {
self.inner.lock().unwrap().0.read_until(byte)
}
/// Like `Buffer::read_char`.
///
/// The read is performed atomically - concurrent read calls in other
/// threads will not interleave with this one.
pub fn read_char(&mut self) -> IoResult<char> {
self.inner.lock().unwrap().0.read_char()
}
}
impl Reader for StdinReader {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
self.inner.lock().unwrap().0.read(buf)
}
// We have to manually delegate all of these because the default impls call
// read more than once and we don't want those calls to interleave (or
// incur the costs of repeated locking).
fn read_at_least(&mut self, min: usize, buf: &mut [u8]) -> IoResult<usize> {
self.inner.lock().unwrap().0.read_at_least(min, buf)
}
fn push_at_least(&mut self, min: usize, len: usize, buf: &mut Vec<u8>) -> IoResult<usize> {
self.inner.lock().unwrap().0.push_at_least(min, len, buf)
}
fn read_to_end(&mut self) -> IoResult<Vec<u8>> {
self.inner.lock().unwrap().0.read_to_end()
}
fn read_le_uint_n(&mut self, nbytes: usize) -> IoResult<u64> {
self.inner.lock().unwrap().0.read_le_uint_n(nbytes)
}
fn read_be_uint_n(&mut self, nbytes: usize) -> IoResult<u64> {
self.inner.lock().unwrap().0.read_be_uint_n(nbytes)
}
}
/// Creates a new handle to the stdin of the current process.
///
/// The returned handle is a wrapper around a global `BufferedReader` shared
/// by all threads. If buffered access is not desired, the `stdin_raw` function
/// is provided to provided unbuffered access to stdin.
///
/// See `stdout()` for more notes about this function.
pub fn stdin() -> StdinReader {
// We're following the same strategy as kimundi's lazy_static library
static mut STDIN: *mut StdinReader = 0 as *mut StdinReader;
static ONCE: Once = ONCE_INIT;
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.
let stdin = if cfg!(windows) {
BufferedReader::with_capacity(8 * 1024, stdin_raw())
} else {
BufferedReader::new(stdin_raw())
};
let stdin = StdinReader {
inner: Arc::new(Mutex::new(RaceBox(stdin)))
};
STDIN = boxed::into_raw(box stdin);
// Make sure to free it at exit
let _ = rt::at_exit(|| {
Box::from_raw(STDIN);
STDIN = ptr::null_mut();
});
});
(*STDIN).clone()
}
}
/// Creates a new non-blocking handle to the stdin of the current process.
///
/// Unlike `stdin()`, the returned reader is *not* a buffered reader.
///
/// See `stdout()` for more notes about this function.
pub fn stdin_raw() -> StdReader {
src(libc::STDIN_FILENO, true, |src| StdReader { inner: src })
}
/// Creates a line-buffered handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
///
/// Care should be taken when creating multiple handles to an output stream for
/// a single process. While usage is still safe, the output may be surprising if
/// no synchronization is performed to ensure a sane output.
pub fn stdout() -> LineBufferedWriter<StdWriter> {
LineBufferedWriter::new(stdout_raw())
}
/// Creates an unbuffered handle to the stdout of the current process
///
/// See notes in `stdout()` for more information.
pub fn stdout_raw() -> StdWriter {
src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src })
}
/// Creates a line-buffered handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> LineBufferedWriter<StdWriter> {
LineBufferedWriter::new(stderr_raw())
}
/// Creates an unbuffered handle to the stderr of the current process
///
/// See notes in `stdout()` for more information.
pub fn stderr_raw() -> StdWriter {
src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src })
}
/// Resets the task-local stdout handle to the specified writer
///
/// This will replace the current task's stdout handle, returning the old
/// handle. All future calls to `print` and friends will emit their output to
/// this specified handle.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stdout stream.
pub fn set_stdout(stdout: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
let mut new = Some(stdout);
LOCAL_STDOUT.with(|slot| {
mem::replace(&mut *slot.borrow_mut(), new.take())
}).and_then(|mut s| {
let _ = s.flush();
Some(s)
})
}
/// Resets the task-local stderr handle to the specified writer
///
/// This will replace the current task's stderr handle, returning the old
/// handle. Currently, the stderr handle is used for printing panic messages
/// during task panic.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stderr stream.
#[unstable(feature = "old_io")]
#[deprecated(since = "1.0.0", reason = "replaced with std::io::set_panic")]
pub fn set_stderr(_stderr: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
None
}
// Helper to access the local task's stdout handle
//
// Note that this is not a safe function to expose because you can create an
// aliased pointer very easily:
//
// with_task_stdout(|io1| {
// with_task_stdout(|io2| {
// // io1 aliases io2
// })
// })
fn with_task_stdout<F>(f: F) where F: FnOnce(&mut Writer) -> IoResult<()> {
let mut my_stdout: Box<Writer + Send> = LOCAL_STDOUT.with(|slot| {
slot.borrow_mut().take()
}).unwrap_or_else(|| {
box stdout()
});
let result = f(&mut *my_stdout);
let mut var = Some(my_stdout);
LOCAL_STDOUT.with(|slot| {
*slot.borrow_mut() = var.take();
});
match result {
Ok(()) => {}
Err(e) => panic!("failed printing to stdout: {:?}", e),
}
}
/// Flushes the local task's stdout handle.
///
/// By default, this stream is a line-buffering stream, so flushing may be
/// necessary to ensure that all output is printed to the screen (if there are
/// no newlines printed).
///
/// Note that logging macros do not use this stream. Using the logging macros
/// will emit output to stderr, and while they are line buffered the log
/// messages are always terminated in a newline (no need to flush).
pub fn flush() {
with_task_stdout(|io| io.flush())
}
/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
with_task_stdout(|io| io.write_all(s.as_bytes()))
}
/// Prints a string to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
with_task_stdout(|io| {
io.write_all(s.as_bytes()).and_then(|()| io.write_all(&[b'\n']))
})
}
/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn print_args(fmt: fmt::Arguments) {
with_task_stdout(|io| write!(io, "{}", fmt))
}
/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn println_args(fmt: fmt::Arguments) {
with_task_stdout(|io| writeln!(io, "{}", fmt))
}
/// Representation of a reader of a standard input stream
pub struct StdReader {
inner: StdSource
}
impl StdReader {
/// Returns whether this stream is attached to a TTY instance or not.
pub fn isatty(&self) -> bool {
match self.inner {
TTY(..) => true,
File(..) => false,
}
}
}
impl Reader for StdReader {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
let ret = match self.inner {
TTY(ref mut tty) => {
// Flush the task-local stdout so that weird issues like a
// print!'d prompt not being shown until after the user hits
// enter.
flush();
tty.read(buf).map(|i| i as usize)
},
File(ref mut file) => file.read(buf).map(|i| i as usize),
};
match ret {
// When reading a piped stdin, libuv will return 0-length reads when
// stdin reaches EOF. For pretty much all other streams it will
// return an actual EOF error, but apparently for stdin it's a
// little different. Hence, here we convert a 0 length read to an
// end-of-file indicator so the caller knows to stop reading.
Ok(0) => { Err(standard_error(EndOfFile)) }
ret @ Ok(..) | ret @ Err(..) => ret,
}
}
}
/// Representation of a writer to a standard output stream
pub struct StdWriter {
inner: StdSource
}
unsafe impl Send for StdWriter {}
unsafe impl Sync for StdWriter {}
impl StdWriter {
/// Gets the size of this output window, if possible. This is typically used
/// when the writer is attached to something like a terminal, this is used
/// to fetch the dimensions of the terminal.
///
/// If successful, returns `Ok((width, height))`.
///
/// # Error
///
/// This function will return an error if the output stream is not actually
/// connected to a TTY instance, or if querying the TTY instance fails.
pub fn winsize(&mut self) -> IoResult<(isize, isize)> {
match self.inner {
TTY(ref mut tty) => {
tty.get_winsize()
}
File(..) => {
Err(IoError {
kind: OtherIoError,
desc: "stream is not a tty",
detail: None,
})
}
}
}
/// Controls whether this output stream is a "raw stream" or simply a normal
/// stream.
///
/// # Error
///
/// This function will return an error if the output stream is not actually
/// connected to a TTY instance, or if querying the TTY instance fails.
pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
match self.inner {
TTY(ref mut tty) => {
tty.set_raw(raw)
}
File(..) => {
Err(IoError {
kind: OtherIoError,
desc: "stream is not a tty",
detail: None,
})
}
}
}
/// Returns whether this stream is attached to a TTY instance or not.
pub fn isatty(&self) -> bool {
match self.inner {
TTY(..) => true,
File(..) => false,
}
}
}
impl Writer for StdWriter {
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
// As with stdin on windows, stdout often can't handle writes of large
// sizes. For an example, see #14940. For this reason, chunk the output
// buffer on windows, but 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
let max_size = if cfg!(windows) {8192} else {usize::MAX};
for chunk in buf.chunks(max_size) {
try!(match self.inner {
TTY(ref mut tty) => tty.write(chunk),
File(ref mut file) => file.write(chunk),
})
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use prelude::v1::*;
use super::*;
use sync::mpsc::channel;
use thread;
#[test]
fn smoke() {
// Just make sure we can acquire handles
stdin();
stdout();
stderr();
}
}

View File

@ -1,188 +0,0 @@
// Copyright 2013 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.
//! Temporary files and directories
#![allow(deprecated)] // rand
use env;
use iter::Iterator;
use old_io::{fs, IoError, IoErrorKind, IoResult};
use old_io;
use ops::Drop;
use option::Option::{None, Some};
use option::Option;
use old_path::{Path, GenericPath};
use rand::{Rng, thread_rng};
use result::Result::{Ok, Err};
use string::String;
/// A wrapper for a path to temporary directory implementing automatic
/// scope-based deletion.
///
/// # Examples
///
/// ```no_run
/// # #![feature(old_io, old_path)]
/// use std::old_io::*;
/// use std::old_path::{Path, GenericPath};
///
/// {
/// // create a temporary directory
/// let tmpdir = match TempDir::new("myprefix") {
/// Ok(dir) => dir,
/// Err(e) => panic!("couldn't create temporary directory: {}", e)
/// };
///
/// // get the path of the temporary directory without affecting the wrapper
/// let tmppath = tmpdir.path();
///
/// println!("The path of temporary directory is {}", tmppath.display());
///
/// // the temporary directory is automatically removed when tmpdir goes
/// // out of scope at the end of the block
/// }
/// {
/// // create a temporary directory, this time using a custom path
/// let tmpdir = match TempDir::new_in(&Path::new("/tmp/best/custom/path"), "myprefix") {
/// Ok(dir) => dir,
/// Err(e) => panic!("couldn't create temporary directory: {}", e)
/// };
///
/// // get the path of the temporary directory and disable automatic deletion in the wrapper
/// let tmppath = tmpdir.into_inner();
///
/// println!("The path of the not-so-temporary directory is {}", tmppath.display());
///
/// // the temporary directory is not removed here
/// // because the directory is detached from the wrapper
/// }
/// {
/// // create a temporary directory
/// let tmpdir = match TempDir::new("myprefix") {
/// Ok(dir) => dir,
/// Err(e) => panic!("couldn't create temporary directory: {}", e)
/// };
///
/// // close the temporary directory manually and check the result
/// match tmpdir.close() {
/// Ok(_) => println!("success!"),
/// Err(e) => panic!("couldn't remove temporary directory: {}", e)
/// };
/// }
/// ```
pub struct TempDir {
path: Option<Path>,
disarmed: bool
}
// How many times should we (re)try finding an unused random name? It should be
// enough that an attacker will run out of luck before we run out of patience.
const NUM_RETRIES: u32 = 1 << 31;
// How many characters should we include in a random file name? It needs to
// be enough to dissuade an attacker from trying to preemptively create names
// of that length, but not so huge that we unnecessarily drain the random number
// generator of entropy.
const NUM_RAND_CHARS: usize = 12;
impl TempDir {
/// Attempts to make a temporary directory inside of `tmpdir` whose name
/// will have the prefix `prefix`. The directory will be automatically
/// deleted once the returned wrapper is destroyed.
///
/// If no directory can be created, `Err` is returned.
#[allow(deprecated)]
pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult<TempDir> {
if !tmpdir.is_absolute() {
let cur_dir = ::env::current_dir().unwrap();
let cur_dir = Path::new(cur_dir.to_str().unwrap());
return TempDir::new_in(&cur_dir.join(tmpdir), prefix);
}
let mut rng = thread_rng();
for _ in 0..NUM_RETRIES {
let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect();
let leaf = if prefix.len() > 0 {
format!("{}.{}", prefix, suffix)
} else {
// If we're given an empty string for a prefix, then creating a
// directory starting with "." would lead to it being
// semi-invisible on some systems.
suffix
};
let path = tmpdir.join(leaf);
match fs::mkdir(&path, old_io::USER_RWX) {
Ok(_) => return Ok(TempDir { path: Some(path), disarmed: false }),
Err(IoError{kind:IoErrorKind::PathAlreadyExists,..}) => (),
Err(e) => return Err(e)
}
}
return Err(IoError{
kind: IoErrorKind::PathAlreadyExists,
desc:"Exhausted",
detail: None});
}
/// Attempts to make a temporary directory inside of `os::tmpdir()` whose
/// name will have the prefix `prefix`. The directory will be automatically
/// deleted once the returned wrapper is destroyed.
///
/// If no directory can be created, `Err` is returned.
#[allow(deprecated)]
pub fn new(prefix: &str) -> IoResult<TempDir> {
let tmp = Path::new(::env::temp_dir().to_str().unwrap());
TempDir::new_in(&tmp, prefix)
}
/// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
/// This discards the wrapper so that the automatic deletion of the
/// temporary directory is prevented.
pub fn into_inner(self) -> Path {
let mut tmpdir = self;
tmpdir.path.take().unwrap()
}
/// Access the wrapped `std::path::Path` to the temporary directory.
pub fn path<'a>(&'a self) -> &'a Path {
self.path.as_ref().unwrap()
}
/// Close and remove the temporary directory
///
/// Although `TempDir` removes the directory on drop, in the destructor
/// any errors are ignored. To detect errors cleaning up the temporary
/// directory, call `close` instead.
pub fn close(mut self) -> IoResult<()> {
self.cleanup_dir()
}
fn cleanup_dir(&mut self) -> IoResult<()> {
assert!(!self.disarmed);
self.disarmed = true;
match self.path {
Some(ref p) => {
fs::rmdir_recursive(p)
}
None => Ok(())
}
}
}
impl Drop for TempDir {
fn drop(&mut self) {
if !self.disarmed {
let _ = self.cleanup_dir();
}
}
}
// the tests for this module need to change the path using change_dir,
// and this doesn't play nicely with other tests so these unit tests are located
// in src/test/run-pass/tempfile.rs

View File

@ -1,177 +0,0 @@
// Copyright 2013 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.
//! Various utility functions useful for writing I/O tests
use prelude::v1::*;
use env;
use libc;
use old_io::net::ip::*;
use old_path::{Path, GenericPath};
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
static NEXT_OFFSET: AtomicUsize = ATOMIC_USIZE_INIT;
base_port() + NEXT_OFFSET.fetch_add(1, Ordering::Relaxed) as u16
}
// iOS has a pretty long tmpdir path which causes pipe creation
// to like: invalid argument: path must be smaller than SUN_LEN
fn next_test_unix_socket() -> String {
static COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
// base port and pid are an attempt to be unique between multiple
// test-runners of different configurations running on one
// buildbot, the count is to be unique within this executable.
format!("rust-test-unix-path-{}-{}-{}",
base_port(),
unsafe {libc::getpid()},
COUNT.fetch_add(1, Ordering::Relaxed))
}
/// Get a temporary path which could be the location of a unix socket
#[cfg(not(target_os = "ios"))]
#[allow(deprecated)]
pub fn next_test_unix() -> Path {
let string = next_test_unix_socket();
if cfg!(unix) {
Path::new(::env::temp_dir().to_str().unwrap()).join(string)
} else {
Path::new(format!("{}{}", r"\\.\pipe\", string))
}
}
/// Get a temporary path which could be the location of a unix socket
#[cfg(target_os = "ios")]
pub fn next_test_unix() -> Path {
Path::new(format!("/var/tmp/{}", next_test_unix_socket()))
}
/// Get a unique IPv4 localhost:port pair starting at 9600
pub fn next_test_ip4() -> SocketAddr {
SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: next_test_port() }
}
/// Get a unique IPv6 localhost:port pair starting at 9600
pub fn next_test_ip6() -> SocketAddr {
SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), port: next_test_port() }
}
/*
XXX: Welcome to MegaHack City.
The bots run multiple builds at the same time, and these builds
all want to use ports. This function figures out which workspace
it is running in and assigns a port range based on it.
*/
fn base_port() -> u16 {
let base = 9600;
let range = 1000;
let bases = [
("32-opt", base + range * 1),
("32-nopt", base + range * 2),
("64-opt", base + range * 3),
("64-nopt", base + range * 4),
("64-opt-vg", base + range * 5),
("all-opt", base + range * 6),
("snap3", base + range * 7),
("dist", base + range * 8)
];
// FIXME (#9639): This needs to handle non-utf8 paths
let path = env::current_dir().unwrap();
let path_s = path.to_str().unwrap();
let mut final_base = base;
for &(dir, base) in &bases {
if path_s.contains(dir) {
final_base = base;
break;
}
}
return final_base;
}
/// Raises the file descriptor limit when running tests if necessary
pub fn raise_fd_limit() {
unsafe { darwin_fd_limit::raise_fd_limit() }
}
/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X defaults the rlimit
/// maxfiles to 256/unlimited. The default soft limit of 256 ends up being far too low for our
/// multithreaded scheduler testing, depending on the number of cores available.
///
/// This fixes issue #7772.
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[allow(non_camel_case_types)]
mod darwin_fd_limit {
use libc;
type rlim_t = libc::uint64_t;
#[repr(C)]
struct rlimit {
rlim_cur: rlim_t,
rlim_max: rlim_t
}
extern {
// name probably doesn't need to be mut, but the C function doesn't specify const
fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint,
oldp: *mut libc::c_void, oldlenp: *mut libc::size_t,
newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int;
fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int;
fn setrlimit(resource: libc::c_int, rlp: *const rlimit) -> libc::c_int;
}
static CTL_KERN: libc::c_int = 1;
static KERN_MAXFILESPERPROC: libc::c_int = 29;
static RLIMIT_NOFILE: libc::c_int = 8;
pub unsafe fn raise_fd_limit() {
// The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
// sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
use ptr::null_mut;
use mem::size_of_val;
use io;
// Fetch the kern.maxfilesperproc value
let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
let mut maxfiles: libc::c_int = 0;
let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
if sysctl(&mut mib[0], 2, &mut maxfiles as *mut libc::c_int as *mut libc::c_void, &mut size,
null_mut(), 0) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling sysctl: {}", err);
}
// Fetch the current resource limits
let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling getrlimit: {}", err);
}
// Bump the soft limit to the smaller of kern.maxfilesperproc and the hard limit
rlim.rlim_cur = ::cmp::min(maxfiles as rlim_t, rlim.rlim_max);
// Set our newly-increased resource limit
if setrlimit(RLIMIT_NOFILE, &rlim) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling setrlimit: {}", err);
}
}
}
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod darwin_fd_limit {
pub unsafe fn raise_fd_limit() {}
}

View File

@ -1,488 +0,0 @@
// Copyright 2013 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.
//! Synchronous Timers
//!
//! This module exposes the functionality to create timers, block the current task,
//! and create receivers which will receive notifications after a period of time.
// FIXME: These functions take Durations but only pass ms to the backend impls.
use boxed::Box;
use sync::mpsc::{Receiver, Sender, channel};
use time::Duration;
use old_io::IoResult;
use sys::timer::Callback;
use sys::timer::Timer as TimerImp;
/// A synchronous timer object
///
/// Values of this type can be used to put the current task to sleep for a
/// period of time. Handles to this timer can also be created in the form of
/// receivers which will receive notifications over time.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, std_misc)]
/// # fn foo() {
/// use std::old_io::Timer;
/// use std::time::Duration;
///
/// let mut timer = Timer::new().unwrap();
/// timer.sleep(Duration::milliseconds(10)); // block the task for awhile
///
/// let timeout = timer.oneshot(Duration::milliseconds(10));
/// // do some work
/// timeout.recv().unwrap(); // wait for the timeout to expire
///
/// let periodic = timer.periodic(Duration::milliseconds(10));
/// loop {
/// periodic.recv().unwrap();
/// // this loop is only executed once every 10ms
/// }
/// # }
/// ```
///
/// If only sleeping is necessary, then a convenience API is provided through
/// the `old_io::timer` module.
///
/// ```
/// # #![feature(old_io, std_misc)]
/// # fn foo() {
/// use std::old_io::timer;
/// use std::time::Duration;
///
/// // Put this task to sleep for 5 seconds
/// timer::sleep(Duration::seconds(5));
/// # }
/// ```
pub struct Timer {
inner: TimerImp,
}
struct TimerCallback { tx: Sender<()> }
/// Sleep the current task for the specified duration.
///
/// When provided a zero or negative `duration`, the function will
/// return immediately.
pub fn sleep(duration: Duration) {
let timer = Timer::new();
let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");
timer.sleep(duration)
}
impl Timer {
/// Creates a new timer which can be used to put the current task to sleep
/// for a number of milliseconds, or to possibly create channels which will
/// get notified after an amount of time has passed.
pub fn new() -> IoResult<Timer> {
TimerImp::new().map(|t| Timer { inner: t })
}
/// Blocks the current task for the specified duration.
///
/// Note that this function will cause any other receivers for this timer to
/// be invalidated (the other end will be closed).
///
/// When provided a zero or negative `duration`, the function will
/// return immediately.
pub fn sleep(&mut self, duration: Duration) {
// Short-circuit the timer backend for 0 duration
let ms = in_ms_u64(duration);
if ms == 0 { return }
self.inner.sleep(ms);
}
/// Creates a oneshot receiver which will have a notification sent when
/// the specified duration has elapsed.
///
/// This does *not* block the current task, but instead returns immediately.
///
/// Note that this invalidates any previous receiver which has been created
/// by this timer, and that the returned receiver will be invalidated once
/// the timer is destroyed (when it falls out of scope). In particular, if
/// this is called in method-chaining style, the receiver will be
/// invalidated at the end of that statement, and all `recv` calls will
/// fail.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, std_misc)]
/// use std::old_io::Timer;
/// use std::time::Duration;
///
/// let mut timer = Timer::new().unwrap();
/// let ten_milliseconds = timer.oneshot(Duration::milliseconds(10));
///
/// for _ in 0..100 { /* do work */ }
///
/// // blocks until 10 ms after the `oneshot` call
/// ten_milliseconds.recv().unwrap();
/// ```
///
/// ```
/// # #![feature(old_io, std_misc)]
/// use std::old_io::Timer;
/// use std::time::Duration;
///
/// // Incorrect, method chaining-style:
/// let mut five_ms = Timer::new().unwrap().oneshot(Duration::milliseconds(5));
/// // The timer object was destroyed, so this will always fail:
/// // five_ms.recv().unwrap()
/// ```
///
/// When provided a zero or negative `duration`, the message will
/// be sent immediately.
pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> {
let (tx, rx) = channel();
// Short-circuit the timer backend for 0 duration
if in_ms_u64(duration) != 0 {
self.inner.oneshot(in_ms_u64(duration), Box::new(TimerCallback { tx: tx }));
} else {
tx.send(()).unwrap();
}
return rx
}
/// Creates a receiver which will have a continuous stream of notifications
/// being sent each time the specified duration has elapsed.
///
/// This does *not* block the current task, but instead returns
/// immediately. The first notification will not be received immediately,
/// but rather after the first duration.
///
/// Note that this invalidates any previous receiver which has been created
/// by this timer, and that the returned receiver will be invalidated once
/// the timer is destroyed (when it falls out of scope). In particular, if
/// this is called in method-chaining style, the receiver will be
/// invalidated at the end of that statement, and all `recv` calls will
/// fail.
///
/// # Examples
///
/// ```
/// # #![feature(old_io, std_misc)]
/// use std::old_io::Timer;
/// use std::time::Duration;
///
/// let mut timer = Timer::new().unwrap();
/// let ten_milliseconds = timer.periodic(Duration::milliseconds(10));
///
/// for _ in 0..100 { /* do work */ }
///
/// // blocks until 10 ms after the `periodic` call
/// ten_milliseconds.recv().unwrap();
///
/// for _ in 0..100 { /* do work */ }
///
/// // blocks until 20 ms after the `periodic` call (*not* 10ms after the
/// // previous `recv`)
/// ten_milliseconds.recv().unwrap();
/// ```
///
/// ```
/// # #![feature(old_io, std_misc)]
/// use std::old_io::Timer;
/// use std::time::Duration;
///
/// // Incorrect, method chaining-style.
/// let mut five_ms = Timer::new().unwrap().periodic(Duration::milliseconds(5));
/// // The timer object was destroyed, so this will always fail:
/// // five_ms.recv().unwrap()
/// ```
///
/// When provided a zero or negative `duration`, the messages will
/// be sent without delay.
pub fn periodic(&mut self, duration: Duration) -> Receiver<()> {
let ms = in_ms_u64(duration);
// FIXME: The backend implementations don't ever send a message
// if given a 0 ms duration. Temporarily using 1ms. It's
// not clear what use a 0ms period is anyway...
let ms = if ms == 0 { 1 } else { ms };
let (tx, rx) = channel();
self.inner.period(ms, Box::new(TimerCallback { tx: tx }));
return rx
}
}
impl Callback for TimerCallback {
fn call(&mut self) {
let _ = self.tx.send(());
}
}
fn in_ms_u64(d: Duration) -> u64 {
let ms = d.num_milliseconds();
if ms < 0 { return 0 };
return ms as u64;
}
#[cfg(test)]
mod test {
use super::Timer;
use thread;
use time::Duration;
#[test]
fn test_timer_send() {
let mut timer = Timer::new().unwrap();
thread::spawn(move || timer.sleep(Duration::milliseconds(1)));
}
#[test]
fn test_io_timer_sleep_simple() {
let mut timer = Timer::new().unwrap();
timer.sleep(Duration::milliseconds(1));
}
#[test]
fn test_io_timer_sleep_oneshot() {
let mut timer = Timer::new().unwrap();
timer.oneshot(Duration::milliseconds(1)).recv().unwrap();
}
#[test]
fn test_io_timer_sleep_oneshot_forget() {
let mut timer = Timer::new().unwrap();
timer.oneshot(Duration::milliseconds(100000000));
}
#[test]
fn oneshot_twice() {
let mut timer = Timer::new().unwrap();
let rx1 = timer.oneshot(Duration::milliseconds(10000));
let rx = timer.oneshot(Duration::milliseconds(1));
rx.recv().unwrap();
assert!(rx1.recv().is_err());
}
#[test]
fn test_io_timer_oneshot_then_sleep() {
let mut timer = Timer::new().unwrap();
let rx = timer.oneshot(Duration::milliseconds(100000000));
timer.sleep(Duration::milliseconds(1)); // this should invalidate rx
assert!(rx.recv().is_err());
}
#[test]
fn test_io_timer_sleep_periodic() {
let mut timer = Timer::new().unwrap();
let rx = timer.periodic(Duration::milliseconds(1));
rx.recv().unwrap();
rx.recv().unwrap();
rx.recv().unwrap();
}
#[test]
fn test_io_timer_sleep_periodic_forget() {
let mut timer = Timer::new().unwrap();
timer.periodic(Duration::milliseconds(100000000));
}
#[test]
fn test_io_timer_sleep_standalone() {
super::sleep(Duration::milliseconds(1))
}
#[test]
fn oneshot() {
let mut timer = Timer::new().unwrap();
let rx = timer.oneshot(Duration::milliseconds(1));
rx.recv().unwrap();
assert!(rx.recv().is_err());
let rx = timer.oneshot(Duration::milliseconds(1));
rx.recv().unwrap();
assert!(rx.recv().is_err());
}
#[test]
fn test_override() {
let mut timer = Timer::new().unwrap();
let orx = timer.oneshot(Duration::milliseconds(100));
let prx = timer.periodic(Duration::milliseconds(100));
timer.sleep(Duration::milliseconds(1));
assert!(orx.recv().is_err());
assert!(prx.recv().is_err());
timer.oneshot(Duration::milliseconds(1)).recv().unwrap();
}
#[test]
fn period() {
let mut timer = Timer::new().unwrap();
let rx = timer.periodic(Duration::milliseconds(1));
rx.recv().unwrap();
rx.recv().unwrap();
let rx2 = timer.periodic(Duration::milliseconds(1));
rx2.recv().unwrap();
rx2.recv().unwrap();
}
#[test]
fn sleep() {
let mut timer = Timer::new().unwrap();
timer.sleep(Duration::milliseconds(1));
timer.sleep(Duration::milliseconds(1));
}
#[test]
#[should_panic]
fn oneshot_fail() {
let mut timer = Timer::new().unwrap();
let _rx = timer.oneshot(Duration::milliseconds(1));
panic!();
}
#[test]
#[should_panic]
fn period_fail() {
let mut timer = Timer::new().unwrap();
let _rx = timer.periodic(Duration::milliseconds(1));
panic!();
}
#[test]
#[should_panic]
fn normal_fail() {
let _timer = Timer::new().unwrap();
panic!();
}
#[test]
fn closing_channel_during_drop_doesnt_kill_everything() {
// see issue #10375
let mut timer = Timer::new().unwrap();
let timer_rx = timer.periodic(Duration::milliseconds(1000));
thread::spawn(move|| {
let _ = timer_rx.recv();
});
// when we drop the TimerWatcher we're going to destroy the channel,
// which must wake up the task on the other end
}
#[test]
fn reset_doesnt_switch_tasks() {
// similar test to the one above.
let mut timer = Timer::new().unwrap();
let timer_rx = timer.periodic(Duration::milliseconds(1000));
thread::spawn(move|| {
let _ = timer_rx.recv();
});
timer.oneshot(Duration::milliseconds(1));
}
#[test]
fn reset_doesnt_switch_tasks2() {
// similar test to the one above.
let mut timer = Timer::new().unwrap();
let timer_rx = timer.periodic(Duration::milliseconds(1000));
thread::spawn(move|| {
let _ = timer_rx.recv();
});
timer.sleep(Duration::milliseconds(1));
}
#[test]
fn sender_goes_away_oneshot() {
let rx = {
let mut timer = Timer::new().unwrap();
timer.oneshot(Duration::milliseconds(1000))
};
assert!(rx.recv().is_err());
}
#[test]
fn sender_goes_away_period() {
let rx = {
let mut timer = Timer::new().unwrap();
timer.periodic(Duration::milliseconds(1000))
};
assert!(rx.recv().is_err());
}
#[test]
fn receiver_goes_away_oneshot() {
let mut timer1 = Timer::new().unwrap();
timer1.oneshot(Duration::milliseconds(1));
let mut timer2 = Timer::new().unwrap();
// while sleeping, the previous timer should fire and not have its
// callback do something terrible.
timer2.sleep(Duration::milliseconds(2));
}
#[test]
fn receiver_goes_away_period() {
let mut timer1 = Timer::new().unwrap();
timer1.periodic(Duration::milliseconds(1));
let mut timer2 = Timer::new().unwrap();
// while sleeping, the previous timer should fire and not have its
// callback do something terrible.
timer2.sleep(Duration::milliseconds(2));
}
#[test]
fn sleep_zero() {
let mut timer = Timer::new().unwrap();
timer.sleep(Duration::milliseconds(0));
}
#[test]
fn sleep_negative() {
let mut timer = Timer::new().unwrap();
timer.sleep(Duration::milliseconds(-1000000));
}
#[test]
fn oneshot_zero() {
let mut timer = Timer::new().unwrap();
let rx = timer.oneshot(Duration::milliseconds(0));
rx.recv().unwrap();
}
#[test]
fn oneshot_negative() {
let mut timer = Timer::new().unwrap();
let rx = timer.oneshot(Duration::milliseconds(-1000000));
rx.recv().unwrap();
}
#[test]
fn periodic_zero() {
let mut timer = Timer::new().unwrap();
let rx = timer.periodic(Duration::milliseconds(0));
rx.recv().unwrap();
rx.recv().unwrap();
rx.recv().unwrap();
rx.recv().unwrap();
}
#[test]
fn periodic_negative() {
let mut timer = Timer::new().unwrap();
let rx = timer.periodic(Duration::milliseconds(-1000000));
rx.recv().unwrap();
rx.recv().unwrap();
rx.recv().unwrap();
rx.recv().unwrap();
}
}

View File

@ -1,495 +0,0 @@
// Copyright 2013 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.
//! Utility implementations of Reader and Writer
#![allow(deprecated)]
use prelude::v1::*;
use cmp;
use old_io::{self, Reader, Writer, Buffer};
use slice::bytes::MutableByteVector;
/// Wraps a `Reader`, limiting the number of bytes that can be read from it.
#[derive(Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::Take")]
#[unstable(feature = "old_io")]
pub struct LimitReader<R> {
limit: usize,
inner: R
}
#[deprecated(since = "1.0.0", reason = "use std::io::Take")]
#[unstable(feature = "old_io")]
impl<R: Reader> LimitReader<R> {
/// Creates a new `LimitReader`
#[deprecated(since = "1.0.0", reason = "use std::io's take method instead")]
#[unstable(feature = "old_io")]
pub fn new(r: R, limit: usize) -> LimitReader<R> {
LimitReader { limit: limit, inner: r }
}
/// Consumes the `LimitReader`, returning the underlying `Reader`.
pub fn into_inner(self) -> R { self.inner }
/// Returns the number of bytes that can be read before the `LimitReader`
/// will return EOF.
///
/// # Note
///
/// The reader may reach EOF after reading fewer bytes than indicated by
/// this method if the underlying reader reaches EOF.
pub fn limit(&self) -> usize { self.limit }
}
#[deprecated(since = "1.0.0", reason = "use std::io's take method instead")]
#[unstable(feature = "old_io")]
impl<R: Reader> Reader for LimitReader<R> {
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
if self.limit == 0 {
return Err(old_io::standard_error(old_io::EndOfFile));
}
let len = cmp::min(self.limit, buf.len());
let res = self.inner.read(&mut buf[..len]);
match res {
Ok(len) => self.limit -= len,
_ => {}
}
res
}
}
#[deprecated(since = "1.0.0", reason = "use std::io's take method instead")]
#[unstable(feature = "old_io")]
impl<R: Buffer> Buffer for LimitReader<R> {
fn fill_buf<'a>(&'a mut self) -> old_io::IoResult<&'a [u8]> {
let amt = try!(self.inner.fill_buf());
let buf = &amt[..cmp::min(amt.len(), self.limit)];
if buf.len() == 0 {
Err(old_io::standard_error(old_io::EndOfFile))
} else {
Ok(buf)
}
}
fn consume(&mut self, amt: usize) {
// Don't let callers reset the limit by passing an overlarge value
let amt = cmp::min(amt, self.limit);
self.limit -= amt;
self.inner.consume(amt);
}
}
/// A `Writer` which ignores bytes written to it, like /dev/null.
#[derive(Copy, Clone, Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::sink() instead")]
#[unstable(feature = "old_io")]
pub struct NullWriter;
#[deprecated(since = "1.0.0", reason = "use std::io::sink() instead")]
#[unstable(feature = "old_io")]
impl Writer for NullWriter {
#[inline]
fn write_all(&mut self, _buf: &[u8]) -> old_io::IoResult<()> { Ok(()) }
}
/// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero.
#[derive(Copy, Clone, Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::repeat(0) instead")]
#[unstable(feature = "old_io")]
pub struct ZeroReader;
#[deprecated(since = "1.0.0", reason = "use std::io::repeat(0) instead")]
#[unstable(feature = "old_io")]
impl Reader for ZeroReader {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
buf.set_memory(0);
Ok(buf.len())
}
}
#[deprecated(since = "1.0.0", reason = "use std::io::repeat(0) instead")]
#[unstable(feature = "old_io")]
impl Buffer for ZeroReader {
fn fill_buf<'a>(&'a mut self) -> old_io::IoResult<&'a [u8]> {
static DATA: [u8; 64] = [0; 64];
Ok(&DATA)
}
fn consume(&mut self, _amt: usize) {}
}
/// A `Reader` which is always at EOF, like /dev/null.
#[derive(Copy, Clone, Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::empty() instead")]
#[unstable(feature = "old_io")]
pub struct NullReader;
#[deprecated(since = "1.0.0", reason = "use std::io::empty() instead")]
#[unstable(feature = "old_io")]
impl Reader for NullReader {
#[inline]
fn read(&mut self, _buf: &mut [u8]) -> old_io::IoResult<usize> {
Err(old_io::standard_error(old_io::EndOfFile))
}
}
#[deprecated(since = "1.0.0", reason = "use std::io::empty() instead")]
#[unstable(feature = "old_io")]
impl Buffer for NullReader {
fn fill_buf<'a>(&'a mut self) -> old_io::IoResult<&'a [u8]> {
Err(old_io::standard_error(old_io::EndOfFile))
}
fn consume(&mut self, _amt: usize) {}
}
/// A `Writer` which multiplexes writes to a set of `Writer`s.
///
/// The `Writer`s are delegated to in order. If any `Writer` returns an error,
/// that error is returned immediately and remaining `Writer`s are not called.
#[derive(Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::Broadcast instead")]
#[unstable(feature = "old_io")]
pub struct MultiWriter<W> {
writers: Vec<W>
}
impl<W> MultiWriter<W> where W: Writer {
/// Creates a new `MultiWriter`
#[deprecated(since = "1.0.0", reason = "use std::io's broadcast method instead")]
#[unstable(feature = "old_io")]
pub fn new(writers: Vec<W>) -> MultiWriter<W> {
MultiWriter { writers: writers }
}
}
#[deprecated(since = "1.0.0", reason = "use std::io::Broadcast instead")]
#[unstable(feature = "old_io")]
impl<W> Writer for MultiWriter<W> where W: Writer {
#[inline]
fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> {
for writer in &mut self.writers {
try!(writer.write_all(buf));
}
Ok(())
}
#[inline]
fn flush(&mut self) -> old_io::IoResult<()> {
for writer in &mut self.writers {
try!(writer.flush());
}
Ok(())
}
}
/// A `Reader` which chains input from multiple `Reader`s, reading each to
/// completion before moving onto the next.
#[derive(Clone, Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::Chain instead")]
#[unstable(feature = "old_io")]
pub struct ChainedReader<I, R> {
readers: I,
cur_reader: Option<R>,
}
impl<R: Reader, I: Iterator<Item=R>> ChainedReader<I, R> {
/// Creates a new `ChainedReader`
#[deprecated(since = "1.0.0", reason = "use std::io's chain method instead")]
#[unstable(feature = "old_io")]
pub fn new(mut readers: I) -> ChainedReader<I, R> {
let r = readers.next();
ChainedReader { readers: readers, cur_reader: r }
}
}
#[deprecated(since = "1.0.0", reason = "use std::io::Chain instead")]
#[unstable(feature = "old_io")]
impl<R: Reader, I: Iterator<Item=R>> Reader for ChainedReader<I, R> {
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
loop {
let err = match self.cur_reader {
Some(ref mut r) => {
match r.read(buf) {
Ok(len) => return Ok(len),
Err(ref e) if e.kind == old_io::EndOfFile => None,
Err(e) => Some(e),
}
}
None => break
};
self.cur_reader = self.readers.next();
match err {
Some(e) => return Err(e),
None => {}
}
}
Err(old_io::standard_error(old_io::EndOfFile))
}
}
/// A `Reader` which forwards input from another `Reader`, passing it along to
/// a `Writer` as well. Similar to the `tee(1)` command.
#[derive(Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::Tee instead")]
#[unstable(feature = "old_io")]
pub struct TeeReader<R, W> {
reader: R,
writer: W,
}
#[deprecated(since = "1.0.0", reason = "use std::io::Tee instead")]
#[unstable(feature = "old_io")]
impl<R: Reader, W: Writer> TeeReader<R, W> {
/// Creates a new `TeeReader`
#[deprecated(since = "1.0.0", reason = "use std::io's tee method instead")]
#[unstable(feature = "old_io")]
pub fn new(r: R, w: W) -> TeeReader<R, W> {
TeeReader { reader: r, writer: w }
}
/// Consumes the `TeeReader`, returning the underlying `Reader` and
/// `Writer`.
pub fn into_inner(self) -> (R, W) {
let TeeReader { reader, writer } = self;
(reader, writer)
}
}
#[deprecated(since = "1.0.0", reason = "use std::io::Tee instead")]
#[unstable(feature = "old_io")]
impl<R: Reader, W: Writer> Reader for TeeReader<R, W> {
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
self.reader.read(buf).and_then(|len| {
self.writer.write_all(&mut buf[..len]).map(|()| len)
})
}
}
/// Copies all data from a `Reader` to a `Writer`.
#[deprecated(since = "1.0.0", reason = "use std::io's copy function instead")]
#[unstable(feature = "old_io")]
pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) -> old_io::IoResult<()> {
let mut buf = [0; super::DEFAULT_BUF_SIZE];
loop {
let len = match r.read(&mut buf) {
Ok(len) => len,
Err(ref e) if e.kind == old_io::EndOfFile => return Ok(()),
Err(e) => return Err(e),
};
try!(w.write_all(&buf[..len]));
}
}
/// An adaptor converting an `Iterator<u8>` to a `Reader`.
#[derive(Clone, Debug)]
pub struct IterReader<T> {
iter: T,
}
impl<T: Iterator<Item=u8>> IterReader<T> {
/// Creates a new `IterReader` which will read from the specified
/// `Iterator`.
pub fn new(iter: T) -> IterReader<T> {
IterReader { iter: iter }
}
}
impl<T: Iterator<Item=u8>> Reader for IterReader<T> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
let mut len = 0;
for (slot, elt) in buf.iter_mut().zip(self.iter.by_ref()) {
*slot = elt;
len += 1;
}
if len == 0 && buf.len() != 0 {
Err(old_io::standard_error(old_io::EndOfFile))
} else {
Ok(len)
}
}
}
#[cfg(test)]
mod test {
use prelude::v1::*;
use old_io::{MemReader, ByRefReader, Reader, Writer, Buffer};
use old_io;
use super::*;
#[test]
fn test_limit_reader_unlimited() {
let mut r = MemReader::new(vec!(0, 1, 2));
{
let mut r = LimitReader::new(r.by_ref(), 4);
assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]);
}
}
#[test]
fn test_limit_reader_limited() {
let mut r = MemReader::new(vec!(0, 1, 2));
{
let mut r = LimitReader::new(r.by_ref(), 2);
assert_eq!(r.read_to_end().unwrap(), [0, 1]);
}
assert_eq!(r.read_to_end().unwrap(), [2]);
}
#[test]
fn test_limit_reader_limit() {
let r = MemReader::new(vec!(0, 1, 2));
let mut r = LimitReader::new(r, 3);
assert_eq!(3, r.limit());
assert_eq!(0, r.read_byte().unwrap());
assert_eq!(2, r.limit());
assert_eq!(r.read_to_end().unwrap(), [1, 2]);
assert_eq!(0, r.limit());
}
#[test]
fn test_limit_reader_overlong_consume() {
let mut r = MemReader::new(vec![0, 1, 2, 3, 4, 5]);
let mut r = LimitReader::new(r.by_ref(), 1);
r.consume(2);
assert_eq!(r.read_to_end().unwrap(), []);
}
#[test]
fn test_null_writer() {
let mut s = NullWriter;
let buf = vec![0, 0, 0];
s.write_all(&buf).unwrap();
s.flush().unwrap();
}
#[test]
fn test_zero_reader() {
let mut s = ZeroReader;
let mut buf = vec![1, 2, 3];
assert_eq!(s.read(&mut buf), Ok(3));
assert_eq!(buf, [0, 0, 0]);
}
#[test]
fn test_null_reader() {
let mut r = NullReader;
let mut buf = vec![0];
assert!(r.read(&mut buf).is_err());
}
#[test]
fn test_multi_writer() {
static mut writes: usize = 0;
static mut flushes: usize = 0;
struct TestWriter;
impl Writer for TestWriter {
fn write_all(&mut self, _buf: &[u8]) -> old_io::IoResult<()> {
unsafe { writes += 1 }
Ok(())
}
fn flush(&mut self) -> old_io::IoResult<()> {
unsafe { flushes += 1 }
Ok(())
}
}
let mut multi = MultiWriter::new(vec!(box TestWriter as Box<Writer>,
box TestWriter as Box<Writer>));
multi.write_all(&[1, 2, 3]).unwrap();
assert_eq!(2, unsafe { writes });
assert_eq!(0, unsafe { flushes });
multi.flush().unwrap();
assert_eq!(2, unsafe { writes });
assert_eq!(2, unsafe { flushes });
}
#[test]
fn test_chained_reader() {
let rs = vec!(MemReader::new(vec!(0, 1)), MemReader::new(vec!()),
MemReader::new(vec!(2, 3)));
let mut r = ChainedReader::new(rs.into_iter());
assert_eq!(r.read_to_end().unwrap(), [0, 1, 2, 3]);
}
#[test]
fn test_tee_reader() {
let mut r = TeeReader::new(MemReader::new(vec!(0, 1, 2)),
Vec::new());
assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]);
let (_, w) = r.into_inner();
assert_eq!(w, [0, 1, 2]);
}
#[test]
fn test_copy() {
let mut r = MemReader::new(vec!(0, 1, 2, 3, 4));
let mut w = Vec::new();
copy(&mut r, &mut w).unwrap();
assert_eq!(w, [0, 1, 2, 3, 4]);
}
#[test]
fn limit_reader_buffer() {
let mut r: &[u8] = b"0123456789\n0123456789\n";
let r = &mut r;
{
let mut r = LimitReader::new(r.by_ref(), 3);
assert_eq!(r.read_line(), Ok("012".to_string()));
assert_eq!(r.limit(), 0);
assert_eq!(r.read_line().err().unwrap().kind, old_io::EndOfFile);
}
{
let mut r = LimitReader::new(r.by_ref(), 9);
assert_eq!(r.read_line(), Ok("3456789\n".to_string()));
assert_eq!(r.limit(), 1);
assert_eq!(r.read_line(), Ok("0".to_string()));
}
{
let mut r = LimitReader::new(r.by_ref(), 100);
assert_eq!(r.read_char(), Ok('1'));
assert_eq!(r.limit(), 99);
assert_eq!(r.read_line(), Ok("23456789\n".to_string()));
}
}
#[test]
fn test_iter_reader() {
let mut r = IterReader::new(0..8);
let mut buf = [0, 0, 0];
let len = r.read(&mut buf).unwrap();
assert_eq!(len, 3);
assert!(buf == [0, 1, 2]);
let len = r.read(&mut buf).unwrap();
assert_eq!(len, 3);
assert!(buf == [3, 4, 5]);
let len = r.read(&mut buf).unwrap();
assert_eq!(len, 2);
assert!(buf == [6, 7, 5]);
assert_eq!(r.read(&mut buf).unwrap_err().kind, old_io::EndOfFile);
}
#[test]
fn iter_reader_zero_length() {
let mut r = IterReader::new(0..8);
let mut buf = [];
assert_eq!(Ok(0), r.read(&mut buf));
}
}

View File

@ -1,985 +0,0 @@
// Copyright 2013 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.
//! Cross-platform path support
//!
//! This module implements support for two flavors of paths. `PosixPath` represents a path on any
//! unix-like system, whereas `WindowsPath` represents a path on Windows. This module also exposes
//! a typedef `Path` which is equal to the appropriate platform-specific path variant.
//!
//! Both `PosixPath` and `WindowsPath` implement a trait `GenericPath`, which contains the set of
//! methods that behave the same for both paths. They each also implement some methods that could
//! not be expressed in `GenericPath`, yet behave identically for both path flavors, such as
//! `.components()`.
//!
//! The three main design goals of this module are 1) to avoid unnecessary allocation, 2) to behave
//! the same regardless of which flavor of path is being used, and 3) to support paths that cannot
//! be represented in UTF-8 (as Linux has no restriction on paths beyond disallowing NUL).
//!
//! ## Usage
//!
//! Usage of this module is fairly straightforward. Unless writing platform-specific code, `Path`
//! should be used to refer to the platform-native path.
//!
//! Creation of a path is typically done with either `Path::new(some_str)` or
//! `Path::new(some_vec)`. This path can be modified with `.push()` and `.pop()` (and other
//! setters). The resulting Path can either be passed to another API that expects a path, or can be
//! turned into a `&[u8]` with `.as_vec()` or a `Option<&str>` with `.as_str()`. Similarly,
//! attributes of the path can be queried with methods such as `.filename()`. There are also
//! methods that return a new path instead of modifying the receiver, such as `.join()` or
//! `.dir_path()`.
//!
//! Paths are always kept in normalized form. This means that creating the path
//! `Path::new("a/b/../c")` will return the path `a/c`. Similarly any attempt to mutate the path
//! will always leave it in normalized form.
//!
//! When rendering a path to some form of output, there is a method `.display()` which is
//! compatible with the `format!()` parameter `{}`. This will render the path as a string,
//! replacing all non-utf8 sequences with the Replacement Character (U+FFFD). As such it is not
//! suitable for passing to any API that actually operates on the path; it is only intended for
//! display.
//!
//! ## Examples
//!
//! ```rust,ignore
//! # #![feature(old_path, old_io)]
//! use std::old_io::fs::PathExtensions;
//! use std::old_path::{Path, GenericPath};
//!
//! let mut path = Path::new("/tmp/path");
//! println!("path: {}", path.display());
//! path.set_filename("foo");
//! path.push("bar");
//! println!("new path: {}", path.display());
//! println!("path exists: {}", path.exists());
//! ```
#![unstable(feature = "old_path")]
#![deprecated(since = "1.0.0", reason = "use std::path instead")]
#![allow(deprecated)] // seriously this is all deprecated
#![allow(unused_imports)]
use core::marker::Sized;
use ffi::CString;
use clone::Clone;
use borrow::Cow;
use fmt;
use iter::Iterator;
use option::Option;
use option::Option::{None, Some};
use str;
use string::String;
use vec::Vec;
/// Typedef for POSIX file paths.
/// See `posix::Path` for more info.
pub use self::posix::Path as PosixPath;
/// Typedef for Windows file paths.
/// See `windows::Path` for more info.
pub use self::windows::Path as WindowsPath;
/// Typedef for the platform-native path type
#[cfg(unix)]
pub use self::posix::Path as Path;
/// Typedef for the platform-native path type
#[cfg(windows)]
pub use self::windows::Path as Path;
/// Typedef for the platform-native component iterator
#[cfg(unix)]
pub use self::posix::Components as Components;
/// Typedef for the platform-native component iterator
#[cfg(windows)]
pub use self::windows::Components as Components;
/// Typedef for the platform-native str component iterator
#[cfg(unix)]
pub use self::posix::StrComponents as StrComponents;
/// Typedef for the platform-native str component iterator
#[cfg(windows)]
pub use self::windows::StrComponents as StrComponents;
/// Alias for the platform-native separator character.
#[cfg(unix)]
pub use self::posix::SEP as SEP;
/// Alias for the platform-native separator character.
#[cfg(windows)]
pub use self::windows::SEP as SEP;
/// Alias for the platform-native separator byte.
#[cfg(unix)]
pub use self::posix::SEP_BYTE as SEP_BYTE;
/// Alias for the platform-native separator byte.
#[cfg(windows)]
pub use self::windows::SEP_BYTE as SEP_BYTE;
/// Typedef for the platform-native separator char func
#[cfg(unix)]
pub use self::posix::is_sep as is_sep;
/// Typedef for the platform-native separator char func
#[cfg(windows)]
pub use self::windows::is_sep as is_sep;
/// Typedef for the platform-native separator byte func
#[cfg(unix)]
pub use self::posix::is_sep_byte as is_sep_byte;
/// Typedef for the platform-native separator byte func
#[cfg(windows)]
pub use self::windows::is_sep_byte as is_sep_byte;
pub mod posix;
pub mod windows;
/// A trait that represents the generic operations available on paths
pub trait GenericPath: Clone + GenericPathUnsafe {
/// Creates a new Path from a byte vector or string.
/// The resulting Path will always be normalized.
///
/// # Examples
///
/// ```no_run
/// # #![feature(old_path)]
/// # fn main() {
/// use std::old_path::Path;
/// let path = Path::new("foo/bar");
/// # }
/// ```
///
/// # Panics
///
/// Panics the task if the path contains a NUL.
///
/// See individual Path impls for additional restrictions.
#[inline]
fn new<T: BytesContainer>(path: T) -> Self {
assert!(!contains_nul(&path));
unsafe { GenericPathUnsafe::new_unchecked(path) }
}
/// Creates a new Path from a byte vector or string, if possible.
/// The resulting Path will always be normalized.
///
/// # Examples
///
/// ```no_run
/// # #![feature(old_path)]
/// # fn main() {
/// use std::old_path::Path;
/// let x: &[u8] = b"foo\0";
/// assert!(Path::new_opt(x).is_none());
/// # }
/// ```
#[inline]
fn new_opt<T: BytesContainer>(path: T) -> Option<Self> {
if contains_nul(&path) {
None
} else {
Some(unsafe { GenericPathUnsafe::new_unchecked(path) })
}
}
/// Returns the path as a string, if possible.
/// If the path is not representable in utf-8, this returns None.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("/abc/def");
/// assert_eq!(p.as_str(), Some("/abc/def"));
/// # }
/// ```
#[inline]
fn as_str<'a>(&'a self) -> Option<&'a str> {
str::from_utf8(self.as_vec()).ok()
}
/// Returns the path as a byte vector
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def");
/// assert_eq!(p.as_vec(), b"abc/def");
/// # }
/// ```
fn as_vec<'a>(&'a self) -> &'a [u8];
/// Converts the Path into an owned byte vector
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def");
/// assert_eq!(p.into_vec(), b"abc/def".to_vec());
/// // attempting to use p now results in "error: use of moved value"
/// # }
/// ```
fn into_vec(self) -> Vec<u8>;
/// Returns an object that implements `Display` for printing paths
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def");
/// println!("{}", p.display()); // prints "abc/def"
/// # }
/// ```
fn display<'a>(&'a self) -> Display<'a, Self> {
Display{ path: self, filename: false }
}
/// Returns an object that implements `Display` for printing filenames
///
/// If there is no filename, nothing will be printed.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def");
/// println!("{}", p.filename_display()); // prints "def"
/// # }
/// ```
fn filename_display<'a>(&'a self) -> Display<'a, Self> {
Display{ path: self, filename: true }
}
/// Returns the directory component of `self`, as a byte vector (with no trailing separator).
/// If `self` has no directory component, returns ['.'].
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def/ghi");
/// assert_eq!(p.dirname(), b"abc/def");
/// # }
/// ```
fn dirname<'a>(&'a self) -> &'a [u8];
/// Returns the directory component of `self`, as a string, if possible.
/// See `dirname` for details.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def/ghi");
/// assert_eq!(p.dirname_str(), Some("abc/def"));
/// # }
/// ```
#[inline]
fn dirname_str<'a>(&'a self) -> Option<&'a str> {
str::from_utf8(self.dirname()).ok()
}
/// Returns the file component of `self`, as a byte vector.
/// If `self` represents the root of the file hierarchy, returns None.
/// If `self` is "." or "..", returns None.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def/ghi");
/// assert_eq!(p.filename(), Some(&b"ghi"[..]));
/// # }
/// ```
fn filename<'a>(&'a self) -> Option<&'a [u8]>;
/// Returns the file component of `self`, as a string, if possible.
/// See `filename` for details.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def/ghi");
/// assert_eq!(p.filename_str(), Some("ghi"));
/// # }
/// ```
#[inline]
fn filename_str<'a>(&'a self) -> Option<&'a str> {
self.filename().and_then(|s| str::from_utf8(s).ok())
}
/// Returns the stem of the filename of `self`, as a byte vector.
/// The stem is the portion of the filename just before the last '.'.
/// If there is no '.', the entire filename is returned.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("/abc/def.txt");
/// assert_eq!(p.filestem(), Some(&b"def"[..]));
/// # }
/// ```
fn filestem<'a>(&'a self) -> Option<&'a [u8]> {
match self.filename() {
None => None,
Some(name) => Some({
let dot = b'.';
match name.rposition_elem(&dot) {
None | Some(0) => name,
Some(1) if name == b".." => name,
Some(pos) => &name[..pos]
}
})
}
}
/// Returns the stem of the filename of `self`, as a string, if possible.
/// See `filestem` for details.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("/abc/def.txt");
/// assert_eq!(p.filestem_str(), Some("def"));
/// # }
/// ```
#[inline]
fn filestem_str<'a>(&'a self) -> Option<&'a str> {
self.filestem().and_then(|s| str::from_utf8(s).ok())
}
/// Returns the extension of the filename of `self`, as an optional byte vector.
/// The extension is the portion of the filename just after the last '.'.
/// If there is no extension, None is returned.
/// If the filename ends in '.', the empty vector is returned.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def.txt");
/// assert_eq!(p.extension(), Some(&b"txt"[..]));
/// # }
/// ```
fn extension<'a>(&'a self) -> Option<&'a [u8]> {
match self.filename() {
None => None,
Some(name) => {
let dot = b'.';
match name.rposition_elem(&dot) {
None | Some(0) => None,
Some(1) if name == b".." => None,
Some(pos) => Some(&name[pos+1..])
}
}
}
}
/// Returns the extension of the filename of `self`, as a string, if possible.
/// See `extension` for details.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def.txt");
/// assert_eq!(p.extension_str(), Some("txt"));
/// # }
/// ```
#[inline]
fn extension_str<'a>(&'a self) -> Option<&'a str> {
self.extension().and_then(|s| str::from_utf8(s).ok())
}
/// Replaces the filename portion of the path with the given byte vector or string.
/// If the replacement name is [], this is equivalent to popping the path.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let mut p = Path::new("abc/def.txt");
/// p.set_filename("foo.dat");
/// assert!(p == Path::new("abc/foo.dat"));
/// # }
/// ```
///
/// # Panics
///
/// Panics the task if the filename contains a NUL.
#[inline]
fn set_filename<T: BytesContainer>(&mut self, filename: T) {
assert!(!contains_nul(&filename));
unsafe { self.set_filename_unchecked(filename) }
}
/// Replaces the extension with the given byte vector or string.
/// If there is no extension in `self`, this adds one.
/// If the argument is [] or "", this removes the extension.
/// If `self` has no filename, this is a no-op.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let mut p = Path::new("abc/def.txt");
/// p.set_extension("csv");
/// assert_eq!(p, Path::new("abc/def.csv"));
/// # }
/// ```
///
/// # Panics
///
/// Panics the task if the extension contains a NUL.
fn set_extension<T: BytesContainer>(&mut self, extension: T) {
assert!(!contains_nul(&extension));
let val = self.filename().and_then(|name| {
let dot = b'.';
let extlen = extension.container_as_bytes().len();
match (name.rposition_elem(&dot), extlen) {
(None, 0) | (Some(0), 0) => None,
(Some(idx), 0) => Some(name[..idx].to_vec()),
(idx, extlen) => {
let idx = match idx {
None | Some(0) => name.len(),
Some(val) => val
};
let mut v;
v = Vec::with_capacity(idx + extlen + 1);
v.push_all(&name[..idx]);
v.push(dot);
v.push_all(extension.container_as_bytes());
Some(v)
}
}
});
match val {
None => (),
Some(v) => unsafe { self.set_filename_unchecked(v) }
}
}
/// Returns a new Path constructed by replacing the filename with the given
/// byte vector or string.
/// See `set_filename` for details.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let mut p = Path::new("abc/def.txt");
/// assert_eq!(p.with_filename("foo.dat"), Path::new("abc/foo.dat"));
/// # }
/// ```
///
/// # Panics
///
/// Panics the task if the filename contains a NUL.
#[inline]
fn with_filename<T: BytesContainer>(&self, filename: T) -> Self {
let mut p = self.clone();
p.set_filename(filename);
p
}
/// Returns a new Path constructed by setting the extension to the given
/// byte vector or string.
/// See `set_extension` for details.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let mut p = Path::new("abc/def.txt");
/// assert_eq!(p.with_extension("csv"), Path::new("abc/def.csv"));
/// # }
/// ```
///
/// # Panics
///
/// Panics the task if the extension contains a NUL.
#[inline]
fn with_extension<T: BytesContainer>(&self, extension: T) -> Self {
let mut p = self.clone();
p.set_extension(extension);
p
}
/// Returns the directory component of `self`, as a Path.
/// If `self` represents the root of the filesystem hierarchy, returns `self`.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def/ghi");
/// assert_eq!(p.dir_path(), Path::new("abc/def"));
/// # }
/// ```
fn dir_path(&self) -> Self {
// self.dirname() returns a NUL-free vector
unsafe { GenericPathUnsafe::new_unchecked(self.dirname()) }
}
/// Returns a Path that represents the filesystem root that `self` is rooted in.
///
/// If `self` is not absolute, or vol/cwd-relative in the case of Windows, this returns None.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// assert_eq!(Path::new("abc/def").root_path(), None);
/// assert_eq!(Path::new("/abc/def").root_path(), Some(Path::new("/")));
/// # }
/// ```
fn root_path(&self) -> Option<Self>;
/// Pushes a path (as a byte vector or string) onto `self`.
/// If the argument represents an absolute path, it replaces `self`.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let mut p = Path::new("foo/bar");
/// p.push("baz.txt");
/// assert_eq!(p, Path::new("foo/bar/baz.txt"));
/// # }
/// ```
///
/// # Panics
///
/// Panics the task if the path contains a NUL.
#[inline]
fn push<T: BytesContainer>(&mut self, path: T) {
assert!(!contains_nul(&path));
unsafe { self.push_unchecked(path) }
}
/// Pushes multiple paths (as byte vectors or strings) onto `self`.
/// See `push` for details.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let mut p = Path::new("foo");
/// p.push_many(&["bar", "baz.txt"]);
/// assert_eq!(p, Path::new("foo/bar/baz.txt"));
/// # }
/// ```
#[inline]
fn push_many<T: BytesContainer>(&mut self, paths: &[T]) {
let t: Option<&T> = None;
if BytesContainer::is_str(t) {
for p in paths {
self.push(p.container_as_str().unwrap())
}
} else {
for p in paths {
self.push(p.container_as_bytes())
}
}
}
/// Removes the last path component from the receiver.
/// Returns `true` if the receiver was modified, or `false` if it already
/// represented the root of the file hierarchy.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let mut p = Path::new("foo/bar/baz.txt");
/// p.pop();
/// assert_eq!(p, Path::new("foo/bar"));
/// # }
/// ```
fn pop(&mut self) -> bool;
/// Returns a new Path constructed by joining `self` with the given path
/// (as a byte vector or string).
/// If the given path is absolute, the new Path will represent just that.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("/foo");
/// assert_eq!(p.join("bar.txt"), Path::new("/foo/bar.txt"));
/// # }
/// ```
///
/// # Panics
///
/// Panics the task if the path contains a NUL.
#[inline]
fn join<T: BytesContainer>(&self, path: T) -> Self {
let mut p = self.clone();
p.push(path);
p
}
/// Returns a new Path constructed by joining `self` with the given paths
/// (as byte vectors or strings).
/// See `join` for details.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("foo");
/// let fbbq = Path::new("foo/bar/baz/quux.txt");
/// assert_eq!(p.join_many(&["bar", "baz", "quux.txt"]), fbbq);
/// # }
/// ```
#[inline]
fn join_many<T: BytesContainer>(&self, paths: &[T]) -> Self {
let mut p = self.clone();
p.push_many(paths);
p
}
/// Returns whether `self` represents an absolute path.
/// An absolute path is defined as one that, when joined to another path, will
/// yield back the same absolute path.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("/abc/def");
/// assert!(p.is_absolute());
/// # }
/// ```
fn is_absolute(&self) -> bool;
/// Returns whether `self` represents a relative path.
/// Typically this is the inverse of `is_absolute`.
/// But for Windows paths, it also means the path is not volume-relative or
/// relative to the current working directory.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("abc/def");
/// assert!(p.is_relative());
/// # }
/// ```
fn is_relative(&self) -> bool {
!self.is_absolute()
}
/// Returns whether `self` is equal to, or is an ancestor of, the given path.
/// If both paths are relative, they are compared as though they are relative
/// to the same parent path.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("foo/bar/baz/quux.txt");
/// let fb = Path::new("foo/bar");
/// let bq = Path::new("baz/quux.txt");
/// assert!(fb.is_ancestor_of(&p));
/// # }
/// ```
fn is_ancestor_of(&self, other: &Self) -> bool;
/// Returns the Path that, were it joined to `base`, would yield `self`.
/// If no such path exists, None is returned.
/// If `self` is absolute and `base` is relative, or on Windows if both
/// paths refer to separate drives, an absolute path is returned.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("foo/bar/baz/quux.txt");
/// let fb = Path::new("foo/bar");
/// let bq = Path::new("baz/quux.txt");
/// assert_eq!(p.path_relative_from(&fb), Some(bq));
/// # }
/// ```
fn path_relative_from(&self, base: &Self) -> Option<Self>;
/// Returns whether the relative path `child` is a suffix of `self`.
///
/// # Examples
///
/// ```ignore
/// # #![feature(old_path)]
/// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// let p = Path::new("foo/bar/baz/quux.txt");
/// let bq = Path::new("baz/quux.txt");
/// assert!(p.ends_with_path(&bq));
/// # }
/// ```
fn ends_with_path(&self, child: &Self) -> bool;
}
/// A trait that represents something bytes-like (e.g. a &[u8] or a &str)
pub trait BytesContainer {
/// Returns a &[u8] representing the receiver
fn container_as_bytes<'a>(&'a self) -> &'a [u8];
/// Returns the receiver interpreted as a utf-8 string, if possible
#[inline]
fn container_as_str<'a>(&'a self) -> Option<&'a str> {
str::from_utf8(self.container_as_bytes()).ok()
}
/// Returns whether .container_as_str() is guaranteed to not fail
// FIXME (#8888): Remove unused arg once ::<for T> works
#[inline]
fn is_str(_: Option<&Self>) -> bool { false }
}
/// A trait that represents the unsafe operations on GenericPaths
pub trait GenericPathUnsafe {
/// Creates a new Path without checking for null bytes.
/// The resulting Path will always be normalized.
unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Self;
/// Replaces the filename portion of the path without checking for null
/// bytes.
/// See `set_filename` for details.
unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T);
/// Pushes a path onto `self` without checking for null bytes.
/// See `push` for details.
unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
}
/// Helper struct for printing paths with format!()
pub struct Display<'a, P:'a> {
path: &'a P,
filename: bool
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, P: GenericPath> fmt::Debug for Display<'a, P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.as_cow(), f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, P: GenericPath> fmt::Display for Display<'a, P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.as_cow().fmt(f)
}
}
impl<'a, P: GenericPath> Display<'a, P> {
/// Returns the path as a possibly-owned string.
///
/// If the path is not UTF-8, invalid sequences will be replaced with the
/// Unicode replacement char. This involves allocation.
#[inline]
pub fn as_cow(&self) -> Cow<'a, str> {
String::from_utf8_lossy(if self.filename {
match self.path.filename() {
None => {
let result: &[u8] = &[];
result
}
Some(v) => v
}
} else {
self.path.as_vec()
})
}
}
impl BytesContainer for str {
#[inline]
fn container_as_bytes(&self) -> &[u8] {
self.as_bytes()
}
#[inline]
fn container_as_str(&self) -> Option<&str> {
Some(self)
}
#[inline]
fn is_str(_: Option<&str>) -> bool { true }
}
impl BytesContainer for String {
#[inline]
fn container_as_bytes(&self) -> &[u8] {
self.as_bytes()
}
#[inline]
fn container_as_str(&self) -> Option<&str> {
Some(&self[..])
}
#[inline]
fn is_str(_: Option<&String>) -> bool { true }
}
impl BytesContainer for [u8] {
#[inline]
fn container_as_bytes(&self) -> &[u8] {
self
}
}
impl BytesContainer for Vec<u8> {
#[inline]
fn container_as_bytes(&self) -> &[u8] {
&self[..]
}
}
impl BytesContainer for CString {
#[inline]
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
self.as_bytes()
}
}
impl<'a, T: ?Sized + BytesContainer> BytesContainer for &'a T {
#[inline]
fn container_as_bytes(&self) -> &[u8] {
(**self).container_as_bytes()
}
#[inline]
fn container_as_str(&self) -> Option<&str> {
(**self).container_as_str()
}
#[inline]
fn is_str(_: Option<& &'a T>) -> bool { BytesContainer::is_str(None::<&T>) }
}
#[inline(always)]
fn contains_nul<T: BytesContainer>(v: &T) -> bool {
v.container_as_bytes().iter().any(|&x| x == 0)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -224,27 +224,22 @@
//! ```
#![unstable(feature = "rand")]
#![deprecated(reason = "use the crates.io `rand` library instead",
since = "1.0.0-alpha")]
#![allow(deprecated)]
use prelude::v1::*;
use cell::RefCell;
use clone::Clone;
use old_io::IoResult;
use iter::Iterator;
use io;
use mem;
use rc::Rc;
use result::Result::{Ok, Err};
use vec::Vec;
#[cfg(target_pointer_width = "32")]
use core_rand::IsaacRng as IsaacWordRng;
#[cfg(target_pointer_width = "64")]
use core_rand::Isaac64Rng as IsaacWordRng;
pub use core_rand::{Rand, Rng, SeedableRng, Open01, Closed01};
pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng};
pub use core_rand::{distributions, reseeding};
pub use core_rand::{Rand, Rng, SeedableRng};
pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng};
pub use core_rand::reseeding;
pub use rand::os::OsRng;
pub mod os;
@ -269,7 +264,7 @@ impl StdRng {
///
/// Reading the randomness from the OS may fail, and any error is
/// propagated via the `IoResult` return value.
pub fn new() -> IoResult<StdRng> {
pub fn new() -> io::Result<StdRng> {
OsRng::new().map(|mut r| StdRng { rng: r.gen() })
}
}
@ -298,22 +293,6 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng {
}
}
/// Create a weak random number generator with a default algorithm and seed.
///
/// It returns the fastest `Rng` algorithm currently available in Rust without
/// consideration for cryptography or security. If you require a specifically
/// seeded `Rng` for consistency over time you should pick one algorithm and
/// create the `Rng` yourself.
///
/// This will read randomness from the operating system to seed the
/// generator.
pub fn weak_rng() -> XorShiftRng {
match OsRng::new() {
Ok(mut r) => r.gen(),
Err(e) => panic!("weak_rng: failed to create seeded RNG: {:?}", e)
}
}
/// Controls how the thread-local RNG is reseeded.
struct ThreadRngReseeder;
@ -376,83 +355,6 @@ impl Rng for ThreadRng {
}
}
/// Generates a random value using the thread-local random number generator.
///
/// `random()` can generate various types of random things, and so may require
/// type hinting to generate the specific type you want.
///
/// This function uses the thread local random number generator. This means
/// that if you're calling `random()` in a loop, caching the generator can
/// increase performance. An example is shown below.
///
/// # Examples
///
/// ```
/// # #![feature(rand)]
/// use std::rand;
///
/// let x: u8 = rand::random();
/// println!("{}", 2 * x as u16);
///
/// let y = rand::random::<f64>();
/// println!("{}", y);
///
/// if rand::random() { // generates a boolean
/// println!("Better lucky than good!");
/// }
/// ```
///
/// Caching the thread local random number generator:
///
/// ```
/// # #![feature(rand)]
/// use std::rand;
/// use std::rand::Rng;
///
/// let mut v = vec![1, 2, 3];
///
/// for x in v.iter_mut() {
/// *x = rand::random()
/// }
///
/// // would be faster as
///
/// let mut rng = rand::thread_rng();
///
/// for x in v.iter_mut() {
/// *x = rng.gen();
/// }
/// ```
#[inline]
pub fn random<T: Rand>() -> T {
thread_rng().gen()
}
/// Randomly sample up to `amount` elements from an iterator.
///
/// # Examples
///
/// ```
/// # #![feature(rand)]
/// use std::rand::{thread_rng, sample};
///
/// let mut rng = thread_rng();
/// let sample = sample(&mut rng, 1..100, 5);
/// println!("{:?}", sample);
/// ```
pub fn sample<T, I: Iterator<Item=T>, R: Rng>(rng: &mut R,
mut iter: I,
amount: usize) -> Vec<T> {
let mut reservoir: Vec<T> = iter.by_ref().take(amount).collect();
for (i, elem) in iter.enumerate() {
let k = rng.gen_range(0, i + 1 + amount);
if k < amount {
reservoir[k] = elem;
}
}
return reservoir;
}
#[cfg(test)]
mod test {
use prelude::v1::*;

View File

@ -18,10 +18,10 @@ mod imp {
use prelude::v1::*;
use self::OsRngInner::*;
use fs::File;
use io;
use libc;
use mem;
use old_io::{IoResult, File};
use old_path::Path;
use rand::Rng;
use rand::reader::ReaderRng;
use sys::os::errno;
@ -147,12 +147,12 @@ mod imp {
impl OsRng {
/// Create a new `OsRng`.
pub fn new() -> IoResult<OsRng> {
pub fn new() -> io::Result<OsRng> {
if is_getrandom_available() {
return Ok(OsRng { inner: OsGetrandomRng });
}
let reader = try!(File::open(&Path::new("/dev/urandom")));
let reader = try!(File::open("/dev/urandom"));
let reader_rng = ReaderRng::new(reader);
Ok(OsRng { inner: OsReaderRng(reader_rng) })
@ -186,7 +186,6 @@ mod imp {
use prelude::v1::*;
use io;
use old_io::IoResult;
use mem;
use rand::Rng;
use libc::{c_int, size_t};
@ -202,7 +201,8 @@ mod imp {
///
/// This does not block.
pub struct OsRng {
// dummy field to ensure that this struct cannot be constructed outside of this module
// dummy field to ensure that this struct cannot be constructed outside
// of this module
_dummy: (),
}
@ -220,7 +220,7 @@ mod imp {
impl OsRng {
/// Create a new `OsRng`.
pub fn new() -> IoResult<OsRng> {
pub fn new() -> io::Result<OsRng> {
Ok(OsRng { _dummy: () })
}
}
@ -238,10 +238,12 @@ mod imp {
}
fn fill_bytes(&mut self, v: &mut [u8]) {
let ret = unsafe {
SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t,
v.as_mut_ptr())
};
if ret == -1 {
panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
panic!("couldn't generate random bytes: {}",
io::Error::last_os_error());
}
}
}
@ -253,7 +255,6 @@ mod imp {
use io;
use mem;
use old_io::{IoResult, IoError};
use rand::Rng;
use libc::types::os::arch::extra::{LONG_PTR};
use libc::{DWORD, BYTE, LPCSTR, BOOL};
@ -293,7 +294,7 @@ mod imp {
impl OsRng {
/// Create a new `OsRng`.
pub fn new() -> IoResult<OsRng> {
pub fn new() -> io::Result<OsRng> {
let mut hcp = 0;
let ret = unsafe {
CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
@ -302,7 +303,7 @@ mod imp {
};
if ret == 0 {
Err(IoError::last_error())
Err(io::Error::last_os_error())
} else {
Ok(OsRng { hcryptprov: hcp })
}

View File

@ -8,35 +8,26 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A wrapper around any Reader to treat it as an RNG.
//! A wrapper around any Read to treat it as an RNG.
use old_io::Reader;
#![allow(dead_code)]
use prelude::v1::*;
use io::prelude::*;
use rand::Rng;
use result::Result::{Ok, Err};
/// An RNG that reads random bytes straight from a `Reader`. This will
/// An RNG that reads random bytes straight from a `Read`. This will
/// work best with an infinite reader, but this is not required.
///
/// # Panics
///
/// It will panic if it there is insufficient data to fulfill a request.
///
/// # Examples
///
/// ```
/// # #![feature(rand, old_io)]
/// use std::rand::{reader, Rng};
/// use std::old_io::MemReader;
///
/// let mut rng = reader::ReaderRng::new(MemReader::new(vec!(1,2,3,4,5,6,7,8)));
/// println!("{:x}", rng.gen::<usize>());
/// ```
pub struct ReaderRng<R> {
reader: R
}
impl<R: Reader> ReaderRng<R> {
/// Create a new `ReaderRng` from a `Reader`.
impl<R: Read> ReaderRng<R> {
/// Create a new `ReaderRng` from a `Read`.
pub fn new(r: R) -> ReaderRng<R> {
ReaderRng {
reader: r
@ -44,30 +35,29 @@ impl<R: Reader> ReaderRng<R> {
}
}
impl<R: Reader> Rng for ReaderRng<R> {
impl<R: Read> Rng for ReaderRng<R> {
fn next_u32(&mut self) -> u32 {
// This is designed for speed: reading a LE integer on a LE
// platform just involves blitting the bytes into the memory
// of the u32, similarly for BE on BE; avoiding byteswapping.
if cfg!(target_endian="little") {
self.reader.read_le_u32().unwrap()
} else {
self.reader.read_be_u32().unwrap()
}
let mut bytes = [0; 4];
self.fill_bytes(&mut bytes);
unsafe { *(bytes.as_ptr() as *const u32) }
}
fn next_u64(&mut self) -> u64 {
// see above for explanation.
if cfg!(target_endian="little") {
self.reader.read_le_u64().unwrap()
} else {
self.reader.read_be_u64().unwrap()
}
let mut bytes = [0; 8];
self.fill_bytes(&mut bytes);
unsafe { *(bytes.as_ptr() as *const u64) }
}
fn fill_bytes(&mut self, v: &mut [u8]) {
if v.len() == 0 { return }
match self.reader.read_at_least(v.len(), v) {
Ok(_) => {}
Err(e) => panic!("ReaderRng.fill_bytes error: {:?}", e)
fn fill_bytes(&mut self, mut v: &mut [u8]) {
while v.len() > 0 {
let t = v;
match self.reader.read(t) {
Ok(0) => panic!("ReaderRng.fill_bytes: EOF reached"),
Ok(n) => v = t.split_at_mut(n).1,
Err(e) => panic!("ReaderRng.fill_bytes: {}", e),
}
}
}
}

View File

@ -10,24 +10,11 @@
#![allow(missing_docs)]
use old_io::{self, IoError, IoResult};
use prelude::v1::*;
use sys::{last_error, retry};
use ffi::CString;
#[allow(deprecated)] // Int
use num::Int;
#[allow(deprecated)]
use old_path::BytesContainer;
use collections;
#[macro_use] pub mod helper_thread;
pub mod backtrace;
pub mod condvar;
pub mod mutex;
pub mod net;
pub mod net2;
pub mod poison;
pub mod remutex;
@ -40,72 +27,6 @@ pub mod wtf8;
// common error constructors
#[allow(deprecated)]
pub fn eof() -> IoError {
IoError {
kind: old_io::EndOfFile,
desc: "end of file",
detail: None,
}
}
#[allow(deprecated)]
pub fn timeout(desc: &'static str) -> IoError {
IoError {
kind: old_io::TimedOut,
desc: desc,
detail: None,
}
}
#[allow(deprecated)]
pub fn short_write(n: usize, desc: &'static str) -> IoError {
IoError {
kind: if n == 0 { old_io::TimedOut } else { old_io::ShortWrite(n) },
desc: desc,
detail: None,
}
}
#[allow(deprecated)]
pub fn unimpl() -> IoError {
IoError {
kind: old_io::IoUnavailable,
desc: "operations not yet supported",
detail: None,
}
}
// unix has nonzero values as errors
#[allow(deprecated)]
pub fn mkerr_libc<T: Int>(ret: T) -> IoResult<()> {
if ret != Int::zero() {
Err(last_error())
} else {
Ok(())
}
}
pub fn keep_going<F>(data: &[u8], mut f: F) -> i64 where
F: FnMut(*const u8, usize) -> i64,
{
let origamt = data.len();
let mut data = data.as_ptr();
let mut amt = origamt;
while amt > 0 {
let ret = retry(|| f(data, amt));
if ret == 0 {
break
} else if ret != -1 {
amt -= ret as usize;
data = unsafe { data.offset(ret as isize) };
} else {
return ret;
}
}
return (origamt - amt) as i64;
}
/// A trait for viewing representations from std types
#[doc(hidden)]
pub trait AsInner<Inner: ?Sized> {
@ -129,15 +50,3 @@ pub trait IntoInner<Inner> {
pub trait FromInner<Inner> {
fn from_inner(inner: Inner) -> Self;
}
#[doc(hidden)]
#[allow(deprecated)]
pub trait ProcessConfig<K: BytesContainer, V: BytesContainer> {
fn program(&self) -> &CString;
fn args(&self) -> &[CString];
fn env(&self) -> Option<&collections::HashMap<K, V>>;
fn cwd(&self) -> Option<&CString>;
fn uid(&self) -> Option<usize>;
fn gid(&self) -> Option<usize>;
fn detach(&self) -> bool;
}

View File

@ -15,14 +15,12 @@
//!
//! # Example
//!
//! ```rust,ignore
//! #![feature(globs)]
//!
//! use std::old_io::fs::File;
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//! let f = File::create(&Path::new("foo.txt")).unwrap();
//! let f = File::create("foo.txt").unwrap();
//! let fd = f.as_raw_fd();
//!
//! // use fd with native unix bindings
@ -34,7 +32,6 @@
/// Unix-specific extensions to general I/O primitives
#[stable(feature = "rust1", since = "1.0.0")]
pub mod io {
#[allow(deprecated)] use old_io;
use fs;
use libc;
use net;
@ -82,14 +79,6 @@ pub mod io {
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::fs::File {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for fs::File {
fn as_raw_fd(&self) -> RawFd {
@ -103,70 +92,6 @@ pub mod io {
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::pipe::PipeStream {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::pipe::UnixStream {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::pipe::UnixListener {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::pipe::UnixAcceptor {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsRawFd for old_io::net::tcp::TcpStream {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsRawFd for old_io::net::tcp::TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsRawFd for old_io::net::tcp::TcpAcceptor {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::udp::UdpSocket {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpStream {
fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }

View File

@ -1,409 +0,0 @@
// Copyright 2013-2014 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.
//! Blocking posix-based file I/O
#![allow(deprecated)]
#![allow(deprecated)] // this module itself is essentially deprecated
use prelude::v1::*;
use ffi::{CString, CStr};
use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
use old_io::{IoResult, FileStat, SeekStyle};
use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
use old_io;
use old_path::{Path, GenericPath};
use libc::{self, c_int, c_void};
use mem;
use ptr;
use sys::retry;
use sys_common::{keep_going, eof, mkerr_libc};
pub type fd_t = libc::c_int;
pub struct FileDesc {
/// The underlying C file descriptor.
fd: fd_t,
/// Whether to close the file descriptor on drop.
close_on_drop: bool,
}
impl FileDesc {
pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc {
FileDesc { fd: fd, close_on_drop: close_on_drop }
}
pub fn read(&self, buf: &mut [u8]) -> IoResult<usize> {
let ret = retry(|| unsafe {
libc::read(self.fd(),
buf.as_mut_ptr() as *mut libc::c_void,
buf.len() as libc::size_t)
});
if ret == 0 {
Err(eof())
} else if ret < 0 {
Err(super::last_error())
} else {
Ok(ret as usize)
}
}
pub fn write(&self, buf: &[u8]) -> IoResult<()> {
let ret = keep_going(buf, |buf, len| {
unsafe {
libc::write(self.fd(), buf as *const libc::c_void,
len as libc::size_t) as i64
}
});
if ret < 0 {
Err(super::last_error())
} else {
Ok(())
}
}
pub fn fd(&self) -> fd_t { self.fd }
pub fn seek(&self, pos: i64, whence: SeekStyle) -> IoResult<u64> {
let whence = match whence {
SeekSet => libc::SEEK_SET,
SeekEnd => libc::SEEK_END,
SeekCur => libc::SEEK_CUR,
};
let n = unsafe { libc::lseek(self.fd(), pos as libc::off_t, whence) };
if n < 0 {
Err(super::last_error())
} else {
Ok(n as u64)
}
}
pub fn tell(&self) -> IoResult<u64> {
let n = unsafe { libc::lseek(self.fd(), 0, libc::SEEK_CUR) };
if n < 0 {
Err(super::last_error())
} else {
Ok(n as u64)
}
}
pub fn fsync(&self) -> IoResult<()> {
mkerr_libc(retry(|| unsafe { libc::fsync(self.fd()) }))
}
pub fn datasync(&self) -> IoResult<()> {
return mkerr_libc(os_datasync(self.fd()));
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn os_datasync(fd: c_int) -> c_int {
unsafe { libc::fcntl(fd, libc::F_FULLFSYNC) }
}
#[cfg(target_os = "linux")]
fn os_datasync(fd: c_int) -> c_int {
retry(|| unsafe { libc::fdatasync(fd) })
}
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))]
fn os_datasync(fd: c_int) -> c_int {
retry(|| unsafe { libc::fsync(fd) })
}
}
pub fn truncate(&self, offset: i64) -> IoResult<()> {
mkerr_libc(retry(|| unsafe {
libc::ftruncate(self.fd(), offset as libc::off_t)
}))
}
pub fn fstat(&self) -> IoResult<FileStat> {
let mut stat: libc::stat = unsafe { mem::zeroed() };
match unsafe { libc::fstat(self.fd(), &mut stat) } {
0 => Ok(mkstat(&stat)),
_ => Err(super::last_error()),
}
}
/// Extract the actual filedescriptor without closing it.
pub fn unwrap(self) -> fd_t {
let fd = self.fd;
unsafe { mem::forget(self) };
fd
}
}
impl Drop for FileDesc {
fn drop(&mut self) {
// closing stdio file handles makes no sense, so never do it. Also, note
// that errors are ignored when closing a file descriptor. The reason
// for this is that if an error occurs we don't actually know if the
// file descriptor was closed or not, and if we retried (for something
// like EINTR), we might close another valid file descriptor (opened
// after we closed ours.
if self.close_on_drop && self.fd > libc::STDERR_FILENO {
let n = unsafe { libc::close(self.fd) };
if n != 0 {
println!("error {} when closing file descriptor {}", n, self.fd);
}
}
}
}
fn cstr(path: &Path) -> IoResult<CString> {
Ok(try!(CString::new(path.as_vec())))
}
pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
let flags = match fm {
Open => 0,
Append => libc::O_APPEND,
Truncate => libc::O_TRUNC,
};
// Opening with a write permission must silently create the file.
let (flags, mode) = match fa {
Read => (flags | libc::O_RDONLY, 0),
Write => (flags | libc::O_WRONLY | libc::O_CREAT,
libc::S_IRUSR | libc::S_IWUSR),
ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT,
libc::S_IRUSR | libc::S_IWUSR),
};
let path = try!(cstr(path));
match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) {
-1 => Err(super::last_error()),
fd => Ok(FileDesc::new(fd, true)),
}
}
pub fn mkdir(p: &Path, mode: usize) -> IoResult<()> {
let p = try!(cstr(p));
mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) })
}
pub fn readdir(p: &Path) -> IoResult<Vec<Path>> {
use libc::{dirent_t};
use libc::{opendir, readdir_r, closedir};
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
let root = Path::new(root);
dirs.into_iter().filter(|path| {
path.as_vec() != b"." && path.as_vec() != b".."
}).map(|path| root.join(path)).collect()
}
extern {
fn rust_dirent_t_size() -> libc::c_int;
fn rust_list_dir_val(ptr: *mut dirent_t) -> *const libc::c_char;
}
let size = unsafe { rust_dirent_t_size() };
let mut buf = Vec::<u8>::with_capacity(size as usize);
let ptr = buf.as_mut_ptr() as *mut dirent_t;
let p = try!(CString::new(p.as_vec()));
let dir_ptr = unsafe {opendir(p.as_ptr())};
if dir_ptr as usize != 0 {
let mut paths = vec!();
let mut entry_ptr = ptr::null_mut();
while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
if entry_ptr.is_null() { break }
paths.push(unsafe {
Path::new(CStr::from_ptr(rust_list_dir_val(entry_ptr)).to_bytes())
});
}
assert_eq!(unsafe { closedir(dir_ptr) }, 0);
Ok(prune(&p, paths))
} else {
Err(super::last_error())
}
}
pub fn unlink(p: &Path) -> IoResult<()> {
let p = try!(cstr(p));
mkerr_libc(unsafe { libc::unlink(p.as_ptr()) })
}
pub fn rename(old: &Path, new: &Path) -> IoResult<()> {
let old = try!(cstr(old));
let new = try!(cstr(new));
mkerr_libc(unsafe {
libc::rename(old.as_ptr(), new.as_ptr())
})
}
pub fn chmod(p: &Path, mode: usize) -> IoResult<()> {
let p = try!(cstr(p));
mkerr_libc(retry(|| unsafe {
libc::chmod(p.as_ptr(), mode as libc::mode_t)
}))
}
pub fn rmdir(p: &Path) -> IoResult<()> {
let p = try!(cstr(p));
mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) })
}
pub fn chown(p: &Path, uid: isize, gid: isize) -> IoResult<()> {
let p = try!(cstr(p));
mkerr_libc(retry(|| unsafe {
libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
}))
}
pub fn readlink(p: &Path) -> IoResult<Path> {
let c_path = try!(cstr(p));
let p = c_path.as_ptr();
let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
if len == -1 {
len = 1024; // FIXME: read PATH_MAX from C ffi?
}
let mut buf: Vec<u8> = Vec::with_capacity(len as usize);
match unsafe {
libc::readlink(p, buf.as_ptr() as *mut libc::c_char,
len as libc::size_t) as libc::c_int
} {
-1 => Err(super::last_error()),
n => {
assert!(n > 0);
unsafe { buf.set_len(n as usize); }
Ok(Path::new(buf))
}
}
}
pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
let src = try!(cstr(src));
let dst = try!(cstr(dst));
mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })
}
pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
let src = try!(cstr(src));
let dst = try!(cstr(dst));
mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })
}
fn mkstat(stat: &libc::stat) -> FileStat {
// FileStat times are in milliseconds
fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 }
fn ctime(stat: &libc::stat) -> u64 {
mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64)
}
fn atime(stat: &libc::stat) -> u64 {
mktime(stat.st_atime as u64, stat.st_atime_nsec as u64)
}
fn mtime(stat: &libc::stat) -> u64 {
mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64)
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn flags(stat: &libc::stat) -> u64 { stat.st_flags as u64 }
#[cfg(any(target_os = "linux", target_os = "android"))]
fn flags(_stat: &libc::stat) -> u64 { 0 }
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn gen(stat: &libc::stat) -> u64 { stat.st_gen as u64 }
#[cfg(any(target_os = "linux", target_os = "android"))]
fn gen(_stat: &libc::stat) -> u64 { 0 }
FileStat {
size: stat.st_size as u64,
kind: match (stat.st_mode as libc::mode_t) & libc::S_IFMT {
libc::S_IFREG => old_io::FileType::RegularFile,
libc::S_IFDIR => old_io::FileType::Directory,
libc::S_IFIFO => old_io::FileType::NamedPipe,
libc::S_IFBLK => old_io::FileType::BlockSpecial,
libc::S_IFLNK => old_io::FileType::Symlink,
_ => old_io::FileType::Unknown,
},
perm: FilePermission::from_bits_truncate(stat.st_mode as u32),
created: ctime(stat),
modified: mtime(stat),
accessed: atime(stat),
unstable: UnstableFileStat {
device: stat.st_dev as u64,
inode: stat.st_ino as u64,
rdev: stat.st_rdev as u64,
nlink: stat.st_nlink as u64,
uid: stat.st_uid as u64,
gid: stat.st_gid as u64,
blksize: stat.st_blksize as u64,
blocks: stat.st_blocks as u64,
flags: flags(stat),
gen: gen(stat),
},
}
}
pub fn stat(p: &Path) -> IoResult<FileStat> {
let p = try!(cstr(p));
let mut stat: libc::stat = unsafe { mem::zeroed() };
match unsafe { libc::stat(p.as_ptr(), &mut stat) } {
0 => Ok(mkstat(&stat)),
_ => Err(super::last_error()),
}
}
pub fn lstat(p: &Path) -> IoResult<FileStat> {
let p = try!(cstr(p));
let mut stat: libc::stat = unsafe { mem::zeroed() };
match unsafe { libc::lstat(p.as_ptr(), &mut stat) } {
0 => Ok(mkstat(&stat)),
_ => Err(super::last_error()),
}
}
pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
let p = try!(cstr(p));
let buf = libc::utimbuf {
actime: (atime / 1000) as libc::time_t,
modtime: (mtime / 1000) as libc::time_t,
};
mkerr_libc(unsafe { libc::utime(p.as_ptr(), &buf) })
}
#[cfg(test)]
mod tests {
use super::FileDesc;
use libc;
use os;
use prelude::v1::*;
#[cfg_attr(any(target_os = "freebsd",
target_os = "openbsd",
target_os = "bitrig"),
ignore)]
// under some system, pipe(2) will return a bidrectionnal pipe
#[test]
fn test_file_desc() {
// Run this test with some pipes so we don't have to mess around with
// opening or closing files.
let (mut reader, mut writer) = unsafe { ::sys::os::pipe().unwrap() };
writer.write(b"test").unwrap();
let mut buf = [0; 4];
match reader.read(&mut buf) {
Ok(4) => {
assert_eq!(buf[0], 't' as u8);
assert_eq!(buf[1], 'e' as u8);
assert_eq!(buf[2], 's' as u8);
assert_eq!(buf[3], 't' as u8);
}
r => panic!("invalid read: {:?}", r),
}
assert!(writer.read(&mut buf).is_err());
assert!(reader.write(&buf).is_err());
}
}

View File

@ -13,124 +13,30 @@
use prelude::v1::*;
use ffi::CStr;
use io::{self, ErrorKind};
use libc;
use num::{Int, SignedInt};
use old_io::{self, IoError};
use str;
use sys_common::mkerr_libc;
pub mod backtrace;
pub mod c;
pub mod condvar;
pub mod ext;
pub mod fd;
pub mod fs; // support for std::old_io
pub mod fs2; // support for std::fs
pub mod helper_signal;
pub mod fs2;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod pipe;
pub mod pipe2;
pub mod process;
pub mod process2;
pub mod rwlock;
pub mod stack_overflow;
pub mod sync;
pub mod tcp;
pub mod thread;
pub mod thread_local;
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;
pub use sys_common::net::get_address_name;
}
// FIXME: move these to c module
pub type sock_t = self::fs::fd_t;
pub type wrlen = libc::size_t;
pub type msglen_t = libc::size_t;
pub unsafe fn close_sock(sock: sock_t) { let _ = libc::close(sock); }
#[allow(deprecated)]
pub fn last_error() -> IoError {
decode_error_detailed(os::errno() as i32)
}
#[allow(deprecated)]
pub fn last_net_error() -> IoError {
last_error()
}
extern "system" {
fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char;
}
#[allow(deprecated)]
pub fn last_gai_error(s: libc::c_int) -> IoError {
let mut err = decode_error(s);
err.detail = Some(unsafe {
let data = CStr::from_ptr(gai_strerror(s));
str::from_utf8(data.to_bytes()).unwrap().to_string()
});
err
}
/// Convert an `errno` value into a high-level error variant and description.
#[allow(deprecated)]
pub fn decode_error(errno: i32) -> IoError {
// FIXME: this should probably be a bit more descriptive...
let (kind, desc) = match errno {
libc::EOF => (old_io::EndOfFile, "end of file"),
libc::ECONNREFUSED => (old_io::ConnectionRefused, "connection refused"),
libc::ECONNRESET => (old_io::ConnectionReset, "connection reset"),
libc::EPERM | libc::EACCES =>
(old_io::PermissionDenied, "permission denied"),
libc::EPIPE => (old_io::BrokenPipe, "broken pipe"),
libc::ENOTCONN => (old_io::NotConnected, "not connected"),
libc::ECONNABORTED => (old_io::ConnectionAborted, "connection aborted"),
libc::EADDRNOTAVAIL => (old_io::ConnectionRefused, "address not available"),
libc::EADDRINUSE => (old_io::ConnectionRefused, "address in use"),
libc::ENOENT => (old_io::FileNotFound, "no such file or directory"),
libc::EISDIR => (old_io::InvalidInput, "illegal operation on a directory"),
libc::ENOSYS => (old_io::IoUnavailable, "function not implemented"),
libc::EINVAL => (old_io::InvalidInput, "invalid argument"),
libc::ENOTTY =>
(old_io::MismatchedFileTypeForOperation,
"file descriptor is not a TTY"),
libc::ETIMEDOUT => (old_io::TimedOut, "operation timed out"),
libc::ECANCELED => (old_io::TimedOut, "operation aborted"),
libc::consts::os::posix88::EEXIST =>
(old_io::PathAlreadyExists, "path already exists"),
// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
// clause
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
(old_io::ResourceUnavailable, "resource temporarily unavailable"),
_ => (old_io::OtherIoError, "unknown error")
};
IoError { kind: kind, desc: desc, detail: None }
}
#[allow(deprecated)]
pub fn decode_error_detailed(errno: i32) -> IoError {
let mut err = decode_error(errno);
err.detail = Some(os::error_string(errno));
err
}
#[allow(deprecated)]
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as libc::c_int {
libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
@ -199,18 +105,3 @@ pub fn ms_to_timeval(ms: u64) -> libc::timeval {
tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t,
}
}
#[allow(deprecated)]
pub fn wouldblock() -> bool {
let err = os::errno();
err == libc::EWOULDBLOCK as i32 || err == libc::EAGAIN as i32
}
#[allow(deprecated)]
pub fn set_nonblocking(fd: sock_t, nb: bool) {
let set = nb as libc::c_int;
mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) })).unwrap();
}
// nothing needed on unix platforms
pub fn init_net() {}

View File

@ -22,14 +22,12 @@ use io;
use iter;
use libc::{self, c_int, c_char, c_void};
use mem;
#[allow(deprecated)] use old_io::{IoError, IoResult};
use ptr;
use path::{self, PathBuf};
use slice;
use str;
use sys::c;
use sys::fd;
use sys::fs::FileDesc;
use vec;
const BUF_BYTES: usize = 2048;
@ -448,16 +446,6 @@ pub fn unsetenv(n: &OsStr) {
}
}
#[allow(deprecated)]
pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
let mut fds = [0; 2];
if libc::pipe(fds.as_mut_ptr()) == 0 {
Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
} else {
Err(IoError::last_error())
}
}
pub fn page_size() -> usize {
unsafe {
libc::sysconf(libc::_SC_PAGESIZE) as usize

View File

@ -1,328 +0,0 @@
// Copyright 2014 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.
#![allow(deprecated)]
use prelude::v1::*;
use ffi::CString;
use libc;
use mem;
use sync::{Arc, Mutex};
use sync::atomic::{AtomicBool, Ordering};
use old_io::{self, IoResult, IoError};
use sys::{self, timer, retry, c, set_nonblocking, wouldblock};
use sys::fs::{fd_t, FileDesc};
use sys_common::net::*;
use sys_common::net::SocketStatus::*;
use sys_common::{eof, mkerr_libc};
fn unix_socket(ty: libc::c_int) -> IoResult<fd_t> {
match unsafe { libc::socket(libc::AF_UNIX, ty, 0) } {
-1 => Err(super::last_error()),
fd => Ok(fd)
}
}
fn addr_to_sockaddr_un(addr: &CString,
storage: &mut libc::sockaddr_storage)
-> IoResult<libc::socklen_t> {
// the sun_path length is limited to SUN_LEN (with null)
assert!(mem::size_of::<libc::sockaddr_storage>() >=
mem::size_of::<libc::sockaddr_un>());
let s = unsafe { &mut *(storage as *mut _ as *mut libc::sockaddr_un) };
let len = addr.as_bytes().len();
if len > s.sun_path.len() - 1 {
return Err(IoError {
kind: old_io::InvalidInput,
desc: "invalid argument: path must be smaller than SUN_LEN",
detail: None,
})
}
s.sun_family = libc::AF_UNIX as libc::sa_family_t;
for (slot, value) in s.sun_path.iter_mut().zip(addr.as_bytes().iter()) {
*slot = *value as libc::c_char;
}
// count the null terminator
let len = mem::size_of::<libc::sa_family_t>() + len + 1;
return Ok(len as libc::socklen_t);
}
struct Inner {
fd: fd_t,
// Unused on Linux, where this lock is not necessary.
#[allow(dead_code)]
lock: Mutex<()>,
}
impl Inner {
fn new(fd: fd_t) -> Inner {
Inner { fd: fd, lock: Mutex::new(()) }
}
}
impl Drop for Inner {
fn drop(&mut self) { unsafe { let _ = libc::close(self.fd); } }
}
fn connect(addr: &CString, ty: libc::c_int,
timeout: Option<u64>) -> IoResult<Inner> {
let mut storage = unsafe { mem::zeroed() };
let len = try!(addr_to_sockaddr_un(addr, &mut storage));
let inner = Inner::new(try!(unix_socket(ty)));
let addrp = &storage as *const _ as *const libc::sockaddr;
match timeout {
None => {
match retry(|| unsafe { libc::connect(inner.fd, addrp, len) }) {
-1 => Err(super::last_error()),
_ => Ok(inner)
}
}
Some(timeout_ms) => {
try!(connect_timeout(inner.fd, addrp, len, timeout_ms));
Ok(inner)
}
}
}
fn bind(addr: &CString, ty: libc::c_int) -> IoResult<Inner> {
let mut storage = unsafe { mem::zeroed() };
let len = try!(addr_to_sockaddr_un(addr, &mut storage));
let inner = Inner::new(try!(unix_socket(ty)));
let addrp = &storage as *const _ as *const libc::sockaddr;
match unsafe {
libc::bind(inner.fd, addrp, len)
} {
-1 => Err(super::last_error()),
_ => Ok(inner)
}
}
////////////////////////////////////////////////////////////////////////////////
// Unix Streams
////////////////////////////////////////////////////////////////////////////////
pub struct UnixStream {
inner: Arc<Inner>,
read_deadline: u64,
write_deadline: u64,
}
impl UnixStream {
pub fn connect(addr: &CString,
timeout: Option<u64>) -> IoResult<UnixStream> {
connect(addr, libc::SOCK_STREAM, timeout).map(|inner| {
UnixStream::new(Arc::new(inner))
})
}
fn new(inner: Arc<Inner>) -> UnixStream {
UnixStream {
inner: inner,
read_deadline: 0,
write_deadline: 0,
}
}
pub fn fd(&self) -> fd_t { self.inner.fd }
#[cfg(target_os = "linux")]
fn lock_nonblocking(&self) {}
#[cfg(not(target_os = "linux"))]
fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
let ret = Guard {
fd: self.fd(),
guard: self.inner.lock.lock().unwrap(),
};
set_nonblocking(self.fd(), true);
ret
}
pub fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
let fd = self.fd();
let dolock = || self.lock_nonblocking();
let doread = |nb| unsafe {
let flags = if nb {c::MSG_DONTWAIT} else {0};
libc::recv(fd,
buf.as_mut_ptr() as *mut libc::c_void,
buf.len() as libc::size_t,
flags) as libc::c_int
};
read(fd, self.read_deadline, dolock, doread)
}
pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
let fd = self.fd();
let dolock = || self.lock_nonblocking();
let dowrite = |nb: bool, buf: *const u8, len: usize| unsafe {
let flags = if nb {c::MSG_DONTWAIT} else {0};
libc::send(fd,
buf as *const _,
len as libc::size_t,
flags) as i64
};
match write(fd, self.write_deadline, buf, true, dolock, dowrite) {
Ok(_) => Ok(()),
Err(e) => Err(e)
}
}
pub fn close_write(&mut self) -> IoResult<()> {
mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) })
}
pub fn close_read(&mut self) -> IoResult<()> {
mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) })
}
pub fn set_timeout(&mut self, timeout: Option<u64>) {
let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
self.read_deadline = deadline;
self.write_deadline = deadline;
}
pub fn set_read_timeout(&mut self, timeout: Option<u64>) {
self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
}
pub fn set_write_timeout(&mut self, timeout: Option<u64>) {
self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
}
}
impl Clone for UnixStream {
fn clone(&self) -> UnixStream {
UnixStream::new(self.inner.clone())
}
}
////////////////////////////////////////////////////////////////////////////////
// Unix Listener
////////////////////////////////////////////////////////////////////////////////
pub struct UnixListener {
inner: Inner,
path: CString,
}
// we currently own the CString, so these impls should be safe
unsafe impl Send for UnixListener {}
unsafe impl Sync for UnixListener {}
impl UnixListener {
pub fn bind(addr: &CString) -> IoResult<UnixListener> {
bind(addr, libc::SOCK_STREAM).map(|fd| {
UnixListener { inner: fd, path: addr.clone() }
})
}
pub fn fd(&self) -> fd_t { self.inner.fd }
pub fn listen(self) -> IoResult<UnixAcceptor> {
match unsafe { libc::listen(self.fd(), 128) } {
-1 => Err(super::last_error()),
_ => {
let (reader, writer) = try!(unsafe { sys::os::pipe() });
set_nonblocking(reader.fd(), true);
set_nonblocking(writer.fd(), true);
set_nonblocking(self.fd(), true);
Ok(UnixAcceptor {
inner: Arc::new(AcceptorInner {
listener: self,
reader: reader,
writer: writer,
closed: AtomicBool::new(false),
}),
deadline: 0,
})
}
}
}
}
pub struct UnixAcceptor {
inner: Arc<AcceptorInner>,
deadline: u64,
}
struct AcceptorInner {
listener: UnixListener,
reader: FileDesc,
writer: FileDesc,
closed: AtomicBool,
}
impl UnixAcceptor {
pub fn fd(&self) -> fd_t { self.inner.listener.fd() }
pub fn accept(&mut self) -> IoResult<UnixStream> {
let deadline = if self.deadline == 0 {None} else {Some(self.deadline)};
while !self.inner.closed.load(Ordering::SeqCst) {
unsafe {
let mut storage: libc::sockaddr_storage = mem::zeroed();
let storagep = &mut storage as *mut libc::sockaddr_storage;
let size = mem::size_of::<libc::sockaddr_storage>();
let mut size = size as libc::socklen_t;
match retry(|| {
libc::accept(self.fd(),
storagep as *mut libc::sockaddr,
&mut size as *mut libc::socklen_t) as libc::c_int
}) {
-1 if wouldblock() => {}
-1 => return Err(super::last_error()),
fd => return Ok(UnixStream::new(Arc::new(Inner::new(fd)))),
}
}
try!(await(&[self.fd(), self.inner.reader.fd()],
deadline, Readable));
}
Err(eof())
}
pub fn set_timeout(&mut self, timeout: Option<u64>) {
self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
}
pub fn close_accept(&mut self) -> IoResult<()> {
self.inner.closed.store(true, Ordering::SeqCst);
let fd = FileDesc::new(self.inner.writer.fd(), false);
match fd.write(&[0]) {
Ok(..) => Ok(()),
Err(..) if wouldblock() => Ok(()),
Err(e) => Err(e),
}
}
}
impl Clone for UnixAcceptor {
fn clone(&self) -> UnixAcceptor {
UnixAcceptor { inner: self.inner.clone(), deadline: 0 }
}
}
impl Drop for UnixListener {
fn drop(&mut self) {
// Unlink the path to the socket to ensure that it doesn't linger. We're
// careful to unlink the path before we close the file descriptor to
// prevent races where we unlink someone else's path.
unsafe {
let _ = libc::unlink(self.path.as_ptr());
}
}
}

View File

@ -1,627 +0,0 @@
// Copyright 2014-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.
#![allow(deprecated)] // this module itself is essentially deprecated
use prelude::v1::*;
use self::Req::*;
use collections::HashMap;
use ffi::CString;
use hash::Hash;
use old_io::process::{ProcessExit, ExitStatus, ExitSignal};
use old_io::{IoResult, EndOfFile};
use libc::{self, pid_t, c_void, c_int};
use io;
use mem;
use sys::os;
use old_path::BytesContainer;
use ptr;
use sync::mpsc::{channel, Sender, Receiver};
use sys::fs::FileDesc;
use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval};
use sys_common::helper_thread::Helper;
use sys_common::{AsInner, mkerr_libc, timeout};
pub use sys_common::ProcessConfig;
helper_init! { static HELPER: Helper<Req> }
/// The unique id of the process (this should never be negative).
pub struct Process {
pub pid: pid_t
}
enum Req {
NewChild(libc::pid_t, Sender<ProcessExit>, u64),
}
const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
impl Process {
pub fn id(&self) -> pid_t {
self.pid
}
pub unsafe fn kill(&self, signal: isize) -> IoResult<()> {
Process::killpid(self.pid, signal)
}
pub unsafe fn killpid(pid: pid_t, signal: isize) -> IoResult<()> {
let r = libc::funcs::posix88::signal::kill(pid, signal as c_int);
mkerr_libc(r)
}
pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>,
out_fd: Option<P>, err_fd: Option<P>)
-> IoResult<Process>
where C: ProcessConfig<K, V>, P: AsInner<FileDesc>,
K: BytesContainer + Eq + Hash, V: BytesContainer
{
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
mod rustrt {
extern {
pub fn rust_unset_sigprocmask();
}
}
unsafe fn set_cloexec(fd: c_int) {
let ret = c::ioctl(fd, c::FIOCLEX);
assert_eq!(ret, 0);
}
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
unsafe fn getdtablesize() -> c_int {
libc::sysconf(libc::consts::os::sysconf::_SC_OPEN_MAX) as c_int
}
#[cfg(not(all(target_os = "android", target_arch = "aarch64")))]
unsafe fn getdtablesize() -> c_int {
libc::funcs::bsd44::getdtablesize()
}
let dirp = cfg.cwd().map(|c| c.as_ptr()).unwrap_or(ptr::null());
// temporary until unboxed closures land
let cfg = unsafe {
mem::transmute::<&ProcessConfig<K,V>,&'static ProcessConfig<K,V>>(cfg)
};
with_envp(cfg.env(), move|envp: *const c_void| {
with_argv(cfg.program(), cfg.args(), move|argv: *const *const libc::c_char| unsafe {
let (input, mut output) = try!(sys::os::pipe());
// We may use this in the child, so perform allocations before the
// fork
let devnull = b"/dev/null\0";
set_cloexec(output.fd());
let pid = fork();
if pid < 0 {
return Err(super::last_error())
} else if pid > 0 {
#[inline]
fn combine(arr: &[u8]) -> i32 {
let a = arr[0] as u32;
let b = arr[1] as u32;
let c = arr[2] as u32;
let d = arr[3] as u32;
((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
}
let p = Process{ pid: pid };
drop(output);
let mut bytes = [0; 8];
return match input.read(&mut bytes) {
Ok(8) => {
assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
"Validation on the CLOEXEC pipe failed: {:?}", bytes);
let errno = combine(&bytes[0.. 4]);
assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic");
Err(super::decode_error(errno))
}
Err(ref e) if e.kind == EndOfFile => Ok(p),
Err(e) => {
assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic");
panic!("the CLOEXEC pipe failed: {:?}", e)
},
Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic");
panic!("short read on the CLOEXEC pipe")
}
};
}
// And at this point we've reached a special time in the life of the
// child. The child must now be considered hamstrung and unable to
// do anything other than syscalls really. Consider the following
// scenario:
//
// 1. Thread A of process 1 grabs the malloc() mutex
// 2. Thread B of process 1 forks(), creating thread C
// 3. Thread C of process 2 then attempts to malloc()
// 4. The memory of process 2 is the same as the memory of
// process 1, so the mutex is locked.
//
// This situation looks a lot like deadlock, right? It turns out
// that this is what pthread_atfork() takes care of, which is
// presumably implemented across platforms. The first thing that
// threads to *before* forking is to do things like grab the malloc
// mutex, and then after the fork they unlock it.
//
// Despite this information, libnative's spawn has been witnessed to
// deadlock on both OSX and FreeBSD. I'm not entirely sure why, but
// all collected backtraces point at malloc/free traffic in the
// child spawned process.
//
// For this reason, the block of code below should contain 0
// invocations of either malloc of free (or their related friends).
//
// As an example of not having malloc/free traffic, we don't close
// this file descriptor by dropping the FileDesc (which contains an
// allocation). Instead we just close it manually. This will never
// have the drop glue anyway because this code never returns (the
// child will either exec() or invoke libc::exit)
let _ = libc::close(input.fd());
fn fail(output: &mut FileDesc) -> ! {
let errno = sys::os::errno() as u32;
let bytes = [
(errno >> 24) as u8,
(errno >> 16) as u8,
(errno >> 8) as u8,
(errno >> 0) as u8,
CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
];
// pipe I/O up to PIPE_BUF bytes should be atomic
assert!(output.write(&bytes).is_ok());
unsafe { libc::_exit(1) }
}
rustrt::rust_unset_sigprocmask();
// If a stdio file descriptor is set to be ignored (via a -1 file
// descriptor), then we don't actually close it, but rather open
// up /dev/null into that file descriptor. Otherwise, the first file
// descriptor opened up in the child would be numbered as one of the
// stdio file descriptors, which is likely to wreak havoc.
let setup = |src: Option<P>, dst: c_int| {
let src = match src {
None => {
let flags = if dst == libc::STDIN_FILENO {
libc::O_RDONLY
} else {
libc::O_RDWR
};
libc::open(devnull.as_ptr() as *const _, flags, 0)
}
Some(obj) => {
let fd = obj.as_inner().fd();
// Leak the memory and the file descriptor. We're in the
// child now an all our resources are going to be
// cleaned up very soon
mem::forget(obj);
fd
}
};
src != -1 && retry(|| dup2(src, dst)) != -1
};
if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) }
if !setup(out_fd, libc::STDOUT_FILENO) { fail(&mut output) }
if !setup(err_fd, libc::STDERR_FILENO) { fail(&mut output) }
// close all other fds
for fd in (3..getdtablesize()).rev() {
if fd != output.fd() {
let _ = close(fd as c_int);
}
}
match cfg.gid() {
Some(u) => {
if libc::setgid(u as libc::gid_t) != 0 {
fail(&mut output);
}
}
None => {}
}
match cfg.uid() {
Some(u) => {
// When dropping privileges from root, the `setgroups` call
// will remove any extraneous groups. If we don't call this,
// then even though our uid has dropped, we may still have
// groups that enable us to do super-user things. This will
// fail if we aren't root, so don't bother checking the
// return value, this is just done as an optimistic
// privilege dropping function.
extern {
fn setgroups(ngroups: libc::c_int,
ptr: *const libc::c_void) -> libc::c_int;
}
let _ = setgroups(0, ptr::null());
if libc::setuid(u as libc::uid_t) != 0 {
fail(&mut output);
}
}
None => {}
}
if cfg.detach() {
// Don't check the error of setsid because it fails if we're the
// process leader already. We just forked so it shouldn't return
// error, but ignore it anyway.
let _ = libc::setsid();
}
if !dirp.is_null() && chdir(dirp) == -1 {
fail(&mut output);
}
if !envp.is_null() {
*sys::os::environ() = envp as *const _;
}
let _ = execvp(*argv, argv as *mut _);
fail(&mut output);
})
})
}
pub fn wait(&self, deadline: u64) -> IoResult<ProcessExit> {
use cmp;
use sync::mpsc::TryRecvError;
static mut WRITE_FD: libc::c_int = 0;
let mut status = 0 as c_int;
if deadline == 0 {
return match retry(|| unsafe { c::waitpid(self.pid, &mut status, 0) }) {
-1 => panic!("unknown waitpid error: {:?}", super::last_error()),
_ => Ok(translate_status(status)),
}
}
// On unix, wait() and its friends have no timeout parameters, so there is
// no way to time out a thread in wait(). From some googling and some
// thinking, it appears that there are a few ways to handle timeouts in
// wait(), but the only real reasonable one for a multi-threaded program is
// to listen for SIGCHLD.
//
// With this in mind, the waiting mechanism with a timeout barely uses
// waitpid() at all. There are a few times that waitpid() is invoked with
// WNOHANG, but otherwise all the necessary blocking is done by waiting for
// a SIGCHLD to arrive (and that blocking has a timeout). Note, however,
// that waitpid() is still used to actually reap the child.
//
// Signal handling is super tricky in general, and this is no exception. Due
// to the async nature of SIGCHLD, we use the self-pipe trick to transmit
// data out of the signal handler to the rest of the application. The first
// idea would be to have each thread waiting with a timeout to read this
// output file descriptor, but a write() is akin to a signal(), not a
// broadcast(), so it would only wake up one thread, and possibly the wrong
// thread. Hence a helper thread is used.
//
// The helper thread here is responsible for farming requests for a
// waitpid() with a timeout, and then processing all of the wait requests.
// By guaranteeing that only this helper thread is reading half of the
// self-pipe, we're sure that we'll never lose a SIGCHLD. This helper thread
// is also responsible for select() to wait for incoming messages or
// incoming SIGCHLD messages, along with passing an appropriate timeout to
// select() to wake things up as necessary.
//
// The ordering of the following statements is also very purposeful. First,
// we must be guaranteed that the helper thread is booted and available to
// receive SIGCHLD signals, and then we must also ensure that we do a
// nonblocking waitpid() at least once before we go ask the sigchld helper.
// This prevents the race where the child exits, we boot the helper, and
// then we ask for the child's exit status (never seeing a sigchld).
//
// The actual communication between the helper thread and this thread is
// quite simple, just a channel moving data around.
HELPER.boot(register_sigchld, waitpid_helper);
match self.try_wait() {
Some(ret) => return Ok(ret),
None => {}
}
let (tx, rx) = channel();
HELPER.send(NewChild(self.pid, tx, deadline));
return match rx.recv() {
Ok(e) => Ok(e),
Err(..) => Err(timeout("wait timed out")),
};
// Register a new SIGCHLD handler, returning the reading half of the
// self-pipe plus the old handler registered (return value of sigaction).
//
// Be sure to set up the self-pipe first because as soon as we register a
// handler we're going to start receiving signals.
fn register_sigchld() -> (libc::c_int, c::sigaction) {
unsafe {
let mut pipes = [0; 2];
assert_eq!(libc::pipe(pipes.as_mut_ptr()), 0);
set_nonblocking(pipes[0], true);
set_nonblocking(pipes[1], true);
WRITE_FD = pipes[1];
let mut old: c::sigaction = mem::zeroed();
let mut new: c::sigaction = mem::zeroed();
new.sa_handler = sigchld_handler;
new.sa_flags = c::SA_NOCLDSTOP;
assert_eq!(c::sigaction(c::SIGCHLD, &new, &mut old), 0);
(pipes[0], old)
}
}
// Helper thread for processing SIGCHLD messages
fn waitpid_helper(input: libc::c_int,
messages: Receiver<Req>,
(read_fd, old): (libc::c_int, c::sigaction)) {
set_nonblocking(input, true);
let mut set: c::fd_set = unsafe { mem::zeroed() };
let mut tv: libc::timeval;
let mut active = Vec::<(libc::pid_t, Sender<ProcessExit>, u64)>::new();
let max = cmp::max(input, read_fd) + 1;
'outer: loop {
// Figure out the timeout of our syscall-to-happen. If we're waiting
// for some processes, then they'll have a timeout, otherwise we
// wait indefinitely for a message to arrive.
//
// FIXME: sure would be nice to not have to scan the entire array
let min = active.iter().map(|a| a.2).enumerate().min_by(|p| {
p.1
});
let (p, idx) = match min {
Some((idx, deadline)) => {
let now = sys::timer::now();
let ms = if now < deadline {deadline - now} else {0};
tv = ms_to_timeval(ms);
(&mut tv as *mut _, idx)
}
None => (ptr::null_mut(), -1),
};
// Wait for something to happen
c::fd_set(&mut set, input);
c::fd_set(&mut set, read_fd);
match unsafe { c::select(max, &mut set, ptr::null_mut(),
ptr::null_mut(), p) } {
// interrupted, retry
-1 if os::errno() == libc::EINTR as i32 => continue,
// We read something, break out and process
1 | 2 => {}
// Timeout, the pending request is removed
0 => {
drop(active.remove(idx));
continue
}
n => panic!("error in select {:?} ({:?})", os::errno(), n),
}
// Process any pending messages
if drain(input) {
loop {
match messages.try_recv() {
Ok(NewChild(pid, tx, deadline)) => {
active.push((pid, tx, deadline));
}
// Once we've been disconnected it means the main
// thread is exiting (at_exit has run). We could
// still have active waiter for other threads, so
// we're just going to drop them all on the floor.
// This means that they won't receive a "you're
// done" message in which case they'll be considered
// as timed out, but more generally errors will
// start propagating.
Err(TryRecvError::Disconnected) => {
break 'outer;
}
Err(TryRecvError::Empty) => break,
}
}
}
// If a child exited (somehow received SIGCHLD), then poll all
// children to see if any of them exited.
//
// We also attempt to be responsible netizens when dealing with
// SIGCHLD by invoking any previous SIGCHLD handler instead of just
// ignoring any previous SIGCHLD handler. Note that we don't provide
// a 1:1 mapping of our handler invocations to the previous handler
// invocations because we drain the `read_fd` entirely. This is
// probably OK because the kernel is already allowed to coalesce
// simultaneous signals, we're just doing some extra coalescing.
//
// Another point of note is that this likely runs the signal handler
// on a different thread than the one that received the signal. I
// *think* this is ok at this time.
//
// The main reason for doing this is to allow stdtest to run native
// tests as well. Both libgreen and libnative are running around
// with process timeouts, but libgreen should get there first
// (currently libuv doesn't handle old signal handlers).
if drain(read_fd) {
let i: usize = unsafe { mem::transmute(old.sa_handler) };
if i != 0 {
assert!(old.sa_flags & c::SA_SIGINFO == 0);
(old.sa_handler)(c::SIGCHLD);
}
// FIXME: sure would be nice to not have to scan the entire
// array...
active.retain(|&(pid, ref tx, _)| {
let pr = Process { pid: pid };
match pr.try_wait() {
Some(msg) => { tx.send(msg).unwrap(); false }
None => true,
}
});
}
}
// Once this helper thread is done, we re-register the old sigchld
// handler and close our intermediate file descriptors.
unsafe {
assert_eq!(c::sigaction(c::SIGCHLD, &old, ptr::null_mut()), 0);
let _ = libc::close(read_fd);
let _ = libc::close(WRITE_FD);
WRITE_FD = -1;
}
}
// Drain all pending data from the file descriptor, returning if any data
// could be drained. This requires that the file descriptor is in
// nonblocking mode.
fn drain(fd: libc::c_int) -> bool {
let mut ret = false;
loop {
let mut buf = [0u8; 1];
match unsafe {
libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void,
buf.len() as libc::size_t)
} {
n if n > 0 => { ret = true; }
0 => return true,
-1 if wouldblock() => return ret,
n => panic!("bad read {} ({})",
io::Error::last_os_error(), n),
}
}
}
// Signal handler for SIGCHLD signals, must be async-signal-safe!
//
// This function will write to the writing half of the "self pipe" to wake
// up the helper thread if it's waiting. Note that this write must be
// nonblocking because if it blocks and the reader is the thread we
// interrupted, then we'll deadlock.
//
// When writing, if the write returns EWOULDBLOCK then we choose to ignore
// it. At that point we're guaranteed that there's something in the pipe
// which will wake up the other end at some point, so we just allow this
// signal to be coalesced with the pending signals on the pipe.
extern fn sigchld_handler(_signum: libc::c_int) {
let msg = 1;
match unsafe {
libc::write(WRITE_FD, &msg as *const _ as *const libc::c_void, 1)
} {
1 => {}
-1 if wouldblock() => {} // see above comments
n => panic!("bad error on write fd: {:?} {:?}", n, os::errno()),
}
}
}
pub fn try_wait(&self) -> Option<ProcessExit> {
let mut status = 0 as c_int;
match retry(|| unsafe {
c::waitpid(self.pid, &mut status, c::WNOHANG)
}) {
n if n == self.pid => Some(translate_status(status)),
0 => None,
n => panic!("unknown waitpid error `{:?}`: {:?}", n,
super::last_error()),
}
}
}
fn with_argv<T,F>(prog: &CString, args: &[CString],
cb: F)
-> T
where F : FnOnce(*const *const libc::c_char) -> T
{
let mut ptrs: Vec<*const libc::c_char> = Vec::with_capacity(args.len()+1);
// Convert the CStrings into an array of pointers. Note: the
// lifetime of the various CStrings involved is guaranteed to be
// larger than the lifetime of our invocation of cb, but this is
// technically unsafe as the callback could leak these pointers
// out of our scope.
ptrs.push(prog.as_ptr());
ptrs.extend(args.iter().map(|tmp| tmp.as_ptr()));
// Add a terminating null pointer (required by libc).
ptrs.push(ptr::null());
cb(ptrs.as_ptr())
}
fn with_envp<K,V,T,F>(env: Option<&HashMap<K, V>>,
cb: F)
-> T
where F : FnOnce(*const c_void) -> T,
K : BytesContainer + Eq + Hash,
V : BytesContainer
{
// On posixy systems we can pass a char** for envp, which is a
// null-terminated array of "k=v\0" strings. Since we must create
// these strings locally, yet expose a raw pointer to them, we
// create a temporary vector to own the CStrings that outlives the
// call to cb.
match env {
Some(env) => {
let mut tmps = Vec::with_capacity(env.len());
for pair in env {
let mut kv = Vec::new();
kv.push_all(pair.0.container_as_bytes());
kv.push('=' as u8);
kv.push_all(pair.1.container_as_bytes());
kv.push(0); // terminating null
tmps.push(kv);
}
// As with `with_argv`, this is unsafe, since cb could leak the pointers.
let mut ptrs: Vec<*const libc::c_char> =
tmps.iter()
.map(|tmp| tmp.as_ptr() as *const libc::c_char)
.collect();
ptrs.push(ptr::null());
cb(ptrs.as_ptr() as *const c_void)
}
_ => cb(ptr::null())
}
}
fn translate_status(status: c_int) -> ProcessExit {
#![allow(non_snake_case)]
#[cfg(any(target_os = "linux", target_os = "android"))]
mod imp {
pub fn WIFEXITED(status: i32) -> bool { (status & 0xff) == 0 }
pub fn WEXITSTATUS(status: i32) -> i32 { (status >> 8) & 0xff }
pub fn WTERMSIG(status: i32) -> i32 { status & 0x7f }
}
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "bitrig",
target_os = "openbsd"))]
mod imp {
pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 }
pub fn WEXITSTATUS(status: i32) -> i32 { status >> 8 }
pub fn WTERMSIG(status: i32) -> i32 { status & 0o177 }
}
if imp::WIFEXITED(status) {
ExitStatus(imp::WEXITSTATUS(status) as isize)
} else {
ExitSignal(imp::WTERMSIG(status) as isize)
}
}

View File

@ -328,8 +328,8 @@ impl Process {
}) {
n if n == self.pid => Some(translate_status(status)),
0 => None,
n => panic!("unknown waitpid error `{:?}`: {:?}", n,
super::last_error()),
n => panic!("unknown waitpid error `{}`: {}", n,
io::Error::last_os_error()),
}
}
}

View File

@ -1,164 +0,0 @@
// Copyright 2014 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.
#![allow(deprecated)]
use prelude::v1::*;
use old_io::net::ip;
use old_io::IoResult;
use libc;
use mem;
use ptr;
use super::{last_error, last_net_error, retry, sock_t};
use sync::Arc;
use sync::atomic::{AtomicBool, Ordering};
use sys::fs::FileDesc;
use sys::{set_nonblocking, wouldblock};
use sys;
use sys_common;
use sys_common::net;
use sys_common::net::SocketStatus::Readable;
pub use sys_common::net::TcpStream;
////////////////////////////////////////////////////////////////////////////////
// TCP listeners
////////////////////////////////////////////////////////////////////////////////
pub struct TcpListener {
pub inner: FileDesc,
}
unsafe impl Sync for TcpListener {}
impl TcpListener {
pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
let fd = try!(net::socket(addr, libc::SOCK_STREAM));
let ret = TcpListener { inner: FileDesc::new(fd, true) };
let mut storage = unsafe { mem::zeroed() };
let len = net::addr_to_sockaddr(addr, &mut storage);
let addrp = &storage as *const _ as *const libc::sockaddr;
// On platforms with Berkeley-derived sockets, this allows
// to quickly rebind a socket, without needing to wait for
// the OS to clean up the previous one.
try!(net::setsockopt(fd, libc::SOL_SOCKET,
libc::SO_REUSEADDR,
1 as libc::c_int));
match unsafe { libc::bind(fd, addrp, len) } {
-1 => Err(last_error()),
_ => Ok(ret),
}
}
pub fn fd(&self) -> sock_t { self.inner.fd() }
pub fn listen(self, backlog: isize) -> IoResult<TcpAcceptor> {
match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } {
-1 => Err(last_net_error()),
_ => {
let (reader, writer) = try!(unsafe { sys::os::pipe() });
set_nonblocking(reader.fd(), true);
set_nonblocking(writer.fd(), true);
set_nonblocking(self.fd(), true);
Ok(TcpAcceptor {
inner: Arc::new(AcceptorInner {
listener: self,
reader: reader,
writer: writer,
closed: AtomicBool::new(false),
}),
deadline: 0,
})
}
}
}
pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
net::sockname(self.fd(), libc::getsockname)
}
}
pub struct TcpAcceptor {
inner: Arc<AcceptorInner>,
deadline: u64,
}
struct AcceptorInner {
listener: TcpListener,
reader: FileDesc,
writer: FileDesc,
closed: AtomicBool,
}
unsafe impl Sync for AcceptorInner {}
impl TcpAcceptor {
pub fn fd(&self) -> sock_t { self.inner.listener.fd() }
pub fn accept(&mut self) -> IoResult<TcpStream> {
// In implementing accept, the two main concerns are dealing with
// close_accept() and timeouts. The unix implementation is based on a
// nonblocking accept plus a call to select(). Windows ends up having
// an entirely separate implementation than unix, which is explained
// below.
//
// To implement timeouts, all blocking is done via select() instead of
// accept() by putting the socket in non-blocking mode. Because
// select() takes a timeout argument, we just pass through the timeout
// to select().
//
// To implement close_accept(), we have a self-pipe to ourselves which
// is passed to select() along with the socket being accepted on. The
// self-pipe is never written to unless close_accept() is called.
let deadline = if self.deadline == 0 {None} else {Some(self.deadline)};
while !self.inner.closed.load(Ordering::SeqCst) {
match retry(|| unsafe {
libc::accept(self.fd(), ptr::null_mut(), ptr::null_mut())
}) {
-1 if wouldblock() => {}
-1 => return Err(last_net_error()),
fd => return Ok(TcpStream::new(fd as sock_t)),
}
try!(net::await(&[self.fd(), self.inner.reader.fd()],
deadline, Readable));
}
Err(sys_common::eof())
}
pub fn set_timeout(&mut self, timeout: Option<u64>) {
self.deadline = timeout.map(|a| sys::timer::now() + a).unwrap_or(0);
}
pub fn close_accept(&mut self) -> IoResult<()> {
self.inner.closed.store(true, Ordering::SeqCst);
let fd = FileDesc::new(self.inner.writer.fd(), false);
match fd.write(&[0]) {
Ok(..) => Ok(()),
Err(..) if wouldblock() => Ok(()),
Err(e) => Err(e),
}
}
}
impl Clone for TcpAcceptor {
fn clone(&self) -> TcpAcceptor {
TcpAcceptor {
inner: self.inner.clone(),
deadline: 0,
}
}
}

View File

@ -1,294 +0,0 @@
// Copyright 2013 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.
//! Timers for non-Linux/non-Windows OSes
//!
//! This module implements timers with a worker thread, select(), and a lot of
//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate
//! part is that I'm at a loss of what else to do one these OSes. This is also
//! why Linux has a specialized timerfd implementation and windows has its own
//! implementation (they're more accurate than this one).
//!
//! The basic idea is that there is a worker thread that's communicated to via a
//! channel and a pipe, the pipe is used by the worker thread in a select()
//! syscall with a timeout. The timeout is the "next timer timeout" while the
//! channel is used to send data over to the worker thread.
//!
//! Whenever the call to select() times out, then a channel receives a message.
//! Whenever the call returns that the file descriptor has information, then the
//! channel from timers is drained, enqueuing all incoming requests.
//!
//! The actual implementation of the helper thread is a sorted array of
//! timers in terms of target firing date. The target is the absolute time at
//! which the timer should fire. Timers are then re-enqueued after a firing if
//! the repeat boolean is set.
//!
//! Naturally, all this logic of adding times and keeping track of
//! relative/absolute time is a little lossy and not quite exact. I've done the
//! best I could to reduce the amount of calls to 'now()', but there's likely
//! still inaccuracies trickling in here and there.
//!
//! One of the tricky parts of this implementation is that whenever a timer is
//! acted upon, it must cancel whatever the previous action was (if one is
//! active) in order to act like the other implementations of this timer. In
//! order to do this, the timer's inner pointer is transferred to the worker
//! thread. Whenever the timer is modified, it first takes ownership back from
//! the worker thread in order to modify the same data structure. This has the
//! side effect of "cancelling" the previous requests while allowing a
//! re-enqueuing later on.
//!
//! Note that all time units in this file are in *milliseconds*.
#![allow(deprecated)]
use prelude::v1::*;
use self::Req::*;
use old_io::IoResult;
use libc;
use mem;
use sys::os;
use io;
use ptr;
use sync::atomic::{self, Ordering};
use sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use sys::c;
use sys::fs::FileDesc;
use sys_common::helper_thread::Helper;
helper_init! { static HELPER: Helper<Req> }
pub trait Callback {
fn call(&mut self);
}
pub struct Timer {
id: usize,
inner: Option<Box<Inner>>,
}
pub struct Inner {
cb: Option<Box<Callback + Send>>,
interval: u64,
repeat: bool,
target: u64,
id: usize,
}
pub enum Req {
// Add a new timer to the helper thread.
NewTimer(Box<Inner>),
// Remove a timer based on its id and then send it back on the channel
// provided
RemoveTimer(usize, Sender<Box<Inner>>),
}
// returns the current time (in milliseconds)
pub fn now() -> u64 {
unsafe {
let mut now: libc::timeval = mem::zeroed();
assert_eq!(c::gettimeofday(&mut now, ptr::null_mut()), 0);
return (now.tv_sec as u64) * 1000 + (now.tv_usec as u64) / 1000;
}
}
fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
let mut set: c::fd_set = unsafe { mem::zeroed() };
let fd = FileDesc::new(input, true);
let mut timeout: libc::timeval = unsafe { mem::zeroed() };
// active timers are those which are able to be selected upon (and it's a
// sorted list, and dead timers are those which have expired, but ownership
// hasn't yet been transferred back to the timer itself.
let mut active: Vec<Box<Inner>> = vec![];
let mut dead = vec![];
// inserts a timer into an array of timers (sorted by firing time)
fn insert(t: Box<Inner>, active: &mut Vec<Box<Inner>>) {
match active.iter().position(|tm| tm.target > t.target) {
Some(pos) => { active.insert(pos, t); }
None => { active.push(t); }
}
}
// signals the first requests in the queue, possible re-enqueueing it.
fn signal(active: &mut Vec<Box<Inner>>,
dead: &mut Vec<(usize, Box<Inner>)>) {
if active.is_empty() { return }
let mut timer = active.remove(0);
let mut cb = timer.cb.take().unwrap();
cb.call();
if timer.repeat {
timer.cb = Some(cb);
timer.target += timer.interval;
insert(timer, active);
} else {
dead.push((timer.id, timer));
}
}
'outer: loop {
let timeout = if active.len() == 0 {
// Empty array? no timeout (wait forever for the next request)
ptr::null_mut()
} else {
let now = now();
// If this request has already expired, then signal it and go
// through another iteration
if active[0].target <= now {
signal(&mut active, &mut dead);
continue;
}
// The actual timeout listed in the requests array is an
// absolute date, so here we translate the absolute time to a
// relative time.
let tm = active[0].target - now;
timeout.tv_sec = (tm / 1000) as libc::time_t;
timeout.tv_usec = ((tm % 1000) * 1000) as libc::suseconds_t;
&mut timeout as *mut libc::timeval
};
c::fd_set(&mut set, input);
match unsafe {
c::select(input + 1, &mut set, ptr::null_mut(),
ptr::null_mut(), timeout)
} {
// timed out
0 => signal(&mut active, &mut dead),
// file descriptor write woke us up, we've got some new requests
1 => {
loop {
match messages.try_recv() {
// Once we've been disconnected it means the main thread
// is exiting (at_exit has run). We could still have
// active timers for other threads, so we're just going
// to drop them all on the floor. This is all we can
// really do, however, to prevent resource leakage. The
// remaining timers will likely start panicking quickly
// as they attempt to re-use this thread but are
// disallowed to do so.
Err(TryRecvError::Disconnected) => {
break 'outer;
}
Ok(NewTimer(timer)) => insert(timer, &mut active),
Ok(RemoveTimer(id, ack)) => {
match dead.iter().position(|&(i, _)| id == i) {
Some(i) => {
let (_, i) = dead.remove(i);
ack.send(i).unwrap();
continue
}
None => {}
}
let i = active.iter().position(|i| i.id == id);
let i = i.expect("no timer found");
let t = active.remove(i);
ack.send(t).unwrap();
}
Err(..) => break
}
}
// drain the file descriptor
let mut buf = [0];
assert_eq!(fd.read(&mut buf).unwrap(), 1);
}
-1 if os::errno() == libc::EINTR as i32 => {}
n => panic!("helper thread failed in select() with error: {} ({})",
n, io::Error::last_os_error())
}
}
}
impl Timer {
pub fn new() -> IoResult<Timer> {
// See notes above regarding using isize return value
// instead of ()
HELPER.boot(|| {}, helper);
static ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
let id = ID.fetch_add(1, Ordering::Relaxed);
Ok(Timer {
id: id,
inner: Some(box Inner {
cb: None,
interval: 0,
target: 0,
repeat: false,
id: id,
})
})
}
pub fn sleep(&mut self, ms: u64) {
let mut inner = self.inner();
inner.cb = None; // cancel any previous request
self.inner = Some(inner);
let mut to_sleep = libc::timespec {
tv_sec: (ms / 1000) as libc::time_t,
tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
};
while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
if os::errno() as isize != libc::EINTR as isize {
panic!("failed to sleep, but not because of EINTR?");
}
}
}
pub fn oneshot(&mut self, msecs: u64, cb: Box<Callback + Send>) {
let now = now();
let mut inner = self.inner();
inner.repeat = false;
inner.cb = Some(cb);
inner.interval = msecs;
inner.target = now + msecs;
HELPER.send(NewTimer(inner));
}
pub fn period(&mut self, msecs: u64, cb: Box<Callback + Send>) {
let now = now();
let mut inner = self.inner();
inner.repeat = true;
inner.cb = Some(cb);
inner.interval = msecs;
inner.target = now + msecs;
HELPER.send(NewTimer(inner));
}
fn inner(&mut self) -> Box<Inner> {
match self.inner.take() {
Some(i) => i,
None => {
let (tx, rx) = channel();
HELPER.send(RemoveTimer(self.id, tx));
rx.recv().unwrap()
}
}
}
}
impl Drop for Timer {
fn drop(&mut self) {
self.inner = Some(self.inner());
}
}

View File

@ -1,81 +0,0 @@
// Copyright 2014 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.
#![allow(deprecated)]
use prelude::v1::*;
use sys::fs::FileDesc;
use libc::{self, c_int, c_ulong};
use old_io::{self, IoResult, IoError};
use sys::c;
use sys_common;
pub struct TTY {
pub fd: FileDesc,
}
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "bitrig",
target_os = "openbsd"))]
const TIOCGWINSZ: c_ulong = 0x40087468;
#[cfg(any(target_os = "linux", target_os = "android"))]
const TIOCGWINSZ: c_ulong = 0x00005413;
impl TTY {
pub fn new(fd: c_int) -> IoResult<TTY> {
if unsafe { libc::isatty(fd) } != 0 {
Ok(TTY { fd: FileDesc::new(fd, true) })
} else {
Err(IoError {
kind: old_io::MismatchedFileTypeForOperation,
desc: "file descriptor is not a TTY",
detail: None,
})
}
}
pub fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
self.fd.read(buf)
}
pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
self.fd.write(buf)
}
pub fn set_raw(&mut self, _raw: bool) -> IoResult<()> {
Err(sys_common::unimpl())
}
pub fn get_winsize(&mut self) -> IoResult<(isize, isize)> {
unsafe {
#[repr(C)]
struct winsize {
ws_row: u16,
ws_col: u16,
ws_xpixel: u16,
ws_ypixel: u16
}
let mut size = winsize { ws_row: 0, ws_col: 0, ws_xpixel: 0, ws_ypixel: 0 };
if c::ioctl(self.fd.fd(), TIOCGWINSZ, &mut size) == -1 {
Err(IoError {
kind: old_io::OtherIoError,
desc: "Size of terminal could not be determined",
detail: None,
})
} else {
Ok((size.ws_col as isize, size.ws_row as isize))
}
}
}
}

View File

@ -1,11 +0,0 @@
// Copyright 2014 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.
pub use sys_common::net::UdpSocket;

View File

@ -24,9 +24,6 @@ pub mod io {
use sys_common::{net2, AsInner, FromInner};
use sys;
#[allow(deprecated)]
use old_io;
/// Raw HANDLEs.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawHandle = libc::HANDLE;
@ -61,14 +58,6 @@ pub mod io {
unsafe fn from_raw_handle(handle: RawHandle) -> Self;
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::fs::File {
fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for fs::File {
fn as_raw_handle(&self) -> RawHandle {
@ -83,38 +72,6 @@ pub mod io {
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::pipe::PipeStream {
fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::net::pipe::UnixStream {
fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::net::pipe::UnixListener {
fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::net::pipe::UnixAcceptor {
fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
/// Extract raw sockets.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawSocket {
@ -139,38 +96,6 @@ pub mod io {
unsafe fn from_raw_socket(sock: RawSocket) -> Self;
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::tcp::TcpStream {
fn as_raw_socket(&self) -> RawSocket {
self.as_inner().fd()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::tcp::TcpListener {
fn as_raw_socket(&self) -> RawSocket {
self.as_inner().socket()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::tcp::TcpAcceptor {
fn as_raw_socket(&self) -> RawSocket {
self.as_inner().socket()
}
}
#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::udp::UdpSocket {
fn as_raw_socket(&self) -> RawSocket {
self.as_inner().fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::TcpStream {
fn as_raw_socket(&self) -> RawSocket {

View File

@ -1,452 +0,0 @@
// Copyright 2014 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.
//! Blocking Windows-based file I/O
#![allow(deprecated)] // this module itself is essentially deprecated
use libc::{self, c_int};
use mem;
use ptr;
use old_io;
use prelude::v1::*;
use sys;
use sys_common::{self, mkerr_libc};
use old_path::{Path, GenericPath};
use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
use old_io::{IoResult, IoError, FileStat, SeekStyle};
use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
pub type fd_t = libc::c_int;
pub struct FileDesc {
/// The underlying C file descriptor.
pub fd: fd_t,
/// Whether to close the file descriptor on drop.
close_on_drop: bool,
}
impl FileDesc {
pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc {
FileDesc { fd: fd, close_on_drop: close_on_drop }
}
pub fn read(&self, buf: &mut [u8]) -> IoResult<usize> {
let mut read = 0;
let ret = unsafe {
libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID,
buf.len() as libc::DWORD, &mut read,
ptr::null_mut())
};
if ret != 0 {
Ok(read as usize)
} else {
Err(super::last_error())
}
}
pub fn write(&self, buf: &[u8]) -> IoResult<()> {
let mut cur = buf.as_ptr();
let mut remaining = buf.len();
while remaining > 0 {
let mut amt = 0;
let ret = unsafe {
libc::WriteFile(self.handle(), cur as libc::LPVOID,
remaining as libc::DWORD, &mut amt,
ptr::null_mut())
};
if ret != 0 {
remaining -= amt as usize;
cur = unsafe { cur.offset(amt as isize) };
} else {
return Err(super::last_error())
}
}
Ok(())
}
pub fn fd(&self) -> fd_t { self.fd }
pub fn handle(&self) -> libc::HANDLE {
unsafe { libc::get_osfhandle(self.fd()) as libc::HANDLE }
}
// A version of seek that takes &self so that tell can call it
// - the private seek should of course take &mut self.
fn seek_common(&self, pos: i64, style: SeekStyle) -> IoResult<u64> {
let whence = match style {
SeekSet => libc::FILE_BEGIN,
SeekEnd => libc::FILE_END,
SeekCur => libc::FILE_CURRENT,
};
unsafe {
let mut newpos = 0;
match libc::SetFilePointerEx(self.handle(), pos, &mut newpos, whence) {
0 => Err(super::last_error()),
_ => Ok(newpos as u64),
}
}
}
pub fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<u64> {
self.seek_common(pos, style)
}
pub fn tell(&self) -> IoResult<u64> {
self.seek_common(0, SeekCur)
}
pub fn fsync(&mut self) -> IoResult<()> {
super::mkerr_winbool(unsafe {
libc::FlushFileBuffers(self.handle())
})
}
pub fn datasync(&mut self) -> IoResult<()> { return self.fsync(); }
pub fn truncate(&mut self, offset: i64) -> IoResult<()> {
let orig_pos = try!(self.tell());
let _ = try!(self.seek(offset, SeekSet));
let ret = unsafe {
match libc::SetEndOfFile(self.handle()) {
0 => Err(super::last_error()),
_ => Ok(())
}
};
let _ = self.seek(orig_pos as i64, SeekSet);
return ret;
}
pub fn fstat(&self) -> IoResult<old_io::FileStat> {
let mut stat: libc::stat = unsafe { mem::zeroed() };
match unsafe { libc::fstat(self.fd(), &mut stat) } {
0 => Ok(mkstat(&stat)),
_ => Err(super::last_error()),
}
}
#[allow(dead_code)]
pub fn unwrap(self) -> fd_t {
let fd = self.fd;
unsafe { mem::forget(self) };
fd
}
}
impl Drop for FileDesc {
fn drop(&mut self) {
// closing stdio file handles makes no sense, so never do it. Also, note
// that errors are ignored when closing a file descriptor. The reason
// for this is that if an error occurs we don't actually know if the
// file descriptor was closed or not, and if we retried (for something
// like EINTR), we might close another valid file descriptor (opened
// after we closed ours.
if self.close_on_drop && self.fd > libc::STDERR_FILENO {
let n = unsafe { libc::close(self.fd) };
if n != 0 {
println!("error {} when closing file descriptor {}", n, self.fd);
}
}
}
}
pub fn to_utf16(s: &Path) -> IoResult<Vec<u16>> {
sys::to_utf16(s.as_str())
}
pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
// Flags passed to open_osfhandle
let flags = match fm {
Open => 0,
Append => libc::O_APPEND,
Truncate => libc::O_TRUNC,
};
let flags = match fa {
Read => flags | libc::O_RDONLY,
Write => flags | libc::O_WRONLY | libc::O_CREAT,
ReadWrite => flags | libc::O_RDWR | libc::O_CREAT,
};
let mut dwDesiredAccess = match fa {
Read => libc::FILE_GENERIC_READ,
Write => libc::FILE_GENERIC_WRITE,
ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE
};
// libuv has a good comment about this, but the basic idea is what we try to
// emulate unix semantics by enabling all sharing by allowing things such as
// deleting a file while it's still open.
let dwShareMode = libc::FILE_SHARE_READ | libc::FILE_SHARE_WRITE |
libc::FILE_SHARE_DELETE;
let dwCreationDisposition = match (fm, fa) {
(Truncate, Read) => libc::TRUNCATE_EXISTING,
(Truncate, _) => libc::CREATE_ALWAYS,
(Open, Read) => libc::OPEN_EXISTING,
(Open, _) => libc::OPEN_ALWAYS,
(Append, Read) => {
dwDesiredAccess |= libc::FILE_APPEND_DATA;
libc::OPEN_EXISTING
}
(Append, _) => {
dwDesiredAccess &= !libc::FILE_WRITE_DATA;
dwDesiredAccess |= libc::FILE_APPEND_DATA;
libc::OPEN_ALWAYS
}
};
let mut dwFlagsAndAttributes = libc::FILE_ATTRIBUTE_NORMAL;
// Compat with unix, this allows opening directories (see libuv)
dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS;
let path = try!(to_utf16(path));
let handle = unsafe {
libc::CreateFileW(path.as_ptr(),
dwDesiredAccess,
dwShareMode,
ptr::null_mut(),
dwCreationDisposition,
dwFlagsAndAttributes,
ptr::null_mut())
};
if handle == libc::INVALID_HANDLE_VALUE {
Err(super::last_error())
} else {
let fd = unsafe {
libc::open_osfhandle(handle as libc::intptr_t, flags)
};
if fd < 0 {
let _ = unsafe { libc::CloseHandle(handle) };
Err(super::last_error())
} else {
Ok(FileDesc::new(fd, true))
}
}
}
pub fn mkdir(p: &Path, _mode: usize) -> IoResult<()> {
let p = try!(to_utf16(p));
super::mkerr_winbool(unsafe {
// FIXME: turn mode into something useful? #2623
libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut())
})
}
pub fn readdir(p: &Path) -> IoResult<Vec<Path>> {
fn prune(root: &Path, dirs: Vec<Path>) -> Vec<Path> {
dirs.into_iter().filter(|path| {
path.as_vec() != b"." && path.as_vec() != b".."
}).map(|path| root.join(path)).collect()
}
let star = p.join("*");
let path = try!(to_utf16(&star));
unsafe {
let mut wfd = mem::zeroed();
let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd);
if find_handle != libc::INVALID_HANDLE_VALUE {
let mut paths = vec![];
let mut more_files = 1 as libc::BOOL;
while more_files != 0 {
{
let filename = super::truncate_utf16_at_nul(&wfd.cFileName);
match String::from_utf16(filename) {
Ok(filename) => paths.push(Path::new(filename)),
Err(..) => {
assert!(libc::FindClose(find_handle) != 0);
return Err(IoError {
kind: old_io::InvalidInput,
desc: "path was not valid UTF-16",
detail: Some(format!("path was not valid UTF-16: {:?}", filename)),
})
}, // FIXME #12056: Convert the UCS-2 to invalid utf-8 instead of erroring
}
}
more_files = libc::FindNextFileW(find_handle, &mut wfd);
}
assert!(libc::FindClose(find_handle) != 0);
Ok(prune(p, paths))
} else {
Err(super::last_error())
}
}
}
pub fn unlink(p: &Path) -> IoResult<()> {
fn do_unlink(p_utf16: &Vec<u16>) -> IoResult<()> {
super::mkerr_winbool(unsafe { libc::DeleteFileW(p_utf16.as_ptr()) })
}
let p_utf16 = try!(to_utf16(p));
let res = do_unlink(&p_utf16);
match res {
Ok(()) => Ok(()),
Err(e) => {
// FIXME: change the code below to use more direct calls
// than `stat` and `chmod`, to avoid re-conversion to
// utf16 etc.
// On unix, a readonly file can be successfully removed. On windows,
// however, it cannot. To keep the two platforms in line with
// respect to their behavior, catch this case on windows, attempt to
// change it to read-write, and then remove the file.
if e.kind == old_io::PermissionDenied {
let stat = match stat(p) {
Ok(stat) => stat,
Err(..) => return Err(e),
};
if stat.perm.intersects(old_io::USER_WRITE) { return Err(e) }
match chmod(p, (stat.perm | old_io::USER_WRITE).bits() as usize) {
Ok(()) => do_unlink(&p_utf16),
Err(..) => {
// Try to put it back as we found it
let _ = chmod(p, stat.perm.bits() as usize);
Err(e)
}
}
} else {
Err(e)
}
}
}
}
pub fn rename(old: &Path, new: &Path) -> IoResult<()> {
let old = try!(to_utf16(old));
let new = try!(to_utf16(new));
super::mkerr_winbool(unsafe {
libc::MoveFileExW(old.as_ptr(), new.as_ptr(), libc::MOVEFILE_REPLACE_EXISTING)
})
}
pub fn chmod(p: &Path, mode: usize) -> IoResult<()> {
let p = try!(to_utf16(p));
mkerr_libc(unsafe {
libc::wchmod(p.as_ptr(), mode as libc::c_int)
})
}
pub fn rmdir(p: &Path) -> IoResult<()> {
let p = try!(to_utf16(p));
super::mkerr_winbool(unsafe { libc::RemoveDirectoryW(p.as_ptr()) })
}
pub fn chown(_p: &Path, _uid: isize, _gid: isize) -> IoResult<()> {
// libuv has this as a no-op, so seems like this should as well?
Ok(())
}
pub fn readlink(p: &Path) -> IoResult<Path> {
// FIXME: I have a feeling that this reads intermediate symlinks as well.
use sys::c::compat::kernel32::GetFinalPathNameByHandleW;
let p = try!(to_utf16(p));
let handle = unsafe {
libc::CreateFileW(p.as_ptr(),
libc::GENERIC_READ,
libc::FILE_SHARE_READ,
ptr::null_mut(),
libc::OPEN_EXISTING,
libc::FILE_ATTRIBUTE_NORMAL,
ptr::null_mut())
};
if handle == libc::INVALID_HANDLE_VALUE {
return Err(super::last_error())
}
// Specify (sz - 1) because the documentation states that it's the size
// without the null pointer
let ret = super::fill_utf16_buf(|buf, sz| unsafe {
GetFinalPathNameByHandleW(handle,
buf as *const u16,
sz - 1,
libc::VOLUME_NAME_DOS)
}, |data| {
Path::new(String::from_utf16(data).unwrap())
});
assert!(unsafe { libc::CloseHandle(handle) } != 0);
return ret;
}
pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
use sys::c::compat::kernel32::CreateSymbolicLinkW;
let src = try!(to_utf16(src));
let dst = try!(to_utf16(dst));
super::mkerr_winbool(unsafe {
CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL
})
}
pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
let src = try!(to_utf16(src));
let dst = try!(to_utf16(dst));
super::mkerr_winbool(unsafe {
libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut())
})
}
fn mkstat(stat: &libc::stat) -> FileStat {
FileStat {
size: stat.st_size as u64,
kind: match (stat.st_mode as libc::c_int) & libc::S_IFMT {
libc::S_IFREG => old_io::FileType::RegularFile,
libc::S_IFDIR => old_io::FileType::Directory,
libc::S_IFIFO => old_io::FileType::NamedPipe,
libc::S_IFBLK => old_io::FileType::BlockSpecial,
libc::S_IFLNK => old_io::FileType::Symlink,
_ => old_io::FileType::Unknown,
},
perm: FilePermission::from_bits_truncate(stat.st_mode as u32),
created: stat.st_ctime as u64,
modified: stat.st_mtime as u64,
accessed: stat.st_atime as u64,
unstable: UnstableFileStat {
device: stat.st_dev as u64,
inode: stat.st_ino as u64,
rdev: stat.st_rdev as u64,
nlink: stat.st_nlink as u64,
uid: stat.st_uid as u64,
gid: stat.st_gid as u64,
blksize:0,
blocks: 0,
flags: 0,
gen: 0,
},
}
}
pub fn stat(p: &Path) -> IoResult<FileStat> {
let mut stat: libc::stat = unsafe { mem::zeroed() };
let p = try!(to_utf16(p));
match unsafe { libc::wstat(p.as_ptr(), &mut stat) } {
0 => Ok(mkstat(&stat)),
_ => Err(super::last_error()),
}
}
// FIXME: move this to platform-specific modules (for now)?
pub fn lstat(_p: &Path) -> IoResult<FileStat> {
// FIXME: implementation is missing
Err(sys_common::unimpl())
}
pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
let mut buf = libc::utimbuf {
actime: atime as libc::time64_t,
modtime: mtime as libc::time64_t,
};
let p = try!(to_utf16(p));
mkerr_libc(unsafe {
libc::wutime(p.as_ptr(), &mut buf)
})
}

View File

@ -1,38 +0,0 @@
// Copyright 2014 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 libc::{self, BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle};
use ptr;
pub type signal = HANDLE;
pub fn new() -> (HANDLE, HANDLE) {
unsafe {
let handle = CreateEventA(ptr::null_mut(), libc::FALSE, libc::FALSE,
ptr::null());
(handle, handle)
}
}
pub fn signal(handle: HANDLE) {
assert!(unsafe { SetEvent(handle) != 0 });
}
pub fn close(handle: HANDLE) {
assert!(unsafe { CloseHandle(handle) != 0 });
}
extern "system" {
fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
bManualReset: BOOL,
bInitialState: BOOL,
lpName: LPCSTR) -> HANDLE;
fn SetEvent(hEvent: HANDLE) -> BOOL;
}

View File

@ -17,136 +17,31 @@ use prelude::v1::*;
use ffi::{OsStr, OsString};
use io::{self, ErrorKind};
use libc;
use mem;
#[allow(deprecated)]
use num::Int;
use old_io::{self, IoResult, IoError};
use os::windows::ffi::{OsStrExt, OsStringExt};
use path::PathBuf;
use sync::{Once, ONCE_INIT};
pub mod backtrace;
pub mod c;
pub mod condvar;
pub mod ext;
pub mod fs;
pub mod fs2;
pub mod handle;
pub mod helper_signal;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod pipe;
pub mod pipe2;
pub mod process;
pub mod process2;
pub mod rwlock;
pub mod stack_overflow;
pub mod sync;
pub mod tcp;
pub mod thread;
pub mod thread_local;
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;
pub use sys_common::net::get_address_name;
}
// FIXME: move these to c module
pub type sock_t = libc::SOCKET;
pub type wrlen = libc::c_int;
pub type msglen_t = libc::c_int;
pub unsafe fn close_sock(sock: sock_t) { let _ = libc::closesocket(sock); }
// windows has zero values as errors
#[allow(deprecated)]
fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
if ret == 0 {
Err(last_error())
} else {
Ok(())
}
}
#[allow(deprecated)]
pub fn last_error() -> IoError {
let errno = os::errno() as i32;
let mut err = decode_error(errno);
err.detail = Some(os::error_string(errno));
err
}
#[allow(deprecated)]
pub fn last_net_error() -> IoError {
let errno = unsafe { c::WSAGetLastError() as i32 };
let mut err = decode_error(errno);
err.detail = Some(os::error_string(errno));
err
}
#[allow(deprecated)]
pub fn last_gai_error(_errno: i32) -> IoError {
last_net_error()
}
/// Convert an `errno` value into a high-level error variant and description.
#[allow(deprecated)]
pub fn decode_error(errno: i32) -> IoError {
let (kind, desc) = match errno {
libc::EOF => (old_io::EndOfFile, "end of file"),
libc::ERROR_NO_DATA => (old_io::BrokenPipe, "the pipe is being closed"),
libc::ERROR_FILE_NOT_FOUND => (old_io::FileNotFound, "file not found"),
libc::ERROR_INVALID_NAME => (old_io::InvalidInput, "invalid file name"),
libc::WSAECONNREFUSED => (old_io::ConnectionRefused, "connection refused"),
libc::WSAECONNRESET => (old_io::ConnectionReset, "connection reset"),
libc::ERROR_ACCESS_DENIED | libc::WSAEACCES =>
(old_io::PermissionDenied, "permission denied"),
libc::WSAEWOULDBLOCK => {
(old_io::ResourceUnavailable, "resource temporarily unavailable")
}
libc::WSAENOTCONN => (old_io::NotConnected, "not connected"),
libc::WSAECONNABORTED => (old_io::ConnectionAborted, "connection aborted"),
libc::WSAEADDRNOTAVAIL => (old_io::ConnectionRefused, "address not available"),
libc::WSAEADDRINUSE => (old_io::ConnectionRefused, "address in use"),
libc::ERROR_BROKEN_PIPE => (old_io::EndOfFile, "the pipe has ended"),
libc::ERROR_OPERATION_ABORTED =>
(old_io::TimedOut, "operation timed out"),
libc::WSAEINVAL => (old_io::InvalidInput, "invalid argument"),
libc::ERROR_CALL_NOT_IMPLEMENTED =>
(old_io::IoUnavailable, "function not implemented"),
libc::ERROR_INVALID_HANDLE =>
(old_io::MismatchedFileTypeForOperation,
"invalid handle provided to function"),
libc::ERROR_NOTHING_TO_TERMINATE =>
(old_io::InvalidInput, "no process to kill"),
libc::ERROR_ALREADY_EXISTS =>
(old_io::PathAlreadyExists, "path already exists"),
// libuv maps this error code to EISDIR. we do too. if it is found
// to be incorrect, we can add in some more machinery to only
// return this message when ERROR_INVALID_FUNCTION after certain
// Windows calls.
libc::ERROR_INVALID_FUNCTION => (old_io::InvalidInput,
"illegal operation on a directory"),
_ => (old_io::OtherIoError, "unknown error")
};
IoError { kind: kind, desc: desc, detail: None }
}
#[allow(deprecated)]
pub fn decode_error_detailed(errno: i32) -> IoError {
let mut err = decode_error(errno);
err.detail = Some(os::error_string(errno));
err
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as libc::c_int {
libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied,
@ -170,58 +65,6 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
}
}
#[inline]
pub fn retry<I, F>(f: F) -> I where F: FnOnce() -> I { f() } // PR rust-lang/rust/#17020
pub fn ms_to_timeval(ms: u64) -> libc::timeval {
libc::timeval {
tv_sec: (ms / 1000) as libc::c_long,
tv_usec: ((ms % 1000) * 1000) as libc::c_long,
}
}
#[allow(deprecated)]
pub fn wouldblock() -> bool {
let err = os::errno();
err == libc::WSAEWOULDBLOCK as i32
}
#[allow(deprecated)]
pub fn set_nonblocking(fd: sock_t, nb: bool) {
let mut set = nb as libc::c_ulong;
if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) } != 0 {
// The above function should not return an error unless we passed it
// invalid parameters. Panic on errors.
panic!("set_nonblocking called with invalid parameters: {}", last_error());
}
}
pub fn init_net() {
unsafe {
static START: Once = ONCE_INIT;
START.call_once(|| {
let mut data: c::WSADATA = mem::zeroed();
let ret = c::WSAStartup(0x202, // version 2.2
&mut data);
assert_eq!(ret, 0);
});
}
}
#[allow(deprecated)]
pub fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> {
match s {
Some(s) => Ok(to_utf16_os(OsStr::from_str(s))),
None => Err(IoError {
kind: old_io::InvalidInput,
desc: "valid unicode input required",
detail: None,
}),
}
}
fn to_utf16_os(s: &OsStr) -> Vec<u16> {
let mut v: Vec<_> = s.encode_wide().collect();
v.push(0);
@ -242,7 +85,7 @@ fn to_utf16_os(s: &OsStr) -> Vec<u16> {
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf_base<F1, F2, T>(mut f1: F1, f2: F2) -> Result<T, ()>
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> io::Result<T>
where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD,
F2: FnOnce(&[u16]) -> T
{
@ -274,7 +117,7 @@ fn fill_utf16_buf_base<F1, F2, T>(mut f1: F1, f2: F2) -> Result<T, ()>
c::SetLastError(0);
let k = match f1(buf.as_mut_ptr(), n as libc::DWORD) {
0 if libc::GetLastError() == 0 => 0,
0 => return Err(()),
0 => return Err(io::Error::last_os_error()),
n => n,
} as usize;
if k == n && libc::GetLastError() ==
@ -289,21 +132,6 @@ fn fill_utf16_buf_base<F1, F2, T>(mut f1: F1, f2: F2) -> Result<T, ()>
}
}
#[allow(deprecated)]
fn fill_utf16_buf<F1, F2, T>(f1: F1, f2: F2) -> IoResult<T>
where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD,
F2: FnOnce(&[u16]) -> T
{
fill_utf16_buf_base(f1, f2).map_err(|()| IoError::last_error())
}
fn fill_utf16_buf_new<F1, F2, T>(f1: F1, f2: F2) -> io::Result<T>
where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD,
F2: FnOnce(&[u16]) -> T
{
fill_utf16_buf_base(f1, f2).map_err(|()| io::Error::last_os_error())
}
fn os2path(s: &[u16]) -> PathBuf {
PathBuf::from(OsString::from_wide(s))
}

View File

@ -22,15 +22,12 @@ use io;
use libc::types::os::arch::extra::LPWCH;
use libc::{self, c_int, c_void};
use mem;
#[allow(deprecated)]
use old_io::{IoError, IoResult};
use ops::Range;
use os::windows::ffi::EncodeWide;
use path::{self, PathBuf};
use ptr;
use slice;
use sys::c;
use sys::fs::FileDesc;
use sys::handle::Handle;
use libc::funcs::extra::kernel32::{
@ -233,13 +230,13 @@ impl StdError for JoinPathsError {
}
pub fn current_exe() -> io::Result<PathBuf> {
super::fill_utf16_buf_new(|buf, sz| unsafe {
super::fill_utf16_buf(|buf, sz| unsafe {
libc::GetModuleFileNameW(ptr::null_mut(), buf, sz)
}, super::os2path)
}
pub fn getcwd() -> io::Result<PathBuf> {
super::fill_utf16_buf_new(|buf, sz| unsafe {
super::fill_utf16_buf(|buf, sz| unsafe {
libc::GetCurrentDirectoryW(sz, buf)
}, super::os2path)
}
@ -259,7 +256,7 @@ pub fn chdir(p: &path::Path) -> io::Result<()> {
pub fn getenv(k: &OsStr) -> Option<OsString> {
let k = super::to_utf16_os(k);
super::fill_utf16_buf_new(|buf, sz| unsafe {
super::fill_utf16_buf(|buf, sz| unsafe {
libc::GetEnvironmentVariableW(k.as_ptr(), buf, sz)
}, |buf| {
OsStringExt::from_wide(buf)
@ -336,27 +333,8 @@ pub fn page_size() -> usize {
}
}
#[allow(deprecated)]
pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
// Windows pipes work subtly differently than unix pipes, and their
// inheritance has to be handled in a different way that I do not
// fully understand. Here we explicitly make the pipe non-inheritable,
// which means to pass it to a subprocess they need to be duplicated
// first, as in std::run.
let mut fds = [0; 2];
match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint,
(libc::O_BINARY | libc::O_NOINHERIT) as c_int) {
0 => {
assert!(fds[0] != -1 && fds[0] != 0);
assert!(fds[1] != -1 && fds[1] != 0);
Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
}
_ => Err(IoError::last_error()),
}
}
pub fn temp_dir() -> PathBuf {
super::fill_utf16_buf_new(|buf, sz| unsafe {
super::fill_utf16_buf(|buf, sz| unsafe {
c::GetTempPathW(sz, buf)
}, super::os2path).unwrap()
}
@ -371,7 +349,7 @@ pub fn home_dir() -> Option<PathBuf> {
return None
}
let _handle = Handle::new(token);
super::fill_utf16_buf_new(|buf, mut sz| {
super::fill_utf16_buf(|buf, mut sz| {
match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
0 if libc::GetLastError() != 0 => 0,
0 => sz,

View File

@ -1,775 +0,0 @@
// Copyright 2014 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.
//! Named pipes implementation for windows
//!
//! If are unfortunate enough to be reading this code, I would like to first
//! apologize. This was my first encounter with windows named pipes, and it
//! didn't exactly turn out very cleanly. If you, too, are new to named pipes,
//! read on as I'll try to explain some fun things that I ran into.
//!
//! # Unix pipes vs Named pipes
//!
//! As with everything else, named pipes on windows are pretty different from
//! unix pipes on unix. On unix, you use one "server pipe" to accept new client
//! pipes. So long as this server pipe is active, new children pipes can
//! connect. On windows, you instead have a number of "server pipes", and each
//! of these server pipes can throughout their lifetime be attached to a client
//! or not. Once attached to a client, a server pipe may then disconnect at a
//! later date.
//!
//! # Accepting clients
//!
//! As with most other I/O interfaces, our Listener/Acceptor/Stream interfaces
//! are built around the unix flavors. This means that we have one "server
//! pipe" to which many clients can connect. In order to make this compatible
//! with the windows model, each connected client consumes ownership of a server
//! pipe, and then a new server pipe is created for the next client.
//!
//! Note that the server pipes attached to clients are never given back to the
//! listener for recycling. This could possibly be implemented with a channel so
//! the listener half can re-use server pipes, but for now I err'd on the simple
//! side of things. Each stream accepted by a listener will destroy the server
//! pipe after the stream is dropped.
//!
//! This model ends up having a small race or two, and you can find more details
//! on the `native_accept` method.
//!
//! # Simultaneous reads and writes
//!
//! In testing, I found that two simultaneous writes and two simultaneous reads
//! on a pipe ended up working out just fine, but problems were encountered when
//! a read was executed simultaneously with a write. After some googling around,
//! it sounded like named pipes just weren't built for this kind of interaction,
//! and the suggested solution was to use overlapped I/O.
//!
//! I don't really know what overlapped I/O is, but my basic understanding after
//! reading about it is that you have an external Event which is used to signal
//! I/O completion, passed around in some OVERLAPPED structures. As to what this
//! is, I'm not exactly sure.
//!
//! This problem implies that all named pipes are created with the
//! FILE_FLAG_OVERLAPPED option. This means that all of their I/O is
//! asynchronous. Each I/O operation has an associated OVERLAPPED structure, and
//! inside of this structure is a HANDLE from CreateEvent. After the I/O is
//! determined to be pending (may complete in the future), the
//! GetOverlappedResult function is used to block on the event, waiting for the
//! I/O to finish.
//!
//! This scheme ended up working well enough. There were two snags that I ran
//! into, however:
//!
//! * Each UnixStream instance needs its own read/write events to wait on. These
//! can't be shared among clones of the same stream because the documentation
//! states that it unsets the event when the I/O is started (would possibly
//! corrupt other events simultaneously waiting). For convenience's sake,
//! these events are lazily initialized.
//!
//! * Each server pipe needs to be created with FILE_FLAG_OVERLAPPED in addition
//! to all pipes created through `connect`. Notably this means that the
//! ConnectNamedPipe function is nonblocking, implying that the Listener needs
//! to have yet another event to do the actual blocking.
//!
//! # Conclusion
//!
//! The conclusion here is that I probably don't know the best way to work with
//! windows named pipes, but the solution here seems to work well enough to get
//! the test suite passing (the suite is in libstd), and that's good enough for
//! me!
#![allow(deprecated)]
use prelude::v1::*;
use libc;
use ffi::CString;
use old_io::{self, IoError, IoResult};
use mem;
use ptr;
use str;
use sync::atomic::{AtomicBool, Ordering};
use sync::{Arc, Mutex};
use sys_common::{self, eof};
use super::{c, os, timer, decode_error_detailed};
fn to_utf16(c: &CString) -> IoResult<Vec<u16>> {
super::to_utf16(str::from_utf8(c.as_bytes()).ok())
}
struct Event(libc::HANDLE);
impl Event {
fn new(manual_reset: bool, initial_state: bool) -> IoResult<Event> {
let event = unsafe {
libc::CreateEventW(ptr::null_mut(),
manual_reset as libc::BOOL,
initial_state as libc::BOOL,
ptr::null())
};
if event as usize == 0 {
Err(super::last_error())
} else {
Ok(Event(event))
}
}
fn handle(&self) -> libc::HANDLE { let Event(handle) = *self; handle }
}
impl Drop for Event {
fn drop(&mut self) {
unsafe { let _ = libc::CloseHandle(self.handle()); }
}
}
unsafe impl Send for Event {}
unsafe impl Sync for Event {}
struct Inner {
handle: libc::HANDLE,
lock: Mutex<()>,
read_closed: AtomicBool,
write_closed: AtomicBool,
}
impl Inner {
fn new(handle: libc::HANDLE) -> Inner {
Inner {
handle: handle,
lock: Mutex::new(()),
read_closed: AtomicBool::new(false),
write_closed: AtomicBool::new(false),
}
}
}
impl Drop for Inner {
fn drop(&mut self) {
unsafe {
let _ = libc::FlushFileBuffers(self.handle);
let _ = libc::CloseHandle(self.handle);
}
}
}
unsafe impl Send for Inner {}
unsafe impl Sync for Inner {}
unsafe fn pipe(name: *const u16, init: bool) -> libc::HANDLE {
libc::CreateNamedPipeW(
name,
libc::PIPE_ACCESS_DUPLEX |
if init {libc::FILE_FLAG_FIRST_PIPE_INSTANCE} else {0} |
libc::FILE_FLAG_OVERLAPPED,
libc::PIPE_TYPE_BYTE | libc::PIPE_READMODE_BYTE |
libc::PIPE_WAIT,
libc::PIPE_UNLIMITED_INSTANCES,
65536,
65536,
0,
ptr::null_mut()
)
}
pub fn await(handle: libc::HANDLE, deadline: u64,
events: &[libc::HANDLE]) -> IoResult<usize> {
use libc::consts::os::extra::{WAIT_FAILED, WAIT_TIMEOUT, WAIT_OBJECT_0};
// If we've got a timeout, use WaitForSingleObject in tandem with CancelIo
// to figure out if we should indeed get the result.
let ms = if deadline == 0 {
libc::INFINITE as u64
} else {
let now = timer::now();
if deadline < now {0} else {deadline - now}
};
let ret = unsafe {
c::WaitForMultipleObjects(events.len() as libc::DWORD,
events.as_ptr(),
libc::FALSE,
ms as libc::DWORD)
};
match ret {
WAIT_FAILED => Err(super::last_error()),
WAIT_TIMEOUT => unsafe {
let _ = c::CancelIo(handle);
Err(sys_common::timeout("operation timed out"))
},
n => Ok((n - WAIT_OBJECT_0) as usize)
}
}
fn epipe() -> IoError {
IoError {
kind: old_io::EndOfFile,
desc: "the pipe has ended",
detail: None,
}
}
////////////////////////////////////////////////////////////////////////////////
// Unix Streams
////////////////////////////////////////////////////////////////////////////////
pub struct UnixStream {
inner: Arc<Inner>,
write: Option<Event>,
read: Option<Event>,
read_deadline: u64,
write_deadline: u64,
}
impl UnixStream {
fn try_connect(p: *const u16) -> Option<libc::HANDLE> {
// Note that most of this is lifted from the libuv implementation.
// The idea is that if we fail to open a pipe in read/write mode
// that we try afterwards in just read or just write
let mut result = unsafe {
libc::CreateFileW(p,
libc::GENERIC_READ | libc::GENERIC_WRITE,
0,
ptr::null_mut(),
libc::OPEN_EXISTING,
libc::FILE_FLAG_OVERLAPPED,
ptr::null_mut())
};
if result != libc::INVALID_HANDLE_VALUE {
return Some(result)
}
let err = unsafe { libc::GetLastError() };
if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
result = unsafe {
libc::CreateFileW(p,
libc::GENERIC_READ | libc::FILE_WRITE_ATTRIBUTES,
0,
ptr::null_mut(),
libc::OPEN_EXISTING,
libc::FILE_FLAG_OVERLAPPED,
ptr::null_mut())
};
if result != libc::INVALID_HANDLE_VALUE {
return Some(result)
}
}
let err = unsafe { libc::GetLastError() };
if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
result = unsafe {
libc::CreateFileW(p,
libc::GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES,
0,
ptr::null_mut(),
libc::OPEN_EXISTING,
libc::FILE_FLAG_OVERLAPPED,
ptr::null_mut())
};
if result != libc::INVALID_HANDLE_VALUE {
return Some(result)
}
}
None
}
pub fn connect(addr: &CString, timeout: Option<u64>) -> IoResult<UnixStream> {
let addr = try!(to_utf16(addr));
let start = timer::now();
loop {
match UnixStream::try_connect(addr.as_ptr()) {
Some(handle) => {
let inner = Inner::new(handle);
let mut mode = libc::PIPE_TYPE_BYTE |
libc::PIPE_READMODE_BYTE |
libc::PIPE_WAIT;
let ret = unsafe {
libc::SetNamedPipeHandleState(inner.handle,
&mut mode,
ptr::null_mut(),
ptr::null_mut())
};
return if ret == 0 {
Err(super::last_error())
} else {
Ok(UnixStream {
inner: Arc::new(inner),
read: None,
write: None,
read_deadline: 0,
write_deadline: 0,
})
}
}
None => {}
}
// On windows, if you fail to connect, you may need to call the
// `WaitNamedPipe` function, and this is indicated with an error
// code of ERROR_PIPE_BUSY.
let code = unsafe { libc::GetLastError() };
if code as isize != libc::ERROR_PIPE_BUSY as isize {
return Err(super::last_error())
}
match timeout {
Some(timeout) => {
let now = timer::now();
let timed_out = (now - start) >= timeout || unsafe {
let ms = (timeout - (now - start)) as libc::DWORD;
libc::WaitNamedPipeW(addr.as_ptr(), ms) == 0
};
if timed_out {
return Err(sys_common::timeout("connect timed out"))
}
}
// An example I found on Microsoft's website used 20
// seconds, libuv uses 30 seconds, hence we make the
// obvious choice of waiting for 25 seconds.
None => {
if unsafe { libc::WaitNamedPipeW(addr.as_ptr(), 25000) } == 0 {
return Err(super::last_error())
}
}
}
}
}
pub fn handle(&self) -> libc::HANDLE { self.inner.handle }
fn read_closed(&self) -> bool {
self.inner.read_closed.load(Ordering::SeqCst)
}
fn write_closed(&self) -> bool {
self.inner.write_closed.load(Ordering::SeqCst)
}
fn cancel_io(&self) -> IoResult<()> {
match unsafe { c::CancelIoEx(self.handle(), ptr::null_mut()) } {
0 if os::errno() == libc::ERROR_NOT_FOUND as i32 => {
Ok(())
}
0 => Err(super::last_error()),
_ => Ok(())
}
}
pub fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
if self.read.is_none() {
self.read = Some(try!(Event::new(true, false)));
}
let mut bytes_read = 0;
let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
overlapped.hEvent = self.read.as_ref().unwrap().handle();
// Pre-flight check to see if the reading half has been closed. This
// must be done before issuing the ReadFile request, but after we
// acquire the lock.
//
// See comments in close_read() about why this lock is necessary.
let guard = self.inner.lock.lock();
if self.read_closed() {
return Err(eof())
}
// Issue a nonblocking requests, succeeding quickly if it happened to
// succeed.
let ret = unsafe {
libc::ReadFile(self.handle(),
buf.as_ptr() as libc::LPVOID,
buf.len() as libc::DWORD,
&mut bytes_read,
&mut overlapped)
};
if ret != 0 { return Ok(bytes_read as usize) }
// If our errno doesn't say that the I/O is pending, then we hit some
// legitimate error and return immediately.
if os::errno() != libc::ERROR_IO_PENDING as i32 {
return Err(super::last_error())
}
// Now that we've issued a successful nonblocking request, we need to
// wait for it to finish. This can all be done outside the lock because
// we'll see any invocation of CancelIoEx. We also call this in a loop
// because we're woken up if the writing half is closed, we just need to
// realize that the reading half wasn't closed and we go right back to
// sleep.
drop(guard);
loop {
// Process a timeout if one is pending
let wait_succeeded = await(self.handle(), self.read_deadline,
&[overlapped.hEvent]);
let ret = unsafe {
libc::GetOverlappedResult(self.handle(),
&mut overlapped,
&mut bytes_read,
libc::TRUE)
};
// If we succeeded, or we failed for some reason other than
// CancelIoEx, return immediately
if ret != 0 { return Ok(bytes_read as usize) }
if os::errno() != libc::ERROR_OPERATION_ABORTED as i32 {
return Err(super::last_error())
}
// If the reading half is now closed, then we're done. If we woke up
// because the writing half was closed, keep trying.
if wait_succeeded.is_err() {
return Err(sys_common::timeout("read timed out"))
}
if self.read_closed() {
return Err(eof())
}
}
}
pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
if self.write.is_none() {
self.write = Some(try!(Event::new(true, false)));
}
let mut offset = 0;
let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
overlapped.hEvent = self.write.as_ref().unwrap().handle();
while offset < buf.len() {
let mut bytes_written = 0;
// This sequence below is quite similar to the one found in read().
// Some careful looping is done to ensure that if close_write() is
// invoked we bail out early, and if close_read() is invoked we keep
// going after we woke up.
//
// See comments in close_read() about why this lock is necessary.
let guard = self.inner.lock.lock();
if self.write_closed() {
return Err(epipe())
}
let ret = unsafe {
libc::WriteFile(self.handle(),
buf[offset..].as_ptr() as libc::LPVOID,
(buf.len() - offset) as libc::DWORD,
&mut bytes_written,
&mut overlapped)
};
let err = os::errno();
drop(guard);
if ret == 0 {
if err != libc::ERROR_IO_PENDING as i32 {
return Err(decode_error_detailed(err as i32))
}
// Process a timeout if one is pending
let wait_succeeded = await(self.handle(), self.write_deadline,
&[overlapped.hEvent]);
let ret = unsafe {
libc::GetOverlappedResult(self.handle(),
&mut overlapped,
&mut bytes_written,
libc::TRUE)
};
// If we weren't aborted, this was a legit error, if we were
// aborted, then check to see if the write half was actually
// closed or whether we woke up from the read half closing.
if ret == 0 {
if os::errno() != libc::ERROR_OPERATION_ABORTED as i32 {
return Err(super::last_error())
}
if !wait_succeeded.is_ok() {
let amt = offset + bytes_written as usize;
return if amt > 0 {
Err(IoError {
kind: old_io::ShortWrite(amt),
desc: "short write during write",
detail: None,
})
} else {
Err(sys_common::timeout("write timed out"))
}
}
if self.write_closed() {
return Err(epipe())
}
continue // retry
}
}
offset += bytes_written as usize;
}
Ok(())
}
pub fn close_read(&mut self) -> IoResult<()> {
// On windows, there's no actual shutdown() method for pipes, so we're
// forced to emulate the behavior manually at the application level. To
// do this, we need to both cancel any pending requests, as well as
// prevent all future requests from succeeding. These two operations are
// not atomic with respect to one another, so we must use a lock to do
// so.
//
// The read() code looks like:
//
// 1. Make sure the pipe is still open
// 2. Submit a read request
// 3. Wait for the read request to finish
//
// The race this lock is preventing is if another thread invokes
// close_read() between steps 1 and 2. By atomically executing steps 1
// and 2 with a lock with respect to close_read(), we're guaranteed that
// no thread will erroneously sit in a read forever.
let _guard = self.inner.lock.lock();
self.inner.read_closed.store(true, Ordering::SeqCst);
self.cancel_io()
}
pub fn close_write(&mut self) -> IoResult<()> {
// see comments in close_read() for why this lock is necessary
let _guard = self.inner.lock.lock();
self.inner.write_closed.store(true, Ordering::SeqCst);
self.cancel_io()
}
pub fn set_timeout(&mut self, timeout: Option<u64>) {
let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
self.read_deadline = deadline;
self.write_deadline = deadline;
}
pub fn set_read_timeout(&mut self, timeout: Option<u64>) {
self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
}
pub fn set_write_timeout(&mut self, timeout: Option<u64>) {
self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
}
}
impl Clone for UnixStream {
fn clone(&self) -> UnixStream {
UnixStream {
inner: self.inner.clone(),
read: None,
write: None,
read_deadline: 0,
write_deadline: 0,
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Unix Listener
////////////////////////////////////////////////////////////////////////////////
pub struct UnixListener {
handle: libc::HANDLE,
name: CString,
}
unsafe impl Send for UnixListener {}
unsafe impl Sync for UnixListener {}
impl UnixListener {
pub fn bind(addr: &CString) -> IoResult<UnixListener> {
// Although we technically don't need the pipe until much later, we
// create the initial handle up front to test the validity of the name
// and such.
let addr_v = try!(to_utf16(addr));
let ret = unsafe { pipe(addr_v.as_ptr(), true) };
if ret == libc::INVALID_HANDLE_VALUE {
Err(super::last_error())
} else {
Ok(UnixListener { handle: ret, name: addr.clone() })
}
}
pub fn listen(self) -> IoResult<UnixAcceptor> {
Ok(UnixAcceptor {
listener: self,
event: try!(Event::new(true, false)),
deadline: 0,
inner: Arc::new(AcceptorState {
abort: try!(Event::new(true, false)),
closed: AtomicBool::new(false),
}),
})
}
pub fn handle(&self) -> libc::HANDLE {
self.handle
}
}
impl Drop for UnixListener {
fn drop(&mut self) {
unsafe { let _ = libc::CloseHandle(self.handle); }
}
}
pub struct UnixAcceptor {
inner: Arc<AcceptorState>,
listener: UnixListener,
event: Event,
deadline: u64,
}
struct AcceptorState {
abort: Event,
closed: AtomicBool,
}
impl UnixAcceptor {
pub fn accept(&mut self) -> IoResult<UnixStream> {
// This function has some funky implementation details when working with
// unix pipes. On windows, each server named pipe handle can be
// connected to a one or zero clients. To the best of my knowledge, a
// named server is considered active and present if there exists at
// least one server named pipe for it.
//
// The model of this function is to take the current known server
// handle, connect a client to it, and then transfer ownership to the
// UnixStream instance. The next time accept() is invoked, it'll need a
// different server handle to connect a client to.
//
// Note that there is a possible race here. Once our server pipe is
// handed off to a `UnixStream` object, the stream could be closed,
// meaning that there would be no active server pipes, hence even though
// we have a valid `UnixAcceptor`, no one can connect to it. For this
// reason, we generate the next accept call's server pipe at the end of
// this function call.
//
// This provides us an invariant that we always have at least one server
// connection open at a time, meaning that all connects to this acceptor
// should succeed while this is active.
//
// The actual implementation of doing this is a little tricky. Once a
// server pipe is created, a client can connect to it at any time. I
// assume that which server a client connects to is nondeterministic, so
// we also need to guarantee that the only server able to be connected
// to is the one that we're calling ConnectNamedPipe on. This means that
// we have to create the second server pipe *after* we've already
// accepted a connection. In order to at least somewhat gracefully
// handle errors, this means that if the second server pipe creation
// fails that we disconnect the connected client and then just keep
// using the original server pipe.
let handle = self.listener.handle;
// If we've had an artificial call to close_accept, be sure to never
// proceed in accepting new clients in the future
if self.inner.closed.load(Ordering::SeqCst) { return Err(eof()) }
let name = try!(to_utf16(&self.listener.name));
// Once we've got a "server handle", we need to wait for a client to
// connect. The ConnectNamedPipe function will block this thread until
// someone on the other end connects. This function can "fail" if a
// client connects after we created the pipe but before we got down
// here. Thanks windows.
let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
overlapped.hEvent = self.event.handle();
if unsafe { libc::ConnectNamedPipe(handle, &mut overlapped) == 0 } {
let mut err = unsafe { libc::GetLastError() };
if err == libc::ERROR_IO_PENDING as libc::DWORD {
// Process a timeout if one is pending
let wait_succeeded = await(handle, self.deadline,
&[self.inner.abort.handle(),
overlapped.hEvent]);
// This will block until the overlapped I/O is completed. The
// timeout was previously handled, so this will either block in
// the normal case or succeed very quickly in the timeout case.
let ret = unsafe {
let mut transfer = 0;
libc::GetOverlappedResult(handle,
&mut overlapped,
&mut transfer,
libc::TRUE)
};
if ret == 0 {
if wait_succeeded.is_ok() {
err = unsafe { libc::GetLastError() };
} else {
return Err(sys_common::timeout("accept timed out"))
}
} else {
// we succeeded, bypass the check below
err = libc::ERROR_PIPE_CONNECTED as libc::DWORD;
}
}
if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD {
return Err(super::last_error())
}
}
// Now that we've got a connected client to our handle, we need to
// create a second server pipe. If this fails, we disconnect the
// connected client and return an error (see comments above).
let new_handle = unsafe { pipe(name.as_ptr(), false) };
if new_handle == libc::INVALID_HANDLE_VALUE {
let ret = Err(super::last_error());
// If our disconnection fails, then there's not really a whole lot
// that we can do, so panic
let err = unsafe { libc::DisconnectNamedPipe(handle) };
assert!(err != 0);
return ret;
} else {
self.listener.handle = new_handle;
}
// Transfer ownership of our handle into this stream
Ok(UnixStream {
inner: Arc::new(Inner::new(handle)),
read: None,
write: None,
read_deadline: 0,
write_deadline: 0,
})
}
pub fn set_timeout(&mut self, timeout: Option<u64>) {
self.deadline = timeout.map(|i| i + timer::now()).unwrap_or(0);
}
pub fn close_accept(&mut self) -> IoResult<()> {
self.inner.closed.store(true, Ordering::SeqCst);
let ret = unsafe {
c::SetEvent(self.inner.abort.handle())
};
if ret == 0 {
Err(super::last_error())
} else {
Ok(())
}
}
pub fn handle(&self) -> libc::HANDLE {
self.listener.handle()
}
}
impl Clone for UnixAcceptor {
fn clone(&self) -> UnixAcceptor {
let name = to_utf16(&self.listener.name).unwrap();
UnixAcceptor {
inner: self.inner.clone(),
event: Event::new(true, false).unwrap(),
deadline: 0,
listener: UnixListener {
name: self.listener.name.clone(),
handle: unsafe {
let p = pipe(name.as_ptr(), false) ;
assert!(p != libc::INVALID_HANDLE_VALUE as libc::HANDLE);
p
},
},
}
}
}

View File

@ -1,518 +0,0 @@
// Copyright 2012-2014 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.
#![allow(deprecated)] // this module itself is essentially deprecated
use prelude::v1::*;
use collections;
use env;
use ffi::CString;
use hash::Hash;
use libc::{pid_t, c_void};
use libc;
use mem;
#[allow(deprecated)] use old_io::fs::PathExtensions;
use old_io::process::{ProcessExit, ExitStatus};
use old_io::{IoResult, IoError};
use old_io;
use fs::PathExt;
use old_path::{BytesContainer, GenericPath};
use ptr;
use str;
use sync::{StaticMutex, MUTEX_INIT};
use sys::fs::FileDesc;
use sys::timer;
use sys_common::{AsInner, timeout};
pub use sys_common::ProcessConfig;
// `CreateProcess` is racy!
// http://support.microsoft.com/kb/315939
static CREATE_PROCESS_LOCK: StaticMutex = MUTEX_INIT;
/// A value representing a child process.
///
/// The lifetime of this value is linked to the lifetime of the actual
/// process - the Process destructor calls self.finish() which waits
/// for the process to terminate.
pub struct Process {
/// The unique id of the process (this should never be negative).
pid: pid_t,
/// A HANDLE to the process, which will prevent the pid being
/// re-used until the handle is closed.
handle: *mut (),
}
impl Drop for Process {
fn drop(&mut self) {
free_handle(self.handle);
}
}
impl Process {
pub fn id(&self) -> pid_t {
self.pid
}
pub unsafe fn kill(&self, signal: isize) -> IoResult<()> {
Process::killpid(self.pid, signal)
}
pub unsafe fn killpid(pid: pid_t, signal: isize) -> IoResult<()> {
let handle = libc::OpenProcess(libc::PROCESS_TERMINATE |
libc::PROCESS_QUERY_INFORMATION,
libc::FALSE, pid as libc::DWORD);
if handle.is_null() {
return Err(super::last_error())
}
let ret = match signal {
// test for existence on signal 0
0 => {
let mut status = 0;
let ret = libc::GetExitCodeProcess(handle, &mut status);
if ret == 0 {
Err(super::last_error())
} else if status != libc::STILL_ACTIVE {
Err(IoError {
kind: old_io::InvalidInput,
desc: "no process to kill",
detail: None,
})
} else {
Ok(())
}
}
15 | 9 => { // sigterm or sigkill
let ret = libc::TerminateProcess(handle, 1);
super::mkerr_winbool(ret)
}
_ => Err(IoError {
kind: old_io::IoUnavailable,
desc: "unsupported signal on windows",
detail: None,
})
};
let _ = libc::CloseHandle(handle);
return ret;
}
#[allow(deprecated)]
pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>,
out_fd: Option<P>, err_fd: Option<P>)
-> IoResult<Process>
where C: ProcessConfig<K, V>, P: AsInner<FileDesc>,
K: BytesContainer + Eq + Hash, V: BytesContainer
{
use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
use libc::consts::os::extra::{
TRUE, FALSE,
STARTF_USESTDHANDLES,
INVALID_HANDLE_VALUE,
DUPLICATE_SAME_ACCESS
};
use libc::funcs::extra::kernel32::{
GetCurrentProcess,
DuplicateHandle,
CloseHandle,
CreateProcessW
};
use libc::funcs::extra::msvcrt::get_osfhandle;
use mem;
if cfg.gid().is_some() || cfg.uid().is_some() {
return Err(IoError {
kind: old_io::IoUnavailable,
desc: "unsupported gid/uid requested on windows",
detail: None,
})
}
// To have the spawning semantics of unix/windows stay the same, we need to
// read the *child's* PATH if one is provided. See #15149 for more details.
let program = cfg.env().and_then(|env| {
for (key, v) in env {
if b"PATH" != key.container_as_bytes() { continue }
let v = match ::str::from_utf8(v.container_as_bytes()) {
Ok(s) => s,
Err(..) => continue,
};
// Split the value and test each path to see if the
// program exists.
for path in ::env::split_paths(v) {
let program = str::from_utf8(cfg.program().as_bytes()).unwrap();
let path = path.join(program)
.with_extension(env::consts::EXE_EXTENSION);
if path.exists() {
return Some(CString::new(path.to_str().unwrap()).unwrap())
}
}
break
}
None
});
unsafe {
let mut si = zeroed_startupinfo();
si.cb = mem::size_of::<STARTUPINFO>() as DWORD;
si.dwFlags = STARTF_USESTDHANDLES;
let cur_proc = GetCurrentProcess();
// Similarly to unix, we don't actually leave holes for the stdio file
// descriptors, but rather open up /dev/null equivalents. These
// equivalents are drawn from libuv's windows process spawning.
let set_fd = |fd: &Option<P>, slot: &mut HANDLE,
is_stdin: bool| {
match *fd {
None => {
let access = if is_stdin {
libc::FILE_GENERIC_READ
} else {
libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES
};
let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>();
let mut sa = libc::SECURITY_ATTRIBUTES {
nLength: size as libc::DWORD,
lpSecurityDescriptor: ptr::null_mut(),
bInheritHandle: 1,
};
let mut filename: Vec<u16> = "NUL".utf16_units().collect();
filename.push(0);
*slot = libc::CreateFileW(filename.as_ptr(),
access,
libc::FILE_SHARE_READ |
libc::FILE_SHARE_WRITE,
&mut sa,
libc::OPEN_EXISTING,
0,
ptr::null_mut());
if *slot == INVALID_HANDLE_VALUE {
return Err(super::last_error())
}
}
Some(ref fd) => {
let orig = get_osfhandle(fd.as_inner().fd()) as HANDLE;
if orig == INVALID_HANDLE_VALUE {
return Err(super::last_error())
}
if DuplicateHandle(cur_proc, orig, cur_proc, slot,
0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
return Err(super::last_error())
}
}
}
Ok(())
};
try!(set_fd(&in_fd, &mut si.hStdInput, true));
try!(set_fd(&out_fd, &mut si.hStdOutput, false));
try!(set_fd(&err_fd, &mut si.hStdError, false));
let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program()),
cfg.args());
let mut pi = zeroed_process_information();
let mut create_err = None;
// stolen from the libuv code.
let mut flags = libc::CREATE_UNICODE_ENVIRONMENT;
if cfg.detach() {
flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP;
}
with_envp(cfg.env(), |envp| {
with_dirp(cfg.cwd(), |dirp| {
let mut cmd_str: Vec<u16> = cmd_str.utf16_units().collect();
cmd_str.push(0);
let _lock = CREATE_PROCESS_LOCK.lock().unwrap();
let created = CreateProcessW(ptr::null(),
cmd_str.as_mut_ptr(),
ptr::null_mut(),
ptr::null_mut(),
TRUE,
flags, envp, dirp,
&mut si, &mut pi);
if created == FALSE {
create_err = Some(super::last_error());
}
})
});
assert!(CloseHandle(si.hStdInput) != 0);
assert!(CloseHandle(si.hStdOutput) != 0);
assert!(CloseHandle(si.hStdError) != 0);
match create_err {
Some(err) => return Err(err),
None => {}
}
// We close the thread handle because we don't care about keeping the
// thread id valid, and we aren't keeping the thread handle around to be
// able to close it later. We don't close the process handle however
// because std::we want the process id to stay valid at least until the
// calling code closes the process handle.
assert!(CloseHandle(pi.hThread) != 0);
Ok(Process {
pid: pi.dwProcessId as pid_t,
handle: pi.hProcess as *mut ()
})
}
}
/// Waits for a process to exit and returns the exit code, failing
/// if there is no process with the specified id.
///
/// Note that this is private to avoid race conditions on unix where if
/// a user calls waitpid(some_process.get_id()) then some_process.finish()
/// and some_process.destroy() and some_process.finalize() will then either
/// operate on a none-existent process or, even worse, on a newer process
/// with the same id.
pub fn wait(&self, deadline: u64) -> IoResult<ProcessExit> {
use libc::types::os::arch::extra::DWORD;
use libc::consts::os::extra::{
SYNCHRONIZE,
PROCESS_QUERY_INFORMATION,
FALSE,
STILL_ACTIVE,
INFINITE,
WAIT_TIMEOUT,
WAIT_OBJECT_0,
};
use libc::funcs::extra::kernel32::{
OpenProcess,
GetExitCodeProcess,
CloseHandle,
WaitForSingleObject,
};
unsafe {
let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
FALSE,
self.pid as DWORD);
if process.is_null() {
return Err(super::last_error())
}
loop {
let mut status = 0;
if GetExitCodeProcess(process, &mut status) == FALSE {
let err = Err(super::last_error());
assert!(CloseHandle(process) != 0);
return err;
}
if status != STILL_ACTIVE {
assert!(CloseHandle(process) != 0);
return Ok(ExitStatus(status as isize));
}
let interval = if deadline == 0 {
INFINITE
} else {
let now = timer::now();
if deadline < now {0} else {(deadline - now) as u32}
};
match WaitForSingleObject(process, interval) {
WAIT_OBJECT_0 => {}
WAIT_TIMEOUT => {
assert!(CloseHandle(process) != 0);
return Err(timeout("process wait timed out"))
}
_ => {
let err = Err(super::last_error());
assert!(CloseHandle(process) != 0);
return err
}
}
}
}
}
}
fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
libc::types::os::arch::extra::STARTUPINFO {
cb: 0,
lpReserved: ptr::null_mut(),
lpDesktop: ptr::null_mut(),
lpTitle: ptr::null_mut(),
dwX: 0,
dwY: 0,
dwXSize: 0,
dwYSize: 0,
dwXCountChars: 0,
dwYCountCharts: 0,
dwFillAttribute: 0,
dwFlags: 0,
wShowWindow: 0,
cbReserved2: 0,
lpReserved2: ptr::null_mut(),
hStdInput: libc::INVALID_HANDLE_VALUE,
hStdOutput: libc::INVALID_HANDLE_VALUE,
hStdError: libc::INVALID_HANDLE_VALUE,
}
}
fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
libc::types::os::arch::extra::PROCESS_INFORMATION {
hProcess: ptr::null_mut(),
hThread: ptr::null_mut(),
dwProcessId: 0,
dwThreadId: 0
}
}
fn make_command_line(prog: &CString, args: &[CString]) -> String {
let mut cmd = String::new();
append_arg(&mut cmd, str::from_utf8(prog.as_bytes()).ok()
.expect("expected program name to be utf-8 encoded"));
for arg in args {
cmd.push(' ');
append_arg(&mut cmd, str::from_utf8(arg.as_bytes()).ok()
.expect("expected argument to be utf-8 encoded"));
}
return cmd;
fn append_arg(cmd: &mut String, arg: &str) {
// If an argument has 0 characters then we need to quote it to ensure
// that it actually gets passed through on the command line or otherwise
// it will be dropped entirely when parsed on the other end.
let quote = arg.chars().any(|c| c == ' ' || c == '\t') || arg.len() == 0;
if quote {
cmd.push('"');
}
let argvec: Vec<char> = arg.chars().collect();
for i in 0..argvec.len() {
append_char_at(cmd, &argvec, i);
}
if quote {
cmd.push('"');
}
}
fn append_char_at(cmd: &mut String, arg: &[char], i: usize) {
match arg[i] {
'"' => {
// Escape quotes.
cmd.push_str("\\\"");
}
'\\' => {
if backslash_run_ends_in_quote(arg, i) {
// Double all backslashes that are in runs before quotes.
cmd.push_str("\\\\");
} else {
// Pass other backslashes through unescaped.
cmd.push('\\');
}
}
c => {
cmd.push(c);
}
}
}
fn backslash_run_ends_in_quote(s: &[char], mut i: usize) -> bool {
while i < s.len() && s[i] == '\\' {
i += 1;
}
return i < s.len() && s[i] == '"';
}
}
fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T
where K: BytesContainer + Eq + Hash,
V: BytesContainer,
F: FnOnce(*mut c_void) -> T,
{
// On Windows we pass an "environment block" which is not a char**, but
// rather a concatenation of null-terminated k=v\0 sequences, with a final
// \0 to terminate.
match env {
Some(env) => {
let mut blk = Vec::new();
for pair in env {
let kv = format!("{}={}",
pair.0.container_as_str().unwrap(),
pair.1.container_as_str().unwrap());
blk.extend(kv.utf16_units());
blk.push(0);
}
blk.push(0);
cb(blk.as_mut_ptr() as *mut c_void)
}
_ => cb(ptr::null_mut())
}
}
fn with_dirp<T, F>(d: Option<&CString>, cb: F) -> T where
F: FnOnce(*const u16) -> T,
{
match d {
Some(dir) => {
let dir_str = str::from_utf8(dir.as_bytes()).ok()
.expect("expected workingdirectory to be utf-8 encoded");
let mut dir_str: Vec<u16> = dir_str.utf16_units().collect();
dir_str.push(0);
cb(dir_str.as_ptr())
},
None => cb(ptr::null())
}
}
fn free_handle(handle: *mut ()) {
assert!(unsafe {
libc::CloseHandle(mem::transmute(handle)) != 0
})
}
#[cfg(test)]
mod tests {
use prelude::v1::*;
use str;
use ffi::CString;
use super::make_command_line;
#[test]
fn test_make_command_line() {
fn test_wrapper(prog: &str, args: &[&str]) -> String {
make_command_line(&CString::new(prog).unwrap(),
&args.iter()
.map(|a| CString::new(*a).unwrap())
.collect::<Vec<CString>>())
}
assert_eq!(
test_wrapper("prog", &["aaa", "bbb", "ccc"]),
"prog aaa bbb ccc"
);
assert_eq!(
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
"\"C:\\Program Files\\blah\\blah.exe\" aaa"
);
assert_eq!(
test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
"\"C:\\Program Files\\test\" aa\\\"bb"
);
assert_eq!(
test_wrapper("echo", &["a b c"]),
"echo \"a b c\""
);
assert_eq!(
test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}"
);
}
}

View File

@ -1,230 +0,0 @@
// Copyright 2014 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.
#![allow(deprecated)]
use prelude::v1::*;
use old_io::net::ip;
use old_io::IoResult;
use libc;
use libc::consts::os::extra::INVALID_SOCKET;
use mem;
use ptr;
use super::{last_error, last_net_error, sock_t};
use sync::Arc;
use sync::atomic::{AtomicBool, Ordering};
use sys::{self, c, set_nonblocking, wouldblock, timer};
use sys_common::{timeout, eof, net};
pub use sys_common::net::TcpStream;
pub struct Event(c::WSAEVENT);
unsafe impl Send for Event {}
unsafe impl Sync for Event {}
impl Event {
pub fn new() -> IoResult<Event> {
let event = unsafe { c::WSACreateEvent() };
if event == c::WSA_INVALID_EVENT {
Err(super::last_error())
} else {
Ok(Event(event))
}
}
pub fn handle(&self) -> c::WSAEVENT { let Event(handle) = *self; handle }
}
impl Drop for Event {
fn drop(&mut self) {
unsafe { let _ = c::WSACloseEvent(self.handle()); }
}
}
////////////////////////////////////////////////////////////////////////////////
// TCP listeners
////////////////////////////////////////////////////////////////////////////////
pub struct TcpListener { sock: sock_t }
unsafe impl Send for TcpListener {}
unsafe impl Sync for TcpListener {}
impl TcpListener {
pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
sys::init_net();
let sock = try!(net::socket(addr, libc::SOCK_STREAM));
let ret = TcpListener { sock: sock };
let mut storage = unsafe { mem::zeroed() };
let len = net::addr_to_sockaddr(addr, &mut storage);
let addrp = &storage as *const _ as *const libc::sockaddr;
match unsafe { libc::bind(sock, addrp, len) } {
-1 => Err(last_net_error()),
_ => Ok(ret),
}
}
pub fn socket(&self) -> sock_t { self.sock }
pub fn listen(self, backlog: isize) -> IoResult<TcpAcceptor> {
match unsafe { libc::listen(self.socket(), backlog as libc::c_int) } {
-1 => Err(last_net_error()),
_ => {
let accept = try!(Event::new());
let ret = unsafe {
c::WSAEventSelect(self.socket(), accept.handle(), c::FD_ACCEPT)
};
if ret != 0 {
return Err(last_net_error())
}
Ok(TcpAcceptor {
inner: Arc::new(AcceptorInner {
listener: self,
abort: try!(Event::new()),
accept: accept,
closed: AtomicBool::new(false),
}),
deadline: 0,
})
}
}
}
pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
net::sockname(self.socket(), libc::getsockname)
}
}
impl Drop for TcpListener {
fn drop(&mut self) {
unsafe { super::close_sock(self.sock); }
}
}
pub struct TcpAcceptor {
inner: Arc<AcceptorInner>,
deadline: u64,
}
struct AcceptorInner {
listener: TcpListener,
abort: Event,
accept: Event,
closed: AtomicBool,
}
unsafe impl Sync for AcceptorInner {}
impl TcpAcceptor {
pub fn socket(&self) -> sock_t { self.inner.listener.socket() }
pub fn accept(&mut self) -> IoResult<TcpStream> {
// Unlink unix, windows cannot invoke `select` on arbitrary file
// descriptors like pipes, only sockets. Consequently, windows cannot
// use the same implementation as unix for accept() when close_accept()
// is considered.
//
// In order to implement close_accept() and timeouts, windows uses
// event handles. An acceptor-specific abort event is created which
// will only get set in close_accept(), and it will never be un-set.
// Additionally, another acceptor-specific event is associated with the
// FD_ACCEPT network event.
//
// These two events are then passed to WaitForMultipleEvents to see
// which one triggers first, and the timeout passed to this function is
// the local timeout for the acceptor.
//
// If the wait times out, then the accept timed out. If the wait
// succeeds with the abort event, then we were closed, and if the wait
// succeeds otherwise, then we do a nonblocking poll via `accept` to
// see if we can accept a connection. The connection is candidate to be
// stolen, so we do all of this in a loop as well.
let events = [self.inner.abort.handle(), self.inner.accept.handle()];
while !self.inner.closed.load(Ordering::SeqCst) {
let ms = if self.deadline == 0 {
c::WSA_INFINITE as u64
} else {
let now = timer::now();
if self.deadline < now {0} else {self.deadline - now}
};
let ret = unsafe {
c::WSAWaitForMultipleEvents(2, events.as_ptr(), libc::FALSE,
ms as libc::DWORD, libc::FALSE)
};
match ret {
c::WSA_WAIT_TIMEOUT => {
return Err(timeout("accept timed out"))
}
c::WSA_WAIT_FAILED => return Err(last_net_error()),
c::WSA_WAIT_EVENT_0 => break,
n => assert_eq!(n, c::WSA_WAIT_EVENT_0 + 1),
}
let mut wsaevents: c::WSANETWORKEVENTS = unsafe { mem::zeroed() };
let ret = unsafe {
c::WSAEnumNetworkEvents(self.socket(), events[1], &mut wsaevents)
};
if ret != 0 { return Err(last_net_error()) }
if wsaevents.lNetworkEvents & c::FD_ACCEPT == 0 { continue }
match unsafe {
libc::accept(self.socket(), ptr::null_mut(), ptr::null_mut())
} {
INVALID_SOCKET if wouldblock() => {}
INVALID_SOCKET => return Err(last_net_error()),
// Accepted sockets inherit the same properties as the caller,
// so we need to deregister our event and switch the socket back
// to blocking mode
socket => {
let stream = TcpStream::new(socket);
let ret = unsafe {
c::WSAEventSelect(socket, events[1], 0)
};
if ret != 0 { return Err(last_net_error()) }
set_nonblocking(socket, false);
return Ok(stream)
}
}
}
Err(eof())
}
pub fn set_timeout(&mut self, timeout: Option<u64>) {
self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
}
pub fn close_accept(&mut self) -> IoResult<()> {
self.inner.closed.store(true, Ordering::SeqCst);
let ret = unsafe { c::WSASetEvent(self.inner.abort.handle()) };
if ret == libc::TRUE {
Ok(())
} else {
Err(last_net_error())
}
}
}
impl Clone for TcpAcceptor {
fn clone(&self) -> TcpAcceptor {
TcpAcceptor {
inner: self.inner.clone(),
deadline: 0,
}
}
}

View File

@ -1,214 +0,0 @@
// Copyright 2013 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.
//! Timers based on Windows WaitableTimers
//!
//! This implementation is meant to be used solely on windows. As with other
//! implementations, there is a worker thread which is doing all the waiting on
//! a large number of timers for all active timers in the system. This worker
//! thread uses the select() equivalent, WaitForMultipleObjects. One of the
//! objects being waited on is a signal into the worker thread to notify that
//! the incoming channel should be looked at.
//!
//! Other than that, the implementation is pretty straightforward in terms of
//! the other two implementations of timers with nothing *that* new showing up.
#![allow(deprecated)]
use prelude::v1::*;
use self::Req::*;
use libc;
use ptr;
use old_io::IoResult;
use sys_common::helper_thread::Helper;
use sync::mpsc::{channel, TryRecvError, Sender, Receiver};
helper_init! { static HELPER: Helper<Req> }
pub trait Callback {
fn call(&mut self);
}
pub struct Timer {
obj: libc::HANDLE,
on_worker: bool,
}
pub enum Req {
NewTimer(libc::HANDLE, Box<Callback + Send>, bool),
RemoveTimer(libc::HANDLE, Sender<()>),
}
unsafe impl Send for Timer {}
unsafe impl Send for Req {}
fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
let mut objs = vec![input];
let mut chans = vec![];
'outer: loop {
let idx = unsafe {
imp::WaitForMultipleObjects(objs.len() as libc::DWORD,
objs.as_ptr(),
0 as libc::BOOL,
libc::INFINITE)
};
if idx == 0 {
loop {
match messages.try_recv() {
Ok(NewTimer(obj, c, one)) => {
objs.push(obj);
chans.push((c, one));
}
Ok(RemoveTimer(obj, c)) => {
c.send(()).unwrap();
match objs.iter().position(|&o| o == obj) {
Some(i) => {
drop(objs.remove(i));
drop(chans.remove(i - 1));
}
None => {}
}
}
// See the comment in unix::timer for why we don't have any
// asserts here and why we're likely just leaving timers on
// the floor as we exit.
Err(TryRecvError::Disconnected) => {
break 'outer;
}
Err(..) => break
}
}
} else {
let remove = {
match &mut chans[idx as usize - 1] {
&mut (ref mut c, oneshot) => { c.call(); oneshot }
}
};
if remove {
drop(objs.remove(idx as usize));
drop(chans.remove(idx as usize - 1));
}
}
}
}
// returns the current time (in milliseconds)
pub fn now() -> u64 {
let mut ticks_per_s = 0;
assert_eq!(unsafe { libc::QueryPerformanceFrequency(&mut ticks_per_s) }, 1);
let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s};
let mut ticks = 0;
assert_eq!(unsafe { libc::QueryPerformanceCounter(&mut ticks) }, 1);
return (ticks as u64 * 1000) / (ticks_per_s as u64);
}
impl Timer {
pub fn new() -> IoResult<Timer> {
HELPER.boot(|| {}, helper);
let obj = unsafe {
imp::CreateWaitableTimerA(ptr::null_mut(), 0, ptr::null())
};
if obj.is_null() {
Err(super::last_error())
} else {
Ok(Timer { obj: obj, on_worker: false, })
}
}
fn remove(&mut self) {
if !self.on_worker { return }
let (tx, rx) = channel();
HELPER.send(RemoveTimer(self.obj, tx));
rx.recv().unwrap();
self.on_worker = false;
}
pub fn sleep(&mut self, msecs: u64) {
self.remove();
// there are 10^6 nanoseconds in a millisecond, and the parameter is in
// 100ns intervals, so we multiply by 10^4.
let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
assert_eq!(unsafe {
imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(),
ptr::null_mut(), 0)
}, 1);
let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) };
}
pub fn oneshot(&mut self, msecs: u64, cb: Box<Callback + Send>) {
self.remove();
// see above for the calculation
let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
assert_eq!(unsafe {
imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(),
ptr::null_mut(), 0)
}, 1);
HELPER.send(NewTimer(self.obj, cb, true));
self.on_worker = true;
}
pub fn period(&mut self, msecs: u64, cb: Box<Callback + Send>) {
self.remove();
// see above for the calculation
let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
assert_eq!(unsafe {
imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG,
ptr::null_mut(), ptr::null_mut(), 0)
}, 1);
HELPER.send(NewTimer(self.obj, cb, false));
self.on_worker = true;
}
}
impl Drop for Timer {
fn drop(&mut self) {
self.remove();
assert!(unsafe { libc::CloseHandle(self.obj) != 0 });
}
}
mod imp {
use libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER,
LONG, LPVOID, DWORD, c_void};
pub type PTIMERAPCROUTINE = *mut c_void;
extern "system" {
pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES,
bManualReset: BOOL,
lpTimerName: LPCSTR) -> HANDLE;
pub fn SetWaitableTimer(hTimer: HANDLE,
pDueTime: *const LARGE_INTEGER,
lPeriod: LONG,
pfnCompletionRoutine: PTIMERAPCROUTINE,
lpArgToCompletionRoutine: LPVOID,
fResume: BOOL) -> BOOL;
pub fn WaitForMultipleObjects(nCount: DWORD,
lpHandles: *const HANDLE,
bWaitAll: BOOL,
dwMilliseconds: DWORD) -> DWORD;
pub fn WaitForSingleObject(hHandle: HANDLE,
dwMilliseconds: DWORD) -> DWORD;
}
}

View File

@ -1,169 +0,0 @@
// Copyright 2014 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.
// ignore-lexer-test FIXME #15877
//! Windows specific console TTY implementation
//!
//! This module contains the implementation of a Windows specific console TTY.
//! Also converts between UTF-16 and UTF-8. Windows has very poor support for
//! UTF-8 and some functions will panic. In particular ReadFile and ReadConsole
//! will panic when the codepage is set to UTF-8 and a Unicode character is
//! entered.
//!
//! FIXME
//! This implementation does not account for codepoints that are split across
//! multiple reads and writes. Also, this implementation does not expose a way
//! to read/write UTF-16 directly. When/if Rust receives a Reader/Writer
//! wrapper that performs encoding/decoding, this implementation should switch
//! to working in raw UTF-16, with such a wrapper around it.
#![allow(deprecated)]
use prelude::v1::*;
use old_io::{self, IoError, IoResult, MemReader, Reader};
use iter::repeat;
use libc::types::os::arch::extra::LPCVOID;
use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
use libc::{get_osfhandle, CloseHandle};
use mem;
use ptr;
use str::from_utf8;
use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS};
use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT};
use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
use super::c::CONSOLE_SCREEN_BUFFER_INFO;
use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode};
use super::c::GetConsoleScreenBufferInfo;
fn invalid_encoding() -> IoError {
IoError {
kind: old_io::InvalidInput,
desc: "text was not valid unicode",
detail: None,
}
}
pub fn is_tty(fd: c_int) -> bool {
let mut out: DWORD = 0;
// If this function doesn't return an error, then fd is a TTY
match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE,
&mut out as LPDWORD) } {
0 => false,
_ => true,
}
}
pub struct TTY {
closeme: bool,
handle: HANDLE,
utf8: MemReader,
}
impl TTY {
pub fn new(fd: c_int) -> IoResult<TTY> {
if is_tty(fd) {
// If the file descriptor is one of stdin, stderr, or stdout
// then it should not be closed by us
let closeme = match fd {
0...2 => false,
_ => true,
};
let handle = unsafe { get_osfhandle(fd) as HANDLE };
Ok(TTY {
handle: handle,
utf8: MemReader::new(Vec::new()),
closeme: closeme,
})
} else {
Err(IoError {
kind: old_io::MismatchedFileTypeForOperation,
desc: "invalid handle provided to function",
detail: None,
})
}
}
pub fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
// Read more if the buffer is empty
if self.utf8.eof() {
let mut utf16: Vec<u16> = repeat(0u16).take(0x1000).collect();
let mut num: DWORD = 0;
match unsafe { ReadConsoleW(self.handle,
utf16.as_mut_ptr() as LPVOID,
utf16.len() as u32,
&mut num as LPDWORD,
ptr::null_mut()) } {
0 => return Err(super::last_error()),
_ => (),
};
utf16.truncate(num as usize);
let utf8 = match String::from_utf16(&utf16) {
Ok(utf8) => utf8.into_bytes(),
Err(..) => return Err(invalid_encoding()),
};
self.utf8 = MemReader::new(utf8);
}
// MemReader shouldn't error here since we just filled it
Ok(self.utf8.read(buf).unwrap())
}
pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
let utf16 = match from_utf8(buf).ok() {
Some(utf8) => {
utf8.utf16_units().collect::<Vec<u16>>()
}
None => return Err(invalid_encoding()),
};
let mut num: DWORD = 0;
match unsafe { WriteConsoleW(self.handle,
utf16.as_ptr() as LPCVOID,
utf16.len() as u32,
&mut num as LPDWORD,
ptr::null_mut()) } {
0 => Err(super::last_error()),
_ => Ok(()),
}
}
pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
// FIXME
// Somebody needs to decide on which of these flags we want
match unsafe { SetConsoleMode(self.handle,
match raw {
true => 0,
false => ENABLE_ECHO_INPUT | ENABLE_EXTENDED_FLAGS |
ENABLE_INSERT_MODE | ENABLE_LINE_INPUT |
ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE,
}) } {
0 => Err(super::last_error()),
_ => Ok(()),
}
}
pub fn get_winsize(&mut self) -> IoResult<(isize, isize)> {
let mut info: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
match unsafe { GetConsoleScreenBufferInfo(self.handle, &mut info as *mut _) } {
0 => Err(super::last_error()),
_ => Ok(((info.srWindow.Right + 1 - info.srWindow.Left) as isize,
(info.srWindow.Bottom + 1 - info.srWindow.Top) as isize)),
}
}
}
impl Drop for TTY {
fn drop(&mut self) {
if self.closeme {
// Nobody cares about the return value
let _ = unsafe { CloseHandle(self.handle) };
}
}
}

View File

@ -1,11 +0,0 @@
// Copyright 2014 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.
pub use sys_common::net::UdpSocket;

View File

@ -30,7 +30,6 @@
#![feature(collections)]
#![feature(core)]
#![feature(libc)]
#![feature(old_path)]
#![feature(quote, unsafe_destructor)]
#![feature(rustc_private)]
#![feature(staged_api)]

View File

@ -23,10 +23,7 @@ use util::interner;
use serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
use std::mem;
use std::ops::Deref;
#[allow(deprecated)]
use std::old_path::BytesContainer;
use std::rc::Rc;
#[allow(non_camel_case_types)]
@ -639,19 +636,6 @@ impl Deref for InternedString {
fn deref(&self) -> &str { &*self.string }
}
#[allow(deprecated)]
impl BytesContainer for InternedString {
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
// FIXME #12938: This is a workaround for the incorrect signature
// of `BytesContainer`, which is itself a workaround for the lack of
// DST.
unsafe {
let this = &self[..];
mem::transmute::<&[u8],&[u8]>(this.container_as_bytes())
}
}
}
impl fmt::Debug for InternedString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.string, f)