diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index e680be2a8c526..eeb1493d86856 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -12,16 +12,16 @@ #![feature(box_syntax)] #![feature(collections)] -#![feature(old_io)] #![feature(rustc_private)] -#![feature(unboxed_closures)] #![feature(std_misc)] #![feature(test)] #![feature(path_ext)] #![feature(str_char)] +#![feature(libc)] #![deny(warnings)] +extern crate libc; extern crate test; extern crate getopts; @@ -42,6 +42,7 @@ pub mod header; pub mod runtest; pub mod common; pub mod errors; +mod raise_fd_limit; pub fn main() { let config = parse_config(env::args().collect()); @@ -245,11 +246,7 @@ pub fn run_tests(config: &Config) { // sadly osx needs some file descriptor limits raised for running tests in // parallel (especially when we have lots and lots of child processes). // For context, see #8904 - #[allow(deprecated)] - fn raise_fd_limit() { - std::old_io::test::raise_fd_limit(); - } - raise_fd_limit(); + unsafe { raise_fd_limit::raise_fd_limit(); } // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary env::set_var("__COMPAT_LAYER", "RunAsInvoker"); diff --git a/src/compiletest/raise_fd_limit.rs b/src/compiletest/raise_fd_limit.rs new file mode 100644 index 0000000000000..89b9135558e06 --- /dev/null +++ b/src/compiletest/raise_fd_limit.rs @@ -0,0 +1,79 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// 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)] +pub unsafe fn raise_fd_limit() { + use libc; + use std::cmp; + use std::io; + use std::mem::size_of_val; + use std::ptr::null_mut; + + 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; + + // 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. + + // 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 _ as *mut _, &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")))] +pub unsafe fn raise_fd_limit() {} diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index daa53e2dbd596..55f158675321b 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -29,7 +29,6 @@ use std::net::TcpStream; use std::path::{Path, PathBuf}; use std::process::{Command, Output, ExitStatus}; use std::str; -use std::time::Duration; use test::MetricMap; pub fn run(config: Config, testfile: &Path) { @@ -452,11 +451,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { .expect(&format!("failed to exec `{:?}`", config.adb_path)); loop { //waiting 1 second for gdbserver start - #[allow(deprecated)] - fn sleep() { - ::std::old_io::timer::sleep(Duration::milliseconds(1000)); - } - sleep(); + ::std::thread::sleep_ms(1000); if TcpStream::connect("127.0.0.1:5039").is_ok() { break } diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index dbdb79565736c..391439bcdf2ff 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -943,7 +943,7 @@ mod test { use std::clone::Clone; use std::iter::Iterator; use std::option::Option::{Some, None, self}; - use std::rand; + use std::__rand::{thread_rng, Rng}; use std::thread; use std::vec::Vec; @@ -1095,7 +1095,7 @@ mod test { let mut v = vec![]; for i in 0..sz { check_links(&m); - let r: u8 = rand::random(); + let r: u8 = thread_rng().next_u32() as u8; match r % 6 { 0 => { m.pop_back(); diff --git a/src/libcollectionstest/bench.rs b/src/libcollectionstest/bench.rs index 8f2e71b666c6b..4e150d4a22234 100644 --- a/src/libcollectionstest/bench.rs +++ b/src/libcollectionstest/bench.rs @@ -12,14 +12,13 @@ macro_rules! map_insert_rand_bench { ($name: ident, $n: expr, $map: ident) => ( #[bench] pub fn $name(b: &mut ::test::Bencher) { - use std::rand; - use std::rand::Rng; + use std::__rand::{thread_rng, Rng}; use test::black_box; let n: usize = $n; let mut map = $map::new(); // setup - let mut rng = rand::weak_rng(); + let mut rng = thread_rng(); for _ in 0..n { let i = rng.gen::() % n; @@ -67,8 +66,7 @@ macro_rules! map_find_rand_bench { #[bench] pub fn $name(b: &mut ::test::Bencher) { use std::iter::Iterator; - use std::rand::Rng; - use std::rand; + use std::__rand::{thread_rng, Rng}; use std::vec::Vec; use test::black_box; @@ -76,7 +74,7 @@ macro_rules! map_find_rand_bench { let n: usize = $n; // setup - let mut rng = rand::weak_rng(); + let mut rng = thread_rng(); let mut keys: Vec<_> = (0..n).map(|_| rng.gen::() % n).collect(); for &k in &keys { diff --git a/src/libcollectionstest/bit/set.rs b/src/libcollectionstest/bit/set.rs index 10c688c3b6633..d020f551dd55d 100644 --- a/src/libcollectionstest/bit/set.rs +++ b/src/libcollectionstest/bit/set.rs @@ -389,16 +389,15 @@ fn test_bit_vec_clone() { mod bench { use std::collections::{BitSet, BitVec}; - use std::rand::{Rng, self}; + use std::__rand::{Rng, thread_rng, ThreadRng}; use std::u32; use test::{Bencher, black_box}; const BENCH_BITS : usize = 1 << 14; - fn rng() -> rand::IsaacRng { - let seed: &[_] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - rand::SeedableRng::from_seed(seed) + fn rng() -> ThreadRng { + thread_rng() } #[bench] diff --git a/src/libcollectionstest/bit/vec.rs b/src/libcollectionstest/bit/vec.rs index de3c0586ab728..3cddaef07915e 100644 --- a/src/libcollectionstest/bit/vec.rs +++ b/src/libcollectionstest/bit/vec.rs @@ -633,15 +633,14 @@ fn test_bit_vec_extend() { mod bench { use std::collections::BitVec; use std::u32; - use std::rand::{Rng, self}; + use std::__rand::{Rng, thread_rng, ThreadRng}; use test::{Bencher, black_box}; const BENCH_BITS : usize = 1 << 14; - fn rng() -> rand::IsaacRng { - let seed: &[_] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - rand::SeedableRng::from_seed(seed) + fn rng() -> ThreadRng { + thread_rng() } #[bench] diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollectionstest/btree/map.rs index 10d69c9f5ece6..a29968ae8a2fc 100644 --- a/src/libcollectionstest/btree/map.rs +++ b/src/libcollectionstest/btree/map.rs @@ -251,7 +251,7 @@ fn test_entry(){ mod bench { use std::collections::BTreeMap; - use std::rand::{Rng, weak_rng}; + use std::__rand::{Rng, thread_rng}; use test::{Bencher, black_box}; @@ -269,7 +269,7 @@ mod bench { fn bench_iter(b: &mut Bencher, size: i32) { let mut map = BTreeMap::::new(); - let mut rng = weak_rng(); + let mut rng = thread_rng(); for _ in 0..size { map.insert(rng.gen(), rng.gen()); diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 5b0aceb76d19c..e1c4e05e192c7 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering::{Equal, Greater, Less}; use std::default::Default; use std::iter::RandomAccessIterator; use std::mem; -use std::rand::{Rng, thread_rng}; +use std::__rand::{Rng, thread_rng}; use std::rc::Rc; use std::slice::ElementSwaps; @@ -1296,7 +1296,7 @@ fn test_to_vec() { mod bench { use std::iter::repeat; use std::{mem, ptr}; - use std::rand::{Rng, weak_rng}; + use std::__rand::{Rng, thread_rng}; use test::{Bencher, black_box}; @@ -1465,7 +1465,7 @@ mod bench { #[bench] fn random_inserts(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = repeat((0, 0)).take(30).collect(); for _ in 0..100 { @@ -1477,7 +1477,7 @@ mod bench { } #[bench] fn random_removes(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = repeat((0, 0)).take(130).collect(); for _ in 0..100 { @@ -1489,7 +1489,7 @@ mod bench { #[bench] fn sort_random_small(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = rng.gen_iter::().take(5).collect(); v.sort(); @@ -1499,7 +1499,7 @@ mod bench { #[bench] fn sort_random_medium(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = rng.gen_iter::().take(100).collect(); v.sort(); @@ -1509,7 +1509,7 @@ mod bench { #[bench] fn sort_random_large(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = rng.gen_iter::().take(10000).collect(); v.sort(); @@ -1530,7 +1530,7 @@ mod bench { #[bench] fn sort_big_random_small(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v = rng.gen_iter::().take(5) .collect::>(); @@ -1541,7 +1541,7 @@ mod bench { #[bench] fn sort_big_random_medium(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v = rng.gen_iter::().take(100) .collect::>(); @@ -1552,7 +1552,7 @@ mod bench { #[bench] fn sort_big_random_large(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v = rng.gen_iter::().take(10000) .collect::>(); diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 67a5ab891f72c..66c6863149146 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -85,35 +85,32 @@ //! functions that may encounter errors but don't otherwise return a //! useful value. //! -//! Consider the `write_line` method defined for I/O types -//! by the [`Writer`](../old_io/trait.Writer.html) trait: +//! Consider the `write_all` method defined for I/O types +//! by the [`Write`](../io/trait.Write.html) trait: //! //! ``` -//! # #![feature(old_io)] -//! use std::old_io::IoError; +//! use std::io; //! //! trait Writer { -//! fn write_line(&mut self, s: &str) -> Result<(), IoError>; +//! fn write_all(&mut self, bytes: &[u8]) -> Result<(), io::Error>; //! } //! ``` //! -//! *Note: The actual definition of `Writer` uses `IoResult`, which -//! is just a synonym for `Result`.* +//! *Note: The actual definition of `Write` uses `io::Result`, which +//! is just a synonym for `Result`.* //! //! This method doesn't produce a value, but the write may //! fail. It's crucial to handle the error case, and *not* write //! something like this: //! -//! ```{.ignore} -//! # #![feature(old_io)] -//! use std::old_io::*; -//! use std::old_path::Path; +//! ```no_run +//! use std::fs::File; +//! use std::io::prelude::*; //! -//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write); -//! // If `write_line` errors, then we'll never know, because the return +//! let mut file = File::create("valuable_data.txt").unwrap(); +//! // If `write_all` errors, then we'll never know, because the return //! // value is ignored. -//! file.write_line("important message"); -//! drop(file); +//! file.write_all(b"important message"); //! ``` //! //! If you *do* write that in Rust, the compiler will give you a @@ -125,37 +122,31 @@ //! a marginally useful message indicating why: //! //! ```{.no_run} -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; +//! use std::fs::File; +//! use std::io::prelude::*; //! -//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write); -//! file.write_line("important message").ok().expect("failed to write message"); -//! drop(file); +//! let mut file = File::create("valuable_data.txt").unwrap(); +//! file.write_all(b"important message").ok().expect("failed to write message"); //! ``` //! //! You might also simply assert success: //! //! ```{.no_run} -//! # #![feature(old_io, old_path)] -//! # use std::old_io::*; -//! # use std::old_path::Path; -//! -//! # let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write); -//! assert!(file.write_line("important message").is_ok()); -//! # drop(file); +//! # use std::fs::File; +//! # use std::io::prelude::*; +//! # let mut file = File::create("valuable_data.txt").unwrap(); +//! assert!(file.write_all(b"important message").is_ok()); //! ``` //! //! Or propagate the error up the call stack with `try!`: //! //! ``` -//! # #![feature(old_io, old_path)] -//! # use std::old_io::*; -//! # use std::old_path::Path; -//! fn write_message() -> Result<(), IoError> { -//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write); -//! try!(file.write_line("important message")); -//! drop(file); +//! # use std::fs::File; +//! # use std::io::prelude::*; +//! # use std::io; +//! fn write_message() -> io::Result<()> { +//! let mut file = try!(File::create("valuable_data.txt")); +//! try!(file.write_all(b"important message")); //! Ok(()) //! } //! ``` @@ -170,9 +161,9 @@ //! It replaces this: //! //! ``` -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; +//! use std::fs::File; +//! use std::io::prelude::*; +//! use std::io; //! //! struct Info { //! name: String, @@ -180,25 +171,28 @@ //! rating: i32, //! } //! -//! fn write_info(info: &Info) -> Result<(), IoError> { -//! let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write); +//! fn write_info(info: &Info) -> io::Result<()> { +//! let mut file = try!(File::create("my_best_friends.txt")); //! // Early return on error -//! if let Err(e) = file.write_line(&format!("name: {}", info.name)) { +//! if let Err(e) = file.write_all(format!("name: {}\n", info.name).as_bytes()) { +//! return Err(e) +//! } +//! if let Err(e) = file.write_all(format!("age: {}\n", info.age).as_bytes()) { //! return Err(e) //! } -//! if let Err(e) = file.write_line(&format!("age: {}", info.age)) { +//! if let Err(e) = file.write_all(format!("rating: {}\n", info.rating).as_bytes()) { //! return Err(e) //! } -//! file.write_line(&format!("rating: {}", info.rating)) +//! Ok(()) //! } //! ``` //! //! With this: //! //! ``` -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; +//! use std::fs::File; +//! use std::io::prelude::*; +//! use std::io; //! //! struct Info { //! name: String, @@ -206,12 +200,12 @@ //! rating: i32, //! } //! -//! fn write_info(info: &Info) -> Result<(), IoError> { -//! let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write); +//! fn write_info(info: &Info) -> io::Result<()> { +//! let mut file = try!(File::create("my_best_friends.txt")); //! // Early return on error -//! try!(file.write_line(&format!("name: {}", info.name))); -//! try!(file.write_line(&format!("age: {}", info.age))); -//! try!(file.write_line(&format!("rating: {}", info.rating))); +//! try!(file.write_all(format!("name: {}\n", info.name).as_bytes())); +//! try!(file.write_all(format!("age: {}\n", info.age).as_bytes())); +//! try!(file.write_all(format!("rating: {}\n", info.rating).as_bytes())); //! Ok(()) //! } //! ``` @@ -464,29 +458,17 @@ impl Result { /// /// # Examples /// - /// Sum the lines of a buffer by mapping strings to numbers, - /// ignoring I/O and parse errors: + /// Print the numbers on each line of a string multiplied by two. /// /// ``` - /// # #![feature(old_io)] - /// use std::old_io::*; + /// let line = "1\n2\n3\n4\n"; /// - /// let mut buffer: &[u8] = b"1\n2\n3\n4\n"; - /// let mut buffer = &mut buffer; - /// - /// let mut sum = 0; - /// - /// while !buffer.is_empty() { - /// let line: IoResult = buffer.read_line(); - /// // Convert the string line to a number using `map` and `from_str` - /// let val: IoResult = line.map(|line| { - /// line.trim_right().parse::().unwrap_or(0) - /// }); - /// // Add the value if there were no errors, otherwise add 0 - /// sum += val.unwrap_or(0); + /// for num in line.lines() { + /// match num.parse::().map(|i| i * 2) { + /// Ok(n) => println!("{}", n), + /// Err(..) => {} + /// } /// } - /// - /// assert!(sum == 10); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs index ba12ff306e9b8..cab2175f89781 100644 --- a/src/libcoretest/fmt/num.rs +++ b/src/libcoretest/fmt/num.rs @@ -169,42 +169,42 @@ fn test_radix_base_too_large() { mod u32 { use test::Bencher; use core::fmt::radix; - use std::rand::{weak_rng, Rng}; + use std::__rand::{thread_rng, Rng}; use std::io::{Write, sink}; #[bench] fn format_bin(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:b}", rng.gen::()) }) } #[bench] fn format_oct(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:o}", rng.gen::()) }) } #[bench] fn format_dec(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{}", rng.gen::()) }) } #[bench] fn format_hex(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:x}", rng.gen::()) }) } #[bench] fn format_show(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:?}", rng.gen::()) }) } #[bench] fn format_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{}", radix(rng.gen::(), 36)) }) } } @@ -212,42 +212,42 @@ mod u32 { mod i32 { use test::Bencher; use core::fmt::radix; - use std::rand::{weak_rng, Rng}; + use std::__rand::{thread_rng, Rng}; use std::io::{Write, sink}; #[bench] fn format_bin(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:b}", rng.gen::()) }) } #[bench] fn format_oct(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:o}", rng.gen::()) }) } #[bench] fn format_dec(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{}", rng.gen::()) }) } #[bench] fn format_hex(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:x}", rng.gen::()) }) } #[bench] fn format_show(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:?}", rng.gen::()) }) } #[bench] fn format_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{}", radix(rng.gen::(), 36)) }) } } diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index 63d1fe968fe1b..1e0e2018050ba 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -155,12 +155,11 @@ pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result { mod tests { #![allow(deprecated)] use super::{inflate_bytes, deflate_bytes}; - use std::rand; - use std::rand::Rng; + use std::__rand::{thread_rng, Rng}; #[test] fn test_flate_round_trip() { - let mut r = rand::thread_rng(); + let mut r = thread_rng(); let mut words = vec![]; for _ in 0..20 { let range = r.gen_range(1, 10); diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index 2ba3164e1b061..5ba6d8912f267 100644 --- a/src/librand/distributions/exponential.rs +++ b/src/librand/distributions/exponential.rs @@ -56,18 +56,6 @@ impl Rand for Exp1 { /// /// This distribution has density function: `f(x) = lambda * /// exp(-lambda * x)` for `x > 0`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{Exp, IndependentSample}; -/// -/// let exp = Exp::new(2.0); -/// let v = exp.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a Exp(2) distribution", v); -/// ``` #[derive(Copy, Clone)] pub struct Exp { /// `lambda` stored as `1/lambda`, since this is what we scale by. diff --git a/src/librand/distributions/gamma.rs b/src/librand/distributions/gamma.rs index d04e83e84f728..1125d09653631 100644 --- a/src/librand/distributions/gamma.rs +++ b/src/librand/distributions/gamma.rs @@ -37,18 +37,6 @@ use super::{IndependentSample, Sample, Exp}; /// == 1`, and using the boosting technique described in [1] for /// `shape < 1`. /// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{IndependentSample, Gamma}; -/// -/// let gamma = Gamma::new(2.0, 5.0); -/// let v = gamma.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a Gamma(2, 5) distribution", v); -/// ``` -/// /// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method /// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3 /// (September 2000), @@ -184,18 +172,6 @@ impl IndependentSample for GammaLargeShape { /// of `k` independent standard normal random variables. For other /// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2, /// 2)`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{ChiSquared, IndependentSample}; -/// -/// let chi = ChiSquared::new(11.0); -/// let v = chi.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a χ²(11) distribution", v) -/// ``` pub struct ChiSquared { repr: ChiSquaredRepr, } @@ -242,18 +218,6 @@ impl IndependentSample for ChiSquared { /// This distribution is equivalent to the ratio of two normalised /// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) / /// (χ²(n)/n)`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{FisherF, IndependentSample}; -/// -/// let f = FisherF::new(2.0, 32.0); -/// let v = f.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from an F(2, 32) distribution", v) -/// ``` pub struct FisherF { numer: ChiSquared, denom: ChiSquared, @@ -287,18 +251,6 @@ impl IndependentSample for FisherF { /// The Student t distribution, `t(nu)`, where `nu` is the degrees of /// freedom. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{StudentT, IndependentSample}; -/// -/// let t = StudentT::new(11.0); -/// let v = t.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a t(11) distribution", v) -/// ``` pub struct StudentT { chi: ChiSquared, dof: f64 diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index 432081063c50f..77e53248607ca 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -90,24 +90,6 @@ pub struct Weighted { /// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for /// all `T`, as is `usize`, so one can store references or indices into /// another vector. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{Weighted, WeightedChoice, IndependentSample}; -/// -/// let mut items = vec!(Weighted { weight: 2, item: 'a' }, -/// Weighted { weight: 4, item: 'b' }, -/// Weighted { weight: 1, item: 'c' }); -/// let wc = WeightedChoice::new(&mut items[..]); -/// let mut rng = rand::thread_rng(); -/// for _ in 0..16 { -/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice. -/// println!("{}", wc.ind_sample(&mut rng)); -/// } -/// ``` pub struct WeightedChoice<'a, T:'a> { items: &'a mut [Weighted], weight_range: Range diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs index fa41c3edfe5ac..ac3fe6510ebcd 100644 --- a/src/librand/distributions/normal.rs +++ b/src/librand/distributions/normal.rs @@ -72,19 +72,6 @@ impl Rand for StandardNormal { /// /// This uses the ZIGNOR variant of the Ziggurat method, see /// `StandardNormal` for more details. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{Normal, IndependentSample}; -/// -/// // mean 2, standard deviation 3 -/// let normal = Normal::new(2.0, 3.0); -/// let v = normal.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a N(2, 9) distribution", v) -/// ``` #[derive(Copy, Clone)] pub struct Normal { mean: f64, @@ -121,19 +108,6 @@ impl IndependentSample for Normal { /// /// If `X` is log-normal distributed, then `ln(X)` is `N(mean, /// std_dev**2)` distributed. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{LogNormal, IndependentSample}; -/// -/// // mean 2, standard deviation 3 -/// let log_normal = LogNormal::new(2.0, 3.0); -/// let v = log_normal.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from an ln N(2, 9) distribution", v) -/// ``` #[derive(Copy, Clone)] pub struct LogNormal { norm: Normal diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index 347d494259d08..8406c76cc1bbc 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -32,23 +32,6 @@ use distributions::{Sample, IndependentSample}; /// including `high`, but this may be very difficult. All the /// primitive integer types satisfy this property, and the float types /// normally satisfy it, but rounding may mean `high` can occur. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand::distributions::{IndependentSample, Range}; -/// -/// fn main() { -/// let between = Range::new(10, 10000); -/// let mut rng = std::rand::thread_rng(); -/// let mut sum = 0; -/// for _ in 0..1000 { -/// sum += between.ind_sample(&mut rng); -/// } -/// println!("{}", sum); -/// } -/// ``` pub struct Range { low: X, range: X, diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 15d3d981eb5c0..53ea28f0c11d3 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -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))] @@ -145,17 +143,6 @@ pub trait Rng : Sized { /// with new data, and may panic if this is impossible /// (e.g. reading past the end of a file that is being used as the /// source of randomness). - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand, core)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut v = [0; 13579]; - /// thread_rng().fill_bytes(&mut v); - /// println!("{:?}", &v[..]); - /// ``` fn fill_bytes(&mut self, dest: &mut [u8]) { // this could, in theory, be done by transmuting dest to a // [u64], but this is (1) likely to be undefined behaviour for @@ -181,18 +168,6 @@ pub trait Rng : Sized { } /// Return a random value of a `Rand` type. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let x: usize = rng.gen(); - /// println!("{}", x); - /// println!("{:?}", rng.gen::<(f64, bool)>()); - /// ``` #[inline(always)] fn gen(&mut self) -> T { Rand::rand(self) @@ -200,19 +175,6 @@ pub trait Rng : Sized { /// Return an iterator that will yield an infinite number of randomly /// generated items. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let x = rng.gen_iter::().take(10).collect::>(); - /// println!("{:?}", x); - /// println!("{:?}", rng.gen_iter::<(f64, bool)>().take(5) - /// .collect::>()); - /// ``` fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> { Generator { rng: self, _marker: PhantomData } } @@ -228,50 +190,17 @@ pub trait Rng : Sized { /// # Panics /// /// Panics if `low >= high`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let n: usize = rng.gen_range(0, 10); - /// println!("{}", n); - /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64); - /// println!("{}", m); - /// ``` fn gen_range(&mut self, low: T, high: T) -> T { assert!(low < high, "Rng.gen_range called with low >= high"); Range::new(low, high).ind_sample(self) } /// Return a bool with a 1 in n chance of true - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// println!("{}", rng.gen_weighted_bool(3)); - /// ``` fn gen_weighted_bool(&mut self, n: usize) -> bool { n <= 1 || self.gen_range(0, n) == 0 } /// Return an iterator of random characters from the set A-Z,a-z,0-9. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let s: String = thread_rng().gen_ascii_chars().take(10).collect(); - /// println!("{}", s); - /// ``` fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> { AsciiGenerator { rng: self } } @@ -279,18 +208,6 @@ pub trait Rng : Sized { /// Return a random element from `values`. /// /// Return `None` if `values` is empty. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let choices = [1, 2, 4, 8, 16, 32]; - /// let mut rng = thread_rng(); - /// println!("{:?}", rng.choose(&choices)); - /// assert_eq!(rng.choose(&choices[..0]), None); - /// ``` fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> { if values.is_empty() { None @@ -300,20 +217,6 @@ pub trait Rng : Sized { } /// Shuffle a mutable slice in place. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand, core)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let mut y = [1, 2, 3]; - /// rng.shuffle(&mut y); - /// println!("{:?}", y); - /// rng.shuffle(&mut y); - /// println!("{:?}", y); - /// ``` fn shuffle(&mut self, values: &mut [T]) { let mut i = values.len(); while i >= 2 { @@ -364,33 +267,9 @@ impl<'a, R: Rng> Iterator for AsciiGenerator<'a, R> { /// the same stream of randomness multiple times. pub trait SeedableRng: Rng { /// Reseed an RNG with the given seed. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{Rng, SeedableRng, StdRng}; - /// - /// let seed: &[_] = &[1, 2, 3, 4]; - /// let mut rng: StdRng = SeedableRng::from_seed(seed); - /// println!("{}", rng.gen::()); - /// rng.reseed(&[5, 6, 7, 8]); - /// println!("{}", rng.gen::()); - /// ``` fn reseed(&mut self, Seed); /// Create a new RNG with the given seed. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{Rng, SeedableRng, StdRng}; - /// - /// let seed: &[_] = &[1, 2, 3, 4]; - /// let mut rng: StdRng = SeedableRng::from_seed(seed); - /// println!("{}", rng.gen::()); - /// ``` fn from_seed(seed: Seed) -> Self; } @@ -486,16 +365,6 @@ impl Rand for XorShiftRng { /// Use `Closed01` for the closed interval `[0,1]`, and the default /// `Rand` implementation for `f32` and `f64` for the half-open /// `[0,1)`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand::{random, Open01}; -/// -/// let Open01(val) = random::>(); -/// println!("f32 from (0,1): {}", val); -/// ``` pub struct Open01(pub F); /// A wrapper for generating floating point numbers uniformly in the @@ -504,31 +373,17 @@ pub struct Open01(pub F); /// Use `Open01` for the closed interval `(0,1)`, and the default /// `Rand` implementation of `f32` and `f64` for the half-open /// `[0,1)`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand::{random, Closed01}; -/// -/// let Closed01(val) = random::>(); -/// println!("f32 from [0,1]: {}", val); -/// ``` pub struct Closed01(pub F); #[cfg(test)] mod test { - use std::rand; + use std::__rand as rand; pub struct MyRng { inner: R } impl ::Rng for MyRng { fn next_u32(&mut self) -> u32 { - fn next(t: &mut T) -> u32 { - use std::rand::Rng; - t.next_u32() - } - next(&mut self.inner) + rand::Rng::next_u32(&mut self.inner) } } @@ -536,7 +391,7 @@ mod test { MyRng { inner: rand::thread_rng() } } - pub fn weak_rng() -> MyRng { - MyRng { inner: rand::weak_rng() } + pub fn weak_rng() -> MyRng { + MyRng { inner: rand::thread_rng() } } } diff --git a/src/librand/rand_impls.rs b/src/librand/rand_impls.rs index e2a5276cc78ab..2f37451ecbb3a 100644 --- a/src/librand/rand_impls.rs +++ b/src/librand/rand_impls.rs @@ -211,55 +211,3 @@ impl Rand for Option { } } } - -#[cfg(test)] -mod tests { - use std::rand::{Rng, thread_rng, Open01, Closed01}; - - struct ConstantRng(u64); - impl Rng for ConstantRng { - fn next_u32(&mut self) -> u32 { - let ConstantRng(v) = *self; - v as u32 - } - fn next_u64(&mut self) -> u64 { - let ConstantRng(v) = *self; - v - } - } - - #[test] - fn floating_point_edge_cases() { - // the test for exact equality is correct here. - assert!(ConstantRng(0xffff_ffff).gen::() != 1.0); - assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::() != 1.0); - } - - #[test] - fn rand_open() { - // this is unlikely to catch an incorrect implementation that - // generates exactly 0 or 1, but it keeps it sane. - let mut rng = thread_rng(); - for _ in 0..1_000 { - // strict inequalities - let Open01(f) = rng.gen::>(); - assert!(0.0 < f && f < 1.0); - - let Open01(f) = rng.gen::>(); - assert!(0.0 < f && f < 1.0); - } - } - - #[test] - fn rand_closed() { - let mut rng = thread_rng(); - for _ in 0..1_000 { - // strict inequalities - let Closed01(f) = rng.gen::>(); - assert!(0.0 <= f && f <= 1.0); - - let Closed01(f) = rng.gen::>(); - assert!(0.0 <= f && f <= 1.0); - } - } -} diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index 98d1bbf5af9da..287a23cf1d1b6 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -99,34 +99,6 @@ impl, Rsdr: Reseeder + Default> } /// Something that can be used to reseed an RNG via `ReseedingRng`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand::{Rng, SeedableRng, StdRng}; -/// use std::rand::reseeding::{Reseeder, ReseedingRng}; -/// -/// struct TickTockReseeder { tick: bool } -/// impl Reseeder for TickTockReseeder { -/// fn reseed(&mut self, rng: &mut StdRng) { -/// let val = if self.tick {0} else {1}; -/// rng.reseed(&[val]); -/// self.tick = !self.tick; -/// } -/// } -/// fn main() { -/// let rsdr = TickTockReseeder { tick: true }; -/// -/// let inner = StdRng::new().unwrap(); -/// let mut rng = ReseedingRng::new(inner, 10, rsdr); -/// -/// // this will repeat, because it gets reseeded very regularly. -/// let s: String = rng.gen_ascii_chars().take(100).collect(); -/// println!("{}", s); -/// } -/// -/// ``` pub trait Reseeder { /// Reseed the given RNG. fn reseed(&mut self, rng: &mut R); diff --git a/src/librustc_back/fs.rs b/src/librustc_back/fs.rs index 231f6ee3be6ad..2ab4d7ff78a1d 100644 --- a/src/librustc_back/fs.rs +++ b/src/librustc_back/fs.rs @@ -9,69 +9,42 @@ // except according to those terms. use std::io; -use std::env; -#[allow(deprecated)] use std::old_path::{self, GenericPath}; -#[allow(deprecated)] use std::old_io; use std::path::{Path, PathBuf}; -/// Returns an absolute path in the filesystem that `path` points to. The -/// returned path does not contain any symlinks in its hierarchy. -#[allow(deprecated)] // readlink is deprecated +#[cfg(windows)] pub fn realpath(original: &Path) -> io::Result { - let old = old_path::Path::new(original.to_str().unwrap()); - match old_realpath(&old) { - Ok(p) => Ok(PathBuf::from(p.as_str().unwrap())), - Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)) - } + Ok(original.to_path_buf()) } -#[allow(deprecated)] -fn old_realpath(original: &old_path::Path) -> old_io::IoResult { - use std::old_io::fs; - const MAX_LINKS_FOLLOWED: usize = 256; - let original = old_path::Path::new(env::current_dir().unwrap() - .to_str().unwrap()).join(original); +#[cfg(unix)] +pub fn realpath(original: &Path) -> io::Result { + use libc; + use std::ffi::{OsString, CString}; + use std::os::unix::prelude::*; - // Right now lstat on windows doesn't work quite well - if cfg!(windows) { - return Ok(original) + extern { + fn realpath(pathname: *const libc::c_char, resolved: *mut libc::c_char) + -> *mut libc::c_char; } - let result = original.root_path(); - let mut result = result.expect("make_absolute has no root_path"); - let mut followed = 0; - - for part in original.components() { - result.push(part); - - loop { - if followed == MAX_LINKS_FOLLOWED { - return Err(old_io::standard_error(old_io::InvalidInput)) - } - - match fs::lstat(&result) { - Err(..) => break, - Ok(ref stat) if stat.kind != old_io::FileType::Symlink => break, - Ok(..) => { - followed += 1; - let path = try!(fs::readlink(&result)); - result.pop(); - result.push(path); - } - } + let path = try!(CString::new(original.as_os_str().as_bytes())); + let mut buf = vec![0u8; 16 * 1024]; + unsafe { + let r = realpath(path.as_ptr(), buf.as_mut_ptr() as *mut _); + if r.is_null() { + return Err(io::Error::last_os_error()) } } - - return Ok(result); + let p = buf.iter().position(|i| *i == 0).unwrap(); + buf.truncate(p); + Ok(PathBuf::from(OsString::from_vec(buf))) } #[cfg(all(not(windows), test))] mod test { - use std::old_io; - use std::old_io::fs::{File, symlink, mkdir, mkdir_recursive}; - use super::old_realpath as realpath; - use std::old_io::TempDir; - use std::old_path::{Path, GenericPath}; + use tempdir::TempDir; + use std::fs::{self, File}; + use super::realpath; #[test] fn realpath_works() { @@ -83,15 +56,15 @@ mod test { let linkdir = tmpdir.join("test3"); File::create(&file).unwrap(); - mkdir(&dir, old_io::USER_RWX).unwrap(); - symlink(&file, &link).unwrap(); - symlink(&dir, &linkdir).unwrap(); - - assert!(realpath(&tmpdir).unwrap() == tmpdir); - assert!(realpath(&file).unwrap() == file); - assert!(realpath(&link).unwrap() == file); - assert!(realpath(&linkdir).unwrap() == dir); - assert!(realpath(&linkdir.join("link")).unwrap() == file); + fs::create_dir(&dir).unwrap(); + fs::soft_link(&file, &link).unwrap(); + fs::soft_link(&dir, &linkdir).unwrap(); + + assert_eq!(realpath(&tmpdir).unwrap(), tmpdir); + assert_eq!(realpath(&file).unwrap(), file); + assert_eq!(realpath(&link).unwrap(), file); + assert_eq!(realpath(&linkdir).unwrap(), dir); + assert_eq!(realpath(&linkdir.join("link")).unwrap(), file); } #[test] @@ -106,13 +79,13 @@ mod test { let e = d.join("e"); let f = a.join("f"); - mkdir_recursive(&b, old_io::USER_RWX).unwrap(); - mkdir_recursive(&d, old_io::USER_RWX).unwrap(); + fs::create_dir_all(&b).unwrap(); + fs::create_dir_all(&d).unwrap(); File::create(&f).unwrap(); - symlink(&Path::new("../d/e"), &c).unwrap(); - symlink(&Path::new("../f"), &e).unwrap(); + fs::soft_link("../d/e", &c).unwrap(); + fs::soft_link("../f", &e).unwrap(); - assert!(realpath(&c).unwrap() == f); - assert!(realpath(&e).unwrap() == f); + assert_eq!(realpath(&c).unwrap(), f); + assert_eq!(realpath(&e).unwrap(), f); } } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 7591ebf67f868..3c54d6631f893 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -35,17 +35,16 @@ #![feature(box_syntax)] #![feature(collections)] #![feature(core)] -#![feature(old_fs)] -#![feature(old_io)] -#![feature(old_path)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(rand)] #![feature(path_ext)] #![feature(step_by)] +#![feature(libc)] #![cfg_attr(test, feature(test, rand))] extern crate syntax; +extern crate libc; extern crate serialize; #[macro_use] extern crate log; diff --git a/src/librustc_back/rpath.rs b/src/librustc_back/rpath.rs index ff3f0b78f91b3..58073079d31df 100644 --- a/src/librustc_back/rpath.rs +++ b/src/librustc_back/rpath.rs @@ -97,8 +97,9 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String let cwd = env::current_dir().unwrap(); let mut lib = (config.realpath)(&cwd.join(lib)).unwrap(); lib.pop(); - let mut output = (config.realpath)(&cwd.join(&config.out_filename)).unwrap(); + let mut output = cwd.join(&config.out_filename); output.pop(); + let output = (config.realpath)(&output).unwrap(); let relative = path_relative_from(&lib, &output) .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib)); // FIXME (#9639): This needs to handle non-utf8 paths diff --git a/src/librustc_back/tempdir.rs b/src/librustc_back/tempdir.rs index b12732f879456..522d66cb563a3 100644 --- a/src/librustc_back/tempdir.rs +++ b/src/librustc_back/tempdir.rs @@ -12,7 +12,7 @@ use std::env; use std::io::{self, Error, ErrorKind}; use std::fs; use std::path::{self, PathBuf, Path}; -use std::rand::{thread_rng, Rng}; +use std::__rand::{thread_rng, Rng}; /// A wrapper for a path to temporary directory implementing automatic /// scope-based deletion. diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 5890bdec8c1bc..620ea40b48a35 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2627,9 +2627,9 @@ mod tests { use super::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser, StackElement, Stack, Decoder, Encoder, EncoderError}; use std::{i64, u64, f32, f64}; + use std::io::prelude::*; use std::collections::BTreeMap; use std::string; - use std::old_io::Writer; #[derive(RustcDecodable, Eq, PartialEq, Debug)] struct OptionData { @@ -3464,7 +3464,6 @@ mod tests { #[test] fn test_encode_hashmap_with_numeric_key() { use std::str::from_utf8; - use std::old_io::Writer; use std::collections::HashMap; let mut hm: HashMap = HashMap::new(); hm.insert(1, true); @@ -3480,7 +3479,6 @@ mod tests { #[test] fn test_prettyencode_hashmap_with_numeric_key() { use std::str::from_utf8; - use std::old_io::Writer; use std::collections::HashMap; let mut hm: HashMap = HashMap::new(); hm.insert(1, true); diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 2e86712c9bccf..dde79b123e602 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -30,13 +30,12 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(collections)] #![feature(core)] -#![feature(old_path)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(std_misc)] #![feature(unicode)] #![feature(str_char)] -#![cfg_attr(test, feature(test, old_io))] +#![cfg_attr(test, feature(test))] // test harness access #[cfg(test)] extern crate test; diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 81b5d4c5818b6..af1387346106a 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -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(&self, e: &mut S) -> Result<(), S::Error> { - self.as_vec().encode(e) - } -} - -#[allow(deprecated)] -impl Decodable for old_path::posix::Path { - fn decode(d: &mut D) -> Result { - let bytes: Vec = try!(Decodable::decode(d)); - Ok(old_path::posix::Path::new(bytes)) - } -} - -#[allow(deprecated)] -impl Encodable for old_path::windows::Path { - fn encode(&self, e: &mut S) -> Result<(), S::Error> { - self.as_vec().encode(e) - } -} - -#[allow(deprecated)] -impl Decodable for old_path::windows::Path { - fn decode(d: &mut D) -> Result { - let bytes: Vec = try!(Decodable::decode(d)); - Ok(old_path::windows::Path::new(bytes)) - } -} - impl Encodable for path::PathBuf { fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.to_str().unwrap().encode(e) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 54a3a0557686d..d0d71a128b6e5 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1631,7 +1631,7 @@ mod test_map { use super::Entry::{Occupied, Vacant}; use iter::{range_inclusive, range_step_inclusive, repeat}; use cell::RefCell; - use rand::{weak_rng, Rng}; + use rand::{thread_rng, Rng}; #[test] fn test_create_capacity_zero() { @@ -2290,7 +2290,7 @@ mod test_map { } let mut m = HashMap::new(); - let mut rng = weak_rng(); + let mut rng = thread_rng(); // Populate the map with some items. for _ in 0..50 { diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index de91e5f326839..d510ee48a1698 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -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 for io::Error { } } -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl From 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. /// diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index ab20efe25eb19..cc2ba265cd75f 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -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 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 for OsString { fn from_inner(buf: Buf) -> OsString { OsString { inner: buf } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 914830d9dcfea..d519e1df13b9a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -123,7 +123,7 @@ pub struct WalkDir { /// Opening a file for both reading and writing, as well as creating it if it /// doesn't exist: /// -/// ``` +/// ```no_run /// use std::fs::OpenOptions; /// /// let file = OpenOptions::new() @@ -1195,7 +1195,8 @@ mod tests { pub fn tmpdir() -> TempDir { let p = env::temp_dir(); - let ret = p.join(&format!("rust-{}", rand::random::())); + let mut r = rand::thread_rng(); + let ret = p.join(&format!("rust-{}", r.next_u32())); check!(fs::create_dir(&ret)); TempDir(ret) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b329494a0526b..b2bcbaa7b1c2b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -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,18 @@ pub mod time; pub mod rt; mod panicking; +mod rand; + +// Some external utilities of the standard library rely on randomness (aka +// rustc_back::TempDir and tests) and need a way to get at the OS rng we've got +// here. This module is not at all intended for stabilization as-is, however, +// but it may be stabilized long-term. As a result we're exposing a hidden, +// unstable module so we can get our build working. +#[doc(hidden)] +#[unstable(feature = "rand")] +pub mod __rand { + pub use rand::{thread_rng, ThreadRng, Rng}; +} // Modules that exist purely to document + host impl docs for primitive types @@ -297,8 +306,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![] diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index ea869ebae100a..8ab66f2328fb6 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -464,7 +464,7 @@ mod bench { mod usize { use super::test::Bencher; - use rand::{weak_rng, Rng}; + use rand::{thread_rng, Rng}; use std::fmt; #[inline] @@ -474,38 +474,38 @@ mod bench { #[bench] fn to_str_bin(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 2); }) } #[bench] fn to_str_oct(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 8); }) } #[bench] fn to_str_dec(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 10); }) } #[bench] fn to_str_hex(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 16); }) } #[bench] fn to_str_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 36); }) } } mod isize { use super::test::Bencher; - use rand::{weak_rng, Rng}; + use rand::{thread_rng, Rng}; use std::fmt; #[inline] @@ -515,43 +515,43 @@ mod bench { #[bench] fn to_str_bin(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 2); }) } #[bench] fn to_str_oct(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 8); }) } #[bench] fn to_str_dec(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 10); }) } #[bench] fn to_str_hex(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 16); }) } #[bench] fn to_str_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { to_string(rng.gen::(), 36); }) } } mod f64 { use super::test::Bencher; - use rand::{weak_rng, Rng}; + use rand::{thread_rng, Rng}; use f64; #[bench] fn float_to_string(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { f64::to_string(rng.gen()); }) } } diff --git a/src/libstd/old_io/buffered.rs b/src/libstd/old_io/buffered.rs deleted file mode 100644 index 68aa7e4770f06..0000000000000 --- a/src/libstd/old_io/buffered.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - inner: R, - buf: Vec, - pos: usize, - cap: usize, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufferedReader 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 BufferedReader { - /// Creates a new `BufferedReader` with the specified buffer capacity - pub fn with_capacity(cap: usize, inner: R) -> BufferedReader { - 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 { - 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 Buffer for BufferedReader { - 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 Reader for BufferedReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - 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 { - inner: Option, - buf: Vec, - pos: usize -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufferedWriter 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 BufferedWriter { - /// Creates a new `BufferedWriter` with the specified buffer capacity - pub fn with_capacity(cap: usize, inner: W) -> BufferedWriter { - // 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 { - 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 Writer for BufferedWriter { - 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 Drop for BufferedWriter { - 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 { - inner: BufferedWriter, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for LineBufferedWriter 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 LineBufferedWriter { - /// Creates a new `LineBufferedWriter` - pub fn new(inner: W) -> LineBufferedWriter { - // 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 Writer for LineBufferedWriter { - 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(BufferedWriter); - -impl InternalBufferedWriter { - fn get_mut<'a>(&'a mut self) -> &'a mut BufferedWriter { - let InternalBufferedWriter(ref mut w) = *self; - return w; - } -} - -impl Reader for InternalBufferedWriter { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - 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 { - inner: BufferedReader> -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufferedStream 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 BufferedStream { - /// 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 { - 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 { - 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 Buffer for BufferedStream { - 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 Reader for BufferedStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.read(buf) - } -} - -impl Writer for BufferedStream { - 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 { - 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, - } - - impl Reader for ShortReader { - fn read(&mut self, _: &mut [u8]) -> old_io::IoResult { - 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 { - 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); - }); - } -} diff --git a/src/libstd/old_io/comm_adapters.rs b/src/libstd/old_io/comm_adapters.rs deleted file mode 100644 index 5ebf931e95c37..0000000000000 --- a/src/libstd/old_io/comm_adapters.rs +++ /dev/null @@ -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 or the MIT license -// , 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, // A buffer of bytes received but not consumed. - pos: usize, // How many of the buffered bytes have already be consumed. - rx: Receiver>, // 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>) -> 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 { - 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>, -} - -impl ChanWriter { - /// Wraps a channel in a `ChanWriter` structure - pub fn new(tx: Sender>) -> 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), - } - } -} diff --git a/src/libstd/old_io/extensions.rs b/src/libstd/old_io/extensions.rs deleted file mode 100644 index 73973d0db282d..0000000000000 --- a/src/libstd/old_io/extensions.rs +++ /dev/null @@ -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 or the MIT license -// , 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; - - #[inline] - fn next(&mut self) -> Option> { - 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(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(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 { - 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 { - Err(old_io::standard_error(old_io::EndOfFile)) - } - } - - struct ErroringReader; - - impl Reader for ErroringReader { - fn read(&mut self, _: &mut [u8]) -> old_io::IoResult { - 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 { - 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 { - 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 { - 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::>(); - 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); - } -} diff --git a/src/libstd/old_io/fs.rs b/src/libstd/old_io/fs.rs deleted file mode 100644 index 509daa46ef3be..0000000000000 --- a/src/libstd/old_io/fs.rs +++ /dev/null @@ -1,1654 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// ignore-lexer-test FIXME #15679 - -//! Synchronous File I/O -//! -//! This module provides a set of functions and traits for working -//! with regular files & directories on a filesystem. -//! -//! At the top-level of the module are a set of freestanding functions, associated -//! with various filesystem operations. They all operate on `Path` objects. -//! -//! All operations in this module, including those as part of `File` et al block -//! the task during execution. In the event of failure, all functions/methods -//! will return an `IoResult` type with an `Err` value. -//! -//! Also included in this module is an implementation block on the `Path` object -//! defined in `std::path::Path`. The impl adds useful methods about inspecting -//! the metadata of a file. This includes getting the `stat` information, -//! reading off particular bits of it, etc. -//! -//! # Examples -//! -//! ```rust -//! # #![feature(old_io, io, old_path)] -//! # #![allow(unused_must_use)] -//! use std::old_io::fs::PathExtensions; -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let path = Path::new("foo.txt"); -//! -//! // create the file, whether it exists or not -//! let mut file = File::create(&path); -//! file.write(b"foobar"); -//! # drop(file); -//! -//! // open the file in read-only mode -//! let mut file = File::open(&path); -//! file.read_to_end(); -//! -//! println!("{}", path.stat().unwrap().size); -//! # drop(file); -//! fs::unlink(&path); -//! ``` - -use clone::Clone; -use old_io::standard_error; -use old_io::{FilePermission, Write, Open, FileAccess, FileMode, FileType}; -use old_io::{IoResult, IoError, InvalidInput}; -use old_io::{FileStat, SeekStyle, Seek, Writer, Reader}; -use old_io::{Read, Truncate, ReadWrite, Append}; -use old_io::UpdateIoError; -use old_io; -use iter::{Iterator, Extend}; -use option::Option; -use option::Option::{Some, None}; -use old_path::{Path, GenericPath}; -use old_path; -use result::Result::{Err, Ok}; -use string::String; -use vec::Vec; - -use sys::fs as fs_imp; -use sys_common; - -/// Unconstrained file access type that exposes read and write operations -/// -/// Can be constructed via `File::open()`, `File::create()`, and -/// `File::open_mode()`. -/// -/// # Error -/// -/// This type will return errors as an `IoResult` if operations are -/// attempted against it for which its underlying file descriptor was not -/// configured at creation time, via the `FileAccess` parameter to -/// `File::open_mode()`. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::File")] -#[unstable(feature = "old_io")] -pub struct File { - fd: fs_imp::FileDesc, - path: Path, - last_nread: isize, -} - -impl sys_common::AsInner for File { - fn as_inner(&self) -> &fs_imp::FileDesc { - &self.fd - } -} - -#[deprecated(since = "1.0.0", reason = "replaced with std::fs")] -#[unstable(feature = "old_io")] -impl File { - /// Open a file at `path` in the mode specified by the `mode` and `access` - /// arguments - /// - /// # Examples - /// - /// ```rust,should_panic - /// # #![feature(old_io, old_path)] - /// use std::old_io::*; - /// use std::old_path::Path; - /// - /// let p = Path::new("/some/file/path.txt"); - /// - /// let file = match File::open_mode(&p, Open, ReadWrite) { - /// Ok(f) => f, - /// Err(e) => panic!("file error: {}", e), - /// }; - /// // do some stuff with that file - /// - /// // the file will be closed at the end of this block - /// ``` - /// - /// `FileMode` and `FileAccess` provide information about the permissions - /// context in which a given stream is created. More information about them - /// can be found in `std::io`'s docs. If a file is opened with `Write` - /// or `ReadWrite` access, then it will be created if it does not already - /// exist. - /// - /// Note that, with this function, a `File` is returned regardless of the - /// access-limitations indicated by `FileAccess` (e.g. calling `write` on a - /// `File` opened as `Read` will return an error at runtime). - /// - /// # Error - /// - /// This function will return an error under a number of different - /// circumstances, to include but not limited to: - /// - /// * Opening a file that does not exist with `Read` access. - /// * Attempting to open a file with a `FileAccess` that the user lacks - /// permissions for - /// * Filesystem-level errors (full disk, etc) - #[deprecated(since = "1.0.0", reason = "replaced with std::fs::OpenOptions")] - #[unstable(feature = "old_io")] - pub fn open_mode(path: &Path, - mode: FileMode, - access: FileAccess) -> IoResult { - fs_imp::open(path, mode, access).and_then(|fd| { - // On *BSD systems, we can open a directory as a file and read from it: - // fd=open("/tmp", O_RDONLY); read(fd, buf, N); - // due to an old tradition before the introduction of opendir(3). - // We explicitly reject it because there are few use cases. - if cfg!(not(any(windows, target_os = "linux", target_os = "android"))) && - try!(fd.fstat()).kind == FileType::Directory { - Err(IoError { - kind: InvalidInput, - desc: "is a directory", - detail: None - }) - } else { - Ok(File { - path: path.clone(), - fd: fd, - last_nread: -1 - }) - } - }).update_err("couldn't open path as file", |e| { - format!("{}; path={}; mode={}; access={}", e, path.display(), - mode_string(mode), access_string(access)) - }) - } - - /// Attempts to open a file in read-only mode. This function is equivalent to - /// `File::open_mode(path, Open, Read)`, and will raise all of the same - /// errors that `File::open_mode` does. - /// - /// For more information, see the `File::open_mode` function. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, old_path)] - /// use std::old_io::*; - /// use std::old_path::Path; - /// - /// let contents = File::open(&Path::new("foo.txt")).read_to_end(); - /// ``` - #[deprecated(since = "1.0.0", reason = "replaced with std::fs::File::open")] - #[unstable(feature = "old_io")] - pub fn open(path: &Path) -> IoResult { - File::open_mode(path, Open, Read) - } - - /// Attempts to create a file in write-only mode. This function is - /// equivalent to `File::open_mode(path, Truncate, Write)`, and will - /// raise all of the same errors that `File::open_mode` does. - /// - /// For more information, see the `File::open_mode` function. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, old_path, io)] - /// # #![allow(unused_must_use)] - /// use std::old_io::*; - /// use std::old_path::Path; - /// - /// let mut f = File::create(&Path::new("foo.txt")); - /// f.write(b"This is a sample file"); - /// # drop(f); - /// # ::std::old_io::fs::unlink(&Path::new("foo.txt")); - /// ``` - #[deprecated(since = "1.0.0", reason = "replaced with std::fs::File::create")] - #[unstable(feature = "old_io")] - pub fn create(path: &Path) -> IoResult { - File::open_mode(path, Truncate, Write) - .update_desc("couldn't create file") - } - - /// Returns the original path that was used to open this file. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn path<'a>(&'a self) -> &'a Path { - &self.path - } - - /// Synchronizes all modifications to this file to its permanent storage - /// device. This will flush any internal buffers necessary to perform this - /// operation. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn fsync(&mut self) -> IoResult<()> { - self.fd.fsync() - .update_err("couldn't fsync file", - |e| format!("{}; path={}", e, self.path.display())) - } - - /// This function is similar to `fsync`, except that it may not synchronize - /// file metadata to the filesystem. This is intended for use cases that - /// must synchronize content, but don't need the metadata on disk. The goal - /// of this method is to reduce disk operations. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn datasync(&mut self) -> IoResult<()> { - self.fd.datasync() - .update_err("couldn't datasync file", - |e| format!("{}; path={}", e, self.path.display())) - } - - /// Either truncates or extends the underlying file, updating the size of - /// this file to become `size`. This is equivalent to unix's `truncate` - /// function. - /// - /// If the `size` is less than the current file's size, then the file will - /// be shrunk. If it is greater than the current file's size, then the file - /// will be extended to `size` and have all of the intermediate data filled - /// in with 0s. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn truncate(&mut self, size: i64) -> IoResult<()> { - self.fd.truncate(size) - .update_err("couldn't truncate file", |e| - format!("{}; path={}; size={}", e, self.path.display(), size)) - } - - /// Returns true if the stream has reached the end of the file. - /// - /// If true, then this file will no longer continue to return data via - /// `read`. - /// - /// Note that the operating system will not return an `EOF` indicator - /// until you have attempted to read past the end of the file, so if - /// you've read _exactly_ the number of bytes in the file, this will - /// return `false`, not `true`. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn eof(&self) -> bool { - self.last_nread == 0 - } - - /// Queries information about the underlying file. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn stat(&self) -> IoResult { - self.fd.fstat() - .update_err("couldn't fstat file", |e| - format!("{}; path={}", e, self.path.display())) - } -} - -/// Unlink a file from the underlying filesystem. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let p = Path::new("/some/file/path.txt"); -/// fs::unlink(&p); -/// ``` -/// -/// Note that, just because an unlink call was successful, it is not -/// guaranteed that a file is immediately deleted (e.g. depending on -/// platform, other open file descriptors may prevent immediate removal) -/// -/// # Error -/// -/// This function will return an error if `path` points to a directory, if the -/// user lacks permissions to remove the file, or if some other filesystem-level -/// error occurs. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::remove_file")] -#[unstable(feature = "old_io")] -pub fn unlink(path: &Path) -> IoResult<()> { - fs_imp::unlink(path) - .update_err("couldn't unlink path", |e| - format!("{}; path={}", e, path.display())) -} - -/// Given a path, query the file system to get information about a file, -/// directory, etc. This function will traverse symlinks to query -/// information about the destination file. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let p = Path::new("/some/file/path.txt"); -/// match fs::stat(&p) { -/// Ok(stat) => { /* ... */ } -/// Err(e) => { /* handle error */ } -/// } -/// ``` -/// -/// # Error -/// -/// This function will return an error if the user lacks the requisite permissions -/// to perform a `stat` call on the given `path` or if there is no entry in the -/// filesystem at the provided path. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::metadata")] -#[unstable(feature = "old_io")] -pub fn stat(path: &Path) -> IoResult { - fs_imp::stat(path) - .update_err("couldn't stat path", |e| - format!("{}; path={}", e, path.display())) -} - -/// Perform the same operation as the `stat` function, except that this -/// function does not traverse through symlinks. This will return -/// information about the symlink file instead of the file that it points -/// to. -/// -/// # Error -/// -/// See `stat` -#[unstable(feature = "old_fs")] -pub fn lstat(path: &Path) -> IoResult { - fs_imp::lstat(path) - .update_err("couldn't lstat path", |e| - format!("{}; path={}", e, path.display())) -} - -/// Rename a file or directory to a new name. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// fs::rename(&Path::new("foo"), &Path::new("bar")); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the provided `from` doesn't exist, if -/// the process lacks permissions to view the contents, or if some other -/// intermittent I/O error occurs. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::rename")] -#[unstable(feature = "old_io")] -pub fn rename(from: &Path, to: &Path) -> IoResult<()> { - fs_imp::rename(from, to) - .update_err("couldn't rename path", |e| - format!("{}; from={:?}; to={:?}", e, from.display(), to.display())) -} - -/// Copies the contents of one file to another. This function will also -/// copy the permission bits of the original file to the destination file. -/// -/// Note that if `from` and `to` both point to the same file, then the file -/// will likely get truncated by this operation. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); -/// ``` -/// -/// # Error -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The `from` path is not a file -/// * The `from` file does not exist -/// * The current process does not have the permission rights to access -/// `from` or write `to` -/// -/// Note that this copy is not atomic in that once the destination is -/// ensured to not exist, there is nothing preventing the destination from -/// being created and then destroyed by this operation. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::copy")] -#[unstable(feature = "old_io")] -pub fn copy(from: &Path, to: &Path) -> IoResult<()> { - fn update_err(result: IoResult, from: &Path, to: &Path) -> IoResult { - result.update_err("couldn't copy path", |e| { - format!("{}; from={:?}; to={:?}", e, from.display(), to.display()) - }) - } - - if !from.is_file() { - return update_err(Err(IoError { - kind: old_io::MismatchedFileTypeForOperation, - desc: "the source path is not an existing file", - detail: None - }), from, to) - } - - let mut reader = try!(File::open(from)); - let mut writer = try!(File::create(to)); - - try!(update_err(super::util::copy(&mut reader, &mut writer), from, to)); - - chmod(to, try!(update_err(from.stat(), from, to)).perm) -} - -/// Changes the permission mode bits found on a file or a directory. This -/// function takes a mask from the `io` module -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io; -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// fs::chmod(&Path::new("file.txt"), old_io::USER_FILE); -/// fs::chmod(&Path::new("file.txt"), old_io::USER_READ | old_io::USER_WRITE); -/// fs::chmod(&Path::new("dir"), old_io::USER_DIR); -/// fs::chmod(&Path::new("file.exe"), old_io::USER_EXEC); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the provided `path` doesn't exist, if -/// the process lacks permissions to change the attributes of the file, or if -/// some other I/O error is encountered. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::set_permissions")] -#[unstable(feature = "old_io")] -pub fn chmod(path: &Path, mode: old_io::FilePermission) -> IoResult<()> { - fs_imp::chmod(path, mode.bits() as usize) - .update_err("couldn't chmod path", |e| - format!("{}; path={}; mode={:?}", e, path.display(), mode)) -} - -/// Change the user and group owners of a file at the specified path. -#[unstable(feature = "old_fs")] -pub fn chown(path: &Path, uid: isize, gid: isize) -> IoResult<()> { - fs_imp::chown(path, uid, gid) - .update_err("couldn't chown path", |e| - format!("{}; path={}; uid={}; gid={}", e, path.display(), uid, gid)) -} - -/// Creates a new hard link on the filesystem. The `dst` path will be a -/// link pointing to the `src` path. Note that systems often require these -/// two paths to both be located on the same filesystem. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::hard_link")] -#[unstable(feature = "old_io")] -pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - fs_imp::link(src, dst) - .update_err("couldn't link path", |e| - format!("{}; src={:?}; dest={:?}", e, src.display(), dst.display())) -} - -/// Creates a new symbolic link on the filesystem. The `dst` path will be a -/// symlink pointing to the `src` path. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::soft_link")] -#[unstable(feature = "old_io")] -pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - fs_imp::symlink(src, dst) - .update_err("couldn't symlink path", |e| - format!("{}; src={:?}; dest={:?}", e, src.display(), dst.display())) -} - -/// Reads a symlink, returning the file that the symlink points to. -/// -/// # Error -/// -/// This function will return an error on failure. Failure conditions include -/// reading a file that does not exist or reading a file that is not a symlink. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::read_link")] -#[unstable(feature = "old_io")] -pub fn readlink(path: &Path) -> IoResult { - fs_imp::readlink(path) - .update_err("couldn't resolve symlink for path", |e| - format!("{}; path={}", e, path.display())) -} - -/// Create a new, empty directory at the provided path -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path, old_fs)] -/// # #![allow(unused_must_use)] -/// use std::old_io; -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let p = Path::new("/some/dir"); -/// fs::mkdir(&p, old_io::USER_RWX); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the user lacks permissions to make a -/// new directory at the provided `path`, or if the directory already exists. -#[unstable(feature = "old_fs")] -pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> { - fs_imp::mkdir(path, mode.bits() as usize) - .update_err("couldn't create directory", |e| - format!("{}; path={}; mode={}", e, path.display(), mode)) -} - -/// Remove an existing, empty directory -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let p = Path::new("/some/dir"); -/// fs::rmdir(&p); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the user lacks permissions to remove -/// the directory at the provided `path`, or if the directory isn't empty. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::remove_dir")] -#[unstable(feature = "old_io")] -pub fn rmdir(path: &Path) -> IoResult<()> { - fs_imp::rmdir(path) - .update_err("couldn't remove directory", |e| - format!("{}; path={}", e, path.display())) -} - -/// Retrieve a vector containing all entries within a provided directory -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// use std::old_io::fs::PathExtensions; -/// use std::old_io; -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// // one possible implementation of fs::walk_dir only visiting files -/// fn visit_dirs(dir: &Path, cb: &mut F) -> old_io::IoResult<()> where -/// F: FnMut(&Path), -/// { -/// if dir.is_dir() { -/// let contents = try!(fs::readdir(dir)); -/// for entry in contents.iter() { -/// if entry.is_dir() { -/// try!(visit_dirs(entry, cb)); -/// } else { -/// (*cb)(entry); -/// } -/// } -/// Ok(()) -/// } else { -/// Err(old_io::standard_error(old_io::InvalidInput)) -/// } -/// } -/// ``` -/// -/// # Error -/// -/// This function will return an error if the provided `path` doesn't exist, if -/// the process lacks permissions to view the contents or if the `path` points -/// at a non-directory file -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::read_dir")] -#[unstable(feature = "old_io")] -pub fn readdir(path: &Path) -> IoResult> { - fs_imp::readdir(path) - .update_err("couldn't read directory", - |e| format!("{}; path={}", e, path.display())) -} - -/// Returns an iterator that will recursively walk the directory structure -/// rooted at `path`. The path given will not be iterated over, and this will -/// perform iteration in some top-down order. The contents of unreadable -/// subdirectories are ignored. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::walk_dir")] -#[unstable(feature = "old_io")] -pub fn walk_dir(path: &Path) -> IoResult { - Ok(Directories { - stack: try!(readdir(path).update_err("couldn't walk directory", - |e| format!("{}; path={}", e, path.display()))) - }) -} - -/// An iterator that walks over a directory -#[derive(Clone)] -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::ReadDir")] -#[unstable(feature = "old_io")] -pub struct Directories { - stack: Vec, -} - -impl Iterator for Directories { - type Item = Path; - - fn next(&mut self) -> Option { - match self.stack.pop() { - Some(path) => { - if path.is_dir() { - match readdir(&path) { - Ok(dirs) => { self.stack.extend(dirs.into_iter()); } - Err(..) => {} - } - } - Some(path) - } - None => None - } - } -} - -/// Recursively create a directory and all of its parent components if they -/// are missing. -/// -/// # Error -/// -/// See `fs::mkdir`. -#[unstable(feature = "old_fs")] -pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> { - // tjc: if directory exists but with different permissions, - // should we return false? - if path.is_dir() { - return Ok(()) - } - - let comps = path.components(); - let mut curpath = path.root_path().unwrap_or(Path::new(".")); - - for c in comps { - curpath.push(c); - - let result = mkdir(&curpath, mode) - .update_err("couldn't recursively mkdir", - |e| format!("{}; path={}", e, path.display())); - - match result { - Err(mkdir_err) => { - // already exists ? - if try!(stat(&curpath)).kind != FileType::Directory { - return Err(mkdir_err); - } - } - Ok(()) => () - } - } - - Ok(()) -} - -/// Removes a directory at this path, after removing all its contents. Use -/// carefully! -/// -/// # Error -/// -/// See `file::unlink` and `fs::readdir` -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::remove_dir_all")] -#[unstable(feature = "old_io")] -pub fn rmdir_recursive(path: &Path) -> IoResult<()> { - let mut rm_stack = Vec::new(); - rm_stack.push(path.clone()); - - fn rmdir_failed(err: &IoError, path: &Path) -> String { - format!("rmdir_recursive failed; path={}; cause={}", - path.display(), err) - } - - fn update_err(err: IoResult, path: &Path) -> IoResult { - err.update_err("couldn't recursively rmdir", - |e| rmdir_failed(e, path)) - } - - while !rm_stack.is_empty() { - let children = try!(readdir(rm_stack.last().unwrap()) - .update_detail(|e| rmdir_failed(e, path))); - - let mut has_child_dir = false; - - // delete all regular files in the way and push subdirs - // on the stack - for child in children { - // FIXME(#12795) we should use lstat in all cases - let child_type = match cfg!(windows) { - true => try!(update_err(stat(&child), path)), - false => try!(update_err(lstat(&child), path)) - }; - - if child_type.kind == FileType::Directory { - rm_stack.push(child); - has_child_dir = true; - } else { - // we can carry on safely if the file is already gone - // (eg: deleted by someone else since readdir) - match update_err(unlink(&child), path) { - Ok(()) => (), - Err(ref e) if e.kind == old_io::FileNotFound => (), - Err(e) => return Err(e) - } - } - } - - // if no subdir was found, let's pop and delete - if !has_child_dir { - let result = update_err(rmdir(&rm_stack.pop().unwrap()), path); - match result { - Ok(()) => (), - Err(ref e) if e.kind == old_io::FileNotFound => (), - Err(e) => return Err(e) - } - } - } - - Ok(()) -} - -/// Changes the timestamps for a file's last modification and access time. -/// The file at the path specified will have its last access time set to -/// `atime` and its modification time set to `mtime`. The times specified should -/// be in milliseconds. -// FIXME(#10301) these arguments should not be u64 -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::set_file_times")] -#[unstable(feature = "old_io")] -pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> { - fs_imp::utime(path, atime, mtime) - .update_err("couldn't change_file_times", |e| - format!("{}; path={}", e, path.display())) -} - -impl Reader for File { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - fn update_err(result: IoResult, file: &File) -> IoResult { - result.update_err("couldn't read file", - |e| format!("{}; path={}", - e, file.path.display())) - } - - let result = update_err(self.fd.read(buf), self); - - match result { - Ok(read) => { - self.last_nread = read as isize; - match read { - 0 => update_err(Err(standard_error(old_io::EndOfFile)), self), - _ => Ok(read as usize) - } - }, - Err(e) => Err(e) - } - } -} - -impl Writer for File { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.fd.write(buf) - .update_err("couldn't write to file", - |e| format!("{}; path={}", e, self.path.display())) - } -} - -impl Seek for File { - fn tell(&self) -> IoResult { - self.fd.tell() - .update_err("couldn't retrieve file cursor (`tell`)", - |e| format!("{}; path={}", e, self.path.display())) - } - - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { - let err = match self.fd.seek(pos, style) { - Ok(_) => { - // successful seek resets EOF indicator - self.last_nread = -1; - Ok(()) - } - Err(e) => Err(e), - }; - err.update_err("couldn't seek in file", - |e| format!("{}; path={}", e, self.path.display())) - } -} - -/// Utility methods for paths. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::PathExt")] -#[unstable(feature = "old_io")] -pub trait PathExtensions { - /// Get information on the file, directory, etc at this path. - /// - /// Consult the `fs::stat` documentation for more info. - /// - /// This call preserves identical runtime/error semantics with `file::stat`. - fn stat(&self) -> IoResult; - - /// Get information on the file, directory, etc at this path, not following - /// symlinks. - /// - /// Consult the `fs::lstat` documentation for more info. - /// - /// This call preserves identical runtime/error semantics with `file::lstat`. - fn lstat(&self) -> IoResult; - - /// Boolean value indicator whether the underlying file exists on the local - /// filesystem. Returns false in exactly the cases where `fs::stat` fails. - fn exists(&self) -> bool; - - /// Whether the underlying implementation (be it a file path, or something - /// else) points at a "regular file" on the FS. Will return false for paths - /// to non-existent locations or directories or other non-regular files - /// (named pipes, etc). Follows links when making this determination. - fn is_file(&self) -> bool; - - /// Whether the underlying implementation (be it a file path, or something - /// else) is pointing at a directory in the underlying FS. Will return - /// false for paths to non-existent locations or if the item is not a - /// directory (eg files, named pipes, etc). Follows links when making this - /// determination. - fn is_dir(&self) -> bool; -} - -impl PathExtensions for old_path::Path { - fn stat(&self) -> IoResult { stat(self) } - fn lstat(&self) -> IoResult { lstat(self) } - fn exists(&self) -> bool { - self.stat().is_ok() - } - fn is_file(&self) -> bool { - match self.stat() { - Ok(s) => s.kind == FileType::RegularFile, - Err(..) => false - } - } - fn is_dir(&self) -> bool { - match self.stat() { - Ok(s) => s.kind == FileType::Directory, - Err(..) => false - } - } -} - -fn mode_string(mode: FileMode) -> &'static str { - match mode { - super::Open => "open", - super::Append => "append", - super::Truncate => "truncate" - } -} - -fn access_string(access: FileAccess) -> &'static str { - match access { - super::Read => "read", - super::Write => "write", - super::ReadWrite => "readwrite" - } -} - -#[cfg(test)] -#[allow(unused_imports)] -#[allow(unused_variables)] -#[allow(unused_mut)] -#[allow(deprecated)] // rand -mod test { - use prelude::v1::*; - use old_io::{SeekSet, SeekCur, SeekEnd, Read, Open, ReadWrite, FileType}; - use old_io::{self, Reader, Writer, Seek}; - use old_path::{Path, GenericPath}; - use str; - use old_io::fs::*; - - macro_rules! check { ($e:expr) => ( - match $e { - Ok(t) => t, - Err(e) => panic!("{} failed with: {:?}", stringify!($e), e), - } - ) } - - macro_rules! error { ($e:expr, $s:expr) => ( - match $e { - Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), - Err(ref err) => assert!(err.to_string().contains($s), - format!("`{}` did not contain `{}`", err, $s)) - } - ) } - - pub struct TempDir(Path); - - impl TempDir { - fn join(&self, path: &str) -> Path { - let TempDir(ref p) = *self; - p.join(path) - } - - fn path<'a>(&'a self) -> &'a Path { - let TempDir(ref p) = *self; - p - } - } - - impl Drop for TempDir { - fn drop(&mut self) { - // Gee, seeing how we're testing the fs module I sure hope that we - // at least implement this correctly! - let TempDir(ref p) = *self; - check!(old_io::fs::rmdir_recursive(p)); - } - } - - pub fn tmpdir() -> TempDir { - use os; - use rand; - let temp = Path::new(::env::temp_dir().to_str().unwrap()); - let ret = temp.join(format!("rust-{}", rand::random::())); - check!(old_io::fs::mkdir(&ret, old_io::USER_RWX)); - TempDir(ret) - } - - #[test] - fn file_test_io_smoke_test() { - let message = "it's alright. have a good time"; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test.txt"); - { - let mut write_stream = File::open_mode(filename, Open, ReadWrite); - check!(write_stream.write(message.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - let mut read_buf = [0; 1028]; - let read_str = match check!(read_stream.read(&mut read_buf)) { - 0 => panic!("shouldn't happen"), - n => str::from_utf8(&read_buf[..n]).unwrap().to_string() - }; - assert_eq!(read_str, message); - } - check!(unlink(filename)); - } - - #[test] - fn invalid_path_raises() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_that_does_not_exist.txt"); - let result = File::open_mode(filename, Open, Read); - - error!(result, "couldn't open path as file"); - if cfg!(unix) { - error!(result, "no such file or directory"); - } - error!(result, &format!("path={}; mode=open; access=read", filename.display())); - } - - #[test] - fn file_test_iounlinking_invalid_path_should_raise_condition() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); - - let result = unlink(filename); - - error!(result, "couldn't unlink path"); - if cfg!(unix) { - error!(result, "no such file or directory"); - } - error!(result, &format!("path={}", filename.display())); - } - - #[test] - fn file_test_io_non_positional_read() { - let message: &str = "ten-four"; - let mut read_mem = [0; 8]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); - { - let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - { - let read_buf = &mut read_mem[0..4]; - check!(read_stream.read(read_buf)); - } - { - let read_buf = &mut read_mem[4..8]; - check!(read_stream.read(read_buf)); - } - } - check!(unlink(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, message); - } - - #[test] - fn file_test_io_seek_and_tell_smoke_test() { - let message = "ten-four"; - let mut read_mem = [0; 4]; - let set_cursor = 4 as u64; - let mut tell_pos_pre_read; - let mut tell_pos_post_read; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); - { - let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - check!(read_stream.seek(set_cursor as i64, SeekSet)); - tell_pos_pre_read = check!(read_stream.tell()); - check!(read_stream.read(&mut read_mem)); - tell_pos_post_read = check!(read_stream.tell()); - } - check!(unlink(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, &message[4..8]); - assert_eq!(tell_pos_pre_read, set_cursor); - assert_eq!(tell_pos_post_read, message.len() as u64); - } - - #[test] - fn file_test_io_seek_and_write() { - let initial_msg = "food-is-yummy"; - let overwrite_msg = "-the-bar!!"; - let final_msg = "foo-the-bar!!"; - let seek_idx = 3; - let mut read_mem = [0; 13]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); - { - let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - check!(rw_stream.write(initial_msg.as_bytes())); - check!(rw_stream.seek(seek_idx as i64, SeekSet)); - check!(rw_stream.write(overwrite_msg.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - check!(read_stream.read(&mut read_mem)); - } - check!(unlink(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert!(read_str == final_msg); - } - - #[test] - fn file_test_io_seek_shakedown() { - use str; // 01234567890123 - let initial_msg = "qwer-asdf-zxcv"; - let chunk_one: &str = "qwer"; - let chunk_two: &str = "asdf"; - let chunk_three: &str = "zxcv"; - let mut read_mem = [0; 4]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); - { - let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - check!(rw_stream.write(initial_msg.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - - check!(read_stream.seek(-4, SeekEnd)); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three); - - check!(read_stream.seek(-9, SeekCur)); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two); - - check!(read_stream.seek(0, SeekSet)); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one); - } - check!(unlink(filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_file() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); - { - let mut fs = check!(File::open_mode(filename, Open, ReadWrite)); - let msg = "hw"; - fs.write(msg.as_bytes()).unwrap(); - - let fstat_res = check!(fs.stat()); - assert_eq!(fstat_res.kind, FileType::RegularFile); - } - let stat_res_fn = check!(stat(filename)); - assert_eq!(stat_res_fn.kind, FileType::RegularFile); - let stat_res_meth = check!(filename.stat()); - assert_eq!(stat_res_meth.kind, FileType::RegularFile); - check!(unlink(filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_dir() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_dir"); - check!(mkdir(filename, old_io::USER_RWX)); - let stat_res_fn = check!(stat(filename)); - assert!(stat_res_fn.kind == FileType::Directory); - let stat_res_meth = check!(filename.stat()); - assert!(stat_res_meth.kind == FileType::Directory); - check!(rmdir(filename)); - } - - #[test] - fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("fileinfo_false_on_dir"); - check!(mkdir(dir, old_io::USER_RWX)); - assert!(dir.is_file() == false); - check!(rmdir(dir)); - } - - #[test] - fn file_test_fileinfo_check_exists_before_and_after_file_creation() { - let tmpdir = tmpdir(); - let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); - check!(File::create(file).write(b"foo")); - assert!(file.exists()); - check!(unlink(file)); - assert!(!file.exists()); - } - - #[test] - fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("before_and_after_dir"); - assert!(!dir.exists()); - check!(mkdir(dir, old_io::USER_RWX)); - assert!(dir.exists()); - assert!(dir.is_dir()); - check!(rmdir(dir)); - assert!(!dir.exists()); - } - - #[test] - fn file_test_directoryinfo_readdir() { - use str; - let tmpdir = tmpdir(); - let dir = &tmpdir.join("di_readdir"); - check!(mkdir(dir, old_io::USER_RWX)); - let prefix = "foo"; - for n in 0..3 { - let f = dir.join(format!("{}.txt", n)); - let mut w = check!(File::create(&f)); - let msg_str = format!("{}{}", prefix, n); - let msg = msg_str.as_bytes(); - check!(w.write(msg)); - } - let files = check!(readdir(dir)); - let mut mem = [0; 4]; - for f in &files { - { - let n = f.filestem_str(); - check!(File::open(f).read(&mut mem)); - let read_str = str::from_utf8(&mem).unwrap(); - let expected = match n { - None|Some("") => panic!("really shouldn't happen.."), - Some(n) => format!("{}{}", prefix, n), - }; - assert_eq!(expected, read_str); - } - check!(unlink(f)); - } - check!(rmdir(dir)); - } - - #[test] - fn file_test_walk_dir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("walk_dir"); - check!(mkdir(dir, old_io::USER_RWX)); - - let dir1 = &dir.join("01/02/03"); - check!(mkdir_recursive(dir1, old_io::USER_RWX)); - check!(File::create(&dir1.join("04"))); - - let dir2 = &dir.join("11/12/13"); - check!(mkdir_recursive(dir2, old_io::USER_RWX)); - check!(File::create(&dir2.join("14"))); - - let mut files = check!(walk_dir(dir)); - let mut cur = [0; 2]; - for f in files { - let stem = f.filestem_str().unwrap(); - let root = stem.as_bytes()[0] - b'0'; - let name = stem.as_bytes()[1] - b'0'; - assert!(cur[root as usize] < name); - cur[root as usize] = name; - } - - check!(rmdir_recursive(dir)); - } - - #[test] - fn mkdir_path_already_exists_error() { - use old_io::{IoError, PathAlreadyExists}; - - let tmpdir = tmpdir(); - let dir = &tmpdir.join("mkdir_error_twice"); - check!(mkdir(dir, old_io::USER_RWX)); - match mkdir(dir, old_io::USER_RWX) { - Err(IoError{kind:PathAlreadyExists,..}) => (), - _ => assert!(false) - }; - } - - #[test] - fn recursive_mkdir() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1/d2"); - check!(mkdir_recursive(&dir, old_io::USER_RWX)); - assert!(dir.is_dir()) - } - - #[test] - fn recursive_mkdir_failure() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1"); - let file = dir.join("f1"); - - check!(mkdir_recursive(&dir, old_io::USER_RWX)); - check!(File::create(&file)); - - let result = mkdir_recursive(&file, old_io::USER_RWX); - - error!(result, "couldn't recursively mkdir"); - error!(result, "couldn't create directory"); - error!(result, "mode=0700"); - error!(result, &format!("path={}", file.display())); - } - - #[test] - fn recursive_mkdir_slash() { - check!(mkdir_recursive(&Path::new("/"), old_io::USER_RWX)); - } - - // FIXME(#12795) depends on lstat to work on windows - #[cfg(not(windows))] - #[test] - fn recursive_rmdir() { - let tmpdir = tmpdir(); - let d1 = tmpdir.join("d1"); - let dt = d1.join("t"); - let dtt = dt.join("t"); - let d2 = tmpdir.join("d2"); - let canary = d2.join("do_not_delete"); - check!(mkdir_recursive(&dtt, old_io::USER_RWX)); - check!(mkdir_recursive(&d2, old_io::USER_RWX)); - check!(File::create(&canary).write(b"foo")); - check!(symlink(&d2, &dt.join("d2"))); - check!(rmdir_recursive(&d1)); - - assert!(!d1.is_dir()); - assert!(canary.exists()); - } - - #[test] - fn unicode_path_is_dir() { - assert!(Path::new(".").is_dir()); - assert!(!Path::new("test/stdtest/fs.rs").is_dir()); - - let tmpdir = tmpdir(); - - let mut dirpath = tmpdir.path().clone(); - dirpath.push(format!("test-가一ー你好")); - check!(mkdir(&dirpath, old_io::USER_RWX)); - assert!(dirpath.is_dir()); - - let mut filepath = dirpath; - filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); - check!(File::create(&filepath)); // ignore return; touch only - assert!(!filepath.is_dir()); - assert!(filepath.exists()); - } - - #[test] - fn unicode_path_exists() { - assert!(Path::new(".").exists()); - assert!(!Path::new("test/nonexistent-bogus-path").exists()); - - let tmpdir = tmpdir(); - let unicode = tmpdir.path(); - let unicode = unicode.join(format!("test-각丁ー再见")); - check!(mkdir(&unicode, old_io::USER_RWX)); - assert!(unicode.exists()); - assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); - } - - #[test] - fn copy_file_does_not_exist() { - let from = Path::new("test/nonexistent-bogus-path"); - let to = Path::new("test/other-bogus-path"); - - error!(copy(&from, &to), - &format!("couldn't copy path (the source path is not an \ - existing file; from={:?}; to={:?})", - from.display(), to.display())); - - match copy(&from, &to) { - Ok(..) => panic!(), - Err(..) => { - assert!(!from.exists()); - assert!(!to.exists()); - } - } - } - - #[test] - fn copy_file_ok() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(File::create(&input).write(b"hello")); - check!(copy(&input, &out)); - let contents = check!(File::open(&out).read_to_end()); - assert_eq!(contents, b"hello"); - - assert_eq!(check!(input.stat()).perm, check!(out.stat()).perm); - } - - #[test] - fn copy_file_dst_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - check!(File::create(&out)); - match copy(&out, tmpdir.path()) { - Ok(..) => panic!(), Err(..) => {} - } - } - - #[test] - fn copy_file_dst_exists() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in"); - let output = tmpdir.join("out"); - - check!(File::create(&input).write("foo".as_bytes())); - check!(File::create(&output).write("bar".as_bytes())); - check!(copy(&input, &output)); - - assert_eq!(check!(File::open(&output).read_to_end()), - b"foo".to_vec()); - } - - #[test] - fn copy_file_src_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - match copy(tmpdir.path(), &out) { - Ok(..) => panic!(), Err(..) => {} - } - assert!(!out.exists()); - } - - #[test] - fn copy_file_preserves_perm_bits() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(File::create(&input)); - check!(chmod(&input, old_io::USER_READ)); - check!(copy(&input, &out)); - assert!(!check!(out.stat()).perm.intersects(old_io::USER_WRITE)); - - check!(chmod(&input, old_io::USER_FILE)); - check!(chmod(&out, old_io::USER_FILE)); - } - - #[cfg(not(windows))] // FIXME(#10264) operation not permitted? - #[test] - fn symlinks_work() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(File::create(&input).write("foobar".as_bytes())); - check!(symlink(&input, &out)); - if cfg!(not(windows)) { - assert_eq!(check!(lstat(&out)).kind, FileType::Symlink); - assert_eq!(check!(out.lstat()).kind, FileType::Symlink); - } - assert_eq!(check!(stat(&out)).size, check!(stat(&input)).size); - assert_eq!(check!(File::open(&out).read_to_end()), - b"foobar".to_vec()); - } - - #[cfg(not(windows))] // apparently windows doesn't like symlinks - #[test] - fn symlink_noexist() { - let tmpdir = tmpdir(); - // symlinks can point to things that don't exist - check!(symlink(&tmpdir.join("foo"), &tmpdir.join("bar"))); - assert!(check!(readlink(&tmpdir.join("bar"))) == tmpdir.join("foo")); - } - - #[test] - fn readlink_not_symlink() { - let tmpdir = tmpdir(); - match readlink(tmpdir.path()) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn links_work() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(File::create(&input).write("foobar".as_bytes())); - check!(link(&input, &out)); - if cfg!(not(windows)) { - assert_eq!(check!(lstat(&out)).kind, FileType::RegularFile); - assert_eq!(check!(out.lstat()).kind, FileType::RegularFile); - assert_eq!(check!(stat(&out)).unstable.nlink, 2); - assert_eq!(check!(out.stat()).unstable.nlink, 2); - } - assert_eq!(check!(stat(&out)).size, check!(stat(&input)).size); - assert_eq!(check!(stat(&out)).size, check!(input.stat()).size); - assert_eq!(check!(File::open(&out).read_to_end()), - b"foobar".to_vec()); - - // can't link to yourself - match link(&input, &input) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - // can't link to something that doesn't exist - match link(&tmpdir.join("foo"), &tmpdir.join("bar")) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn chmod_works() { - let tmpdir = tmpdir(); - let file = tmpdir.join("in.txt"); - - check!(File::create(&file)); - assert!(check!(stat(&file)).perm.contains(old_io::USER_WRITE)); - check!(chmod(&file, old_io::USER_READ)); - assert!(!check!(stat(&file)).perm.contains(old_io::USER_WRITE)); - - match chmod(&tmpdir.join("foo"), old_io::USER_RWX) { - Ok(..) => panic!("wanted a panic"), - Err(..) => {} - } - - check!(chmod(&file, old_io::USER_FILE)); - } - - #[test] - fn sync_doesnt_kill_anything() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::open_mode(&path, old_io::Open, old_io::ReadWrite)); - check!(file.fsync()); - check!(file.datasync()); - check!(file.write(b"foo")); - check!(file.fsync()); - check!(file.datasync()); - drop(file); - } - - #[test] - fn truncate_works() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::open_mode(&path, old_io::Open, old_io::ReadWrite)); - check!(file.write(b"foo")); - check!(file.fsync()); - - // Do some simple things with truncation - assert_eq!(check!(file.stat()).size, 3); - check!(file.truncate(10)); - assert_eq!(check!(file.stat()).size, 10); - check!(file.write(b"bar")); - check!(file.fsync()); - assert_eq!(check!(file.stat()).size, 10); - assert_eq!(check!(File::open(&path).read_to_end()), - b"foobar\0\0\0\0".to_vec()); - - // Truncate to a smaller length, don't seek, and then write something. - // Ensure that the intermediate zeroes are all filled in (we have `seek`ed - // past the end of the file). - check!(file.truncate(2)); - assert_eq!(check!(file.stat()).size, 2); - check!(file.write(b"wut")); - check!(file.fsync()); - assert_eq!(check!(file.stat()).size, 9); - assert_eq!(check!(File::open(&path).read_to_end()), - b"fo\0\0\0\0wut".to_vec()); - drop(file); - } - - #[test] - fn open_flavors() { - let tmpdir = tmpdir(); - - match File::open_mode(&tmpdir.join("a"), old_io::Open, old_io::Read) { - Ok(..) => panic!(), Err(..) => {} - } - - // Perform each one twice to make sure that it succeeds the second time - // (where the file exists) - check!(File::open_mode(&tmpdir.join("b"), old_io::Open, old_io::Write)); - assert!(tmpdir.join("b").exists()); - check!(File::open_mode(&tmpdir.join("b"), old_io::Open, old_io::Write)); - - check!(File::open_mode(&tmpdir.join("c"), old_io::Open, old_io::ReadWrite)); - assert!(tmpdir.join("c").exists()); - check!(File::open_mode(&tmpdir.join("c"), old_io::Open, old_io::ReadWrite)); - - check!(File::open_mode(&tmpdir.join("d"), old_io::Append, old_io::Write)); - assert!(tmpdir.join("d").exists()); - check!(File::open_mode(&tmpdir.join("d"), old_io::Append, old_io::Write)); - - check!(File::open_mode(&tmpdir.join("e"), old_io::Append, old_io::ReadWrite)); - assert!(tmpdir.join("e").exists()); - check!(File::open_mode(&tmpdir.join("e"), old_io::Append, old_io::ReadWrite)); - - check!(File::open_mode(&tmpdir.join("f"), old_io::Truncate, old_io::Write)); - assert!(tmpdir.join("f").exists()); - check!(File::open_mode(&tmpdir.join("f"), old_io::Truncate, old_io::Write)); - - check!(File::open_mode(&tmpdir.join("g"), old_io::Truncate, old_io::ReadWrite)); - assert!(tmpdir.join("g").exists()); - check!(File::open_mode(&tmpdir.join("g"), old_io::Truncate, old_io::ReadWrite)); - - check!(File::create(&tmpdir.join("h")).write("foo".as_bytes())); - check!(File::open_mode(&tmpdir.join("h"), old_io::Open, old_io::Read)); - { - let mut f = check!(File::open_mode(&tmpdir.join("h"), old_io::Open, - old_io::Read)); - match f.write("wut".as_bytes()) { - Ok(..) => panic!(), Err(..) => {} - } - } - assert!(check!(stat(&tmpdir.join("h"))).size == 3, - "write/stat failed"); - { - let mut f = check!(File::open_mode(&tmpdir.join("h"), old_io::Append, - old_io::Write)); - check!(f.write("bar".as_bytes())); - } - assert!(check!(stat(&tmpdir.join("h"))).size == 6, - "append didn't append"); - { - let mut f = check!(File::open_mode(&tmpdir.join("h"), old_io::Truncate, - old_io::Write)); - check!(f.write("bar".as_bytes())); - } - assert!(check!(stat(&tmpdir.join("h"))).size == 3, - "truncate didn't truncate"); - } - - #[test] - fn utime() { - let tmpdir = tmpdir(); - let path = tmpdir.join("a"); - check!(File::create(&path)); - // These numbers have to be bigger than the time in the day to account - // for timezones Windows in particular will fail in certain timezones - // with small enough values - check!(change_file_times(&path, 100000, 200000)); - assert_eq!(check!(path.stat()).accessed, 100000); - assert_eq!(check!(path.stat()).modified, 200000); - } - - #[test] - fn utime_noexist() { - let tmpdir = tmpdir(); - - match change_file_times(&tmpdir.join("a"), 100, 200) { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[test] - fn binary_file() { - use rand::{StdRng, Rng}; - - let mut bytes = [0; 1024]; - StdRng::new().unwrap().fill_bytes(&mut bytes); - - let tmpdir = tmpdir(); - - check!(File::create(&tmpdir.join("test")).write(&bytes)); - let actual = check!(File::open(&tmpdir.join("test")).read_to_end()); - assert!(actual == &bytes[..]); - } - - #[test] - fn unlink_readonly() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(File::create(&path)); - check!(chmod(&path, old_io::USER_READ)); - check!(unlink(&path)); - } -} diff --git a/src/libstd/old_io/mem.rs b/src/libstd/old_io/mem.rs deleted file mode 100644 index c92e74fbc565e..0000000000000 --- a/src/libstd/old_io/mem.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - // 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 { - #[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 Writer implementation directly")] -#[derive(Clone)] -#[allow(deprecated)] -pub struct MemWriter { - buf: Vec, -} - -#[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) -> 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 { 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, - 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) -> 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 { self.buf } -} - -impl Reader for MemReader { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> IoResult { - 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 { 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 { - 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 { 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 { - 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 { 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 = 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]); - } - } - }); - } -} diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs deleted file mode 100644 index f62b1a836fd10..0000000000000 --- a/src/libstd/old_io/mod.rs +++ /dev/null @@ -1,1984 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// ignore-lexer-test FIXME #15883 - -// FIXME: cover these topics: -// path, reader, writer, stream, raii (close not needed), -// stdio, print!, println!, file access, process spawning, -// error handling - - -//! I/O, including files, networking, timers, and processes -//! -//! > **Warning**: This module is currently called `old_io` for a reason! The -//! > module is currently being redesigned in a number of RFCs. For more details -//! > follow the RFC repository in connection with [RFC 517][base] or follow -//! > some of these sub-RFCs -//! > -//! > * [String handling][osstr] -//! > * [Core I/O support][core] -//! > * [Deadlines][deadlines] -//! > * [std::env][env] -//! > * [std::process][process] -//! -//! [base]: https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md -//! [osstr]: https://github.com/rust-lang/rfcs/pull/575 -//! [core]: https://github.com/rust-lang/rfcs/pull/576 -//! [deadlines]: https://github.com/rust-lang/rfcs/pull/577 -//! [env]: https://github.com/rust-lang/rfcs/pull/578 -//! [process]: https://github.com/rust-lang/rfcs/pull/579 -//! -//! `std::io` provides Rust's basic I/O types, -//! for reading and writing to files, TCP, UDP, -//! and other types of sockets and pipes, -//! manipulating the file system, spawning processes. -//! -//! # Examples -//! -//! Some examples of obvious things you might want to do -//! -//! * Read lines from stdin -//! -//! ```rust -//! # #![feature(old_io)] -//! use std::old_io as io; -//! use std::old_io::*; -//! -//! let mut stdin = io::stdin(); -//! for line in stdin.lock().lines() { -//! print!("{}", line.unwrap()); -//! } -//! ``` -//! -//! * Read a complete file -//! -//! ```rust -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let contents = File::open(&Path::new("message.txt")).read_to_end(); -//! ``` -//! -//! * Write a line to a file -//! -//! ```rust -//! # #![feature(old_io, old_path)] -//! # #![allow(unused_must_use)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let mut file = File::create(&Path::new("message.txt")); -//! file.write_all(b"hello, file!\n"); -//! # drop(file); -//! # ::std::old_io::fs::unlink(&Path::new("message.txt")); -//! ``` -//! -//! * Iterate over the lines of a file -//! -//! ```rust,no_run -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let path = Path::new("message.txt"); -//! let mut file = BufferedReader::new(File::open(&path)); -//! for line in file.lines() { -//! print!("{}", line.unwrap()); -//! } -//! ``` -//! -//! * Pull the lines of a file into a vector of strings -//! -//! ```rust,no_run -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let path = Path::new("message.txt"); -//! let mut file = BufferedReader::new(File::open(&path)); -//! let lines: Vec = file.lines().map(|x| x.unwrap()).collect(); -//! ``` -//! -//! * Make a simple TCP client connection and request -//! -//! ```rust -//! # #![feature(old_io)] -//! # #![allow(unused_must_use)] -//! use std::old_io::*; -//! -//! # // connection doesn't fail if a server is running on 8080 -//! # // locally, we still want to be type checking this code, so lets -//! # // just stop it running (#11576) -//! # if false { -//! let mut socket = TcpStream::connect("127.0.0.1:8080").unwrap(); -//! socket.write_all(b"GET / HTTP/1.0\n\n"); -//! let response = socket.read_to_end(); -//! # } -//! ``` -//! -//! * Make a simple TCP server -//! -//! ```rust -//! # #![feature(old_io)] -//! # fn main() { } -//! # fn foo() { -//! # #![allow(dead_code)] -//! use std::old_io::*; -//! use std::thread; -//! -//! let listener = TcpListener::bind("127.0.0.1:80"); -//! -//! // bind the listener to the specified address -//! let mut acceptor = listener.listen(); -//! -//! fn handle_client(mut stream: TcpStream) { -//! // ... -//! # &mut stream; // silence unused mutability/variable warning -//! } -//! // accept connections and process them, spawning a new tasks for each one -//! for stream in acceptor.incoming() { -//! match stream { -//! Err(e) => { /* connection failed */ } -//! Ok(stream) => { -//! thread::spawn(move|| { -//! // connection succeeded -//! handle_client(stream) -//! }); -//! } -//! } -//! } -//! -//! // close the socket server -//! drop(acceptor); -//! # } -//! ``` -//! -//! -//! # Error Handling -//! -//! I/O is an area where nearly every operation can result in unexpected -//! errors. Errors should be painfully visible when they happen, and handling them -//! should be easy to work with. It should be convenient to handle specific I/O -//! errors, and it should also be convenient to not deal with I/O errors. -//! -//! Rust's I/O employs a combination of techniques to reduce boilerplate -//! while still providing feedback about errors. The basic strategy: -//! -//! * All I/O operations return `IoResult` which is equivalent to -//! `Result`. The `Result` type is defined in the `std::result` -//! module. -//! * If the `Result` type goes unused, then the compiler will by default emit a -//! warning about the unused result. This is because `Result` has the -//! `#[must_use]` attribute. -//! * Common traits are implemented for `IoResult`, e.g. -//! `impl Reader for IoResult`, so that error values do not have -//! to be 'unwrapped' before use. -//! -//! These features combine in the API to allow for expressions like -//! `File::create(&Path::new("diary.txt")).write_all(b"Met a girl.\n")` -//! without having to worry about whether "diary.txt" exists or whether -//! the write succeeds. As written, if either `new` or `write_line` -//! encounters an error then the result of the entire expression will -//! be an error. -//! -//! If you wanted to handle the error though you might write: -//! -//! ```rust -//! # #![feature(old_io, old_path)] -//! # #![allow(unused_must_use)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! match File::create(&Path::new("diary.txt")).write_all(b"Met a girl.\n") { -//! Ok(()) => (), // succeeded -//! Err(e) => println!("failed to write to my diary: {}", e), -//! } -//! -//! # ::std::old_io::fs::unlink(&Path::new("diary.txt")); -//! ``` -//! -//! So what actually happens if `create` encounters an error? -//! It's important to know that what `new` returns is not a `File` -//! but an `IoResult`. If the file does not open, then `new` will simply -//! return `Err(..)`. Because there is an implementation of `Writer` (the trait -//! required ultimately required for types to implement `write_line`) there is no -//! need to inspect or unwrap the `IoResult` and we simply call `write_line` -//! on it. If `new` returned an `Err(..)` then the followup call to `write_line` -//! will also return an error. -//! -//! ## `try!` -//! -//! Explicit pattern matching on `IoResult`s can get quite verbose, especially -//! when performing many I/O operations. Some examples (like those above) are -//! alleviated with extra methods implemented on `IoResult`, but others have more -//! complex interdependencies among each I/O operation. -//! -//! The `try!` macro from `std::macros` is provided as a method of early-return -//! inside `Result`-returning functions. It expands to an early-return on `Err` -//! and otherwise unwraps the contained `Ok` value. -//! -//! If you wanted to read several `u32`s from a file and return their product: -//! -//! ```rust -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! fn file_product(p: &Path) -> IoResult { -//! let mut f = File::open(p); -//! let x1 = try!(f.read_le_u32()); -//! let x2 = try!(f.read_le_u32()); -//! -//! Ok(x1 * x2) -//! } -//! -//! match file_product(&Path::new("numbers.bin")) { -//! Ok(x) => println!("{}", x), -//! Err(e) => println!("Failed to read numbers!") -//! } -//! ``` -//! -//! With `try!` in `file_product`, each `read_le_u32` need not be directly -//! concerned with error handling; instead its caller is responsible for -//! responding to errors that may occur while attempting to read the numbers. - -#![unstable(feature = "old_io")] -#![deny(unused_must_use)] -#![allow(deprecated)] // seriously this is all deprecated -#![allow(unused_imports)] -#![deprecated(since = "1.0.0", - reasons = "APIs have been replaced with new I/O modules such as \ - std::{io, fs, net, process}")] - -pub use self::SeekStyle::*; -pub use self::FileMode::*; -pub use self::FileAccess::*; -pub use self::IoErrorKind::*; - -use default::Default; -use error::Error; -use fmt; -use isize; -use iter::Iterator; -use marker::{PhantomFn, Sized}; -use mem::transmute; -use ops::FnOnce; -use option::Option; -use option::Option::{Some, None}; -use sys::os; -use boxed::Box; -use result::Result; -use result::Result::{Ok, Err}; -use sys; -use str; -use string::String; -use usize; -use unicode; -use vec::Vec; - -// Reexports -pub use self::stdio::stdin; -pub use self::stdio::stdout; -pub use self::stdio::stderr; -pub use self::stdio::print; -pub use self::stdio::println; - -pub use self::fs::File; -pub use self::timer::Timer; -pub use self::net::ip::IpAddr; -pub use self::net::tcp::TcpListener; -pub use self::net::tcp::TcpStream; -pub use self::pipe::PipeStream; -pub use self::process::{Process, Command}; -pub use self::tempfile::TempDir; - -pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter}; -pub use self::buffered::{BufferedReader, BufferedWriter, BufferedStream, - LineBufferedWriter}; -pub use self::comm_adapters::{ChanReader, ChanWriter}; - -mod buffered; -mod comm_adapters; -mod mem; -mod result; -mod tempfile; -pub mod extensions; -pub mod fs; -pub mod net; -pub mod pipe; -pub mod process; -pub mod stdio; -pub mod timer; -pub mod util; - -#[macro_use] -pub mod test; - -/// The default buffer size for various I/O operations -// libuv recommends 64k buffers to maximize throughput -// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA -const DEFAULT_BUF_SIZE: usize = 1024 * 64; - -/// A convenient typedef of the return value of any I/O action. -pub type IoResult = Result; - -/// The type passed to I/O condition handlers to indicate error -/// -/// # FIXME -/// -/// Is something like this sufficient? It's kind of archaic -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct IoError { - /// An enumeration which can be matched against for determining the flavor - /// of error. - pub kind: IoErrorKind, - /// A human-readable description about the error - pub desc: &'static str, - /// Detailed information about this error, not always available - pub detail: Option -} - -impl IoError { - /// Convert an `errno` value into an `IoError`. - /// - /// If `detail` is `true`, the `detail` field of the `IoError` - /// struct is filled with an allocated string describing the error - /// in more detail, retrieved from the operating system. - pub fn from_errno(errno: i32, detail: bool) -> IoError { - let mut err = sys::decode_error(errno as i32); - if detail && err.kind == OtherIoError { - err.detail = Some(os::error_string(errno).to_lowercase()); - } - err - } - - /// Retrieve the last error to occur as a (detailed) IoError. - /// - /// This uses the OS `errno`, and so there should not be any task - /// descheduling or migration (other than that performed by the - /// operating system) between the call(s) for which errors are - /// being checked and the call of this function. - pub fn last_error() -> IoError { - IoError::from_errno(os::errno(), true) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for IoError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - IoError { kind: OtherIoError, desc: "unknown error", detail: Some(ref detail) } => - write!(fmt, "{}", detail), - IoError { detail: None, desc, .. } => - write!(fmt, "{}", desc), - IoError { detail: Some(ref detail), desc, .. } => - write!(fmt, "{} ({})", desc, detail) - } - } -} - -impl Error for IoError { - fn description(&self) -> &str { self.desc } -} - -/// A list specifying general categories of I/O error. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum IoErrorKind { - /// Any I/O error not part of this list. - OtherIoError, - /// The operation could not complete because end of file was reached. - EndOfFile, - /// The file was not found. - FileNotFound, - /// The file permissions disallowed access to this file. - PermissionDenied, - /// A network connection failed for some reason not specified in this list. - ConnectionFailed, - /// The network operation failed because the network connection was closed. - Closed, - /// The connection was refused by the remote server. - ConnectionRefused, - /// The connection was reset by the remote server. - ConnectionReset, - /// The connection was aborted (terminated) by the remote server. - ConnectionAborted, - /// The network operation failed because it was not connected yet. - NotConnected, - /// The operation failed because a pipe was closed. - BrokenPipe, - /// A file already existed with that name. - PathAlreadyExists, - /// No file exists at that location. - PathDoesntExist, - /// The path did not specify the type of file that this operation required. For example, - /// attempting to copy a directory with the `fs::copy()` operation will fail with this error. - MismatchedFileTypeForOperation, - /// The operation temporarily failed (for example, because a signal was received), and retrying - /// may succeed. - ResourceUnavailable, - /// No I/O functionality is available for this task. - IoUnavailable, - /// A parameter was incorrect in a way that caused an I/O error not part of this list. - InvalidInput, - /// The I/O operation's timeout expired, causing it to be canceled. - TimedOut, - /// This write operation failed to write all of its data. - /// - /// Normally the write() method on a Writer guarantees that all of its data - /// has been written, but some operations may be terminated after only - /// partially writing some data. An example of this is a timed out write - /// which successfully wrote a known number of bytes, but bailed out after - /// doing so. - /// - /// The payload contained as part of this variant is the number of bytes - /// which are known to have been successfully written. - ShortWrite(usize), - /// The Reader returned 0 bytes from `read()` too many times. - NoProgress, -} - -/// A trait that lets you add a `detail` to an IoError easily -trait UpdateIoError { - /// Returns an IoError with updated description and detail - fn update_err(self, desc: &'static str, detail: D) -> Self where - D: FnOnce(&IoError) -> String; - - /// Returns an IoError with updated detail - fn update_detail(self, detail: D) -> Self where - D: FnOnce(&IoError) -> String; - - /// Returns an IoError with update description - fn update_desc(self, desc: &'static str) -> Self; -} - -impl UpdateIoError for IoResult { - fn update_err(self, desc: &'static str, detail: D) -> IoResult where - D: FnOnce(&IoError) -> String, - { - self.map_err(move |mut e| { - let detail = detail(&e); - e.desc = desc; - e.detail = Some(detail); - e - }) - } - - fn update_detail(self, detail: D) -> IoResult where - D: FnOnce(&IoError) -> String, - { - self.map_err(move |mut e| { e.detail = Some(detail(&e)); e }) - } - - fn update_desc(self, desc: &'static str) -> IoResult { - self.map_err(|mut e| { e.desc = desc; e }) - } -} - -static NO_PROGRESS_LIMIT: usize = 1000; - -/// A trait for objects which are byte-oriented streams. Readers are defined by -/// one method, `read`. This function will block until data is available, -/// filling in the provided buffer with any data read. -/// -/// Readers are intended to be composable with one another. Many objects -/// throughout the I/O and related libraries take and provide types which -/// implement the `Reader` trait. -pub trait Reader { - - // Only method which need to get implemented for this trait - - /// Read bytes, up to the length of `buf` and place them in `buf`. - /// Returns the number of bytes read. The number of bytes read may - /// be less than the number requested, even 0. Returns `Err` on EOF. - /// - /// # Error - /// - /// If an error occurs during this I/O operation, then it is returned as - /// `Err(IoError)`. Note that end-of-file is considered an error, and can be - /// inspected for in the error's `kind` field. Also note that reading 0 - /// bytes is not considered an error in all circumstances - /// - /// # Implementation Note - /// - /// When implementing this method on a new Reader, you are strongly encouraged - /// not to return 0 if you can avoid it. - fn read(&mut self, buf: &mut [u8]) -> IoResult; - - // Convenient helper methods based on the above methods - - /// Reads at least `min` bytes and places them in `buf`. - /// Returns the number of bytes read. - /// - /// This will continue to call `read` until at least `min` bytes have been - /// read. If `read` returns 0 too many times, `NoProgress` will be - /// returned. - /// - /// # Error - /// - /// If an error occurs at any point, that error is returned, and no further - /// bytes are read. - fn read_at_least(&mut self, min: usize, buf: &mut [u8]) -> IoResult { - if min > buf.len() { - return Err(IoError { - detail: Some(String::from_str("the buffer is too short")), - ..standard_error(InvalidInput) - }); - } - let mut read = 0; - while read < min { - let mut zeroes = 0; - loop { - match self.read(&mut buf[read..]) { - Ok(0) => { - zeroes += 1; - if zeroes >= NO_PROGRESS_LIMIT { - return Err(standard_error(NoProgress)); - } - } - Ok(n) => { - read += n; - break; - } - err@Err(_) => return err - } - } - } - Ok(read) - } - - /// Reads a single byte. Returns `Err` on EOF. - fn read_byte(&mut self) -> IoResult { - let mut buf = [0]; - try!(self.read_at_least(1, &mut buf)); - Ok(buf[0]) - } - - /// Reads up to `len` bytes and appends them to a vector. - /// Returns the number of bytes read. The number of bytes read may be - /// less than the number requested, even 0. Returns Err on EOF. - /// - /// # Error - /// - /// If an error occurs during this I/O operation, then it is returned - /// as `Err(IoError)`. See `read()` for more details. - fn push(&mut self, len: usize, buf: &mut Vec) -> IoResult { - let start_len = buf.len(); - buf.reserve(len); - - let n = { - let s = unsafe { slice_vec_capacity(buf, start_len, start_len + len) }; - try!(self.read(s)) - }; - unsafe { buf.set_len(start_len + n) }; - Ok(n) - } - - /// Reads at least `min` bytes, but no more than `len`, and appends them to - /// a vector. - /// Returns the number of bytes read. - /// - /// This will continue to call `read` until at least `min` bytes have been - /// read. If `read` returns 0 too many times, `NoProgress` will be - /// returned. - /// - /// # Error - /// - /// If an error occurs at any point, that error is returned, and no further - /// bytes are read. - fn push_at_least(&mut self, min: usize, len: usize, buf: &mut Vec) -> IoResult { - if min > len { - return Err(IoError { - detail: Some(String::from_str("the buffer is too short")), - ..standard_error(InvalidInput) - }); - } - - let start_len = buf.len(); - buf.reserve(len); - - // we can't just use self.read_at_least(min, slice) because we need to push - // successful reads onto the vector before any returned errors. - - let mut read = 0; - while read < min { - read += { - let s = unsafe { slice_vec_capacity(buf, start_len + read, start_len + len) }; - try!(self.read_at_least(1, s)) - }; - unsafe { buf.set_len(start_len + read) }; - } - Ok(read) - } - - /// Reads exactly `len` bytes and gives you back a new vector of length - /// `len` - /// - /// # Error - /// - /// Fails with the same conditions as `read`. Additionally returns error - /// on EOF. Note that if an error is returned, then some number of bytes may - /// have already been consumed from the underlying reader, and they are lost - /// (not returned as part of the error). If this is unacceptable, then it is - /// recommended to use the `push_at_least` or `read` methods. - fn read_exact(&mut self, len: usize) -> IoResult> { - let mut buf = Vec::with_capacity(len); - match self.push_at_least(len, len, &mut buf) { - Ok(_) => Ok(buf), - Err(e) => Err(e), - } - } - - /// Reads all remaining bytes from the stream. - /// - /// # Error - /// - /// Returns any non-EOF error immediately. Previously read bytes are - /// discarded when an error is returned. - /// - /// When EOF is encountered, all bytes read up to that point are returned. - fn read_to_end(&mut self) -> IoResult> { - let mut buf = Vec::with_capacity(DEFAULT_BUF_SIZE); - loop { - match self.push_at_least(1, DEFAULT_BUF_SIZE, &mut buf) { - Ok(_) => {} - Err(ref e) if e.kind == EndOfFile => break, - Err(e) => return Err(e) - } - } - return Ok(buf); - } - - /// Reads all of the remaining bytes of this stream, interpreting them as a - /// UTF-8 encoded stream. The corresponding string is returned. - /// - /// # Error - /// - /// This function returns all of the same errors as `read_to_end` with an - /// additional error if the reader's contents are not a valid sequence of - /// UTF-8 bytes. - fn read_to_string(&mut self) -> IoResult { - self.read_to_end().and_then(|s| { - match String::from_utf8(s) { - Ok(s) => Ok(s), - Err(_) => Err(standard_error(InvalidInput)), - } - }) - } - - // Byte conversion helpers - - /// Reads `n` little-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_uint_n(&mut self, nbytes: usize) -> IoResult { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0; - let mut pos = 0; - let mut i = nbytes; - while i > 0 { - val += (try!(self.read_u8()) as u64) << pos; - pos += 8; - i -= 1; - } - Ok(val) - } - - /// Reads `n` little-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_int_n(&mut self, nbytes: usize) -> IoResult { - self.read_le_uint_n(nbytes).map(|i| extend_sign(i, nbytes)) - } - - /// Reads `n` big-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_uint_n(&mut self, nbytes: usize) -> IoResult { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0; - let mut i = nbytes; - while i > 0 { - i -= 1; - val += (try!(self.read_u8()) as u64) << i * 8; - } - Ok(val) - } - - /// Reads `n` big-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_int_n(&mut self, nbytes: usize) -> IoResult { - self.read_be_uint_n(nbytes).map(|i| extend_sign(i, nbytes)) - } - - /// Reads a little-endian unsigned integer. - /// - /// The number of bytes returned is system-dependent. - fn read_le_uint(&mut self) -> IoResult { - self.read_le_uint_n(usize::BYTES).map(|i| i as usize) - } - - /// Reads a little-endian integer. - /// - /// The number of bytes returned is system-dependent. - fn read_le_int(&mut self) -> IoResult { - self.read_le_int_n(isize::BYTES).map(|i| i as isize) - } - - /// Reads a big-endian unsigned integer. - /// - /// The number of bytes returned is system-dependent. - fn read_be_uint(&mut self) -> IoResult { - self.read_be_uint_n(usize::BYTES).map(|i| i as usize) - } - - /// Reads a big-endian integer. - /// - /// The number of bytes returned is system-dependent. - fn read_be_int(&mut self) -> IoResult { - self.read_be_int_n(isize::BYTES).map(|i| i as isize) - } - - /// Reads a big-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_be_u64(&mut self) -> IoResult { - self.read_be_uint_n(8) - } - - /// Reads a big-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_be_u32(&mut self) -> IoResult { - self.read_be_uint_n(4).map(|i| i as u32) - } - - /// Reads a big-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_be_u16(&mut self) -> IoResult { - self.read_be_uint_n(2).map(|i| i as u16) - } - - /// Reads a big-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_be_i64(&mut self) -> IoResult { - self.read_be_int_n(8) - } - - /// Reads a big-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_be_i32(&mut self) -> IoResult { - self.read_be_int_n(4).map(|i| i as i32) - } - - /// Reads a big-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_be_i16(&mut self) -> IoResult { - self.read_be_int_n(2).map(|i| i as i16) - } - - /// Reads a big-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_be_f64(&mut self) -> IoResult { - self.read_be_u64().map(|i| unsafe { - transmute::(i) - }) - } - - /// Reads a big-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_be_f32(&mut self) -> IoResult { - self.read_be_u32().map(|i| unsafe { - transmute::(i) - }) - } - - /// Reads a little-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_le_u64(&mut self) -> IoResult { - self.read_le_uint_n(8) - } - - /// Reads a little-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_le_u32(&mut self) -> IoResult { - self.read_le_uint_n(4).map(|i| i as u32) - } - - /// Reads a little-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_le_u16(&mut self) -> IoResult { - self.read_le_uint_n(2).map(|i| i as u16) - } - - /// Reads a little-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_le_i64(&mut self) -> IoResult { - self.read_le_int_n(8) - } - - /// Reads a little-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_le_i32(&mut self) -> IoResult { - self.read_le_int_n(4).map(|i| i as i32) - } - - /// Reads a little-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_le_i16(&mut self) -> IoResult { - self.read_le_int_n(2).map(|i| i as i16) - } - - /// Reads a little-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_le_f64(&mut self) -> IoResult { - self.read_le_u64().map(|i| unsafe { - transmute::(i) - }) - } - - /// Reads a little-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_le_f32(&mut self) -> IoResult { - self.read_le_u32().map(|i| unsafe { - transmute::(i) - }) - } - - /// Read a u8. - /// - /// `u8`s are 1 byte. - fn read_u8(&mut self) -> IoResult { - self.read_byte() - } - - /// Read an i8. - /// - /// `i8`s are 1 byte. - fn read_i8(&mut self) -> IoResult { - self.read_byte().map(|i| i as i8) - } -} - -/// A reader which can be converted to a RefReader. -pub trait ByRefReader { - /// Creates a wrapper around a mutable reference to the reader. - /// - /// This is useful to allow applying adaptors while still - /// retaining ownership of the original value. - fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self>; -} - -impl ByRefReader for T { - fn by_ref<'a>(&'a mut self) -> RefReader<'a, T> { - RefReader { inner: self } - } -} - -/// A reader which can be converted to bytes. -pub trait BytesReader { - /// Create an iterator that reads a single byte on - /// each iteration, until EOF. - /// - /// # 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. - fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self>; -} - -impl BytesReader for T { - fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, T> { - extensions::Bytes::new(self) - } -} - -impl<'a> Reader for Box { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let reader: &mut Reader = &mut **self; - reader.read(buf) - } -} - -impl<'a> Reader for &'a mut (Reader+'a) { - fn read(&mut self, buf: &mut [u8]) -> IoResult { (*self).read(buf) } -} - -/// Returns a slice of `v` between `start` and `end`. -/// -/// Similar to `slice()` except this function only bounds the slice on the -/// capacity of `v`, not the length. -/// -/// # Panics -/// -/// Panics when `start` or `end` point outside the capacity of `v`, or when -/// `start` > `end`. -// Private function here because we aren't sure if we want to expose this as -// API yet. If so, it should be a method on Vec. -unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec, start: usize, end: usize) -> &'a mut [T] { - use slice; - - assert!(start <= end); - assert!(end <= v.capacity()); - slice::from_raw_parts_mut( - v.as_mut_ptr().offset(start as isize), - end - start - ) -} - -/// A `RefReader` is a struct implementing `Reader` which contains a reference -/// to another reader. This is often useful when composing streams. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// use std::old_io as io; -/// use std::old_io::*; -/// use std::old_io::util::LimitReader; -/// -/// fn process_input(r: R) {} -/// -/// let mut stream = io::stdin(); -/// -/// // Only allow the function to process at most one kilobyte of input -/// { -/// let stream = LimitReader::new(stream.by_ref(), 1024); -/// process_input(stream); -/// } -/// -/// // 'stream' is still available for use here -/// ``` -pub struct RefReader<'a, R:'a> { - /// The underlying reader which this is referencing - inner: &'a mut R -} - -impl<'a, R: Reader> Reader for RefReader<'a, R> { - fn read(&mut self, buf: &mut [u8]) -> IoResult { self.inner.read(buf) } -} - -impl<'a, R: Buffer> Buffer for RefReader<'a, R> { - fn fill_buf(&mut self) -> IoResult<&[u8]> { self.inner.fill_buf() } - fn consume(&mut self, amt: usize) { self.inner.consume(amt) } -} - -fn extend_sign(val: u64, nbytes: usize) -> i64 { - let shift = (8 - nbytes) * 8; - (val << shift) as i64 >> shift -} - -/// A trait for objects which are byte-oriented streams. Writers are defined by -/// one method, `write`. This function will block until the provided buffer of -/// bytes has been entirely written, and it will return any failures which occur. -/// -/// Another commonly overridden method is the `flush` method for writers such as -/// buffered writers. -/// -/// Writers are intended to be composable with one another. Many objects -/// throughout the I/O and related libraries take and provide types which -/// implement the `Writer` trait. -pub trait Writer { - /// Write the entirety of a given buffer - /// - /// # Errors - /// - /// If an error happens during the I/O operation, the error is returned as - /// `Err`. Note that it is considered an error if the entire buffer could - /// not be written, and if an error is returned then it is unknown how much - /// data (if any) was actually written. - fn write_all(&mut self, buf: &[u8]) -> IoResult<()>; - - /// Deprecated, this method was renamed to `write_all` - #[unstable(feature = "io")] - #[deprecated(since = "1.0.0", reason = "renamed to `write_all`")] - fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write_all(buf) } - - /// Flush this output stream, ensuring that all intermediately buffered - /// contents reach their destination. - /// - /// This is by default a no-op and implementers of the `Writer` trait should - /// decide whether their stream needs to be buffered or not. - fn flush(&mut self) -> IoResult<()> { Ok(()) } - - /// Writes a formatted string into this writer, returning any error - /// encountered. - /// - /// This method is primarily used to interface with the `format_args!` - /// macro, but it is rare that this should explicitly be called. The - /// `write!` macro should be favored to invoke this method instead. - /// - /// # Errors - /// - /// This function will return any I/O error reported while formatting. - fn write_fmt(&mut self, fmt: fmt::Arguments) -> IoResult<()> { - // Create a shim which translates a Writer to a fmt::Write and saves - // off I/O errors. instead of discarding them - struct Adaptor<'a, T: ?Sized +'a> { - inner: &'a mut T, - error: IoResult<()>, - } - - impl<'a, T: ?Sized + Writer> fmt::Write for Adaptor<'a, T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.inner.write_all(s.as_bytes()) { - Ok(()) => Ok(()), - Err(e) => { - self.error = Err(e); - Err(fmt::Error) - } - } - } - } - - let mut output = Adaptor { inner: self, error: Ok(()) }; - match fmt::write(&mut output, fmt) { - Ok(()) => Ok(()), - Err(..) => output.error - } - } - - - /// Write a rust string into this sink. - /// - /// The bytes written will be the UTF-8 encoded version of the input string. - /// If other encodings are desired, it is recommended to compose this stream - /// with another performing the conversion, or to use `write` with a - /// converted byte-array instead. - #[inline] - fn write_str(&mut self, s: &str) -> IoResult<()> { - self.write_all(s.as_bytes()) - } - - /// Writes a string into this sink, and then writes a literal newline (`\n`) - /// byte afterwards. Note that the writing of the newline is *not* atomic in - /// the sense that the call to `write` is invoked twice (once with the - /// string and once with a newline character). - /// - /// If other encodings or line ending flavors are desired, it is recommended - /// that the `write` method is used specifically instead. - #[inline] - fn write_line(&mut self, s: &str) -> IoResult<()> { - self.write_str(s).and_then(|()| self.write_all(&[b'\n'])) - } - - /// Write a single char, encoded as UTF-8. - #[inline] - fn write_char(&mut self, c: char) -> IoResult<()> { - let mut buf = [0; 4]; - let n = c.encode_utf8(&mut buf).unwrap_or(0); - self.write_all(&buf[..n]) - } - - /// Write the result of passing n through `isize::to_str_bytes`. - #[inline] - fn write_int(&mut self, n: isize) -> IoResult<()> { - write!(self, "{}", n) - } - - /// Write the result of passing n through `usize::to_str_bytes`. - #[inline] - fn write_uint(&mut self, n: usize) -> IoResult<()> { - write!(self, "{}", n) - } - - /// Write a little-endian usize (number of bytes depends on system). - #[inline] - fn write_le_uint(&mut self, n: usize) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, usize::BYTES, |v| self.write_all(v)) - } - - /// Write a little-endian isize (number of bytes depends on system). - #[inline] - fn write_le_int(&mut self, n: isize) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, isize::BYTES, |v| self.write_all(v)) - } - - /// Write a big-endian usize (number of bytes depends on system). - #[inline] - fn write_be_uint(&mut self, n: usize) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, usize::BYTES, |v| self.write_all(v)) - } - - /// Write a big-endian isize (number of bytes depends on system). - #[inline] - fn write_be_int(&mut self, n: isize) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, isize::BYTES, |v| self.write_all(v)) - } - - /// Write a big-endian u64 (8 bytes). - #[inline] - fn write_be_u64(&mut self, n: u64) -> IoResult<()> { - extensions::u64_to_be_bytes(n, 8, |v| self.write_all(v)) - } - - /// Write a big-endian u32 (4 bytes). - #[inline] - fn write_be_u32(&mut self, n: u32) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 4, |v| self.write_all(v)) - } - - /// Write a big-endian u16 (2 bytes). - #[inline] - fn write_be_u16(&mut self, n: u16) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 2, |v| self.write_all(v)) - } - - /// Write a big-endian i64 (8 bytes). - #[inline] - fn write_be_i64(&mut self, n: i64) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 8, |v| self.write_all(v)) - } - - /// Write a big-endian i32 (4 bytes). - #[inline] - fn write_be_i32(&mut self, n: i32) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 4, |v| self.write_all(v)) - } - - /// Write a big-endian i16 (2 bytes). - #[inline] - fn write_be_i16(&mut self, n: i16) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 2, |v| self.write_all(v)) - } - - /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - #[inline] - fn write_be_f64(&mut self, f: f64) -> IoResult<()> { - unsafe { - self.write_be_u64(transmute(f)) - } - } - - /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - #[inline] - fn write_be_f32(&mut self, f: f32) -> IoResult<()> { - unsafe { - self.write_be_u32(transmute(f)) - } - } - - /// Write a little-endian u64 (8 bytes). - #[inline] - fn write_le_u64(&mut self, n: u64) -> IoResult<()> { - extensions::u64_to_le_bytes(n, 8, |v| self.write_all(v)) - } - - /// Write a little-endian u32 (4 bytes). - #[inline] - fn write_le_u32(&mut self, n: u32) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 4, |v| self.write_all(v)) - } - - /// Write a little-endian u16 (2 bytes). - #[inline] - fn write_le_u16(&mut self, n: u16) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 2, |v| self.write_all(v)) - } - - /// Write a little-endian i64 (8 bytes). - #[inline] - fn write_le_i64(&mut self, n: i64) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 8, |v| self.write_all(v)) - } - - /// Write a little-endian i32 (4 bytes). - #[inline] - fn write_le_i32(&mut self, n: i32) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 4, |v| self.write_all(v)) - } - - /// Write a little-endian i16 (2 bytes). - #[inline] - fn write_le_i16(&mut self, n: i16) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 2, |v| self.write_all(v)) - } - - /// Write a little-endian IEEE754 double-precision floating-point - /// (8 bytes). - #[inline] - fn write_le_f64(&mut self, f: f64) -> IoResult<()> { - unsafe { - self.write_le_u64(transmute(f)) - } - } - - /// Write a little-endian IEEE754 single-precision floating-point - /// (4 bytes). - #[inline] - fn write_le_f32(&mut self, f: f32) -> IoResult<()> { - unsafe { - self.write_le_u32(transmute(f)) - } - } - - /// Write a u8 (1 byte). - #[inline] - fn write_u8(&mut self, n: u8) -> IoResult<()> { - self.write_all(&[n]) - } - - /// Write an i8 (1 byte). - #[inline] - fn write_i8(&mut self, n: i8) -> IoResult<()> { - self.write_all(&[n as u8]) - } -} - -/// A writer which can be converted to a RefWriter. -pub trait ByRefWriter { - /// Creates a wrapper around a mutable reference to the writer. - /// - /// This is useful to allow applying wrappers while still - /// retaining ownership of the original value. - #[inline] - fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self>; -} - -impl ByRefWriter for T { - fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { - RefWriter { inner: self } - } -} - -impl<'a> Writer for Box { - #[inline] - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - (&mut **self).write_all(buf) - } - - #[inline] - fn flush(&mut self) -> IoResult<()> { - (&mut **self).flush() - } -} - -impl<'a> Writer for &'a mut (Writer+'a) { - #[inline] - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { (**self).write_all(buf) } - - #[inline] - fn flush(&mut self) -> IoResult<()> { (**self).flush() } -} - -/// A `RefWriter` is a struct implementing `Writer` which contains a reference -/// to another writer. This is often useful when composing streams. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// use std::old_io::util::TeeReader; -/// use std::old_io::*; -/// -/// fn process_input(r: R) {} -/// -/// let mut output = Vec::new(); -/// -/// { -/// // Don't give ownership of 'output' to the 'tee'. Instead we keep a -/// // handle to it in the outer scope -/// let mut tee = TeeReader::new(stdin(), output.by_ref()); -/// process_input(tee); -/// } -/// -/// println!("input processed: {:?}", output); -/// ``` -pub struct RefWriter<'a, W:'a> { - /// The underlying writer which this is referencing - inner: &'a mut W -} - -impl<'a, W: Writer> Writer for RefWriter<'a, W> { - #[inline] - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write_all(buf) } - - #[inline] - fn flush(&mut self) -> IoResult<()> { self.inner.flush() } -} - - -/// A Stream is a readable and a writable object. Data written is typically -/// received by the object which reads receive data from. -pub trait Stream: Reader + Writer { } - -impl Stream for T {} - -/// An iterator that reads a line on each iteration, -/// until `.read_line()` encounters `EndOfFile`. -/// -/// # Notes about the Iteration Protocol -/// -/// The `Lines` 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 Lines<'r, T:'r> { - buffer: &'r mut T, -} - -impl<'r, T: Buffer> Iterator for Lines<'r, T> { - type Item = IoResult; - - fn next(&mut self) -> Option> { - match self.buffer.read_line() { - Ok(x) => Some(Ok(x)), - Err(IoError { kind: EndOfFile, ..}) => None, - Err(y) => Some(Err(y)) - } - } -} - -/// An iterator that reads a utf8-encoded character on each iteration, -/// until `.read_char()` encounters `EndOfFile`. -/// -/// # Notes about the Iteration Protocol -/// -/// The `Chars` 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 Chars<'r, T:'r> { - buffer: &'r mut T -} - -impl<'r, T: Buffer> Iterator for Chars<'r, T> { - type Item = IoResult; - - fn next(&mut self) -> Option> { - match self.buffer.read_char() { - Ok(x) => Some(Ok(x)), - Err(IoError { kind: EndOfFile, ..}) => None, - Err(y) => Some(Err(y)) - } - } -} - -/// A Buffer is a type of reader which has some form of internal buffering to -/// allow certain kinds of reading operations to be more optimized than others. -/// This type extends the `Reader` trait with a few methods that are not -/// possible to reasonably implement with purely a read interface. -pub trait Buffer: Reader { - /// Fills the internal buffer of this object, returning the buffer contents. - /// Note that none of the contents will be "read" in the sense that later - /// calling `read` may return the same contents. - /// - /// The `consume` function must be called with the number of bytes that are - /// consumed from this buffer returned to ensure that the bytes are never - /// returned twice. - /// - /// # Error - /// - /// This function will return an I/O error if the underlying reader was - /// read, but returned an error. Note that it is not an error to return a - /// 0-length buffer. - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]>; - - /// Tells this buffer that `amt` bytes have been consumed from the buffer, - /// so they should no longer be returned in calls to `read`. - fn consume(&mut self, amt: usize); - - /// Reads the next line of input, interpreted as a sequence of UTF-8 - /// encoded Unicode codepoints. If a newline is encountered, then the - /// newline is contained in the returned string. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io)] - /// use std::old_io::*; - /// - /// let mut reader = BufReader::new(b"hello\nworld"); - /// assert_eq!("hello\n", &*reader.read_line().unwrap()); - /// ``` - /// - /// # Error - /// - /// This function has the same error semantics as `read_until`: - /// - /// * All non-EOF errors will be returned immediately - /// * If an error is returned previously consumed bytes are lost - /// * EOF is only returned if no bytes have been read - /// * Reach EOF may mean that the delimiter is not present in the return - /// value - /// - /// Additionally, this function can fail if the line of input read is not a - /// valid UTF-8 sequence of bytes. - fn read_line(&mut self) -> IoResult { - self.read_until(b'\n').and_then(|line| - match String::from_utf8(line) { - Ok(s) => Ok(s), - Err(_) => Err(standard_error(InvalidInput)), - } - ) - } - - /// Reads a sequence of bytes leading up to a specified delimiter. Once the - /// specified byte is encountered, reading ceases and the bytes up to and - /// including the delimiter are returned. - /// - /// # Error - /// - /// If any I/O error is encountered other than EOF, the error is immediately - /// returned. Note that this may discard bytes which have already been read, - /// and those bytes will *not* be returned. It is recommended to use other - /// methods if this case is worrying. - /// - /// If EOF is encountered, then this function will return EOF if 0 bytes - /// have been read, otherwise the pending byte buffer is returned. This - /// is the reason that the byte buffer returned may not always contain the - /// delimiter. - fn read_until(&mut self, byte: u8) -> IoResult> { - let mut res = Vec::new(); - - loop { - let (done, used) = { - let available = match self.fill_buf() { - Ok(n) => n, - Err(ref e) if res.len() > 0 && e.kind == EndOfFile => { - return Ok(res); - } - Err(e) => return Err(e) - }; - match available.iter().position(|&b| b == byte) { - Some(i) => { - res.push_all(&available[..i + 1]); - (true, i + 1) - } - None => { - res.push_all(available); - (false, available.len()) - } - } - }; - self.consume(used); - if done { - return Ok(res); - } - } - } - - /// Reads the next utf8-encoded character from the underlying stream. - /// - /// # Error - /// - /// If an I/O error occurs, or EOF, then this function will return `Err`. - /// This function will also return error if the stream does not contain a - /// valid utf-8 encoded codepoint as the next few bytes in the stream. - fn read_char(&mut self) -> IoResult { - let first_byte = try!(self.read_byte()); - let width = unicode::str::utf8_char_width(first_byte); - if width == 1 { return Ok(first_byte as char) } - if width == 0 { return Err(standard_error(InvalidInput)) } // not utf8 - let mut buf = [first_byte, 0, 0, 0]; - { - let mut start = 1; - while start < width { - match try!(self.read(&mut buf[start .. width])) { - n if n == width - start => break, - n if n < width - start => { start += n; } - _ => return Err(standard_error(InvalidInput)), - } - } - } - match str::from_utf8(&buf[..width]).ok() { - Some(s) => Ok(s.char_at(0)), - None => Err(standard_error(InvalidInput)) - } - } -} - -/// Extension methods for the Buffer trait which are included in the prelude. -pub trait BufferPrelude { - /// Create an iterator that reads a utf8-encoded character on each iteration - /// until EOF. - /// - /// # 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. - fn chars<'r>(&'r mut self) -> Chars<'r, Self>; - - /// Create an iterator that reads a line on each iteration until EOF. - /// - /// # 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. - fn lines<'r>(&'r mut self) -> Lines<'r, Self>; -} - -impl BufferPrelude for T { - fn chars<'r>(&'r mut self) -> Chars<'r, T> { - Chars { buffer: self } - } - - fn lines<'r>(&'r mut self) -> Lines<'r, T> { - Lines { buffer: self } - } -} - -/// When seeking, the resulting cursor is offset from a base by the offset given -/// to the `seek` function. The base used is specified by this enumeration. -#[derive(Copy, Clone)] -pub enum SeekStyle { - /// Seek from the beginning of the stream - SeekSet, - /// Seek from the end of the stream - SeekEnd, - /// Seek from the current position - SeekCur, -} - -/// An object implementing `Seek` internally has some form of cursor which can -/// be moved within a stream of bytes. The stream typically has a fixed size, -/// allowing seeking relative to either end. -pub trait Seek { - /// Return position of file cursor in the stream - fn tell(&self) -> IoResult; - - /// Seek to an offset in a stream - /// - /// A successful seek clears the EOF indicator. Seeking beyond EOF is - /// allowed, but seeking before position 0 is not allowed. - /// - /// # Errors - /// - /// * Seeking to a negative offset is considered an error - /// * Seeking past the end of the stream does not modify the underlying - /// stream, but the next write may cause the previous data to be filled in - /// with a bit pattern. - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>; -} - -/// A listener is a value that can consume itself to start listening for -/// connections. -/// -/// Doing so produces some sort of Acceptor. -pub trait Listener { - /// Spin up the listener and start queuing incoming connections - /// - /// # Error - /// - /// Returns `Err` if this listener could not be bound to listen for - /// connections. In all cases, this listener is consumed. - fn listen(self) -> IoResult; -} - -/// An acceptor is a value that presents incoming connections -pub trait Acceptor { - /// Type of connection that is accepted by this acceptor. - type Connection; - - /// Wait for and accept an incoming connection - /// - /// # Error - /// - /// Returns `Err` if an I/O error is encountered. - fn accept(&mut self) -> IoResult; - - /// Create an iterator over incoming connection attempts. - /// - /// Note that I/O errors will be yielded by the iterator itself. - fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> { - IncomingConnections { inc: self } - } -} - -/// An infinite iterator over incoming connection attempts. -/// Calling `next` will block the task until a connection is attempted. -/// -/// Since connection attempts can continue forever, this iterator always returns -/// `Some`. The `Some` contains the `IoResult` representing whether the -/// connection attempt was successful. A successful connection will be wrapped -/// in `Ok`. A failed connection is represented as an `Err`. -pub struct IncomingConnections<'a, A: ?Sized +'a> { - inc: &'a mut A, -} - -impl<'a, A: ?Sized + Acceptor> Iterator for IncomingConnections<'a, A> { - type Item = IoResult; - - fn next(&mut self) -> Option> { - Some(self.inc.accept()) - } -} - -/// Creates a standard error for a commonly used flavor of error. The `detail` -/// field of the returned error will always be `None`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// use std::old_io as io; -/// -/// let eof = io::standard_error(io::EndOfFile); -/// let einval = io::standard_error(io::InvalidInput); -/// ``` -pub fn standard_error(kind: IoErrorKind) -> IoError { - let desc = match kind { - EndOfFile => "end of file", - IoUnavailable => "I/O is unavailable", - InvalidInput => "invalid input", - OtherIoError => "unknown I/O error", - FileNotFound => "file not found", - PermissionDenied => "permission denied", - ConnectionFailed => "connection failed", - Closed => "stream is closed", - ConnectionRefused => "connection refused", - ConnectionReset => "connection reset", - ConnectionAborted => "connection aborted", - NotConnected => "not connected", - BrokenPipe => "broken pipe", - PathAlreadyExists => "file already exists", - PathDoesntExist => "no such file", - MismatchedFileTypeForOperation => "mismatched file type", - ResourceUnavailable => "resource unavailable", - TimedOut => "operation timed out", - ShortWrite(..) => "short write", - NoProgress => "no progress", - }; - IoError { - kind: kind, - desc: desc, - detail: None, - } -} - -/// A mode specifies how a file should be opened or created. These modes are -/// passed to `File::open_mode` and are used to control where the file is -/// positioned when it is initially opened. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum FileMode { - /// Opens a file positioned at the beginning. - Open, - /// Opens a file positioned at EOF. - Append, - /// Opens a file, truncating it if it already exists. - Truncate, -} - -/// Access permissions with which the file should be opened. `File`s -/// opened with `Read` will return an error if written to. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum FileAccess { - /// Read-only access, requests to write will result in an error - Read, - /// Write-only access, requests to read will result in an error - Write, - /// Read-write access, no requests are denied by default - ReadWrite, -} - -/// Different kinds of files which can be identified by a call to stat -#[derive(Copy, PartialEq, Debug, Hash, Clone)] -pub enum FileType { - /// This is a normal file, corresponding to `S_IFREG` - RegularFile, - - /// This file is a directory, corresponding to `S_IFDIR` - Directory, - - /// This file is a named pipe, corresponding to `S_IFIFO` - NamedPipe, - - /// This file is a block device, corresponding to `S_IFBLK` - BlockSpecial, - - /// This file is a symbolic link to another file, corresponding to `S_IFLNK` - Symlink, - - /// The type of this file is not recognized as one of the other categories - Unknown, -} - -/// A structure used to describe metadata information about a file. This -/// structure is created through the `stat` method on a `Path`. -/// -/// # Examples -/// -/// ```no_run -/// # #![feature(old_io, old_path)] -/// -/// use std::old_io::fs::PathExtensions; -/// use std::old_path::Path; -/// -/// let info = match Path::new("foo.txt").stat() { -/// Ok(stat) => stat, -/// Err(e) => panic!("couldn't read foo.txt: {}", e), -/// }; -/// -/// println!("byte size: {}", info.size); -/// ``` -#[derive(Copy, Clone, Hash)] -pub struct FileStat { - /// The size of the file, in bytes - pub size: u64, - /// The kind of file this path points to (directory, file, pipe, etc.) - pub kind: FileType, - /// The file permissions currently on the file - pub perm: FilePermission, - - // FIXME(#10301): These time fields are pretty useless without an actual - // time representation, what are the milliseconds relative - // to? - - /// The time that the file was created at, in platform-dependent - /// milliseconds - pub created: u64, - /// The time that this file was last modified, in platform-dependent - /// milliseconds - pub modified: u64, - /// The time that this file was last accessed, in platform-dependent - /// milliseconds - pub accessed: u64, - - /// Information returned by stat() which is not guaranteed to be - /// platform-independent. This information may be useful on some platforms, - /// but it may have different meanings or no meaning at all on other - /// platforms. - /// - /// Usage of this field is discouraged, but if access is desired then the - /// fields are located here. - #[unstable(feature = "io")] - pub unstable: UnstableFileStat, -} - -/// This structure represents all of the possible information which can be -/// returned from a `stat` syscall which is not contained in the `FileStat` -/// structure. This information is not necessarily platform independent, and may -/// have different meanings or no meaning at all on some platforms. -#[unstable(feature = "io")] -#[derive(Copy, Clone, Hash)] -pub struct UnstableFileStat { - /// The ID of the device containing the file. - pub device: u64, - /// The file serial number. - pub inode: u64, - /// The device ID. - pub rdev: u64, - /// The number of hard links to this file. - pub nlink: u64, - /// The user ID of the file. - pub uid: u64, - /// The group ID of the file. - pub gid: u64, - /// The optimal block size for I/O. - pub blksize: u64, - /// The blocks allocated for this file. - pub blocks: u64, - /// User-defined flags for the file. - pub flags: u64, - /// The file generation number. - pub gen: u64, -} - - -bitflags! { - /// A set of permissions for a file or directory is represented by a set of - /// flags which are or'd together. - #[derive(Debug)] - flags FilePermission: u32 { - const USER_READ = 0o400, - const USER_WRITE = 0o200, - const USER_EXECUTE = 0o100, - const GROUP_READ = 0o040, - const GROUP_WRITE = 0o020, - const GROUP_EXECUTE = 0o010, - const OTHER_READ = 0o004, - const OTHER_WRITE = 0o002, - const OTHER_EXECUTE = 0o001, - - const USER_RWX = USER_READ.bits | USER_WRITE.bits | USER_EXECUTE.bits, - const GROUP_RWX = GROUP_READ.bits | GROUP_WRITE.bits | GROUP_EXECUTE.bits, - const OTHER_RWX = OTHER_READ.bits | OTHER_WRITE.bits | OTHER_EXECUTE.bits, - - /// Permissions for user owned files, equivalent to 0644 on unix-like - /// systems. - const USER_FILE = USER_READ.bits | USER_WRITE.bits | GROUP_READ.bits | OTHER_READ.bits, - - /// Permissions for user owned directories, equivalent to 0755 on - /// unix-like systems. - const USER_DIR = USER_RWX.bits | GROUP_READ.bits | GROUP_EXECUTE.bits | - OTHER_READ.bits | OTHER_EXECUTE.bits, - - /// Permissions for user owned executables, equivalent to 0755 - /// on unix-like systems. - const USER_EXEC = USER_DIR.bits, - - /// All possible permissions enabled. - const ALL_PERMISSIONS = USER_RWX.bits | GROUP_RWX.bits | OTHER_RWX.bits, - } -} - - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for FilePermission { - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - fn default() -> FilePermission { FilePermission::empty() } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for FilePermission { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:04o}", self.bits) - } -} - -#[cfg(test)] -mod tests { - use self::BadReaderBehavior::*; - use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput, Writer}; - use super::Buffer; - use prelude::v1::{Ok, Vec}; - use usize; - - #[derive(Clone, PartialEq, Debug)] - enum BadReaderBehavior { - GoodBehavior(usize), - BadBehavior(usize) - } - - struct BadReader { - r: T, - behavior: Vec, - } - - impl BadReader { - fn new(r: T, behavior: Vec) -> BadReader { - BadReader { behavior: behavior, r: r } - } - } - - impl Reader for BadReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let BadReader { ref mut behavior, ref mut r } = *self; - loop { - if behavior.is_empty() { - // fall back on good - return r.read(buf); - } - match (&mut **behavior)[0] { - GoodBehavior(0) => (), - GoodBehavior(ref mut x) => { - *x -= 1; - return r.read(buf); - } - BadBehavior(0) => (), - BadBehavior(ref mut x) => { - *x -= 1; - return Ok(0); - } - }; - behavior.remove(0); - } - } - } - - #[test] - fn test_read_at_least() { - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![GoodBehavior(usize::MAX)]); - let buf = &mut [0; 5]; - assert!(r.read_at_least(1, buf).unwrap() >= 1); - assert!(r.read_exact(5).unwrap().len() == 5); // read_exact uses read_at_least - assert!(r.read_at_least(0, buf).is_ok()); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(50), GoodBehavior(usize::MAX)]); - assert!(r.read_at_least(1, buf).unwrap() >= 1); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(1), GoodBehavior(1), - BadBehavior(50), GoodBehavior(usize::MAX)]); - assert!(r.read_at_least(1, buf).unwrap() >= 1); - assert!(r.read_at_least(1, buf).unwrap() >= 1); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(usize::MAX)]); - assert_eq!(r.read_at_least(1, buf).unwrap_err().kind, NoProgress); - - let mut r = MemReader::new(b"hello, world!".to_vec()); - assert_eq!(r.read_at_least(5, buf).unwrap(), 5); - assert_eq!(r.read_at_least(6, buf).unwrap_err().kind, InvalidInput); - } - - #[test] - fn test_push_at_least() { - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![GoodBehavior(usize::MAX)]); - let mut buf = Vec::new(); - assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - assert!(r.push_at_least(0, 5, &mut buf).is_ok()); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(50), GoodBehavior(usize::MAX)]); - assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(1), GoodBehavior(1), - BadBehavior(50), GoodBehavior(usize::MAX)]); - assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(usize::MAX)]); - assert_eq!(r.push_at_least(1, 5, &mut buf).unwrap_err().kind, NoProgress); - - let mut r = MemReader::new(b"hello, world!".to_vec()); - assert_eq!(r.push_at_least(5, 1, &mut buf).unwrap_err().kind, InvalidInput); - } - - #[test] - fn test_show() { - use super::*; - - assert_eq!(format!("{}", USER_READ), "0400"); - assert_eq!(format!("{}", USER_FILE), "0644"); - assert_eq!(format!("{}", USER_EXEC), "0755"); - assert_eq!(format!("{}", USER_RWX), "0700"); - assert_eq!(format!("{}", GROUP_RWX), "0070"); - assert_eq!(format!("{}", OTHER_RWX), "0007"); - assert_eq!(format!("{}", ALL_PERMISSIONS), "0777"); - assert_eq!(format!("{}", USER_READ | USER_WRITE | OTHER_WRITE), "0602"); - } - - fn _ensure_buffer_is_object_safe(x: &T) -> &Buffer { - x as &Buffer - } -} diff --git a/src/libstd/old_io/net/addrinfo.rs b/src/libstd/old_io/net/addrinfo.rs deleted file mode 100644 index dd30363e316af..0000000000000 --- a/src/libstd/old_io/net/addrinfo.rs +++ /dev/null @@ -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 or the MIT license -// , 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, - pub protocol: Option, - pub flags: usize, -} - -#[derive(Copy, Clone, Debug)] -pub struct Info { - pub address: SocketAddr, - pub family: usize, - pub socktype: Option, - pub protocol: Option, - 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> { - 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 { - 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) - -> IoResult> { - 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"); - } -} diff --git a/src/libstd/old_io/net/ip.rs b/src/libstd/old_io/net/ip.rs deleted file mode 100644 index f5310292b911b..0000000000000 --- a/src/libstd/old_io/net/ip.rs +++ /dev/null @@ -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 or the MIT license -// , 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(&mut self, cb: F) -> Option where - F: FnOnce(&mut Parser) -> Option, - { - 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(&mut self, cb: F) -> Option where - F: FnOnce(&mut Parser) -> Option, - { - 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(&mut self, parsers: &mut [Box Option>]) - -> Option { - 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(&mut self, - pa: PA, - pb: PB, - pc: PC) - -> Option<(A, B, C)> where - PA: FnOnce(&mut Parser) -> Option, - PB: FnOnce(&mut Parser) -> Option, - PC: FnOnce(&mut Parser) -> Option, - { - 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 { - 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 { - 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 { - fn parse_digit(c: char, radix: u8) -> Option { - 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 { - 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 { - self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto)) - } - - fn read_ipv4_addr_impl(&mut self) -> Option { - 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 { - self.read_atomically(|p| p.read_ipv4_addr_impl()) - } - - fn read_ipv6_addr_impl(&mut self) -> Option { - 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 { - self.read_atomically(|p| p.read_ipv6_addr_impl()) - } - - fn read_ip_addr(&mut self) -> Option { - 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 { - 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::(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::(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 { - 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 { - 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 `:` pair -/// where `` 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 { - 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> { - self.to_socket_addr().map(|a| vec![a]) - } -} - -impl ToSocketAddr for SocketAddr { - #[inline] - fn to_socket_addr(&self) -> IoResult { Ok(*self) } -} - -impl ToSocketAddr for (IpAddr, u16) { - #[inline] - fn to_socket_addr(&self) -> IoResult { - let (ip, port) = *self; - Ok(SocketAddr { ip: ip, port: port }) - } -} - -fn resolve_socket_addr(s: &str, p: u16) -> IoResult> { - 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> { - 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> { - 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 { - // 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> { - // 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 = "256.0.0.1".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "255.0.0".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "255.0.0.1.2".parse().ok(); - assert_eq!(None, none); - // no number between dots - let none: Option = "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 = "::00000".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "1:2:3:4:5:6:7".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); - assert_eq!(None, none); - // triple colon - let none: Option = "1:2:::6:7:8".parse().ok(); - assert_eq!(None, none); - // two double colons - let none: Option = "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 = "::127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // not enough groups - let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); - assert_eq!(None, none); - // too many groups - let none: Option = "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 = "127.0.0.1".parse().ok(); - assert_eq!(None, none); - // without port - let none: Option = "127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // wrong brackets around v4 - let none: Option = "[127.0.0.1]:22".parse().ok(); - assert_eq!(None, none); - // port out of range - let none: Option = "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)); - } -} diff --git a/src/libstd/old_io/net/mod.rs b/src/libstd/old_io/net/mod.rs deleted file mode 100644 index a3567290b0e16..0000000000000 --- a/src/libstd/old_io/net/mod.rs +++ /dev/null @@ -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 or the MIT license -// , 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(addr: A, mut action: F) -> IoResult where - A: ToSocketAddr, - F: FnMut(SocketAddr) -> IoResult, -{ - 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) -} diff --git a/src/libstd/old_io/net/pipe.rs b/src/libstd/old_io/net/pipe.rs deleted file mode 100644 index 7b23c3e1d03f2..0000000000000 --- a/src/libstd/old_io/net/pipe.rs +++ /dev/null @@ -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 or the MIT license -// , 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(path: P) -> IoResult { - 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

, - out_fd: Option

, err_fd: Option

) - -> IoResult - where C: ProcessConfig, P: AsInner, - 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,&'static ProcessConfig>(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

, 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 { - 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, - (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, 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 { - 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(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(env: Option<&HashMap>, - 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) - } -} diff --git a/src/libstd/sys/unix/process2.rs b/src/libstd/sys/unix/process2.rs index 0b4e871454db0..caa7b4eb29c7b 100644 --- a/src/libstd/sys/unix/process2.rs +++ b/src/libstd/sys/unix/process2.rs @@ -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()), } } } diff --git a/src/libstd/sys/unix/tcp.rs b/src/libstd/sys/unix/tcp.rs deleted file mode 100644 index a9f2198208bc3..0000000000000 --- a/src/libstd/sys/unix/tcp.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - 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 { - 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 { - net::sockname(self.fd(), libc::getsockname) - } -} - -pub struct TcpAcceptor { - inner: Arc, - 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 { - // 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) { - 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, - } - } -} diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs deleted file mode 100644 index 9309147b15c44..0000000000000 --- a/src/libstd/sys/unix/timer.rs +++ /dev/null @@ -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 or the MIT license -// , 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 } - -pub trait Callback { - fn call(&mut self); -} - -pub struct Timer { - id: usize, - inner: Option>, -} - -pub struct Inner { - cb: Option>, - interval: u64, - repeat: bool, - target: u64, - id: usize, -} - -pub enum Req { - // Add a new timer to the helper thread. - NewTimer(Box), - - // Remove a timer based on its id and then send it back on the channel - // provided - RemoveTimer(usize, Sender>), -} - -// 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, _: ()) { - 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> = vec![]; - let mut dead = vec![]; - - // inserts a timer into an array of timers (sorted by firing time) - fn insert(t: Box, active: &mut Vec>) { - 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>, - dead: &mut Vec<(usize, Box)>) { - 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 { - // 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) { - 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) { - 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 { - 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()); - } -} diff --git a/src/libstd/sys/unix/tty.rs b/src/libstd/sys/unix/tty.rs deleted file mode 100644 index 2f6fd713bfba5..0000000000000 --- a/src/libstd/sys/unix/tty.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - 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 { - 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)) - } - } - } -} diff --git a/src/libstd/sys/unix/udp.rs b/src/libstd/sys/unix/udp.rs deleted file mode 100644 index 50f8fb828ad32..0000000000000 --- a/src/libstd/sys/unix/udp.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use sys_common::net::UdpSocket; diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs index 5f6e74d4b7251..ea95cc5bfd5b9 100644 --- a/src/libstd/sys/windows/ext.rs +++ b/src/libstd/sys/windows/ext.rs @@ -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 { diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs deleted file mode 100644 index 0bbb1a9e92752..0000000000000 --- a/src/libstd/sys/windows/fs.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - 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 { - 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 { - self.seek_common(pos, style) - } - - pub fn tell(&self) -> IoResult { - 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 { - 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> { - sys::to_utf16(s.as_str()) -} - -pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { - // 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> { - fn prune(root: &Path, dirs: Vec) -> Vec { - 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) -> 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 { - // 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 { - 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 { - // 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) - }) -} diff --git a/src/libstd/sys/windows/helper_signal.rs b/src/libstd/sys/windows/helper_signal.rs deleted file mode 100644 index a9fb2c6822767..0000000000000 --- a/src/libstd/sys/windows/helper_signal.rs +++ /dev/null @@ -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 or the MIT license -// , 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; -} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index e9d5fca531fdb..1171c6c068b12 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -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(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> { - 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 { let mut v: Vec<_> = s.encode_wide().collect(); v.push(0); @@ -242,7 +85,7 @@ fn to_utf16_os(s: &OsStr) -> Vec { // 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(mut f1: F1, f2: F2) -> Result +fn fill_utf16_buf(mut f1: F1, f2: F2) -> io::Result where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD, F2: FnOnce(&[u16]) -> T { @@ -274,7 +117,7 @@ fn fill_utf16_buf_base(mut f1: F1, f2: F2) -> Result 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(mut f1: F1, f2: F2) -> Result } } -#[allow(deprecated)] -fn fill_utf16_buf(f1: F1, f2: F2) -> IoResult - 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: F1, f2: F2) -> io::Result - 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)) } diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index d5843a2f9987b..ebf5532b0cadb 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -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 { - 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 { - 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 { 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 { 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, diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs deleted file mode 100644 index 064c003bd15a9..0000000000000 --- a/src/libstd/sys/windows/pipe.rs +++ /dev/null @@ -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 or the MIT license -// , 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> { - 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 { - 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 { - 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, - write: Option, - read: Option, - read_deadline: u64, - write_deadline: u64, -} - -impl UnixStream { - fn try_connect(p: *const u16) -> Option { - // 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) -> IoResult { - 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 { - 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) { - 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) { - self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - pub fn set_write_timeout(&mut self, timeout: Option) { - 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 { - // 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 { - 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, - listener: UnixListener, - event: Event, - deadline: u64, -} - -struct AcceptorState { - abort: Event, - closed: AtomicBool, -} - -impl UnixAcceptor { - pub fn accept(&mut self) -> IoResult { - // 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) { - 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 - }, - }, - } - } -} diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs deleted file mode 100644 index b10042090ddc8..0000000000000 --- a/src/libstd/sys/windows/process.rs +++ /dev/null @@ -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 or the MIT license -// , 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(cfg: &C, in_fd: Option

, - out_fd: Option

, err_fd: Option

) - -> IoResult - where C: ProcessConfig, P: AsInner, - 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::() 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

, 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::(); - let mut sa = libc::SECURITY_ATTRIBUTES { - nLength: size as libc::DWORD, - lpSecurityDescriptor: ptr::null_mut(), - bInheritHandle: 1, - }; - let mut filename: Vec = "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 = 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 { - 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 = 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(env: Option<&collections::HashMap>, 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(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 = 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::>()) - } - - 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}" - ); - } -} diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs deleted file mode 100644 index 41e97dc847502..0000000000000 --- a/src/libstd/sys/windows/tcp.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - 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 { - 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 { - 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 { - 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, - 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 { - // 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) { - 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, - } - } -} diff --git a/src/libstd/sys/windows/timer.rs b/src/libstd/sys/windows/timer.rs deleted file mode 100644 index 8856cc26b2e90..0000000000000 --- a/src/libstd/sys/windows/timer.rs +++ /dev/null @@ -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 or the MIT license -// , 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 } - -pub trait Callback { - fn call(&mut self); -} - -pub struct Timer { - obj: libc::HANDLE, - on_worker: bool, -} - -pub enum Req { - NewTimer(libc::HANDLE, Box, bool), - RemoveTimer(libc::HANDLE, Sender<()>), -} - -unsafe impl Send for Timer {} -unsafe impl Send for Req {} - -fn helper(input: libc::HANDLE, messages: Receiver, _: ()) { - 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 { - 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) { - 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) { - 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; - } -} diff --git a/src/libstd/sys/windows/tty.rs b/src/libstd/sys/windows/tty.rs deleted file mode 100644 index 791c7532bd007..0000000000000 --- a/src/libstd/sys/windows/tty.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - 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 { - // Read more if the buffer is empty - if self.utf8.eof() { - let mut utf16: Vec = 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::>() - } - 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) }; - } - } -} diff --git a/src/libstd/sys/windows/udp.rs b/src/libstd/sys/windows/udp.rs deleted file mode 100644 index 50f8fb828ad32..0000000000000 --- a/src/libstd/sys/windows/udp.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use sys_common::net::UdpSocket; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 0e5fee27ffe22..c47e238943272 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -728,7 +728,6 @@ mod test { use any::Any; use sync::mpsc::{channel, Sender}; use result; - use std::old_io::{ChanReader, ChanWriter}; use super::{Builder}; use thread; use thunk::Thunk; @@ -967,13 +966,11 @@ mod test { #[test] fn test_park_timeout_unpark_called_other_thread() { - use std::old_io; - for _ in 0..10 { let th = thread::current(); let _guard = thread::spawn(move || { - old_io::timer::sleep(Duration::milliseconds(50)); + super::sleep_ms(50); th.unpark(); }); diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index d8c50b5a0942a..65554efdd680f 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -61,7 +61,6 @@ pub mod clone; pub mod encodable; pub mod decodable; pub mod hash; -pub mod rand; pub mod show; pub mod default; pub mod primitive; @@ -168,8 +167,6 @@ derive_traits! { "PartialOrd" => ord::expand_deriving_ord, "Ord" => totalord::expand_deriving_totalord, - "Rand" => rand::expand_deriving_rand, - "Debug" => show::expand_deriving_show, "Default" => default::expand_deriving_default, diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs deleted file mode 100644 index 631e5f979d9ee..0000000000000 --- a/src/libsyntax/ext/deriving/rand.rs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use ast::{MetaItem, Item, Expr}; -use codemap::Span; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use ptr::P; - -pub fn expand_deriving_rand(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), -{ - cx.span_warn(span, - "`#[derive(Rand)]` is deprecated in favour of `#[derive_Rand]` from \ - `rand_macros` on crates.io"); - - if !cx.use_std { - // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std]"); - return; - } - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path!(std::rand::Rand), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - methods: vec!( - MethodDef { - name: "rand", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("R", - vec!( path!(std::rand::Rng) ))), - }, - explicit_self: None, - args: vec!( - Ptr(box Literal(Path::new_local("R")), - Borrowed(None, ast::MutMutable)) - ), - ret_ty: Self_, - attributes: Vec::new(), - combine_substructure: combine_substructure(Box::new(|a, b, c| { - rand_substructure(a, b, c) - })) - } - ), - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} - -fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { - let rng = match substr.nonself_args { - [ref rng] => rng, - _ => cx.bug("Incorrect number of arguments to `rand` in `derive(Rand)`") - }; - let rand_ident = vec!( - cx.ident_of("std"), - cx.ident_of("rand"), - cx.ident_of("Rand"), - cx.ident_of("rand") - ); - let rand_call = |cx: &mut ExtCtxt, span| { - cx.expr_call_global(span, - rand_ident.clone(), - vec!(rng.clone())) - }; - - return match *substr.fields { - StaticStruct(_, ref summary) => { - let path = cx.path_ident(trait_span, substr.type_ident); - rand_thing(cx, trait_span, path, summary, rand_call) - } - StaticEnum(_, ref variants) => { - if variants.is_empty() { - cx.span_err(trait_span, "`Rand` cannot be derived for enums with no variants"); - // let compilation continue - return cx.expr_usize(trait_span, 0); - } - - let variant_count = cx.expr_usize(trait_span, variants.len()); - - let rand_name = cx.path_all(trait_span, - true, - rand_ident.clone(), - Vec::new(), - Vec::new(), - Vec::new()); - let rand_name = cx.expr_path(rand_name); - - // ::rand::Rand::rand(rng) - let rv_call = cx.expr_call(trait_span, - rand_name, - vec!(rng.clone())); - - // need to specify the usize-ness of the random number - let usize_ty = cx.ty_ident(trait_span, cx.ident_of("usize")); - let value_ident = cx.ident_of("__value"); - let let_statement = cx.stmt_let_typed(trait_span, - false, - value_ident, - usize_ty, - rv_call); - - // rand() % variants.len() - let value_ref = cx.expr_ident(trait_span, value_ident); - let rand_variant = cx.expr_binary(trait_span, - ast::BiRem, - value_ref, - variant_count); - - let mut arms = variants.iter().enumerate().map(|(i, &(ident, v_span, ref summary))| { - let i_expr = cx.expr_usize(v_span, i); - let pat = cx.pat_lit(v_span, i_expr); - - let path = cx.path(v_span, vec![substr.type_ident, ident]); - let thing = rand_thing(cx, v_span, path, summary, |cx, sp| rand_call(cx, sp)); - cx.arm(v_span, vec!( pat ), thing) - }).collect:: >(); - - // _ => {} at the end. Should never occur - arms.push(cx.arm_unreachable(trait_span)); - - let match_expr = cx.expr_match(trait_span, rand_variant, arms); - - let block = cx.block(trait_span, vec!( let_statement ), Some(match_expr)); - cx.expr_block(block) - } - _ => cx.bug("Non-static method in `derive(Rand)`") - }; - - fn rand_thing(cx: &mut ExtCtxt, - trait_span: Span, - ctor_path: ast::Path, - summary: &StaticFields, - mut rand_call: F) - -> P where - F: FnMut(&mut ExtCtxt, Span) -> P, - { - let path = cx.expr_path(ctor_path.clone()); - match *summary { - Unnamed(ref fields) => { - if fields.is_empty() { - path - } else { - let exprs = fields.iter().map(|span| rand_call(cx, *span)).collect(); - cx.expr_call(trait_span, path, exprs) - } - } - Named(ref fields) => { - let rand_fields = fields.iter().map(|&(ident, span)| { - let e = rand_call(cx, span); - cx.field_imm(span, ident, e) - }).collect(); - cx.expr_struct(trait_span, ctor_path, rand_fields) - } - } - } -} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index bf95daf87555d..3f36d0e8eda0f 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -30,7 +30,6 @@ #![feature(collections)] #![feature(core)] #![feature(libc)] -#![feature(old_path)] #![feature(quote, unsafe_destructor)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4db85eeea46f1..2bb74944ce91a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -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) diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 94dee5ccc36b7..a786d24ed8581 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -43,7 +43,6 @@ pub trait Stats { /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at: /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates"] /// (http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps) - /// *Discrete & Computational Geometry 18*, 3 (Oct 1997), 305-363, Shewchuk J.R. fn sum(&self) -> T; /// Minimum value of the samples. @@ -334,8 +333,9 @@ pub fn winsorize(samples: &mut [T], pct: T) { mod tests { use stats::Stats; use stats::Summary; - use std::old_io::{self, Writer}; use std::f64; + use std::io::prelude::*; + use std::io; macro_rules! assert_approx_eq { ($a:expr, $b:expr) => ({ @@ -350,7 +350,7 @@ mod tests { let summ2 = Summary::new(samples); - let mut w = old_io::stdout(); + let mut w = io::sink(); let w = &mut w; (write!(w, "\n")).unwrap(); diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 0cff90d61ed99..8f3e939f1f40d 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures, std_misc, rand)] +#![feature(std_misc, rand)] use std::collections::{BTreeMap, HashMap, HashSet}; use std::env; -use std::rand::{Rng, IsaacRng, SeedableRng}; +use std::__rand::{Rng, thread_rng}; use std::time::Duration; fn timed(label: &str, f: F) where F: FnMut() { @@ -114,7 +114,7 @@ fn main() { { let seed: &[_] = &[1, 1, 1, 1, 1, 1, 1]; - let mut rng: IsaacRng = SeedableRng::from_seed(seed); + let mut rng = thread_rng(); let mut set = HashSet::new(); while set.len() != n_keys { let next = rng.gen(); diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 0344d6a46eeb5..d910367afbf49 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -11,18 +11,14 @@ // ignore-lexer-test FIXME #15679 // Microbenchmarks for various functions in std and extra -#![feature(unboxed_closures, rand, old_io, old_path, std_misc, collections)] +#![feature(rand, collections, std_misc)] -use std::old_io::*; -use std::old_path::{Path, GenericPath}; use std::iter::repeat; use std::mem::swap; use std::env; -use std::rand::Rng; -use std::rand; +use std::__rand::{thread_rng, Rng}; use std::str; use std::time::Duration; -use std::vec; fn main() { let argv: Vec = env::args().collect(); @@ -35,7 +31,6 @@ fn main() { } bench!(shift_push); - bench!(read_line); bench!(vec_plus); bench!(vec_append); bench!(vec_push_all); @@ -70,21 +65,8 @@ fn shift_push() { } } -fn read_line() { - use std::old_io::BufferedReader; - - let mut path = Path::new(env!("CFG_SRC_DIR")); - path.push("src/test/bench/shootout-k-nucleotide.data"); - - for _ in 0..3 { - let mut reader = BufferedReader::new(File::open(&path).unwrap()); - for _line in reader.lines() { - } - } -} - fn vec_plus() { - let mut r = rand::thread_rng(); + let mut r = thread_rng(); let mut v = Vec::new(); let mut i = 0; @@ -102,7 +84,7 @@ fn vec_plus() { } fn vec_append() { - let mut r = rand::thread_rng(); + let mut r = thread_rng(); let mut v = Vec::new(); let mut i = 0; @@ -123,7 +105,7 @@ fn vec_append() { } fn vec_push_all() { - let mut r = rand::thread_rng(); + let mut r = thread_rng(); let mut v = Vec::new(); for i in 0..1500 { diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 83c39b3f3faf6..c21470d4bb3e7 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -16,7 +16,7 @@ use std::f32::consts::PI; use std::num::Float; -use std::rand::{Rng, StdRng}; +use std::__rand::{Rng, thread_rng}; #[derive(Copy, Clone)] struct Vec2 { @@ -44,7 +44,7 @@ struct Noise2DContext { impl Noise2DContext { fn new() -> Noise2DContext { - let mut rng = StdRng::new().unwrap(); + let mut rng = thread_rng(); let mut rgradients = [Vec2 { x: 0.0, y: 0.0 }; 256]; for x in &mut rgradients[..] { diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index effdd67027a44..145ab71446354 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -38,13 +38,11 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -#![feature(core, old_io, io, core)] - use std::cmp::min; -use std::old_io::*; -use std::iter::repeat; use std::env; -use std::slice::bytes::copy_memory; +use std::io; +use std::io::prelude::*; +use std::iter::repeat; const LINE_LEN: usize = 60; const LOOKUP_SIZE: usize = 4 * 1024; @@ -116,27 +114,31 @@ struct RepeatFasta<'a, W:'a> { out: &'a mut W } -impl<'a, W: Writer> RepeatFasta<'a, W> { +impl<'a, W: Write> RepeatFasta<'a, W> { fn new(alu: &'static str, w: &'a mut W) -> RepeatFasta<'a, W> { RepeatFasta { alu: alu, out: w } } - fn make(&mut self, n: usize) -> IoResult<()> { + fn make(&mut self, n: usize) -> io::Result<()> { let alu_len = self.alu.len(); let mut buf = repeat(0).take(alu_len + LINE_LEN).collect::>(); let alu: &[u8] = self.alu.as_bytes(); - copy_memory(alu, &mut buf); + for (slot, val) in buf.iter_mut().zip(alu.iter()) { + *slot = *val; + } let buf_len = buf.len(); - copy_memory(&alu[..LINE_LEN], &mut buf[alu_len..buf_len]); + for (slot, val) in buf[alu_len..buf_len].iter_mut().zip(alu[..LINE_LEN].iter()) { + *slot = *val; + } let mut pos = 0; let mut bytes; let mut n = n; while n > 0 { bytes = min(LINE_LEN, n); - try!(self.out.write(&buf[pos..pos + bytes])); - try!(self.out.write_u8('\n' as u8)); + try!(self.out.write_all(&buf[pos..pos + bytes])); + try!(self.out.write_all(&[b'\n'])); pos += bytes; if pos > alu_len { pos -= alu_len; @@ -165,7 +167,7 @@ struct RandomFasta<'a, W:'a> { out: &'a mut W, } -impl<'a, W: Writer> RandomFasta<'a, W> { +impl<'a, W: Write> RandomFasta<'a, W> { fn new(w: &'a mut W, a: &[AminoAcid]) -> RandomFasta<'a, W> { RandomFasta { seed: 42, @@ -189,7 +191,7 @@ impl<'a, W: Writer> RandomFasta<'a, W> { 0 } - fn make(&mut self, n: usize) -> IoResult<()> { + fn make(&mut self, n: usize) -> io::Result<()> { let lines = n / LINE_LEN; let chars_left = n % LINE_LEN; let mut buf = [0;LINE_LEN + 1]; @@ -204,7 +206,7 @@ impl<'a, W: Writer> RandomFasta<'a, W> { for i in 0..chars_left { buf[i] = self.nextc(); } - self.out.write(&buf[..chars_left]) + self.out.write_all(&buf[..chars_left]) } } @@ -216,23 +218,23 @@ fn main() { 5 }; - let mut out = stdout(); + let mut out = io::stdout(); - out.write_line(">ONE Homo sapiens alu").unwrap(); + out.write_all(b">ONE Homo sapiens alu\n").unwrap(); { let mut repeat = RepeatFasta::new(ALU, &mut out); repeat.make(n * 2).unwrap(); } - out.write_line(">TWO IUB ambiguity codes").unwrap(); + out.write_all(b">TWO IUB ambiguity codes\n").unwrap(); let iub = sum_and_scale(&IUB); let mut random = RandomFasta::new(&mut out, &iub); random.make(n * 3).unwrap(); - random.out.write_line(">THREE Homo sapiens frequency").unwrap(); + random.out.write_all(b">THREE Homo sapiens frequency\n").unwrap(); let homo_sapiens = sum_and_scale(&HOMO_SAPIENS); random.lookup = make_lookup(&homo_sapiens); random.make(n * 5).unwrap(); - random.out.write_str("\n").unwrap(); + random.out.write_all(b"\n").unwrap(); } diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 78d31faeb5169..0474cfb6fc819 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -38,14 +38,12 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -#![feature(old_io, old_path, io, core)] - use std::cmp::min; -use std::old_io::*; -use std::old_io; -use std::old_path::Path; -use std::num::Float; use std::env; +use std::fs::File; +use std::io::{self, BufWriter}; +use std::io::prelude::*; +use std::num::Float; const LINE_LENGTH: usize = 60; const IM: u32 = 139968; @@ -87,9 +85,9 @@ impl<'a> Iterator for AAGen<'a> { } } -fn make_fasta>( +fn make_fasta>( wr: &mut W, header: &str, mut it: I, mut n: usize) - -> std::old_io::IoResult<()> + -> io::Result<()> { try!(wr.write(header.as_bytes())); let mut line = [0; LINE_LENGTH + 1]; @@ -105,7 +103,7 @@ fn make_fasta>( Ok(()) } -fn run(writer: &mut W) -> std::old_io::IoResult<()> { +fn run(writer: &mut W) -> io::Result<()> { let mut args = env::args(); let n = if env::var_os("RUST_BENCH").is_some() { 25000000 @@ -146,10 +144,10 @@ fn run(writer: &mut W) -> std::old_io::IoResult<()> { fn main() { let res = if env::var_os("RUST_BENCH").is_some() { - let mut file = BufferedWriter::new(File::create(&Path::new("./shootout-fasta.data"))); + let mut file = BufWriter::new(File::create("./shootout-fasta.data").unwrap()); run(&mut file) } else { - run(&mut old_io::stdout()) + run(&mut io::stdout()) }; res.unwrap() } diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index c190641bfbff0..bcd8fbf88523e 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -13,18 +13,17 @@ // multi tasking k-nucleotide -#![feature(box_syntax, std_misc, old_io, collections, os)] +#![allow(bad_style)] -use std::ascii::{AsciiExt, OwnedAsciiExt}; +use std::ascii::AsciiExt; use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::collections::HashMap; use std::mem::replace; -use std::num::Float; -use std::option; -use std::os; use std::env; use std::sync::mpsc::{channel, Sender, Receiver}; use std::thread; +use std::io; +use std::io::prelude::*; fn f64_cmp(x: f64, y: f64) -> Ordering { // arbitrarily decide that NaNs are larger than everything. @@ -75,10 +74,10 @@ fn sort_and_fmt(mm: &HashMap , usize>, total: usize) -> String { // given a map, search for the frequency of a pattern fn find(mm: &HashMap , usize>, key: String) -> usize { - let key = key.into_ascii_lowercase(); + let key = key.to_ascii_lowercase(); match mm.get(key.as_bytes()) { - option::Option::None => { return 0; } - option::Option::Some(&num) => { return num; } + None => 0, + Some(&num) => num, } } @@ -123,7 +122,7 @@ fn make_sequence_processor(sz: usize, line = from_parent.recv().unwrap(); if line == Vec::new() { break; } - carry.push_all(&line); + carry.extend(line); carry = windows_with_carry(&carry, sz, |window| { update_freq(&mut freqs, window); total += 1; @@ -147,15 +146,13 @@ fn make_sequence_processor(sz: usize, // given a FASTA file on stdin, process sequence THREE fn main() { - use std::old_io::*; - + let input = io::stdin(); let rdr = if env::var_os("RUST_BENCH").is_some() { - let foo = include_bytes!("shootout-k-nucleotide.data"); - box MemReader::new(foo.to_vec()) as Box + let foo: &[u8] = include_bytes!("shootout-k-nucleotide.data"); + Box::new(foo) as Box } else { - box stdio::stdin() as Box + Box::new(input.lock()) as Box }; - let mut rdr = BufferedReader::new(rdr); // initialize each sequence sorter let sizes: Vec = vec!(1,2,3,4,6,12,18); diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index d248293103bde..93a0a461746bf 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -38,13 +38,13 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -#![feature(simd, old_io, core, io)] +#![feature(simd, core)] // ignore-pretty very bad with line comments -use std::old_io; -use std::old_io::*; use std::env; +use std::io::prelude::*; +use std::io; use std::simd::f64x2; use std::sync::Arc; use std::thread; @@ -53,8 +53,7 @@ const ITER: usize = 50; const LIMIT: f64 = 2.0; const WORKERS: usize = 16; -#[inline(always)] -fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { +fn mandelbrot(w: usize, mut out: W) -> io::Result<()> { assert!(WORKERS % 2 == 0); // Ensure w and h are multiples of 8. @@ -142,9 +141,9 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { }) }).collect::>(); - try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h)); + try!(writeln!(&mut out, "P4\n{} {}", w, h)); for res in data { - try!(out.write(&res.join())); + try!(out.write_all(&res.join())); } out.flush() } @@ -202,9 +201,9 @@ fn main() { let res = if args.len() < 2 { println!("Test mode: do not dump the image because it's not utf8, \ which interferes with the test runner."); - mandelbrot(1000, old_io::util::NullWriter) + mandelbrot(1000, io::sink()) } else { - mandelbrot(args.nth(1).unwrap().parse().unwrap(), old_io::stdout()) + mandelbrot(args.nth(1).unwrap().parse().unwrap(), io::stdout()) }; res.unwrap(); } diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs index cda90c08f23ad..96ac1e064bfd0 100644 --- a/src/test/bench/shootout-reverse-complement.rs +++ b/src/test/bench/shootout-reverse-complement.rs @@ -40,18 +40,18 @@ // ignore-android see #10393 #13206 -#![feature(unboxed_closures, libc, old_io, collections, io, core)] +#![feature(libc)] extern crate libc; -use std::old_io::stdio::{stdin_raw, stdout_raw}; -use std::old_io::*; -use std::ptr::{copy, Unique}; +use std::io; +use std::io::prelude::*; +use std::ptr::copy; use std::thread; struct Tables { - table8: [u8;1 << 8], - table16: [u16;1 << 16] + table8: [u8; 1 << 8], + table16: [u16; 1 << 16] } impl Tables { @@ -101,36 +101,6 @@ impl Tables { } } -/// Reads all remaining bytes from the stream. -fn read_to_end(r: &mut R) -> IoResult> { - // As reading the input stream in memory is a bottleneck, we tune - // Reader::read_to_end() with a fast growing policy to limit - // recopies. If MREMAP_RETAIN is implemented in the linux kernel - // and jemalloc use it, this trick will become useless. - const CHUNK: usize = 64 * 1024; - - let mut vec = Vec::with_capacity(CHUNK); - loop { - // workaround: very fast growing - let len = vec.len(); - if vec.capacity() - len < CHUNK { - let cap = vec.capacity(); - let mult = if cap < 256 * 1024 * 1024 { - 16 - } else { - 2 - }; - vec.reserve_exact(mult * cap - len); - } - match r.push_at_least(1, CHUNK, &mut vec) { - Ok(_) => {} - Err(ref e) if e.kind == EndOfFile => break, - Err(e) => return Err(e) - } - } - Ok(vec) -} - /// Finds the first position at which `b` occurs in `s`. fn memchr(h: &[u8], n: u8) -> Option { use libc::{c_void, c_int, size_t}; @@ -175,7 +145,8 @@ const LINE_LEN: usize = 60; /// Compute the reverse complement. fn reverse_complement(seq: &mut [u8], tables: &Tables) { - let seq = seq.init_mut();// Drop the last newline + let len = seq.len(); + let seq = &mut seq[..len - 1]; // Drop the last newline let len = seq.len(); let off = LINE_LEN - len % (LINE_LEN + 1); let mut i = LINE_LEN; @@ -222,26 +193,20 @@ fn reverse_complement(seq: &mut [u8], tables: &Tables) { } } - -struct Racy(T); - -unsafe impl Send for Racy {} - /// Executes a closure in parallel over the given iterator over mutable slice. /// The closure `f` is run in parallel with an element of `iter`. -fn parallel<'a, I: Iterator, F>(iter: I, ref f: F) - where I::Item: Send + 'a, - F: Fn(I::Item) + Sync + 'a { +fn parallel(iter: I, ref f: F) + where I::Item: Send, + F: Fn(I::Item) + Sync, { iter.map(|x| { - thread::scoped(move|| { - f(x) - }) + thread::scoped(move || f(x)) }).collect::>(); } fn main() { - let mut data = read_to_end(&mut stdin_raw()).unwrap(); + let mut data = Vec::with_capacity(1024 * 1024); + io::stdin().read_to_end(&mut data); let tables = &Tables::new(); parallel(mut_dna_seqs(&mut data), |seq| reverse_complement(seq, tables)); - stdout_raw().write(&data).unwrap(); + io::stdout().write_all(&data).unwrap(); } diff --git a/src/test/compile-fail/derive-no-std-not-supported.rs b/src/test/compile-fail/derive-no-std-not-supported.rs index d0cb4f23a8c28..327e2c9e0f996 100644 --- a/src/test/compile-fail/derive-no-std-not-supported.rs +++ b/src/test/compile-fail/derive-no-std-not-supported.rs @@ -15,12 +15,6 @@ extern crate core; extern crate rand; extern crate serialize as rustc_serialize; -#[derive(Rand)] //~ ERROR this trait cannot be derived -//~^ WARNING `#[derive(Rand)]` is deprecated -struct Foo { - x: u32, -} - #[derive(RustcEncodable)] //~ ERROR this trait cannot be derived struct Bar { x: u32, diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs index d611e4a65a613..a1ca59caa3304 100644 --- a/src/test/debuginfo/function-arg-initialization.rs +++ b/src/test/debuginfo/function-arg-initialization.rs @@ -10,15 +10,15 @@ // min-lldb-version: 310 -// This test case checks if function arguments already have the correct value when breaking at the -// first line of the function, that is if the function prologue has already been executed at the -// first line. Note that because of the __morestack part of the prologue GDB incorrectly breaks at -// before the arguments have been properly loaded when setting the breakpoint via the function name. +// This test case checks if function arguments already have the correct value +// when breaking at the first line of the function, that is if the function +// prologue has already been executed at the first line. Note that because of +// the __morestack part of the prologue GDB incorrectly breaks at before the +// arguments have been properly loaded when setting the breakpoint via the +// function name. // compile-flags:-g -#![feature(old_io)] - // === GDB TESTS =================================================================================== // gdb-command:run @@ -227,7 +227,7 @@ #![omit_gdb_pretty_printer_section] fn immediate_args(a: isize, b: bool, c: f64) { - ::std::old_io::print("") // #break + println!("") // #break } struct BigStruct { @@ -242,21 +242,21 @@ struct BigStruct { } fn non_immediate_args(a: BigStruct, b: BigStruct) { - ::std::old_io::print("") // #break + println!("") // #break } fn binding(a: i64, b: u64, c: f64) { let x = 0; // #break - ::std::old_io::print("") + println!("") } fn assignment(mut a: u64, b: u64, c: f64) { a = b; // #break - ::std::old_io::print("") + println!("") } fn function_call(x: u64, y: u64, z: f64) { - std::old_io::stdio::print("Hi!") // #break + println!("Hi!") // #break } fn identifier(x: u64, y: u64, z: f64) -> u64 { diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs index 0608e49b28cf4..7e959a1e92012 100644 --- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs +++ b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs @@ -11,17 +11,17 @@ // ignore-android: FIXME(#10381) // min-lldb-version: 310 -// This test case checks if function arguments already have the correct value when breaking at the -// beginning of a function. Functions with the #[no_stack_check] attribute have the same prologue as -// regular C functions compiled with GCC or Clang and therefore are better handled by GDB. As a -// consequence, and as opposed to regular Rust functions, we can set the breakpoints via the -// function name (and don't have to fall back on using line numbers). For LLDB this shouldn't make -// a difference because it can handle both cases. +// This test case checks if function arguments already have the correct value +// when breaking at the beginning of a function. Functions with the +// #[no_stack_check] attribute have the same prologue as regular C functions +// compiled with GCC or Clang and therefore are better handled by GDB. As a +// consequence, and as opposed to regular Rust functions, we can set the +// breakpoints via the function name (and don't have to fall back on using line +// numbers). For LLDB this shouldn't make a difference because it can handle +// both cases. // compile-flags:-g -#![feature(old_io)] - // === GDB TESTS =================================================================================== // gdb-command:rbreak immediate_args @@ -251,7 +251,7 @@ #[no_stack_check] fn immediate_args(a: isize, b: bool, c: f64) { - ::std::old_io::print(""); + println!(""); } struct BigStruct { @@ -267,24 +267,24 @@ struct BigStruct { #[no_stack_check] fn non_immediate_args(a: BigStruct, b: BigStruct) { - ::std::old_io::print(""); + println!(""); } #[no_stack_check] fn binding(a: i64, b: u64, c: f64) { let x = 0; - ::std::old_io::print(""); + println!(""); } #[no_stack_check] fn assignment(mut a: u64, b: u64, c: f64) { a = b; - ::std::old_io::print(""); + println!(""); } #[no_stack_check] fn function_call(x: u64, y: u64, z: f64) { - std::old_io::stdio::print("Hi!") + println!("Hi!") } #[no_stack_check] diff --git a/src/test/debuginfo/issue13213.rs b/src/test/debuginfo/issue13213.rs index 38b149ef243e9..13dc0c6d12007 100644 --- a/src/test/debuginfo/issue13213.rs +++ b/src/test/debuginfo/issue13213.rs @@ -23,5 +23,5 @@ extern crate issue13213aux; // be available because they have been optimized out from the exporting crate. fn main() { let b: issue13213aux::S = issue13213aux::A; - ::std::old_io::println("Nothing to do here..."); + println!("Nothing to do here..."); } diff --git a/src/test/run-make/save-analysis/SubDir/mod.rs b/src/test/run-make/save-analysis/SubDir/mod.rs index 23b7d8bbf0970..fe84db08da900 100644 --- a/src/test/run-make/save-analysis/SubDir/mod.rs +++ b/src/test/run-make/save-analysis/SubDir/mod.rs @@ -12,21 +12,18 @@ use sub::sub2 as msalias; use sub::sub2; -use std::old_io::stdio::println; static yy: usize = 25; mod sub { pub mod sub2 { - use std::old_io::stdio::println; pub mod sub3 { - use std::old_io::stdio::println; pub fn hello() { - println("hello from module 3"); + println!("hello from module 3"); } } pub fn hello() { - println("hello from a module"); + println!("hello from a module"); } pub struct nested_struct { diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 56da6693939eb..fe0f32d97d6b1 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -10,7 +10,7 @@ #![ crate_name = "test" ] #![allow(unstable)] -#![feature(box_syntax, old_io, rustc_private, core, zero_one)] +#![feature(box_syntax, rustc_private, core, zero_one)] extern crate graphviz; // A simple rust project @@ -19,7 +19,6 @@ extern crate flate as myflate; use std::collections::{HashMap,HashSet}; use std::cell::RefCell; -use std::old_io::stdio::println; use sub::sub2 as msalias; @@ -61,15 +60,13 @@ fn test_tup_struct(x: TupStruct) -> isize { mod sub { pub mod sub2 { - use std::old_io::stdio::println; pub mod sub3 { - use std::old_io::stdio::println; pub fn hello() { - println("hello from module 3"); + println!("hello from module 3"); } } pub fn hello() { - println("hello from a module"); + println!("hello from a module"); } pub struct nested_struct { @@ -106,7 +103,7 @@ trait SomeTrait: SuperTrait { fn Method(&self, x: u32) -> u32; fn prov(&self, x: u32) -> u32 { - println(&x.to_string()); + println!("{}", &x.to_string()); 42 } fn provided_method(&self) -> u32 { @@ -122,7 +119,7 @@ trait SubTrait: SomeTrait { impl SomeTrait for some_fields { fn Method(&self, x: u32) -> u32 { - println(&x.to_string()); + println!("{}", &x.to_string()); self.field1 } } @@ -134,7 +131,7 @@ impl SubTrait for some_fields {} impl some_fields { fn stat(x: u32) -> u32 { - println(&x.to_string()); + println!("{}", &x.to_string()); 42 } fn stat2(x: &some_fields) -> u32 { @@ -194,20 +191,20 @@ enum SomeStructEnum { fn matchSomeEnum(val: SomeEnum) { match val { - SomeEnum::Ints(int1, int2) => { println(&(int1+int2).to_string()); } - SomeEnum::Floats(float1, float2) => { println(&(float2*float1).to_string()); } - SomeEnum::Strings(_, _, s3) => { println(s3); } + SomeEnum::Ints(int1, int2) => { println!("{}", &(int1+int2).to_string()); } + SomeEnum::Floats(float1, float2) => { println!("{}", &(float2*float1).to_string()); } + SomeEnum::Strings(_, _, s3) => { println!("{}", s3); } SomeEnum::MyTypes(mt1, mt2) => { - println(&(mt1.field1 - mt2.field1).to_string()); + println!("{}", &(mt1.field1 - mt2.field1).to_string()); } } } fn matchSomeStructEnum(se: SomeStructEnum) { match se { - SomeStructEnum::EnumStruct{a:a, ..} => println(&a.to_string()), - SomeStructEnum::EnumStruct2{f1:f1, f2:f_2} => println(&f_2.field1.to_string()), - SomeStructEnum::EnumStruct3{f1, ..} => println(&f1.field1.to_string()), + SomeStructEnum::EnumStruct{a:a, ..} => println!("{}", &a.to_string()), + SomeStructEnum::EnumStruct2{f1:f1, f2:f_2} => println!("{}", &f_2.field1.to_string()), + SomeStructEnum::EnumStruct3{f1, ..} => println!("{}", &f1.field1.to_string()), } } @@ -215,9 +212,9 @@ fn matchSomeStructEnum(se: SomeStructEnum) { fn matchSomeStructEnum2(se: SomeStructEnum) { use SomeStructEnum::*; match se { - EnumStruct{a: ref aaa, ..} => println(&aaa.to_string()), - EnumStruct2{f1, f2: f2} => println(&f1.field1.to_string()), - EnumStruct3{f1, f3: SomeEnum::Ints(_, _), f2} => println(&f1.field1.to_string()), + EnumStruct{a: ref aaa, ..} => println!("{}", &aaa.to_string()), + EnumStruct2{f1, f2: f2} => println!("{}", &f1.field1.to_string()), + EnumStruct3{f1, f3: SomeEnum::Ints(_, _), f2} => println!("{}", &f1.field1.to_string()), _ => {}, } } @@ -225,22 +222,22 @@ fn matchSomeStructEnum2(se: SomeStructEnum) { fn matchSomeOtherEnum(val: SomeOtherEnum) { use SomeOtherEnum::{SomeConst2, SomeConst3}; match val { - SomeOtherEnum::SomeConst1 => { println("I'm const1."); } - SomeConst2 | SomeConst3 => { println("I'm const2 or const3."); } + SomeOtherEnum::SomeConst1 => { println!("I'm const1."); } + SomeConst2 | SomeConst3 => { println!("I'm const2 or const3."); } } } fn hello((z, a) : (u32, String), ex: X) { SameDir2::hello(43); - println(&yy.to_string()); + println!("{}", &yy.to_string()); let (x, y): (u32, u32) = (5, 3); - println(&x.to_string()); - println(&z.to_string()); + println!("{}", &x.to_string()); + println!("{}", &z.to_string()); let x: u32 = x; - println(&x.to_string()); + println!("{}", &x.to_string()); let x = "hello"; - println(x); + println!("{}", x); let x = 32.0f32; let _ = (x + ((x * x) + 1.0).sqrt()).ln(); @@ -312,7 +309,7 @@ fn main() { // foo let s3: some_fields = some_fields{ field1: 55}; let s4: msalias::nested_struct = sub::sub2::nested_struct{ field2: 55}; let s4: msalias::nested_struct = sub2::nested_struct{ field2: 55}; - println(&s2.field1.to_string()); + println!("{}", &s2.field1.to_string()); let s5: MyType = box some_fields{ field1: 55}; let s = SameDir::SameStruct{name: "Bob".to_string()}; let s = SubDir::SubStruct{name:"Bob".to_string()}; diff --git a/src/test/run-make/unicode-input/multiple_files.rs b/src/test/run-make/unicode-input/multiple_files.rs index aa2ce78577121..b1fe938767dc9 100644 --- a/src/test/run-make/unicode-input/multiple_files.rs +++ b/src/test/run-make/unicode-input/multiple_files.rs @@ -14,7 +14,7 @@ use std::fs::File; use std::io::prelude::*; use std::path::Path; use std::process::Command; -use std::rand::{thread_rng, Rng}; +use std::__rand::{thread_rng, Rng}; use std::{char, env}; // creates unicode_input_multiple_files_{main,chars}.rs, where the diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index a70a160076520..0c01a84d1bf93 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -15,7 +15,7 @@ use std::io::prelude::*; use std::iter::repeat; use std::path::Path; use std::process::Command; -use std::rand::{thread_rng, Rng}; +use std::__rand::{thread_rng, Rng}; use std::{char, env}; // creates a file with `fn main() { }` and checks the diff --git a/src/test/run-pass-valgrind/cleanup-stdin.rs b/src/test/run-pass-valgrind/cleanup-stdin.rs index 301c4b917816a..dcdce50c1e9b5 100644 --- a/src/test/run-pass-valgrind/cleanup-stdin.rs +++ b/src/test/run-pass-valgrind/cleanup-stdin.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(old_io, io)] - fn main() { - let _ = std::old_io::stdin(); let _ = std::io::stdin(); + let _ = std::io::stdout(); + let _ = std::io::stderr(); } diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 14d8bce061f5a..f4b62eb2e7c50 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -11,11 +11,8 @@ // no-pretty-expanded FIXME #15189 // ignore-windows FIXME #13259 -#![feature(unboxed_closures)] -#![feature(unsafe_destructor, old_io, collections)] - use std::env; -use std::old_io::process::Command; +use std::process::{Command, Stdio}; use std::str; use std::ops::{Drop, FnMut, FnOnce}; @@ -40,44 +37,49 @@ fn double() { panic!("once"); } -fn runtest(me: &str) { - let mut template = Command::new(me); - template.env("IS_TEST", "1"); +fn template(me: &str) -> Command { + let mut m = Command::new(me); + m.env("IS_TEST", "1") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + return m; +} +fn runtest(me: &str) { // Make sure that the stack trace is printed - let p = template.clone().arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap(); + let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); - let s = str::from_utf8(&out.error).unwrap(); + let s = str::from_utf8(&out.stderr).unwrap(); assert!(s.contains("stack backtrace") && s.contains("foo::h"), "bad output: {}", s); // Make sure the stack trace is *not* printed // (Remove RUST_BACKTRACE from our own environment, in case developer // is running `make check` with it on.) - let p = template.clone().arg("fail").env_remove("RUST_BACKTRACE").spawn().unwrap(); + let p = template(me).arg("fail").env_remove("RUST_BACKTRACE").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); - let s = str::from_utf8(&out.error).unwrap(); + let s = str::from_utf8(&out.stderr).unwrap(); assert!(!s.contains("stack backtrace") && !s.contains("foo::h"), "bad output2: {}", s); // Make sure a stack trace is printed - let p = template.clone().arg("double-fail").spawn().unwrap(); + let p = template(me).arg("double-fail").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); - let s = str::from_utf8(&out.error).unwrap(); + let s = str::from_utf8(&out.stderr).unwrap(); // loosened the following from double::h to double:: due to // spurious failures on mac, 32bit, optimized assert!(s.contains("stack backtrace") && s.contains("double::"), "bad output3: {}", s); // Make sure a stack trace isn't printed too many times - let p = template.clone().arg("double-fail") + let p = template(me).arg("double-fail") .env("RUST_BACKTRACE", "1").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); - let s = str::from_utf8(&out.error).unwrap(); + let s = str::from_utf8(&out.stderr).unwrap(); let mut i = 0; for _ in 0..2 { i += s[i + 10..].find("stack backtrace").unwrap() + 10; diff --git a/src/test/run-pass/capturing-logging.rs b/src/test/run-pass/capturing-logging.rs deleted file mode 100644 index 6c58194f857a6..0000000000000 --- a/src/test/run-pass/capturing-logging.rs +++ /dev/null @@ -1,46 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// exec-env:RUST_LOG=info - - -#![allow(unknown_features)] -#![feature(box_syntax, old_io, rustc_private, std_misc)] - -#[macro_use] -extern crate log; - -use log::{set_logger, Logger, LogRecord}; -use std::sync::mpsc::channel; -use std::fmt; -use std::old_io::{ChanReader, ChanWriter, Reader, Writer}; -use std::thread; - -struct MyWriter(ChanWriter); - -impl Logger for MyWriter { - fn log(&mut self, record: &LogRecord) { - let MyWriter(ref mut inner) = *self; - write!(inner, "{}", record.args); - } -} - -fn main() { - let (tx, rx) = channel(); - let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx)); - let _t = thread::scoped(move|| { - set_logger(box MyWriter(w) as Box); - debug!("debug"); - info!("info"); - }); - let s = r.read_to_string().unwrap(); - assert!(s.contains("info")); - assert!(!s.contains("debug")); -} diff --git a/src/test/run-pass/closure-reform.rs b/src/test/run-pass/closure-reform.rs index fefab45714f77..50f05c050b173 100644 --- a/src/test/run-pass/closure-reform.rs +++ b/src/test/run-pass/closure-reform.rs @@ -14,7 +14,6 @@ #![feature(unboxed_closures, old_io)] use std::mem; -use std::old_io::stdio::println; fn call_it(f: F) where F : FnOnce(String) -> String @@ -62,7 +61,8 @@ pub fn main() { // External functions - call_bare(println); + fn foo(s: &str) {} + call_bare(foo); - call_bare_again(println); + call_bare_again(foo); } diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 03bf3851257df..df7cedd1c2938 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -16,34 +16,34 @@ // instead of in std. #![reexport_test_harness_main = "test_main"] -#![feature(old_io, libc, std_misc)] +#![feature(libc, std_misc)] extern crate libc; -use std::old_io::{Process, Command, timer}; -use std::time::Duration; +use std::process::{self, Command, Child, Output, Stdio}; use std::str; use std::sync::mpsc::channel; use std::thread; +use std::time::Duration; -macro_rules! succeed { ($e:expr) => ( - match $e { Ok(..) => {}, Err(e) => panic!("panic: {}", e) } -) } +macro_rules! t { + ($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("error: {}", e) }) +} fn test_destroy_once() { let mut p = sleeper(); - match p.signal_exit() { + match p.kill() { Ok(()) => {} Err(e) => panic!("error: {}", e), } } #[cfg(unix)] -pub fn sleeper() -> Process { +pub fn sleeper() -> Child { Command::new("sleep").arg("1000").spawn().unwrap() } #[cfg(windows)] -pub fn sleeper() -> Process { +pub fn sleeper() -> Child { // There's a `timeout` command on windows, but it doesn't like having // its output piped, so instead just ping ourselves a few times with // gaps in between so we're sure this process is alive for awhile @@ -52,16 +52,12 @@ pub fn sleeper() -> Process { fn test_destroy_twice() { let mut p = sleeper(); - succeed!(p.signal_exit()); // this shouldn't crash... - let _ = p.signal_exit(); // ...and nor should this (and nor should the destructor) + t!(p.kill()); // this shouldn't crash... + let _ = p.kill(); // ...and nor should this (and nor should the destructor) } -pub fn test_destroy_actually_kills(force: bool) { - use std::old_io::process::{Command, ProcessOutput, ExitStatus, ExitSignal}; - use std::old_io::timer; - use libc; - use std::str; - +#[test] +fn test_destroy_actually_kills() { #[cfg(all(unix,not(target_os="android")))] static BLOCK_COMMAND: &'static str = "cat"; @@ -72,36 +68,25 @@ pub fn test_destroy_actually_kills(force: bool) { static BLOCK_COMMAND: &'static str = "cmd"; // this process will stay alive indefinitely trying to read from stdin - let mut p = Command::new(BLOCK_COMMAND).spawn().unwrap(); - - assert!(p.signal(0).is_ok()); + let mut p = Command::new(BLOCK_COMMAND) + .stdin(Stdio::piped()) + .spawn().unwrap(); - if force { - p.signal_kill().unwrap(); - } else { - p.signal_exit().unwrap(); - } + p.kill().unwrap(); // Don't let this test time out, this should be quick - let (tx, rx1) = channel(); - let mut t = timer::Timer::new().unwrap(); - let rx2 = t.oneshot(Duration::milliseconds(1000)); + let (tx, rx) = channel(); thread::spawn(move|| { - select! { - _ = rx2.recv() => unsafe { libc::exit(1) }, - _ = rx1.recv() => {} + thread::sleep_ms(1000); + if rx.try_recv().is_err() { + process::exit(1); } }); - match p.wait().unwrap() { - ExitStatus(..) => panic!("expected a signal"), - ExitSignal(..) => tx.send(()).unwrap(), + let code = p.wait().unwrap().code(); + if cfg!(windows) { + assert!(code.is_some()); + } else { + assert!(code.is_none()); } -} - -fn test_unforced_destroy_actually_kills() { - test_destroy_actually_kills(false); -} - -fn test_forced_destroy_actually_kills() { - test_destroy_actually_kills(true); + tx.send(()); } diff --git a/src/test/run-pass/deriving-global.rs b/src/test/run-pass/deriving-global.rs index 105d421b40415..10e8ddc41f3f9 100644 --- a/src/test/run-pass/deriving-global.rs +++ b/src/test/run-pass/deriving-global.rs @@ -11,7 +11,6 @@ #![feature(rand, rustc_private)] extern crate serialize; -extern crate rand; mod submod { // if any of these are implemented without global calls for any @@ -20,21 +19,21 @@ mod submod { #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, - Debug, Rand, + Debug, Encodable, Decodable)] enum A { A1(usize), A2(isize) } #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, - Debug, Rand, + Debug, Encodable, Decodable)] struct B { x: usize, y: isize } #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, - Debug, Rand, + Debug, Encodable, Decodable)] struct C(usize, isize); diff --git a/src/test/run-pass/deriving-rand.rs b/src/test/run-pass/deriving-rand.rs deleted file mode 100644 index bc11b55d3105f..0000000000000 --- a/src/test/run-pass/deriving-rand.rs +++ /dev/null @@ -1,43 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#![feature(rand)] - -use std::rand; - -#[derive(Rand)] -struct A; - -#[derive(Rand)] -struct B(isize, isize); - -#[derive(Rand)] -struct C { - x: f64, - y: (u8, u8) -} - -#[derive(Rand)] -enum D { - D0, - D1(usize), - D2 { x: (), y: () } -} - -pub fn main() { - // check there's no segfaults - for _ in 0..20 { - rand::random::(); - rand::random::(); - rand::random::(); - rand::random::(); - } -} diff --git a/src/test/run-pass/drop-flag-sanity-check.rs b/src/test/run-pass/drop-flag-sanity-check.rs index 02f6cc70fd5b8..f9e1b651a4933 100644 --- a/src/test/run-pass/drop-flag-sanity-check.rs +++ b/src/test/run-pass/drop-flag-sanity-check.rs @@ -17,10 +17,8 @@ // // See also drop-flag-skip-sanity-check.rs. -#![feature(old_io)] - use std::env; -use std::old_io::process::{Command, ExitSignal, ExitStatus}; +use std::process::Command; fn main() { let args: Vec = env::args().collect(); diff --git a/src/test/run-pass/drop-flag-skip-sanity-check.rs b/src/test/run-pass/drop-flag-skip-sanity-check.rs index 7066b4017af23..aaf5eb6f2a14b 100644 --- a/src/test/run-pass/drop-flag-skip-sanity-check.rs +++ b/src/test/run-pass/drop-flag-skip-sanity-check.rs @@ -17,10 +17,8 @@ // // See also drop-flag-sanity-check.rs. -#![feature(old_io)] - use std::env; -use std::old_io::process::{Command, ExitSignal, ExitStatus}; +use std::process::Command; fn main() { let args: Vec = env::args().collect(); @@ -28,9 +26,9 @@ fn main() { return test(); } - let mut p = Command::new(&args[0]).arg("test").spawn().unwrap(); + let s = Command::new(&args[0]).arg("test").status().unwrap(); // Invocatinn should succeed as drop-flag sanity check is skipped. - assert!(p.wait().unwrap().success()); + assert!(s.success()); } #[derive(Debug)] diff --git a/src/test/run-pass/issue-10626.rs b/src/test/run-pass/issue-10626.rs index 2c0811b69e020..0d8f22254857d 100644 --- a/src/test/run-pass/issue-10626.rs +++ b/src/test/run-pass/issue-10626.rs @@ -15,7 +15,7 @@ #![feature(old_io)] use std::env; -use std::old_io::process; +use std::process::{Command, Stdio}; pub fn main () { let args: Vec = env::args().collect(); @@ -29,7 +29,7 @@ pub fn main () { return; } - let mut p = process::Command::new(&args[0]); - p.arg("child").stdout(process::Ignored).stderr(process::Ignored); + let mut p = Command::new(&args[0]); + p.arg("child").stdout(Stdio::null()).stderr(Stdio::null()); println!("{:?}", p.spawn().unwrap().wait()); } diff --git a/src/test/run-pass/issue-12684.rs b/src/test/run-pass/issue-12684.rs deleted file mode 100644 index 2b89915516469..0000000000000 --- a/src/test/run-pass/issue-12684.rs +++ /dev/null @@ -1,26 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// pretty-expanded FIXME #23616 - -#![feature(old_io, std_misc)] - -use std::time::Duration; -use std::thread; - -fn main() { - thread::spawn(move|| customtask()).join().ok().unwrap(); -} - -fn customtask() { - let mut timer = std::old_io::timer::Timer::new().unwrap(); - let periodic = timer.periodic(Duration::milliseconds(10)); - periodic.recv(); -} diff --git a/src/test/run-pass/issue-12699.rs b/src/test/run-pass/issue-12699.rs index ac5a9b728b992..1e9f30bb766b2 100644 --- a/src/test/run-pass/issue-12699.rs +++ b/src/test/run-pass/issue-12699.rs @@ -8,13 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(old_io, std_misc)] - -use std::old_io::timer; -use std::time::Duration; +use std::thread; fn main() { - timer::sleep(Duration::milliseconds(250)); + thread::sleep_ms(250); } diff --git a/src/test/run-pass/issue-14901.rs b/src/test/run-pass/issue-14901.rs index 7e7886e3a6e76..566836784696d 100644 --- a/src/test/run-pass/issue-14901.rs +++ b/src/test/run-pass/issue-14901.rs @@ -8,11 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(old_io)] - -use std::old_io::Reader; +pub trait Reader {} enum Wrapper<'a> { WrapReader(&'a (Reader + 'a)) diff --git a/src/test/run-pass/issue-15149.rs b/src/test/run-pass/issue-15149.rs index f6ffd03c81aee..500235b74f684 100644 --- a/src/test/run-pass/issue-15149.rs +++ b/src/test/run-pass/issue-15149.rs @@ -10,14 +10,15 @@ // no-prefer-dynamic +#![feature(rustc_private)] -#![feature(fs, process, env, path, rand)] +extern crate rustc_back; use std::env; use std::fs; use std::process; -use std::rand::random; use std::str; +use rustc_back::tempdir::TempDir; fn main() { // If we're the child, make sure we were invoked correctly @@ -27,7 +28,8 @@ fn main() { // checking that it ends_with the executable name. This // is needed because of Windows, which has a different behavior. // See #15149 for more info. - return assert!(args[0].ends_with(&format!("mytest{}", env::consts::EXE_SUFFIX))); + return assert!(args[0].ends_with(&format!("mytest{}", + env::consts::EXE_SUFFIX))); } test(); @@ -38,9 +40,8 @@ fn test() { let my_path = env::current_exe().unwrap(); let my_dir = my_path.parent().unwrap(); - let random_u32: u32 = random(); - let child_dir = my_dir.join(&format!("issue-15149-child-{}", random_u32)); - fs::create_dir(&child_dir).unwrap(); + let child_dir = TempDir::new_in(&my_dir, "issue-15140-child").unwrap(); + let child_dir = child_dir.path(); let child_path = child_dir.join(&format!("mytest{}", env::consts::EXE_SUFFIX)); diff --git a/src/test/run-pass/issue-18619.rs b/src/test/run-pass/issue-18619.rs deleted file mode 100644 index a256e61921686..0000000000000 --- a/src/test/run-pass/issue-18619.rs +++ /dev/null @@ -1,19 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// pretty-expanded FIXME #23616 - -#![feature(old_io)] - -use std::old_io::FileType; - -pub fn main() { - let _ = FileType::RegularFile.clone(); -} diff --git a/src/test/run-pass/issue-2904.rs b/src/test/run-pass/issue-2904.rs index b05baa24b7aa1..2c45d664d894e 100644 --- a/src/test/run-pass/issue-2904.rs +++ b/src/test/run-pass/issue-2904.rs @@ -11,10 +11,8 @@ // Map representation -#![feature(old_io)] - -use std::old_io; use std::fmt; +use std::io::prelude::*; use square::{bot, wall, rock, lambda, closed_lift, open_lift, earth, empty}; enum square { @@ -60,9 +58,9 @@ fn square_from_char(c: char) -> square { } } -fn read_board_grid(mut input: rdr) +fn read_board_grid(mut input: rdr) -> Vec> { - let mut input: &mut old_io::Reader = &mut input; + let mut input: &mut Read = &mut input; let mut grid = Vec::new(); let mut line = [0; 10]; input.read(&mut line); diff --git a/src/test/run-pass/issue-3424.rs b/src/test/run-pass/issue-3424.rs index 29d963bb70468..74e58f31e23e2 100644 --- a/src/test/run-pass/issue-3424.rs +++ b/src/test/run-pass/issue-3424.rs @@ -10,24 +10,17 @@ // rustc --test ignores2.rs && ./ignores2 -#![allow(unknown_features)] -#![feature(unboxed_closures, old_path, std_misc)] +pub struct Path; -use std::old_path::Path; -use std::old_path; -use std::result; -use std::thunk::Thunk; - -type rsrc_loader = Box (result::Result) + 'static>; +type rsrc_loader = Box Result>; fn tester() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - let mut loader: rsrc_loader = Box::new(move|_path| { - result::Result::Ok("more blah".to_string()) + let mut loader: rsrc_loader = Box::new(move |_path| { + Ok("more blah".to_string()) }); - let path = old_path::Path::new("blah"); + let path = Path; assert!(loader(&path).is_ok()); } diff --git a/src/test/run-pass/issue-4446.rs b/src/test/run-pass/issue-4446.rs index 9f8d93461a263..9292a9c608eb9 100644 --- a/src/test/run-pass/issue-4446.rs +++ b/src/test/run-pass/issue-4446.rs @@ -8,11 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(old_io)] - -use std::old_io::println; use std::sync::mpsc::channel; use std::thread; @@ -22,6 +17,6 @@ pub fn main() { tx.send("hello, world").unwrap(); thread::spawn(move|| { - println(rx.recv().unwrap()); + println!("{}", rx.recv().unwrap()); }).join().ok().unwrap(); } diff --git a/src/test/run-pass/issue-5988.rs b/src/test/run-pass/issue-5988.rs index 8ec88d55721d3..2cf0089c6bb65 100644 --- a/src/test/run-pass/issue-5988.rs +++ b/src/test/run-pass/issue-5988.rs @@ -10,9 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(old_io)] - -use std::old_io; trait B { fn f(&self); } @@ -23,7 +20,7 @@ trait T : B { struct A; impl B for U { - fn f(&self) { old_io::println("Hey, I'm a T!"); } + fn f(&self) { } } impl T for A { diff --git a/src/test/run-pass/issue-8398.rs b/src/test/run-pass/issue-8398.rs index 8eb10a199eaae..5c2c03f9857f3 100644 --- a/src/test/run-pass/issue-8398.rs +++ b/src/test/run-pass/issue-8398.rs @@ -10,11 +10,11 @@ // pretty-expanded FIXME #23616 -#![feature(old_io, io)] - -use std::old_io; +pub trait Writer { + fn write(&mut self, b: &[u8]) -> Result<(), ()>; +} -fn foo(a: &mut old_io::Writer) { +fn foo(a: &mut Writer) { a.write(&[]).unwrap(); } diff --git a/src/test/run-pass/issue-9396.rs b/src/test/run-pass/issue-9396.rs index bfaf060e43c30..394fd84781d59 100644 --- a/src/test/run-pass/issue-9396.rs +++ b/src/test/run-pass/issue-9396.rs @@ -8,20 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(old_io, std_misc)] - use std::sync::mpsc::{TryRecvError, channel}; -use std::old_io::timer::Timer; use std::thread; -use std::time::Duration; pub fn main() { let (tx, rx) = channel(); let _t = thread::scoped(move||{ - let mut timer = Timer::new().unwrap(); - timer.sleep(Duration::milliseconds(10)); + thread::sleep_ms(10); tx.send(()).unwrap(); }); loop { diff --git a/src/test/run-pass/logging-separate-lines.rs b/src/test/run-pass/logging-separate-lines.rs index b27080b65b781..29cfe91eba5ac 100644 --- a/src/test/run-pass/logging-separate-lines.rs +++ b/src/test/run-pass/logging-separate-lines.rs @@ -17,7 +17,7 @@ #[macro_use] extern crate log; -use std::old_io::Command; +use std::process::Command; use std::env; use std::str; @@ -31,9 +31,9 @@ fn main() { let p = Command::new(&args[0]) .arg("child") - .spawn().unwrap().wait_with_output().unwrap(); + .output().unwrap(); assert!(p.status.success()); - let mut lines = str::from_utf8(&p.error).unwrap().lines(); + let mut lines = str::from_utf8(&p.stderr).unwrap().lines(); assert!(lines.next().unwrap().contains("foo")); assert!(lines.next().unwrap().contains("bar")); } diff --git a/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs index 25e0b272fd2e5..1611a2c07227a 100644 --- a/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs +++ b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs @@ -17,7 +17,8 @@ use std::mem; use std::slice; -use std::old_io::IoResult; + +pub type IoResult = Result; trait MyWriter { fn my_write(&mut self, buf: &[u8]) -> IoResult<()>; diff --git a/src/test/run-pass/out-of-stack-new-thread-no-split.rs b/src/test/run-pass/out-of-stack-new-thread-no-split.rs index f08ed6e7f9cdc..d321d9142ca6e 100644 --- a/src/test/run-pass/out-of-stack-new-thread-no-split.rs +++ b/src/test/run-pass/out-of-stack-new-thread-no-split.rs @@ -14,9 +14,9 @@ //ignore-dragonfly //ignore-bitrig -#![feature(asm, old_io, std_misc)] +#![feature(asm)] -use std::old_io::process::Command; +use std::process::Command; use std::env; use std::thread; @@ -41,7 +41,7 @@ fn main() { } else { let recurse = Command::new(&args[0]).arg("recurse").output().unwrap(); assert!(!recurse.status.success()); - let error = String::from_utf8_lossy(&recurse.error); + let error = String::from_utf8_lossy(&recurse.stderr); println!("wut"); println!("`{}`", error); assert!(error.contains("has overflowed its stack")); diff --git a/src/test/run-pass/out-of-stack-no-split.rs b/src/test/run-pass/out-of-stack-no-split.rs index 8887e1937c6f7..da7342d251e6e 100644 --- a/src/test/run-pass/out-of-stack-no-split.rs +++ b/src/test/run-pass/out-of-stack-no-split.rs @@ -8,16 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-android -//ignore-linux -//ignore-freebsd -//ignore-ios -//ignore-dragonfly -//ignore-bitrig +// ignore-android +// ignore-linux +// ignore-freebsd +// ignore-ios +// ignore-dragonfly +// ignore-bitrig -#![feature(asm, old_io)] +#![feature(asm)] -use std::old_io::process::Command; +use std::process::Command; use std::env; // lifted from the test module @@ -41,7 +41,7 @@ fn main() { } else { let recurse = Command::new(&args[0]).arg("recurse").output().unwrap(); assert!(!recurse.status.success()); - let error = String::from_utf8_lossy(&recurse.error); + let error = String::from_utf8_lossy(&recurse.stderr); assert!(error.contains("has overflowed its stack")); } } diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs index 47f83eab4c1f4..d90b88cbfd573 100644 --- a/src/test/run-pass/out-of-stack.rs +++ b/src/test/run-pass/out-of-stack.rs @@ -10,9 +10,9 @@ // ignore-android: FIXME (#20004) -#![feature(asm, old_io)] +#![feature(asm)] -use std::old_io::process::Command; +use std::process::Command; use std::env; // lifted from the test module @@ -42,12 +42,12 @@ fn main() { } else { let silent = Command::new(&args[0]).arg("silent").output().unwrap(); assert!(!silent.status.success()); - let error = String::from_utf8_lossy(&silent.error); + let error = String::from_utf8_lossy(&silent.stderr); assert!(error.contains("has overflowed its stack")); let loud = Command::new(&args[0]).arg("loud").output().unwrap(); assert!(!loud.status.success()); - let error = String::from_utf8_lossy(&silent.error); + let error = String::from_utf8_lossy(&silent.stderr); assert!(error.contains("has overflowed its stack")); } } diff --git a/src/test/run-pass/process-remove-from-env.rs b/src/test/run-pass/process-remove-from-env.rs index c6adda6067936..3096fe4a266c9 100644 --- a/src/test/run-pass/process-remove-from-env.rs +++ b/src/test/run-pass/process-remove-from-env.rs @@ -9,9 +9,7 @@ // except according to those terms. -#![feature(old_io)] - -use std::old_io::Command; +use std::process::Command; use std::env; #[cfg(all(unix, not(target_os="android")))] @@ -49,7 +47,7 @@ fn main() { let prog = cmd.spawn().unwrap(); let result = prog.wait_with_output().unwrap(); - let output = String::from_utf8_lossy(&result.output); + let output = String::from_utf8_lossy(&result.stdout); assert!(!output.contains("RUN_TEST_NEW_ENV"), "found RUN_TEST_NEW_ENV inside of:\n\n{}", output); diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs index abad08c7ac6b3..31d97305e0be4 100644 --- a/src/test/run-pass/running-with-no-runtime.rs +++ b/src/test/run-pass/running-with-no-runtime.rs @@ -11,7 +11,7 @@ #![feature(start, os, std_misc, old_io)] use std::ffi::CStr; -use std::old_io::process::{Command, ProcessOutput}; +use std::process::{Command, Output}; use std::os; use std::rt::unwind::try; use std::rt; @@ -23,12 +23,12 @@ use std::thunk::Thunk; fn start(argc: isize, argv: *const *const u8) -> isize { if argc > 1 { unsafe { - match **argv.offset(1) { - 1 => {} - 2 => println!("foo"), - 3 => assert!(try(|| {}).is_ok()), - 4 => assert!(try(|| panic!()).is_err()), - 5 => assert!(Command::new("test").spawn().is_err()), + match **argv.offset(1) as char { + '1' => {} + '2' => println!("foo"), + '3' => assert!(try(|| {}).is_ok()), + '4' => assert!(try(|| panic!()).is_err()), + '5' => assert!(Command::new("test").spawn().is_err()), _ => panic!() } } @@ -41,25 +41,20 @@ fn start(argc: isize, argv: *const *const u8) -> isize { CStr::from_ptr(ptr).to_bytes().to_vec() }).collect::>() }; - let me = &*args[0]; + let me = String::from_utf8(args[0].to_vec()).unwrap(); - let x: &[u8] = &[1]; - pass(Command::new(me).arg(x).output().unwrap()); - let x: &[u8] = &[2]; - pass(Command::new(me).arg(x).output().unwrap()); - let x: &[u8] = &[3]; - pass(Command::new(me).arg(x).output().unwrap()); - let x: &[u8] = &[4]; - pass(Command::new(me).arg(x).output().unwrap()); - let x: &[u8] = &[5]; - pass(Command::new(me).arg(x).output().unwrap()); + pass(Command::new(&me).arg("1").output().unwrap()); + pass(Command::new(&me).arg("2").output().unwrap()); + pass(Command::new(&me).arg("3").output().unwrap()); + pass(Command::new(&me).arg("4").output().unwrap()); + pass(Command::new(&me).arg("5").output().unwrap()); 0 } -fn pass(output: ProcessOutput) { +fn pass(output: Output) { if !output.status.success() { - println!("{:?}", str::from_utf8(&output.output)); - println!("{:?}", str::from_utf8(&output.error)); + println!("{:?}", str::from_utf8(&output.stdout)); + println!("{:?}", str::from_utf8(&output.stderr)); } } diff --git a/src/test/run-pass/segfault-no-out-of-stack.rs b/src/test/run-pass/segfault-no-out-of-stack.rs index 385c5326c978e..dd33c330cfd36 100644 --- a/src/test/run-pass/segfault-no-out-of-stack.rs +++ b/src/test/run-pass/segfault-no-out-of-stack.rs @@ -9,9 +9,7 @@ // except according to those terms. -#![feature(old_io)] - -use std::old_io::process::Command; +use std::process::Command; use std::env; fn main() { @@ -21,7 +19,7 @@ fn main() { } else { let segfault = Command::new(&args[0]).arg("segfault").output().unwrap(); assert!(!segfault.status.success()); - let error = String::from_utf8_lossy(&segfault.error); + let error = String::from_utf8_lossy(&segfault.stderr); assert!(!error.contains("has overflowed its stack")); } } diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs index bfc4aee7757a5..51b369092f0f4 100644 --- a/src/test/run-pass/signal-exit-status.rs +++ b/src/test/run-pass/signal-exit-status.rs @@ -10,11 +10,8 @@ // ignore-windows -#![feature(old_io)] -#![feature(os)] - use std::env; -use std::old_io::process::{Command, ExitSignal, ExitStatus}; +use std::process::Command; pub fn main() { let args: Vec = env::args().collect(); @@ -23,11 +20,6 @@ pub fn main() { unsafe { *(0 as *mut isize) = 0; } } else { let status = Command::new(&args[0]).arg("signal").status().unwrap(); - // Windows does not have signal, so we get exit status 0xC0000028 (STATUS_BAD_STACK). - match status { - ExitSignal(_) if cfg!(unix) => {}, - ExitStatus(0xC0000028) if cfg!(windows) => {}, - _ => panic!("invalid termination (was not signalled): {}", status) - } + assert!(status.code().is_none()); } } diff --git a/src/test/run-pass/tcp-accept-stress.rs b/src/test/run-pass/tcp-accept-stress.rs deleted file mode 100644 index 00467e563347a..0000000000000 --- a/src/test/run-pass/tcp-accept-stress.rs +++ /dev/null @@ -1,88 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-macos osx really doesn't like cycling through large numbers of -// sockets as calls to connect() will start returning EADDRNOTAVAIL -// quite quickly and it takes a few seconds for the sockets to get -// recycled. - -#![feature(old_io, io, std_misc)] - -use std::old_io::{TcpListener, Listener, Acceptor, EndOfFile, TcpStream}; -use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::mpsc::channel; -use std::thread; - -static N: usize = 8; -static M: usize = 20; - -fn main() { - test(); -} - -fn test() { - let mut l = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = l.socket_name().unwrap(); - let mut a = l.listen().unwrap(); - let cnt = Arc::new(AtomicUsize::new(0)); - - let (srv_tx, srv_rx) = channel(); - let (cli_tx, cli_rx) = channel(); - let _t = (0..N).map(|_| { - let a = a.clone(); - let cnt = cnt.clone(); - let srv_tx = srv_tx.clone(); - thread::scoped(move|| { - let mut a = a; - loop { - match a.accept() { - Ok(..) => { - if cnt.fetch_add(1, Ordering::SeqCst) == N * M - 1 { - break - } - } - Err(ref e) if e.kind == EndOfFile => break, - Err(e) => panic!("{}", e), - } - } - srv_tx.send(()); - }) - }).collect::>(); - - let _t = (0..N).map(|_| { - let cli_tx = cli_tx.clone(); - thread::scoped(move|| { - for _ in 0..M { - let _s = TcpStream::connect(addr).unwrap(); - } - cli_tx.send(()); - }) - }).collect::>(); - drop((cli_tx, srv_tx)); - - // wait for senders - if cli_rx.iter().take(N).count() != N { - a.close_accept().unwrap(); - panic!("clients panicked"); - } - - // wait for one acceptor to die - let _ = srv_rx.recv(); - - // Notify other receivers should die - a.close_accept().unwrap(); - - // wait for receivers - assert_eq!(srv_rx.iter().take(N - 1).count(), N - 1); - - // Everything should have been accepted. - assert_eq!(cnt.load(Ordering::SeqCst), N * M); -} diff --git a/src/test/run-pass/tcp-connect-timeouts.rs b/src/test/run-pass/tcp-connect-timeouts.rs deleted file mode 100644 index 64f07a60b3503..0000000000000 --- a/src/test/run-pass/tcp-connect-timeouts.rs +++ /dev/null @@ -1,76 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-pretty -// compile-flags:--test -// exec-env:RUST_TEST_THREADS=1 - -// Tests for the connect_timeout() function on a TcpStream. This runs with only -// one test task to ensure that errors are timeouts, not file descriptor -// exhaustion. - -#![reexport_test_harness_main = "test_main"] - -#![allow(unused_imports)] -#![feature(old_io, std_misc, io)] - -use std::old_io::*; -use std::old_io::test::*; -use std::old_io; -use std::time::Duration; -use std::sync::mpsc::channel; -use std::thread; - -#[cfg_attr(target_os = "freebsd", ignore)] -fn eventual_timeout() { - let addr = next_test_ip4(); - - let (tx1, rx1) = channel(); - let (_tx2, rx2) = channel::<()>(); - let _t = thread::scoped(move|| { - let _l = TcpListener::bind(addr).unwrap().listen(); - tx1.send(()).unwrap(); - let _ = rx2.recv(); - }); - rx1.recv().unwrap(); - - let mut v = Vec::new(); - for _ in 0_usize..10000 { - match TcpStream::connect_timeout(addr, Duration::milliseconds(100)) { - Ok(e) => v.push(e), - Err(ref e) if e.kind == old_io::TimedOut => return, - Err(e) => panic!("other error: {}", e), - } - } - panic!("never timed out!"); -} - -fn timeout_success() { - let addr = next_test_ip4(); - let _l = TcpListener::bind(addr).unwrap().listen(); - - assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(1000)).is_ok()); -} - -fn timeout_error() { - let addr = next_test_ip4(); - - assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(1000)).is_err()); -} - -fn connect_timeout_zero() { - let addr = next_test_ip4(); - assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(0)).is_err()); -} - -fn connect_timeout_negative() { - let addr = next_test_ip4(); - assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(-1)).is_err()); -} diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index f6952ad64f1f3..c47b95bec2b52 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -8,65 +8,46 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-linux see joyent/libuv#1189 // ignore-android needs extra network permissions // ignore-openbsd system ulimit (Too many open files) // ignore-bitrig system ulimit (Too many open files) -// exec-env:RUST_LOG=debug - -#![feature(rustc_private, libc, old_io, io, std_misc)] -#![allow(deprecated, unused_must_use)] - -#[macro_use] -extern crate log; -extern crate libc; +use std::io::prelude::*; +use std::net::{TcpListener, TcpStream}; +use std::process; use std::sync::mpsc::channel; -use std::old_io::net::tcp::{TcpListener, TcpStream}; -use std::old_io::{Acceptor, Listener, Reader, Writer}; use std::thread::{self, Builder}; -use std::time::Duration; fn main() { // This test has a chance to time out, try to not let it time out thread::spawn(move|| -> () { - use std::old_io::timer; - timer::sleep(Duration::milliseconds(30 * 1000)); - println!("timed out!"); - unsafe { libc::exit(1) } + thread::sleep_ms(30 * 1000); + process::exit(1); }); - let (tx, rx) = channel(); + let mut listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); thread::spawn(move || -> () { - let mut listener = TcpListener::bind("127.0.0.1:0").unwrap(); - tx.send(listener.socket_name().unwrap()).unwrap(); - let mut acceptor = listener.listen(); loop { - let mut stream = match acceptor.accept() { - Ok(stream) => stream, - Err(error) => { - debug!("accept panicked: {}", error); - continue; - } + let mut stream = match listener.accept() { + Ok(stream) => stream.0, + Err(error) => continue, }; - stream.read_byte(); + stream.read(&mut [0]); stream.write(&[2]); } }); - let addr = rx.recv().unwrap(); let (tx, rx) = channel(); for _ in 0..1000 { let tx = tx.clone(); Builder::new().stack_size(64 * 1024).spawn(move|| { match TcpStream::connect(addr) { - Ok(stream) => { - let mut stream = stream; + Ok(mut stream) => { stream.write(&[1]); - let mut buf = [0]; - stream.read(&mut buf); + stream.read(&mut [0]); }, - Err(e) => debug!("{}", e) + Err(..) => {} } tx.send(()).unwrap(); }); @@ -78,5 +59,5 @@ fn main() { for _ in 0..1000 { rx.recv().unwrap(); } - unsafe { libc::exit(0) } + process::exit(0); } diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs deleted file mode 100644 index 49fac24d0b3a5..0000000000000 --- a/src/test/run-pass/tempfile.rs +++ /dev/null @@ -1,213 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-windows TempDir may cause IoError on windows: #10463 - -// These tests are here to exercise the functionality of the `tempfile` module. -// One might expect these tests to be located in that module, but sadly they -// cannot. The tests need to invoke `os::change_dir` which cannot be done in the -// normal test infrastructure. If the tests change the current working -// directory, then *all* tests which require relative paths suddenly break b/c -// they're in a different location than before. Hence, these tests are all run -// serially here. - -#![feature(old_io, old_path, os, old_fs)] - -use std::old_path::{Path, GenericPath}; -use std::old_io::fs::PathExtensions; -use std::old_io::{fs, TempDir}; -use std::old_io; -use std::env; -use std::sync::mpsc::channel; -use std::thread; - -fn test_tempdir() { - let path = { - let p = TempDir::new_in(&Path::new("."), "foobar").unwrap(); - let p = p.path(); - assert!(p.as_str().unwrap().contains("foobar")); - p.clone() - }; - assert!(!path.exists()); -} - -fn test_rm_tempdir() { - let (tx, rx) = channel(); - let f = move|| -> () { - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - tx.send(tmp.path().clone()).unwrap(); - panic!("panic to unwind past `tmp`"); - }; - thread::spawn(f).join(); - let path = rx.recv().unwrap(); - assert!(!path.exists()); - - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - let path = tmp.path().clone(); - let f = move|| -> () { - let _tmp = tmp; - panic!("panic to unwind past `tmp`"); - }; - thread::spawn(f).join(); - assert!(!path.exists()); - - let path; - { - let f = move || { - TempDir::new("test_rm_tempdir").unwrap() - }; - // FIXME(#16640) `: TempDir` annotation shouldn't be necessary - let tmp: TempDir = thread::scoped(f).join(); - path = tmp.path().clone(); - assert!(path.exists()); - } - assert!(!path.exists()); - - let path; - { - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - path = tmp.into_inner(); - } - assert!(path.exists()); - fs::rmdir_recursive(&path); - assert!(!path.exists()); -} - -fn test_rm_tempdir_close() { - let (tx, rx) = channel(); - let f = move|| -> () { - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - tx.send(tmp.path().clone()).unwrap(); - tmp.close(); - panic!("panic when unwinding past `tmp`"); - }; - thread::spawn(f).join(); - let path = rx.recv().unwrap(); - assert!(!path.exists()); - - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - let path = tmp.path().clone(); - let f = move|| -> () { - let tmp = tmp; - tmp.close(); - panic!("panic when unwinding past `tmp`"); - }; - thread::spawn(f).join(); - assert!(!path.exists()); - - let path; - { - let f = move || { - TempDir::new("test_rm_tempdir").unwrap() - }; - // FIXME(#16640) `: TempDir` annotation shouldn't be necessary - let tmp: TempDir = thread::scoped(f).join(); - path = tmp.path().clone(); - assert!(path.exists()); - tmp.close(); - } - assert!(!path.exists()); - - let path; - { - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - path = tmp.into_inner(); - } - assert!(path.exists()); - fs::rmdir_recursive(&path); - assert!(!path.exists()); -} - -// Ideally these would be in std::os but then core would need -// to depend on std -fn recursive_mkdir_rel() { - let path = Path::new("frob"); - let cwd = Path::new(env::current_dir().unwrap().to_str().unwrap()); - println!("recursive_mkdir_rel: Making: {} in cwd {} [{}]", path.display(), - cwd.display(), path.exists()); - fs::mkdir_recursive(&path, old_io::USER_RWX); - assert!(path.is_dir()); - fs::mkdir_recursive(&path, old_io::USER_RWX); - assert!(path.is_dir()); -} - -fn recursive_mkdir_dot() { - let dot = Path::new("."); - fs::mkdir_recursive(&dot, old_io::USER_RWX); - let dotdot = Path::new(".."); - fs::mkdir_recursive(&dotdot, old_io::USER_RWX); -} - -fn recursive_mkdir_rel_2() { - let path = Path::new("./frob/baz"); - let cwd = Path::new(env::current_dir().unwrap().to_str().unwrap()); - println!("recursive_mkdir_rel_2: Making: {} in cwd {} [{}]", path.display(), - cwd.display(), path.exists()); - fs::mkdir_recursive(&path, old_io::USER_RWX); - assert!(path.is_dir()); - assert!(path.dir_path().is_dir()); - let path2 = Path::new("quux/blat"); - println!("recursive_mkdir_rel_2: Making: {} in cwd {}", path2.display(), - cwd.display()); - fs::mkdir_recursive(&path2, old_io::USER_RWX); - assert!(path2.is_dir()); - assert!(path2.dir_path().is_dir()); -} - -// Ideally this would be in core, but needs TempFile -pub fn test_rmdir_recursive_ok() { - let rwx = old_io::USER_RWX; - - let tmpdir = TempDir::new("test").ok().expect("test_rmdir_recursive_ok: \ - couldn't create temp dir"); - let tmpdir = tmpdir.path(); - let root = tmpdir.join("foo"); - - println!("making {}", root.display()); - fs::mkdir(&root, rwx); - fs::mkdir(&root.join("foo"), rwx); - fs::mkdir(&root.join("foo").join("bar"), rwx); - fs::mkdir(&root.join("foo").join("bar").join("blat"), rwx); - fs::rmdir_recursive(&root); - assert!(!root.exists()); - assert!(!root.join("bar").exists()); - assert!(!root.join("bar").join("blat").exists()); -} - -pub fn dont_double_panic() { - let r: Result<(), _> = thread::spawn(move|| { - let tmpdir = TempDir::new("test").unwrap(); - // Remove the temporary directory so that TempDir sees - // an error on drop - fs::rmdir(tmpdir.path()); - // Panic. If TempDir panics *again* due to the rmdir - // error then the process will abort. - panic!(); - }).join(); - assert!(r.is_err()); -} - -fn in_tmpdir(f: F) where F: FnOnce() { - let tmpdir = TempDir::new("test").ok().expect("can't make tmpdir"); - assert!(env::set_current_dir(tmpdir.path().as_str().unwrap()).is_ok()); - - f(); -} - -pub fn main() { - in_tmpdir(test_tempdir); - in_tmpdir(test_rm_tempdir); - in_tmpdir(test_rm_tempdir_close); - in_tmpdir(recursive_mkdir_rel); - in_tmpdir(recursive_mkdir_dot); - in_tmpdir(recursive_mkdir_rel_2); - in_tmpdir(test_rmdir_recursive_ok); - in_tmpdir(dont_double_panic); -} diff --git a/src/test/run-pass/ufcs-polymorphic-paths.rs b/src/test/run-pass/ufcs-polymorphic-paths.rs index db3581976bbc3..eec852ae181c4 100644 --- a/src/test/run-pass/ufcs-polymorphic-paths.rs +++ b/src/test/run-pass/ufcs-polymorphic-paths.rs @@ -17,11 +17,19 @@ use std::default::Default; use std::iter::FromIterator; use std::ops::Add; use std::option::IntoIter as OptionIter; -use std::rand::Rand; -use std::rand::XorShiftRng as DummyRng; -// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent methods. +// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent +// methods. use std::vec::Vec; +pub struct XorShiftRng; +use XorShiftRng as DummyRng; +impl Rng for XorShiftRng {} +pub trait Rng {} +pub trait Rand: Default + Sized { + fn rand(rng: &mut R) -> Self { Default::default() } +} +impl Rand for i32 { } + #[derive(PartialEq, Eq)] struct Newt(T); @@ -29,7 +37,7 @@ fn id(x: T) -> T { x } fn eq(a: T, b: T) -> bool { a == b } fn u8_as_i8(x: u8) -> i8 { x as i8 } fn odd(x: usize) -> bool { x % 2 == 1 } -fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() } +fn dummy_rng() -> DummyRng { XorShiftRng } trait Size: Sized { fn size() -> usize { std::mem::size_of::() } diff --git a/src/test/run-pass/vector-sort-panic-safe.rs b/src/test/run-pass/vector-sort-panic-safe.rs index acb29d284b956..a51274199b620 100644 --- a/src/test/run-pass/vector-sort-panic-safe.rs +++ b/src/test/run-pass/vector-sort-panic-safe.rs @@ -12,7 +12,7 @@ #![feature(rand, core)] use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; -use std::rand::{thread_rng, Rng, Rand}; +use std::__rand::{thread_rng, Rng}; use std::thread; const REPEATS: usize = 5; @@ -36,18 +36,7 @@ static drop_counts: [AtomicUsize; MAX_LEN] = static creation_count: AtomicUsize = ATOMIC_USIZE_INIT; #[derive(Clone, PartialEq, PartialOrd, Eq, Ord)] -struct DropCounter { x: usize, creation_id: usize } - -impl Rand for DropCounter { - fn rand(rng: &mut R) -> DropCounter { - // (we're not using this concurrently, so Relaxed is fine.) - let num = creation_count.fetch_add(1, Ordering::Relaxed); - DropCounter { - x: rng.gen(), - creation_id: num - } - } -} +struct DropCounter { x: u32, creation_id: usize } impl Drop for DropCounter { fn drop(&mut self) { @@ -64,9 +53,13 @@ pub fn main() { // IDs start from 0. creation_count.store(0, Ordering::Relaxed); - let main = thread_rng().gen_iter::() - .take(len) - .collect::>(); + let mut rng = thread_rng(); + let main = (0..len).map(|_| { + DropCounter { + x: rng.next_u32(), + creation_id: creation_count.fetch_add(1, Ordering::Relaxed), + } + }).collect::>(); // work out the total number of comparisons required to sort // this array... diff --git a/src/test/run-pass/wait-forked-but-failed-child.rs b/src/test/run-pass/wait-forked-but-failed-child.rs index 998360f08ba0d..1d0004bafa356 100644 --- a/src/test/run-pass/wait-forked-but-failed-child.rs +++ b/src/test/run-pass/wait-forked-but-failed-child.rs @@ -9,11 +9,11 @@ // except according to those terms. -#![feature(libc, old_io)] +#![feature(libc)] extern crate libc; -use std::old_io::process::Command; +use std::process::Command; use libc::funcs::posix88::unistd; @@ -38,7 +38,7 @@ fn find_zombies() { // http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html let ps_cmd_output = Command::new("ps").args(&["-A", "-o", "pid,ppid,args"]).output().unwrap(); - let ps_output = String::from_utf8_lossy(&ps_cmd_output.output); + let ps_output = String::from_utf8_lossy(&ps_cmd_output.stdout); for (line_no, line) in ps_output.split('\n').enumerate() { if 0 < line_no && 0 < line.len() && @@ -59,7 +59,7 @@ fn main() { let too_long = format!("/NoSuchCommand{:0300}", 0u8); let _failures = (0..100).map(|_| { - let cmd = Command::new(&too_long); + let mut cmd = Command::new(&too_long); let failed = cmd.spawn(); assert!(failed.is_err(), "Make sure the command fails to spawn(): {:?}", cmd); failed

(path: P, timeout: Duration) - -> IoResult - 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) { - 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) { - 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) { - 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 { - self.inner.read(buf) - } -} - -impl Writer for UnixStream { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner.write(buf) - } -} - -impl sys_common::AsInner 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(path: P) -> IoResult { - let path = try!(CString::new(path.container_as_bytes())); - UnixListenerImp::bind(&path) - .map(|inner| UnixListener { inner: inner }) - } -} - -impl Listener for UnixListener { - fn listen(self) -> IoResult { - self.inner.listen() - .map(|inner| UnixAcceptor { inner: inner }) - } -} - -impl sys_common::AsInner 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) { - 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 { - 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 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(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); - } -} diff --git a/src/libstd/old_io/net/tcp.rs b/src/libstd/old_io/net/tcp.rs deleted file mode 100644 index 7fc460c16efca..0000000000000 --- a/src/libstd/old_io/net/tcp.rs +++ /dev/null @@ -1,1483 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! TCP network connections -//! -//! This module contains the ability to open a TCP stream to a socket address, -//! as well as creating a socket server to accept incoming connections. The -//! destination and binding addresses can either be an IPv4 or IPv6 address. -//! -//! A TCP connection implements the `Reader` and `Writer` traits, while the TCP -//! listener (socket server) implements the `Listener` and `Acceptor` traits. - -use clone::Clone; -use old_io::IoResult; -use result::Result::Err; -use old_io::net::ip::{SocketAddr, ToSocketAddr}; -use old_io::{Reader, Writer, Listener, Acceptor}; -use old_io::{standard_error, TimedOut}; -use option::Option; -use option::Option::{None, Some}; -use time::Duration; - -use sys::tcp::TcpStream as TcpStreamImp; -use sys::tcp::TcpListener as TcpListenerImp; -use sys::tcp::TcpAcceptor as TcpAcceptorImp; - -use sys_common; - -/// A structure which represents a TCP stream between a local socket and a -/// remote socket. -/// -/// The socket will be closed when the value is dropped. -/// -/// # Examples -/// -/// ```no_run -/// # #![feature(old_io, io)] -/// use std::old_io::*; -/// -/// { -/// let mut stream = TcpStream::connect("127.0.0.1:34254"); -/// -/// // ignore the Result -/// let _ = stream.write(&[1]); -/// -/// let mut buf = [0]; -/// let _ = stream.read(&mut buf); // ignore here too -/// } // the stream is closed here -/// ``` -pub struct TcpStream { - inner: TcpStreamImp, -} - -impl TcpStream { - fn new(s: TcpStreamImp) -> TcpStream { - TcpStream { inner: s } - } - - /// Open a TCP connection to a remote host. - /// - /// `addr` is an address of the remote host. Anything which implements `ToSocketAddr` - /// trait can be supplied for the address; see this trait documentation for - /// concrete examples. - pub fn connect(addr: A) -> IoResult { - super::with_addresses(addr, |addr| { - TcpStreamImp::connect(addr, None).map(TcpStream::new) - }) - } - - /// Creates a TCP connection to a remote socket address, timing out after - /// the specified duration. - /// - /// This is the same as the `connect` method, except that if the timeout - /// specified elapses before a connection is made an error will be - /// returned. The error's kind will be `TimedOut`. - /// - /// Same as the `connect` method, `addr` argument type can be anything which - /// implements `ToSocketAddr` trait. - /// - /// 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 may eventually change types")] - pub fn connect_timeout(addr: A, - timeout: Duration) -> IoResult { - if timeout <= Duration::milliseconds(0) { - return Err(standard_error(TimedOut)); - } - - super::with_addresses(addr, |addr| { - TcpStreamImp::connect(addr, Some(timeout.num_milliseconds() as u64)) - .map(TcpStream::new) - }) - } - - /// Returns the socket address of the remote peer of this TCP connection. - pub fn peer_name(&mut self) -> IoResult { - self.inner.peer_name() - } - - /// Returns the socket address of the local half of this TCP connection. - pub fn socket_name(&mut self) -> IoResult { - self.inner.socket_name() - } - - /// Sets the nodelay flag on this connection to the boolean specified - #[unstable(feature = "io")] - pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { - self.inner.set_nodelay(nodelay) - } - - /// Sets the keepalive timeout to the timeout specified. - /// - /// If the value specified is `None`, then the keepalive flag is cleared on - /// this connection. Otherwise, the keepalive timeout will be set to the - /// specified time, in seconds. - #[unstable(feature = "io")] - pub fn set_keepalive(&mut self, delay_in_seconds: Option) -> IoResult<()> { - self.inner.set_keepalive(delay_in_seconds) - } - - /// 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. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(old_io, std_misc)] - /// # #![allow(unused_must_use)] - /// use std::old_io::*; - /// use std::time::Duration; - /// use std::thread; - /// - /// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); - /// let stream2 = stream.clone(); - /// - /// let _t = thread::spawn(move|| { - /// // close this stream after one second - /// timer::sleep(Duration::seconds(1)); - /// let mut stream = stream2; - /// stream.close_read(); - /// }); - /// - /// // wait for some data, will get canceled after one second - /// let mut buf = [0]; - /// stream.read(&mut buf); - /// ``` - /// - /// 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 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 a timeout, in milliseconds, for blocking operations on this stream. - /// - /// This function will set a timeout for all blocking operations (including - /// reads and writes) on this stream. The timeout specified is a relative - /// time, in milliseconds, into the future after which point operations will - /// time out. This means that the timeout must be reset periodically to keep - /// it from expiring. Specifying a value of `None` will clear the timeout - /// for this stream. - /// - /// The timeout on this stream is local to this stream only. Setting a - /// timeout does not affect any other cloned instances of this stream, nor - /// does the timeout propagated to cloned handles of this stream. Setting - /// this timeout will override any specific read or write timeouts - /// previously set for this stream. - /// - /// For clarification on the semantics of interrupting a read and a write, - /// take a look at `set_read_timeout` and `set_write_timeout`. - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_timeout(&mut self, timeout_ms: Option) { - self.inner.set_timeout(timeout_ms) - } - - /// Sets the timeout for read operations on this stream. - /// - /// See documentation in `set_timeout` for the semantics of this read time. - /// This will overwrite any previous read timeout set through either this - /// function or `set_timeout`. - /// - /// # Errors - /// - /// When this timeout expires, if there is no pending read operation, no - /// action is taken. Otherwise, the read operation will be scheduled to - /// promptly return. If a timeout error is returned, then no data was read - /// during the timeout period. - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_read_timeout(&mut self, timeout_ms: Option) { - self.inner.set_read_timeout(timeout_ms) - } - - /// Sets the timeout for write operations on this stream. - /// - /// See documentation in `set_timeout` for the semantics of this write time. - /// This will overwrite any previous write timeout set through either this - /// function or `set_timeout`. - /// - /// # Errors - /// - /// When this timeout expires, if there is no pending write operation, no - /// action is taken. Otherwise, the pending write operation will be - /// scheduled to promptly return. The actual state of the underlying stream - /// is not specified. - /// - /// The write operation may return an error of type `ShortWrite` which - /// indicates that the object is known to have written an exact number of - /// bytes successfully during the timeout period, and the remaining bytes - /// were never written. - /// - /// If the write operation returns `TimedOut`, then it the timeout primitive - /// does not know how many bytes were written as part of the timeout - /// operation. It may be the case that bytes continue to be written in an - /// asynchronous fashion after the call to write returns. - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_write_timeout(&mut self, timeout_ms: Option) { - self.inner.set_write_timeout(timeout_ms) - } -} - -impl Clone for TcpStream { - /// Creates a new handle to this TCP stream, allowing for simultaneous reads - /// and writes of this connection. - /// - /// The underlying TCP stream will not be closed until all handles to the - /// stream have been deallocated. All handles will also follow the same - /// stream, but 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) -> TcpStream { - TcpStream { inner: self.inner.clone() } - } -} - -impl Reader for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.read(buf) - } -} - -impl Writer for TcpStream { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner.write(buf) - } -} - -impl sys_common::AsInner for TcpStream { - fn as_inner(&self) -> &TcpStreamImp { - &self.inner - } -} - -/// A structure representing a socket server. This listener is used to create a -/// `TcpAcceptor` which can be used to accept sockets on a local port. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// # fn foo() { -/// use std::old_io::*; -/// use std::thread; -/// -/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); -/// -/// // bind the listener to the specified address -/// let mut acceptor = listener.listen().unwrap(); -/// -/// fn handle_client(mut stream: TcpStream) { -/// // ... -/// # &mut stream; // silence unused mutability/variable warning -/// } -/// // accept connections and process them, spawning a new tasks for each one -/// for stream in acceptor.incoming() { -/// match stream { -/// Err(e) => { /* connection failed */ } -/// Ok(stream) => { -/// thread::spawn(move|| { -/// // connection succeeded -/// handle_client(stream) -/// }); -/// } -/// } -/// } -/// -/// // close the socket server -/// drop(acceptor); -/// # } -/// ``` -pub struct TcpListener { - inner: TcpListenerImp, -} - -impl TcpListener { - /// Creates a new `TcpListener` which will be bound to the specified address. - /// This listener is not ready for accepting connections, `listen` must be called - /// on it before that's possible. - /// - /// Binding with a port number of 0 will request that the OS assigns a port - /// to this listener. The port allocated can be queried via the - /// `socket_name` function. - /// - /// The address type can be any implementer of `ToSocketAddr` trait. See its - /// documentation for concrete examples. - pub fn bind(addr: A) -> IoResult { - super::with_addresses(addr, |addr| { - TcpListenerImp::bind(addr).map(|inner| TcpListener { inner: inner }) - }) - } - - /// Returns the local socket address of this listener. - pub fn socket_name(&mut self) -> IoResult { - self.inner.socket_name() - } -} - -impl Listener for TcpListener { - fn listen(self) -> IoResult { - self.inner.listen(128).map(|a| TcpAcceptor { inner: a }) - } -} - -impl sys_common::AsInner for TcpListener { - fn as_inner(&self) -> &TcpListenerImp { - &self.inner - } -} - -/// The accepting half of a TCP socket server. This structure is created through -/// a `TcpListener`'s `listen` method, and this object can be used to accept new -/// `TcpStream` instances. -pub struct TcpAcceptor { - inner: TcpAcceptorImp, -} - -impl TcpAcceptor { - /// Prevents blocking on all future accepts after `ms` milliseconds have - /// elapsed. - /// - /// This function is used to set a deadline after which this acceptor will - /// time out accepting any connections. The argument is the relative - /// distance, in milliseconds, to a point in the future after which all - /// accepts will fail. - /// - /// If the argument specified is `None`, then any previously registered - /// timeout is cleared. - /// - /// A timeout of `0` can be used to "poll" this acceptor to see if it has - /// any pending connections. All pending connections will be accepted, - /// regardless of whether the timeout has expired or not (the accept will - /// not block in this case). - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(old_io, io)] - /// use std::old_io::*; - /// - /// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap(); - /// - /// // After 100ms have passed, all accepts will fail - /// a.set_timeout(Some(100)); - /// - /// match a.accept() { - /// Ok(..) => println!("accepted a socket"), - /// Err(ref e) if e.kind == TimedOut => { println!("timed out!"); } - /// Err(e) => println!("err: {}", e), - /// } - /// - /// // Reset the timeout and try again - /// a.set_timeout(Some(100)); - /// let socket = a.accept(); - /// - /// // Clear the timeout and block indefinitely waiting for a connection - /// a.set_timeout(None); - /// let socket = a.accept(); - /// ``` - #[unstable(feature = "io", - reason = "the type of the argument and name of this function are \ - subject to change")] - pub fn set_timeout(&mut self, ms: Option) { self.inner.set_timeout(ms); } - - /// Closes the accepting capabilities of this acceptor. - /// - /// This function is similar to `TcpStream`'s `close_{read,write}` methods - /// in that it will affect *all* cloned handles of this acceptor's original - /// handle. - /// - /// Once this function succeeds, all future calls to `accept` will return - /// immediately with an error, preventing all future calls to accept. The - /// underlying socket will not be relinquished back to the OS until all - /// acceptors have been deallocated. - /// - /// This is useful for waking up a thread in an accept loop to indicate that - /// it should exit. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, io)] - /// use std::old_io::*; - /// use std::thread; - /// - /// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap(); - /// let a2 = a.clone(); - /// - /// let _t = thread::spawn(move|| { - /// let mut a2 = a2; - /// for socket in a2.incoming() { - /// match socket { - /// Ok(s) => { /* handle s */ } - /// Err(ref e) if e.kind == EndOfFile => break, // closed - /// Err(e) => panic!("unexpected error: {}", e), - /// } - /// } - /// }); - /// - /// # fn wait_for_sigint() {} - /// // Now that our accept loop is running, wait for the program to be - /// // requested to exit. - /// wait_for_sigint(); - /// - /// // Signal our accept loop to exit - /// assert!(a.close_accept().is_ok()); - /// ``` - #[unstable(feature = "io")] - pub fn close_accept(&mut self) -> IoResult<()> { - self.inner.close_accept() - } -} - -impl Acceptor for TcpAcceptor { - type Connection = TcpStream; - fn accept(&mut self) -> IoResult { - self.inner.accept().map(TcpStream::new) - } -} - -impl Clone for TcpAcceptor { - /// Creates a new handle to this TCP acceptor, allowing for simultaneous - /// accepts. - /// - /// The underlying TCP 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) -> TcpAcceptor { - TcpAcceptor { inner: self.inner.clone() } - } -} - -impl sys_common::AsInner for TcpAcceptor { - fn as_inner(&self) -> &TcpAcceptorImp { - &self.inner - } -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - - use sync::mpsc::channel; - use thread; - use old_io::net::tcp::*; - use old_io::net::ip::*; - use old_io::test::*; - use old_io::{EndOfFile, TimedOut, ShortWrite, IoError}; - use old_io::{ConnectionRefused, BrokenPipe, ConnectionAborted}; - use old_io::{ConnectionReset, NotConnected, PermissionDenied, OtherIoError}; - use old_io::{InvalidInput}; - use old_io::{Acceptor, Listener}; - use old_io::{Reader, Writer}; - - // FIXME #11530 this fails on android because tests are run as root - #[cfg_attr(any(windows, target_os = "android"), ignore)] - #[test] - fn bind_error() { - match TcpListener::bind("0.0.0.0:1") { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, PermissionDenied), - } - } - - #[test] - fn connect_error() { - match TcpStream::connect("0.0.0.0:1") { - Ok(..) => panic!(), - Err(e) => assert!((e.kind == ConnectionRefused) - || (e.kind == InvalidInput)), - } - } - - #[test] - fn listen_ip4_localhost() { - let socket_addr = next_test_ip4(); - let listener = TcpListener::bind(socket_addr); - let mut acceptor = listener.listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(("localhost", socket_addr.port)); - stream.write(&[144]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 144); - } - - #[test] - fn connect_localhost() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(("localhost", addr.port)); - stream.write(&[64]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 64); - } - - #[test] - fn connect_ip4_loopback() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(("127.0.0.1", addr.port)); - stream.write(&[44]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 44); - } - - #[test] - fn connect_ip6_loopback() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(("::1", addr.port)); - stream.write(&[66]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 66); - } - - #[test] - fn smoke_test_ip4() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(addr); - stream.write(&[99]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 99); - } - - #[test] - fn smoke_test_ip6() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(addr); - stream.write(&[99]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 99); - } - - #[test] - fn read_eof_ip4() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let _stream = TcpStream::connect(addr); - // Close - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - let nread = stream.read(&mut buf); - assert!(nread.is_err()); - } - - #[test] - fn read_eof_ip6() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let _stream = TcpStream::connect(addr); - // Close - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - let nread = stream.read(&mut buf); - assert!(nread.is_err()); - } - - #[test] - fn read_eof_twice_ip4() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let _stream = TcpStream::connect(addr); - // Close - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - let nread = stream.read(&mut buf); - assert!(nread.is_err()); - - match stream.read(&mut buf) { - Ok(..) => panic!(), - Err(ref e) => { - assert!(e.kind == NotConnected || e.kind == EndOfFile, - "unknown kind: {:?}", e.kind); - } - } - } - - #[test] - fn read_eof_twice_ip6() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let _stream = TcpStream::connect(addr); - // Close - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - let nread = stream.read(&mut buf); - assert!(nread.is_err()); - - match stream.read(&mut buf) { - Ok(..) => panic!(), - Err(ref e) => { - assert!(e.kind == NotConnected || e.kind == EndOfFile, - "unknown kind: {:?}", e.kind); - } - } - } - - #[test] - fn write_close_ip4() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - drop(TcpStream::connect(addr)); - tx.send(()).unwrap(); - }); - - let mut stream = acceptor.accept(); - rx.recv().unwrap(); - let buf = [0]; - match stream.write(&buf) { - Ok(..) => {} - Err(e) => { - assert!(e.kind == ConnectionReset || - e.kind == BrokenPipe || - e.kind == ConnectionAborted, - "unknown error: {}", e); - } - } - } - - #[test] - fn write_close_ip6() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - drop(TcpStream::connect(addr)); - tx.send(()).unwrap(); - }); - - let mut stream = acceptor.accept(); - rx.recv().unwrap(); - let buf = [0]; - match stream.write(&buf) { - Ok(..) => {} - Err(e) => { - assert!(e.kind == ConnectionReset || - e.kind == BrokenPipe || - e.kind == ConnectionAborted, - "unknown error: {}", e); - } - } - } - - #[test] - fn multiple_connect_serial_ip4() { - let addr = next_test_ip4(); - let max = 10; - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - for _ in 0..max { - let mut stream = TcpStream::connect(addr); - stream.write(&[99]).unwrap(); - } - }); - - for ref mut stream in acceptor.incoming().take(max) { - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert_eq!(buf[0], 99); - } - } - - #[test] - fn multiple_connect_serial_ip6() { - let addr = next_test_ip6(); - let max = 10; - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - for _ in 0..max { - let mut stream = TcpStream::connect(addr); - stream.write(&[99]).unwrap(); - } - }); - - for ref mut stream in acceptor.incoming().take(max) { - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert_eq!(buf[0], 99); - } - } - - #[test] - fn multiple_connect_interleaved_greedy_schedule_ip4() { - let addr = next_test_ip4(); - static MAX: isize = 10; - let acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - for (i, stream) in acceptor.incoming().enumerate().take(MAX as usize) { - // Start another task to handle the connection - let _t = thread::spawn(move|| { - let mut stream = stream; - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == i as u8); - debug!("read"); - }); - } - }); - - connect(0, addr); - - fn connect(i: isize, addr: SocketAddr) { - if i == MAX { return } - - let _t = thread::spawn(move|| { - debug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - debug!("writing"); - stream.write(&[i as u8]).unwrap(); - }); - } - } - - #[test] - fn multiple_connect_interleaved_greedy_schedule_ip6() { - let addr = next_test_ip6(); - static MAX: isize = 10; - let acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - for (i, stream) in acceptor.incoming().enumerate().take(MAX as usize) { - // Start another task to handle the connection - let _t = thread::spawn(move|| { - let mut stream = stream; - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == i as u8); - debug!("read"); - }); - } - }); - - connect(0, addr); - - fn connect(i: isize, addr: SocketAddr) { - if i == MAX { return } - - let _t = thread::spawn(move|| { - debug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - debug!("writing"); - stream.write(&[i as u8]).unwrap(); - }); - } - } - - #[test] - fn multiple_connect_interleaved_lazy_schedule_ip4() { - static MAX: isize = 10; - let addr = next_test_ip4(); - let acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - for stream in acceptor.incoming().take(MAX as usize) { - // Start another task to handle the connection - let _t = thread::spawn(move|| { - let mut stream = stream; - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 99); - debug!("read"); - }); - } - }); - - connect(0, addr); - - fn connect(i: isize, addr: SocketAddr) { - if i == MAX { return } - - let _t = thread::spawn(move|| { - debug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - debug!("writing"); - stream.write(&[99]).unwrap(); - }); - } - } - - #[test] - fn multiple_connect_interleaved_lazy_schedule_ip6() { - static MAX: isize = 10; - let addr = next_test_ip6(); - let acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - for stream in acceptor.incoming().take(MAX as usize) { - // Start another task to handle the connection - let _t = thread::spawn(move|| { - let mut stream = stream; - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 99); - debug!("read"); - }); - } - }); - - connect(0, addr); - - fn connect(i: isize, addr: SocketAddr) { - if i == MAX { return } - - let _t = thread::spawn(move|| { - debug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - debug!("writing"); - stream.write(&[99]).unwrap(); - }); - } - } - - pub fn socket_name(addr: SocketAddr) { - let mut listener = TcpListener::bind(addr).unwrap(); - - // Make sure socket_name gives - // us the socket we binded to. - let so_name = listener.socket_name(); - assert!(so_name.is_ok()); - assert_eq!(addr, so_name.unwrap()); - } - - pub fn peer_name(addr: SocketAddr) { - let acceptor = TcpListener::bind(addr).listen(); - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - acceptor.accept().unwrap(); - }); - - let stream = TcpStream::connect(addr); - - assert!(stream.is_ok()); - let mut stream = stream.unwrap(); - - // Make sure peer_name gives us the - // address/port of the peer we've - // connected to. - let peer_name = stream.peer_name(); - assert!(peer_name.is_ok()); - assert_eq!(addr, peer_name.unwrap()); - } - - #[test] - fn socket_and_peer_name_ip4() { - peer_name(next_test_ip4()); - socket_name(next_test_ip4()); - } - - #[test] - fn socket_and_peer_name_ip6() { - // FIXME: peer name is not consistent - //peer_name(next_test_ip6()); - socket_name(next_test_ip6()); - } - - #[test] - fn partial_read() { - let addr = next_test_ip4(); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut srv = TcpListener::bind(addr).listen().unwrap(); - tx.send(()).unwrap(); - let mut cl = srv.accept().unwrap(); - cl.write(&[10]).unwrap(); - let mut b = [0]; - cl.read(&mut b).unwrap(); - tx.send(()).unwrap(); - }); - - rx.recv().unwrap(); - let mut c = TcpStream::connect(addr).unwrap(); - let mut b = [0; 10]; - assert_eq!(c.read(&mut b), Ok(1)); - c.write(&[1]).unwrap(); - rx.recv().unwrap(); - } - - #[test] - fn double_bind() { - let addr = next_test_ip4(); - let listener = TcpListener::bind(addr).unwrap().listen(); - assert!(listener.is_ok()); - match TcpListener::bind(addr).listen() { - Ok(..) => panic!(), - Err(e) => { - assert!(e.kind == ConnectionRefused || e.kind == OtherIoError, - "unknown error: {} {:?}", e, e.kind); - } - } - } - - #[test] - fn fast_rebind() { - let addr = next_test_ip4(); - let (tx, rx) = channel(); - - let _t = thread::spawn(move|| { - rx.recv().unwrap(); - let _stream = TcpStream::connect(addr).unwrap(); - // Close - rx.recv().unwrap(); - }); - - { - let mut acceptor = TcpListener::bind(addr).listen(); - tx.send(()).unwrap(); - { - let _stream = acceptor.accept().unwrap(); - // Close client - tx.send(()).unwrap(); - } - // Close listener - } - let _listener = TcpListener::bind(addr); - } - - #[test] - fn tcp_clone_smoke() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut s = TcpStream::connect(addr); - let mut buf = [0, 0]; - assert_eq!(s.read(&mut buf), Ok(1)); - assert_eq!(buf[0], 1); - s.write(&[2]).unwrap(); - }); - - 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(); - s2.write(&[1]).unwrap(); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - assert_eq!(s1.read(&mut buf), Ok(1)); - rx2.recv().unwrap(); - } - - #[test] - fn tcp_clone_two_read() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move|| { - let mut s = TcpStream::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 tcp_clone_two_write() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut s = TcpStream::connect(addr); - let mut buf = [0, 1]; - s.read(&mut buf).unwrap(); - s.read(&mut buf).unwrap(); - }); - - let mut s1 = acceptor.accept().unwrap(); - let s2 = s1.clone(); - - let (done, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - s2.write(&[1]).unwrap(); - done.send(()).unwrap(); - }); - s1.write(&[2]).unwrap(); - - rx.recv().unwrap(); - } - - #[test] - fn shutdown_smoke() { - let addr = next_test_ip4(); - let a = TcpListener::bind(addr).unwrap().listen(); - let _t = thread::spawn(move|| { - let mut a = a; - let mut c = a.accept().unwrap(); - assert_eq!(c.read_to_end(), Ok(vec!())); - c.write(&[1]).unwrap(); - }); - - let mut s = TcpStream::connect(addr).unwrap(); - assert!(s.inner.close_write().is_ok()); - assert!(s.write(&[1]).is_err()); - assert_eq!(s.read_to_end(), Ok(vec!(1))); - } - - #[test] - fn accept_timeout() { - let addr = next_test_ip4(); - let mut a = TcpListener::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. - // - // FIXME: freebsd apparently never sees the pending connection, but - // testing manually always works. Need to investigate this - // flakiness. - if !cfg!(target_os = "freebsd") { - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - tx.send(TcpStream::connect(addr).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") } - } - } - - // Unset the timeout and make sure that this always blocks. - a.set_timeout(None); - let _t = thread::spawn(move|| { - drop(TcpStream::connect(addr).unwrap()); - }); - a.accept().unwrap(); - } - - #[test] - fn close_readwrite_smoke() { - let addr = next_test_ip4(); - let a = TcpListener::bind(addr).listen().unwrap(); - let (_tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut a = a; - let _s = a.accept().unwrap(); - let _ = rx.recv().unwrap(); - }); - - let mut b = [0]; - let mut s = TcpStream::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_ip4(); - let a = TcpListener::bind(addr).listen().unwrap(); - let (_tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut a = a; - let _s = a.accept().unwrap(); - let _ = rx.recv().unwrap(); - }); - - let mut s = TcpStream::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_ip6(); - let mut a = TcpListener::bind(addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = TcpStream::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?!"); } - } - 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_ip6(); - let mut a = TcpListener::bind(addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = TcpStream::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_ip6(); - let mut a = TcpListener::bind(addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = TcpStream::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?!"); } - } - assert_eq!(s.write(&[0]).err().unwrap().kind, TimedOut); - - tx.send(()).unwrap(); - assert!(s.read(&mut [0]).is_ok()); - } - - #[test] - fn timeout_concurrent_read() { - let addr = next_test_ip6(); - let mut a = TcpListener::bind(addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = TcpStream::connect(addr).unwrap(); - rx.recv().unwrap(); - assert_eq!(s.write(&[0]), 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_eq!(s2.read(&mut [0]), Ok(1)); - 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(); - } - - #[test] - fn clone_while_reading() { - let addr = next_test_ip6(); - let listen = TcpListener::bind(addr); - let mut accept = listen.listen().unwrap(); - - // Enqueue a task to write to a socket - let (tx, rx) = channel(); - let (txdone, rxdone) = channel(); - let txdone2 = txdone.clone(); - let _t = thread::spawn(move|| { - let mut tcp = TcpStream::connect(addr).unwrap(); - rx.recv().unwrap(); - tcp.write_u8(0).unwrap(); - txdone2.send(()).unwrap(); - }); - - // Spawn off a reading clone - let tcp = accept.accept().unwrap(); - let tcp2 = tcp.clone(); - let txdone3 = txdone.clone(); - let _t = thread::spawn(move|| { - let mut tcp2 = tcp2; - tcp2.read_u8().unwrap(); - txdone3.send(()).unwrap(); - }); - - // Try to ensure that the reading clone is indeed reading - for _ in 0..50 { - ::thread::yield_now(); - } - - // clone the handle again while it's reading, then let it finish the - // read. - let _ = tcp.clone(); - tx.send(()).unwrap(); - rxdone.recv().unwrap(); - rxdone.recv().unwrap(); - } - - #[test] - fn clone_accept_smoke() { - let addr = next_test_ip4(); - let l = TcpListener::bind(addr); - let mut a = l.listen().unwrap(); - let mut a2 = a.clone(); - - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(addr); - }); - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(addr); - }); - - assert!(a.accept().is_ok()); - assert!(a2.accept().is_ok()); - } - - #[test] - fn clone_accept_concurrent() { - let addr = next_test_ip4(); - let l = TcpListener::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 _t = thread::spawn(move|| { - let _ = TcpStream::connect(addr); - }); - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(addr); - }); - - assert!(rx.recv().unwrap().is_ok()); - assert!(rx.recv().unwrap().is_ok()); - } - - #[test] - fn close_accept_smoke() { - let addr = next_test_ip4(); - let l = TcpListener::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_ip4(); - let l = TcpListener::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); - } -} diff --git a/src/libstd/old_io/net/udp.rs b/src/libstd/old_io/net/udp.rs deleted file mode 100644 index 196447d71efbf..0000000000000 --- a/src/libstd/old_io/net/udp.rs +++ /dev/null @@ -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 or the MIT license -// , 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(addr: A) -> IoResult { - 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(&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 { - 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) { - 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) { - 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) { - 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 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), - } - } - } -} diff --git a/src/libstd/old_io/pipe.rs b/src/libstd/old_io/pipe.rs deleted file mode 100644 index fd1df49473e58..0000000000000 --- a/src/libstd/old_io/pipe.rs +++ /dev/null @@ -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 or the MIT license -// , 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 -} - -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 { - 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 { - let (reader, writer) = try!(unsafe { sys::os::pipe() }); - Ok(PipePair { - reader: PipeStream::from_filedesc(reader), - writer: PipeStream::from_filedesc(writer), - }) - } -} - -impl sys_common::AsInner 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 { - 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(); - } -} diff --git a/src/libstd/old_io/process.rs b/src/libstd/old_io/process.rs deleted file mode 100644 index b55d1f4db07f7..0000000000000 --- a/src/libstd/old_io/process.rs +++ /dev/null @@ -1,1239 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Bindings for executing child processes - -#![allow(non_upper_case_globals)] -#![unstable(feature = "old_io")] -#![deprecated(since = "1.0.0", - reason = "replaced with the std::process module")] - -pub use self::StdioContainer::*; -pub use self::ProcessExit::*; - -use prelude::v1::*; - -use collections::HashMap; -use ffi::CString; -use fmt; -use old_io::pipe::{PipeStream, PipePair}; -use old_io::{IoResult, IoError, Reader, Writer}; -use old_io; -use old_path::{Path, GenericPath}; -use libc; -use os; -use old_path::BytesContainer; -use sync::mpsc::{channel, Receiver}; -use sys::fs::FileDesc; -use sys::process::Process as ProcessImp; -use sys; -use thread; - -#[cfg(windows)] use hash; -#[cfg(windows)] use str; - -/// Signal a process to exit, without forcibly killing it. Corresponds to -/// SIGTERM on unix platforms. -#[cfg(windows)] pub const PleaseExitSignal: isize = 15; -/// Signal a process to exit immediately, forcibly killing it. Corresponds to -/// SIGKILL on unix platforms. -#[cfg(windows)] pub const MustDieSignal: isize = 9; -/// Signal a process to exit, without forcibly killing it. Corresponds to -/// SIGTERM on unix platforms. -#[cfg(not(windows))] pub const PleaseExitSignal: isize = libc::SIGTERM as isize; -/// Signal a process to exit immediately, forcibly killing it. Corresponds to -/// SIGKILL on unix platforms. -#[cfg(not(windows))] pub const MustDieSignal: isize = libc::SIGKILL as isize; - -/// Representation of a running or exited child process. -/// -/// This structure is used to represent and manage child processes. A child -/// process is created via the `Command` struct, which configures the spawning -/// process and can itself be constructed using a builder-style interface. -/// -/// # Examples -/// -/// ```should_panic -/// # #![feature(old_io)] -/// use std::old_io::*; -/// -/// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() { -/// Ok(child) => child, -/// Err(e) => panic!("failed to execute child: {}", e), -/// }; -/// -/// let contents = child.stdout.as_mut().unwrap().read_to_end(); -/// assert!(child.wait().unwrap().success()); -/// ``` -pub struct Process { - handle: ProcessImp, - forget: bool, - - /// None until wait() is called. - exit_code: Option, - - /// Manually delivered signal - exit_signal: Option, - - /// Deadline after which wait() will return - deadline: u64, - - /// Handle to the child's stdin, if the `stdin` field of this process's - /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. - pub stdin: Option, - - /// Handle to the child's stdout, if the `stdout` field of this process's - /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. - pub stdout: Option, - - /// Handle to the child's stderr, if the `stderr` field of this process's - /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. - pub stderr: Option, -} - -/// A representation of environment variable name -/// It compares case-insensitive on Windows and case-sensitive everywhere else. -#[cfg(not(windows))] -#[derive(Hash, PartialEq, Eq, Clone, Debug)] -struct EnvKey(CString); - -#[doc(hidden)] -#[cfg(windows)] -#[derive(Eq, Clone, Debug)] -struct EnvKey(CString); - -#[cfg(windows)] -impl hash::Hash for EnvKey { - fn hash(&self, state: &mut H) { - use ascii::AsciiExt; - let &EnvKey(ref x) = self; - match str::from_utf8(x.as_bytes()) { - Ok(s) => for ch in s.chars() { - ch.to_ascii_lowercase().hash(state); - }, - Err(..) => x.hash(state) - } - } -} - -#[cfg(windows)] -impl PartialEq for EnvKey { - fn eq(&self, other: &EnvKey) -> bool { - use ascii::AsciiExt; - let &EnvKey(ref x) = self; - let &EnvKey(ref y) = other; - match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) { - (Ok(xs), Ok(ys)) => { - if xs.len() != ys.len() { - return false - } else { - for (xch, ych) in xs.chars().zip(ys.chars()) { - if xch.to_ascii_lowercase() != ych.to_ascii_lowercase() { - return false; - } - } - return true; - } - }, - // If either is not a valid utf8 string, just compare them byte-wise - _ => return x.eq(y) - } - } -} - -impl BytesContainer for EnvKey { - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - let &EnvKey(ref k) = self; - k.container_as_bytes() - } -} - -/// A HashMap representation of environment variables. -pub type EnvMap = HashMap; - -/// The `Command` type acts as a process builder, providing fine-grained control -/// over how a new process should be spawned. A default configuration can be -/// generated using `Command::new(program)`, where `program` gives a path to the -/// program to be executed. Additional builder methods allow the configuration -/// to be changed (for example, by adding arguments) prior to spawning: -/// -/// ``` -/// # #![feature(old_io)] -/// use std::old_io::*; -/// -/// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() { -/// Ok(p) => p, -/// Err(e) => panic!("failed to execute process: {}", e), -/// }; -/// -/// let output = process.stdout.as_mut().unwrap().read_to_end(); -/// ``` -#[derive(Clone)] -pub struct Command { - // The internal data for the builder. Documented by the builder - // methods below, and serialized into rt::rtio::ProcessConfig. - program: CString, - args: Vec, - env: Option, - cwd: Option, - stdin: StdioContainer, - stdout: StdioContainer, - stderr: StdioContainer, - uid: Option, - gid: Option, - detach: bool, -} - -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take BytesContainer arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by BytesContainer should be passed by -// reference. (Here: {new, arg, args, env}.) - -impl Command { - /// Constructs a new `Command` for launching the program at - /// path `program`, with the following default configuration: - /// - /// * No arguments to the program - /// * Inherit the current process's environment - /// * Inherit the current process's working directory - /// * A readable pipe for stdin (file descriptor 0) - /// * A writeable pipe for stdout and stderr (file descriptors 1 and 2) - /// - /// Builder methods are provided to change these defaults and - /// otherwise configure the process. - pub fn new(program: T) -> Command { - Command { - program: CString::new(program.container_as_bytes()).unwrap(), - args: Vec::new(), - env: None, - cwd: None, - stdin: CreatePipe(true, false), - stdout: CreatePipe(false, true), - stderr: CreatePipe(false, true), - uid: None, - gid: None, - detach: false, - } - } - - /// Add an argument to pass to the program. - pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command { - self.args.push(CString::new(arg.container_as_bytes()).unwrap()); - self - } - - /// Add multiple arguments to pass to the program. - pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command { - self.args.extend(args.iter().map(|arg| { - CString::new(arg.container_as_bytes()).unwrap() - })); - self - } - // Get a mutable borrow of the environment variable map for this `Command`. - #[allow(deprecated)] - fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { - match self.env { - Some(ref mut map) => map, - None => { - // if the env is currently just inheriting from the parent's, - // materialize the parent's env into a hashtable. - self.env = Some(::env::vars().map(|(k, v)| { - (EnvKey(CString::new(k).unwrap()), - CString::new(v).unwrap()) - }).collect()); - self.env.as_mut().unwrap() - } - } - } - - /// Inserts or updates an environment variable mapping. - /// - /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, - /// and case-sensitive on all other platforms. - pub fn env<'a, T, U>(&'a mut self, key: T, val: U) - -> &'a mut Command - where T: BytesContainer, U: BytesContainer { - let key = EnvKey(CString::new(key.container_as_bytes()).unwrap()); - let val = CString::new(val.container_as_bytes()).unwrap(); - self.get_env_map().insert(key, val); - self - } - - /// Removes an environment variable mapping. - pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command - where T: BytesContainer { - let key = EnvKey(CString::new(key.container_as_bytes()).unwrap()); - self.get_env_map().remove(&key); - self - } - - /// Sets the entire environment map for the child process. - /// - /// If the given slice contains multiple instances of an environment - /// variable, the *rightmost* instance will determine the value. - pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)]) - -> &'a mut Command - where T: BytesContainer, U: BytesContainer { - self.env = Some(env.iter().map(|&(ref k, ref v)| { - (EnvKey(CString::new(k.container_as_bytes()).unwrap()), - CString::new(v.container_as_bytes()).unwrap()) - }).collect()); - self - } - - /// Set the working directory for the child process. - pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command { - self.cwd = Some(CString::new(dir.as_vec()).unwrap()); - self - } - - /// Configuration for the child process's stdin handle (file descriptor 0). - /// Defaults to `CreatePipe(true, false)` so the input can be written to. - pub fn stdin<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { - self.stdin = cfg; - self - } - - /// Configuration for the child process's stdout handle (file descriptor 1). - /// Defaults to `CreatePipe(false, true)` so the output can be collected. - pub fn stdout<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { - self.stdout = cfg; - self - } - - /// Configuration for the child process's stderr handle (file descriptor 2). - /// Defaults to `CreatePipe(false, true)` so the output can be collected. - pub fn stderr<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { - self.stderr = cfg; - self - } - - /// Sets the child process's user id. This translates to a `setuid` call in - /// the child process. Setting this value on windows will cause the spawn to - /// fail. Failure in the `setuid` call on unix will also cause the spawn to - /// fail. - pub fn uid<'a>(&'a mut self, id: usize) -> &'a mut Command { - self.uid = Some(id); - self - } - - /// Similar to `uid`, but sets the group id of the child process. This has - /// the same semantics as the `uid` field. - pub fn gid<'a>(&'a mut self, id: usize) -> &'a mut Command { - self.gid = Some(id); - self - } - - /// Sets the child process to be spawned in a detached state. On unix, this - /// means that the child is the leader of a new process group. - pub fn detached<'a>(&'a mut self) -> &'a mut Command { - self.detach = true; - self - } - - /// Executes the command as a child process, which is returned. - pub fn spawn(&self) -> IoResult { - let (their_stdin, our_stdin) = try!(setup_io(self.stdin)); - let (their_stdout, our_stdout) = try!(setup_io(self.stdout)); - let (their_stderr, our_stderr) = try!(setup_io(self.stderr)); - - match ProcessImp::spawn(self, their_stdin, their_stdout, their_stderr) { - Err(e) => Err(e), - Ok(handle) => Ok(Process { - handle: handle, - forget: false, - exit_code: None, - exit_signal: None, - deadline: 0, - stdin: our_stdin, - stdout: our_stdout, - stderr: our_stderr, - }) - } - } - - /// Executes the command as a child process, waiting for it to finish and - /// collecting all of its output. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io)] - /// use std::old_io::Command; - /// - /// let output = match Command::new("cat").arg("foot.txt").output() { - /// Ok(output) => output, - /// Err(e) => panic!("failed to execute process: {}", e), - /// }; - /// - /// println!("status: {}", output.status); - /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_ref())); - /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_ref())); - /// ``` - pub fn output(&self) -> IoResult { - self.spawn().and_then(|p| p.wait_with_output()) - } - - /// Executes a command as a child process, waiting for it to finish and - /// collecting its exit status. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io)] - /// use std::old_io::Command; - /// - /// let status = match Command::new("ls").status() { - /// Ok(status) => status, - /// Err(e) => panic!("failed to execute process: {}", e), - /// }; - /// - /// println!("process exited with: {}", status); - /// ``` - pub fn status(&self) -> IoResult { - self.spawn().and_then(|mut p| p.wait()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Command { - /// Format the program and arguments of a Command for display. Any - /// non-utf8 data is lossily converted using the utf8 replacement - /// character. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "{:?}", self.program)); - for arg in &self.args { - try!(write!(f, " '{:?}'", arg)); - } - Ok(()) - } -} - -fn setup_io(io: StdioContainer) -> IoResult<(Option, Option)> { - let ours; - let theirs; - match io { - Ignored => { - theirs = None; - ours = None; - } - InheritFd(fd) => { - theirs = Some(PipeStream::from_filedesc(FileDesc::new(fd, false))); - ours = None; - } - CreatePipe(readable, _writable) => { - let PipePair { reader, writer } = try!(PipeStream::pair()); - if readable { - theirs = Some(reader); - ours = Some(writer); - } else { - theirs = Some(writer); - ours = Some(reader); - } - } - } - Ok((theirs, ours)) -} - -// Allow the sys module to get access to the Command state -impl sys::process::ProcessConfig for Command { - fn program(&self) -> &CString { - &self.program - } - fn args(&self) -> &[CString] { - &self.args - } - fn env(&self) -> Option<&EnvMap> { - self.env.as_ref() - } - fn cwd(&self) -> Option<&CString> { - self.cwd.as_ref() - } - fn uid(&self) -> Option { - self.uid.clone() - } - fn gid(&self) -> Option { - self.gid.clone() - } - fn detach(&self) -> bool { - self.detach - } - -} - -/// The output of a finished process. -#[derive(PartialEq, Eq, Clone)] -pub struct ProcessOutput { - /// The status (exit code) of the process. - pub status: ProcessExit, - /// The data that the process wrote to stdout. - pub output: Vec, - /// The data that the process wrote to stderr. - pub error: Vec, -} - -/// Describes what to do with a standard io stream for a child process. -#[derive(Clone, Copy)] -pub enum StdioContainer { - /// This stream will be ignored. This is the equivalent of attaching the - /// stream to `/dev/null` - Ignored, - - /// The specified file descriptor is inherited for the stream which it is - /// specified for. Ownership of the file descriptor is *not* taken, so the - /// caller must clean it up. - InheritFd(libc::c_int), - - /// Creates a pipe for the specified file descriptor which will be created - /// when the process is spawned. - /// - /// The first boolean argument is whether the pipe is readable, and the - /// second is whether it is writable. These properties are from the view of - /// the *child* process, not the parent process. - CreatePipe(bool /* readable */, bool /* writable */), -} - -/// Describes the result of a process after it has terminated. -/// Note that Windows have no signals, so the result is usually ExitStatus. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub enum ProcessExit { - /// Normal termination with an exit status. - ExitStatus(isize), - - /// Termination by signal, with the signal number. - ExitSignal(isize), -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ProcessExit { - /// Format a ProcessExit enum, to nicely present the information. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ExitStatus(code) => write!(f, "exit code: {}", code), - ExitSignal(code) => write!(f, "signal: {}", code), - } - } -} - -impl ProcessExit { - /// Was termination successful? Signal termination not considered a success, - /// and success is defined as a zero exit status. - pub fn success(&self) -> bool { - return self.matches_exit_status(0); - } - - /// Checks whether this ProcessExit matches the given exit status. - /// Termination by signal will never match an exit code. - pub fn matches_exit_status(&self, wanted: isize) -> bool { - *self == ExitStatus(wanted) - } -} - -impl Process { - /// Sends `signal` to another process in the system identified by `id`. - /// - /// Note that windows doesn't quite have the same model as unix, so some - /// unix signals are mapped to windows signals. Notably, unix termination - /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`. - /// - /// Additionally, a signal number of 0 can check for existence of the target - /// process. Note, though, that on some platforms signals will continue to - /// be successfully delivered if the child has exited, but not yet been - /// reaped. - pub fn kill(id: libc::pid_t, signal: isize) -> IoResult<()> { - unsafe { ProcessImp::killpid(id, signal) } - } - - /// Returns the process id of this child process - pub fn id(&self) -> libc::pid_t { self.handle.id() } - - /// Sends the specified signal to the child process, returning whether the - /// signal could be delivered or not. - /// - /// Note that signal 0 is interpreted as a poll to check whether the child - /// process is still alive or not. If an error is returned, then the child - /// process has exited. - /// - /// On some unix platforms signals will continue to be received after a - /// child has exited but not yet been reaped. In order to report the status - /// of signal delivery correctly, unix implementations may invoke - /// `waitpid()` with `WNOHANG` in order to reap the child as necessary. - /// - /// # Errors - /// - /// If the signal delivery fails, the corresponding error is returned. - pub fn signal(&mut self, signal: isize) -> IoResult<()> { - #[cfg(unix)] fn collect_status(p: &mut Process) { - // On Linux (and possibly other unices), a process that has exited will - // continue to accept signals because it is "defunct". The delivery of - // signals will only fail once the child has been reaped. For this - // reason, if the process hasn't exited yet, then we attempt to collect - // their status with WNOHANG. - if p.exit_code.is_none() { - match p.handle.try_wait() { - Some(code) => { p.exit_code = Some(code); } - None => {} - } - } - } - #[cfg(windows)] fn collect_status(_p: &mut Process) {} - - collect_status(self); - - // if the process has finished, and therefore had waitpid called, - // and we kill it, then on unix we might ending up killing a - // newer process that happens to have the same (re-used) id - if self.exit_code.is_some() { - return Err(IoError { - kind: old_io::InvalidInput, - desc: "invalid argument: can't kill an exited process", - detail: None, - }) - } - - // A successfully delivered signal that isn't 0 (just a poll for being - // alive) is recorded for windows (see wait()) - match unsafe { self.handle.kill(signal) } { - Ok(()) if signal == 0 => Ok(()), - Ok(()) => { self.exit_signal = Some(signal); Ok(()) } - Err(e) => Err(e), - } - - } - - /// Sends a signal to this child requesting that it exits. This is - /// equivalent to sending a SIGTERM on unix platforms. - pub fn signal_exit(&mut self) -> IoResult<()> { - self.signal(PleaseExitSignal) - } - - /// Sends a signal to this child forcing it to exit. This is equivalent to - /// sending a SIGKILL on unix platforms. - pub fn signal_kill(&mut self) -> IoResult<()> { - self.signal(MustDieSignal) - } - - /// Wait for the child to exit completely, returning the status that it - /// exited with. This function will continue to have the same return value - /// after it has been called at least once. - /// - /// The stdin handle to the child process will be closed before waiting. - /// - /// # Errors - /// - /// This function can fail if a timeout was previously specified via - /// `set_timeout` and the timeout expires before the child exits. - pub fn wait(&mut self) -> IoResult { - drop(self.stdin.take()); - match self.exit_code { - Some(code) => Ok(code), - None => { - let code = try!(self.handle.wait(self.deadline)); - // On windows, waitpid will never return a signal. If a signal - // was successfully delivered to the process, however, we can - // consider it as having died via a signal. - let code = match self.exit_signal { - None => code, - Some(signal) if cfg!(windows) => ExitSignal(signal), - Some(..) => code, - }; - self.exit_code = Some(code); - Ok(code) - } - } - } - - /// Sets a timeout, in milliseconds, for future calls to wait(). - /// - /// The argument specified is a relative distance into the future, in - /// milliseconds, after which any call to wait() will return immediately - /// with a timeout error, and all future calls to wait() will not block. - /// - /// A value of `None` will clear any previous timeout, and a value of `Some` - /// will override any previously set timeout. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(old_io, io)] - /// use std::old_io::{Command, IoResult}; - /// use std::old_io::process::ProcessExit; - /// - /// fn run_gracefully(prog: &str) -> IoResult { - /// let mut p = try!(Command::new("long-running-process").spawn()); - /// - /// // give the process 10 seconds to finish completely - /// p.set_timeout(Some(10_000)); - /// match p.wait() { - /// Ok(status) => return Ok(status), - /// Err(..) => {} - /// } - /// - /// // Attempt to exit gracefully, but don't wait for it too long - /// try!(p.signal_exit()); - /// p.set_timeout(Some(1_000)); - /// match p.wait() { - /// Ok(status) => return Ok(status), - /// Err(..) => {} - /// } - /// - /// // Well, we did our best, forcefully kill the process - /// try!(p.signal_kill()); - /// p.set_timeout(None); - /// p.wait() - /// } - /// ``` - #[unstable(feature = "io", - reason = "the type of the timeout is likely to change")] - pub fn set_timeout(&mut self, timeout_ms: Option) { - self.deadline = timeout_ms.map(|i| i + sys::timer::now()).unwrap_or(0); - } - - /// Simultaneously wait for the child to exit and collect all remaining - /// output on the stdout/stderr handles, returning a `ProcessOutput` - /// instance. - /// - /// The stdin handle to the child is closed before waiting. - /// - /// # Errors - /// - /// This function can fail for any of the same reasons that `wait()` can - /// fail. - pub fn wait_with_output(mut self) -> IoResult { - drop(self.stdin.take()); - fn read(stream: Option) -> Receiver>> { - let (tx, rx) = channel(); - match stream { - Some(stream) => { - thread::spawn(move || { - let mut stream = stream; - tx.send(stream.read_to_end()).unwrap(); - }); - } - None => tx.send(Ok(Vec::new())).unwrap() - } - rx - } - let stdout = read(self.stdout.take()); - let stderr = read(self.stderr.take()); - - let status = try!(self.wait()); - - Ok(ProcessOutput { - status: status, - output: stdout.recv().unwrap().unwrap_or(Vec::new()), - error: stderr.recv().unwrap().unwrap_or(Vec::new()), - }) - } - - /// Forgets this process, allowing it to outlive the parent - /// - /// This function will forcefully prevent calling `wait()` on the child - /// process in the destructor, allowing the child to outlive the - /// parent. Note that this operation can easily lead to leaking the - /// resources of the child process, so care must be taken when - /// invoking this method. - pub fn forget(mut self) { - self.forget = true; - } -} - -impl Drop for Process { - fn drop(&mut self) { - if self.forget { return } - - // Close all I/O before exiting to ensure that the child doesn't wait - // forever to print some text or something similar. - drop(self.stdin.take()); - drop(self.stdout.take()); - drop(self.stderr.take()); - - self.set_timeout(None); - let _ = self.wait().unwrap(); - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use old_io::{Truncate, Write, TimedOut, timer, process, FileNotFound}; - use old_io::{Reader, Writer}; - use old_path::{GenericPath, Path}; - use old_io::fs::PathExtensions; - use old_io::timer::*; - use rt::running_on_valgrind; - use str; - use super::{CreatePipe}; - use super::{InheritFd, Process, PleaseExitSignal, Command, ProcessOutput}; - use sync::mpsc::channel; - use thread; - use time::Duration; - - // FIXME(#10380) these tests should not all be ignored on android. - - #[cfg(not(target_os="android"))] - #[test] - fn smoke() { - let p = Command::new("true").spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[cfg(not(target_os="android"))] - #[test] - fn smoke_failure() { - match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[cfg(not(target_os="android"))] - #[test] - fn exit_reported_right() { - let p = Command::new("false").spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().matches_exit_status(1)); - drop(p.wait().clone()); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn signal_reported_right() { - let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - match p.wait().unwrap() { - process::ExitSignal(9) => {}, - result => panic!("not terminated by signal 9 (instead, {})", result), - } - } - - pub fn read_all(input: &mut Reader) -> String { - input.read_to_string().unwrap() - } - - pub fn run_output(cmd: Command) -> String { - let p = cmd.spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.stdout.is_some()); - let ret = read_all(p.stdout.as_mut().unwrap() as &mut Reader); - assert!(p.wait().unwrap().success()); - return ret; - } - - #[cfg(not(target_os="android"))] - #[test] - fn stdout_works() { - let mut cmd = Command::new("echo"); - cmd.arg("foobar").stdout(CreatePipe(false, true)); - assert_eq!(run_output(cmd), "foobar\n"); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn set_cwd_works() { - let mut cmd = Command::new("/bin/sh"); - cmd.arg("-c").arg("pwd") - .cwd(&Path::new("/")) - .stdout(CreatePipe(false, true)); - assert_eq!(run_output(cmd), "/\n"); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn stdin_works() { - let mut p = Command::new("/bin/sh") - .arg("-c").arg("read line; echo $line") - .stdin(CreatePipe(true, false)) - .stdout(CreatePipe(false, true)) - .spawn().unwrap(); - p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap(); - drop(p.stdin.take()); - let out = read_all(p.stdout.as_mut().unwrap() as &mut Reader); - assert!(p.wait().unwrap().success()); - assert_eq!(out, "foobar\n"); - } - - #[cfg(not(target_os="android"))] - #[test] - fn detach_works() { - let mut p = Command::new("true").detached().spawn().unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[cfg(windows)] - #[test] - fn uid_fails_on_windows() { - assert!(Command::new("test").uid(10).spawn().is_err()); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn uid_works() { - use libc; - let mut p = Command::new("/bin/sh") - .arg("-c").arg("true") - .uid(unsafe { libc::getuid() as usize }) - .gid(unsafe { libc::getgid() as usize }) - .spawn().unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn uid_to_root_fails() { - use libc; - - // if we're already root, this isn't a valid test. Most of the bots run - // as non-root though (android is an exception). - if unsafe { libc::getuid() == 0 } { return } - assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err()); - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_process_status() { - let mut status = Command::new("false").status().unwrap(); - assert!(status.matches_exit_status(1)); - - status = Command::new("true").status().unwrap(); - assert!(status.success()); - } - - #[test] - fn test_process_output_fail_to_start() { - match Command::new("/no-binary-by-this-name-should-exist").output() { - Err(e) => assert_eq!(e.kind, FileNotFound), - Ok(..) => panic!() - } - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_process_output_output() { - let ProcessOutput {status, output, error} - = Command::new("echo").arg("hello").output().unwrap(); - let output_str = str::from_utf8(&output).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - // FIXME #7224 - if !running_on_valgrind() { - assert_eq!(error, Vec::new()); - } - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_process_output_error() { - let ProcessOutput {status, output, error} - = Command::new("mkdir").arg(".").output().unwrap(); - - assert!(status.matches_exit_status(1)); - assert_eq!(output, Vec::new()); - assert!(!error.is_empty()); - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_finish_once() { - let mut prog = Command::new("false").spawn().unwrap(); - assert!(prog.wait().unwrap().matches_exit_status(1)); - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_finish_twice() { - let mut prog = Command::new("false").spawn().unwrap(); - assert!(prog.wait().unwrap().matches_exit_status(1)); - assert!(prog.wait().unwrap().matches_exit_status(1)); - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_wait_with_output_once() { - let prog = Command::new("echo").arg("hello").spawn().unwrap(); - let ProcessOutput {status, output, error} = prog.wait_with_output().unwrap(); - let output_str = str::from_utf8(&output).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - // FIXME #7224 - if !running_on_valgrind() { - assert_eq!(error, Vec::new()); - } - } - - #[cfg(all(unix, not(target_os="android")))] - pub fn pwd_cmd() -> Command { - Command::new("pwd") - } - #[cfg(target_os="android")] - pub fn pwd_cmd() -> Command { - let mut cmd = Command::new("/system/bin/sh"); - cmd.arg("-c").arg("pwd"); - cmd - } - - #[cfg(windows)] - pub fn pwd_cmd() -> Command { - let mut cmd = Command::new("cmd"); - cmd.arg("/c").arg("cd"); - cmd - } - - #[test] - fn test_keep_current_working_dir() { - use os; - let prog = pwd_cmd().spawn().unwrap(); - - let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap()); - let child_dir = Path::new(output.trim()); - - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); - - assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); - assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); - } - - #[test] - fn test_change_working_directory() { - use os; - // test changing to the parent of os::getcwd() because we know - // the path exists (and os::getcwd() is not expected to be root) - let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap()); - let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap(); - - let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - let child_dir = Path::new(output.trim()); - - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); - - assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); - assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); - } - - #[cfg(all(unix, not(target_os="android")))] - pub fn env_cmd() -> Command { - Command::new("env") - } - #[cfg(target_os="android")] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("/system/bin/sh"); - cmd.arg("-c").arg("set"); - cmd - } - - #[cfg(windows)] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("cmd"); - cmd.arg("/c").arg("set"); - cmd - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_inherit_env() { - use os; - if running_on_valgrind() { return; } - - let prog = env_cmd().spawn().unwrap(); - let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - - let r = ::env::vars(); - for (k, v) in r { - // don't check windows magical empty-named variables - assert!(k.is_empty() || - output.contains(&format!("{}={}", k, v)), - "output doesn't contain `{}={}`\n{}", - k, v, output); - } - } - #[cfg(target_os="android")] - #[test] - fn test_inherit_env() { - use os; - if running_on_valgrind() { return; } - - let mut prog = env_cmd().spawn().unwrap(); - let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - - let r = ::env::vars(); - for (k, v) in r { - // don't check android RANDOM variables - if k != "RANDOM".to_string() { - assert!(output.contains(&format!("{}={}", k, v)) || - output.contains(&format!("{}=\'{}\'", k, v))); - } - } - } - - #[test] - fn test_override_env() { - use os; - - // In some build environments (such as chrooted Nix builds), `env` can - // only be found in the explicitly-provided PATH env variable, not in - // default places such as /bin or /usr/bin. So we need to pass through - // PATH to our sub-process. - let path_val: String; - let mut new_env = vec![("RUN_TEST_NEW_ENV", "123")]; - match ::env::var("PATH") { - Err(..) => {} - Ok(val) => { - path_val = val; - new_env.push(("PATH", &path_val)) - } - } - - let prog = env_cmd().env_set_all(&new_env).spawn().unwrap(); - let result = prog.wait_with_output().unwrap(); - let output = String::from_utf8_lossy(&result.output).to_string(); - - assert!(output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); - } - - #[test] - fn test_add_to_env() { - let prog = env_cmd().env("RUN_TEST_NEW_ENV", "123").spawn().unwrap(); - let result = prog.wait_with_output().unwrap(); - let output = String::from_utf8_lossy(&result.output).to_string(); - - assert!(output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); - } - - #[cfg(unix)] - pub fn sleeper() -> Process { - Command::new("sleep").arg("1000").spawn().unwrap() - } - #[cfg(windows)] - pub fn sleeper() -> Process { - // There's a `timeout` command on windows, but it doesn't like having - // its output piped, so instead just ping ourselves a few times with - // gaps in between so we're sure this process is alive for awhile - Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap() - } - - #[test] - fn test_kill() { - let mut p = sleeper(); - Process::kill(p.id(), PleaseExitSignal).unwrap(); - assert!(!p.wait().unwrap().success()); - } - - #[test] - fn test_exists() { - let mut p = sleeper(); - assert!(Process::kill(p.id(), 0).is_ok()); - p.signal_kill().unwrap(); - assert!(!p.wait().unwrap().success()); - } - - #[test] - fn test_zero() { - let mut p = sleeper(); - p.signal_kill().unwrap(); - for _ in 0..20 { - if p.signal(0).is_err() { - assert!(!p.wait().unwrap().success()); - return - } - timer::sleep(Duration::milliseconds(100)); - } - panic!("never saw the child go away"); - } - - #[test] - fn wait_timeout() { - let mut p = sleeper(); - p.set_timeout(Some(10)); - assert_eq!(p.wait().err().unwrap().kind, TimedOut); - assert_eq!(p.wait().err().unwrap().kind, TimedOut); - p.signal_kill().unwrap(); - p.set_timeout(None); - assert!(p.wait().is_ok()); - } - - #[test] - fn wait_timeout2() { - let (tx, rx) = channel(); - let tx2 = tx.clone(); - let _t = thread::spawn(move|| { - let mut p = sleeper(); - p.set_timeout(Some(10)); - assert_eq!(p.wait().err().unwrap().kind, TimedOut); - p.signal_kill().unwrap(); - tx.send(()).unwrap(); - }); - let _t = thread::spawn(move|| { - let mut p = sleeper(); - p.set_timeout(Some(10)); - assert_eq!(p.wait().err().unwrap().kind, TimedOut); - p.signal_kill().unwrap(); - tx2.send(()).unwrap(); - }); - rx.recv().unwrap(); - rx.recv().unwrap(); - } - - #[test] - fn forget() { - let p = sleeper(); - let id = p.id(); - p.forget(); - assert!(Process::kill(id, 0).is_ok()); - assert!(Process::kill(id, PleaseExitSignal).is_ok()); - } - - #[test] - fn dont_close_fd_on_command_spawn() { - use sys::fs; - - let path = if cfg!(windows) { - Path::new("NUL") - } else { - Path::new("/dev/null") - }; - - let fdes = match fs::open(&path, Truncate, Write) { - Ok(f) => f, - Err(_) => panic!("failed to open file descriptor"), - }; - - let mut cmd = pwd_cmd(); - let _ = cmd.stdout(InheritFd(fdes.fd())); - assert!(cmd.status().unwrap().success()); - assert!(fdes.write("extra write\n".as_bytes()).is_ok()); - } - - #[test] - #[cfg(windows)] - fn env_map_keys_ci() { - use ffi::CString; - use super::EnvKey; - let mut cmd = Command::new(""); - cmd.env("path", "foo"); - cmd.env("Path", "bar"); - let env = &cmd.env.unwrap(); - let val = env.get(&EnvKey(CString::new("PATH").unwrap())); - assert!(val.unwrap() == &CString::new("bar").unwrap()); - } -} diff --git a/src/libstd/old_io/result.rs b/src/libstd/old_io/result.rs deleted file mode 100644 index e1037f26b7fcf..0000000000000 --- a/src/libstd/old_io/result.rs +++ /dev/null @@ -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 or the MIT license -// , 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` 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 Writer for IoResult { - 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 Reader for IoResult { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - match *self { - Ok(ref mut reader) => reader.read(buf), - Err(ref e) => Err(e.clone()), - } - } -} - -impl Seek for IoResult { - fn tell(&self) -> IoResult { - 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> Listener for IoResult { - fn listen(self) -> IoResult { - match self { - Ok(listener) => listener.listen(), - Err(e) => Err(e), - } - } -} - -impl Acceptor for IoResult { - type Connection = A::Connection; - fn accept(&mut self) -> IoResult { - 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> = 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> = - 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 = - 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 = - 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), - } - } -} diff --git a/src/libstd/old_io/stdio.rs b/src/libstd/old_io/stdio.rs deleted file mode 100644 index b4924c7b78b75..0000000000000 --- a/src/libstd/old_io/stdio.rs +++ /dev/null @@ -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 or the MIT license -// , 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(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>> = { - RefCell::new(None) - } -} - -struct RaceBox(BufferedReader); - -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>, -} - -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; - - fn deref(&self) -> &BufferedReader { - &self.inner.0 - } -} - -impl<'a> DerefMut for StdinReaderGuard<'a> { - fn deref_mut(&mut self) -> &mut BufferedReader { - &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 { - 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> { - 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 { - self.inner.lock().unwrap().0.read_char() - } -} - -impl Reader for StdinReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - 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 { - self.inner.lock().unwrap().0.read_at_least(min, buf) - } - - fn push_at_least(&mut self, min: usize, len: usize, buf: &mut Vec) -> IoResult { - self.inner.lock().unwrap().0.push_at_least(min, len, buf) - } - - fn read_to_end(&mut self) -> IoResult> { - self.inner.lock().unwrap().0.read_to_end() - } - - fn read_le_uint_n(&mut self, nbytes: usize) -> IoResult { - self.inner.lock().unwrap().0.read_le_uint_n(nbytes) - } - - fn read_be_uint_n(&mut self, nbytes: usize) -> IoResult { - 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 { - 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 { - 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) -> Option> { - 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) -> Option> { - 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) where F: FnOnce(&mut Writer) -> IoResult<()> { - let mut my_stdout: Box = 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 { - 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(); - } -} diff --git a/src/libstd/old_io/tempfile.rs b/src/libstd/old_io/tempfile.rs deleted file mode 100644 index 94faa5540bb30..0000000000000 --- a/src/libstd/old_io/tempfile.rs +++ /dev/null @@ -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 or the MIT license -// , 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, - 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 { - 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 { - 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 diff --git a/src/libstd/old_io/test.rs b/src/libstd/old_io/test.rs deleted file mode 100644 index 312e1c814dc58..0000000000000 --- a/src/libstd/old_io/test.rs +++ /dev/null @@ -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 or the MIT license -// , 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() {} -} diff --git a/src/libstd/old_io/timer.rs b/src/libstd/old_io/timer.rs deleted file mode 100644 index f8cba04444331..0000000000000 --- a/src/libstd/old_io/timer.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - 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(); - } - -} diff --git a/src/libstd/old_io/util.rs b/src/libstd/old_io/util.rs deleted file mode 100644 index 818c8e76d6087..0000000000000 --- a/src/libstd/old_io/util.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - limit: usize, - inner: R -} - -#[deprecated(since = "1.0.0", reason = "use std::io::Take")] -#[unstable(feature = "old_io")] -impl LimitReader { - /// 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 { - 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 Reader for LimitReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - 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 Buffer for LimitReader { - 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 { - 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 { - 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 { - writers: Vec -} - -impl MultiWriter 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) -> MultiWriter { - MultiWriter { writers: writers } - } -} - -#[deprecated(since = "1.0.0", reason = "use std::io::Broadcast instead")] -#[unstable(feature = "old_io")] -impl Writer for MultiWriter 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 { - readers: I, - cur_reader: Option, -} - -impl> ChainedReader { - /// 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 { - 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> Reader for ChainedReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - 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 { - reader: R, - writer: W, -} - -#[deprecated(since = "1.0.0", reason = "use std::io::Tee instead")] -#[unstable(feature = "old_io")] -impl TeeReader { - /// 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 { - 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 Reader for TeeReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - 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: &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` to a `Reader`. -#[derive(Clone, Debug)] -pub struct IterReader { - iter: T, -} - -impl> IterReader { - /// Creates a new `IterReader` which will read from the specified - /// `Iterator`. - pub fn new(iter: T) -> IterReader { - IterReader { iter: iter } - } -} - -impl> Reader for IterReader { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - 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, - box TestWriter as Box)); - 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)); - } -} diff --git a/src/libstd/old_path/mod.rs b/src/libstd/old_path/mod.rs deleted file mode 100644 index 2dee90e9a6660..0000000000000 --- a/src/libstd/old_path/mod.rs +++ /dev/null @@ -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 or the MIT license -// , 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(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(path: T) -> Option { - 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; - - /// 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(&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(&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(&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(&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; - - /// 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(&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(&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(&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(&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; - - /// 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 :: 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(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(&mut self, filename: T); - - /// Pushes a path onto `self` without checking for null bytes. - /// See `push` for details. - unsafe fn push_unchecked(&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 { - #[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(v: &T) -> bool { - v.container_as_bytes().iter().any(|&x| x == 0) -} diff --git a/src/libstd/old_path/posix.rs b/src/libstd/old_path/posix.rs deleted file mode 100644 index af63be2aa9e3f..0000000000000 --- a/src/libstd/old_path/posix.rs +++ /dev/null @@ -1,1347 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! POSIX file path handling - -use clone::Clone; -use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; -use fmt; -use hash; -use old_io::Writer; -use iter::{Extend, Iterator, Map}; -use marker::Sized; -use option::Option::{self, Some, None}; -use result::Result::{self, Ok, Err}; -use slice::{Split, SliceConcatExt}; -use str::{self, FromStr}; -use vec::Vec; - -use super::{BytesContainer, GenericPath, GenericPathUnsafe}; - -/// Iterator that yields successive components of a Path as &[u8] -pub type Components<'a> = Split<'a, u8, fn(&u8) -> bool>; - -/// Iterator that yields successive components of a Path as Option<&str> -pub type StrComponents<'a> = - Map, fn(&[u8]) -> Option<&str>>; - -/// Represents a POSIX file path -#[derive(Clone)] -pub struct Path { - repr: Vec, // assumed to never be empty or contain NULs - sepidx: Option // index of the final separator in repr -} - -/// The standard path separator character -pub const SEP: char = '/'; - -/// The standard path separator byte -pub const SEP_BYTE: u8 = SEP as u8; - -/// Returns whether the given byte is a path separator -#[inline] -pub fn is_sep_byte(u: &u8) -> bool { - *u as char == SEP -} - -/// Returns whether the given char is a path separator -#[inline] -pub fn is_sep(c: char) -> bool { - c == SEP -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Path { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.display(), f) - } -} - -impl PartialEq for Path { - #[inline] - fn eq(&self, other: &Path) -> bool { - self.repr == other.repr - } -} - -impl Eq for Path {} - -impl PartialOrd for Path { - fn partial_cmp(&self, other: &Path) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Path { - fn cmp(&self, other: &Path) -> Ordering { - self.repr.cmp(&other.repr) - } -} - -impl FromStr for Path { - type Err = ParsePathError; - fn from_str(s: &str) -> Result { - match Path::new_opt(s) { - Some(p) => Ok(p), - None => Err(ParsePathError), - } - } -} - -/// Valuelue indicating that a path could not be parsed from a string. -#[derive(Debug, Clone, PartialEq, Copy)] -pub struct ParsePathError; - -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for Path { - #[inline] - fn hash(&self, state: &mut H) { - self.repr.hash(state) - } -} - -impl BytesContainer for Path { - #[inline] - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - self.as_vec() - } -} - -impl GenericPathUnsafe for Path { - unsafe fn new_unchecked(path: T) -> Path { - let path = Path::normalize(path.container_as_bytes()); - assert!(!path.is_empty()); - let idx = path.rposition_elem(&SEP_BYTE); - Path{ repr: path, sepidx: idx } - } - - unsafe fn set_filename_unchecked(&mut self, filename: T) { - let filename = filename.container_as_bytes(); - match self.sepidx { - None if self.repr == b".." => { - let mut v = Vec::with_capacity(3 + filename.len()); - v.push_all(dot_dot_static); - v.push(SEP_BYTE); - v.push_all(filename); - // FIXME: this is slow - self.repr = Path::normalize(&v); - } - None => { - self.repr = Path::normalize(filename); - } - Some(idx) if &self.repr[idx+1..] == b".." => { - let mut v = Vec::with_capacity(self.repr.len() + 1 + filename.len()); - v.push_all(&self.repr); - v.push(SEP_BYTE); - v.push_all(filename); - // FIXME: this is slow - self.repr = Path::normalize(&v); - } - Some(idx) => { - let mut v = Vec::with_capacity(idx + 1 + filename.len()); - v.push_all(&self.repr[..idx+1]); - v.push_all(filename); - // FIXME: this is slow - self.repr = Path::normalize(&v); - } - } - self.sepidx = self.repr.rposition_elem(&SEP_BYTE); - } - - unsafe fn push_unchecked(&mut self, path: T) { - let path = path.container_as_bytes(); - if !path.is_empty() { - if path[0] == SEP_BYTE { - self.repr = Path::normalize(path); - } else { - let mut v = Vec::with_capacity(self.repr.len() + path.len() + 1); - v.push_all(&self.repr); - v.push(SEP_BYTE); - v.push_all(path); - // FIXME: this is slow - self.repr = Path::normalize(&v); - } - self.sepidx = self.repr.rposition_elem(&SEP_BYTE); - } - } -} - -impl GenericPath for Path { - #[inline] - fn as_vec<'a>(&'a self) -> &'a [u8] { - &self.repr - } - - fn into_vec(self) -> Vec { - self.repr - } - - fn dirname<'a>(&'a self) -> &'a [u8] { - match self.sepidx { - None if self.repr == b".." => &self.repr, - None => dot_static, - Some(0) => &self.repr[..1], - Some(idx) if &self.repr[idx+1..] == b".." => &self.repr, - Some(idx) => &self.repr[..idx] - } - } - - fn filename<'a>(&'a self) -> Option<&'a [u8]> { - match self.sepidx { - None if self.repr == b"." || self.repr == b".." => None, - None => Some(&self.repr), - Some(idx) if &self.repr[idx+1..] == b".." => None, - Some(0) if self.repr[1..].is_empty() => None, - Some(idx) => Some(&self.repr[idx+1..]) - } - } - - fn pop(&mut self) -> bool { - match self.sepidx { - None if self.repr == b"." => false, - None => { - self.repr = vec![b'.']; - self.sepidx = None; - true - } - Some(0) if self.repr == b"/" => false, - Some(idx) => { - if idx == 0 { - self.repr.truncate(idx+1); - } else { - self.repr.truncate(idx); - } - self.sepidx = self.repr.rposition_elem(&SEP_BYTE); - true - } - } - } - - fn root_path(&self) -> Option { - if self.is_absolute() { - Some(Path::new("/")) - } else { - None - } - } - - #[inline] - fn is_absolute(&self) -> bool { - self.repr[0] == SEP_BYTE - } - - fn is_ancestor_of(&self, other: &Path) -> bool { - if self.is_absolute() != other.is_absolute() { - false - } else { - let mut ita = self.components(); - let mut itb = other.components(); - if self.repr == b"." { - return match itb.next() { - None => true, - Some(b) => b != b".." - }; - } - loop { - match (ita.next(), itb.next()) { - (None, _) => break, - (Some(a), Some(b)) if a == b => { continue }, - (Some(a), _) if a == b".." => { - // if ita contains only .. components, it's an ancestor - return ita.all(|x| x == b".."); - } - _ => return false - } - } - true - } - } - - fn path_relative_from(&self, base: &Path) -> Option { - if self.is_absolute() != base.is_absolute() { - if self.is_absolute() { - Some(self.clone()) - } else { - None - } - } else { - let mut ita = self.components(); - let mut itb = base.components(); - let mut comps = vec![]; - loop { - match (ita.next(), itb.next()) { - (None, None) => break, - (Some(a), None) => { - comps.push(a); - comps.extend(ita.by_ref()); - break; - } - (None, _) => comps.push(dot_dot_static), - (Some(a), Some(b)) if comps.is_empty() && a == b => (), - (Some(a), Some(b)) if b == b"." => comps.push(a), - (Some(_), Some(b)) if b == b".." => return None, - (Some(a), Some(_)) => { - comps.push(dot_dot_static); - for _ in itb { - comps.push(dot_dot_static); - } - comps.push(a); - comps.extend(ita.by_ref()); - break; - } - } - } - Some(Path::new(comps.connect(&SEP_BYTE))) - } - } - - fn ends_with_path(&self, child: &Path) -> bool { - if !child.is_relative() { return false; } - let mut selfit = self.components().rev(); - let mut childit = child.components().rev(); - loop { - match (selfit.next(), childit.next()) { - (Some(a), Some(b)) => if a != b { return false; }, - (Some(_), None) => break, - (None, Some(_)) => return false, - (None, None) => break - } - } - true - } -} - -impl Path { - /// Returns a new Path from a byte vector or string - /// - /// # Panics - /// - /// Panics the task if the vector contains a NUL. - #[inline] - pub fn new(path: T) -> Path { - GenericPath::new(path) - } - - /// Returns a new Path from a byte vector or string, if possible - #[inline] - pub fn new_opt(path: T) -> Option { - GenericPath::new_opt(path) - } - - /// Returns a normalized byte vector representation of a path, by removing all empty - /// components, and unnecessary . and .. components. - fn normalize(v: &[u8]) -> Vec { - // borrowck is being very picky - let val = { - let is_abs = !v.is_empty() && v[0] == SEP_BYTE; - let v_ = if is_abs { &v[1..] } else { v }; - let comps = normalize_helper(v_, is_abs); - match comps { - None => None, - Some(comps) => { - if is_abs && comps.is_empty() { - Some(vec![SEP_BYTE]) - } else { - let n = if is_abs { comps.len() } else { comps.len() - 1} + - comps.iter().map(|v| v.len()).sum::(); - let mut v = Vec::with_capacity(n); - let mut it = comps.into_iter(); - if !is_abs { - match it.next() { - None => (), - Some(comp) => v.push_all(comp) - } - } - for comp in it { - v.push(SEP_BYTE); - v.push_all(comp); - } - Some(v) - } - } - } - }; - match val { - None => v.to_vec(), - Some(val) => val - } - } - - /// Returns an iterator that yields each component of the path in turn. - /// Does not distinguish between absolute and relative paths, e.g. - /// /a/b/c and a/b/c yield the same set of components. - /// A path of "/" yields no components. A path of "." yields one component. - pub fn components<'a>(&'a self) -> Components<'a> { - let v = if self.repr[0] == SEP_BYTE { - &self.repr[1..] - } else { &*self.repr }; - let is_sep_byte: fn(&u8) -> bool = is_sep_byte; // coerce to fn ptr - let mut ret = v.split(is_sep_byte); - if v.is_empty() { - // consume the empty "" component - ret.next(); - } - ret - } - - /// Returns an iterator that yields each component of the path as Option<&str>. - /// See components() for details. - pub fn str_components<'a>(&'a self) -> StrComponents<'a> { - fn from_utf8(s: &[u8]) -> Option<&str> { - str::from_utf8(s).ok() - } - let f: fn(&[u8]) -> Option<&str> = from_utf8; // coerce to fn ptr - self.components().map(f) - } -} - -// None result means the byte vector didn't need normalizing -fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option> { - if is_abs && v.is_empty() { - return None; - } - let mut comps: Vec<&'a [u8]> = vec![]; - let mut n_up = 0; - let mut changed = false; - for comp in v.split(is_sep_byte) { - if comp.is_empty() { changed = true } - else if comp == b"." { changed = true } - else if comp == b".." { - if is_abs && comps.is_empty() { changed = true } - else if comps.len() == n_up { comps.push(dot_dot_static); n_up += 1 } - else { comps.pop().unwrap(); changed = true } - } else { comps.push(comp) } - } - if changed { - if comps.is_empty() && !is_abs { - if v == b"." { - return None; - } - comps.push(dot_static); - } - Some(comps) - } else { - None - } -} - -#[allow(non_upper_case_globals)] -static dot_static: &'static [u8] = b"."; -#[allow(non_upper_case_globals)] -static dot_dot_static: &'static [u8] = b".."; - -#[cfg(test)] -mod tests { - use super::*; - - use clone::Clone; - use option::Option::{self, Some, None}; - use old_path::GenericPath; - use str; - use string::ToString; - use vec::Vec; - use iter::Iterator; - - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = $path; - assert_eq!(path.as_str(), Some($exp)); - } - ); - (v: $path:expr, $exp:expr) => ( - { - let path = $path; - assert_eq!(path.as_vec(), $exp); - } - ) - } - - #[test] - fn test_paths() { - let empty: &[u8] = &[]; - t!(v: Path::new(empty), b"."); - t!(v: Path::new(&b"/"[..]), b"/"); - t!(v: Path::new(&b"a/b/c"[..]), b"a/b/c"); - t!(v: Path::new(&b"a/b/c\xFF"[..]), b"a/b/c\xFF"); - t!(v: Path::new(&b"\xFF/../foo\x80"[..]), b"foo\x80"); - let p = Path::new(&b"a/b/c\xFF"[..]); - assert!(p.as_str().is_none()); - - t!(s: Path::new(""), "."); - t!(s: Path::new("/"), "/"); - t!(s: Path::new("hi"), "hi"); - t!(s: Path::new("hi/"), "hi"); - t!(s: Path::new("/lib"), "/lib"); - t!(s: Path::new("/lib/"), "/lib"); - t!(s: Path::new("hi/there"), "hi/there"); - t!(s: Path::new("hi/there.txt"), "hi/there.txt"); - - t!(s: Path::new("hi/there/"), "hi/there"); - t!(s: Path::new("hi/../there"), "there"); - t!(s: Path::new("../hi/there"), "../hi/there"); - t!(s: Path::new("/../hi/there"), "/hi/there"); - t!(s: Path::new("foo/.."), "."); - t!(s: Path::new("/foo/.."), "/"); - t!(s: Path::new("/foo/../.."), "/"); - t!(s: Path::new("/foo/../../bar"), "/bar"); - t!(s: Path::new("/./hi/./there/."), "/hi/there"); - t!(s: Path::new("/./hi/./there/./.."), "/hi"); - t!(s: Path::new("foo/../.."), ".."); - t!(s: Path::new("foo/../../.."), "../.."); - t!(s: Path::new("foo/../../bar"), "../bar"); - - assert_eq!(Path::new(&b"foo/bar"[..]).into_vec(), b"foo/bar"); - assert_eq!(Path::new(&b"/foo/../../bar"[..]).into_vec(), - b"/bar"); - - let p = Path::new(&b"foo/bar\x80"[..]); - assert!(p.as_str().is_none()); - } - - #[test] - fn test_opt_paths() { - assert!(Path::new_opt(&b"foo/bar\0"[..]).is_none()); - t!(v: Path::new_opt(&b"foo/bar"[..]).unwrap(), b"foo/bar"); - assert!(Path::new_opt("foo/bar\0").is_none()); - t!(s: Path::new_opt("foo/bar").unwrap(), "foo/bar"); - } - - #[test] - fn test_null_byte() { - use thread; - let result = thread::spawn(move|| { - Path::new(&b"foo/bar\0"[..]); - }).join(); - assert!(result.is_err()); - - let result = thread::spawn(move|| { - Path::new("test").set_filename(&b"f\0o"[..]) - }).join(); - assert!(result.is_err()); - - let result = thread::spawn(move|| { - Path::new("test").push(&b"f\0o"[..]); - }).join(); - assert!(result.is_err()); - } - - #[test] - fn test_display_str() { - macro_rules! t { - ($path:expr, $disp:ident, $exp:expr) => ( - { - let path = Path::new($path); - assert_eq!(path.$disp().to_string(), $exp); - } - ) - } - t!("foo", display, "foo"); - t!(&b"foo\x80"[..], display, "foo\u{FFFD}"); - t!(&b"foo\xFFbar"[..], display, "foo\u{FFFD}bar"); - t!(&b"foo\xFF/bar"[..], filename_display, "bar"); - t!(&b"foo/\xFFbar"[..], filename_display, "\u{FFFD}bar"); - t!(&b"/"[..], filename_display, ""); - - macro_rules! t { - ($path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let mo = path.display().as_cow(); - assert_eq!(mo, $exp); - } - ); - ($path:expr, $exp:expr, filename) => ( - { - let path = Path::new($path); - let mo = path.filename_display().as_cow(); - assert_eq!(mo, $exp); - } - ) - } - - t!("foo", "foo"); - t!(&b"foo\x80"[..], "foo\u{FFFD}"); - t!(&b"foo\xFFbar"[..], "foo\u{FFFD}bar"); - t!(&b"foo\xFF/bar"[..], "bar", filename); - t!(&b"foo/\xFFbar"[..], "\u{FFFD}bar", filename); - t!(&b"/"[..], "", filename); - } - - #[test] - fn test_display() { - macro_rules! t { - ($path:expr, $exp:expr, $expf:expr) => ( - { - let path = Path::new($path); - let f = format!("{}", path.display()); - assert_eq!(f, $exp); - let f = format!("{}", path.filename_display()); - assert_eq!(f, $expf); - } - ) - } - - t!(&b"foo"[..], "foo", "foo"); - t!(&b"foo/bar"[..], "foo/bar", "bar"); - t!(&b"/"[..], "/", ""); - t!(&b"foo\xFF"[..], "foo\u{FFFD}", "foo\u{FFFD}"); - t!(&b"foo\xFF/bar"[..], "foo\u{FFFD}/bar", "bar"); - t!(&b"foo/\xFFbar"[..], "foo/\u{FFFD}bar", "\u{FFFD}bar"); - t!(&b"\xFFfoo/bar\xFF"[..], "\u{FFFD}foo/bar\u{FFFD}", "bar\u{FFFD}"); - } - - #[test] - fn test_components() { - macro_rules! t { - (s: $path:expr, $op:ident, $exp:expr) => ( - { - let path = Path::new($path); - assert_eq!(path.$op(), ($exp).as_bytes()); - } - ); - (s: $path:expr, $op:ident, $exp:expr, opt) => ( - { - let path = Path::new($path); - let left = path.$op().map(|x| str::from_utf8(x).unwrap()); - assert_eq!(left, $exp); - } - ); - (v: $path:expr, $op:ident, $exp:expr) => ( - { - let arg = $path; - let path = Path::new(arg); - assert_eq!(path.$op(), $exp); - } - ); - } - - t!(v: &b"a/b/c"[..], filename, Some(&b"c"[..])); - t!(v: &b"a/b/c\xFF"[..], filename, Some(&b"c\xFF"[..])); - t!(v: &b"a/b\xFF/c"[..], filename, Some(&b"c"[..])); - t!(s: "a/b/c", filename, Some("c"), opt); - t!(s: "/a/b/c", filename, Some("c"), opt); - t!(s: "a", filename, Some("a"), opt); - t!(s: "/a", filename, Some("a"), opt); - t!(s: ".", filename, None, opt); - t!(s: "/", filename, None, opt); - t!(s: "..", filename, None, opt); - t!(s: "../..", filename, None, opt); - - t!(v: &b"a/b/c"[..], dirname, b"a/b"); - t!(v: &b"a/b/c\xFF"[..], dirname, b"a/b"); - t!(v: &b"a/b\xFF/c"[..], dirname, b"a/b\xFF"); - t!(s: "a/b/c", dirname, "a/b"); - t!(s: "/a/b/c", dirname, "/a/b"); - t!(s: "a", dirname, "."); - t!(s: "/a", dirname, "/"); - t!(s: ".", dirname, "."); - t!(s: "/", dirname, "/"); - t!(s: "..", dirname, ".."); - t!(s: "../..", dirname, "../.."); - - t!(v: &b"hi/there.txt"[..], filestem, Some(&b"there"[..])); - t!(v: &b"hi/there\x80.txt"[..], filestem, Some(&b"there\x80"[..])); - t!(v: &b"hi/there.t\x80xt"[..], filestem, Some(&b"there"[..])); - t!(s: "hi/there.txt", filestem, Some("there"), opt); - t!(s: "hi/there", filestem, Some("there"), opt); - t!(s: "there.txt", filestem, Some("there"), opt); - t!(s: "there", filestem, Some("there"), opt); - t!(s: ".", filestem, None, opt); - t!(s: "/", filestem, None, opt); - t!(s: "foo/.bar", filestem, Some(".bar"), opt); - t!(s: ".bar", filestem, Some(".bar"), opt); - t!(s: "..bar", filestem, Some("."), opt); - t!(s: "hi/there..txt", filestem, Some("there."), opt); - t!(s: "..", filestem, None, opt); - t!(s: "../..", filestem, None, opt); - - t!(v: &b"hi/there.txt"[..], extension, Some(&b"txt"[..])); - t!(v: &b"hi/there\x80.txt"[..], extension, Some(&b"txt"[..])); - t!(v: &b"hi/there.t\x80xt"[..], extension, Some(&b"t\x80xt"[..])); - t!(v: &b"hi/there"[..], extension, None); - t!(v: &b"hi/there\x80"[..], extension, None); - t!(s: "hi/there.txt", extension, Some("txt"), opt); - t!(s: "hi/there", extension, None, opt); - t!(s: "there.txt", extension, Some("txt"), opt); - t!(s: "there", extension, None, opt); - t!(s: ".", extension, None, opt); - t!(s: "/", extension, None, opt); - t!(s: "foo/.bar", extension, None, opt); - t!(s: ".bar", extension, None, opt); - t!(s: "..bar", extension, Some("bar"), opt); - t!(s: "hi/there..txt", extension, Some("txt"), opt); - t!(s: "..", extension, None, opt); - t!(s: "../..", extension, None, opt); - } - - #[test] - fn test_push() { - macro_rules! t { - (s: $path:expr, $join:expr) => ( - { - let path = $path; - let join = $join; - let mut p1 = Path::new(path); - let p2 = p1.clone(); - p1.push(join); - assert_eq!(p1, p2.join(join)); - } - ) - } - - t!(s: "a/b/c", ".."); - t!(s: "/a/b/c", "d"); - t!(s: "a/b", "c/d"); - t!(s: "a/b", "/c/d"); - } - - #[test] - fn test_push_path() { - macro_rules! t { - (s: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - let push = Path::new($push); - p.push(&push); - assert_eq!(p.as_str(), Some($exp)); - } - ) - } - - t!(s: "a/b/c", "d", "a/b/c/d"); - t!(s: "/a/b/c", "d", "/a/b/c/d"); - t!(s: "a/b", "c/d", "a/b/c/d"); - t!(s: "a/b", "/c/d", "/c/d"); - t!(s: "a/b", ".", "a/b"); - t!(s: "a/b", "../c", "a/c"); - } - - #[test] - fn test_push_many() { - macro_rules! t { - (s: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - p.push_many(&$push); - assert_eq!(p.as_str(), Some($exp)); - } - ); - (v: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - p.push_many(&$push); - assert_eq!(p.as_vec(), $exp); - } - ) - } - - t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e"); - t!(s: "a/b/c", ["d", "/e"], "/e"); - t!(s: "a/b/c", ["d", "/e", "f"], "/e/f"); - t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e"); - t!(v: &b"a/b/c"[..], [&b"d"[..], &b"e"[..]], b"a/b/c/d/e"); - t!(v: &b"a/b/c"[..], [&b"d"[..], &b"/e"[..], &b"f"[..]], b"/e/f"); - t!(v: &b"a/b/c"[..], [b"d".to_vec(), b"e".to_vec()], b"a/b/c/d/e"); - } - - #[test] - fn test_pop() { - macro_rules! t { - (s: $path:expr, $left:expr, $right:expr) => ( - { - let mut p = Path::new($path); - let result = p.pop(); - assert_eq!(p.as_str(), Some($left)); - assert_eq!(result, $right); - } - ); - (b: $path:expr, $left:expr, $right:expr) => ( - { - let mut p = Path::new($path); - let result = p.pop(); - assert_eq!(p.as_vec(), $left); - assert_eq!(result, $right); - } - ) - } - - t!(b: &b"a/b/c"[..], b"a/b", true); - t!(b: &b"a"[..], b".", true); - t!(b: &b"."[..], b".", false); - t!(b: &b"/a"[..], b"/", true); - t!(b: &b"/"[..], b"/", false); - t!(b: &b"a/b/c\x80"[..], b"a/b", true); - t!(b: &b"a/b\x80/c"[..], b"a/b\x80", true); - t!(b: &b"\xFF"[..], b".", true); - t!(b: &b"/\xFF"[..], b"/", true); - t!(s: "a/b/c", "a/b", true); - t!(s: "a", ".", true); - t!(s: ".", ".", false); - t!(s: "/a", "/", true); - t!(s: "/", "/", false); - } - - #[test] - fn test_root_path() { - assert_eq!(Path::new(&b"a/b/c"[..]).root_path(), None); - assert_eq!(Path::new(&b"/a/b/c"[..]).root_path(), Some(Path::new("/"))); - } - - #[test] - fn test_join() { - t!(v: Path::new(&b"a/b/c"[..]).join(&b".."[..]), b"a/b"); - t!(v: Path::new(&b"/a/b/c"[..]).join(&b"d"[..]), b"/a/b/c/d"); - t!(v: Path::new(&b"a/\x80/c"[..]).join(&b"\xFF"[..]), b"a/\x80/c/\xFF"); - t!(s: Path::new("a/b/c").join(".."), "a/b"); - t!(s: Path::new("/a/b/c").join("d"), "/a/b/c/d"); - t!(s: Path::new("a/b").join("c/d"), "a/b/c/d"); - t!(s: Path::new("a/b").join("/c/d"), "/c/d"); - t!(s: Path::new(".").join("a/b"), "a/b"); - t!(s: Path::new("/").join("a/b"), "/a/b"); - } - - #[test] - fn test_join_path() { - macro_rules! t { - (s: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let join = Path::new($join); - let res = path.join(&join); - assert_eq!(res.as_str(), Some($exp)); - } - ) - } - - t!(s: "a/b/c", "..", "a/b"); - t!(s: "/a/b/c", "d", "/a/b/c/d"); - t!(s: "a/b", "c/d", "a/b/c/d"); - t!(s: "a/b", "/c/d", "/c/d"); - t!(s: ".", "a/b", "a/b"); - t!(s: "/", "a/b", "/a/b"); - } - - #[test] - fn test_join_many() { - macro_rules! t { - (s: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let res = path.join_many(&$join); - assert_eq!(res.as_str(), Some($exp)); - } - ); - (v: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let res = path.join_many(&$join); - assert_eq!(res.as_vec(), $exp); - } - ) - } - - t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e"); - t!(s: "a/b/c", ["..", "d"], "a/b/d"); - t!(s: "a/b/c", ["d", "/e", "f"], "/e/f"); - t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e"); - t!(v: &b"a/b/c"[..], [&b"d"[..], &b"e"[..]], b"a/b/c/d/e"); - t!(v: &b"a/b/c"[..], [b"d".to_vec(), b"e".to_vec()], b"a/b/c/d/e"); - } - - #[test] - fn test_with_helpers() { - let empty: &[u8] = &[]; - - t!(v: Path::new(&b"a/b/c"[..]).with_filename(&b"d"[..]), b"a/b/d"); - t!(v: Path::new(&b"a/b/c\xFF"[..]).with_filename(&b"\x80"[..]), b"a/b/\x80"); - t!(v: Path::new(&b"/\xFF/foo"[..]).with_filename(&b"\xCD"[..]), - b"/\xFF/\xCD"); - t!(s: Path::new("a/b/c").with_filename("d"), "a/b/d"); - t!(s: Path::new(".").with_filename("foo"), "foo"); - t!(s: Path::new("/a/b/c").with_filename("d"), "/a/b/d"); - t!(s: Path::new("/").with_filename("foo"), "/foo"); - t!(s: Path::new("/a").with_filename("foo"), "/foo"); - t!(s: Path::new("foo").with_filename("bar"), "bar"); - t!(s: Path::new("/").with_filename("foo/"), "/foo"); - t!(s: Path::new("/a").with_filename("foo/"), "/foo"); - t!(s: Path::new("a/b/c").with_filename(""), "a/b"); - t!(s: Path::new("a/b/c").with_filename("."), "a/b"); - t!(s: Path::new("a/b/c").with_filename(".."), "a"); - t!(s: Path::new("/a").with_filename(""), "/"); - t!(s: Path::new("foo").with_filename(""), "."); - t!(s: Path::new("a/b/c").with_filename("d/e"), "a/b/d/e"); - t!(s: Path::new("a/b/c").with_filename("/d"), "a/b/d"); - t!(s: Path::new("..").with_filename("foo"), "../foo"); - t!(s: Path::new("../..").with_filename("foo"), "../../foo"); - t!(s: Path::new("..").with_filename(""), ".."); - t!(s: Path::new("../..").with_filename(""), "../.."); - - t!(v: Path::new(&b"hi/there\x80.txt"[..]).with_extension(&b"exe"[..]), - b"hi/there\x80.exe"); - t!(v: Path::new(&b"hi/there.txt\x80"[..]).with_extension(&b"\xFF"[..]), - b"hi/there.\xFF"); - t!(v: Path::new(&b"hi/there\x80"[..]).with_extension(&b"\xFF"[..]), - b"hi/there\x80.\xFF"); - t!(v: Path::new(&b"hi/there.\xFF"[..]).with_extension(empty), b"hi/there"); - t!(s: Path::new("hi/there.txt").with_extension("exe"), "hi/there.exe"); - t!(s: Path::new("hi/there.txt").with_extension(""), "hi/there"); - t!(s: Path::new("hi/there.txt").with_extension("."), "hi/there.."); - t!(s: Path::new("hi/there.txt").with_extension(".."), "hi/there..."); - t!(s: Path::new("hi/there").with_extension("txt"), "hi/there.txt"); - t!(s: Path::new("hi/there").with_extension("."), "hi/there.."); - t!(s: Path::new("hi/there").with_extension(".."), "hi/there..."); - t!(s: Path::new("hi/there.").with_extension("txt"), "hi/there.txt"); - t!(s: Path::new("hi/.foo").with_extension("txt"), "hi/.foo.txt"); - t!(s: Path::new("hi/there.txt").with_extension(".foo"), "hi/there..foo"); - t!(s: Path::new("/").with_extension("txt"), "/"); - t!(s: Path::new("/").with_extension("."), "/"); - t!(s: Path::new("/").with_extension(".."), "/"); - t!(s: Path::new(".").with_extension("txt"), "."); - } - - #[test] - fn test_setters() { - macro_rules! t { - (s: $path:expr, $set:ident, $with:ident, $arg:expr) => ( - { - let path = $path; - let arg = $arg; - let mut p1 = Path::new(path); - p1.$set(arg); - let p2 = Path::new(path); - assert_eq!(p1, p2.$with(arg)); - } - ); - (v: $path:expr, $set:ident, $with:ident, $arg:expr) => ( - { - let path = $path; - let arg = $arg; - let mut p1 = Path::new(path); - p1.$set(arg); - let p2 = Path::new(path); - assert_eq!(p1, p2.$with(arg)); - } - ) - } - - t!(v: &b"a/b/c"[..], set_filename, with_filename, &b"d"[..]); - t!(v: &b"/"[..], set_filename, with_filename, &b"foo"[..]); - t!(v: &b"\x80"[..], set_filename, with_filename, &b"\xFF"[..]); - t!(s: "a/b/c", set_filename, with_filename, "d"); - t!(s: "/", set_filename, with_filename, "foo"); - t!(s: ".", set_filename, with_filename, "foo"); - t!(s: "a/b", set_filename, with_filename, ""); - t!(s: "a", set_filename, with_filename, ""); - - t!(v: &b"hi/there.txt"[..], set_extension, with_extension, &b"exe"[..]); - t!(v: &b"hi/there.t\x80xt"[..], set_extension, with_extension, &b"exe\xFF"[..]); - t!(s: "hi/there.txt", set_extension, with_extension, "exe"); - t!(s: "hi/there.", set_extension, with_extension, "txt"); - t!(s: "hi/there", set_extension, with_extension, "txt"); - t!(s: "hi/there.txt", set_extension, with_extension, ""); - t!(s: "hi/there", set_extension, with_extension, ""); - t!(s: ".", set_extension, with_extension, "txt"); - } - - #[test] - fn test_getters() { - macro_rules! t { - (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( - { - let path = $path; - assert_eq!(path.filename_str(), $filename); - assert_eq!(path.dirname_str(), $dirname); - assert_eq!(path.filestem_str(), $filestem); - assert_eq!(path.extension_str(), $ext); - } - ); - (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( - { - let path = $path; - assert_eq!(path.filename(), $filename); - assert_eq!(path.dirname(), $dirname); - assert_eq!(path.filestem(), $filestem); - assert_eq!(path.extension(), $ext); - } - ) - } - - t!(v: Path::new(&b"a/b/c"[..]), Some(&b"c"[..]), b"a/b", Some(&b"c"[..]), None); - t!(v: Path::new(&b"a/b/\xFF"[..]), Some(&b"\xFF"[..]), b"a/b", Some(&b"\xFF"[..]), None); - t!(v: Path::new(&b"hi/there.\xFF"[..]), Some(&b"there.\xFF"[..]), b"hi", - Some(&b"there"[..]), Some(&b"\xFF"[..])); - t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None); - t!(s: Path::new("."), None, Some("."), None, None); - t!(s: Path::new("/"), None, Some("/"), None, None); - t!(s: Path::new(".."), None, Some(".."), None, None); - t!(s: Path::new("../.."), None, Some("../.."), None, None); - t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"), - Some("there"), Some("txt")); - t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None); - t!(s: Path::new("hi/there."), Some("there."), Some("hi"), - Some("there"), Some("")); - t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None); - t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"), - Some("."), Some("there")); - t!(s: Path::new(&b"a/b/\xFF"[..]), None, Some("a/b"), None, None); - t!(s: Path::new(&b"a/b/\xFF.txt"[..]), None, Some("a/b"), None, Some("txt")); - t!(s: Path::new(&b"a/b/c.\x80"[..]), None, Some("a/b"), Some("c"), None); - t!(s: Path::new(&b"\xFF/b"[..]), Some("b"), None, Some("b"), None); - } - - #[test] - fn test_dir_path() { - t!(v: Path::new(&b"hi/there\x80"[..]).dir_path(), b"hi"); - t!(v: Path::new(&b"hi\xFF/there"[..]).dir_path(), b"hi\xFF"); - t!(s: Path::new("hi/there").dir_path(), "hi"); - t!(s: Path::new("hi").dir_path(), "."); - t!(s: Path::new("/hi").dir_path(), "/"); - t!(s: Path::new("/").dir_path(), "/"); - t!(s: Path::new("..").dir_path(), ".."); - t!(s: Path::new("../..").dir_path(), "../.."); - } - - #[test] - fn test_is_absolute() { - macro_rules! t { - (s: $path:expr, $abs:expr, $rel:expr) => ( - { - let path = Path::new($path); - assert_eq!(path.is_absolute(), $abs); - assert_eq!(path.is_relative(), $rel); - } - ) - } - t!(s: "a/b/c", false, true); - t!(s: "/a/b/c", true, false); - t!(s: "a", false, true); - t!(s: "/a", true, false); - t!(s: ".", false, true); - t!(s: "/", true, false); - t!(s: "..", false, true); - t!(s: "../..", false, true); - } - - #[test] - fn test_is_ancestor_of() { - macro_rules! t { - (s: $path:expr, $dest:expr, $exp:expr) => ( - { - let path = Path::new($path); - let dest = Path::new($dest); - assert_eq!(path.is_ancestor_of(&dest), $exp); - } - ) - } - - t!(s: "a/b/c", "a/b/c/d", true); - t!(s: "a/b/c", "a/b/c", true); - t!(s: "a/b/c", "a/b", false); - t!(s: "/a/b/c", "/a/b/c", true); - t!(s: "/a/b", "/a/b/c", true); - t!(s: "/a/b/c/d", "/a/b/c", false); - t!(s: "/a/b", "a/b/c", false); - t!(s: "a/b", "/a/b/c", false); - t!(s: "a/b/c", "a/b/d", false); - t!(s: "../a/b/c", "a/b/c", false); - t!(s: "a/b/c", "../a/b/c", false); - t!(s: "a/b/c", "a/b/cd", false); - t!(s: "a/b/cd", "a/b/c", false); - t!(s: "../a/b", "../a/b/c", true); - t!(s: ".", "a/b", true); - t!(s: ".", ".", true); - t!(s: "/", "/", true); - t!(s: "/", "/a/b", true); - t!(s: "..", "a/b", true); - t!(s: "../..", "a/b", true); - } - - #[test] - fn test_ends_with_path() { - macro_rules! t { - (s: $path:expr, $child:expr, $exp:expr) => ( - { - let path = Path::new($path); - let child = Path::new($child); - assert_eq!(path.ends_with_path(&child), $exp); - } - ); - (v: $path:expr, $child:expr, $exp:expr) => ( - { - let path = Path::new($path); - let child = Path::new($child); - assert_eq!(path.ends_with_path(&child), $exp); - } - ) - } - - t!(s: "a/b/c", "c", true); - t!(s: "a/b/c", "d", false); - t!(s: "foo/bar/quux", "bar", false); - t!(s: "foo/bar/quux", "barquux", false); - t!(s: "a/b/c", "b/c", true); - t!(s: "a/b/c", "a/b/c", true); - t!(s: "a/b/c", "foo/a/b/c", false); - t!(s: "/a/b/c", "a/b/c", true); - t!(s: "/a/b/c", "/a/b/c", false); // child must be relative - t!(s: "/a/b/c", "foo/a/b/c", false); - t!(s: "a/b/c", "", false); - t!(s: "", "", true); - t!(s: "/a/b/c", "d/e/f", false); - t!(s: "a/b/c", "a/b", false); - t!(s: "a/b/c", "b", false); - t!(v: &b"a/b/c"[..], &b"b/c"[..], true); - t!(v: &b"a/b/\xFF"[..], &b"\xFF"[..], true); - t!(v: &b"a/b/\xFF"[..], &b"b/\xFF"[..], true); - } - - #[test] - fn test_path_relative_from() { - macro_rules! t { - (s: $path:expr, $other:expr, $exp:expr) => ( - { - let path = Path::new($path); - let other = Path::new($other); - let res = path.path_relative_from(&other); - assert_eq!(res.as_ref().and_then(|x| x.as_str()), $exp); - } - ) - } - - t!(s: "a/b/c", "a/b", Some("c")); - t!(s: "a/b/c", "a/b/d", Some("../c")); - t!(s: "a/b/c", "a/b/c/d", Some("..")); - t!(s: "a/b/c", "a/b/c", Some(".")); - t!(s: "a/b/c", "a/b/c/d/e", Some("../..")); - t!(s: "a/b/c", "a/d/e", Some("../../b/c")); - t!(s: "a/b/c", "d/e/f", Some("../../../a/b/c")); - t!(s: "a/b/c", "/a/b/c", None); - t!(s: "/a/b/c", "a/b/c", Some("/a/b/c")); - t!(s: "/a/b/c", "/a/b/c/d", Some("..")); - t!(s: "/a/b/c", "/a/b", Some("c")); - t!(s: "/a/b/c", "/a/b/c/d/e", Some("../..")); - t!(s: "/a/b/c", "/a/d/e", Some("../../b/c")); - t!(s: "/a/b/c", "/d/e/f", Some("../../../a/b/c")); - t!(s: "hi/there.txt", "hi/there", Some("../there.txt")); - t!(s: ".", "a", Some("..")); - t!(s: ".", "a/b", Some("../..")); - t!(s: ".", ".", Some(".")); - t!(s: "a", ".", Some("a")); - t!(s: "a/b", ".", Some("a/b")); - t!(s: "..", ".", Some("..")); - t!(s: "a/b/c", "a/b/c", Some(".")); - t!(s: "/a/b/c", "/a/b/c", Some(".")); - t!(s: "/", "/", Some(".")); - t!(s: "/", ".", Some("/")); - t!(s: "../../a", "b", Some("../../../a")); - t!(s: "a", "../../b", None); - t!(s: "../../a", "../../b", Some("../a")); - t!(s: "../../a", "../../a/b", Some("..")); - t!(s: "../../a/b", "../../a", Some("b")); - } - - #[test] - fn test_components_iter() { - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let comps = path.components().collect::>(); - let exp: &[&str] = &$exp; - let exps = exp.iter().map(|x| x.as_bytes()).collect::>(); - assert_eq!(comps, exps); - let comps = path.components().rev().collect::>(); - let exps = exps.into_iter().rev().collect::>(); - assert_eq!(comps, exps); - } - ); - (b: $arg:expr, [$($exp:expr),*]) => ( - { - let path = Path::new($arg); - let comps = path.components().collect::>(); - let exp: &[&[u8]] = &[$($exp),*]; - assert_eq!(comps, exp); - let comps = path.components().rev().collect::>(); - let exp = exp.iter().rev().cloned().collect::>(); - assert_eq!(comps, exp) - } - ) - } - - t!(b: &b"a/b/c"[..], [b"a", b"b", b"c"]); - t!(b: &b"/\xFF/a/\x80"[..], [b"\xFF", b"a", b"\x80"]); - t!(b: &b"../../foo\xCDbar"[..], [b"..", b"..", b"foo\xCDbar"]); - t!(s: "a/b/c", ["a", "b", "c"]); - t!(s: "a/b/d", ["a", "b", "d"]); - t!(s: "a/b/cd", ["a", "b", "cd"]); - t!(s: "/a/b/c", ["a", "b", "c"]); - t!(s: "a", ["a"]); - t!(s: "/a", ["a"]); - t!(s: "/", []); - t!(s: ".", ["."]); - t!(s: "..", [".."]); - t!(s: "../..", ["..", ".."]); - t!(s: "../../foo", ["..", "..", "foo"]); - } - - #[test] - fn test_str_components() { - macro_rules! t { - (b: $arg:expr, $exp:expr) => ( - { - let path = Path::new($arg); - let comps = path.str_components().collect::>>(); - let exp: &[Option<&str>] = &$exp; - assert_eq!(comps, exp); - let comps = path.str_components().rev().collect::>>(); - let exp = exp.iter().rev().cloned().collect::>>(); - assert_eq!(comps, exp); - } - ) - } - - t!(b: &b"a/b/c"[..], [Some("a"), Some("b"), Some("c")]); - t!(b: &b"/\xFF/a/\x80"[..], [None, Some("a"), None]); - t!(b: &b"../../foo\xCDbar"[..], [Some(".."), Some(".."), None]); - // str_components is a wrapper around components, so no need to do - // the full set of tests - } -} - -#[cfg(test)] -mod bench { - extern crate test; - use self::test::Bencher; - use super::*; - use old_path::GenericPath; - use prelude::v1::Clone; - - #[bench] - fn join_home_dir(b: &mut Bencher) { - let posix_path = Path::new("/"); - b.iter(|| { - posix_path.join("home"); - }); - } - - #[bench] - fn join_abs_path_home_dir(b: &mut Bencher) { - let posix_path = Path::new("/"); - b.iter(|| { - posix_path.join("/home"); - }); - } - - #[bench] - fn join_many_home_dir(b: &mut Bencher) { - let posix_path = Path::new("/"); - b.iter(|| { - posix_path.join_many(&["home"]); - }); - } - - #[bench] - fn join_many_abs_path_home_dir(b: &mut Bencher) { - let posix_path = Path::new("/"); - b.iter(|| { - posix_path.join_many(&["/home"]); - }); - } - - #[bench] - fn push_home_dir(b: &mut Bencher) { - let mut posix_path = Path::new("/"); - b.iter(|| { - posix_path.push("home"); - }); - } - - #[bench] - fn push_abs_path_home_dir(b: &mut Bencher) { - let mut posix_path = Path::new("/"); - b.iter(|| { - posix_path.push("/home"); - }); - } - - #[bench] - fn push_many_home_dir(b: &mut Bencher) { - let mut posix_path = Path::new("/"); - b.iter(|| { - posix_path.push_many(&["home"]); - }); - } - - #[bench] - fn push_many_abs_path_home_dir(b: &mut Bencher) { - let mut posix_path = Path::new("/"); - b.iter(|| { - posix_path.push_many(&["/home"]); - }); - } - - #[bench] - fn ends_with_path_home_dir(b: &mut Bencher) { - let posix_home_path = Path::new("/home"); - b.iter(|| { - posix_home_path.ends_with_path(&Path::new("home")); - }); - } - - #[bench] - fn ends_with_path_missmatch_jome_home(b: &mut Bencher) { - let posix_home_path = Path::new("/home"); - b.iter(|| { - posix_home_path.ends_with_path(&Path::new("jome")); - }); - } - - #[bench] - fn is_ancestor_of_path_with_10_dirs(b: &mut Bencher) { - let path = Path::new("/home/1/2/3/4/5/6/7/8/9"); - let mut sub = path.clone(); - sub.pop(); - b.iter(|| { - path.is_ancestor_of(&sub); - }); - } - - #[bench] - fn path_relative_from_forward(b: &mut Bencher) { - let path = Path::new("/a/b/c"); - let mut other = path.clone(); - other.pop(); - b.iter(|| { - path.path_relative_from(&other); - }); - } - - #[bench] - fn path_relative_from_same_level(b: &mut Bencher) { - let path = Path::new("/a/b/c"); - let mut other = path.clone(); - other.pop(); - other.push("d"); - b.iter(|| { - path.path_relative_from(&other); - }); - } - - #[bench] - fn path_relative_from_backward(b: &mut Bencher) { - let path = Path::new("/a/b"); - let mut other = path.clone(); - other.push("c"); - b.iter(|| { - path.path_relative_from(&other); - }); - } -} diff --git a/src/libstd/old_path/windows.rs b/src/libstd/old_path/windows.rs deleted file mode 100644 index 65aad38a2b43d..0000000000000 --- a/src/libstd/old_path/windows.rs +++ /dev/null @@ -1,2330 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// ignore-lexer-test FIXME #15883 - -//! Windows file path handling - -use self::PathPrefix::*; - -use ascii::AsciiExt; -use clone::Clone; -use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; -use fmt; -use hash; -use old_io::Writer; -use iter::{Extend, Iterator, Map, repeat}; -use mem; -use option::Option::{self, Some, None}; -use result::Result::{self, Ok, Err}; -use slice::SliceConcatExt; -use str::{SplitTerminator, FromStr}; -use string::{String, ToString}; -use vec::Vec; - -use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe}; - -/// Iterator that yields successive components of a Path as &str -/// -/// Each component is yielded as Option<&str> for compatibility with PosixPath, but -/// every component in WindowsPath is guaranteed to be Some. -pub type StrComponents<'a> = - Map, fn(&'a str) -> Option<&'a str>>; - -/// Iterator that yields successive components of a Path as &[u8] -pub type Components<'a> = - Map, fn(Option<&str>) -> &[u8]>; - -/// Represents a Windows path -// Notes for Windows path impl: -// The MAX_PATH is 260, but 253 is the practical limit due to some API bugs -// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx for good information -// about windows paths. -// That same page puts a bunch of restrictions on allowed characters in a path. -// `\foo.txt` means "relative to current drive", but will not be considered to be absolute here -// as `∃P | P.join("\foo.txt") != "\foo.txt"`. -// `C:` is interesting, that means "the current directory on drive C". -// Long absolute paths need to have \\?\ prefix (or, for UNC, \\?\UNC\). I think that can be -// ignored for now, though, and only added in a hypothetical .to_pwstr() function. -// However, if a path is parsed that has \\?\, this needs to be preserved as it disables the -// processing of "." and ".." components and / as a separator. -// Experimentally, \\?\foo is not the same thing as \foo. -// Also, \\foo is not valid either (certainly not equivalent to \foo). -// Similarly, C:\\Users is not equivalent to C:\Users, although C:\Users\\foo is equivalent -// to C:\Users\foo. In fact the command prompt treats C:\\foo\bar as UNC path. But it might be -// best to just ignore that and normalize it to C:\foo\bar. -// -// Based on all this, I think the right approach is to do the following: -// * Require valid utf-8 paths. Windows API may use WCHARs, but we don't, and utf-8 is convertible -// to UTF-16 anyway (though does Windows use UTF-16 or UCS-2? Not sure). -// * Parse the prefixes \\?\UNC\, \\?\, and \\.\ explicitly. -// * If \\?\UNC\, treat following two path components as server\share. Don't error for missing -// server\share. -// * If \\?\, parse disk from following component, if present. Don't error for missing disk. -// * If \\.\, treat rest of path as just regular components. I don't know how . and .. are handled -// here, they probably aren't, but I'm not going to worry about that. -// * Else if starts with \\, treat following two components as server\share. Don't error for missing -// server\share. -// * Otherwise, attempt to parse drive from start of path. -// -// The only error condition imposed here is valid utf-8. All other invalid paths are simply -// preserved by the data structure; let the Windows API error out on them. -#[derive(Clone)] -pub struct Path { - repr: String, // assumed to never be empty - prefix: Option, - sepidx: Option // index of the final separator in the non-prefix portion of repr -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Path { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.display(), f) - } -} - -impl PartialEq for Path { - #[inline] - fn eq(&self, other: &Path) -> bool { - self.repr == other.repr - } -} - -impl Eq for Path {} - -impl PartialOrd for Path { - fn partial_cmp(&self, other: &Path) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Path { - fn cmp(&self, other: &Path) -> Ordering { - self.repr.cmp(&other.repr) - } -} - -impl FromStr for Path { - type Err = ParsePathError; - fn from_str(s: &str) -> Result { - match Path::new_opt(s) { - Some(p) => Ok(p), - None => Err(ParsePathError), - } - } -} - -/// Value indicating that a path could not be parsed from a string. -#[derive(Debug, Clone, PartialEq, Copy)] -pub struct ParsePathError; - -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for Path { - #[cfg(not(test))] - #[inline] - fn hash(&self, state: &mut H) { - self.repr.hash(state) - } - - #[cfg(test)] - #[inline] - fn hash(&self, _: &mut H) { - // No-op because the `hash` implementation will be wrong. - } -} - -impl BytesContainer for Path { - #[inline] - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - self.as_vec() - } - #[inline] - fn container_as_str<'a>(&'a self) -> Option<&'a str> { - self.as_str() - } - #[inline] - fn is_str(_: Option<&Path>) -> bool { true } -} - -impl GenericPathUnsafe for Path { - /// See `GenericPathUnsafe::from_vec_unchecked`. - /// - /// # Panics - /// - /// Panics if not valid UTF-8. - #[inline] - unsafe fn new_unchecked(path: T) -> Path { - let (prefix, path) = Path::normalize_(path.container_as_str().unwrap()); - assert!(!path.is_empty()); - let mut ret = Path{ repr: path, prefix: prefix, sepidx: None }; - ret.update_sepidx(); - ret - } - - /// See `GenericPathUnsafe::set_filename_unchecked`. - /// - /// # Panics - /// - /// Panics if not valid UTF-8. - unsafe fn set_filename_unchecked(&mut self, filename: T) { - let filename = filename.container_as_str().unwrap(); - match self.sepidx_or_prefix_len() { - None if ".." == self.repr => { - let mut s = String::with_capacity(3 + filename.len()); - s.push_str(".."); - s.push(SEP); - s.push_str(filename); - self.update_normalized(&s[..]); - } - None => { - self.update_normalized(filename); - } - Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => { - let mut s = String::with_capacity(end + 1 + filename.len()); - s.push_str(&self.repr[..end]); - s.push(SEP); - s.push_str(filename); - self.update_normalized(&s[..]); - } - Some((idxb,idxa,_)) if self.prefix == Some(DiskPrefix) && idxa == self.prefix_len() => { - let mut s = String::with_capacity(idxb + filename.len()); - s.push_str(&self.repr[..idxb]); - s.push_str(filename); - self.update_normalized(&s[..]); - } - Some((idxb,_,_)) => { - let mut s = String::with_capacity(idxb + 1 + filename.len()); - s.push_str(&self.repr[..idxb]); - s.push(SEP); - s.push_str(filename); - self.update_normalized(&s[..]); - } - } - } - - /// See `GenericPathUnsafe::push_unchecked`. - /// - /// Concatenating two Windows Paths is rather complicated. - /// For the most part, it will behave as expected, except in the case of - /// pushing a volume-relative path, e.g. `C:foo.txt`. Because we have no - /// concept of per-volume cwds like Windows does, we can't behave exactly - /// like Windows will. Instead, if the receiver is an absolute path on - /// the same volume as the new path, it will be treated as the cwd that - /// the new path is relative to. Otherwise, the new path will be treated - /// as if it were absolute and will replace the receiver outright. - unsafe fn push_unchecked(&mut self, path: T) { - let path = path.container_as_str().unwrap(); - fn is_vol_abs(path: &str, prefix: Option) -> bool { - // assume prefix is Some(DiskPrefix) - let rest = &path[prefix_len(prefix)..]; - !rest.is_empty() && rest.as_bytes()[0].is_ascii() && is_sep(rest.as_bytes()[0] as char) - } - fn shares_volume(me: &Path, path: &str) -> bool { - // path is assumed to have a prefix of Some(DiskPrefix) - let repr = &me.repr[..]; - match me.prefix { - Some(DiskPrefix) => { - repr.as_bytes()[0] == path.as_bytes()[0].to_ascii_uppercase() - } - Some(VerbatimDiskPrefix) => { - repr.as_bytes()[4] == path.as_bytes()[0].to_ascii_uppercase() - } - _ => false - } - } - fn is_sep_(prefix: Option, u: u8) -> bool { - if prefix_is_verbatim(prefix) { is_sep_verbatim(u as char) } - else { is_sep(u as char) } - } - - fn replace_path(me: &mut Path, path: &str, prefix: Option) { - let newpath = Path::normalize__(path, prefix); - me.repr = match newpath { - Some(p) => p, - None => String::from_str(path) - }; - me.prefix = prefix; - me.update_sepidx(); - } - fn append_path(me: &mut Path, path: &str) { - // appends a path that has no prefix - // if me is verbatim, we need to pre-normalize the new path - let path_ = if is_verbatim(me) { Path::normalize__(path, None) } - else { None }; - let pathlen = path_.as_ref().map_or(path.len(), |p| p.len()); - let mut s = String::with_capacity(me.repr.len() + 1 + pathlen); - s.push_str(&me.repr[..]); - let plen = me.prefix_len(); - // if me is "C:" we don't want to add a path separator - match me.prefix { - Some(DiskPrefix) if me.repr.len() == plen => (), - _ if !(me.repr.len() > plen && me.repr.as_bytes()[me.repr.len()-1] == SEP_BYTE) => { - s.push(SEP); - } - _ => () - } - match path_ { - None => s.push_str(path), - Some(p) => s.push_str(&p[..]), - }; - me.update_normalized(&s[..]) - } - - if !path.is_empty() { - let prefix = parse_prefix(path); - match prefix { - Some(DiskPrefix) if !is_vol_abs(path, prefix) && shares_volume(self, path) => { - // cwd-relative path, self is on the same volume - append_path(self, &path[prefix_len(prefix)..]); - } - Some(_) => { - // absolute path, or cwd-relative and self is not same volume - replace_path(self, path, prefix); - } - None if !path.is_empty() && is_sep_(self.prefix, path.as_bytes()[0]) => { - // volume-relative path - if self.prefix.is_some() { - // truncate self down to the prefix, then append - let n = self.prefix_len(); - self.repr.truncate(n); - append_path(self, path); - } else { - // we have no prefix, so nothing to be relative to - replace_path(self, path, prefix); - } - } - None => { - // relative path - append_path(self, path); - } - } - } - } -} - -impl GenericPath for Path { - #[inline] - fn new_opt(path: T) -> Option { - match path.container_as_str() { - None => None, - Some(ref s) => { - if contains_nul(s) { - None - } else { - Some(unsafe { GenericPathUnsafe::new_unchecked(*s) }) - } - } - } - } - - /// See `GenericPath::as_str` for info. - /// Always returns a `Some` value. - #[inline] - fn as_str<'a>(&'a self) -> Option<&'a str> { - Some(&self.repr[..]) - } - - #[inline] - fn as_vec<'a>(&'a self) -> &'a [u8] { - self.repr.as_bytes() - } - - #[inline] - fn into_vec(self) -> Vec { - self.repr.into_bytes() - } - - #[inline] - fn dirname<'a>(&'a self) -> &'a [u8] { - self.dirname_str().unwrap().as_bytes() - } - - /// See `GenericPath::dirname_str` for info. - /// Always returns a `Some` value. - fn dirname_str<'a>(&'a self) -> Option<&'a str> { - Some(match self.sepidx_or_prefix_len() { - None if ".." == self.repr => &self.repr[..], - None => ".", - Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => { - &self.repr[..] - } - Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => { - &self.repr[..] - } - Some((0,idxa,_)) => &self.repr[..idxa], - Some((idxb,idxa,_)) => { - match self.prefix { - Some(DiskPrefix) | Some(VerbatimDiskPrefix) if idxb == self.prefix_len() => { - &self.repr[..idxa] - } - _ => &self.repr[..idxb] - } - } - }) - } - - #[inline] - fn filename<'a>(&'a self) -> Option<&'a [u8]> { - self.filename_str().map(|x| x.as_bytes()) - } - - /// See `GenericPath::filename_str` for info. - /// Always returns a `Some` value if `filename` returns a `Some` value. - fn filename_str<'a>(&'a self) -> Option<&'a str> { - let repr = &self.repr[..]; - match self.sepidx_or_prefix_len() { - None if "." == repr || ".." == repr => None, - None => Some(repr), - Some((_,idxa,end)) if &repr[idxa..end] == ".." => None, - Some((_,idxa,end)) if idxa == end => None, - Some((_,idxa,end)) => Some(&repr[idxa..end]) - } - } - - /// See `GenericPath::filestem_str` for info. - /// Always returns a `Some` value if `filestem` returns a `Some` value. - #[inline] - fn filestem_str<'a>(&'a self) -> Option<&'a str> { - // filestem() returns a byte vector that's guaranteed valid UTF-8 - self.filestem().map(|t| unsafe { mem::transmute(t) }) - } - - #[inline] - fn extension_str<'a>(&'a self) -> Option<&'a str> { - // extension() returns a byte vector that's guaranteed valid UTF-8 - self.extension().map(|t| unsafe { mem::transmute(t) }) - } - - fn dir_path(&self) -> Path { - unsafe { GenericPathUnsafe::new_unchecked(self.dirname_str().unwrap()) } - } - - #[inline] - fn pop(&mut self) -> bool { - match self.sepidx_or_prefix_len() { - None if "." == self.repr => false, - None => { - self.repr = String::from_str("."); - self.sepidx = None; - true - } - Some((idxb,idxa,end)) if idxb == idxa && idxb == end => false, - Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => false, - Some((idxb,idxa,_)) => { - let trunc = match self.prefix { - Some(DiskPrefix) | Some(VerbatimDiskPrefix) | None => { - let plen = self.prefix_len(); - if idxb == plen { idxa } else { idxb } - } - _ => idxb - }; - self.repr.truncate(trunc); - self.update_sepidx(); - true - } - } - } - - fn root_path(&self) -> Option { - if self.prefix.is_some() { - Some(Path::new(match self.prefix { - Some(DiskPrefix) if self.is_absolute() => { - &self.repr[..self.prefix_len()+1] - } - Some(VerbatimDiskPrefix) => { - &self.repr[..self.prefix_len()+1] - } - _ => &self.repr[..self.prefix_len()] - })) - } else if is_vol_relative(self) { - Some(Path::new(&self.repr[..1])) - } else { - None - } - } - - /// See `GenericPath::is_absolute` for info. - /// - /// A Windows Path is considered absolute only if it has a non-volume prefix, - /// or if it has a volume prefix and the path starts with '\'. - /// A path of `\foo` is not considered absolute because it's actually - /// relative to the "current volume". A separate method `Path::is_vol_relative` - /// is provided to indicate this case. Similarly a path of `C:foo` is not - /// considered absolute because it's relative to the cwd on volume C:. A - /// separate method `Path::is_cwd_relative` is provided to indicate this case. - #[inline] - fn is_absolute(&self) -> bool { - match self.prefix { - Some(DiskPrefix) => { - let rest = &self.repr[self.prefix_len()..]; - rest.len() > 0 && rest.as_bytes()[0] == SEP_BYTE - } - Some(_) => true, - None => false - } - } - - #[inline] - fn is_relative(&self) -> bool { - self.prefix.is_none() && !is_vol_relative(self) - } - - fn is_ancestor_of(&self, other: &Path) -> bool { - if !self.equiv_prefix(other) { - false - } else if self.is_absolute() != other.is_absolute() || - is_vol_relative(self) != is_vol_relative(other) { - false - } else { - let mut ita = self.str_components().map(|x|x.unwrap()); - let mut itb = other.str_components().map(|x|x.unwrap()); - if "." == self.repr { - return itb.next() != Some(".."); - } - loop { - match (ita.next(), itb.next()) { - (None, _) => break, - (Some(a), Some(b)) if a == b => { continue }, - (Some(a), _) if a == ".." => { - // if ita contains only .. components, it's an ancestor - return ita.all(|x| x == ".."); - } - _ => return false - } - } - true - } - } - - fn path_relative_from(&self, base: &Path) -> Option { - fn comp_requires_verbatim(s: &str) -> bool { - s == "." || s == ".." || s.contains(SEP2) - } - - if !self.equiv_prefix(base) { - // prefixes differ - if self.is_absolute() { - Some(self.clone()) - } else if self.prefix == Some(DiskPrefix) && base.prefix == Some(DiskPrefix) { - // both drives, drive letters must differ or they'd be equiv - Some(self.clone()) - } else { - None - } - } else if self.is_absolute() != base.is_absolute() { - if self.is_absolute() { - Some(self.clone()) - } else { - None - } - } else if is_vol_relative(self) != is_vol_relative(base) { - if is_vol_relative(self) { - Some(self.clone()) - } else { - None - } - } else { - let mut ita = self.str_components().map(|x|x.unwrap()); - let mut itb = base.str_components().map(|x|x.unwrap()); - let mut comps = vec![]; - - let a_verb = is_verbatim(self); - let b_verb = is_verbatim(base); - loop { - match (ita.next(), itb.next()) { - (None, None) => break, - (Some(a), None) if a_verb && comp_requires_verbatim(a) => { - return Some(self.clone()) - } - (Some(a), None) => { - comps.push(a); - if !a_verb { - comps.extend(ita.by_ref()); - break; - } - } - (None, _) => comps.push(".."), - (Some(a), Some(b)) if comps.is_empty() && a == b => (), - (Some(a), Some(b)) if !b_verb && b == "." => { - if a_verb && comp_requires_verbatim(a) { - return Some(self.clone()) - } else { comps.push(a) } - } - (Some(_), Some(b)) if !b_verb && b == ".." => return None, - (Some(a), Some(_)) if a_verb && comp_requires_verbatim(a) => { - return Some(self.clone()) - } - (Some(a), Some(_)) => { - comps.push(".."); - for _ in itb.by_ref() { - comps.push(".."); - } - comps.push(a); - if !a_verb { - comps.extend(ita.by_ref()); - break; - } - } - } - } - Some(Path::new(comps.connect("\\"))) - } - } - - fn ends_with_path(&self, child: &Path) -> bool { - if !child.is_relative() { return false; } - let mut selfit = self.str_components().rev(); - let mut childit = child.str_components().rev(); - loop { - match (selfit.next(), childit.next()) { - (Some(a), Some(b)) => if a != b { return false; }, - (Some(_), None) => break, - (None, Some(_)) => return false, - (None, None) => break - } - } - true - } -} - -impl Path { - /// Returns a new `Path` from a `BytesContainer`. - /// - /// # Panics - /// - /// Panics if the vector contains a `NUL`, or if it contains invalid UTF-8. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// println!("{}", Path::new(r"C:\some\path").display()); - /// ``` - #[inline] - pub fn new(path: T) -> Path { - GenericPath::new(path) - } - - /// Returns a new `Some(Path)` from a `BytesContainer`. - /// - /// Returns `None` if the vector contains a `NUL`, or if it contains invalid UTF-8. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// let path = Path::new_opt(r"C:\some\path"); - /// - /// match path { - /// Some(path) => println!("{}", path.display()), - /// None => println!("There was a problem with your path."), - /// } - /// ``` - #[inline] - pub fn new_opt(path: T) -> Option { - GenericPath::new_opt(path) - } - - /// Returns an iterator that yields each component of the path in turn as a Option<&str>. - /// Every component is guaranteed to be Some. - /// Does not yield the path prefix (including server/share components in UNC paths). - /// Does not distinguish between volume-relative and relative paths, e.g. - /// \a\b\c and a\b\c. - /// Does not distinguish between absolute and cwd-relative paths, e.g. - /// C:\foo and C:foo. - pub fn str_components<'a>(&'a self) -> StrComponents<'a> { - let repr = &self.repr[..]; - let s = match self.prefix { - Some(_) => { - let plen = self.prefix_len(); - if repr.len() > plen && repr.as_bytes()[plen] == SEP_BYTE { - &repr[plen+1..] - } else { &repr[plen..] } - } - None if repr.as_bytes()[0] == SEP_BYTE => &repr[1..], - None => repr - }; - let some: fn(&'a str) -> Option<&'a str> = Some; // coerce to fn ptr - let ret = s.split_terminator(SEP).map(some); - ret - } - - /// Returns an iterator that yields each component of the path in turn as a &[u8]. - /// See str_components() for details. - pub fn components<'a>(&'a self) -> Components<'a> { - fn convert<'a>(x: Option<&'a str>) -> &'a [u8] { - #![inline] - x.unwrap().as_bytes() - } - let convert: for<'b> fn(Option<&'b str>) -> &'b [u8] = convert; // coerce to fn ptr - self.str_components().map(convert) - } - - fn equiv_prefix(&self, other: &Path) -> bool { - let s_repr = &self.repr[..]; - let o_repr = &other.repr[..]; - match (self.prefix, other.prefix) { - (Some(DiskPrefix), Some(VerbatimDiskPrefix)) => { - self.is_absolute() && - s_repr.as_bytes()[0].to_ascii_lowercase() == - o_repr.as_bytes()[4].to_ascii_lowercase() - } - (Some(VerbatimDiskPrefix), Some(DiskPrefix)) => { - other.is_absolute() && - s_repr.as_bytes()[4].to_ascii_lowercase() == - o_repr.as_bytes()[0].to_ascii_lowercase() - } - (Some(VerbatimDiskPrefix), Some(VerbatimDiskPrefix)) => { - s_repr.as_bytes()[4].to_ascii_lowercase() == - o_repr.as_bytes()[4].to_ascii_lowercase() - } - (Some(UNCPrefix(_,_)), Some(VerbatimUNCPrefix(_,_))) => { - &s_repr[2..self.prefix_len()] == &o_repr[8..other.prefix_len()] - } - (Some(VerbatimUNCPrefix(_,_)), Some(UNCPrefix(_,_))) => { - &s_repr[8..self.prefix_len()] == &o_repr[2..other.prefix_len()] - } - (None, None) => true, - (a, b) if a == b => { - &s_repr[..self.prefix_len()] == &o_repr[..other.prefix_len()] - } - _ => false - } - } - - fn normalize_(s: &str) -> (Option, String) { - // make borrowck happy - let (prefix, val) = { - let prefix = parse_prefix(s); - let path = Path::normalize__(s, prefix); - (prefix, path) - }; - (prefix, match val { - None => s.to_string(), - Some(val) => val - }) - } - - fn normalize__(s: &str, prefix: Option) -> Option { - if prefix_is_verbatim(prefix) { - // don't do any normalization - match prefix { - Some(VerbatimUNCPrefix(x, 0)) if s.len() == 8 + x => { - // the server component has no trailing '\' - let mut s = String::from_str(s); - s.push(SEP); - Some(s) - } - _ => None - } - } else { - let (is_abs, comps) = normalize_helper(s, prefix); - let mut comps = comps; - match (comps.is_some(),prefix) { - (false, Some(DiskPrefix)) => { - if s.as_bytes()[0] >= b'a' && s.as_bytes()[0] <= b'z' { - comps = Some(vec![]); - } - } - (false, Some(VerbatimDiskPrefix)) => { - if s.as_bytes()[4] >= b'a' && s.as_bytes()[0] <= b'z' { - comps = Some(vec![]); - } - } - _ => () - } - match comps { - None => None, - Some(comps) => { - if prefix.is_some() && comps.is_empty() { - match prefix.unwrap() { - DiskPrefix => { - let len = prefix_len(prefix) + is_abs as usize; - let mut s = String::from_str(&s[..len]); - unsafe { - let v = s.as_mut_vec(); - v[0] = (*v)[0].to_ascii_uppercase(); - } - if is_abs { - // normalize C:/ to C:\ - unsafe { - s.as_mut_vec()[2] = SEP_BYTE; - } - } - Some(s) - } - VerbatimDiskPrefix => { - let len = prefix_len(prefix) + is_abs as usize; - let mut s = String::from_str(&s[..len]); - unsafe { - let v = s.as_mut_vec(); - v[4] = (*v)[4].to_ascii_uppercase(); - } - Some(s) - } - _ => { - let plen = prefix_len(prefix); - if s.len() > plen { - Some(String::from_str(&s[..plen])) - } else { None } - } - } - } else if is_abs && comps.is_empty() { - Some(repeat(SEP).take(1).collect()) - } else { - let prefix_ = &s[..prefix_len(prefix)]; - let n = prefix_.len() + - if is_abs { comps.len() } else { comps.len() - 1} + - comps.iter().map(|v| v.len()).sum::(); - let mut s = String::with_capacity(n); - match prefix { - Some(DiskPrefix) => { - s.push(prefix_.as_bytes()[0].to_ascii_uppercase() as char); - s.push(':'); - } - Some(VerbatimDiskPrefix) => { - s.push_str(&prefix_[..4]); - s.push(prefix_.as_bytes()[4].to_ascii_uppercase() as char); - s.push_str(&prefix_[5..]); - } - Some(UNCPrefix(a,b)) => { - s.push_str("\\\\"); - s.push_str(&prefix_[2..a+2]); - s.push(SEP); - s.push_str(&prefix_[3+a..3+a+b]); - } - Some(_) => s.push_str(prefix_), - None => () - } - let mut it = comps.into_iter(); - if !is_abs { - match it.next() { - None => (), - Some(comp) => s.push_str(comp) - } - } - for comp in it { - s.push(SEP); - s.push_str(comp); - } - Some(s) - } - } - } - } - } - - fn update_sepidx(&mut self) { - let s = if self.has_nonsemantic_trailing_slash() { - &self.repr[..self.repr.len()-1] - } else { &self.repr[..] }; - let sep_test: fn(char) -> bool = if !prefix_is_verbatim(self.prefix) { - is_sep - } else { - is_sep_verbatim - }; - let idx = s.rfind(sep_test); - let prefixlen = self.prefix_len(); - self.sepidx = idx.and_then(|x| if x < prefixlen { None } else { Some(x) }); - } - - fn prefix_len(&self) -> usize { - prefix_len(self.prefix) - } - - // Returns a tuple (before, after, end) where before is the index of the separator - // and after is the index just after the separator. - // end is the length of the string, normally, or the index of the final character if it is - // a non-semantic trailing separator in a verbatim string. - // If the prefix is considered the separator, before and after are the same. - fn sepidx_or_prefix_len(&self) -> Option<(usize,usize,usize)> { - match self.sepidx { - None => match self.prefix_len() { 0 => None, x => Some((x,x,self.repr.len())) }, - Some(x) => { - if self.has_nonsemantic_trailing_slash() { - Some((x,x+1,self.repr.len()-1)) - } else { Some((x,x+1,self.repr.len())) } - } - } - } - - fn has_nonsemantic_trailing_slash(&self) -> bool { - is_verbatim(self) && self.repr.len() > self.prefix_len()+1 && - self.repr.as_bytes()[self.repr.len()-1] == SEP_BYTE - } - - fn update_normalized(&mut self, s: &str) { - let (prefix, path) = Path::normalize_(s); - self.repr = path; - self.prefix = prefix; - self.update_sepidx(); - } -} - -/// Returns whether the path is considered "volume-relative", which means a path -/// that looks like "\foo". Paths of this form are relative to the current volume, -/// but absolute within that volume. -#[inline] -pub fn is_vol_relative(path: &Path) -> bool { - path.prefix.is_none() && is_sep_byte(&path.repr.as_bytes()[0]) -} - -/// Returns whether the path is considered "cwd-relative", which means a path -/// with a volume prefix that is not absolute. This look like "C:foo.txt". Paths -/// of this form are relative to the cwd on the given volume. -#[inline] -pub fn is_cwd_relative(path: &Path) -> bool { - path.prefix == Some(DiskPrefix) && !path.is_absolute() -} - -/// Returns the PathPrefix for this Path -#[inline] -pub fn prefix(path: &Path) -> Option { - path.prefix -} - -/// Returns whether the Path's prefix is a verbatim prefix, i.e. `\\?\` -#[inline] -pub fn is_verbatim(path: &Path) -> bool { - prefix_is_verbatim(path.prefix) -} - -/// Returns the non-verbatim equivalent of the input path, if possible. -/// If the input path is a device namespace path, None is returned. -/// If the input path is not verbatim, it is returned as-is. -/// If the input path is verbatim, but the same path can be expressed as -/// non-verbatim, the non-verbatim version is returned. -/// Otherwise, None is returned. -pub fn make_non_verbatim(path: &Path) -> Option { - let repr = &path.repr[..]; - let new_path = match path.prefix { - Some(VerbatimPrefix(_)) | Some(DeviceNSPrefix(_)) => return None, - Some(UNCPrefix(_,_)) | Some(DiskPrefix) | None => return Some(path.clone()), - Some(VerbatimDiskPrefix) => { - // \\?\D:\ - Path::new(&repr[4..]) - } - Some(VerbatimUNCPrefix(_,_)) => { - // \\?\UNC\server\share - Path::new(format!(r"\{}", &repr[7..])) - } - }; - if new_path.prefix.is_none() { - // \\?\UNC\server is a VerbatimUNCPrefix - // but \\server is nothing - return None; - } - // now ensure normalization didn't change anything - if &repr[path.prefix_len()..] == &new_path.repr[new_path.prefix_len()..] { - Some(new_path) - } else { - None - } -} - -/// The standard path separator character -pub const SEP: char = '\\'; -/// The standard path separator byte -pub const SEP_BYTE: u8 = SEP as u8; - -/// The alternative path separator character -pub const SEP2: char = '/'; -/// The alternative path separator character -pub const SEP2_BYTE: u8 = SEP2 as u8; - -/// Returns whether the given char is a path separator. -/// Allows both the primary separator '\' and the alternative separator '/'. -#[inline] -pub fn is_sep(c: char) -> bool { - c == SEP || c == SEP2 -} - -/// Returns whether the given char is a path separator. -/// Only allows the primary separator '\'; use is_sep to allow '/'. -#[inline] -pub fn is_sep_verbatim(c: char) -> bool { - c == SEP -} - -/// Returns whether the given byte is a path separator. -/// Allows both the primary separator '\' and the alternative separator '/'. -#[inline] -pub fn is_sep_byte(u: &u8) -> bool { - *u == SEP_BYTE || *u == SEP2_BYTE -} - -/// Returns whether the given byte is a path separator. -/// Only allows the primary separator '\'; use is_sep_byte to allow '/'. -#[inline] -pub fn is_sep_byte_verbatim(u: &u8) -> bool { - *u == SEP_BYTE -} - -/// Prefix types for Path -#[derive(Copy, PartialEq, Clone, Debug)] -pub enum PathPrefix { - /// Prefix `\\?\`, usize is the length of the following component - VerbatimPrefix(usize), - /// Prefix `\\?\UNC\`, uints are the lengths of the UNC components - VerbatimUNCPrefix(usize, usize), - /// Prefix `\\?\C:\` (for any alphabetic character) - VerbatimDiskPrefix, - /// Prefix `\\.\`, usize is the length of the following component - DeviceNSPrefix(usize), - /// UNC prefix `\\server\share`, uints are the lengths of the server/share - UNCPrefix(usize, usize), - /// Prefix `C:` for any alphabetic character - DiskPrefix -} - -fn parse_prefix<'a>(mut path: &'a str) -> Option { - if path.starts_with("\\\\") { - // \\ - path = &path[2..]; - if path.starts_with("?\\") { - // \\?\ - path = &path[2..]; - if path.starts_with("UNC\\") { - // \\?\UNC\server\share - path = &path[4..]; - let (idx_a, idx_b) = match parse_two_comps(path, is_sep_verbatim) { - Some(x) => x, - None => (path.len(), 0) - }; - return Some(VerbatimUNCPrefix(idx_a, idx_b)); - } else { - // \\?\path - let idx = path.find('\\'); - if idx == Some(2) && path.as_bytes()[1] == b':' { - let c = path.as_bytes()[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - // \\?\C:\ path - return Some(VerbatimDiskPrefix); - } - } - let idx = idx.unwrap_or(path.len()); - return Some(VerbatimPrefix(idx)); - } - } else if path.starts_with(".\\") { - // \\.\path - path = &path[2..]; - let idx = path.find('\\').unwrap_or(path.len()); - return Some(DeviceNSPrefix(idx)); - } - match parse_two_comps(path, is_sep) { - Some((idx_a, idx_b)) if idx_a > 0 && idx_b > 0 => { - // \\server\share - return Some(UNCPrefix(idx_a, idx_b)); - } - _ => () - } - } else if path.len() > 1 && path.as_bytes()[1] == b':' { - // C: - let c = path.as_bytes()[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - return Some(DiskPrefix); - } - } - return None; - - fn parse_two_comps(mut path: &str, f: fn(char) -> bool) -> Option<(usize, usize)> { - let idx_a = match path.find(f) { - None => return None, - Some(x) => x - }; - path = &path[idx_a+1..]; - let idx_b = path.find(f).unwrap_or(path.len()); - Some((idx_a, idx_b)) - } -} - -// None result means the string didn't need normalizing -fn normalize_helper<'a>(s: &'a str, prefix: Option) -> (bool, Option>) { - let f: fn(char) -> bool = if !prefix_is_verbatim(prefix) { - is_sep - } else { - is_sep_verbatim - }; - let is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix))); - let s_ = &s[prefix_len(prefix)..]; - let s_ = if is_abs { &s_[1..] } else { s_ }; - - if is_abs && s_.is_empty() { - return (is_abs, match prefix { - Some(DiskPrefix) | None => (if is_sep_verbatim(s.char_at(prefix_len(prefix))) { None } - else { Some(vec![]) }), - Some(_) => Some(vec![]), // need to trim the trailing separator - }); - } - let mut comps: Vec<&'a str> = vec![]; - let mut n_up = 0; - let mut changed = false; - for comp in s_.split(f) { - if comp.is_empty() { changed = true } - else if comp == "." { changed = true } - else if comp == ".." { - let has_abs_prefix = match prefix { - Some(DiskPrefix) => false, - Some(_) => true, - None => false - }; - if (is_abs || has_abs_prefix) && comps.is_empty() { changed = true } - else if comps.len() == n_up { comps.push(".."); n_up += 1 } - else { comps.pop().unwrap(); changed = true } - } else { comps.push(comp) } - } - if !changed && !prefix_is_verbatim(prefix) { - changed = s.find(is_sep).is_some(); - } - if changed { - if comps.is_empty() && !is_abs && prefix.is_none() { - if s == "." { - return (is_abs, None); - } - comps.push("."); - } - (is_abs, Some(comps)) - } else { - (is_abs, None) - } -} - -fn prefix_is_verbatim(p: Option) -> bool { - match p { - Some(VerbatimPrefix(_)) | Some(VerbatimUNCPrefix(_,_)) | Some(VerbatimDiskPrefix) => true, - Some(DeviceNSPrefix(_)) => true, // not really sure, but I think so - _ => false - } -} - -fn prefix_len(p: Option) -> usize { - match p { - None => 0, - Some(VerbatimPrefix(x)) => 4 + x, - Some(VerbatimUNCPrefix(x,y)) => 8 + x + 1 + y, - Some(VerbatimDiskPrefix) => 6, - Some(UNCPrefix(x,y)) => 2 + x + 1 + y, - Some(DeviceNSPrefix(x)) => 4 + x, - Some(DiskPrefix) => 2 - } -} - -#[cfg(test)] -mod tests { - use super::PathPrefix::*; - use super::parse_prefix; - use super::*; - - use clone::Clone; - use iter::Iterator; - use option::Option::{self, Some, None}; - use old_path::GenericPath; - use string::ToString; - use vec::Vec; - - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = $path; - assert_eq!(path.as_str(), Some($exp)); - } - ); - (v: $path:expr, $exp:expr) => ( - { - let path = $path; - assert_eq!(path.as_vec(), $exp); - } - ) - } - - #[test] - fn test_parse_prefix() { - macro_rules! t { - ($path:expr, $exp:expr) => ( - { - let path = $path; - let exp = $exp; - let res = parse_prefix(path); - assert_eq!(res, exp); - } - ) - } - - t!("\\\\SERVER\\share\\foo", Some(UNCPrefix(6,5))); - t!("\\\\", None); - t!("\\\\SERVER", None); - t!("\\\\SERVER\\", None); - t!("\\\\SERVER\\\\", None); - t!("\\\\SERVER\\\\foo", None); - t!("\\\\SERVER\\share", Some(UNCPrefix(6,5))); - t!("\\\\SERVER/share/foo", Some(UNCPrefix(6,5))); - t!("\\\\SERVER\\share/foo", Some(UNCPrefix(6,5))); - t!("//SERVER/share/foo", None); - t!("\\\\\\a\\b\\c", None); - t!("\\\\?\\a\\b\\c", Some(VerbatimPrefix(1))); - t!("\\\\?\\a/b/c", Some(VerbatimPrefix(5))); - t!("//?/a/b/c", None); - t!("\\\\.\\a\\b", Some(DeviceNSPrefix(1))); - t!("\\\\.\\a/b", Some(DeviceNSPrefix(3))); - t!("//./a/b", None); - t!("\\\\?\\UNC\\server\\share\\foo", Some(VerbatimUNCPrefix(6,5))); - t!("\\\\?\\UNC\\\\share\\foo", Some(VerbatimUNCPrefix(0,5))); - t!("\\\\?\\UNC\\", Some(VerbatimUNCPrefix(0,0))); - t!("\\\\?\\UNC\\server/share/foo", Some(VerbatimUNCPrefix(16,0))); - t!("\\\\?\\UNC\\server", Some(VerbatimUNCPrefix(6,0))); - t!("\\\\?\\UNC\\server\\", Some(VerbatimUNCPrefix(6,0))); - t!("\\\\?\\UNC/server/share", Some(VerbatimPrefix(16))); - t!("\\\\?\\UNC", Some(VerbatimPrefix(3))); - t!("\\\\?\\C:\\a\\b.txt", Some(VerbatimDiskPrefix)); - t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix)); - t!("\\\\?\\C:", Some(VerbatimPrefix(2))); - t!("\\\\?\\C:a.txt", Some(VerbatimPrefix(7))); - t!("\\\\?\\C:a\\b.txt", Some(VerbatimPrefix(3))); - t!("\\\\?\\C:/a", Some(VerbatimPrefix(4))); - t!("C:\\foo", Some(DiskPrefix)); - t!("z:/foo", Some(DiskPrefix)); - t!("d:", Some(DiskPrefix)); - t!("ab:", None); - t!("ü:\\foo", None); - t!("3:\\foo", None); - t!(" :\\foo", None); - t!("::\\foo", None); - t!("\\\\?\\C:", Some(VerbatimPrefix(2))); - t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix)); - t!("\\\\?\\ab:\\", Some(VerbatimPrefix(3))); - t!("\\\\?\\C:\\a", Some(VerbatimDiskPrefix)); - t!("\\\\?\\C:/a", Some(VerbatimPrefix(4))); - t!("\\\\?\\C:\\a/b", Some(VerbatimDiskPrefix)); - } - - #[test] - fn test_paths() { - let empty: &[u8] = &[]; - t!(v: Path::new(empty), b"."); - t!(v: Path::new(&b"\\"[..]), b"\\"); - t!(v: Path::new(&b"a\\b\\c"[..]), b"a\\b\\c"); - - t!(s: Path::new(""), "."); - t!(s: Path::new("\\"), "\\"); - t!(s: Path::new("hi"), "hi"); - t!(s: Path::new("hi\\"), "hi"); - t!(s: Path::new("\\lib"), "\\lib"); - t!(s: Path::new("\\lib\\"), "\\lib"); - t!(s: Path::new("hi\\there"), "hi\\there"); - t!(s: Path::new("hi\\there.txt"), "hi\\there.txt"); - t!(s: Path::new("/"), "\\"); - t!(s: Path::new("hi/"), "hi"); - t!(s: Path::new("/lib"), "\\lib"); - t!(s: Path::new("/lib/"), "\\lib"); - t!(s: Path::new("hi/there"), "hi\\there"); - - t!(s: Path::new("hi\\there\\"), "hi\\there"); - t!(s: Path::new("hi\\..\\there"), "there"); - t!(s: Path::new("hi/../there"), "there"); - t!(s: Path::new("..\\hi\\there"), "..\\hi\\there"); - t!(s: Path::new("\\..\\hi\\there"), "\\hi\\there"); - t!(s: Path::new("/../hi/there"), "\\hi\\there"); - t!(s: Path::new("foo\\.."), "."); - t!(s: Path::new("\\foo\\.."), "\\"); - t!(s: Path::new("\\foo\\..\\.."), "\\"); - t!(s: Path::new("\\foo\\..\\..\\bar"), "\\bar"); - t!(s: Path::new("\\.\\hi\\.\\there\\."), "\\hi\\there"); - t!(s: Path::new("\\.\\hi\\.\\there\\.\\.."), "\\hi"); - t!(s: Path::new("foo\\..\\.."), ".."); - t!(s: Path::new("foo\\..\\..\\.."), "..\\.."); - t!(s: Path::new("foo\\..\\..\\bar"), "..\\bar"); - - assert_eq!(Path::new(&b"foo\\bar"[..]).into_vec(), b"foo\\bar"); - assert_eq!(Path::new(&b"\\foo\\..\\..\\bar"[..]).into_vec(), b"\\bar"); - - t!(s: Path::new("\\\\a"), "\\a"); - t!(s: Path::new("\\\\a\\"), "\\a"); - t!(s: Path::new("\\\\a\\b"), "\\\\a\\b"); - t!(s: Path::new("\\\\a\\b\\"), "\\\\a\\b"); - t!(s: Path::new("\\\\a\\b/"), "\\\\a\\b"); - t!(s: Path::new("\\\\\\b"), "\\b"); - t!(s: Path::new("\\\\a\\\\b"), "\\a\\b"); - t!(s: Path::new("\\\\a\\b\\c"), "\\\\a\\b\\c"); - t!(s: Path::new("\\\\server\\share/path"), "\\\\server\\share\\path"); - t!(s: Path::new("\\\\server/share/path"), "\\\\server\\share\\path"); - t!(s: Path::new("C:a\\b.txt"), "C:a\\b.txt"); - t!(s: Path::new("C:a/b.txt"), "C:a\\b.txt"); - t!(s: Path::new("z:\\a\\b.txt"), "Z:\\a\\b.txt"); - t!(s: Path::new("z:/a/b.txt"), "Z:\\a\\b.txt"); - t!(s: Path::new("ab:/a/b.txt"), "ab:\\a\\b.txt"); - t!(s: Path::new("C:\\"), "C:\\"); - t!(s: Path::new("C:"), "C:"); - t!(s: Path::new("q:"), "Q:"); - t!(s: Path::new("C:/"), "C:\\"); - t!(s: Path::new("C:\\foo\\.."), "C:\\"); - t!(s: Path::new("C:foo\\.."), "C:"); - t!(s: Path::new("C:\\a\\"), "C:\\a"); - t!(s: Path::new("C:\\a/"), "C:\\a"); - t!(s: Path::new("C:\\a\\b\\"), "C:\\a\\b"); - t!(s: Path::new("C:\\a\\b/"), "C:\\a\\b"); - t!(s: Path::new("C:a\\"), "C:a"); - t!(s: Path::new("C:a/"), "C:a"); - t!(s: Path::new("C:a\\b\\"), "C:a\\b"); - t!(s: Path::new("C:a\\b/"), "C:a\\b"); - t!(s: Path::new("\\\\?\\z:\\a\\b.txt"), "\\\\?\\z:\\a\\b.txt"); - t!(s: Path::new("\\\\?\\C:/a/b.txt"), "\\\\?\\C:/a/b.txt"); - t!(s: Path::new("\\\\?\\C:\\a/b.txt"), "\\\\?\\C:\\a/b.txt"); - t!(s: Path::new("\\\\?\\test\\a\\b.txt"), "\\\\?\\test\\a\\b.txt"); - t!(s: Path::new("\\\\?\\foo\\bar\\"), "\\\\?\\foo\\bar\\"); - t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar"); - t!(s: Path::new("\\\\.\\"), "\\\\.\\"); - t!(s: Path::new("\\\\?\\UNC\\server\\share\\foo"), "\\\\?\\UNC\\server\\share\\foo"); - t!(s: Path::new("\\\\?\\UNC\\server/share"), "\\\\?\\UNC\\server/share\\"); - t!(s: Path::new("\\\\?\\UNC\\server"), "\\\\?\\UNC\\server\\"); - t!(s: Path::new("\\\\?\\UNC\\"), "\\\\?\\UNC\\\\"); - t!(s: Path::new("\\\\?\\UNC"), "\\\\?\\UNC"); - - // I'm not sure whether \\.\foo/bar should normalize to \\.\foo\bar - // as information is sparse and this isn't really googleable. - // I'm going to err on the side of not normalizing it, as this skips the filesystem - t!(s: Path::new("\\\\.\\foo/bar"), "\\\\.\\foo/bar"); - t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar"); - } - - #[test] - fn test_opt_paths() { - assert!(Path::new_opt(&b"foo\\bar\0"[..]) == None); - assert!(Path::new_opt(&b"foo\\bar\x80"[..]) == None); - t!(v: Path::new_opt(&b"foo\\bar"[..]).unwrap(), b"foo\\bar"); - assert!(Path::new_opt("foo\\bar\0") == None); - t!(s: Path::new_opt("foo\\bar").unwrap(), "foo\\bar"); - } - - #[test] - fn test_null_byte() { - use thread; - let result = thread::spawn(move|| { - Path::new(&b"foo/bar\0"[..]); - }).join(); - assert!(result.is_err()); - - let result = thread::spawn(move|| { - Path::new("test").set_filename(&b"f\0o"[..]) - }).join(); - assert!(result.is_err()); - - let result = thread::spawn(move || { - Path::new("test").push(&b"f\0o"[..]); - }).join(); - assert!(result.is_err()); - } - - #[test] - #[should_panic] - fn test_not_utf8_panics() { - Path::new(&b"hello\x80.txt"[..]); - } - - #[test] - fn test_display_str() { - let path = Path::new("foo"); - assert_eq!(path.display().to_string(), "foo"); - let path = Path::new(&b"\\"[..]); - assert_eq!(path.filename_display().to_string(), ""); - - let path = Path::new("foo"); - let mo = path.display().as_cow(); - assert_eq!(mo, "foo"); - let path = Path::new(&b"\\"[..]); - let mo = path.filename_display().as_cow(); - assert_eq!(mo, ""); - } - - #[test] - fn test_display() { - macro_rules! t { - ($path:expr, $exp:expr, $expf:expr) => ( - { - let path = Path::new($path); - let f = format!("{}", path.display()); - assert_eq!(f, $exp); - let f = format!("{}", path.filename_display()); - assert_eq!(f, $expf); - } - ) - } - - t!("foo", "foo", "foo"); - t!("foo\\bar", "foo\\bar", "bar"); - t!("\\", "\\", ""); - } - - #[test] - fn test_components() { - macro_rules! t { - (s: $path:expr, $op:ident, $exp:expr) => ( - { - let path = $path; - let path = Path::new(path); - assert_eq!(path.$op(), Some($exp)); - } - ); - (s: $path:expr, $op:ident, $exp:expr, opt) => ( - { - let path = $path; - let path = Path::new(path); - let left = path.$op(); - assert_eq!(left, $exp); - } - ); - (v: $path:expr, $op:ident, $exp:expr) => ( - { - let path = $path; - let path = Path::new(path); - assert_eq!(path.$op(), $exp); - } - ) - } - - t!(v: &b"a\\b\\c"[..], filename, Some(&b"c"[..])); - t!(s: "a\\b\\c", filename_str, "c"); - t!(s: "\\a\\b\\c", filename_str, "c"); - t!(s: "a", filename_str, "a"); - t!(s: "\\a", filename_str, "a"); - t!(s: ".", filename_str, None, opt); - t!(s: "\\", filename_str, None, opt); - t!(s: "..", filename_str, None, opt); - t!(s: "..\\..", filename_str, None, opt); - t!(s: "c:\\foo.txt", filename_str, "foo.txt"); - t!(s: "C:\\", filename_str, None, opt); - t!(s: "C:", filename_str, None, opt); - t!(s: "\\\\server\\share\\foo.txt", filename_str, "foo.txt"); - t!(s: "\\\\server\\share", filename_str, None, opt); - t!(s: "\\\\server", filename_str, "server"); - t!(s: "\\\\?\\bar\\foo.txt", filename_str, "foo.txt"); - t!(s: "\\\\?\\bar", filename_str, None, opt); - t!(s: "\\\\?\\", filename_str, None, opt); - t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", filename_str, "foo.txt"); - t!(s: "\\\\?\\UNC\\server", filename_str, None, opt); - t!(s: "\\\\?\\UNC\\", filename_str, None, opt); - t!(s: "\\\\?\\C:\\foo.txt", filename_str, "foo.txt"); - t!(s: "\\\\?\\C:\\", filename_str, None, opt); - t!(s: "\\\\?\\C:", filename_str, None, opt); - t!(s: "\\\\?\\foo/bar", filename_str, None, opt); - t!(s: "\\\\?\\C:/foo", filename_str, None, opt); - t!(s: "\\\\.\\foo\\bar", filename_str, "bar"); - t!(s: "\\\\.\\foo", filename_str, None, opt); - t!(s: "\\\\.\\foo/bar", filename_str, None, opt); - t!(s: "\\\\.\\foo\\bar/baz", filename_str, "bar/baz"); - t!(s: "\\\\.\\", filename_str, None, opt); - t!(s: "\\\\?\\a\\b\\", filename_str, "b"); - - t!(v: &b"a\\b\\c"[..], dirname, b"a\\b"); - t!(s: "a\\b\\c", dirname_str, "a\\b"); - t!(s: "\\a\\b\\c", dirname_str, "\\a\\b"); - t!(s: "a", dirname_str, "."); - t!(s: "\\a", dirname_str, "\\"); - t!(s: ".", dirname_str, "."); - t!(s: "\\", dirname_str, "\\"); - t!(s: "..", dirname_str, ".."); - t!(s: "..\\..", dirname_str, "..\\.."); - t!(s: "c:\\foo.txt", dirname_str, "C:\\"); - t!(s: "C:\\", dirname_str, "C:\\"); - t!(s: "C:", dirname_str, "C:"); - t!(s: "C:foo.txt", dirname_str, "C:"); - t!(s: "\\\\server\\share\\foo.txt", dirname_str, "\\\\server\\share"); - t!(s: "\\\\server\\share", dirname_str, "\\\\server\\share"); - t!(s: "\\\\server", dirname_str, "\\"); - t!(s: "\\\\?\\bar\\foo.txt", dirname_str, "\\\\?\\bar"); - t!(s: "\\\\?\\bar", dirname_str, "\\\\?\\bar"); - t!(s: "\\\\?\\", dirname_str, "\\\\?\\"); - t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", dirname_str, "\\\\?\\UNC\\server\\share"); - t!(s: "\\\\?\\UNC\\server", dirname_str, "\\\\?\\UNC\\server\\"); - t!(s: "\\\\?\\UNC\\", dirname_str, "\\\\?\\UNC\\\\"); - t!(s: "\\\\?\\C:\\foo.txt", dirname_str, "\\\\?\\C:\\"); - t!(s: "\\\\?\\C:\\", dirname_str, "\\\\?\\C:\\"); - t!(s: "\\\\?\\C:", dirname_str, "\\\\?\\C:"); - t!(s: "\\\\?\\C:/foo/bar", dirname_str, "\\\\?\\C:/foo/bar"); - t!(s: "\\\\?\\foo/bar", dirname_str, "\\\\?\\foo/bar"); - t!(s: "\\\\.\\foo\\bar", dirname_str, "\\\\.\\foo"); - t!(s: "\\\\.\\foo", dirname_str, "\\\\.\\foo"); - t!(s: "\\\\?\\a\\b\\", dirname_str, "\\\\?\\a"); - - t!(v: &b"hi\\there.txt"[..], filestem, Some(&b"there"[..])); - t!(s: "hi\\there.txt", filestem_str, "there"); - t!(s: "hi\\there", filestem_str, "there"); - t!(s: "there.txt", filestem_str, "there"); - t!(s: "there", filestem_str, "there"); - t!(s: ".", filestem_str, None, opt); - t!(s: "\\", filestem_str, None, opt); - t!(s: "foo\\.bar", filestem_str, ".bar"); - t!(s: ".bar", filestem_str, ".bar"); - t!(s: "..bar", filestem_str, "."); - t!(s: "hi\\there..txt", filestem_str, "there."); - t!(s: "..", filestem_str, None, opt); - t!(s: "..\\..", filestem_str, None, opt); - // filestem is based on filename, so we don't need the full set of prefix tests - - t!(v: &b"hi\\there.txt"[..], extension, Some(&b"txt"[..])); - t!(v: &b"hi\\there"[..], extension, None); - t!(s: "hi\\there.txt", extension_str, Some("txt"), opt); - t!(s: "hi\\there", extension_str, None, opt); - t!(s: "there.txt", extension_str, Some("txt"), opt); - t!(s: "there", extension_str, None, opt); - t!(s: ".", extension_str, None, opt); - t!(s: "\\", extension_str, None, opt); - t!(s: "foo\\.bar", extension_str, None, opt); - t!(s: ".bar", extension_str, None, opt); - t!(s: "..bar", extension_str, Some("bar"), opt); - t!(s: "hi\\there..txt", extension_str, Some("txt"), opt); - t!(s: "..", extension_str, None, opt); - t!(s: "..\\..", extension_str, None, opt); - // extension is based on filename, so we don't need the full set of prefix tests - } - - #[test] - fn test_push() { - macro_rules! t { - (s: $path:expr, $join:expr) => ( - { - let path = $path; - let join = $join; - let mut p1 = Path::new(path); - let p2 = p1.clone(); - p1.push(join); - assert_eq!(p1, p2.join(join)); - } - ) - } - - t!(s: "a\\b\\c", ".."); - t!(s: "\\a\\b\\c", "d"); - t!(s: "a\\b", "c\\d"); - t!(s: "a\\b", "\\c\\d"); - // this is just a sanity-check test. push and join share an implementation, - // so there's no need for the full set of prefix tests - - // we do want to check one odd case though to ensure the prefix is re-parsed - let mut p = Path::new("\\\\?\\C:"); - assert_eq!(prefix(&p), Some(VerbatimPrefix(2))); - p.push("foo"); - assert_eq!(prefix(&p), Some(VerbatimDiskPrefix)); - assert_eq!(p.as_str(), Some("\\\\?\\C:\\foo")); - - // and another with verbatim non-normalized paths - let mut p = Path::new("\\\\?\\C:\\a\\"); - p.push("foo"); - assert_eq!(p.as_str(), Some("\\\\?\\C:\\a\\foo")); - } - - #[test] - fn test_push_path() { - macro_rules! t { - (s: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - let push = Path::new($push); - p.push(&push); - assert_eq!(p.as_str(), Some($exp)); - } - ) - } - - t!(s: "a\\b\\c", "d", "a\\b\\c\\d"); - t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d"); - t!(s: "a\\b", "c\\d", "a\\b\\c\\d"); - t!(s: "a\\b", "\\c\\d", "\\c\\d"); - t!(s: "a\\b", ".", "a\\b"); - t!(s: "a\\b", "..\\c", "a\\c"); - t!(s: "a\\b", "C:a.txt", "C:a.txt"); - t!(s: "a\\b", "..\\..\\..\\c", "..\\c"); - t!(s: "a\\b", "C:\\a.txt", "C:\\a.txt"); - t!(s: "C:\\a", "C:\\b.txt", "C:\\b.txt"); - t!(s: "C:\\a\\b\\c", "C:d", "C:\\a\\b\\c\\d"); - t!(s: "C:a\\b\\c", "C:d", "C:a\\b\\c\\d"); - t!(s: "C:a\\b", "..\\..\\..\\c", "C:..\\c"); - t!(s: "C:\\a\\b", "..\\..\\..\\c", "C:\\c"); - t!(s: "C:", r"a\b\c", r"C:a\b\c"); - t!(s: "C:", r"..\a", r"C:..\a"); - t!(s: "\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar"); - t!(s: "\\\\server\\share\\foo", "..\\..\\bar", "\\\\server\\share\\bar"); - t!(s: "\\\\server\\share\\foo", "C:baz", "C:baz"); - t!(s: "\\\\?\\C:\\a\\b", "C:c\\d", "\\\\?\\C:\\a\\b\\c\\d"); - t!(s: "\\\\?\\C:a\\b", "C:c\\d", "C:c\\d"); - t!(s: "\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d"); - t!(s: "\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz"); - t!(s: "\\\\?\\C:\\a\\b", "..\\..\\..\\c", "\\\\?\\C:\\a\\b\\..\\..\\..\\c"); - t!(s: "\\\\?\\foo\\bar", "..\\..\\c", "\\\\?\\foo\\bar\\..\\..\\c"); - t!(s: "\\\\?\\", "foo", "\\\\?\\\\foo"); - t!(s: "\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar"); - t!(s: "\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a"); - t!(s: "\\\\?\\UNC\\server\\share", "C:a", "C:a"); - t!(s: "\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\\\foo"); - t!(s: "C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share"); - t!(s: "\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz"); - t!(s: "\\\\.\\foo\\bar", "C:a", "C:a"); - // again, not sure about the following, but I'm assuming \\.\ should be verbatim - t!(s: "\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); - - t!(s: "\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one - } - - #[test] - fn test_push_many() { - macro_rules! t { - (s: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - p.push_many(&$push); - assert_eq!(p.as_str(), Some($exp)); - } - ); - (v: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - p.push_many(&$push); - assert_eq!(p.as_vec(), $exp); - } - ) - } - - t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e"); - t!(s: "a\\b\\c", ["d", "\\e"], "\\e"); - t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f"); - t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e"); - t!(v: &b"a\\b\\c"[..], [&b"d"[..], &b"e"[..]], b"a\\b\\c\\d\\e"); - t!(v: &b"a\\b\\c"[..], [&b"d"[..], &b"\\e"[..], &b"f"[..]], b"\\e\\f"); - t!(v: &b"a\\b\\c"[..], [b"d".to_vec(), b"e".to_vec()], - b"a\\b\\c\\d\\e"); - } - - #[test] - fn test_pop() { - macro_rules! t { - (s: $path:expr, $left:expr, $right:expr) => ( - { - let pstr = $path; - let mut p = Path::new(pstr); - let result = p.pop(); - let left = $left; - assert_eq!(p.as_str(), Some(left)); - assert_eq!(result, $right); - } - ); - (b: $path:expr, $left:expr, $right:expr) => ( - { - let mut p = Path::new($path); - let result = p.pop(); - assert_eq!(p.as_vec(), $left); - assert_eq!(result, $right); - } - ) - } - - t!(s: "a\\b\\c", "a\\b", true); - t!(s: "a", ".", true); - t!(s: ".", ".", false); - t!(s: "\\a", "\\", true); - t!(s: "\\", "\\", false); - t!(b: &b"a\\b\\c"[..], b"a\\b", true); - t!(b: &b"a"[..], b".", true); - t!(b: &b"."[..], b".", false); - t!(b: &b"\\a"[..], b"\\", true); - t!(b: &b"\\"[..], b"\\", false); - - t!(s: "C:\\a\\b", "C:\\a", true); - t!(s: "C:\\a", "C:\\", true); - t!(s: "C:\\", "C:\\", false); - t!(s: "C:a\\b", "C:a", true); - t!(s: "C:a", "C:", true); - t!(s: "C:", "C:", false); - t!(s: "\\\\server\\share\\a\\b", "\\\\server\\share\\a", true); - t!(s: "\\\\server\\share\\a", "\\\\server\\share", true); - t!(s: "\\\\server\\share", "\\\\server\\share", false); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", true); - t!(s: "\\\\?\\a\\b", "\\\\?\\a", true); - t!(s: "\\\\?\\a", "\\\\?\\a", false); - t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true); - t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\", true); - t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\", false); - t!(s: "\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true); - t!(s: "\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share", true); - t!(s: "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false); - t!(s: "\\\\.\\a\\b\\c", "\\\\.\\a\\b", true); - t!(s: "\\\\.\\a\\b", "\\\\.\\a", true); - t!(s: "\\\\.\\a", "\\\\.\\a", false); - - t!(s: "\\\\?\\a\\b\\", "\\\\?\\a", true); - } - - #[test] - fn test_root_path() { - assert_eq!(Path::new("a\\b\\c").root_path(), None); - assert_eq!(Path::new("\\a\\b\\c").root_path(), Some(Path::new("\\"))); - assert_eq!(Path::new("C:a").root_path(), Some(Path::new("C:"))); - assert_eq!(Path::new("C:\\a").root_path(), Some(Path::new("C:\\"))); - assert_eq!(Path::new("\\\\a\\b\\c").root_path(), Some(Path::new("\\\\a\\b"))); - assert_eq!(Path::new("\\\\?\\a\\b").root_path(), Some(Path::new("\\\\?\\a"))); - assert_eq!(Path::new("\\\\?\\C:\\a").root_path(), Some(Path::new("\\\\?\\C:\\"))); - assert_eq!(Path::new("\\\\?\\UNC\\a\\b\\c").root_path(), - Some(Path::new("\\\\?\\UNC\\a\\b"))); - assert_eq!(Path::new("\\\\.\\a\\b").root_path(), Some(Path::new("\\\\.\\a"))); - } - - #[test] - fn test_join() { - t!(s: Path::new("a\\b\\c").join(".."), "a\\b"); - t!(s: Path::new("\\a\\b\\c").join("d"), "\\a\\b\\c\\d"); - t!(s: Path::new("a\\b").join("c\\d"), "a\\b\\c\\d"); - t!(s: Path::new("a\\b").join("\\c\\d"), "\\c\\d"); - t!(s: Path::new(".").join("a\\b"), "a\\b"); - t!(s: Path::new("\\").join("a\\b"), "\\a\\b"); - t!(v: Path::new(&b"a\\b\\c"[..]).join(&b".."[..]), b"a\\b"); - t!(v: Path::new(&b"\\a\\b\\c"[..]).join(&b"d"[..]), b"\\a\\b\\c\\d"); - // full join testing is covered under test_push_path, so no need for - // the full set of prefix tests - } - - #[test] - fn test_join_path() { - macro_rules! t { - (s: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let join = Path::new($join); - let res = path.join(&join); - assert_eq!(res.as_str(), Some($exp)); - } - ) - } - - t!(s: "a\\b\\c", "..", "a\\b"); - t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d"); - t!(s: "a\\b", "c\\d", "a\\b\\c\\d"); - t!(s: "a\\b", "\\c\\d", "\\c\\d"); - t!(s: ".", "a\\b", "a\\b"); - t!(s: "\\", "a\\b", "\\a\\b"); - // join is implemented using push, so there's no need for - // the full set of prefix tests - } - - #[test] - fn test_join_many() { - macro_rules! t { - (s: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let res = path.join_many(&$join); - assert_eq!(res.as_str(), Some($exp)); - } - ); - (v: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let res = path.join_many(&$join); - assert_eq!(res.as_vec(), $exp); - } - ) - } - - t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e"); - t!(s: "a\\b\\c", ["..", "d"], "a\\b\\d"); - t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f"); - t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e"); - t!(v: &b"a\\b\\c"[..], [&b"d"[..], &b"e"[..]], b"a\\b\\c\\d\\e"); - t!(v: &b"a\\b\\c"[..], [b"d".to_vec(), b"e".to_vec()], - b"a\\b\\c\\d\\e"); - } - - #[test] - fn test_with_helpers() { - macro_rules! t { - (s: $path:expr, $op:ident, $arg:expr, $res:expr) => ( - { - let pstr = $path; - let path = Path::new(pstr); - let arg = $arg; - let res = path.$op(arg); - let exp = Path::new($res); - assert_eq!(res, exp); - } - ) - } - - t!(s: "a\\b\\c", with_filename, "d", "a\\b\\d"); - t!(s: ".", with_filename, "foo", "foo"); - t!(s: "\\a\\b\\c", with_filename, "d", "\\a\\b\\d"); - t!(s: "\\", with_filename, "foo", "\\foo"); - t!(s: "\\a", with_filename, "foo", "\\foo"); - t!(s: "foo", with_filename, "bar", "bar"); - t!(s: "\\", with_filename, "foo\\", "\\foo"); - t!(s: "\\a", with_filename, "foo\\", "\\foo"); - t!(s: "a\\b\\c", with_filename, "", "a\\b"); - t!(s: "a\\b\\c", with_filename, ".", "a\\b"); - t!(s: "a\\b\\c", with_filename, "..", "a"); - t!(s: "\\a", with_filename, "", "\\"); - t!(s: "foo", with_filename, "", "."); - t!(s: "a\\b\\c", with_filename, "d\\e", "a\\b\\d\\e"); - t!(s: "a\\b\\c", with_filename, "\\d", "a\\b\\d"); - t!(s: "..", with_filename, "foo", "..\\foo"); - t!(s: "..\\..", with_filename, "foo", "..\\..\\foo"); - t!(s: "..", with_filename, "", ".."); - t!(s: "..\\..", with_filename, "", "..\\.."); - t!(s: "C:\\foo\\bar", with_filename, "baz", "C:\\foo\\baz"); - t!(s: "C:\\foo", with_filename, "bar", "C:\\bar"); - t!(s: "C:\\", with_filename, "foo", "C:\\foo"); - t!(s: "C:foo\\bar", with_filename, "baz", "C:foo\\baz"); - t!(s: "C:foo", with_filename, "bar", "C:bar"); - t!(s: "C:", with_filename, "foo", "C:foo"); - t!(s: "C:\\foo", with_filename, "", "C:\\"); - t!(s: "C:foo", with_filename, "", "C:"); - t!(s: "C:\\foo\\bar", with_filename, "..", "C:\\"); - t!(s: "C:\\foo", with_filename, "..", "C:\\"); - t!(s: "C:\\", with_filename, "..", "C:\\"); - t!(s: "C:foo\\bar", with_filename, "..", "C:"); - t!(s: "C:foo", with_filename, "..", "C:.."); - t!(s: "C:", with_filename, "..", "C:.."); - t!(s: "\\\\server\\share\\foo", with_filename, "bar", "\\\\server\\share\\bar"); - t!(s: "\\\\server\\share", with_filename, "foo", "\\\\server\\share\\foo"); - t!(s: "\\\\server\\share\\foo", with_filename, "", "\\\\server\\share"); - t!(s: "\\\\server\\share", with_filename, "", "\\\\server\\share"); - t!(s: "\\\\server\\share\\foo", with_filename, "..", "\\\\server\\share"); - t!(s: "\\\\server\\share", with_filename, "..", "\\\\server\\share"); - t!(s: "\\\\?\\C:\\foo\\bar", with_filename, "baz", "\\\\?\\C:\\foo\\baz"); - t!(s: "\\\\?\\C:\\foo", with_filename, "bar", "\\\\?\\C:\\bar"); - t!(s: "\\\\?\\C:\\", with_filename, "foo", "\\\\?\\C:\\foo"); - t!(s: "\\\\?\\C:\\foo", with_filename, "..", "\\\\?\\C:\\.."); - t!(s: "\\\\?\\foo\\bar", with_filename, "baz", "\\\\?\\foo\\baz"); - t!(s: "\\\\?\\foo", with_filename, "bar", "\\\\?\\foo\\bar"); - t!(s: "\\\\?\\", with_filename, "foo", "\\\\?\\\\foo"); - t!(s: "\\\\?\\foo\\bar", with_filename, "..", "\\\\?\\foo\\.."); - t!(s: "\\\\.\\foo\\bar", with_filename, "baz", "\\\\.\\foo\\baz"); - t!(s: "\\\\.\\foo", with_filename, "bar", "\\\\.\\foo\\bar"); - t!(s: "\\\\.\\foo\\bar", with_filename, "..", "\\\\.\\foo\\.."); - - t!(s: "hi\\there.txt", with_extension, "exe", "hi\\there.exe"); - t!(s: "hi\\there.txt", with_extension, "", "hi\\there"); - t!(s: "hi\\there.txt", with_extension, ".", "hi\\there.."); - t!(s: "hi\\there.txt", with_extension, "..", "hi\\there..."); - t!(s: "hi\\there", with_extension, "txt", "hi\\there.txt"); - t!(s: "hi\\there", with_extension, ".", "hi\\there.."); - t!(s: "hi\\there", with_extension, "..", "hi\\there..."); - t!(s: "hi\\there.", with_extension, "txt", "hi\\there.txt"); - t!(s: "hi\\.foo", with_extension, "txt", "hi\\.foo.txt"); - t!(s: "hi\\there.txt", with_extension, ".foo", "hi\\there..foo"); - t!(s: "\\", with_extension, "txt", "\\"); - t!(s: "\\", with_extension, ".", "\\"); - t!(s: "\\", with_extension, "..", "\\"); - t!(s: ".", with_extension, "txt", "."); - // extension setter calls filename setter internally, no need for extended tests - } - - #[test] - fn test_setters() { - macro_rules! t { - (s: $path:expr, $set:ident, $with:ident, $arg:expr) => ( - { - let path = $path; - let arg = $arg; - let mut p1 = Path::new(path); - p1.$set(arg); - let p2 = Path::new(path); - assert_eq!(p1, p2.$with(arg)); - } - ); - (v: $path:expr, $set:ident, $with:ident, $arg:expr) => ( - { - let path = $path; - let arg = $arg; - let mut p1 = Path::new(path); - p1.$set(arg); - let p2 = Path::new(path); - assert_eq!(p1, p2.$with(arg)); - } - ) - } - - t!(v: &b"a\\b\\c"[..], set_filename, with_filename, &b"d"[..]); - t!(v: &b"\\"[..], set_filename, with_filename, &b"foo"[..]); - t!(s: "a\\b\\c", set_filename, with_filename, "d"); - t!(s: "\\", set_filename, with_filename, "foo"); - t!(s: ".", set_filename, with_filename, "foo"); - t!(s: "a\\b", set_filename, with_filename, ""); - t!(s: "a", set_filename, with_filename, ""); - - t!(v: &b"hi\\there.txt"[..], set_extension, with_extension, &b"exe"[..]); - t!(s: "hi\\there.txt", set_extension, with_extension, "exe"); - t!(s: "hi\\there.", set_extension, with_extension, "txt"); - t!(s: "hi\\there", set_extension, with_extension, "txt"); - t!(s: "hi\\there.txt", set_extension, with_extension, ""); - t!(s: "hi\\there", set_extension, with_extension, ""); - t!(s: ".", set_extension, with_extension, "txt"); - - // with_ helpers use the setter internally, so the tests for the with_ helpers - // will suffice. No need for the full set of prefix tests. - } - - #[test] - fn test_getters() { - macro_rules! t { - (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( - { - let path = $path; - assert_eq!(path.filename_str(), $filename); - assert_eq!(path.dirname_str(), $dirname); - assert_eq!(path.filestem_str(), $filestem); - assert_eq!(path.extension_str(), $ext); - } - ); - (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( - { - let path = $path; - assert_eq!(path.filename(), $filename); - assert_eq!(path.dirname(), $dirname); - assert_eq!(path.filestem(), $filestem); - assert_eq!(path.extension(), $ext); - } - ) - } - - t!(v: Path::new(&b"a\\b\\c"[..]), Some(&b"c"[..]), b"a\\b", Some(&b"c"[..]), None); - t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None); - t!(s: Path::new("."), None, Some("."), None, None); - t!(s: Path::new("\\"), None, Some("\\"), None, None); - t!(s: Path::new(".."), None, Some(".."), None, None); - t!(s: Path::new("..\\.."), None, Some("..\\.."), None, None); - t!(s: Path::new("hi\\there.txt"), Some("there.txt"), Some("hi"), - Some("there"), Some("txt")); - t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), None); - t!(s: Path::new("hi\\there."), Some("there."), Some("hi"), - Some("there"), Some("")); - t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), None); - t!(s: Path::new("hi\\..there"), Some("..there"), Some("hi"), - Some("."), Some("there")); - - // these are already tested in test_components, so no need for extended tests - } - - #[test] - fn test_dir_path() { - t!(s: Path::new("hi\\there").dir_path(), "hi"); - t!(s: Path::new("hi").dir_path(), "."); - t!(s: Path::new("\\hi").dir_path(), "\\"); - t!(s: Path::new("\\").dir_path(), "\\"); - t!(s: Path::new("..").dir_path(), ".."); - t!(s: Path::new("..\\..").dir_path(), "..\\.."); - - // dir_path is just dirname interpreted as a path. - // No need for extended tests - } - - #[test] - fn test_is_absolute() { - macro_rules! t { - ($path:expr, $abs:expr, $vol:expr, $cwd:expr, $rel:expr) => ( - { - let path = Path::new($path); - let (abs, vol, cwd, rel) = ($abs, $vol, $cwd, $rel); - assert_eq!(path.is_absolute(), abs); - assert_eq!(is_vol_relative(&path), vol); - assert_eq!(is_cwd_relative(&path), cwd); - assert_eq!(path.is_relative(), rel); - } - ) - } - t!("a\\b\\c", false, false, false, true); - t!("\\a\\b\\c", false, true, false, false); - t!("a", false, false, false, true); - t!("\\a", false, true, false, false); - t!(".", false, false, false, true); - t!("\\", false, true, false, false); - t!("..", false, false, false, true); - t!("..\\..", false, false, false, true); - t!("C:a\\b.txt", false, false, true, false); - t!("C:\\a\\b.txt", true, false, false, false); - t!("\\\\server\\share\\a\\b.txt", true, false, false, false); - t!("\\\\?\\a\\b\\c.txt", true, false, false, false); - t!("\\\\?\\C:\\a\\b.txt", true, false, false, false); - t!("\\\\?\\C:a\\b.txt", true, false, false, false); // NB: not equivalent to C:a\b.txt - t!("\\\\?\\UNC\\server\\share\\a\\b.txt", true, false, false, false); - t!("\\\\.\\a\\b", true, false, false, false); - } - - #[test] - fn test_is_ancestor_of() { - macro_rules! t { - (s: $path:expr, $dest:expr, $exp:expr) => ( - { - let path = Path::new($path); - let dest = Path::new($dest); - let exp = $exp; - let res = path.is_ancestor_of(&dest); - assert_eq!(res, exp); - } - ) - } - - t!(s: "a\\b\\c", "a\\b\\c\\d", true); - t!(s: "a\\b\\c", "a\\b\\c", true); - t!(s: "a\\b\\c", "a\\b", false); - t!(s: "\\a\\b\\c", "\\a\\b\\c", true); - t!(s: "\\a\\b", "\\a\\b\\c", true); - t!(s: "\\a\\b\\c\\d", "\\a\\b\\c", false); - t!(s: "\\a\\b", "a\\b\\c", false); - t!(s: "a\\b", "\\a\\b\\c", false); - t!(s: "a\\b\\c", "a\\b\\d", false); - t!(s: "..\\a\\b\\c", "a\\b\\c", false); - t!(s: "a\\b\\c", "..\\a\\b\\c", false); - t!(s: "a\\b\\c", "a\\b\\cd", false); - t!(s: "a\\b\\cd", "a\\b\\c", false); - t!(s: "..\\a\\b", "..\\a\\b\\c", true); - t!(s: ".", "a\\b", true); - t!(s: ".", ".", true); - t!(s: "\\", "\\", true); - t!(s: "\\", "\\a\\b", true); - t!(s: "..", "a\\b", true); - t!(s: "..\\..", "a\\b", true); - t!(s: "foo\\bar", "foobar", false); - t!(s: "foobar", "foo\\bar", false); - - t!(s: "foo", "C:foo", false); - t!(s: "C:foo", "foo", false); - t!(s: "C:foo", "C:foo\\bar", true); - t!(s: "C:foo\\bar", "C:foo", false); - t!(s: "C:\\foo", "C:\\foo\\bar", true); - t!(s: "C:", "C:", true); - t!(s: "C:", "C:\\", false); - t!(s: "C:\\", "C:", false); - t!(s: "C:\\", "C:\\", true); - t!(s: "C:\\foo\\bar", "C:\\foo", false); - t!(s: "C:foo\\bar", "C:foo", false); - t!(s: "C:\\foo", "\\foo", false); - t!(s: "\\foo", "C:\\foo", false); - t!(s: "\\\\server\\share\\foo", "\\\\server\\share\\foo\\bar", true); - t!(s: "\\\\server\\share", "\\\\server\\share\\foo", true); - t!(s: "\\\\server\\share\\foo", "\\\\server\\share", false); - t!(s: "C:\\foo", "\\\\server\\share\\foo", false); - t!(s: "\\\\server\\share\\foo", "C:\\foo", false); - t!(s: "\\\\?\\foo\\bar", "\\\\?\\foo\\bar\\baz", true); - t!(s: "\\\\?\\foo\\bar\\baz", "\\\\?\\foo\\bar", false); - t!(s: "\\\\?\\foo\\bar", "\\foo\\bar\\baz", false); - t!(s: "\\foo\\bar", "\\\\?\\foo\\bar\\baz", false); - t!(s: "\\\\?\\C:\\foo\\bar", "\\\\?\\C:\\foo\\bar\\baz", true); - t!(s: "\\\\?\\C:\\foo\\bar\\baz", "\\\\?\\C:\\foo\\bar", false); - t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\foo", true); - t!(s: "\\\\?\\C:", "\\\\?\\C:\\", false); // this is a weird one - t!(s: "\\\\?\\C:\\", "\\\\?\\C:", false); - t!(s: "\\\\?\\C:\\a", "\\\\?\\c:\\a\\b", true); - t!(s: "\\\\?\\c:\\a", "\\\\?\\C:\\a\\b", true); - t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a\\b", false); - t!(s: "\\\\?\\foo", "\\\\?\\foobar", false); - t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", true); - t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\", true); - t!(s: "\\\\?\\a\\b\\", "\\\\?\\a\\b", true); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", false); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b\\", false); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c\\d", true); - t!(s: "\\\\?\\UNC\\a\\b\\c\\d", "\\\\?\\UNC\\a\\b\\c", false); - t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", true); - t!(s: "\\\\.\\foo\\bar", "\\\\.\\foo\\bar\\baz", true); - t!(s: "\\\\.\\foo\\bar\\baz", "\\\\.\\foo\\bar", false); - t!(s: "\\\\.\\foo", "\\\\.\\foo\\bar", true); - t!(s: "\\\\.\\foo", "\\\\.\\foobar", false); - - t!(s: "\\a\\b", "\\\\?\\a\\b", false); - t!(s: "\\\\?\\a\\b", "\\a\\b", false); - t!(s: "\\a\\b", "\\\\?\\C:\\a\\b", false); - t!(s: "\\\\?\\C:\\a\\b", "\\a\\b", false); - t!(s: "Z:\\a\\b", "\\\\?\\z:\\a\\b", true); - t!(s: "C:\\a\\b", "\\\\?\\D:\\a\\b", false); - t!(s: "a\\b", "\\\\?\\a\\b", false); - t!(s: "\\\\?\\a\\b", "a\\b", false); - t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b", true); - t!(s: "\\\\?\\C:\\a\\b", "C:\\a\\b", true); - t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", false); - t!(s: "C:a\\b", "\\\\?\\C:a\\b", false); - t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", false); - t!(s: "\\\\?\\C:a\\b", "C:a\\b", false); - t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b\\", true); - t!(s: "\\\\?\\C:\\a\\b\\", "C:\\a\\b", true); - t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c", true); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b\\c", true); - } - - #[test] - fn test_ends_with_path() { - macro_rules! t { - (s: $path:expr, $child:expr, $exp:expr) => ( - { - let path = Path::new($path); - let child = Path::new($child); - assert_eq!(path.ends_with_path(&child), $exp); - } - ); - } - - t!(s: "a\\b\\c", "c", true); - t!(s: "a\\b\\c", "d", false); - t!(s: "foo\\bar\\quux", "bar", false); - t!(s: "foo\\bar\\quux", "barquux", false); - t!(s: "a\\b\\c", "b\\c", true); - t!(s: "a\\b\\c", "a\\b\\c", true); - t!(s: "a\\b\\c", "foo\\a\\b\\c", false); - t!(s: "\\a\\b\\c", "a\\b\\c", true); - t!(s: "\\a\\b\\c", "\\a\\b\\c", false); // child must be relative - t!(s: "\\a\\b\\c", "foo\\a\\b\\c", false); - t!(s: "a\\b\\c", "", false); - t!(s: "", "", true); - t!(s: "\\a\\b\\c", "d\\e\\f", false); - t!(s: "a\\b\\c", "a\\b", false); - t!(s: "a\\b\\c", "b", false); - t!(s: "C:\\a\\b", "b", true); - t!(s: "C:\\a\\b", "C:b", false); - t!(s: "C:\\a\\b", "C:a\\b", false); - } - - #[test] - fn test_path_relative_from() { - macro_rules! t { - (s: $path:expr, $other:expr, $exp:expr) => ( - { - assert_eq!(Path::new($path).path_relative_from(&Path::new($other)) - .as_ref().and_then(|x| x.as_str()), $exp); - } - ) - } - - t!(s: "a\\b\\c", "a\\b", Some("c")); - t!(s: "a\\b\\c", "a\\b\\d", Some("..\\c")); - t!(s: "a\\b\\c", "a\\b\\c\\d", Some("..")); - t!(s: "a\\b\\c", "a\\b\\c", Some(".")); - t!(s: "a\\b\\c", "a\\b\\c\\d\\e", Some("..\\..")); - t!(s: "a\\b\\c", "a\\d\\e", Some("..\\..\\b\\c")); - t!(s: "a\\b\\c", "d\\e\\f", Some("..\\..\\..\\a\\b\\c")); - t!(s: "a\\b\\c", "\\a\\b\\c", None); - t!(s: "\\a\\b\\c", "a\\b\\c", Some("\\a\\b\\c")); - t!(s: "\\a\\b\\c", "\\a\\b\\c\\d", Some("..")); - t!(s: "\\a\\b\\c", "\\a\\b", Some("c")); - t!(s: "\\a\\b\\c", "\\a\\b\\c\\d\\e", Some("..\\..")); - t!(s: "\\a\\b\\c", "\\a\\d\\e", Some("..\\..\\b\\c")); - t!(s: "\\a\\b\\c", "\\d\\e\\f", Some("..\\..\\..\\a\\b\\c")); - t!(s: "hi\\there.txt", "hi\\there", Some("..\\there.txt")); - t!(s: ".", "a", Some("..")); - t!(s: ".", "a\\b", Some("..\\..")); - t!(s: ".", ".", Some(".")); - t!(s: "a", ".", Some("a")); - t!(s: "a\\b", ".", Some("a\\b")); - t!(s: "..", ".", Some("..")); - t!(s: "a\\b\\c", "a\\b\\c", Some(".")); - t!(s: "\\a\\b\\c", "\\a\\b\\c", Some(".")); - t!(s: "\\", "\\", Some(".")); - t!(s: "\\", ".", Some("\\")); - t!(s: "..\\..\\a", "b", Some("..\\..\\..\\a")); - t!(s: "a", "..\\..\\b", None); - t!(s: "..\\..\\a", "..\\..\\b", Some("..\\a")); - t!(s: "..\\..\\a", "..\\..\\a\\b", Some("..")); - t!(s: "..\\..\\a\\b", "..\\..\\a", Some("b")); - - t!(s: "C:a\\b\\c", "C:a\\b", Some("c")); - t!(s: "C:a\\b", "C:a\\b\\c", Some("..")); - t!(s: "C:" ,"C:a\\b", Some("..\\..")); - t!(s: "C:a\\b", "C:c\\d", Some("..\\..\\a\\b")); - t!(s: "C:a\\b", "D:c\\d", Some("C:a\\b")); - t!(s: "C:a\\b", "C:..\\c", None); - t!(s: "C:..\\a", "C:b\\c", Some("..\\..\\..\\a")); - t!(s: "C:\\a\\b\\c", "C:\\a\\b", Some("c")); - t!(s: "C:\\a\\b", "C:\\a\\b\\c", Some("..")); - t!(s: "C:\\", "C:\\a\\b", Some("..\\..")); - t!(s: "C:\\a\\b", "C:\\c\\d", Some("..\\..\\a\\b")); - t!(s: "C:\\a\\b", "C:a\\b", Some("C:\\a\\b")); - t!(s: "C:a\\b", "C:\\a\\b", None); - t!(s: "\\a\\b", "C:\\a\\b", None); - t!(s: "\\a\\b", "C:a\\b", None); - t!(s: "a\\b", "C:\\a\\b", None); - t!(s: "a\\b", "C:a\\b", None); - - t!(s: "\\\\a\\b\\c", "\\\\a\\b", Some("c")); - t!(s: "\\\\a\\b", "\\\\a\\b\\c", Some("..")); - t!(s: "\\\\a\\b\\c\\e", "\\\\a\\b\\c\\d", Some("..\\e")); - t!(s: "\\\\a\\c\\d", "\\\\a\\b\\d", Some("\\\\a\\c\\d")); - t!(s: "\\\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\b\\c\\d")); - t!(s: "\\\\a\\b\\c", "\\d\\e", Some("\\\\a\\b\\c")); - t!(s: "\\d\\e", "\\\\a\\b\\c", None); - t!(s: "d\\e", "\\\\a\\b\\c", None); - t!(s: "C:\\a\\b\\c", "\\\\a\\b\\c", Some("C:\\a\\b\\c")); - t!(s: "C:\\c", "\\\\a\\b\\c", Some("C:\\c")); - - t!(s: "\\\\?\\a\\b", "\\a\\b", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a\\b", "a\\b", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a\\b", "\\b", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a\\b", "b", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", Some("..")); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", Some("c")); - t!(s: "\\\\?\\a\\b", "\\\\?\\c\\d", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a", "\\\\?\\b", Some("\\\\?\\a")); - - t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", Some("b")); - t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\a\\b", Some("..")); - t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\b", Some("..\\a")); - t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a", Some("\\\\?\\C:\\a")); - t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\c:\\a", Some("b")); - t!(s: "\\\\?\\C:\\a\\b", "C:\\a", Some("b")); - t!(s: "\\\\?\\C:\\a", "C:\\a\\b", Some("..")); - t!(s: "C:\\a\\b", "\\\\?\\C:\\a", Some("b")); - t!(s: "C:\\a", "\\\\?\\C:\\a\\b", Some("..")); - t!(s: "\\\\?\\C:\\a", "D:\\a", Some("\\\\?\\C:\\a")); - t!(s: "\\\\?\\c:\\a\\b", "C:\\a", Some("b")); - t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", Some("\\\\?\\C:\\a\\b")); - t!(s: "\\\\?\\C:\\a\\.\\b", "C:\\a", Some("\\\\?\\C:\\a\\.\\b")); - t!(s: "\\\\?\\C:\\a\\b/c", "C:\\a", Some("\\\\?\\C:\\a\\b/c")); - t!(s: "\\\\?\\C:\\a\\..\\b", "C:\\a", Some("\\\\?\\C:\\a\\..\\b")); - t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", None); - t!(s: "\\\\?\\C:\\a\\.\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\.\\b")); - t!(s: "\\\\?\\C:\\a\\b/c", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\b/c")); - t!(s: "\\\\?\\C:\\a\\..\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\..\\b")); - t!(s: "\\\\?\\C:\\a\\b\\", "\\\\?\\C:\\a", Some("b")); - t!(s: "\\\\?\\C:\\.\\b", "\\\\?\\C:\\.", Some("b")); - t!(s: "C:\\b", "\\\\?\\C:\\.", Some("..\\b")); - t!(s: "\\\\?\\a\\.\\b\\c", "\\\\?\\a\\.\\b", Some("c")); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\.\\d", Some("..\\..\\b\\c")); - t!(s: "\\\\?\\a\\..\\b", "\\\\?\\a\\..", Some("b")); - t!(s: "\\\\?\\a\\b\\..", "\\\\?\\a\\b", Some("\\\\?\\a\\b\\..")); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\..\\b", Some("..\\..\\b\\c")); - - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c")); - t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", Some("..")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c")); - t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\C:\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c")); - t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d")); - t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\.")); - t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\..")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b", Some("c")); - t!(s: "\\\\?\\UNC\\a\\b", "\\\\a\\b\\c", Some("..")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c")); - t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d")); - t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\.")); - t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d")); - t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\..")); - t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c")); - t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\a\\b\\c")); - } - - #[test] - fn test_str_components() { - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let comps = path.str_components().map(|x|x.unwrap()) - .collect::>(); - let exp: &[&str] = &$exp; - assert_eq!(comps, exp); - let comps = path.str_components().rev().map(|x|x.unwrap()) - .collect::>(); - let exp = exp.iter().rev().cloned().collect::>(); - assert_eq!(comps, exp); - } - ); - } - - t!(s: &b"a\\b\\c"[..], ["a", "b", "c"]); - t!(s: "a\\b\\c", ["a", "b", "c"]); - t!(s: "a\\b\\d", ["a", "b", "d"]); - t!(s: "a\\b\\cd", ["a", "b", "cd"]); - t!(s: "\\a\\b\\c", ["a", "b", "c"]); - t!(s: "a", ["a"]); - t!(s: "\\a", ["a"]); - t!(s: "\\", []); - t!(s: ".", ["."]); - t!(s: "..", [".."]); - t!(s: "..\\..", ["..", ".."]); - t!(s: "..\\..\\foo", ["..", "..", "foo"]); - t!(s: "C:foo\\bar", ["foo", "bar"]); - t!(s: "C:foo", ["foo"]); - t!(s: "C:", []); - t!(s: "C:\\foo\\bar", ["foo", "bar"]); - t!(s: "C:\\foo", ["foo"]); - t!(s: "C:\\", []); - t!(s: "\\\\server\\share\\foo\\bar", ["foo", "bar"]); - t!(s: "\\\\server\\share\\foo", ["foo"]); - t!(s: "\\\\server\\share", []); - t!(s: "\\\\?\\foo\\bar\\baz", ["bar", "baz"]); - t!(s: "\\\\?\\foo\\bar", ["bar"]); - t!(s: "\\\\?\\foo", []); - t!(s: "\\\\?\\", []); - t!(s: "\\\\?\\a\\b", ["b"]); - t!(s: "\\\\?\\a\\b\\", ["b"]); - t!(s: "\\\\?\\foo\\bar\\\\baz", ["bar", "", "baz"]); - t!(s: "\\\\?\\C:\\foo\\bar", ["foo", "bar"]); - t!(s: "\\\\?\\C:\\foo", ["foo"]); - t!(s: "\\\\?\\C:\\", []); - t!(s: "\\\\?\\C:\\foo\\", ["foo"]); - t!(s: "\\\\?\\UNC\\server\\share\\foo\\bar", ["foo", "bar"]); - t!(s: "\\\\?\\UNC\\server\\share\\foo", ["foo"]); - t!(s: "\\\\?\\UNC\\server\\share", []); - t!(s: "\\\\.\\foo\\bar\\baz", ["bar", "baz"]); - t!(s: "\\\\.\\foo\\bar", ["bar"]); - t!(s: "\\\\.\\foo", []); - } - - #[test] - fn test_components_iter() { - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let comps = path.components().collect::>(); - let exp: &[&[u8]] = &$exp; - assert_eq!(comps, exp); - let comps = path.components().rev().collect::>(); - let exp = exp.iter().rev().cloned().collect::>(); - assert_eq!(comps, exp); - } - ) - } - - t!(s: "a\\b\\c", [b"a", b"b", b"c"]); - t!(s: ".", [b"."]); - // since this is really a wrapper around str_components, those tests suffice - } - - #[test] - fn test_make_non_verbatim() { - macro_rules! t { - ($path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let exp: Option<&str> = $exp; - let exp = exp.map(|s| Path::new(s)); - assert_eq!(make_non_verbatim(&path), exp); - } - ) - } - - t!(r"\a\b\c", Some(r"\a\b\c")); - t!(r"a\b\c", Some(r"a\b\c")); - t!(r"C:\a\b\c", Some(r"C:\a\b\c")); - t!(r"C:a\b\c", Some(r"C:a\b\c")); - t!(r"\\server\share\foo", Some(r"\\server\share\foo")); - t!(r"\\.\foo", None); - t!(r"\\?\foo", None); - t!(r"\\?\C:", None); - t!(r"\\?\C:foo", None); - t!(r"\\?\C:\", Some(r"C:\")); - t!(r"\\?\C:\foo", Some(r"C:\foo")); - t!(r"\\?\C:\foo\bar\baz", Some(r"C:\foo\bar\baz")); - t!(r"\\?\C:\foo\.\bar\baz", None); - t!(r"\\?\C:\foo\bar\..\baz", None); - t!(r"\\?\C:\foo\bar\..", None); - t!(r"\\?\UNC\server\share\foo", Some(r"\\server\share\foo")); - t!(r"\\?\UNC\server\share", Some(r"\\server\share")); - t!(r"\\?\UNC\server", None); - t!(r"\\?\UNC\server\", None); - } -} diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 84a450867675c..c93fc13284b44 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -47,6 +47,3 @@ #[doc(no_inline)] pub use string::{String, ToString}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use vec::Vec; - -#[allow(deprecated)] pub use slice::AsSlice; -#[allow(deprecated)] pub use str::Str; diff --git a/src/libstd/process.rs b/src/libstd/process.rs index cac1540d0ec4c..a92c6318c3264 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -534,8 +534,6 @@ mod tests { use io::prelude::*; use io::ErrorKind; - use old_path::{self, GenericPath}; - use old_io::fs::PathExtensions; use rt::running_on_valgrind; use str; use super::{Command, Output, Stdio}; @@ -748,43 +746,6 @@ mod tests { cmd } - #[cfg(not(target_arch = "aarch64"))] - #[test] - fn test_keep_current_working_dir() { - use os; - let prog = pwd_cmd().spawn().unwrap(); - - let output = String::from_utf8(prog.wait_with_output().unwrap().stdout).unwrap(); - let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string(); - let parent_dir = old_path::Path::new(parent_dir); - let child_dir = old_path::Path::new(output.trim()); - - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); - - assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); - assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); - } - - #[test] - fn test_change_working_directory() { - use os; - // test changing to the parent of os::getcwd() because we know - // the path exists (and os::getcwd() is not expected to be root) - let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string(); - let parent_dir = old_path::Path::new(parent_dir).dir_path(); - let result = pwd_cmd().current_dir(parent_dir.as_str().unwrap()).output().unwrap(); - - let output = String::from_utf8(result.stdout).unwrap(); - let child_dir = old_path::Path::new(output.trim()); - - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); - - assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); - assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); - } - #[cfg(all(unix, not(target_os="android")))] pub fn env_cmd() -> Command { Command::new("env") diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index fad57323d34ba..e11a5818966fa 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -54,197 +54,24 @@ //! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference //! between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` //! and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) -//! -//! # Examples -//! -//! ```rust -//! # #![feature(rand)] -//! use std::rand; -//! use std::rand::Rng; -//! -//! let mut rng = rand::thread_rng(); -//! if rng.gen() { // random bool -//! println!("isize: {}, usize: {}", rng.gen::(), rng.gen::()) -//! } -//! ``` -//! -//! ```rust -//! # #![feature(rand)] -//! use std::rand; -//! -//! let tuple = rand::random::<(f64, char)>(); -//! println!("{:?}", tuple) -//! ``` -//! -//! ## Monte Carlo estimation of π -//! -//! For this example, imagine we have a square with sides of length 2 and a unit -//! circle, both centered at the origin. Since the area of a unit circle is π, -//! we have: -//! -//! ```text -//! (area of unit circle) / (area of square) = π / 4 -//! ``` -//! -//! So if we sample many points randomly from the square, roughly π / 4 of them -//! should be inside the circle. -//! -//! We can use the above fact to estimate the value of π: pick many points in the -//! square at random, calculate the fraction that fall within the circle, and -//! multiply this fraction by 4. -//! -//! ``` -//! # #![feature(rand)] -//! use std::rand; -//! use std::rand::distributions::{IndependentSample, Range}; -//! -//! fn main() { -//! let between = Range::new(-1f64, 1.); -//! let mut rng = rand::thread_rng(); -//! -//! let total = 1_000_000; -//! let mut in_circle = 0; -//! -//! for _ in 0..total { -//! let a = between.ind_sample(&mut rng); -//! let b = between.ind_sample(&mut rng); -//! if a*a + b*b <= 1. { -//! in_circle += 1; -//! } -//! } -//! -//! // prints something close to 3.14159... -//! println!("{}", 4. * (in_circle as f64) / (total as f64)); -//! } -//! ``` -//! -//! ## Monty Hall Problem -//! -//! This is a simulation of the [Monty Hall Problem][]: -//! -//! > Suppose you're on a game show, and you're given the choice of three doors: -//! > Behind one door is a car; behind the others, goats. You pick a door, say No. 1, -//! > and the host, who knows what's behind the doors, opens another door, say No. 3, -//! > which has a goat. He then says to you, "Do you want to pick door No. 2?" -//! > Is it to your advantage to switch your choice? -//! -//! The rather unintuitive answer is that you will have a 2/3 chance of winning if -//! you switch and a 1/3 chance of winning if you don't, so it's better to switch. -//! -//! This program will simulate the game show and with large enough simulation steps -//! it will indeed confirm that it is better to switch. -//! -//! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem -//! -//! ``` -//! # #![feature(rand)] -//! use std::rand; -//! use std::rand::Rng; -//! use std::rand::distributions::{IndependentSample, Range}; -//! -//! struct SimulationResult { -//! win: bool, -//! switch: bool, -//! } -//! -//! // Run a single simulation of the Monty Hall problem. -//! fn simulate(random_door: &Range, rng: &mut R) -> SimulationResult { -//! let car = random_door.ind_sample(rng); -//! -//! // This is our initial choice -//! let mut choice = random_door.ind_sample(rng); -//! -//! // The game host opens a door -//! let open = game_host_open(car, choice, rng); -//! -//! // Shall we switch? -//! let switch = rng.gen(); -//! if switch { -//! choice = switch_door(choice, open); -//! } -//! -//! SimulationResult { win: choice == car, switch: switch } -//! } -//! -//! // Returns the door the game host opens given our choice and knowledge of -//! // where the car is. The game host will never open the door with the car. -//! fn game_host_open(car: usize, choice: usize, rng: &mut R) -> usize { -//! let choices = free_doors(&[car, choice]); -//! rand::sample(rng, choices.into_iter(), 1)[0] -//! } -//! -//! // Returns the door we switch to, given our current choice and -//! // the open door. There will only be one valid door. -//! fn switch_door(choice: usize, open: usize) -> usize { -//! free_doors(&[choice, open])[0] -//! } -//! -//! fn free_doors(blocked: &[usize]) -> Vec { -//! (0..3).filter(|x| !blocked.contains(x)).collect() -//! } -//! -//! fn main() { -//! // The estimation will be more accurate with more simulations -//! let num_simulations = 10000; -//! -//! let mut rng = rand::thread_rng(); -//! let random_door = Range::new(0, 3); -//! -//! let (mut switch_wins, mut switch_losses) = (0, 0); -//! let (mut keep_wins, mut keep_losses) = (0, 0); -//! -//! println!("Running {} simulations...", num_simulations); -//! for _ in 0..num_simulations { -//! let result = simulate(&random_door, &mut rng); -//! -//! match (result.win, result.switch) { -//! (true, true) => switch_wins += 1, -//! (true, false) => keep_wins += 1, -//! (false, true) => switch_losses += 1, -//! (false, false) => keep_losses += 1, -//! } -//! } -//! -//! let total_switches = switch_wins + switch_losses; -//! let total_keeps = keep_wins + keep_losses; -//! -//! println!("Switched door {} times with {} wins and {} losses", -//! total_switches, switch_wins, switch_losses); -//! -//! println!("Kept our choice {} times with {} wins and {} losses", -//! total_keeps, keep_wins, keep_losses); -//! -//! // With a large number of simulations, the values should converge to -//! // 0.667 and 0.333 respectively. -//! println!("Estimated chance to win if we switch: {}", -//! switch_wins as f32 / total_switches as f32); -//! println!("Estimated chance to win if we don't: {}", -//! keep_wins as f32 / total_keeps as f32); -//! } -//! ``` #![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 +96,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 { + pub fn new() -> io::Result { OsRng::new().map(|mut r| StdRng { rng: r.gen() }) } } @@ -298,22 +125,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; @@ -375,338 +186,3 @@ impl Rng for ThreadRng { self.rng.borrow_mut().fill_bytes(bytes) } } - -/// 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::(); -/// 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 { - 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, R: Rng>(rng: &mut R, - mut iter: I, - amount: usize) -> Vec { - let mut reservoir: Vec = 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::*; - use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample}; - use iter::{order, repeat}; - - struct ConstRng { i: u64 } - impl Rng for ConstRng { - fn next_u32(&mut self) -> u32 { self.i as u32 } - fn next_u64(&mut self) -> u64 { self.i } - - // no fill_bytes on purpose - } - - #[test] - fn test_fill_bytes_default() { - let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 }; - - // check every remainder mod 8, both in small and big vectors. - let lengths = [0, 1, 2, 3, 4, 5, 6, 7, - 80, 81, 82, 83, 84, 85, 86, 87]; - for &n in &lengths { - let mut v = repeat(0).take(n).collect::>(); - r.fill_bytes(&mut v); - - // use this to get nicer error messages. - for (i, &byte) in v.iter().enumerate() { - if byte == 0 { - panic!("byte {} of {} is zero", i, n) - } - } - } - } - - #[test] - fn test_gen_range() { - let mut r = thread_rng(); - for _ in 0..1000 { - let a = r.gen_range(-3, 42); - assert!(a >= -3 && a < 42); - assert_eq!(r.gen_range(0, 1), 0); - assert_eq!(r.gen_range(-12, -11), -12); - } - - for _ in 0..1000 { - let a = r.gen_range(10, 42); - assert!(a >= 10 && a < 42); - assert_eq!(r.gen_range(0, 1), 0); - assert_eq!(r.gen_range(3_000_000, 3_000_001), 3_000_000); - } - - } - - #[test] - #[should_panic] - fn test_gen_range_panic_int() { - let mut r = thread_rng(); - r.gen_range(5, -2); - } - - #[test] - #[should_panic] - fn test_gen_range_panic_uint() { - let mut r = thread_rng(); - r.gen_range(5, 2); - } - - #[test] - fn test_gen_f64() { - let mut r = thread_rng(); - let a = r.gen::(); - let b = r.gen::(); - debug!("{:?}", (a, b)); - } - - #[test] - fn test_gen_weighted_bool() { - let mut r = thread_rng(); - assert_eq!(r.gen_weighted_bool(0), true); - assert_eq!(r.gen_weighted_bool(1), true); - } - - #[test] - fn test_gen_ascii_str() { - let mut r = thread_rng(); - assert_eq!(r.gen_ascii_chars().take(0).count(), 0); - assert_eq!(r.gen_ascii_chars().take(10).count(), 10); - assert_eq!(r.gen_ascii_chars().take(16).count(), 16); - } - - #[test] - fn test_gen_vec() { - let mut r = thread_rng(); - assert_eq!(r.gen_iter::().take(0).count(), 0); - assert_eq!(r.gen_iter::().take(10).count(), 10); - assert_eq!(r.gen_iter::().take(16).count(), 16); - } - - #[test] - fn test_choose() { - let mut r = thread_rng(); - assert_eq!(r.choose(&[1, 1, 1]).cloned(), Some(1)); - - let v: &[isize] = &[]; - assert_eq!(r.choose(v), None); - } - - #[test] - fn test_shuffle() { - let mut r = thread_rng(); - let empty: &mut [isize] = &mut []; - r.shuffle(empty); - let mut one = [1]; - r.shuffle(&mut one); - let b: &[_] = &[1]; - assert_eq!(one, b); - - let mut two = [1, 2]; - r.shuffle(&mut two); - assert!(two == [1, 2] || two == [2, 1]); - - let mut x = [1, 1, 1]; - r.shuffle(&mut x); - let b: &[_] = &[1, 1, 1]; - assert_eq!(x, b); - } - - #[test] - fn test_thread_rng() { - let mut r = thread_rng(); - r.gen::(); - let mut v = [1, 1, 1]; - r.shuffle(&mut v); - let b: &[_] = &[1, 1, 1]; - assert_eq!(v, b); - assert_eq!(r.gen_range(0, 1), 0); - } - - #[test] - fn test_random() { - // not sure how to test this aside from just getting some values - let _n : usize = random(); - let _f : f32 = random(); - let _o : Option> = random(); - let _many : ((), - (usize, - isize, - Option<(u32, (bool,))>), - (u8, i8, u16, i16, u32, i32, u64, i64), - (f32, (f64, (f64,)))) = random(); - } - - #[test] - fn test_sample() { - let min_val = 1; - let max_val = 100; - - let mut r = thread_rng(); - let vals = (min_val..max_val).collect::>(); - let small_sample = sample(&mut r, vals.iter(), 5); - let large_sample = sample(&mut r, vals.iter(), vals.len() + 5); - - assert_eq!(small_sample.len(), 5); - assert_eq!(large_sample.len(), vals.len()); - - assert!(small_sample.iter().all(|e| { - **e >= min_val && **e <= max_val - })); - } - - #[test] - fn test_std_rng_seeded() { - let s = thread_rng().gen_iter::().take(256).collect::>(); - let mut ra: StdRng = SeedableRng::from_seed(&*s); - let mut rb: StdRng = SeedableRng::from_seed(&*s); - assert!(order::equals(ra.gen_ascii_chars().take(100), - rb.gen_ascii_chars().take(100))); - } - - #[test] - fn test_std_rng_reseed() { - let s = thread_rng().gen_iter::().take(256).collect::>(); - let mut r: StdRng = SeedableRng::from_seed(&*s); - let string1 = r.gen_ascii_chars().take(100).collect::(); - - r.reseed(&s); - - let string2 = r.gen_ascii_chars().take(100).collect::(); - assert_eq!(string1, string2); - } -} - -#[cfg(test)] -mod bench { - extern crate test; - use prelude::v1::*; - - use self::test::Bencher; - use super::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, Rng}; - use super::{OsRng, weak_rng}; - use mem::size_of; - - const RAND_BENCH_N: u64 = 100; - - #[bench] - fn rand_xorshift(b: &mut Bencher) { - let mut rng: XorShiftRng = OsRng::new().unwrap().gen(); - b.iter(|| { - for _ in 0..RAND_BENCH_N { - rng.gen::(); - } - }); - b.bytes = size_of::() as u64 * RAND_BENCH_N; - } - - #[bench] - fn rand_isaac(b: &mut Bencher) { - let mut rng: IsaacRng = OsRng::new().unwrap().gen(); - b.iter(|| { - for _ in 0..RAND_BENCH_N { - rng.gen::(); - } - }); - b.bytes = size_of::() as u64 * RAND_BENCH_N; - } - - #[bench] - fn rand_isaac64(b: &mut Bencher) { - let mut rng: Isaac64Rng = OsRng::new().unwrap().gen(); - b.iter(|| { - for _ in 0..RAND_BENCH_N { - rng.gen::(); - } - }); - b.bytes = size_of::() as u64 * RAND_BENCH_N; - } - - #[bench] - fn rand_std(b: &mut Bencher) { - let mut rng = StdRng::new().unwrap(); - b.iter(|| { - for _ in 0..RAND_BENCH_N { - rng.gen::(); - } - }); - b.bytes = size_of::() as u64 * RAND_BENCH_N; - } - - #[bench] - fn rand_shuffle_100(b: &mut Bencher) { - let mut rng = weak_rng(); - let x : &mut[usize] = &mut [1; 100]; - b.iter(|| { - rng.shuffle(x); - }) - } -} diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 38c57eec684db..6c10759023770 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -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 { + pub fn new() -> io::Result { 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 { + pub fn new() -> io::Result { 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 { + pub fn new() -> io::Result { 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 }) } diff --git a/src/libstd/rand/reader.rs b/src/libstd/rand/reader.rs index ece6867ddcaa1..60645707c6aee 100644 --- a/src/libstd/rand/reader.rs +++ b/src/libstd/rand/reader.rs @@ -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::()); -/// ``` pub struct ReaderRng { reader: R } -impl ReaderRng { - /// Create a new `ReaderRng` from a `Reader`. +impl ReaderRng { + /// Create a new `ReaderRng` from a `Read`. pub fn new(r: R) -> ReaderRng { ReaderRng { reader: r @@ -44,30 +35,29 @@ impl ReaderRng { } } -impl Rng for ReaderRng { +impl Rng for ReaderRng { 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), + } } } } @@ -77,17 +67,16 @@ mod test { use prelude::v1::*; use super::ReaderRng; - use old_io::MemReader; use num::Int; use rand::Rng; #[test] fn test_reader_rng_u64() { // transmute from the target to avoid endianness concerns. - let v = vec![0, 0, 0, 0, 0, 0, 0, 1, - 0 , 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 3]; - let mut rng = ReaderRng::new(MemReader::new(v)); + let v = &[0, 0, 0, 0, 0, 0, 0, 1, + 0 , 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 3][..]; + let mut rng = ReaderRng::new(v); assert_eq!(rng.next_u64(), 1.to_be()); assert_eq!(rng.next_u64(), 2.to_be()); @@ -95,8 +84,8 @@ mod test { } #[test] fn test_reader_rng_u32() { - let v = vec![0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]; - let mut rng = ReaderRng::new(MemReader::new(v)); + let v = &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3][..]; + let mut rng = ReaderRng::new(v); assert_eq!(rng.next_u32(), 1.to_be()); assert_eq!(rng.next_u32(), 2.to_be()); @@ -107,7 +96,7 @@ mod test { let v = [1, 2, 3, 4, 5, 6, 7, 8]; let mut w = [0; 8]; - let mut rng = ReaderRng::new(MemReader::new(v.to_vec())); + let mut rng = ReaderRng::new(&v[..]); rng.fill_bytes(&mut w); assert!(v == w); @@ -116,7 +105,7 @@ mod test { #[test] #[should_panic] fn test_reader_rng_insufficient_bytes() { - let mut rng = ReaderRng::new(MemReader::new(vec!())); + let mut rng = ReaderRng::new(&[][..]); let mut v = [0; 3]; rng.fill_bytes(&mut v); } diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 8a01eace889c3..95294b813ea19 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -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(ret: T) -> IoResult<()> { - if ret != Int::zero() { - Err(last_error()) - } else { - Ok(()) - } -} - -pub fn keep_going(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 { @@ -129,15 +50,3 @@ pub trait IntoInner { pub trait FromInner { fn from_inner(inner: Inner) -> Self; } - -#[doc(hidden)] -#[allow(deprecated)] -pub trait ProcessConfig { - fn program(&self) -> &CString; - fn args(&self) -> &[CString]; - fn env(&self) -> Option<&collections::HashMap>; - fn cwd(&self) -> Option<&CString>; - fn uid(&self) -> Option; - fn gid(&self) -> Option; - fn detach(&self) -> bool; -} diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs index fa0f14b480789..0fbcf3aee6100 100644 --- a/src/libstd/sys/unix/ext.rs +++ b/src/libstd/sys/unix/ext.rs @@ -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() } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs deleted file mode 100644 index 6121105f10b95..0000000000000 --- a/src/libstd/sys/unix/fs.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - 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 { - 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 { - 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 { - 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 { - Ok(try!(CString::new(path.as_vec()))) -} - -pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { - 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> { - use libc::{dirent_t}; - use libc::{opendir, readdir_r, closedir}; - - fn prune(root: &CString, dirs: Vec) -> Vec { - 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::::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 { - 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 = 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 { - 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 { - 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()); - } -} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index e8409bb4fd42c..a8a6219f3981d 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -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() {} diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index d2220bdec32b7..1c6a13352fff9 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -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 diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs deleted file mode 100644 index f0071295bf237..0000000000000 --- a/src/libstd/sys/unix/pipe.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - 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 { - // the sun_path length is limited to SUN_LEN (with null) - assert!(mem::size_of::() >= - mem::size_of::()); - 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::() + 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) -> IoResult { - 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 { - 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, - read_deadline: u64, - write_deadline: u64, -} - -impl UnixStream { - pub fn connect(addr: &CString, - timeout: Option) -> IoResult { - connect(addr, libc::SOCK_STREAM, timeout).map(|inner| { - UnixStream::new(Arc::new(inner)) - }) - } - - fn new(inner: Arc) -> 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 { - 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) { - 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) { - self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - - pub fn set_write_timeout(&mut self, timeout: Option) { - 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 { - 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 { - 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, - 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 { - 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::(); - 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) { - 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()); - } - } -} diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs deleted file mode 100644 index 8095325f83d1f..0000000000000 --- a/src/libstd/sys/unix/process.rs +++ /dev/null @@ -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 or the MIT license -// , 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 } - -/// 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, 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(cfg: &C, in_fd: Option