diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index e680be2a8c5..eeb1493d868 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 00000000000..89b9135558e --- /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 daa53e2dbd5..55f15867532 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/doc/index.md b/src/doc/index.md index f6b0a18824a..124a82aa7dc 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -15,6 +15,12 @@ Rust, its syntax, and its concepts. Upon completing the book, you'll be an intermediate Rust developer, and will have a good grasp of the fundamental ideas behind Rust. +[Rust By Example][rbe] was originally a community resource, but was then +donated to the Rust project. As the name implies, it teaches you Rust through a +series of small examples. + +[rbe]: rustbyexample.com + # Community & Getting Help If you need help with something, or just want to talk about Rust with others, @@ -76,17 +82,3 @@ We have [API documentation for the entire standard library](std/index.html). There's a list of crates on the left with more specific sections, or you can use the search bar at the top to search for something if you know its name. - -# External documentation - -*Note: While these are great resources for learning Rust, they may track a -particular version of Rust that is likely not exactly the same as that for -which this documentation was generated.* - -* [Rust by Example] - Short examples of common tasks in Rust (tracks the master - branch). -* [Rust for Rubyists] - The first community tutorial for Rust. Tracks the last - stable release. Not just for Ruby programmers. - -[Rust by Example]: http://rustbyexample.com/ -[Rust for Rubyists]: http://www.rustforrubyists.com/ diff --git a/src/doc/intro.md b/src/doc/intro.md index 1dc9f09c220..e6d560d8122 100644 --- a/src/doc/intro.md +++ b/src/doc/intro.md @@ -389,6 +389,7 @@ safe concurrent programs. Here's an example of a concurrent Rust program: ```{rust} +# #![feature(scoped)] use std::thread; fn main() { @@ -421,6 +422,7 @@ problem. Let's see an example. This Rust code will not compile: ```{rust,ignore} +# #![feature(scoped)] use std::thread; fn main() { @@ -467,6 +469,7 @@ that our mutation doesn't cause a data race. Here's what using a Mutex looks like: ```{rust} +# #![feature(scoped)] use std::thread; use std::sync::Mutex; @@ -527,6 +530,7 @@ As an example, Rust's ownership system is _entirely_ at compile time. The safety check that makes this an error about moved values: ```{rust,ignore} +# #![feature(scoped)] use std::thread; fn main() { diff --git a/src/doc/trpl/comments.md b/src/doc/trpl/comments.md index 441496e6a75..fa27d1c226c 100644 --- a/src/doc/trpl/comments.md +++ b/src/doc/trpl/comments.md @@ -1,47 +1,45 @@ % Comments -Now that we have some functions, it's a good idea to learn about comments. +Now that we have some functions, it’s a good idea to learn about comments. Comments are notes that you leave to other programmers to help explain things about your code. The compiler mostly ignores them. Rust has two kinds of comments that you should care about: *line comments* and *doc comments*. -```{rust} -// Line comments are anything after '//' and extend to the end of the line. +```rust +// Line comments are anything after ‘//’ and extend to the end of the line. let x = 5; // this is also a line comment. // If you have a long explanation for something, you can put line comments next -// to each other. Put a space between the // and your comment so that it's +// to each other. Put a space between the // and your comment so that it’s // more readable. ``` The other kind of comment is a doc comment. Doc comments use `///` instead of `//`, and support Markdown notation inside: -```{rust} -/// `hello` is a function that prints a greeting that is personalized based on -/// the name given. -/// -/// # Arguments -/// -/// * `name` - The name of the person you'd like to greet. +```rust +/// Adds one to the number given. /// /// # Examples /// -/// ```rust -/// let name = "Steve"; -/// hello(name); // prints "Hello, Steve!" /// ``` -fn hello(name: &str) { - println!("Hello, {}!", name); +/// let five = 5; +/// +/// assert_eq!(6, add_one(5)); +/// ``` +fn add_one(x: i32) -> i32 { + x + 1 } ``` -When writing doc comments, adding sections for any arguments, return values, -and providing some examples of usage is very, very helpful. Don't worry about -the `&str`, we'll get to it soon. +When writing doc comments, providing some examples of usage is very, very +helpful. You’ll notice we’ve used a new macro here: `assert_eq!`. This compares +two values, and `panic!`s if they’re not equal to each other. It’s very helpful +in documentation. There’s another macro, `assert!`, which `panic!`s if the +value passed to it is `false`. You can use the [`rustdoc`](documentation.html) tool to generate HTML documentation -from these doc comments. +from these doc comments, and also to run the code examples as tests! diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index f9358f28b01..159e04e9429 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -56,67 +56,34 @@ place! ## Threads -Rust's standard library provides a library for 'threads', which allow you to +Rust's standard library provides a library for threads, which allow you to run Rust code in parallel. Here's a basic example of using `std::thread`: ``` use std::thread; -fn main() { - thread::scoped(|| { - println!("Hello from a thread!"); - }); -} -``` - -The `thread::scoped()` method accepts a closure, which is executed in a new -thread. It's called `scoped` because this thread returns a join guard: - -``` -use std::thread; - -fn main() { - let guard = thread::scoped(|| { - println!("Hello from a thread!"); - }); - - // guard goes out of scope here -} -``` - -When `guard` goes out of scope, it will block execution until the thread is -finished. If we didn't want this behaviour, we could use `thread::spawn()`: - -``` -use std::thread; - fn main() { thread::spawn(|| { println!("Hello from a thread!"); }); - - thread::sleep_ms(50); } ``` -We need to `sleep` here because when `main()` ends, it kills all of the -running threads. +The `thread::spawn()` method accepts a closure, which is executed in a +new thread. It returns a handle to the thread, that can be used to +wait for the child thread to finish and extract its result: -[`scoped`](std/thread/struct.Builder.html#method.scoped) has an interesting -type signature: - -```text -fn scoped<'a, T, F>(self, f: F) -> JoinGuard<'a, T> - where T: Send + 'a, - F: FnOnce() -> T, - F: Send + 'a ``` +use std::thread; -Specifically, `F`, the closure that we pass to execute in the new thread. It -has two restrictions: It must be a `FnOnce` from `()` to `T`. Using `FnOnce` -allows the closure to take ownership of any data it mentions from the parent -thread. The other restriction is that `F` must be `Send`. We aren't allowed to -transfer this ownership unless the type thinks that's okay. +fn main() { + let handle = thread::spawn(|| { + "Hello from a thread!" + }); + + println!("{}", handle.join().unwrap()); +} +``` Many languages have the ability to execute threads, but it's wildly unsafe. There are entire books about how to prevent errors that occur from shared diff --git a/src/doc/trpl/enums.md b/src/doc/trpl/enums.md index cbb74d97c35..504bd099171 100644 --- a/src/doc/trpl/enums.md +++ b/src/doc/trpl/enums.md @@ -143,7 +143,5 @@ matching, a tool that will let us deconstruct sum types (the type theory term for enums) like `Ordering` in a very elegant way that avoids all these messy and brittle `if`/`else`s. - -[arity]: ./glossary.html#arity [match]: ./match.html [generics]: ./generics.html diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index b9e7bd78c5b..491f7b0c2a0 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -297,5 +297,5 @@ It's worth noting that you can only use `try!` from a function that returns a `Result`, which means that you cannot use `try!` inside of `main()`, because `main()` doesn't return anything. -`try!` makes use of [`FromError`](../std/error/#the-fromerror-trait) to determine +`try!` makes use of [`From`](../std/convert/trait.From.hml) to determine what to return in the error case. diff --git a/src/doc/trpl/functions.md b/src/doc/trpl/functions.md index 8e8ee8d63d6..87af48532a0 100644 --- a/src/doc/trpl/functions.md +++ b/src/doc/trpl/functions.md @@ -1,6 +1,6 @@ % Functions -You've already seen one function so far, the `main` function: +Every Rust program has at least one function, the `main` function: ```rust fn main() { @@ -8,16 +8,16 @@ fn main() { ``` This is the simplest possible function declaration. As we mentioned before, -`fn` says "this is a function," followed by the name, some parentheses because +`fn` says ‘this is a function’, followed by the name, some parentheses because this function takes no arguments, and then some curly braces to indicate the -body. Here's a function named `foo`: +body. Here’s a function named `foo`: ```rust fn foo() { } ``` -So, what about taking arguments? Here's a function that prints a number: +So, what about taking arguments? Here’s a function that prints a number: ```rust fn print_number(x: i32) { @@ -25,7 +25,7 @@ fn print_number(x: i32) { } ``` -Here's a complete program that uses `print_number`: +Here’s a complete program that uses `print_number`: ```rust fn main() { @@ -40,7 +40,7 @@ fn print_number(x: i32) { As you can see, function arguments work very similar to `let` declarations: you add a type to the argument name, after a colon. -Here's a complete program that adds two numbers together and prints them: +Here’s a complete program that adds two numbers together and prints them: ```rust fn main() { @@ -58,7 +58,7 @@ as when you declare it. Unlike `let`, you _must_ declare the types of function arguments. This does not work: -```{rust,ignore} +```rust,ignore fn print_sum(x, y) { println!("sum is: {}", x + y); } @@ -67,8 +67,8 @@ fn print_sum(x, y) { You get this error: ```text -hello.rs:5:18: 5:19 expected one of `!`, `:`, or `@`, found `)` -hello.rs:5 fn print_number(x, y) { +expected one of `!`, `:`, or `@`, found `)` +fn print_number(x, y) { ``` This is a deliberate design decision. While full-program inference is possible, @@ -77,7 +77,7 @@ types explicitly is a best-practice. We agree that forcing functions to declare types while allowing for inference inside of function bodies is a wonderful sweet spot between full inference and no inference. -What about returning a value? Here's a function that adds one to an integer: +What about returning a value? Here’s a function that adds one to an integer: ```rust fn add_one(x: i32) -> i32 { @@ -86,11 +86,11 @@ fn add_one(x: i32) -> i32 { ``` Rust functions return exactly one value, and you declare the type after an -"arrow," which is a dash (`-`) followed by a greater-than sign (`>`). +‘arrow’, which is a dash (`-`) followed by a greater-than sign (`>`). The last +line of a function determines what it returns. You’ll note the lack of a +semicolon here. If we added it in: -You'll note the lack of a semicolon here. If we added it in: - -```{rust,ignore} +```rust,ignore fn add_one(x: i32) -> i32 { x + 1; } @@ -109,24 +109,79 @@ help: consider removing this semicolon: ^ ``` -Remember our earlier discussions about semicolons and `()`? Our function claims -to return an `i32`, but with a semicolon, it would return `()` instead. Rust -realizes this probably isn't what we want, and suggests removing the semicolon. +This reveals two interesting things about Rust: it is an expression-based +language, and semicolons are different from semicolons in other ‘curly brace +and semicolon’-based languages. These two things are related. -This is very much like our `if` statement before: the result of the block -(`{}`) is the value of the expression. Other expression-oriented languages, -such as Ruby, work like this, but it's a bit unusual in the systems programming -world. When people first learn about this, they usually assume that it -introduces bugs. But because Rust's type system is so strong, and because unit -is its own unique type, we have never seen an issue where adding or removing a -semicolon in a return position would cause a bug. +## Expressions vs. Statements + +Rust is primarily an expression-based language. There are only two kinds of +statements, and everything else is an expression. + +So what's the difference? Expressions return a value, and statements do not. +That’s why we end up with ‘not all control paths return a value’ here: the +statement `x + 1;` doesn’t return a value. There are two kinds of statements in +Rust: ‘declaration statements’ and ‘expression statements’. Everything else is +an expression. Let’s talk about declaration statements first. + +In some languages, variable bindings can be written as expressions, not just +statements. Like Ruby: + +```ruby +x = y = 5 +``` + +In Rust, however, using `let` to introduce a binding is _not_ an expression. The +following will produce a compile-time error: + +```ignore +let x = (let y = 5); // expected identifier, found keyword `let` +``` + +The compiler is telling us here that it was expecting to see the beginning of +an expression, and a `let` can only begin a statement, not an expression. + +Note that assigning to an already-bound variable (e.g. `y = 5`) is still an +expression, although its value is not particularly useful. Unlike other +languages where an assignment evaluates to the assigned value (e.g. `5` in the +previous example), in Rust the value of an assignment is an empty tuple `()`: + +``` +let mut y = 5; + +let x = (y = 6); // x has the value `()`, not `6` +``` + +The second kind of statement in Rust is the *expression statement*. Its +purpose is to turn any expression into a statement. In practical terms, Rust's +grammar expects statements to follow other statements. This means that you use +semicolons to separate expressions from each other. This means that Rust +looks a lot like most other languages that require you to use semicolons +at the end of every line, and you will see semicolons at the end of almost +every line of Rust code you see. + +What is this exception that makes us say "almost"? You saw it already, in this +code: + +```rust +fn add_one(x: i32) -> i32 { + x + 1 +} +``` + +Our function claims to return an `i32`, but with a semicolon, it would return +`()` instead. Rust realizes this probably isn’t what we want, and suggests +removing the semicolon in the error we saw before. + +## Early returns But what about early returns? Rust does have a keyword for that, `return`: ```rust fn foo(x: i32) -> i32 { - if x < 5 { return x; } + return x; + // we never run this code! x + 1 } ``` @@ -136,33 +191,17 @@ style: ```rust fn foo(x: i32) -> i32 { - if x < 5 { return x; } - return x + 1; } ``` -The previous definition without `return` may look a bit strange if you haven't +The previous definition without `return` may look a bit strange if you haven’t worked in an expression-based language before, but it becomes intuitive over -time. If this were production code, we wouldn't write it in that way anyway, -we'd write this: - -```rust -fn foo(x: i32) -> i32 { - if x < 5 { - x - } else { - x + 1 - } -} -``` - -Because `if` is an expression, and it's the only expression in this function, -the value will be the result of the `if`. +time. ## Diverging functions -Rust has some special syntax for 'diverging functions', which are functions that +Rust has some special syntax for ‘diverging functions’, which are functions that do not return: ``` @@ -171,23 +210,18 @@ fn diverges() -> ! { } ``` -`panic!` is a macro, similar to `println!()` that we've already seen. Unlike +`panic!` is a macro, similar to `println!()` that we’ve already seen. Unlike `println!()`, `panic!()` causes the current thread of execution to crash with the given message. Because this function will cause a crash, it will never return, and so it has -the type '`!`', which is read "diverges." A diverging function can be used +the type ‘`!`’, which is read ‘diverges’. A diverging function can be used as any type: ```should_panic # fn diverges() -> ! { # panic!("This function never returns!"); # } - let x: i32 = diverges(); let x: String = diverges(); ``` - -We don't have a good use for diverging functions yet, because they're used in -conjunction with other Rust features. But when you see `-> !` later, you'll -know what it's called. diff --git a/src/doc/trpl/nightly-rust.md b/src/doc/trpl/nightly-rust.md index da6985da19f..3b76cce568c 100644 --- a/src/doc/trpl/nightly-rust.md +++ b/src/doc/trpl/nightly-rust.md @@ -18,7 +18,7 @@ use a two-step version of the installation and examine our installation script: ```bash $ curl -f -L https://static.rust-lang.org/rustup.sh -O -$ sudo sh rustup.sh +$ sudo sh rustup.sh --channel=nightly ``` [insecurity]: http://curlpipesh.tumblr.com diff --git a/src/doc/trpl/structs.md b/src/doc/trpl/structs.md index eff1a47761d..83d5a15bc2c 100644 --- a/src/doc/trpl/structs.md +++ b/src/doc/trpl/structs.md @@ -1,8 +1,15 @@ % Structs -A struct is another form of a *record type*, just like a tuple. There's a -difference: structs give each element that they contain a name, called a -*field* or a *member*. Check it out: +Structs are a way of creating more complex datatypes. For example, if we were +doing calculations involving coordinates in 2D space, we would need both an `x` +and a `y` value: + +```rust +let origin_x = 0; +let origin_y = 0; +``` + +A struct lets us combine these two into a single, unified datatype: ```rust struct Point { @@ -17,7 +24,7 @@ fn main() { } ``` -There's a lot going on here, so let's break it down. We declare a struct with +There’s a lot going on here, so let’s break it down. We declare a struct with the `struct` keyword, and then with a name. By convention, structs begin with a capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`. @@ -31,7 +38,7 @@ notation: `origin.x`. The values in structs are immutable by default, like other bindings in Rust. Use `mut` to make them mutable: -```{rust} +```rust struct Point { x: i32, y: i32, @@ -47,3 +54,36 @@ fn main() { ``` This will print `The point is at (5, 0)`. + +Rust does not support field mutability at the language level, so you cannot +write something like this: + +```rust,ignore +struct Point { + mut x: i32, + y: i32, +} +``` + +Mutability is a property of the binding, not of the structure itself. If you’re +used to field-level mutability, this may seem strange at first, but it +significantly simplifies things. It even lets you make things mutable for a short +time only: + + +```rust,ignore +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut point = Point { x: 0, y: 0 }; + + point.x = 5; + + let point = point; // this new binding can’t change now + + point.y = 6; // this causes an error +} +``` diff --git a/src/doc/trpl/vectors.md b/src/doc/trpl/vectors.md index cba435233fa..0dfbfc11913 100644 --- a/src/doc/trpl/vectors.md +++ b/src/doc/trpl/vectors.md @@ -1,8 +1,7 @@ % Vectors A *vector* is a dynamic or "growable" array, implemented as the standard -library type [`Vec`](../std/vec/) (we'll talk about what the `` means -later). Vectors always allocate their data on the heap. Vectors are to slices +library type [`Vec`](../std/vec/) (Where `` is a [Generic](./generics.md) statement). Vectors always allocate their data on the heap. Vectors are to slices what `String` is to `&str`. You can create them with the `vec!` macro: ```{rust} diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index d9255241af0..d12b979e084 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -923,7 +923,7 @@ impl BitVec { self.set(insert_pos, elem); } - /// Return the total number of bits in this vector + /// Returns the total number of bits in this vector #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.nbits } @@ -1695,7 +1695,7 @@ impl BitSet { self.other_op(other, |w1, w2| w1 ^ w2); } - /// Return the number of set bits in this set. + /// Returns the number of set bits in this set. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index e704a956492..413100039a2 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1339,7 +1339,7 @@ impl BTreeMap { Values { inner: self.iter().map(second) } } - /// Return the number of elements in the map. + /// Returns the number of elements in the map. /// /// # Examples /// @@ -1354,7 +1354,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.length } - /// Return true if the map contains no elements. + /// Returns true if the map contains no elements. /// /// # Examples /// diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 840110b5b27..1abd56fd145 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -284,7 +284,7 @@ impl BTreeSet { Union{a: self.iter().peekable(), b: other.iter().peekable()} } - /// Return the number of elements in the set + /// Returns the number of elements in the set. /// /// # Examples /// @@ -299,7 +299,7 @@ impl BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.map.len() } - /// Returns true if the set contains no elements + /// Returns true if the set contains no elements. /// /// # Examples /// diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 7658611d809..5179b04f882 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -40,6 +40,7 @@ #![feature(str_char)] #![feature(slice_patterns)] #![feature(debug_builders)] +#![feature(utf8_error)] #![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))] #![cfg_attr(test, allow(deprecated))] // rand diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index dbdb7956573..391439bcdf2 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/libcollections/slice.rs b/src/libcollections/slice.rs index 8622b8cd935..5be9739cb32 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -549,7 +549,7 @@ impl [T] { core_slice::SliceExt::binary_search_by(self, f) } - /// Return the number of elements in the slice + /// Returns the number of elements in the slice. /// /// # Example /// @@ -757,7 +757,7 @@ impl [T] { core_slice::SliceExt::get_unchecked_mut(self, index) } - /// Return an unsafe mutable pointer to the slice's buffer. + /// Returns an unsafe mutable pointer to the slice's buffer. /// /// The caller must ensure that the slice outlives the pointer this /// function returns, or else it will end up pointing to garbage. @@ -984,7 +984,7 @@ impl [T] { core_slice::SliceExt::ends_with(self, needle) } - /// Convert `self` into a vector without clones or allocation. + /// Converts `self` into a vector without clones or allocation. #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn into_vec(self: Box) -> Vec { diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 98f2933effc..e1da8b3b3bc 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1248,7 +1248,7 @@ impl str { core_str::StrExt::trim_right_matches(&self[..], pat) } - /// Check that `index`-th byte lies at the start and/or end of a + /// Checks that `index`-th byte lies at the start and/or end of a /// UTF-8 code point sequence. /// /// The start and end of the string (when `index == self.len()`) are @@ -1435,7 +1435,7 @@ impl str { core_str::StrExt::char_at_reverse(&self[..], i) } - /// Convert `self` to a byte slice. + /// Converts `self` to a byte slice. /// /// # Examples /// @@ -1591,7 +1591,7 @@ impl str { core_str::StrExt::subslice_offset(&self[..], inner) } - /// Return an unsafe pointer to the `&str`'s buffer. + /// Returns an unsafe pointer to the `&str`'s buffer. /// /// The caller must ensure that the string outlives this pointer, and /// that it is not @@ -1609,7 +1609,7 @@ impl str { core_str::StrExt::as_ptr(&self[..]) } - /// Return an iterator of `u16` over the string encoded as UTF-16. + /// Returns an iterator of `u16` over the string encoded as UTF-16. #[unstable(feature = "collections", reason = "this functionality may only be provided by libunicode")] pub fn utf16_units(&self) -> Utf16Units { diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 441d0f2c5df..51ce5564c49 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -132,7 +132,7 @@ impl String { /// /// let invalid_vec = vec![240, 144, 128]; /// let s = String::from_utf8(invalid_vec).err().unwrap(); - /// assert_eq!(s.utf8_error(), Utf8Error::TooShort); + /// let err = s.utf8_error(); /// assert_eq!(s.into_bytes(), [240, 144, 128]); /// ``` #[inline] @@ -156,14 +156,10 @@ impl String { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str> { - let mut i = 0; + let mut i; match str::from_utf8(v) { Ok(s) => return Cow::Borrowed(s), - Err(e) => { - if let Utf8Error::InvalidByte(firstbad) = e { - i = firstbad; - } - } + Err(e) => i = e.valid_up_to(), } const TAG_CONT_U8: u8 = 128; @@ -188,9 +184,9 @@ impl String { }; } - // subseqidx is the index of the first byte of the subsequence we're looking at. - // It's used to copy a bunch of contiguous good codepoints at once instead of copying - // them one by one. + // subseqidx is the index of the first byte of the subsequence we're + // looking at. It's used to copy a bunch of contiguous good codepoints + // at once instead of copying them one by one. let mut subseqidx = i; while i < total { @@ -347,7 +343,7 @@ impl String { String { vec: bytes } } - /// Return the underlying byte buffer, encoded as UTF-8. + /// Returns the underlying byte buffer, encoded as UTF-8. /// /// # Examples /// @@ -363,7 +359,7 @@ impl String { self.vec } - /// Extract a string slice containing the entire string. + /// Extracts a string slice containing the entire string. #[inline] #[unstable(feature = "convert", reason = "waiting on RFC revision")] @@ -607,7 +603,7 @@ impl String { ch } - /// Insert a character into the string buffer at byte position `idx`. + /// Inserts a character into the string buffer at byte position `idx`. /// /// # Warning /// @@ -662,7 +658,7 @@ impl String { &mut self.vec } - /// Return the number of bytes in this string. + /// Returns the number of bytes in this string. /// /// # Examples /// @@ -705,12 +701,12 @@ impl String { } impl FromUtf8Error { - /// Consume this error, returning the bytes that were attempted to make a + /// Consumes this error, returning the bytes that were attempted to make a /// `String` with. #[stable(feature = "rust1", since = "1.0.0")] pub fn into_bytes(self) -> Vec { self.bytes } - /// Access the underlying UTF8-error that was the cause of this error. + /// Accesss the underlying UTF8-error that was the cause of this error. #[stable(feature = "rust1", since = "1.0.0")] pub fn utf8_error(&self) -> Utf8Error { self.error } } @@ -959,7 +955,7 @@ impl<'a> Deref for DerefString<'a> { } } -/// Convert a string slice to a wrapper type providing a `&String` reference. +/// Converts a string slice to a wrapper type providing a `&String` reference. /// /// # Examples /// diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 240a55181de..4fa91a6a16a 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -393,7 +393,7 @@ impl Vec { } } - /// Convert the vector into Box<[T]>. + /// Converts the vector into Box<[T]>. /// /// Note that this will drop any excess capacity. Calling this and /// converting back to a vector with `into_vec()` is equivalent to calling @@ -434,7 +434,7 @@ impl Vec { } } - /// Extract a slice containing the entire vector. + /// Extracts a slice containing the entire vector. #[inline] #[unstable(feature = "convert", reason = "waiting on RFC revision")] @@ -1936,7 +1936,7 @@ impl<'a, T> Drop for DerefVec<'a, T> { } } -/// Convert a slice to a wrapper type providing a `&Vec` reference. +/// Converts a slice to a wrapper type providing a `&Vec` reference. #[unstable(feature = "collections")] pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> { unsafe { diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 49b0c229215..a66cde81c8b 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -481,7 +481,7 @@ impl VecDeque { } } - /// Shorten a ringbuf, dropping excess elements from the back. + /// Shortens a ringbuf, dropping excess elements from the back. /// /// If `len` is greater than the ringbuf's current length, this has no /// effect. diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 3d9d8cf51ec..cb86e4ab38d 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -452,7 +452,7 @@ impl VecMap { Drain { iter: self.v.drain().enumerate().filter_map(filter) } } - /// Return the number of elements in the map. + /// Returns the number of elements in the map. /// /// # Examples /// @@ -470,7 +470,7 @@ impl VecMap { self.v.iter().filter(|elt| elt.is_some()).count() } - /// Return true if the map contains no elements. + /// Returns true if the map contains no elements. /// /// # Examples /// diff --git a/src/libcollectionstest/bench.rs b/src/libcollectionstest/bench.rs index 8f2e71b666c..4e150d4a222 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 10c688c3b66..d020f551dd5 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 de3c0586ab7..3cddaef0791 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 10d69c9f5ec..a29968ae8a2 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 5b0aceb76d1..e1c4e05e192 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/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 15f15900e78..cacafab4e3c 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -1502,7 +1502,7 @@ fn test_str_from_utf8() { assert_eq!(from_utf8(xs), Ok("ศไทย中华Việt Nam")); let xs = b"hello\xFF"; - assert_eq!(from_utf8(xs), Err(Utf8Error::TooShort)); + assert!(from_utf8(xs).is_err()); } #[test] diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 5d6aa8ac0dc..3184f842e9a 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -45,7 +45,6 @@ fn test_from_utf8() { let xs = b"hello\xFF".to_vec(); let err = String::from_utf8(xs).err().unwrap(); - assert_eq!(err.utf8_error(), Utf8Error::TooShort); assert_eq!(err.into_bytes(), b"hello\xff".to_vec()); } diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 7025c76d92c..85b8accadf3 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -91,7 +91,7 @@ use marker::{Reflect, Sized}; /// [mod]: index.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Any: Reflect + 'static { - /// Get the `TypeId` of `self` + /// Gets the `TypeId` of `self`. #[unstable(feature = "core", reason = "this method will likely be replaced by an associated static")] fn get_type_id(&self) -> TypeId; diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index ed35e095492..02f9ee506f9 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -78,12 +78,20 @@ use intrinsics; use cell::UnsafeCell; use marker::PhantomData; +use default::Default; + /// A boolean type which can be safely shared between threads. #[stable(feature = "rust1", since = "1.0.0")] pub struct AtomicBool { v: UnsafeCell, } +impl Default for AtomicBool { + fn default() -> AtomicBool { + ATOMIC_BOOL_INIT + } +} + unsafe impl Sync for AtomicBool {} /// A signed integer type which can be safely shared between threads. @@ -92,6 +100,12 @@ pub struct AtomicIsize { v: UnsafeCell, } +impl Default for AtomicIsize { + fn default() -> AtomicIsize { + ATOMIC_ISIZE_INIT + } +} + unsafe impl Sync for AtomicIsize {} /// An unsigned integer type which can be safely shared between threads. @@ -100,6 +114,12 @@ pub struct AtomicUsize { v: UnsafeCell, } +impl Default for AtomicUsize { + fn default() -> AtomicUsize { + ATOMIC_USIZE_INIT + } +} + unsafe impl Sync for AtomicUsize {} /// A raw pointer type which can be safely shared between threads. diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 76e09eedbdf..df0de234b9a 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -211,7 +211,7 @@ impl Cell { } } - /// Get a reference to the underlying `UnsafeCell`. + /// Gets a reference to the underlying `UnsafeCell`. /// /// # Unsafety /// @@ -436,7 +436,7 @@ impl RefCell { } } - /// Get a reference to the underlying `UnsafeCell`. + /// Gets a reference to the underlying `UnsafeCell`. /// /// This can be used to circumvent `RefCell`'s safety checks. /// @@ -537,7 +537,7 @@ impl<'b, T> Deref for Ref<'b, T> { } } -/// Copy a `Ref`. +/// Copies a `Ref`. /// /// The `RefCell` is already immutably borrowed, so this cannot fail. /// @@ -647,7 +647,7 @@ pub struct UnsafeCell { impl !Sync for UnsafeCell {} impl UnsafeCell { - /// Construct a new instance of `UnsafeCell` which will wrap the specified + /// Constructs a new instance of `UnsafeCell` which will wrap the specified /// value. /// /// All access to the inner value through methods is `unsafe`, and it is highly discouraged to @@ -685,7 +685,7 @@ impl UnsafeCell { &self.value as *const T as *mut T } - /// Unwraps the value + /// Unwraps the value. /// /// # Unsafety /// diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 311901b43d4..f11c01507dc 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -38,7 +38,7 @@ pub trait Clone : Sized { #[stable(feature = "rust1", since = "1.0.0")] fn clone(&self) -> Self; - /// Perform copy-assignment from `source`. + /// Performs copy-assignment from `source`. /// /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality, /// but can be overridden to reuse the resources of `a` to avoid unnecessary @@ -52,7 +52,7 @@ pub trait Clone : Sized { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> Clone for &'a T { - /// Return a shallow copy of the reference. + /// Returns a shallow copy of the reference. #[inline] fn clone(&self) -> &'a T { *self } } @@ -61,7 +61,7 @@ macro_rules! clone_impl { ($t:ty) => { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for $t { - /// Return a deep copy of the value. + /// Returns a deep copy of the value. #[inline] fn clone(&self) -> $t { *self } } @@ -92,28 +92,28 @@ macro_rules! extern_fn_clone { #[unstable(feature = "core", reason = "this may not be sufficient for fns with region parameters")] impl<$($A,)* ReturnType> Clone for extern "Rust" fn($($A),*) -> ReturnType { - /// Return a copy of a function pointer + /// Returns a copy of a function pointer. #[inline] fn clone(&self) -> extern "Rust" fn($($A),*) -> ReturnType { *self } } #[unstable(feature = "core", reason = "brand new")] impl<$($A,)* ReturnType> Clone for extern "C" fn($($A),*) -> ReturnType { - /// Return a copy of a function pointer + /// Returns a copy of a function pointer. #[inline] fn clone(&self) -> extern "C" fn($($A),*) -> ReturnType { *self } } #[unstable(feature = "core", reason = "brand new")] impl<$($A,)* ReturnType> Clone for unsafe extern "Rust" fn($($A),*) -> ReturnType { - /// Return a copy of a function pointer + /// Returns a copy of a function pointer. #[inline] fn clone(&self) -> unsafe extern "Rust" fn($($A),*) -> ReturnType { *self } } #[unstable(feature = "core", reason = "brand new")] impl<$($A,)* ReturnType> Clone for unsafe extern "C" fn($($A),*) -> ReturnType { - /// Return a copy of a function pointer + /// Returns a copy of a function pointer. #[inline] fn clone(&self) -> unsafe extern "C" fn($($A),*) -> ReturnType { *self } } diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 5f19bc5be98..72c25c68040 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,14 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(missing_docs)] - pub use self::ExponentFormat::*; pub use self::SignificantDigits::*; -pub use self::SignFormat::*; -use char; -use char::CharExt; +use char::{self, CharExt}; use fmt; use iter::Iterator; use num::{cast, Float, ToPrimitive}; @@ -46,50 +42,29 @@ pub enum SignificantDigits { DigExact(usize) } -/// How to emit the sign of a number. -pub enum SignFormat { - /// `-` will be printed for negative values, but no sign will be emitted - /// for positive numbers. - SignNeg -} - -const DIGIT_E_RADIX: u32 = ('e' as u32) - ('a' as u32) + 11; - -/// Converts a number to its string representation as a byte vector. -/// This is meant to be a common base implementation for all numeric string -/// conversion functions like `to_string()` or `to_str_radix()`. +/// Converts a float number to its string representation. +/// This is meant to be a common base implementation for various formatting styles. +/// The number is assumed to be non-negative, callers use `Formatter::pad_integral` +/// to add the right sign, if any. /// /// # Arguments /// -/// - `num` - The number to convert. Accepts any number that +/// - `num` - The number to convert (non-negative). Accepts any number that /// implements the numeric traits. -/// - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation -/// is used, then this base is only used for the significand. The exponent -/// itself always printed using a base of 10. -/// - `negative_zero` - Whether to treat the special value `-0` as -/// `-0` or as `+0`. -/// - `sign` - How to emit the sign. See `SignFormat`. /// - `digits` - The amount of digits to use for emitting the fractional /// part, if any. See `SignificantDigits`. /// - `exp_format` - Whether or not to use the exponential (scientific) notation. /// See `ExponentFormat`. /// - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if /// exponential notation is desired. -/// - `f` - A closure to invoke with the bytes representing the +/// - `f` - A closure to invoke with the string representing the /// float. /// /// # Panics /// -/// - Panics if `radix` < 2 or `radix` > 36. -/// - Panics if `radix` > 14 and `exp_format` is `ExpDec` due to conflict -/// between digit and exponent sign `'e'`. -/// - Panics if `radix` > 25 and `exp_format` is `ExpBin` due to conflict -/// between digit and exponent sign `'p'`. +/// - Panics if `num` is negative. pub fn float_to_str_bytes_common( num: T, - radix: u32, - negative_zero: bool, - sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool, @@ -97,16 +72,12 @@ pub fn float_to_str_bytes_common( ) -> U where F: FnOnce(&str) -> U, { - assert!(2 <= radix && radix <= 36); - match exp_format { - ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' - => panic!("float_to_str_bytes_common: radix {} incompatible with \ - use of 'e' as decimal exponent", radix), - _ => () - } - let _0: T = Float::zero(); let _1: T = Float::one(); + let radix: u32 = 10; + let radix_f: T = cast(radix).unwrap(); + + assert!(num.is_nan() || num >= _0, "float_to_str_bytes_common: number is negative"); match num.classify() { Fp::Nan => return f("NaN"), @@ -119,41 +90,28 @@ pub fn float_to_str_bytes_common( _ => {} } - let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity()); - // For an f64 the exponent is in the range of [-1022, 1023] for base 2, so - // we may have up to that many digits. Give ourselves some extra wiggle room - // otherwise as well. - let mut buf = [0; 1536]; + // For an f64 the (decimal) exponent is roughly in the range of [-307, 308], so + // we may have up to that many digits. We err on the side of caution and + // add 50% extra wiggle room. + let mut buf = [0; 462]; let mut end = 0; - let radix_gen: T = cast(radix as isize).unwrap(); let (num, exp) = match exp_format { - ExpNone => (num, 0), - ExpDec if num == _0 => (num, 0), - ExpDec => { - let (exp, exp_base) = match exp_format { - ExpDec => (num.abs().log10().floor(), cast::(10.0f64).unwrap()), - ExpNone => panic!("unreachable"), - }; - - (num / exp_base.powf(exp), cast::(exp).unwrap()) + ExpDec if num != _0 => { + let exp = num.log10().floor(); + (num / radix_f.powf(exp), cast::(exp).unwrap()) } + _ => (num, 0) }; // First emit the non-fractional part, looping at least once to make // sure at least a `0` gets emitted. let mut deccum = num.trunc(); loop { - // Calculate the absolute value of each digit instead of only - // doing it once for the whole number because a - // representable negative number doesn't necessary have an - // representable additive inverse of the same type - // (See twos complement). But we assume that for the - // numbers [-35 .. 0] we always have [0 .. 35]. - let current_digit = (deccum % radix_gen).abs(); + let current_digit = deccum % radix_f; // Decrease the deccumulator one digit at a time - deccum = deccum / radix_gen; + deccum = deccum / radix_f; deccum = deccum.trunc(); let c = char::from_digit(current_digit.to_isize().unwrap() as u32, radix); @@ -170,15 +128,6 @@ pub fn float_to_str_bytes_common( DigExact(count) => (true, count + 1, true) }; - // Decide what sign to put in front - match sign { - SignNeg if neg => { - buf[end] = b'-'; - end += 1; - } - _ => () - } - buf[..end].reverse(); // Remember start of the fractional digits. @@ -205,14 +154,11 @@ pub fn float_to_str_bytes_common( ) ) { // Shift first fractional digit into the integer part - deccum = deccum * radix_gen; + deccum = deccum * radix_f; - // Calculate the absolute value of each digit. - // See note in first loop. - let current_digit = deccum.trunc().abs(); + let current_digit = deccum.trunc(); - let c = char::from_digit(current_digit.to_isize().unwrap() as u32, - radix); + let c = char::from_digit(current_digit.to_isize().unwrap() as u32, radix); buf[end] = c.unwrap() as u8; end += 1; @@ -301,12 +247,8 @@ pub fn float_to_str_bytes_common( match exp_format { ExpNone => {}, - _ => { - buf[end] = match exp_format { - ExpDec if exp_upper => 'E', - ExpDec if !exp_upper => 'e', - _ => panic!("unreachable"), - } as u8; + ExpDec => { + buf[end] = if exp_upper { b'E' } else { b'e' }; end += 1; struct Filler<'a> { @@ -324,11 +266,7 @@ pub fn float_to_str_bytes_common( } let mut filler = Filler { buf: &mut buf, end: &mut end }; - match sign { - SignNeg => { - let _ = fmt::write(&mut filler, format_args!("{:-}", exp)); - } - } + let _ = fmt::write(&mut filler, format_args!("{:-}", exp)); } } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 1c70f9941f7..80c661b260c 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -18,6 +18,7 @@ use clone::Clone; use iter::Iterator; use marker::{Copy, PhantomData, Sized}; use mem; +use num::Float; use option::Option; use option::Option::{Some, None}; use result::Result::Ok; @@ -910,33 +911,38 @@ impl<'a, T> Pointer for &'a mut T { } } +// Common code of floating point Debug and Display. +fn float_to_str_common(num: &T, precision: Option, post: F) -> Result + where F : FnOnce(&str) -> Result { + let digits = match precision { + Some(i) => float::DigExact(i), + None => float::DigMax(6), + }; + float::float_to_str_bytes_common(num.abs(), + digits, + float::ExpNone, + false, + post) +} + macro_rules! floating { ($ty:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - Display::fmt(self, fmt) + float_to_str_common(self, fmt.precision, |absolute| { + // is_positive() counts -0.0 as negative + fmt.pad_integral(self.is_nan() || self.is_positive(), "", absolute) + }) } } #[stable(feature = "rust1", since = "1.0.0")] impl Display for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - use num::Float; - - let digits = match fmt.precision { - Some(i) => float::DigExact(i), - None => float::DigMax(6), - }; - float::float_to_str_bytes_common(self.abs(), - 10, - true, - float::SignNeg, - digits, - float::ExpNone, - false, - |bytes| { - fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes) + float_to_str_common(self, fmt.precision, |absolute| { + // simple comparison counts -0.0 as positive + fmt.pad_integral(self.is_nan() || *self >= 0.0, "", absolute) }) } } @@ -951,9 +957,6 @@ macro_rules! floating { ($ty:ident) => { None => float::DigMax(6), }; float::float_to_str_bytes_common(self.abs(), - 10, - true, - float::SignNeg, digits, float::ExpDec, false, @@ -973,9 +976,6 @@ macro_rules! floating { ($ty:ident) => { None => float::DigMax(6), }; float::float_to_str_bytes_common(self.abs(), - 10, - true, - float::SignNeg, digits, float::ExpDec, true, diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 80f506ebc06..8ed89adec5b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -139,16 +139,16 @@ extern "rust-intrinsic" { pub fn atomic_fence_rel(); pub fn atomic_fence_acqrel(); - /// Abort the execution of the process. + /// Aborts the execution of the process. pub fn abort() -> !; - /// Tell LLVM that this point in the code is not reachable, + /// Tells LLVM that this point in the code is not reachable, /// enabling further optimizations. /// /// NB: This is very different from the `unreachable!()` macro! pub fn unreachable() -> !; - /// Inform the optimizer that a condition is always true. + /// Informs the optimizer that a condition is always true. /// If the condition is false, the behavior is undefined. /// /// No code is generated for this intrinsic, but the optimizer will try @@ -158,7 +158,7 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. pub fn assume(b: bool); - /// Execute a breakpoint trap, for inspection by a debugger. + /// Executes a breakpoint trap, for inspection by a debugger. pub fn breakpoint(); /// The size of a type in bytes. @@ -170,7 +170,7 @@ extern "rust-intrinsic" { /// elements. pub fn size_of() -> usize; - /// Move a value to an uninitialized memory location. + /// Moves a value to an uninitialized memory location. /// /// Drop glue is not run on the destination. pub fn move_val_init(dst: &mut T, src: T); @@ -186,7 +186,7 @@ extern "rust-intrinsic" { /// crate it is invoked in. pub fn type_id() -> u64; - /// Create a value initialized to so that its drop flag, + /// Creates a value initialized to so that its drop flag, /// if any, says that it has been dropped. /// /// `init_dropped` is unsafe because it returns a datum with all @@ -199,7 +199,7 @@ extern "rust-intrinsic" { /// intrinsic). pub fn init_dropped() -> T; - /// Create a value initialized to zero. + /// Creates a value initialized to zero. /// /// `init` is unsafe because it returns a zeroed-out datum, /// which is unsafe unless T is `Copy`. Also, even if T is @@ -207,7 +207,7 @@ extern "rust-intrinsic" { /// state for the type in question. pub fn init() -> T; - /// Create an uninitialized value. + /// Creates an uninitialized value. /// /// `uninit` is unsafe because there is no guarantee of what its /// contents are. In particular its drop-flag may be set to any @@ -216,7 +216,7 @@ extern "rust-intrinsic" { /// initialize memory previous set to the result of `uninit`. pub fn uninit() -> T; - /// Move a value out of scope without running drop glue. + /// Moves a value out of scope without running drop glue. /// /// `forget` is unsafe because the caller is responsible for /// ensuring the argument is deallocated already. diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index c756d3cb9c2..4a0706906ee 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -91,7 +91,7 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] type Item; - /// Advance the iterator and return the next value. Return `None` when the + /// Advances the iterator and returns the next value. Returns `None` when the /// end is reached. #[stable(feature = "rust1", since = "1.0.0")] fn next(&mut self) -> Option; @@ -670,7 +670,7 @@ pub trait Iterator { None } - /// Return the index of the first element satisfying the specified predicate + /// Returns the index of the first element satisfying the specified predicate /// /// Does not consume the iterator past the first found element. /// @@ -698,7 +698,7 @@ pub trait Iterator { None } - /// Return the index of the last element satisfying the specified predicate + /// Returns the index of the last element satisfying the specified predicate /// /// If no element matches, None is returned. /// @@ -853,7 +853,7 @@ pub trait Iterator { MinMax(min, max) } - /// Return the element that gives the maximum value from the + /// Returns the element that gives the maximum value from the /// specified function. /// /// Returns the rightmost element if the comparison determines two elements @@ -882,7 +882,7 @@ pub trait Iterator { .map(|(_, x)| x) } - /// Return the element that gives the minimum value from the + /// Returns the element that gives the minimum value from the /// specified function. /// /// Returns the leftmost element if the comparison determines two elements @@ -1099,7 +1099,7 @@ impl<'a, I: Iterator + ?Sized> Iterator for &'a mut I { #[rustc_on_unimplemented="a collection of type `{Self}` cannot be \ built from an iterator over elements of type `{A}`"] pub trait FromIterator { - /// Build a container with elements from something iterable. + /// Builds a container with elements from something iterable. /// /// # Examples /// @@ -1158,7 +1158,7 @@ impl IntoIterator for I { /// A type growable from an `Iterator` implementation #[stable(feature = "rust1", since = "1.0.0")] pub trait Extend { - /// Extend a container with the elements yielded by an arbitrary iterator + /// Extends a container with the elements yielded by an arbitrary iterator #[stable(feature = "rust1", since = "1.0.0")] fn extend>(&mut self, iterable: T); } @@ -1170,7 +1170,7 @@ pub trait Extend { /// independently of each other. #[stable(feature = "rust1", since = "1.0.0")] pub trait DoubleEndedIterator: Iterator { - /// Yield an element from the end of the range, returning `None` if the + /// Yields an element from the end of the range, returning `None` if the /// range is empty. #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; @@ -1191,11 +1191,11 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { reason = "not widely used, may be better decomposed into Index \ and ExactSizeIterator")] pub trait RandomAccessIterator: Iterator { - /// Return the number of indexable elements. At most `std::usize::MAX` + /// Returns the number of indexable elements. At most `std::usize::MAX` /// elements are indexable, even if the iterator represents a longer range. fn indexable(&self) -> usize; - /// Return an element at an index, or `None` if the index is out of bounds + /// Returns an element at an index, or `None` if the index is out of bounds fn idx(&mut self, index: usize) -> Option; } @@ -1210,7 +1210,7 @@ pub trait RandomAccessIterator: Iterator { pub trait ExactSizeIterator: Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] - /// Return the exact length of the iterator. + /// Returns the exact length of the iterator. fn len(&self) -> usize { let (lower, upper) = self.size_hint(); // Note: This assertion is overly defensive, but it checks the invariant @@ -1856,7 +1856,7 @@ impl ExactSizeIterator for Peekable {} #[stable(feature = "rust1", since = "1.0.0")] impl Peekable { - /// Return a reference to the next element of the iterator with out + /// Returns a reference to the next element of the iterator with out /// advancing it, or None if the iterator is exhausted. #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1870,7 +1870,7 @@ impl Peekable { } } - /// Check whether peekable iterator is empty or not. + /// Checks whether peekable iterator is empty or not. #[inline] pub fn is_empty(&mut self) -> bool { self.peek().is_none() @@ -2401,12 +2401,12 @@ pub trait Step: PartialOrd { /// Steps `self` if possible. fn step(&self, by: &Self) -> Option; - /// The number of steps between two step objects. + /// Returns the number of steps between two step objects. /// /// `start` should always be less than `end`, so the result should never /// be negative. /// - /// Return `None` if it is not possible to calculate steps_between + /// Returns `None` if it is not possible to calculate steps_between /// without overflow. fn steps_between(start: &Self, end: &Self, by: &Self) -> Option; } @@ -2549,7 +2549,7 @@ pub struct RangeInclusive { done: bool, } -/// Return an iterator over the range [start, stop] +/// Returns an iterator over the range [start, stop]. #[inline] #[unstable(feature = "core", reason = "likely to be replaced by range notation and adapters")] @@ -2657,7 +2657,7 @@ pub struct RangeStepInclusive { done: bool, } -/// Return an iterator over the range [start, stop] by `step`. +/// Returns an iterator over the range [start, stop] by `step`. /// /// It handles overflow by stopping. /// @@ -2827,7 +2827,7 @@ type IterateState = (F, Option, bool); #[unstable(feature = "core")] pub type Iterate = Unfold, fn(&mut IterateState) -> Option>; -/// Create a new iterator that produces an infinite sequence of +/// Creates a new iterator that produces an infinite sequence of /// repeated applications of the given function `f`. #[unstable(feature = "core")] pub fn iterate(seed: T, f: F) -> Iterate where @@ -2853,7 +2853,7 @@ pub fn iterate(seed: T, f: F) -> Iterate where Unfold::new((f, Some(seed), true), next) } -/// Create a new iterator that endlessly repeats the element `elt`. +/// Creates a new iterator that endlessly repeats the element `elt`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn repeat(elt: T) -> Repeat { @@ -2940,7 +2940,7 @@ pub mod order { } } - /// Compare `a` and `b` for nonequality (Using partial equality, `PartialEq`) + /// Compares `a` and `b` for nonequality (Using partial equality, `PartialEq`) pub fn ne(mut a: L, mut b: R) -> bool where L::Item: PartialEq, { @@ -2953,7 +2953,7 @@ pub mod order { } } - /// Return `a` < `b` lexicographically (Using partial order, `PartialOrd`) + /// Returns `a` < `b` lexicographically (Using partial order, `PartialOrd`) pub fn lt(mut a: L, mut b: R) -> bool where L::Item: PartialOrd, { @@ -2967,7 +2967,7 @@ pub mod order { } } - /// Return `a` <= `b` lexicographically (Using partial order, `PartialOrd`) + /// Returns `a` <= `b` lexicographically (Using partial order, `PartialOrd`) pub fn le(mut a: L, mut b: R) -> bool where L::Item: PartialOrd, { @@ -2981,7 +2981,7 @@ pub mod order { } } - /// Return `a` > `b` lexicographically (Using partial order, `PartialOrd`) + /// Returns `a` > `b` lexicographically (Using partial order, `PartialOrd`) pub fn gt(mut a: L, mut b: R) -> bool where L::Item: PartialOrd, { @@ -2995,7 +2995,7 @@ pub mod order { } } - /// Return `a` >= `b` lexicographically (Using partial order, `PartialOrd`) + /// Returns `a` >= `b` lexicographically (Using partial order, `PartialOrd`) pub fn ge(mut a: L, mut b: R) -> bool where L::Item: PartialOrd, { diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 249beb6295c..c4128e79765 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -134,7 +134,7 @@ pub fn align_of_val(_val: &T) -> usize { align_of::() } -/// Create a value initialized to zero. +/// Creates a value initialized to zero. /// /// This function is similar to allocating space for a local variable and zeroing it out (an unsafe /// operation). @@ -158,7 +158,7 @@ pub unsafe fn zeroed() -> T { intrinsics::init() } -/// Create a value initialized to an unspecified series of bytes. +/// Creates a value initialized to an unspecified series of bytes. /// /// The byte sequence usually indicates that the value at the memory /// in question has been dropped. Thus, *if* T carries a drop flag, @@ -179,7 +179,7 @@ pub unsafe fn dropped() -> T { dropped_impl() } -/// Create an uninitialized value. +/// Creates an uninitialized value. /// /// Care must be taken when using this function, if the type `T` has a destructor and the value /// falls out of scope (due to unwinding or returning) before being initialized, then the @@ -234,7 +234,7 @@ pub fn swap(x: &mut T, y: &mut T) { } } -/// Replace the value at a mutable location with a new one, returning the old value, without +/// Replaces the value at a mutable location with a new one, returning the old value, without /// deinitialising or copying either one. /// /// This is primarily used for transferring and swapping ownership of a value in a mutable diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 3df4d00f60c..db2d1b2f1fd 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -38,7 +38,7 @@ unsafe impl Zeroable for u64 {} pub struct NonZero(T); impl NonZero { - /// Create an instance of NonZero with the provided value. + /// Creates an instance of NonZero with the provided value. /// You must indeed ensure that the value is actually "non-zero". #[inline(always)] pub unsafe fn new(inner: T) -> NonZero { diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 3fd179cf86f..9b1a384a0d0 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -268,7 +268,7 @@ pub trait Int #[stable(feature = "rust1", since = "1.0.0")] fn swap_bytes(self) -> Self; - /// Convert an integer from big endian to the target's endianness. + /// Converts an integer from big endian to the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are swapped. /// @@ -291,7 +291,7 @@ pub trait Int if cfg!(target_endian = "big") { x } else { x.swap_bytes() } } - /// Convert an integer from little endian to the target's endianness. + /// Converts an integer from little endian to the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are swapped. /// @@ -314,7 +314,7 @@ pub trait Int if cfg!(target_endian = "little") { x } else { x.swap_bytes() } } - /// Convert `self` to big endian from the target's endianness. + /// Converts `self` to big endian from the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are swapped. /// @@ -337,7 +337,7 @@ pub trait Int if cfg!(target_endian = "big") { self } else { self.swap_bytes() } } - /// Convert `self` to little endian from the target's endianness. + /// Converts `self` to little endian from the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are swapped. /// @@ -845,7 +845,7 @@ macro_rules! int_impl { let min: $T = Int::min_value(); !min } - /// Convert a string slice in a given base to an integer. + /// Converts a string slice in a given base to an integer. /// /// Leading and trailing whitespace represent an error. /// @@ -995,7 +995,7 @@ macro_rules! int_impl { (self as $UnsignedT).swap_bytes() as $T } - /// Convert an integer from big endian to the target's endianness. + /// Converts an integer from big endian to the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are /// swapped. @@ -1019,7 +1019,7 @@ macro_rules! int_impl { if cfg!(target_endian = "big") { x } else { x.swap_bytes() } } - /// Convert an integer from little endian to the target's endianness. + /// Converts an integer from little endian to the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are /// swapped. @@ -1043,7 +1043,7 @@ macro_rules! int_impl { if cfg!(target_endian = "little") { x } else { x.swap_bytes() } } - /// Convert `self` to big endian from the target's endianness. + /// Converts `self` to big endian from the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are /// swapped. @@ -1067,7 +1067,7 @@ macro_rules! int_impl { if cfg!(target_endian = "big") { self } else { self.swap_bytes() } } - /// Convert `self` to little endian from the target's endianness. + /// Converts `self` to little endian from the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are /// swapped. @@ -1361,7 +1361,7 @@ macro_rules! uint_impl { #[stable(feature = "rust1", since = "1.0.0")] pub fn max_value() -> $T { !0 } - /// Convert a string slice in a given base to an integer. + /// Converts a string slice in a given base to an integer. /// /// Leading and trailing whitespace represent an error. /// @@ -1517,7 +1517,7 @@ macro_rules! uint_impl { unsafe { $bswap(self as $ActualT) as $T } } - /// Convert an integer from big endian to the target's endianness. + /// Converts an integer from big endian to the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are /// swapped. @@ -1541,7 +1541,7 @@ macro_rules! uint_impl { if cfg!(target_endian = "big") { x } else { x.swap_bytes() } } - /// Convert an integer from little endian to the target's endianness. + /// Converts an integer from little endian to the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are /// swapped. @@ -1565,7 +1565,7 @@ macro_rules! uint_impl { if cfg!(target_endian = "little") { x } else { x.swap_bytes() } } - /// Convert `self` to big endian from the target's endianness. + /// Converts `self` to big endian from the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are /// swapped. @@ -1589,7 +1589,7 @@ macro_rules! uint_impl { if cfg!(target_endian = "big") { self } else { self.swap_bytes() } } - /// Convert `self` to little endian from the target's endianness. + /// Converts `self` to little endian from the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are /// swapped. @@ -2183,7 +2183,7 @@ impl_to_primitive_float! { f64 } /// A generic trait for converting a number to a value. #[unstable(feature = "core", reason = "trait is likely to be removed")] pub trait FromPrimitive : ::marker::Sized { - /// Convert an `isize` to return an optional value of this type. If the + /// Converts an `isize` to return an optional value of this type. If the /// value cannot be represented by this value, the `None` is returned. #[inline] #[unstable(feature = "core")] @@ -2192,39 +2192,39 @@ pub trait FromPrimitive : ::marker::Sized { FromPrimitive::from_i64(n as i64) } - /// Convert an `isize` to return an optional value of this type. If the + /// Converts an `isize` to return an optional value of this type. If the /// value cannot be represented by this value, the `None` is returned. #[inline] fn from_isize(n: isize) -> Option { FromPrimitive::from_i64(n as i64) } - /// Convert an `i8` to return an optional value of this type. If the + /// Converts an `i8` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_i8(n: i8) -> Option { FromPrimitive::from_i64(n as i64) } - /// Convert an `i16` to return an optional value of this type. If the + /// Converts an `i16` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_i16(n: i16) -> Option { FromPrimitive::from_i64(n as i64) } - /// Convert an `i32` to return an optional value of this type. If the + /// Converts an `i32` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_i32(n: i32) -> Option { FromPrimitive::from_i64(n as i64) } - /// Convert an `i64` to return an optional value of this type. If the + /// Converts an `i64` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. fn from_i64(n: i64) -> Option; - /// Convert an `usize` to return an optional value of this type. If the + /// Converts an `usize` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] #[unstable(feature = "core")] @@ -2233,46 +2233,46 @@ pub trait FromPrimitive : ::marker::Sized { FromPrimitive::from_u64(n as u64) } - /// Convert a `usize` to return an optional value of this type. If the + /// Converts a `usize` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_usize(n: usize) -> Option { FromPrimitive::from_u64(n as u64) } - /// Convert an `u8` to return an optional value of this type. If the + /// Converts an `u8` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_u8(n: u8) -> Option { FromPrimitive::from_u64(n as u64) } - /// Convert an `u16` to return an optional value of this type. If the + /// Converts an `u16` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_u16(n: u16) -> Option { FromPrimitive::from_u64(n as u64) } - /// Convert an `u32` to return an optional value of this type. If the + /// Converts an `u32` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_u32(n: u32) -> Option { FromPrimitive::from_u64(n as u64) } - /// Convert an `u64` to return an optional value of this type. If the + /// Converts an `u64` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. fn from_u64(n: u64) -> Option; - /// Convert a `f32` to return an optional value of this type. If the + /// Converts a `f32` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_f32(n: f32) -> Option { FromPrimitive::from_f64(n as f64) } - /// Convert a `f64` to return an optional value of this type. If the + /// Converts a `f64` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_f64(n: f64) -> Option { @@ -2401,7 +2401,7 @@ impl_from_primitive! { u64, to_u64 } impl_from_primitive! { f32, to_f32 } impl_from_primitive! { f64, to_f64 } -/// Cast from one machine scalar to another. +/// Casts from one machine scalar to another. /// /// # Examples /// @@ -2583,16 +2583,16 @@ pub trait Float /// Returns the mantissa, exponent and sign as integers, respectively. fn integer_decode(self) -> (u64, i16, i8); - /// Return the largest integer less than or equal to a number. + /// Returns the largest integer less than or equal to a number. fn floor(self) -> Self; - /// Return the smallest integer greater than or equal to a number. + /// Returns the smallest integer greater than or equal to a number. fn ceil(self) -> Self; - /// Return the nearest integer to a number. Round half-way cases away from + /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. fn round(self) -> Self; - /// Return the integer part of a number. + /// Returns the integer part of a number. fn trunc(self) -> Self; - /// Return the fractional part of a number. + /// Returns the fractional part of a number. fn fract(self) -> Self; /// Computes the absolute value of `self`. Returns `Float::nan()` if the @@ -2615,21 +2615,21 @@ pub trait Float /// error. This produces a more accurate result with better performance than /// a separate multiplication operation followed by an add. fn mul_add(self, a: Self, b: Self) -> Self; - /// Take the reciprocal (inverse) of a number, `1/x`. + /// Takes the reciprocal (inverse) of a number, `1/x`. fn recip(self) -> Self; - /// Raise a number to an integer power. + /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` fn powi(self, n: i32) -> Self; - /// Raise a number to a floating point power. + /// Raises a number to a floating point power. fn powf(self, n: Self) -> Self; - /// Take the square root of a number. + /// Takes the square root of a number. /// /// Returns NaN if `self` is a negative number. fn sqrt(self) -> Self; - /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. + /// Takes the reciprocal (inverse) square root of a number, `1/sqrt(x)`. fn rsqrt(self) -> Self; /// Returns `e^(self)`, (the exponential function). @@ -2645,9 +2645,9 @@ pub trait Float /// Returns the base 10 logarithm of the number. fn log10(self) -> Self; - /// Convert radians to degrees. + /// Converts radians to degrees. fn to_degrees(self) -> Self; - /// Convert degrees to radians. + /// Converts degrees to radians. fn to_radians(self) -> Self; } @@ -2682,7 +2682,7 @@ macro_rules! from_str_radix_float_impl { impl FromStr for $T { type Err = ParseFloatError; - /// Convert a string in base 10 to a float. + /// Converts a string in base 10 to a float. /// Accepts an optional decimal exponent. /// /// This function accepts strings such as @@ -2719,7 +2719,7 @@ macro_rules! from_str_radix_float_impl { impl FromStrRadix for $T { type Err = ParseFloatError; - /// Convert a string in a given base to a float. + /// Converts a string in a given base to a float. /// /// Due to possible conflicts, this function does **not** accept /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 6db7c9bd99d..4c784a579da 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -223,7 +223,7 @@ impl Option { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Convert from `Option` to `Option<&T>` + /// Converts from `Option` to `Option<&T>` /// /// # Examples /// @@ -248,7 +248,7 @@ impl Option { } } - /// Convert from `Option` to `Option<&mut T>` + /// Converts from `Option` to `Option<&mut T>` /// /// # Examples /// @@ -269,7 +269,7 @@ impl Option { } } - /// Convert from `Option` to `&mut [T]` (without copying) + /// Converts from `Option` to `&mut [T]` (without copying) /// /// # Examples /// @@ -704,7 +704,7 @@ impl Option { mem::replace(self, None) } - /// Convert from `Option` to `&[T]` (without copying) + /// Converts from `Option` to `&[T]` (without copying) #[inline] #[unstable(feature = "as_slice", since = "unsure of the utility here")] pub fn as_slice<'a>(&'a self) -> &'a [T] { diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a622ef78a21..9a165a2e317 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -544,19 +544,19 @@ unsafe impl Send for Unique { } unsafe impl Sync for Unique { } impl Unique { - /// Create a new `Unique`. + /// Creates a new `Unique`. #[unstable(feature = "unique")] pub unsafe fn new(ptr: *mut T) -> Unique { Unique { pointer: NonZero::new(ptr), _marker: PhantomData } } - /// Dereference the content. + /// Dereferences the content. #[unstable(feature = "unique")] pub unsafe fn get(&self) -> &T { &**self.pointer } - /// Mutably dereference the content. + /// Mutably dereferences the content. #[unstable(feature = "unique")] pub unsafe fn get_mut(&mut self) -> &mut T { &mut ***self diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 67a5ab891f7..4c74f4646ac 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -69,7 +69,7 @@ //! let good_result: Result = good_result.and_then(|i| Ok(i == 11)); //! //! // Use `or_else` to handle the error. -//! let bad_result: Result = bad_result.or_else(|i| Ok(11)); +//! let bad_result: Result = bad_result.or_else(|i| Ok(i + 20)); //! //! // Consume the result and return the contents with `unwrap`. //! let final_awesome_result = good_result.unwrap(); @@ -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_line(&format!("age: {}", info.age)) { +//! if let Err(e) = file.write_all(format!("age: {}\n", info.age).as_bytes()) { //! return Err(e) //! } -//! file.write_line(&format!("rating: {}", info.rating)) +//! if let Err(e) = file.write_all(format!("rating: {}\n", info.rating).as_bytes()) { +//! return Err(e) +//! } +//! 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(()) //! } //! ``` @@ -311,7 +305,7 @@ impl Result { // Adapter for each variant ///////////////////////////////////////////////////////////////////////// - /// Convert from `Result` to `Option` + /// Converts from `Result` to `Option` /// /// Converts `self` into an `Option`, consuming `self`, /// and discarding the error, if any. @@ -334,7 +328,7 @@ impl Result { } } - /// Convert from `Result` to `Option` + /// Converts from `Result` to `Option` /// /// Converts `self` into an `Option`, consuming `self`, /// and discarding the success value, if any. @@ -361,7 +355,7 @@ impl Result { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Convert from `Result` to `Result<&T, &E>` + /// Converts from `Result` to `Result<&T, &E>` /// /// Produces a new `Result`, containing a reference /// into the original, leaving the original in place. @@ -382,7 +376,7 @@ impl Result { } } - /// Convert from `Result` to `Result<&mut T, &mut E>` + /// Converts from `Result` to `Result<&mut T, &mut E>` /// /// ``` /// fn mutate(r: &mut Result) { @@ -409,7 +403,7 @@ impl Result { } } - /// Convert from `Result` to `&[T]` (without copying) + /// Converts from `Result` to `&[T]` (without copying) #[inline] #[unstable(feature = "as_slice", since = "unsure of the utility here")] pub fn as_slice(&self) -> &[T] { @@ -423,7 +417,7 @@ impl Result { } } - /// Convert from `Result` to `&mut [T]` (without copying) + /// Converts from `Result` to `&mut [T]` (without copying) /// /// ``` /// # #![feature(core)] @@ -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")] @@ -811,7 +793,7 @@ impl Result { reason = "use inherent method instead")] #[allow(deprecated)] impl AsSlice for Result { - /// Convert from `Result` to `&[T]` (without copying) + /// Converts from `Result` to `&[T]` (without copying) #[inline] fn as_slice<'a>(&'a self) -> &'a [T] { match *self { @@ -974,7 +956,7 @@ impl> FromIterator> for Result { // FromIterator ///////////////////////////////////////////////////////////////////////////// -/// Perform a fold operation over the result values from an iterator. +/// Performs a fold operation over the result values from an iterator. /// /// If an `Err` is encountered, it is immediately returned. /// Otherwise, the folded value is returned. diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 9bc760b56ec..fc623f21167 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -106,19 +106,19 @@ Section: Creating a string /// Errors which can occur when attempting to interpret a byte slice as a `str`. #[derive(Copy, Eq, PartialEq, Clone, Debug)] -#[unstable(feature = "core", - reason = "error enumeration recently added and definitions may be refined")] -pub enum Utf8Error { - /// An invalid byte was detected at the byte offset given. - /// - /// The offset is guaranteed to be in bounds of the slice in question, and - /// the byte at the specified offset was the first invalid byte in the - /// sequence detected. - InvalidByte(usize), +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Utf8Error { + valid_up_to: usize, +} - /// The byte slice was invalid because more bytes were needed but no more - /// bytes were available. - TooShort, +impl Utf8Error { + /// Returns the index in the given string up to which valid UTF-8 was + /// verified. + /// + /// Starting at the index provided, but not necessarily at it precisely, an + /// invalid UTF-8 encoding sequence was found. + #[unstable(feature = "utf8_error", reason = "method just added")] + pub fn valid_up_to(&self) -> usize { self.valid_up_to } } /// Converts a slice of bytes to a string slice without performing any @@ -147,14 +147,7 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Utf8Error::InvalidByte(n) => { - write!(f, "invalid utf-8: invalid byte at index {}", n) - } - Utf8Error::TooShort => { - write!(f, "invalid utf-8: byte slice too short") - } - } + write!(f, "invalid utf-8: invalid byte near index {}", self.valid_up_to) } } @@ -1218,14 +1211,16 @@ fn run_utf8_validation_iterator(iter: &mut slice::Iter) // restore the iterator we had at the start of this codepoint. macro_rules! err { () => {{ *iter = old.clone(); - return Err(Utf8Error::InvalidByte(whole.len() - iter.as_slice().len())) + return Err(Utf8Error { + valid_up_to: whole.len() - iter.as_slice().len() + }) }}} macro_rules! next { () => { match iter.next() { Some(a) => *a, // we needed data, but there was none: error! - None => return Err(Utf8Error::TooShort), + None => err!(), } }} diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 9f701e1b031..62b693dcbe6 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -32,17 +32,17 @@ pub trait Pattern<'a>: Sized { /// Associated searcher for this pattern type Searcher: Searcher<'a>; - /// Construct the associated searcher from + /// Constructs the associated searcher from /// `self` and the `haystack` to search in. fn into_searcher(self, haystack: &'a str) -> Self::Searcher; - /// Check whether the pattern matches anywhere in the haystack + /// Checks whether the pattern matches anywhere in the haystack #[inline] fn is_contained_in(self, haystack: &'a str) -> bool { self.into_searcher(haystack).next_match().is_some() } - /// Check whether the pattern matches at the front of the haystack + /// Checks whether the pattern matches at the front of the haystack #[inline] fn is_prefix_of(self, haystack: &'a str) -> bool { match self.into_searcher(haystack).next() { @@ -51,7 +51,7 @@ pub trait Pattern<'a>: Sized { } } - /// Check whether the pattern matches at the back of the haystack + /// Checks whether the pattern matches at the back of the haystack #[inline] fn is_suffix_of(self, haystack: &'a str) -> bool where Self::Searcher: ReverseSearcher<'a> diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs index ba12ff306e9..cab2175f897 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 63d1fe968fe..1e0e2018050 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/liblibc/lib.rs b/src/liblibc/lib.rs index 040c9b011f3..ba3a6831d8c 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -3344,6 +3344,8 @@ pub mod consts { pub const _SC_XOPEN_REALTIME : c_int = 130; pub const _SC_XOPEN_REALTIME_THREADS : c_int = 131; + + pub const PTHREAD_CREATE_JOINABLE: c_int = 0; pub const PTHREAD_CREATE_DETACHED: c_int = 1; @@ -3727,12 +3729,14 @@ pub mod consts { pub const _SC_2_FORT_RUN : c_int = 50; pub const _SC_2_SW_DEV : c_int = 51; pub const _SC_2_LOCALEDEF : c_int = 52; + pub const _SC_NPROCESSORS_ONLN : c_int = 84; pub const _SC_2_CHAR_TERM : c_int = 95; pub const _SC_2_C_VERSION : c_int = 96; pub const _SC_2_UPE : c_int = 97; pub const _SC_XBS5_ILP32_OFF32 : c_int = 125; pub const _SC_XBS5_ILP32_OFFBIG : c_int = 126; pub const _SC_XBS5_LPBIG_OFFBIG : c_int = 128; + } #[cfg(target_os = "nacl")] pub mod sysconf { @@ -3742,6 +3746,13 @@ pub mod consts { pub static _SC_NPROCESSORS_ONLN : c_int = 1; pub static _SC_PAGESIZE : c_int = 2; } + + #[cfg(target_os = "macos")] + pub mod sysconf { + use types::os::arch::c95::c_int; + pub static _SC_NPROCESSORS_ONLN : c_int = 58; + } + #[cfg(target_os = "android")] pub mod sysconf { use types::os::arch::c95::c_int; diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index 2ba3164e1b0..5ba6d8912f2 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 d04e83e84f7..1125d096536 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 432081063c5..77e53248607 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 fa41c3edfe5..ac3fe6510eb 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 347d494259d..8406c76cc1b 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 15d3d981eb5..53ea28f0c11 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 e2a5276cc78..2f37451ecbb 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 98d1bbf5af9..287a23cf1d1 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/middle/dead.rs b/src/librustc/middle/dead.rs index 426540ce156..b3188f260b9 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -562,7 +562,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { span: codemap::Span, id: ast::NodeId) { // Have to warn method here because methods are not ast::Item match fk { - visit::FkMethod(name, _) => { + visit::FkMethod(name, _, _) => { if !self.symbol_is_live(id, None) { self.warn_dead_code(id, span, name.name, "method"); } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 814492cbef1..b6a070c9332 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -87,9 +87,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { block: &'v ast::Block, span: Span, _: ast::NodeId) { let (is_item_fn, is_unsafe_fn) = match fn_kind { - visit::FkItemFn(_, _, fn_style, _) => + visit::FkItemFn(_, _, fn_style, _, _) => (true, fn_style == ast::Unsafety::Unsafe), - visit::FkMethod(_, sig) => + visit::FkMethod(_, sig, _) => (true, sig.unsafety == ast::Unsafety::Unsafe), _ => (false, false), }; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 1036c97a5ad..53ed3b91948 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -142,12 +142,12 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, b: &'v ast::Block, s: Span, _: ast::NodeId) { match fk { - visit::FkItemFn(_, generics, _, _) => { + visit::FkItemFn(_, generics, _, _, _) => { self.visit_early_late(subst::FnSpace, generics, |this| { visit::walk_fn(this, fk, fd, b, s) }) } - visit::FkMethod(_, sig) => { + visit::FkMethod(_, sig, _) => { self.visit_early_late(subst::FnSpace, &sig.generics, |this| { visit::walk_fn(this, fk, fd, b, s) }) diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 9f05423e1eb..e7c25d82150 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -96,8 +96,8 @@ impl<'a> Annotator<'a> { if tag == "unstable" || tag == "stable" || tag == "deprecated" { attr::mark_used(attr); self.sess.span_warn(attr.span(), - "stability attributes are deprecated and \ - will soon become errors"); + "stability attributes are deprecated \ + and will soon become errors"); } } f(self); diff --git a/src/librustc_back/fs.rs b/src/librustc_back/fs.rs index 231f6ee3be6..2ab4d7ff78a 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(); + fs::create_dir(&dir).unwrap(); + fs::soft_link(&file, &link).unwrap(); + fs::soft_link(&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); + 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 7591ebf67f8..3c54d6631f8 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 ff3f0b78f91..58073079d31 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 b12732f8794..522d66cb563 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/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c1d71671eb3..72c679e8833 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -957,7 +957,7 @@ impl LintPass for NonSnakeCase { fk: visit::FnKind, _: &ast::FnDecl, _: &ast::Block, span: Span, id: ast::NodeId) { match fk { - visit::FkMethod(ident, _) => match method_context(cx, id, span) { + visit::FkMethod(ident, _, _) => match method_context(cx, id, span) { MethodContext::PlainImpl => { self.check_snake_case(cx, "method", ident, span) }, @@ -966,7 +966,7 @@ impl LintPass for NonSnakeCase { }, _ => (), }, - visit::FkItemFn(ident, _, _, _) => { + visit::FkItemFn(ident, _, _, _, _) => { self.check_snake_case(cx, "function", ident, span) }, _ => (), @@ -1290,10 +1290,10 @@ impl LintPass for UnsafeCode { fn check_fn(&mut self, cx: &Context, fk: visit::FnKind, _: &ast::FnDecl, _: &ast::Block, span: Span, _: ast::NodeId) { match fk { - visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _) => + visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _, _) => cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"), - visit::FkMethod(_, sig) => { + visit::FkMethod(_, sig, _) => { if sig.unsafety == ast::Unsafety::Unsafe { cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method") } @@ -1818,8 +1818,8 @@ impl LintPass for UnconditionalRecursion { ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool; let (name, checker) = match fn_kind { - visit::FkItemFn(name, _, _, _) => (name, id_refers_to_this_fn as F), - visit::FkMethod(name, _) => (name, id_refers_to_this_method as F), + visit::FkItemFn(name, _, _, _, _) => (name, id_refers_to_this_fn as F), + visit::FkMethod(name, _, _) => (name, id_refers_to_this_method as F), // closures can't recur, so they don't matter. visit::FkFnBlock => return }; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f90c7640f8c..6fd59a20532 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -242,11 +242,11 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { _: Span, node_id: NodeId) { let rib_kind = match function_kind { - visit::FkItemFn(_, generics, _, _) => { + visit::FkItemFn(_, generics, _, _, _) => { self.visit_generics(generics); ItemRibKind } - visit::FkMethod(_, sig) => { + visit::FkMethod(_, sig, _) => { self.visit_generics(&sig.generics); self.visit_explicit_self(&sig.explicit_self); MethodRibKind diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index f544efe7401..8cecc39ec39 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -131,7 +131,9 @@ pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match b.expr { Some(ref e) => { - bcx = expr::trans_into(bcx, &**e, dest); + if !bcx.unreachable.get() { + bcx = expr::trans_into(bcx, &**e, dest); + } } None => { assert!(dest == expr::Ignore || bcx.unreachable.get()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a54adb3533a..8264647b256 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2616,8 +2616,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, actual) }, expr_t, None); - if let Some(t) = ty::ty_to_def_id(expr_t) { - suggest_field_names(t, field, tcx, vec![]); + if let ty::ty_struct(did, _) = expr_t.sty { + suggest_field_names(did, field, tcx, vec![]); } } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 484021fedc4..c3ab375a9e2 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -78,9 +78,11 @@ return; } - if (e.which === 191 && $('#help').hasClass('hidden')) { // question mark - e.preventDefault(); - $('#help').removeClass('hidden'); + if (e.which === 191) { // question mark + if (e.shiftKey && $('#help').hasClass('hidden')) { + e.preventDefault(); + $('#help').removeClass('hidden'); + } } else if (e.which === 27) { // esc if (!$('#help').hasClass('hidden')) { e.preventDefault(); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index bdee53cd009..1393c39f66c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -130,10 +130,10 @@ struct Output { pub fn main() { const STACK_SIZE: usize = 32000000; // 32MB - let res = std::thread::Builder::new().stack_size(STACK_SIZE).scoped(move || { + let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { let s = env::args().collect::>(); main_args(&s) - }).unwrap().join(); + }).unwrap().join().unwrap(); env::set_exit_status(res as i32); } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 5890bdec8c1..620ea40b48a 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 2e86712c9bc..dde79b123e6 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 81b5d4c5818..af138734610 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/ascii.rs b/src/libstd/ascii.rs index 20ad71a4bf8..a2ba8c4c1ba 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -23,12 +23,12 @@ use mem; #[unstable(feature = "std_misc", reason = "would prefer to do this in a more general way")] pub trait OwnedAsciiExt { - /// Convert the string to ASCII upper case: + /// Converts the string to ASCII upper case: /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. fn into_ascii_uppercase(self) -> Self; - /// Convert the string to ASCII lower case: + /// Converts the string to ASCII lower case: /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. fn into_ascii_lowercase(self) -> Self; @@ -41,7 +41,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] type Owned; - /// Check if within the ASCII range. + /// Checks if within the ASCII range. /// /// # Examples /// @@ -95,7 +95,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_lowercase(&self) -> Self::Owned; - /// Check that two strings are an ASCII case-insensitive match. + /// Checks that two strings are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporary strings. @@ -117,7 +117,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn eq_ignore_ascii_case(&self, other: &Self) -> bool; - /// Convert this type to its ASCII upper case equivalent in-place. + /// Converts this type to its ASCII upper case equivalent in-place. /// /// See `to_ascii_uppercase` for more information. /// @@ -136,7 +136,7 @@ pub trait AsciiExt { #[unstable(feature = "ascii")] fn make_ascii_uppercase(&mut self); - /// Convert this type to its ASCII lower case equivalent in-place. + /// Converts this type to its ASCII lower case equivalent in-place. /// /// See `to_ascii_lowercase` for more information. /// diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 54a3a055768..f554a4f4ed6 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -506,7 +506,7 @@ impl HashMap } impl HashMap { - /// Create an empty HashMap. + /// Creates an empty HashMap. /// /// # Examples /// @@ -563,7 +563,7 @@ impl HashMap } } - /// Create an empty HashMap with space for at least `capacity` + /// Creates an empty HashMap with space for at least `capacity` /// elements, using `hasher` to hash the keys. /// /// Warning: `hasher` is normally randomly generated, and @@ -1596,7 +1596,7 @@ pub struct RandomState { #[unstable(feature = "std_misc", reason = "hashing an hash maps may be altered")] impl RandomState { - /// Construct a new `RandomState` that is initialized with random keys. + /// Constructs a new `RandomState` that is initialized with random keys. #[inline] #[allow(deprecated)] pub fn new() -> RandomState { @@ -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/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index f897d565321..6b0546b1ee7 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -111,7 +111,7 @@ pub struct HashSet { } impl HashSet { - /// Create an empty HashSet. + /// Creates an empty HashSet. /// /// # Examples /// @@ -125,7 +125,7 @@ impl HashSet { HashSet::with_capacity(INITIAL_CAPACITY) } - /// Create an empty HashSet with space for at least `n` elements in + /// Creates an empty HashSet with space for at least `n` elements in /// the hash table. /// /// # Examples @@ -166,7 +166,7 @@ impl HashSet HashSet::with_capacity_and_hash_state(INITIAL_CAPACITY, hash_state) } - /// Create an empty HashSet with space for at least `capacity` + /// Creates an empty HashSet with space for at least `capacity` /// elements in the hash table, using `hasher` to hash the keys. /// /// Warning: `hasher` is normally randomly generated, and @@ -402,7 +402,7 @@ impl HashSet Union { iter: self.iter().chain(other.difference(self)) } } - /// Return the number of elements in the set + /// Returns the number of elements in the set. /// /// # Examples /// @@ -417,7 +417,7 @@ impl HashSet #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.map.len() } - /// Returns true if the set contains no elements + /// Returns true if the set contains no elements. /// /// # Examples /// diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index e76d5460eb0..c69df6435c4 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -105,7 +105,7 @@ impl DynamicLibrary { } } - /// Access the value at the symbol of the dynamic library + /// Accesses the value at the symbol of the dynamic library. pub unsafe fn symbol(&self, symbol: &str) -> Result<*mut T, String> { // This function should have a lifetime constraint of 'a on // T but that feature is still unimplemented diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 931cf46a58f..bcc109a71cb 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -261,7 +261,7 @@ pub fn set_var(k: &K, v: &V) os_imp::setenv(k.as_ref(), v.as_ref()) } -/// Remove an environment variable from the environment of the currently running process. +/// Removes an environment variable from the environment of the currently running process. /// /// # Examples /// diff --git a/src/libstd/error.rs b/src/libstd/error.rs index c9babeb3230..96087bf1183 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -122,10 +122,7 @@ impl Error for str::ParseBoolError { #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::Utf8Error { fn description(&self) -> &str { - match *self { - str::Utf8Error::TooShort => "invalid utf-8: not enough bytes", - str::Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents", - } + "invalid utf-8: corrupt contents" } } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index de91e5f3268..c1c05da4ee4 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}; @@ -133,7 +131,7 @@ pub struct CStr { pub struct NulError(usize, Vec); impl CString { - /// Create a new C-compatible string from a container of bytes. + /// Creates a new C-compatible string from a container of bytes. /// /// This method will consume the provided data and use the underlying bytes /// to construct a new string, ensuring that there is a trailing 0 byte. @@ -169,11 +167,12 @@ impl CString { } } - /// Create a C-compatible string from a byte vector without checking for + /// Creates a C-compatible string from a byte vector without checking for /// interior 0 bytes. /// - /// This method is equivalent to `from_vec` except that no runtime assertion - /// is made that `v` contains no 0 bytes. + /// This method is equivalent to `new` except that no runtime assertion + /// is made that `v` contains no 0 bytes, and it requires an actual + /// byte vector, not anyhting that can be converted to one with Into. #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { v.push(0); @@ -215,7 +214,7 @@ impl fmt::Debug for CString { impl NulError { /// Returns the position of the nul byte in the slice that was provided to - /// `CString::from_vec`. + /// `CString::new`. #[stable(feature = "rust1", since = "1.0.0")] pub fn nul_position(&self) -> usize { self.0 } @@ -245,20 +244,8 @@ 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. + /// Casts a raw C string to a safe C string wrapper. /// /// This function will cast the provided `ptr` to the `CStr` wrapper which /// allows inspection and interoperation of non-owned C strings. This method @@ -301,7 +288,7 @@ impl CStr { mem::transmute(slice::from_raw_parts(ptr, len as usize + 1)) } - /// Return the inner pointer to this C string. + /// Returns the inner pointer to this C string. /// /// The returned pointer will be valid for as long as `self` is and points /// to a contiguous region of memory terminated with a 0 byte to represent @@ -311,7 +298,7 @@ impl CStr { self.inner.as_ptr() } - /// Convert this C string to a byte slice. + /// Converts this C string to a byte slice. /// /// This function will calculate the length of this string (which normally /// requires a linear amount of work to be done) and then return the @@ -329,7 +316,7 @@ impl CStr { &bytes[..bytes.len() - 1] } - /// Convert this C string to a byte slice containing the trailing 0 byte. + /// Converts this C string to a byte slice containing the trailing 0 byte. /// /// This function is the equivalent of `to_bytes` except that it will retain /// the trailing nul instead of chopping it off. diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index 1b7e913d46c..99becb67a5a 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -25,6 +25,6 @@ mod os_str; /// Freely convertible to an `&OsStr` slice. #[unstable(feature = "std_misc")] pub trait AsOsStr { - /// Convert to an `&OsStr` slice. + /// Converts to an `&OsStr` slice. fn as_os_str(&self) -> &OsStr; } diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index ab20efe25eb..08b41915d91 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}; @@ -69,7 +68,7 @@ impl OsString { OsString { inner: Buf::from_string(String::new()) } } - /// Construct an `OsString` from a byte sequence. + /// Constructs an `OsString` from a byte sequence. /// /// # Platform behavior /// @@ -94,13 +93,13 @@ impl OsString { from_bytes_inner(bytes.into()) } - /// Convert to an `OsStr` slice. + /// Converts to an `OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &OsStr { self } - /// Convert the `OsString` into a `String` if it contains valid Unicode data. + /// Converts the `OsString` into a `String` if it contains valid Unicode data. /// /// On failure, ownership of the original `OsString` is returned. #[stable(feature = "rust1", since = "1.0.0")] @@ -108,7 +107,7 @@ impl OsString { self.inner.into_string().map_err(|buf| OsString { inner: buf} ) } - /// Extend the string with the given `&OsStr` slice. + /// Extends the string with the given `&OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn push>(&mut self, s: T) { self.inner.push_slice(&s.as_ref().inner) @@ -221,13 +220,13 @@ impl Hash for OsString { } impl OsStr { - /// Coerce into an `OsStr` slice. + /// Coerces into an `OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn new + ?Sized>(s: &S) -> &OsStr { s.as_ref() } - /// Coerce directly from a `&str` slice to a `&OsStr` slice. + /// Coerces directly from a `&str` slice to a `&OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] #[deprecated(since = "1.0.0", reason = "use `OsStr::new` instead")] @@ -235,7 +234,7 @@ impl OsStr { unsafe { mem::transmute(Slice::from_str(s)) } } - /// Yield a `&str` slice if the `OsStr` is valid unicode. + /// Yields a `&str` slice if the `OsStr` is valid unicode. /// /// This conversion may entail doing a check for UTF-8 validity. #[stable(feature = "rust1", since = "1.0.0")] @@ -243,7 +242,7 @@ impl OsStr { self.inner.to_str() } - /// Convert an `OsStr` to a `Cow`. + /// Converts an `OsStr` to a `Cow`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. #[stable(feature = "rust1", since = "1.0.0")] @@ -251,13 +250,13 @@ impl OsStr { self.inner.to_string_lossy() } - /// Copy the slice into an owned `OsString`. + /// Copies the slice into an owned `OsString`. #[stable(feature = "rust1", since = "1.0.0")] pub fn to_os_string(&self) -> OsString { OsString { inner: self.inner.to_owned() } } - /// Yield this `OsStr` as a byte slice. + /// Yields this `OsStr` as a byte slice. /// /// # Platform behavior /// @@ -275,7 +274,7 @@ impl OsStr { } } - /// Create a `CString` containing this `OsStr` data. + /// Creates a `CString` containing this `OsStr` data. /// /// Fails if the `OsStr` contains interior nulls. /// @@ -287,7 +286,7 @@ impl OsStr { self.to_bytes().and_then(|b| CString::new(b).ok()) } - /// Get the underlying byte representation. + /// Gets the underlying byte representation. /// /// Note: it is *crucial* that this API is private, to avoid /// revealing the internal, platform-specific encodings. @@ -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 914830d9dcf..6e902a47396 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() @@ -171,7 +171,7 @@ impl File { OpenOptions::new().read(true).open(path) } - /// Open a file in write-only mode. + /// Opens a file in write-only mode. /// /// This function will create a file if it does not exist, /// and will truncate it if it does. @@ -201,7 +201,7 @@ impl File { self.path.as_ref().map(|p| &**p) } - /// Attempt to sync all OS-internal metadata to disk. + /// Attempts to sync all OS-internal metadata to disk. /// /// This function will attempt to ensure that all in-core data reaches the /// filesystem before returning. @@ -362,7 +362,7 @@ impl OpenOptions { OpenOptions(fs_imp::OpenOptions::new()) } - /// Set the option for read access. + /// Sets the option for read access. /// /// This option, when true, will indicate that the file should be /// `read`-able if opened. @@ -379,7 +379,7 @@ impl OpenOptions { self.0.read(read); self } - /// Set the option for write access. + /// Sets the option for write access. /// /// This option, when true, will indicate that the file should be /// `write`-able if opened. @@ -396,7 +396,7 @@ impl OpenOptions { self.0.write(write); self } - /// Set the option for the append mode. + /// Sets the option for the append mode. /// /// This option, when true, means that writes will append to a file instead /// of overwriting previous contents. @@ -413,7 +413,7 @@ impl OpenOptions { self.0.append(append); self } - /// Set the option for truncating a previous file. + /// Sets the option for truncating a previous file. /// /// If a file is successfully opened with this option set it will truncate /// the file to 0 length if it already exists. @@ -430,7 +430,7 @@ impl OpenOptions { self.0.truncate(truncate); self } - /// Set the option for creating a new file. + /// Sets the option for creating a new file. /// /// This option indicates whether a new file will be created if the file /// does not yet already exist. @@ -447,7 +447,7 @@ impl OpenOptions { self.0.create(create); self } - /// Open a file at `path` with the options specified by `self`. + /// Opens a file at `path` with the options specified by `self`. /// /// # Errors /// @@ -587,7 +587,7 @@ impl Permissions { #[stable(feature = "rust1", since = "1.0.0")] pub fn readonly(&self) -> bool { self.0.readonly() } - /// Modify the readonly flag for this set of permissions. + /// Modifies the readonly flag for this set of permissions. /// /// This operation does **not** modify the filesystem. To modify the /// filesystem use the `fs::set_permissions` function. @@ -670,7 +670,7 @@ impl DirEntry { pub fn path(&self) -> PathBuf { self.0.path() } } -/// Remove a file from the underlying filesystem. +/// Removes a file from the underlying filesystem. /// /// Note that, just because an unlink call was successful, it is not /// guaranteed that a file is immediately deleted (e.g. depending on @@ -856,7 +856,7 @@ pub fn read_link>(path: P) -> io::Result { fs_imp::readlink(path.as_ref()) } -/// Create a new, empty directory at the provided path +/// Creates a new, empty directory at the provided path /// /// # Errors /// @@ -906,7 +906,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { create_dir(path) } -/// Remove an existing, empty directory +/// Removes an existing, empty directory. /// /// # Errors /// @@ -1058,7 +1058,7 @@ impl Iterator for WalkDir { reason = "the precise set of methods exposed on this trait may \ change and some methods may be removed")] pub trait PathExt { - /// Get information on the file, directory, etc at this path. + /// Gets information on the file, directory, etc at this path. /// /// Consult the `fs::stat` documentation for more info. /// @@ -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/io/cursor.rs b/src/libstd/io/cursor.rs index 6433c29bb9d..72743106abf 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -34,21 +34,21 @@ pub struct Cursor { } impl Cursor { - /// Create a new cursor wrapping the provided underlying I/O object. + /// Creates a new cursor wrapping the provided underlying I/O object. #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: T) -> Cursor { Cursor { pos: 0, inner: inner } } - /// Consume this cursor, returning the underlying value. + /// Consumes this cursor, returning the underlying value. #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> T { self.inner } - /// Get a reference to the underlying value in this cursor. + /// Gets a reference to the underlying value in this cursor. #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &T { &self.inner } - /// Get a mutable reference to the underlying value in this cursor. + /// Gets a mutable reference to the underlying value in this cursor. /// /// Care should be taken to avoid modifying the internal I/O state of the /// underlying value as it may corrupt this cursor's position. diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 7428d0a8e35..a49039b1ec4 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -191,7 +191,7 @@ impl Error { } } - /// Return the corresponding `ErrorKind` for this error. + /// Returns the corresponding `ErrorKind` for this error. #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> ErrorKind { match self.repr { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index f0f37117ed3..f3ba5cd7854 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -172,14 +172,11 @@ pub trait Read { /// Read all bytes until EOF in this source, placing them into `buf`. /// /// All bytes read from this source will be appended to the specified buffer - /// `buf`. This function will return a call to `read` either: + /// `buf`. This function will continuously call `read` to append more data to + /// `buf` until `read` returns either `Ok(0)` or an error of + /// non-`ErrorKind::Interrupted` kind. /// - /// 1. Returns `Ok(0)`. - /// 2. Returns an error which is not of the kind `ErrorKind::Interrupted`. - /// - /// Until one of these conditions is met the function will continuously - /// invoke `read` to append more data to `buf`. If successful, this function - /// will return the total number of bytes read. + /// If successful, this function will return the total number of bytes read. /// /// # Errors /// @@ -220,14 +217,14 @@ pub trait Read { append_to_string(buf, |b| read_to_end(self, b)) } - /// Create a "by reference" adaptor for this instance of `Read`. + /// Creates a "by reference" adaptor for this instance of `Read`. /// /// The returned adaptor also implements `Read` and will simply borrow this /// current reader. #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } - /// Transform this `Read` instance to an `Iterator` over its bytes. + /// Transforms this `Read` instance to an `Iterator` over its bytes. /// /// The returned type implements `Iterator` where the `Item` is `Result`. The yielded item is `Ok` if a byte was successfully read and @@ -238,7 +235,7 @@ pub trait Read { Bytes { inner: self } } - /// Transform this `Read` instance to an `Iterator` over `char`s. + /// Transforms this `Read` instance to an `Iterator` over `char`s. /// /// This adaptor will attempt to interpret this reader as an UTF-8 encoded /// sequence of characters. The returned iterator will return `None` once @@ -255,7 +252,7 @@ pub trait Read { Chars { inner: self } } - /// Create an adaptor which will chain this stream with another. + /// Creates an adaptor which will chain this stream with another. /// /// The returned `Read` instance will first read all bytes from this object /// until EOF is encountered. Afterwards the output is equivalent to the @@ -265,7 +262,7 @@ pub trait Read { Chain { first: self, second: next, done_first: false } } - /// Create an adaptor which will read at most `limit` bytes from it. + /// Creates an adaptor which will read at most `limit` bytes from it. /// /// This function returns a new instance of `Read` which will read at most /// `limit` bytes, after which it will always return EOF (`Ok(0)`). Any @@ -406,7 +403,7 @@ pub trait Write { } } - /// Create a "by reference" adaptor for this instance of `Write`. + /// Creates a "by reference" adaptor for this instance of `Write`. /// /// The returned adaptor also implements `Write` and will simply borrow this /// current writer. diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 2850d92e34d..cd6af77daa9 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -45,7 +45,7 @@ struct StdoutRaw(stdio::Stdout); /// the `std::io::stdio::stderr_raw` function. struct StderrRaw(stdio::Stderr); -/// Construct a new raw handle to the standard input of this process. +/// Constructs a new raw handle to the standard input of this process. /// /// The returned handle does not interact with any other handles created nor /// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin` @@ -54,7 +54,7 @@ struct StderrRaw(stdio::Stderr); /// The returned handle has no external synchronization or buffering. fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) } -/// Construct a new raw handle to the standard input stream of this process. +/// Constructs a new raw handle to the standard input stream of this process. /// /// The returned handle does not interact with any other handles created nor /// handles returned by `std::io::stdout`. Note that data is buffered by the @@ -65,7 +65,7 @@ fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) } /// top. fn stdout_raw() -> StdoutRaw { StdoutRaw(stdio::Stdout::new()) } -/// Construct a new raw handle to the standard input stream of this process. +/// Constructs a new raw handle to the standard input stream of this process. /// /// The returned handle does not interact with any other handles created nor /// handles returned by `std::io::stdout`. @@ -109,7 +109,7 @@ pub struct StdinLock<'a> { inner: MutexGuard<'a, BufReader>, } -/// Create a new handle to the global standard input stream of this process. +/// Creates a new handle to the global standard input stream of this process. /// /// The handle returned refers to a globally shared buffer between all threads. /// Access is synchronized and can be explicitly controlled with the `lock()` @@ -139,7 +139,7 @@ pub fn stdin() -> Stdin { } impl Stdin { - /// Lock this handle to the standard input stream, returning a readable + /// Locks this handle to the standard input stream, returning a readable /// guard. /// /// The lock is released when the returned lock goes out of scope. The @@ -243,7 +243,7 @@ pub fn stdout() -> Stdout { } impl Stdout { - /// Lock this handle to the standard output stream, returning a writable + /// Locks this handle to the standard output stream, returning a writable /// guard. /// /// The lock is released when the returned lock goes out of scope. The @@ -315,7 +315,7 @@ pub fn stderr() -> Stderr { } impl Stderr { - /// Lock this handle to the standard error stream, returning a writable + /// Locks this handle to the standard error stream, returning a writable /// guard. /// /// The lock is released when the returned lock goes out of scope. The diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b329494a052..b2bcbaa7b1c 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/net/addr.rs b/src/libstd/net/addr.rs index 702b76e7d1c..05a3ca91948 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -615,7 +615,7 @@ mod tests { fn ipv4_properties() { fn check(octets: &[u8; 4], unspec: bool, loopback: bool, private: bool, link_local: bool, global: bool, - multicast: bool) { + multicast: bool, broadcast: bool, documentation: bool) { let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]); assert_eq!(octets, &ip.octets()); @@ -625,20 +625,23 @@ mod tests { assert_eq!(ip.is_link_local(), link_local); assert_eq!(ip.is_global(), global); assert_eq!(ip.is_multicast(), multicast); + assert_eq!(ip.is_broadcast(), broadcast); + assert_eq!(ip.is_documentation(), documentation); } - // address unspec loopbk privt linloc global multicast - check(&[0, 0, 0, 0], true, false, false, false, true, false); - check(&[0, 0, 0, 1], false, false, false, false, true, false); - check(&[1, 0, 0, 0], false, false, false, false, true, false); - check(&[10, 9, 8, 7], false, false, true, false, false, false); - check(&[127, 1, 2, 3], false, true, false, false, false, false); - check(&[172, 31, 254, 253], false, false, true, false, false, false); - check(&[169, 254, 253, 242], false, false, false, true, false, false); - check(&[192, 168, 254, 253], false, false, true, false, false, false); - check(&[224, 0, 0, 0], false, false, false, false, true, true); - check(&[239, 255, 255, 255], false, false, false, false, true, true); - check(&[255, 255, 255, 255], false, false, false, false, true, false); + // address unspec loopbk privt linloc global multicast brdcast doc + check(&[0, 0, 0, 0], true, false, false, false, true, false, false, false); + check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false); + check(&[1, 0, 0, 0], false, false, false, false, true, false, false, false); + check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false); + check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false); + check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false); + check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false); + check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false); + check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false); + check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false); + check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); + check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); } #[test] diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index c8b19287477..0e493b271f9 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -58,7 +58,7 @@ pub enum Ipv6MulticastScope { } impl Ipv4Addr { - /// Create a new IPv4 address from four eight-bit octets. + /// Creates a new IPv4 address from four eight-bit octets. /// /// The result will represent the IP address a.b.c.d #[stable(feature = "rust1", since = "1.0.0")] @@ -115,9 +115,11 @@ impl Ipv4Addr { /// /// Non-globally-routable networks include the private networks (10.0.0.0/8, /// 172.16.0.0/12 and 192.168.0.0/16), the loopback network (127.0.0.0/8), - /// and the link-local network (169.254.0.0/16). + /// the link-local network (169.254.0.0/16), the broadcast address (255.255.255.255/32) and + /// the test networks used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) pub fn is_global(&self) -> bool { - !self.is_private() && !self.is_loopback() && !self.is_link_local() + !self.is_private() && !self.is_loopback() && !self.is_link_local() && + !self.is_broadcast() && !self.is_documentation() } /// Returns true if this is a multicast address. @@ -127,7 +129,30 @@ impl Ipv4Addr { self.octets()[0] >= 224 && self.octets()[0] <= 239 } - /// Convert this address to an IPv4-compatible IPv6 address + /// Returns true if this is a broadcast address. + /// + /// A broadcast address has all octets set to 255 as defined in RFC 919 + pub fn is_broadcast(&self) -> bool { + self.octets()[0] == 255 && self.octets()[1] == 255 && + self.octets()[2] == 255 && self.octets()[3] == 255 + } + + /// Returns true if this address is in a range designated for documentation + /// + /// This is defined in RFC 5737 + /// - 192.0.2.0/24 (TEST-NET-1) + /// - 198.51.100.0/24 (TEST-NET-2) + /// - 203.0.113.0/24 (TEST-NET-3) + pub fn is_documentation(&self) -> bool { + match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { + (192, _, 2, _) => true, + (198, 51, 100, _) => true, + (203, _, 113, _) => true, + _ => false + } + } + + /// Converts this address to an IPv4-compatible IPv6 address /// /// a.b.c.d becomes ::a.b.c.d #[stable(feature = "rust1", since = "1.0.0")] @@ -137,7 +162,7 @@ impl Ipv4Addr { ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) } - /// Convert this address to an IPv4-mapped IPv6 address + /// Converts this address to an IPv4-mapped IPv6 address /// /// a.b.c.d becomes ::ffff:a.b.c.d #[stable(feature = "rust1", since = "1.0.0")] @@ -220,7 +245,7 @@ impl FromInner for Ipv4Addr { } impl Ipv6Addr { - /// Create a new IPv6 address from eight 16-bit segments. + /// Creates a new IPv6 address from eight 16-bit segments. /// /// The result will represent the IP address a:b:c:d:e:f:g:h #[stable(feature = "rust1", since = "1.0.0")] @@ -234,7 +259,7 @@ impl Ipv6Addr { } } - /// Return the eight 16-bit segments that make up this address + /// Returns the eight 16-bit segments that make up this address #[stable(feature = "rust1", since = "1.0.0")] pub fn segments(&self) -> [u16; 8] { [ntoh(self.inner.s6_addr[0]), @@ -324,7 +349,7 @@ impl Ipv6Addr { (self.segments()[0] & 0xff00) == 0xff00 } - /// Convert this address to an IPv4 address. Returns None if this address is + /// Converts this address to an IPv4 address. Returns None if this address is /// neither IPv4-compatible or IPv4-mapped. /// /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 2da6f7420ac..209a0032fb4 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -82,7 +82,7 @@ pub struct TcpListener(net_imp::TcpListener); pub struct Incoming<'a> { listener: &'a TcpListener } impl TcpStream { - /// Open a TCP connection to a remote host. + /// Opens a TCP connection to a remote host. /// /// `addr` is an address of the remote host. Anything which implements /// `ToSocketAddrs` trait can be supplied for the address; see this trait @@ -104,7 +104,7 @@ impl TcpStream { self.0.socket_addr() } - /// Shut down the read, write, or both halves of this connection. + /// Shuts down the read, write, or both halves of this connection. /// /// This function will cause all pending and future I/O on the specified /// portions to return immediately with an appropriate value (see the @@ -114,7 +114,7 @@ impl TcpStream { self.0.shutdown(how) } - /// Create a new independently owned handle to the underlying socket. + /// Creates a new independently owned handle to the underlying socket. /// /// The returned `TcpStream` is a reference to the same stream that this /// object references. Both handles will read and write the same stream of @@ -190,7 +190,7 @@ impl TcpListener { self.0.socket_addr() } - /// Create a new independently owned handle to the underlying socket. + /// Creates a new independently owned handle to the underlying socket. /// /// The returned `TcpListener` is a reference to the same socket that this /// object references. Both handles can be used to accept incoming diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index bec9c09bc31..1955b895300 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -85,7 +85,7 @@ impl UdpSocket { self.0.socket_addr() } - /// Create a new independently owned handle to the underlying socket. + /// Creates a new independently owned handle to the underlying socket. /// /// The returned `UdpSocket` is a reference to the same socket that this /// object references. Both handles will read and write the same port, and @@ -100,7 +100,7 @@ impl UdpSocket { self.0.set_broadcast(on) } - /// Set the multicast loop flag to the specified value + /// Sets the multicast loop flag to the specified value /// /// This lets multicast packets loop back to local sockets (if enabled) pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> { diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 6128469c60e..736f6d2f4f4 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -527,7 +527,7 @@ impl f32 { #[inline] pub fn round(self) -> f32 { num::Float::round(self) } - /// Return the integer part of a number. + /// Returns the integer part of a number. /// /// ``` /// let f = 3.3_f32; @@ -666,7 +666,7 @@ impl f32 { #[inline] pub fn mul_add(self, a: f32, b: f32) -> f32 { num::Float::mul_add(self, a, b) } - /// Take the reciprocal (inverse) of a number, `1/x`. + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` /// use std::f32; @@ -680,7 +680,7 @@ impl f32 { #[inline] pub fn recip(self) -> f32 { num::Float::recip(self) } - /// Raise a number to an integer power. + /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` /// @@ -696,7 +696,7 @@ impl f32 { #[inline] pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) } - /// Raise a number to a floating point power. + /// Raises a number to a floating point power. /// /// ``` /// use std::f32; @@ -710,7 +710,7 @@ impl f32 { #[inline] pub fn powf(self, n: f32) -> f32 { num::Float::powf(self, n) } - /// Take the square root of a number. + /// Takes the square root of a number. /// /// Returns NaN if `self` is a negative number. /// @@ -729,7 +729,7 @@ impl f32 { #[inline] pub fn sqrt(self) -> f32 { num::Float::sqrt(self) } - /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. + /// Takes the reciprocal (inverse) square root of a number, `1/sqrt(x)`. /// /// ``` /// # #![feature(std_misc)] @@ -852,7 +852,7 @@ impl f32 { #[inline] pub fn log10(self) -> f32 { num::Float::log10(self) } - /// Convert radians to degrees. + /// Converts radians to degrees. /// /// ``` /// # #![feature(std_misc)] @@ -868,7 +868,7 @@ impl f32 { #[inline] pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) } - /// Convert degrees to radians. + /// Converts degrees to radians. /// /// ``` /// # #![feature(std_misc)] @@ -1003,7 +1003,7 @@ impl f32 { unsafe { cmath::fdimf(self, other) } } - /// Take the cubic root of a number. + /// Takes the cubic root of a number. /// /// ``` /// use std::f32; @@ -1021,7 +1021,7 @@ impl f32 { unsafe { cmath::cbrtf(self) } } - /// Calculate the length of the hypotenuse of a right-angle triangle given + /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// /// ``` diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 794853f6f70..bb9067eca13 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -534,7 +534,7 @@ impl f64 { #[inline] pub fn round(self) -> f64 { num::Float::round(self) } - /// Return the integer part of a number. + /// Returns the integer part of a number. /// /// ``` /// let f = 3.3_f64; @@ -671,7 +671,7 @@ impl f64 { #[inline] pub fn mul_add(self, a: f64, b: f64) -> f64 { num::Float::mul_add(self, a, b) } - /// Take the reciprocal (inverse) of a number, `1/x`. + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` /// let x = 2.0_f64; @@ -683,7 +683,7 @@ impl f64 { #[inline] pub fn recip(self) -> f64 { num::Float::recip(self) } - /// Raise a number to an integer power. + /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` /// @@ -697,7 +697,7 @@ impl f64 { #[inline] pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) } - /// Raise a number to a floating point power. + /// Raises a number to a floating point power. /// /// ``` /// let x = 2.0_f64; @@ -709,7 +709,7 @@ impl f64 { #[inline] pub fn powf(self, n: f64) -> f64 { num::Float::powf(self, n) } - /// Take the square root of a number. + /// Takes the square root of a number. /// /// Returns NaN if `self` is a negative number. /// @@ -726,7 +726,7 @@ impl f64 { #[inline] pub fn sqrt(self) -> f64 { num::Float::sqrt(self) } - /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. + /// Takes the reciprocal (inverse) square root of a number, `1/sqrt(x)`. /// /// ``` /// # #![feature(std_misc)] @@ -835,7 +835,7 @@ impl f64 { #[inline] pub fn log10(self) -> f64 { num::Float::log10(self) } - /// Convert radians to degrees. + /// Converts radians to degrees. /// /// ``` /// use std::f64::consts; @@ -850,7 +850,7 @@ impl f64 { #[inline] pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } - /// Convert degrees to radians. + /// Converts degrees to radians. /// /// ``` /// use std::f64::consts; @@ -978,7 +978,7 @@ impl f64 { unsafe { cmath::fdim(self, other) } } - /// Take the cubic root of a number. + /// Takes the cubic root of a number. /// /// ``` /// let x = 8.0_f64; @@ -994,7 +994,7 @@ impl f64 { unsafe { cmath::cbrt(self) } } - /// Calculate the length of the hypotenuse of a right-angle triangle given + /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// /// ``` diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index ea516e5b20b..e0b9c720dbb 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -383,7 +383,7 @@ pub trait Float /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn round(self) -> Self; - /// Return the integer part of a number. + /// Returns the integer part of a number. /// /// ``` /// use std::num::Float; @@ -509,7 +509,7 @@ pub trait Float #[unstable(feature = "std_misc", reason = "unsure about its place in the world")] fn mul_add(self, a: Self, b: Self) -> Self; - /// Take the reciprocal (inverse) of a number, `1/x`. + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` /// # #![feature(std_misc)] @@ -524,7 +524,7 @@ pub trait Float reason = "unsure about its place in the world")] fn recip(self) -> Self; - /// Raise a number to an integer power. + /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` /// @@ -538,7 +538,7 @@ pub trait Float /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn powi(self, n: i32) -> Self; - /// Raise a number to a floating point power. + /// Raises a number to a floating point power. /// /// ``` /// use std::num::Float; @@ -550,7 +550,7 @@ pub trait Float /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn powf(self, n: Self) -> Self; - /// Take the square root of a number. + /// Takes the square root of a number. /// /// Returns NaN if `self` is a negative number. /// @@ -569,7 +569,7 @@ pub trait Float #[stable(feature = "rust1", since = "1.0.0")] fn sqrt(self) -> Self; - /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. + /// Takes the reciprocal (inverse) square root of a number, `1/sqrt(x)`. /// /// ``` /// # #![feature(std_misc)] @@ -679,7 +679,7 @@ pub trait Float #[stable(feature = "rust1", since = "1.0.0")] fn log10(self) -> Self; - /// Convert radians to degrees. + /// Converts radians to degrees. /// /// ``` /// use std::num::Float; @@ -693,7 +693,7 @@ pub trait Float /// ``` #[unstable(feature = "std_misc", reason = "desirability is unclear")] fn to_degrees(self) -> Self; - /// Convert degrees to radians. + /// Converts degrees to radians. /// /// ``` /// # #![feature(std_misc)] @@ -807,7 +807,7 @@ pub trait Float /// ``` #[unstable(feature = "std_misc", reason = "may be renamed")] fn abs_sub(self, other: Self) -> Self; - /// Take the cubic root of a number. + /// Takes the cubic root of a number. /// /// ``` /// # #![feature(std_misc)] @@ -822,7 +822,7 @@ pub trait Float /// ``` #[unstable(feature = "std_misc", reason = "may be renamed")] fn cbrt(self) -> Self; - /// Calculate the length of the hypotenuse of a right-angle triangle given + /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// /// ``` diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index ea869ebae10..8ab66f2328f 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 68aa7e4770f..00000000000 --- 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 5ebf931e95c..00000000000 --- 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 73973d0db28..00000000000 --- 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 509daa46ef3..00000000000 --- 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 c92e74fbc56..00000000000 --- 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 f62b1a836fd..00000000000 --- 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 dd30363e316..00000000000 --- 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 f5310292b91..00000000000 --- 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 a3567290b0e..00000000000 --- 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 7b23c3e1d03..00000000000 --- 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 0b4e871454d..caa7b4eb29c 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 a9f2198208b..00000000000 --- 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 9309147b15c..00000000000 --- 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 2f6fd713bfb..00000000000 --- 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/windows/ext.rs b/src/libstd/sys/windows/ext.rs index 5f6e74d4b72..90548dcefb4 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; @@ -38,7 +35,7 @@ pub mod io { /// Extract raw handles. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawHandle { - /// Extract the raw handle, without taking any ownership. + /// Extracts the raw handle, without taking any ownership. #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_handle(&self) -> RawHandle; } @@ -47,7 +44,7 @@ pub mod io { #[unstable(feature = "from_raw_os", reason = "recent addition to the std::os::windows::io module")] pub trait FromRawHandle { - /// Construct a new I/O object from the specified raw handle. + /// Constructs a new I/O object from the specified raw handle. /// /// This function will **consume ownership** of the handle given, /// passing responsibility for closing the handle to the returned @@ -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,42 +72,10 @@ 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 { - /// Extract the underlying raw socket from this object. + /// Extracts the underlying raw socket from this object. #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_socket(&self) -> RawSocket; } @@ -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 { @@ -226,7 +151,7 @@ pub mod ffi { /// Windows-specific extensions to `OsString`. #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { - /// Create an `OsString` from a potentially ill-formed UTF-16 slice of + /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of /// 16-bit code units. /// /// This is lossless: calling `.encode_wide()` on the resulting string @@ -245,7 +170,7 @@ pub mod ffi { /// Windows-specific extensions to `OsStr`. #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { - /// Re-encode an `OsStr` as a wide character sequence, + /// Re-encodes an `OsStr` as a wide character sequence, /// i.e. potentially ill-formed UTF-16. /// /// This is lossless. Note that the encoding does not include a final @@ -270,25 +195,25 @@ pub mod fs { /// Windows-specific extensions to `OpenOptions` pub trait OpenOptionsExt { - /// Override the `dwDesiredAccess` argument to the call to `CreateFile` + /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile` /// with the specified value. fn desired_access(&mut self, access: i32) -> &mut Self; - /// Override the `dwCreationDisposition` argument to the call to + /// Overrides the `dwCreationDisposition` argument to the call to /// `CreateFile` with the specified value. /// /// This will override any values of the standard `create` flags, for /// example. fn creation_disposition(&mut self, val: i32) -> &mut Self; - /// Override the `dwFlagsAndAttributes` argument to the call to + /// Overrides the `dwFlagsAndAttributes` argument to the call to /// `CreateFile` with the specified value. /// /// This will override any values of the standard flags on the /// `OpenOptions` structure. fn flags_and_attributes(&mut self, val: i32) -> &mut Self; - /// Override the `dwShareMode` argument to the call to `CreateFile` with + /// Overrides the `dwShareMode` argument to the call to `CreateFile` with /// the specified value. /// /// This will override any values of the standard flags on the diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs deleted file mode 100644 index 0bbb1a9e927..00000000000 --- 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 a9fb2c68227..00000000000 --- 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 e9d5fca531f..1171c6c068b 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 d5843a2f998..5cfc2010424 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::{ @@ -42,7 +39,7 @@ pub fn errno() -> i32 { unsafe { libc::GetLastError() as i32 } } -/// Get a detailed string description for the given error number +/// Gets a detailed string description for the given error number. pub fn error_string(errnum: i32) -> String { use libc::types::os::arch::extra::DWORD; use libc::types::os::arch::extra::LPWSTR; @@ -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 064c003bd15..00000000000 --- 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 b10042090dd..00000000000 --- 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 41e97dc8475..00000000000 --- 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 8856cc26b2e..00000000000 --- 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 791c7532bd0..00000000000 --- 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 50f8fb828ad..00000000000 --- 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/local.rs b/src/libstd/thread/local.rs index f5a1093be2b..cc4031cc180 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -226,7 +226,7 @@ pub enum LocalKeyState { } impl LocalKey { - /// Acquire a reference to the value in this TLS key. + /// Acquires a reference to the value in this TLS key. /// /// This will lazily initialize the value if this thread has not referenced /// this key yet. diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 0e5fee27ffe..4fd0340f09a 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -67,15 +67,35 @@ //! thread. This means that it can outlive its parent (the thread that spawned //! it), unless this parent is the main thread. //! -//! ## Scoped threads -//! -//! Often a parent thread uses a child thread to perform some particular task, -//! and at some point must wait for the child to complete before continuing. -//! For this scenario, use the `thread::scoped` function: +//! The parent thread can also wait on the completion of the child +//! thread; a call to `spawn` produces a `JoinHandle`, which provides +//! a `join` method for waiting: //! //! ```rust //! use std::thread; //! +//! let child = thread::spawn(move || { +//! // some work here +//! }); +//! // some work here +//! let res = child.join(); +//! ``` +//! +//! The `join` method returns a `Result` containing `Ok` of the final +//! value produced by the child thread, or `Err` of the value given to +//! a call to `panic!` if the child panicked. +//! +//! ## Scoped threads +//! +//! The `spawn` method does not allow the child and parent threads to +//! share any stack data, since that is not safe in general. However, +//! `scoped` makes it possible to share the parent's stack by forcing +//! a join before any relevant stack frames are popped: +//! +//! ```rust +//! # #![feature(scoped)] +//! use std::thread; +//! //! let guard = thread::scoped(move || { //! // some work here //! }); @@ -215,7 +235,7 @@ pub struct Builder { } impl Builder { - /// Generate the base configuration for spawning a thread, from which + /// Generates the base configuration for spawning a thread, from which /// configuration methods can be chained. #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Builder { @@ -225,7 +245,7 @@ impl Builder { } } - /// Name the thread-to-be. Currently the name is used for identification + /// Names the thread-to-be. Currently the name is used for identification /// only in panic messages. #[stable(feature = "rust1", since = "1.0.0")] pub fn name(mut self, name: String) -> Builder { @@ -233,14 +253,14 @@ impl Builder { self } - /// Set the size of the stack for the new thread. + /// Sets the size of the stack for the new thread. #[stable(feature = "rust1", since = "1.0.0")] pub fn stack_size(mut self, size: usize) -> Builder { self.stack_size = Some(size); self } - /// Spawn a new thread, and return a join handle for it. + /// Spawns a new thread, and returns a join handle for it. /// /// The child thread may outlive the parent (unless the parent thread /// is the main thread; the whole process is terminated when the main @@ -253,14 +273,14 @@ impl Builder { /// `io::Result` to capture any failure to create the thread at /// the OS level. #[stable(feature = "rust1", since = "1.0.0")] - pub fn spawn(self, f: F) -> io::Result where - F: FnOnce(), F: Send + 'static + pub fn spawn(self, f: F) -> io::Result> where + F: FnOnce() -> T, F: Send + 'static, T: Send + 'static { self.spawn_inner(Box::new(f)).map(|i| JoinHandle(i)) } - /// Spawn a new child thread that must be joined within a given - /// scope, and return a `JoinGuard`. + /// Spawns a new child thread that must be joined within a given + /// scope, and returns a `JoinGuard`. /// /// The join guard can be used to explicitly join the child thread (via /// `join`), returning `Result`, or it will implicitly join the child @@ -274,7 +294,8 @@ impl Builder { /// Unlike the `scoped` free function, this method yields an /// `io::Result` to capture any failure to create the thread at /// the OS level. - #[stable(feature = "rust1", since = "1.0.0")] + #[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] pub fn scoped<'a, T, F>(self, f: F) -> io::Result> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { @@ -355,7 +376,7 @@ impl Builder { // Free functions //////////////////////////////////////////////////////////////////////////////// -/// Spawn a new thread, returning a `JoinHandle` for it. +/// Spawns a new thread, returning a `JoinHandle` for it. /// /// The join handle will implicitly *detach* the child thread upon being /// dropped. In this case, the child thread may outlive the parent (unless @@ -370,11 +391,13 @@ impl Builder { /// Panics if the OS fails to create a thread; use `Builder::spawn` /// to recover from such errors. #[stable(feature = "rust1", since = "1.0.0")] -pub fn spawn(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static { +pub fn spawn(f: F) -> JoinHandle where + F: FnOnce() -> T, F: Send + 'static, T: Send + 'static +{ Builder::new().spawn(f).unwrap() } -/// Spawn a new *scoped* thread, returning a `JoinGuard` for it. +/// Spawns a new *scoped* thread, returning a `JoinGuard` for it. /// /// The join guard can be used to explicitly join the child thread (via /// `join`), returning `Result`, or it will implicitly join the child @@ -387,7 +410,8 @@ pub fn spawn(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static { /// /// Panics if the OS fails to create a thread; use `Builder::scoped` /// to recover from such errors. -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { @@ -400,7 +424,7 @@ pub fn current() -> Thread { thread_info::current_thread() } -/// Cooperatively give up a timeslice to the OS scheduler. +/// Cooperatively gives up a timeslice to the OS scheduler. #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { unsafe { imp::yield_now() } @@ -413,7 +437,7 @@ pub fn panicking() -> bool { unwind::panicking() } -/// Invoke a closure, capturing the cause of panic if one occurs. +/// Invokes a closure, capturing the cause of panic if one occurs. /// /// This function will return `Ok(())` if the closure does not panic, and will /// return `Err(cause)` if the closure panics. The `cause` returned is the @@ -462,7 +486,7 @@ pub fn catch_panic(f: F) -> Result Ok(result.unwrap()) } -/// Put the current thread to sleep for the specified amount of time. +/// Puts the current thread to sleep for the specified amount of time. /// /// The thread may sleep longer than the duration specified due to scheduling /// specifics or platform-dependent functionality. Note that on unix platforms @@ -482,7 +506,7 @@ pub fn sleep(dur: Duration) { imp::sleep(dur) } -/// Block unless or until the current thread's token is made available (may wake spuriously). +/// Blocks unless or until the current thread's token is made available (may wake spuriously). /// /// See the module doc for more detail. // @@ -501,7 +525,7 @@ pub fn park() { *guard = false; } -/// Block unless or until the current thread's token is made available or +/// Blocks unless or until the current thread's token is made available or /// the specified duration has been reached (may wake spuriously). /// /// The semantics of this function are equivalent to `park()` except that the @@ -573,7 +597,7 @@ impl Thread { } } - /// Get the thread's name. + /// Gets the thread's name. #[stable(feature = "rust1", since = "1.0.0")] pub fn name(&self) -> Option<&str> { self.inner.name.as_ref().map(|s| &**s) @@ -635,27 +659,28 @@ impl JoinInner { /// handle: the ability to join a child thread is a uniquely-owned /// permission. #[stable(feature = "rust1", since = "1.0.0")] -pub struct JoinHandle(JoinInner<()>); +pub struct JoinHandle(JoinInner); -impl JoinHandle { - /// Extract a handle to the underlying thread +impl JoinHandle { + /// Extracts a handle to the underlying thread #[stable(feature = "rust1", since = "1.0.0")] pub fn thread(&self) -> &Thread { &self.0.thread } - /// Wait for the associated thread to finish. + /// Waits for the associated thread to finish. /// /// If the child thread panics, `Err` is returned with the parameter given /// to `panic`. #[stable(feature = "rust1", since = "1.0.0")] - pub fn join(mut self) -> Result<()> { + pub fn join(mut self) -> Result { self.0.join() } } #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for JoinHandle { +#[unsafe_destructor] +impl Drop for JoinHandle { fn drop(&mut self) { if !self.0.joined { unsafe { imp::detach(self.0.native) } @@ -674,7 +699,8 @@ impl Drop for JoinHandle { /// handle: the ability to join a child thread is a uniquely-owned /// permission. #[must_use = "thread will be immediately joined if `JoinGuard` is not used"] -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] pub struct JoinGuard<'a, T: Send + 'a> { inner: JoinInner, _marker: PhantomData<&'a T>, @@ -684,13 +710,13 @@ pub struct JoinGuard<'a, T: Send + 'a> { unsafe impl<'a, T: Send + 'a> Sync for JoinGuard<'a, T> {} impl<'a, T: Send + 'a> JoinGuard<'a, T> { - /// Extract a handle to the thread this guard will join on. + /// Extracts a handle to the thread this guard will join on. #[stable(feature = "rust1", since = "1.0.0")] pub fn thread(&self) -> &Thread { &self.inner.thread } - /// Wait for the associated thread to finish, returning the result of the + /// Waits for the associated thread to finish, returning the result of the /// thread's calculation. /// /// # Panics @@ -706,7 +732,8 @@ impl<'a, T: Send + 'a> JoinGuard<'a, T> { } #[unsafe_destructor] -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> { fn drop(&mut self) { if !self.inner.joined { @@ -728,7 +755,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 +993,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/libstd/thread/scoped_tls.rs b/src/libstd/thread/scoped_tls.rs index fa980954c2f..9c0b4a5d833 100644 --- a/src/libstd/thread/scoped_tls.rs +++ b/src/libstd/thread/scoped_tls.rs @@ -135,7 +135,7 @@ macro_rules! __scoped_thread_local_inner { reason = "scoped TLS has yet to have wide enough use to fully consider \ stabilizing its interface")] impl ScopedKey { - /// Insert a value into this scoped thread local storage slot for a + /// Inserts a value into this scoped thread local storage slot for a /// duration of a closure. /// /// While `cb` is running, the value `t` will be returned by `get` unless @@ -188,7 +188,7 @@ impl ScopedKey { cb() } - /// Get a value out of this scoped variable. + /// Gets a value out of this scoped variable. /// /// This function takes a closure which receives the value of this /// variable. diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 475970ac30a..1505d1e91b8 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -121,6 +121,7 @@ struct ItemFnParts<'a> { decl: &'a ast::FnDecl, unsafety: ast::Unsafety, abi: abi::Abi, + vis: ast::Visibility, generics: &'a ast::Generics, body: &'a Block, id: ast::NodeId, @@ -155,44 +156,50 @@ impl<'a> FnLikeNode<'a> { pub fn body(self) -> &'a Block { self.handle(|i: ItemFnParts<'a>| &*i.body, - |_, _, _: &'a ast::MethodSig, body: &'a ast::Block, _| body, + |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body, |c: ClosureParts<'a>| c.body) } pub fn decl(self) -> &'a FnDecl { self.handle(|i: ItemFnParts<'a>| &*i.decl, - |_, _, sig: &'a ast::MethodSig, _, _| &sig.decl, + |_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl, |c: ClosureParts<'a>| c.decl) } pub fn span(self) -> Span { self.handle(|i: ItemFnParts| i.span, - |_, _, _: &'a ast::MethodSig, _, span| span, + |_, _, _: &'a ast::MethodSig, _, _, span| span, |c: ClosureParts| c.span) } pub fn id(self) -> NodeId { self.handle(|i: ItemFnParts| i.id, - |id, _, _: &'a ast::MethodSig, _, _| id, + |id, _, _: &'a ast::MethodSig, _, _, _| id, |c: ClosureParts| c.id) } pub fn kind(self) -> visit::FnKind<'a> { let item = |p: ItemFnParts<'a>| -> visit::FnKind<'a> { - visit::FkItemFn(p.ident, p.generics, p.unsafety, p.abi) + visit::FkItemFn(p.ident, p.generics, p.unsafety, p.abi, p.vis) }; let closure = |_: ClosureParts| { visit::FkFnBlock }; - let method = |_, ident, sig: &'a ast::MethodSig, _, _| { - visit::FkMethod(ident, sig) + let method = |_, ident, sig: &'a ast::MethodSig, vis, _, _| { + visit::FkMethod(ident, sig, vis) }; self.handle(item, method, closure) } fn handle(self, item_fn: I, method: M, closure: C) -> A where I: FnOnce(ItemFnParts<'a>) -> A, - M: FnOnce(NodeId, ast::Ident, &'a ast::MethodSig, &'a ast::Block, Span) -> A, + M: FnOnce(NodeId, + ast::Ident, + &'a ast::MethodSig, + Option, + &'a ast::Block, + Span) + -> A, C: FnOnce(ClosureParts<'a>) -> A, { match self.node { @@ -200,20 +207,20 @@ impl<'a> FnLikeNode<'a> { ast::ItemFn(ref decl, unsafety, abi, ref generics, ref block) => item_fn(ItemFnParts{ ident: i.ident, decl: &**decl, unsafety: unsafety, body: &**block, - generics: generics, abi: abi, id: i.id, span: i.span + generics: generics, abi: abi, vis: i.vis, id: i.id, span: i.span }), _ => panic!("item FnLikeNode that is not fn-like"), }, ast_map::NodeTraitItem(ti) => match ti.node { ast::MethodTraitItem(ref sig, Some(ref body)) => { - method(ti.id, ti.ident, sig, body, ti.span) + method(ti.id, ti.ident, sig, None, body, ti.span) } _ => panic!("trait method FnLikeNode that is not fn-like"), }, ast_map::NodeImplItem(ii) => { match ii.node { ast::MethodImplItem(ref sig, ref body) => { - method(ii.id, ii.ident, sig, body, ii.span) + method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span) } ast::TypeImplItem(_) | ast::MacImplItem(_) => { diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index c4c2249d029..0ad75c5ec8c 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -440,10 +440,10 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { self.operation.visit_id(node_id); match function_kind { - visit::FkItemFn(_, generics, _, _) => { + visit::FkItemFn(_, generics, _, _, _) => { self.visit_generics_helper(generics) } - visit::FkMethod(_, sig) => { + visit::FkMethod(_, sig, _) => { self.visit_generics_helper(&sig.generics) } visit::FkFnBlock => {} diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index d8c50b5a094..65554efdd68 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 631e5f979d9..00000000000 --- 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/feature_gate.rs b/src/libsyntax/feature_gate.rs index 689b4595d39..a6f8a718b33 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -644,13 +644,13 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { span: Span, _node_id: NodeId) { match fn_kind { - visit::FkItemFn(_, _, _, abi) if abi == Abi::RustIntrinsic => { + visit::FkItemFn(_, _, _, abi, _) if abi == Abi::RustIntrinsic => { self.gate_feature("intrinsics", span, "intrinsics are subject to change") } - visit::FkItemFn(_, _, _, abi) | - visit::FkMethod(_, &ast::MethodSig { abi, .. }) if abi == Abi::RustCall => { + visit::FkItemFn(_, _, _, abi, _) | + visit::FkMethod(_, &ast::MethodSig { abi, .. }, _) if abi == Abi::RustCall => { self.gate_feature("unboxed_closures", span, "rust-call ABI is subject to change") diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index bf95daf8755..3f36d0e8eda 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/parser.rs b/src/libsyntax/parse/parser.rs index a3dd77b8197..e45b7c1df91 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3855,7 +3855,7 @@ impl<'a> Parser<'a> { /// ``` /// where T : Trait + 'b, 'a : 'b /// ``` - fn parse_where_clause(&mut self) -> PResult { + pub fn parse_where_clause(&mut self) -> PResult { let mut where_clause = WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4db85eeea46..2bb74944ce9 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/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 46d196d13fa..3f883fb1172 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -352,6 +352,10 @@ pub fn stmt_to_string(stmt: &ast::Stmt) -> String { $to_string(|s| s.print_stmt(stmt)) } +pub fn attr_to_string(attr: &ast::Attribute) -> String { + $to_string(|s| s.print_attribute(attr)) +} + pub fn item_to_string(i: &ast::Item) -> String { $to_string(|s| s.print_item(i)) } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 5c345c75642..4c70fc9f81f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -35,10 +35,10 @@ use owned_slice::OwnedSlice; #[derive(Copy, Clone)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - FkItemFn(Ident, &'a Generics, Unsafety, Abi), + FkItemFn(Ident, &'a Generics, Unsafety, Abi, Visibility), /// fn foo(&self) - FkMethod(Ident, &'a MethodSig), + FkMethod(Ident, &'a MethodSig, Option), /// |x, y| ... /// proc(x, y) ... @@ -247,7 +247,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_expr(&**expr); } ItemFn(ref declaration, fn_style, abi, ref generics, ref body) => { - visitor.visit_fn(FkItemFn(item.ident, generics, fn_style, abi), + visitor.visit_fn(FkItemFn(item.ident, generics, fn_style, abi, item.vis), &**declaration, &**body, item.span, @@ -600,10 +600,10 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, walk_fn_decl(visitor, function_declaration); match function_kind { - FkItemFn(_, generics, _, _) => { + FkItemFn(_, generics, _, _, _) => { visitor.visit_generics(generics); } - FkMethod(_, sig) => { + FkMethod(_, sig, _) => { visitor.visit_generics(&sig.generics); visitor.visit_explicit_self(&sig.explicit_self); } @@ -625,7 +625,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai walk_fn_decl(visitor, &sig.decl); } MethodTraitItem(ref sig, Some(ref body)) => { - visitor.visit_fn(FkMethod(trait_item.ident, sig), &sig.decl, + visitor.visit_fn(FkMethod(trait_item.ident, sig, None), &sig.decl, body, trait_item.span, trait_item.id); } TypeTraitItem(ref bounds, ref default) => { @@ -642,7 +642,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } match impl_item.node { MethodImplItem(ref sig, ref body) => { - visitor.visit_fn(FkMethod(impl_item.ident, sig), &sig.decl, + visitor.visit_fn(FkMethod(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl, body, impl_item.span, impl_item.id); } TypeImplItem(ref ty) => { diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 94dee5ccc36..a786d24ed85 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 0cff90d61ed..8f3e939f1f4 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 0344d6a46ee..d910367afbf 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 83c39b3f3fa..c21470d4bb3 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-binarytrees.rs b/src/test/bench/shootout-binarytrees.rs index ce050cc7323..61fe6593dc3 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -111,11 +111,11 @@ fn main() { let messages = (min_depth..max_depth + 1).step_by(2).map(|depth| { use std::num::Int; let iterations = 2.pow((max_depth - depth + min_depth) as u32); - thread::scoped(move || inner(depth, iterations)) + thread::spawn(move || inner(depth, iterations)) }).collect::>(); for message in messages { - println!("{}", message.join()); + println!("{}", message.join().unwrap()); } println!("long lived tree of depth {}\t check: {}", diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index 4489a124abe..32504350e42 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -166,7 +166,7 @@ fn fannkuch(n: i32) -> (i32, i32) { for (_, j) in (0..N).zip((0..).step_by(k)) { let max = cmp::min(j+k, perm.max()); - futures.push(thread::scoped(move|| { + futures.push(thread::spawn(move|| { work(perm, j as usize, max as usize) })) } @@ -174,7 +174,7 @@ fn fannkuch(n: i32) -> (i32, i32) { let mut checksum = 0; let mut maxflips = 0; for fut in futures { - let (cs, mf) = fut.join(); + let (cs, mf) = fut.join().unwrap(); checksum += cs; maxflips = cmp::max(maxflips, mf); } diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index effdd67027a..145ab714463 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 78d31faeb51..0474cfb6fc8 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 c190641bfbf..bcd8fbf8852 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-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index db131bcfdc3..07cb120ef0e 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -307,17 +307,17 @@ fn main() { let nb_freqs: Vec<_> = (1..3).map(|i| { let input = input.clone(); - (i, thread::scoped(move|| generate_frequencies(&input, i))) + (i, thread::spawn(move|| generate_frequencies(&input, i))) }).collect(); let occ_freqs: Vec<_> = OCCURRENCES.iter().map(|&occ| { let input = input.clone(); - thread::scoped(move|| generate_frequencies(&input, occ.len())) + thread::spawn(move|| generate_frequencies(&input, occ.len())) }).collect(); for (i, freq) in nb_freqs { - print_frequencies(&freq.join(), i); + print_frequencies(&freq.join().unwrap(), i); } for (&occ, freq) in OCCURRENCES.iter().zip(occ_freqs.into_iter()) { - print_occurrences(&mut freq.join(), occ); + print_occurrences(&mut freq.join().unwrap(), occ); } } diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index d248293103b..f2714d55e5e 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. @@ -82,7 +81,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { let mut precalc_i = Vec::with_capacity(h); let precalc_futures = (0..WORKERS).map(|i| { - thread::scoped(move|| { + thread::spawn(move|| { let mut rs = Vec::with_capacity(w / WORKERS); let mut is = Vec::with_capacity(w / WORKERS); @@ -108,7 +107,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { }).collect::>(); for res in precalc_futures { - let (rs, is) = res.join(); + let (rs, is) = res.join().unwrap(); precalc_r.extend(rs.into_iter()); precalc_i.extend(is.into_iter()); } @@ -123,7 +122,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { let vec_init_r = arc_init_r.clone(); let vec_init_i = arc_init_i.clone(); - thread::scoped(move|| { + thread::spawn(move|| { let mut res: Vec = Vec::with_capacity((chunk_size * w) / 8); let init_r_slice = vec_init_r; @@ -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().unwrap())); } 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 cda90c08f23..7c9f33678a3 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, scoped)] 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/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index 5fcbe773299..b0e8c395673 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -41,7 +41,7 @@ // no-pretty-expanded FIXME #15189 #![allow(non_snake_case)] -#![feature(unboxed_closures, core, os)] +#![feature(unboxed_closures, core, os, scoped)] use std::iter::repeat; use std::thread; 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 d0cb4f23a8c..327e2c9e0f9 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/run-pass/issue-12684.rs b/src/test/compile-fail/issue-24365.rs similarity index 50% rename from src/test/run-pass/issue-12684.rs rename to src/test/compile-fail/issue-24365.rs index 2b899155164..a4df42a8c70 100644 --- a/src/test/run-pass/issue-12684.rs +++ b/src/test/compile-fail/issue-24365.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,19 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +pub enum Attribute { + Code {attr_name_idx: u16}, +} -#![feature(old_io, std_misc)] +pub enum Foo { + Bar +} -use std::time::Duration; -use std::thread; +fn test(a: Foo) { + println!("{}", a.b); //~ ERROR attempted access of field +} 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(); + let x = Attribute::Code { + attr_name_idx: 42, + }; + let z = (&x).attr_name_idx; //~ ERROR attempted access of field + let y = x.attr_name_idx; //~ ERROR attempted access of field } diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs index d611e4a65a6..a1ca59caa33 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 0608e49b28c..7e959a1e920 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/function-prologue-stepping-regular.rs b/src/test/debuginfo/function-prologue-stepping-regular.rs index e1a77b34e7f..b34f1af01f5 100644 --- a/src/test/debuginfo/function-prologue-stepping-regular.rs +++ b/src/test/debuginfo/function-prologue-stepping-regular.rs @@ -126,7 +126,6 @@ // lldb-command:continue #![allow(unused_variables)] -#![feature(old_io)] #![omit_gdb_pretty_printer_section] fn immediate_args(a: isize, b: bool, c: f64) { @@ -157,7 +156,7 @@ fn assignment(mut a: u64, b: u64, c: f64) { } fn function_call(x: u64, y: u64, z: f64) { - std::old_io::stdio::print("Hi!") + println!("Hi!") } fn identifier(x: u64, y: u64, z: f64) -> u64 { diff --git a/src/test/debuginfo/issue13213.rs b/src/test/debuginfo/issue13213.rs index 38b149ef243..13dc0c6d120 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-fail/panic-task-name-owned.rs b/src/test/run-fail/panic-task-name-owned.rs index 8cab9e05f96..561f141100c 100644 --- a/src/test/run-fail/panic-task-name-owned.rs +++ b/src/test/run-fail/panic-task-name-owned.rs @@ -13,9 +13,9 @@ use std::thread::Builder; fn main() { - let r: () = Builder::new().name("owned name".to_string()).scoped(move|| { + let r: () = Builder::new().name("owned name".to_string()).spawn(move|| { panic!("test"); () - }).unwrap().join(); + }).unwrap().join().unwrap(); panic!(); } diff --git a/src/test/run-fail/rt-set-exit-status-panic2.rs b/src/test/run-fail/rt-set-exit-status-panic2.rs index fddff3c5a9f..b4f0d7ceb99 100644 --- a/src/test/run-fail/rt-set-exit-status-panic2.rs +++ b/src/test/run-fail/rt-set-exit-status-panic2.rs @@ -37,7 +37,7 @@ fn r(x:isize) -> r { fn main() { error!("whatever"); - let _t = thread::scoped(move|| { + let _t = thread::spawn(move|| { let _i = r(5); }); panic!(); diff --git a/src/test/run-make/save-analysis/SubDir/mod.rs b/src/test/run-make/save-analysis/SubDir/mod.rs index 23b7d8bbf09..fe84db08da9 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 56da6693939..fe0f32d97d6 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 aa2ce785771..b1fe938767d 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 a70a1600765..0c01a84d1bf 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/issue-15149.rs b/src/test/run-pass-fulldeps/issue-15149.rs similarity index 85% rename from src/test/run-pass/issue-15149.rs rename to src/test/run-pass-fulldeps/issue-15149.rs index f6ffd03c81a..7e64bbdf703 100644 --- a/src/test/run-pass/issue-15149.rs +++ b/src/test/run-pass-fulldeps/issue-15149.rs @@ -9,15 +9,17 @@ // except according to those terms. // no-prefer-dynamic +// ignore-android +#![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 +29,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 +41,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-valgrind/cleanup-stdin.rs b/src/test/run-pass-valgrind/cleanup-stdin.rs index 301c4b91781..dcdce50c1e9 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/atomic-print.rs b/src/test/run-pass/atomic-print.rs index df3b572bce4..ae0a358ac4e 100644 --- a/src/test/run-pass/atomic-print.rs +++ b/src/test/run-pass/atomic-print.rs @@ -27,7 +27,7 @@ fn main(){ if env::args().count() == 2 { let barrier = sync::Arc::new(sync::Barrier::new(2)); let tbarrier = barrier.clone(); - let t = thread::scoped(||{ + let t = thread::spawn(move || { tbarrier.wait(); do_print(1); }); diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 14d8bce061f..f4b62eb2e7c 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 6c58194f857..00000000000 --- 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/clone-with-exterior.rs b/src/test/run-pass/clone-with-exterior.rs index 352733601f2..5a7b1c83dfd 100644 --- a/src/test/run-pass/clone-with-exterior.rs +++ b/src/test/run-pass/clone-with-exterior.rs @@ -22,8 +22,8 @@ struct Pair { pub fn main() { let z: Box<_> = box Pair { a : 10, b : 12}; - let _t = thread::scoped(move|| { + thread::spawn(move|| { assert_eq!(z.a, 10); assert_eq!(z.b, 12); - }); + }).join(); } diff --git a/src/test/run-pass/closure-reform.rs b/src/test/run-pass/closure-reform.rs index fefab45714f..50f05c050b1 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/comm.rs b/src/test/run-pass/comm.rs index 859599596ae..72f623ccfde 100644 --- a/src/test/run-pass/comm.rs +++ b/src/test/run-pass/comm.rs @@ -15,11 +15,12 @@ use std::sync::mpsc::{channel, Sender}; pub fn main() { let (tx, rx) = channel(); - let _t = thread::scoped(move|| { child(&tx) }); + let t = thread::spawn(move|| { child(&tx) }); let y = rx.recv().unwrap(); println!("received"); println!("{}", y); assert_eq!(y, 10); + t.join(); } fn child(c: &Sender) { diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 03bf3851257..df7cedd1c29 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(); + let mut p = Command::new(BLOCK_COMMAND) + .stdin(Stdio::piped()) + .spawn().unwrap(); - assert!(p.signal(0).is_ok()); - - 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 105d421b404..10e8ddc41f3 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 bc11b55d310..00000000000 --- 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 02f6cc70fd5..f9e1b651a49 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 7066b4017af..4a6c8ce70dc 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)] @@ -65,5 +63,4 @@ fn test() { // drop-glue should detect the corruption of (at least one of) // the drop-flags. } - println!("We should never get here."); } diff --git a/src/test/run-pass/extern-call-deep2.rs b/src/test/run-pass/extern-call-deep2.rs index 198745f5b19..b35095171ec 100644 --- a/src/test/run-pass/extern-call-deep2.rs +++ b/src/test/run-pass/extern-call-deep2.rs @@ -42,7 +42,7 @@ fn count(n: libc::uintptr_t) -> libc::uintptr_t { pub fn main() { // Make sure we're on a task with small Rust stacks (main currently // has a large stack) - thread::scoped(move|| { + thread::spawn(move|| { let result = count(1000); println!("result = {}", result); assert_eq!(result, 1000); diff --git a/src/test/run-pass/extern-call-scrub.rs b/src/test/run-pass/extern-call-scrub.rs index e8c9bc76335..39938680681 100644 --- a/src/test/run-pass/extern-call-scrub.rs +++ b/src/test/run-pass/extern-call-scrub.rs @@ -46,9 +46,9 @@ fn count(n: libc::uintptr_t) -> libc::uintptr_t { pub fn main() { // Make sure we're on a task with small Rust stacks (main currently // has a large stack) - let _t = thread::scoped(move|| { + thread::spawn(move|| { let result = count(12); println!("result = {}", result); assert_eq!(result, 2048); - }); + }).join(); } diff --git a/src/test/run-pass/fds-are-cloexec.rs b/src/test/run-pass/fds-are-cloexec.rs index cbf7830513a..3be47e8430d 100644 --- a/src/test/run-pass/fds-are-cloexec.rs +++ b/src/test/run-pass/fds-are-cloexec.rs @@ -34,14 +34,12 @@ fn main() { fn parent() { let file = File::open("Makefile").unwrap(); - let _dir = fs::read_dir("/").unwrap(); let tcp1 = TcpListener::bind("127.0.0.1:0").unwrap(); - assert_eq!(tcp1.as_raw_fd(), file.as_raw_fd() + 2); let tcp2 = tcp1.try_clone().unwrap(); let addr = tcp1.local_addr().unwrap(); - let t = thread::scoped(|| TcpStream::connect(addr).unwrap()); + let t = thread::spawn(move || TcpStream::connect(addr).unwrap()); let tcp3 = tcp1.accept().unwrap().0; - let tcp4 = t.join(); + let tcp4 = t.join().unwrap(); let tcp5 = tcp3.try_clone().unwrap(); let tcp6 = tcp4.try_clone().unwrap(); let udp1 = UdpSocket::bind("127.0.0.1:0").unwrap(); @@ -49,7 +47,6 @@ fn parent() { let status = Command::new(env::args().next().unwrap()) .arg(file.as_raw_fd().to_string()) - .arg((file.as_raw_fd() + 1).to_string()) .arg(tcp1.as_raw_fd().to_string()) .arg(tcp2.as_raw_fd().to_string()) .arg(tcp3.as_raw_fd().to_string()) diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 3a7af097644..ea9db9b1e1f 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -144,6 +144,12 @@ pub fn main() { t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6"); t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); + // Float edge cases + t!(format!("{}", -0.0), "0"); + t!(format!("{:?}", -0.0), "-0"); + t!(format!("{:?}", 0.0), "0"); + + // Test that pointers don't get truncated. { let val = usize::MAX; diff --git a/src/test/run-pass/init-large-type.rs b/src/test/run-pass/init-large-type.rs index 26d58d34b9d..dafa8ee1033 100644 --- a/src/test/run-pass/init-large-type.rs +++ b/src/test/run-pass/init-large-type.rs @@ -26,7 +26,7 @@ const SIZE: usize = 1024 * 1024; fn main() { // do the test in a new thread to avoid (spurious?) stack overflows - let _ = thread::scoped(|| { + thread::spawn(|| { let _memory: [u8; SIZE] = unsafe { init() }; }).join(); } diff --git a/src/test/run-pass/issue-10626.rs b/src/test/run-pass/issue-10626.rs index 2c0811b69e0..0d8f2225485 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-12699.rs b/src/test/run-pass/issue-12699.rs index ac5a9b728b9..1e9f30bb766 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-13494.rs b/src/test/run-pass/issue-13494.rs index d1b1647de78..71897ea68c2 100644 --- a/src/test/run-pass/issue-13494.rs +++ b/src/test/run-pass/issue-13494.rs @@ -26,7 +26,7 @@ fn helper(rx: Receiver>) { fn main() { let (tx, rx) = channel(); - let _t = thread::scoped(move|| { helper(rx) }); + let t = thread::spawn(move|| { helper(rx) }); let (snd, rcv) = channel::(); for _ in 1..100000 { snd.send(1).unwrap(); @@ -38,4 +38,5 @@ fn main() { } } drop(tx); + t.join(); } diff --git a/src/test/run-pass/issue-14901.rs b/src/test/run-pass/issue-14901.rs index 7e7886e3a6e..56683678469 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-18619.rs b/src/test/run-pass/issue-18619.rs deleted file mode 100644 index a256e619216..00000000000 --- 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-20454.rs b/src/test/run-pass/issue-20454.rs index d527d9519cf..522f544a21c 100644 --- a/src/test/run-pass/issue-20454.rs +++ b/src/test/run-pass/issue-20454.rs @@ -13,11 +13,11 @@ use std::thread; fn _foo() { - let _t = thread::scoped(move || { // no need for -> () + thread::spawn(move || { // no need for -> () loop { println!("hello"); } - }); + }).join(); } fn main() {} diff --git a/src/test/run-pass/issue-2904.rs b/src/test/run-pass/issue-2904.rs index b05baa24b7a..2c45d664d89 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 29d963bb704..74e58f31e23 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-3609.rs b/src/test/run-pass/issue-3609.rs index 2167a3df976..61de3c6385e 100644 --- a/src/test/run-pass/issue-3609.rs +++ b/src/test/run-pass/issue-3609.rs @@ -23,7 +23,7 @@ enum Msg } fn foo(name: String, samples_chan: Sender) { - let _t = thread::scoped(move|| { + thread::spawn(move|| { let mut samples_chan = samples_chan; // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. @@ -34,7 +34,7 @@ fn foo(name: String, samples_chan: Sender) { }); samples_chan.send(Msg::GetSamples(name.clone(), callback)); - }); + }).join(); } pub fn main() {} diff --git a/src/test/run-pass/issue-4446.rs b/src/test/run-pass/issue-4446.rs index 9f8d93461a2..9292a9c608e 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 8ec88d55721..2cf0089c6bb 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 8eb10a199ea..5c2c03f9857 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)] +pub trait Writer { + fn write(&mut self, b: &[u8]) -> Result<(), ()>; +} -use std::old_io; - -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 bfaf060e43c..ed67630bcac 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)); + let t = thread::spawn(move||{ + thread::sleep_ms(10); tx.send(()).unwrap(); }); loop { @@ -31,4 +24,5 @@ pub fn main() { Err(TryRecvError::Disconnected) => unreachable!() } } + t.join(); } diff --git a/src/libstd/sys/unix/udp.rs b/src/test/run-pass/issue24353.rs similarity index 77% rename from src/libstd/sys/unix/udp.rs rename to src/test/run-pass/issue24353.rs index 50f8fb828ad..7a41a013927 100644 --- a/src/libstd/sys/unix/udp.rs +++ b/src/test/run-pass/issue24353.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,4 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use sys_common::net::UdpSocket; +fn main() { + return (); + + let x = (); + x +} diff --git a/src/test/run-pass/ivec-tag.rs b/src/test/run-pass/ivec-tag.rs index 8ae084dce8c..3f0daf2610c 100644 --- a/src/test/run-pass/ivec-tag.rs +++ b/src/test/run-pass/ivec-tag.rs @@ -23,9 +23,10 @@ fn producer(tx: &Sender>) { pub fn main() { let (tx, rx) = channel::>(); - let _prod = thread::scoped(move|| { + let prod = thread::spawn(move|| { producer(&tx) }); let _data: Vec = rx.recv().unwrap(); + prod.join(); } diff --git a/src/test/run-pass/kindck-implicit-close-over-mut-var.rs b/src/test/run-pass/kindck-implicit-close-over-mut-var.rs index 11b1d70137d..a81c0846a27 100644 --- a/src/test/run-pass/kindck-implicit-close-over-mut-var.rs +++ b/src/test/run-pass/kindck-implicit-close-over-mut-var.rs @@ -18,12 +18,13 @@ fn foo() { // Here, i is *copied* into the proc (heap closure). // Requires allocation. The proc's copy is not mutable. let mut i = 0; - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { user(i); println!("spawned {}", i) }); i += 1; - println!("original {}", i) + println!("original {}", i); + t.join(); } fn bar() { @@ -31,10 +32,11 @@ fn bar() { // mutable outside of the proc. let mut i = 0; while i < 10 { - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { user(i); }); i += 1; + t.join(); } } @@ -42,12 +44,13 @@ fn car() { // Here, i must be shadowed in the proc to be mutable. let mut i = 0; while i < 10 { - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { let mut i = i; i += 1; user(i); }); i += 1; + t.join(); } } diff --git a/src/test/run-pass/logging-separate-lines.rs b/src/test/run-pass/logging-separate-lines.rs index b27080b65b7..29cfe91eba5 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 25e0b272fd2..1611a2c0722 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/moves-based-on-type-capture-clause.rs b/src/test/run-pass/moves-based-on-type-capture-clause.rs index b6509d28036..c7ef9776367 100644 --- a/src/test/run-pass/moves-based-on-type-capture-clause.rs +++ b/src/test/run-pass/moves-based-on-type-capture-clause.rs @@ -14,7 +14,7 @@ use std::thread; pub fn main() { let x = "Hello world!".to_string(); - let _t = thread::scoped(move|| { + thread::spawn(move|| { println!("{}", x); - }); + }).join(); } 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 f08ed6e7f9c..0d0a5bee8a4 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; @@ -37,11 +37,11 @@ fn recurse() { fn main() { let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "recurse" { - let _t = thread::scoped(recurse); + thread::spawn(recurse).join(); } 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 8887e1937c6..da7342d251e 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 47f83eab4c1..d90b88cbfd5 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 c6adda60679..3096fe4a266 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 abad08c7ac6..31d97305e0b 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/rust-log-filter.rs b/src/test/run-pass/rust-log-filter.rs index 3517e4a29b8..59179206104 100644 --- a/src/test/run-pass/rust-log-filter.rs +++ b/src/test/run-pass/rust-log-filter.rs @@ -40,7 +40,7 @@ impl log::Logger for ChannelLogger { pub fn main() { let (logger, rx) = ChannelLogger::new(); - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { log::set_logger(logger); info!("foo"); @@ -53,4 +53,6 @@ pub fn main() { assert_eq!(rx.recv().unwrap(), "foo bar"); assert_eq!(rx.recv().unwrap(), "bar foo"); assert!(rx.recv().is_err()); + + t.join(); } 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 385c5326c97..dd33c330cfd 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/send-is-not-static-par-for.rs b/src/test/run-pass/send-is-not-static-par-for.rs index 99ae3b7c7d8..5f0902d34d3 100644 --- a/src/test/run-pass/send-is-not-static-par-for.rs +++ b/src/test/run-pass/send-is-not-static-par-for.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(core, std_misc)] +#![feature(core, std_misc, scoped)] use std::thread; use std::sync::Mutex; @@ -25,7 +25,6 @@ fn par_for(iter: I, f: F) f(elem) }) }).collect(); - } fn sum(x: &[i32]) { diff --git a/src/test/run-pass/send-resource.rs b/src/test/run-pass/send-resource.rs index 3f64b2adb63..66878d98c84 100644 --- a/src/test/run-pass/send-resource.rs +++ b/src/test/run-pass/send-resource.rs @@ -32,7 +32,7 @@ fn test(f: isize) -> test { pub fn main() { let (tx, rx) = channel(); - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { let (tx2, rx2) = channel(); tx.send(tx2).unwrap(); @@ -40,4 +40,6 @@ pub fn main() { }); rx.recv().unwrap().send(test(42)).unwrap(); + + t.join(); } diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs index bfc4aee7757..51b369092f0 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/spawn-fn.rs b/src/test/run-pass/spawn-fn.rs index efddf0455cd..4a35ed609e0 100644 --- a/src/test/run-pass/spawn-fn.rs +++ b/src/test/run-pass/spawn-fn.rs @@ -16,13 +16,16 @@ fn x(s: String, n: isize) { } pub fn main() { - let _t = thread::scoped(|| x("hello from first spawned fn".to_string(), 65) ); - let _t = thread::scoped(|| x("hello from second spawned fn".to_string(), 66) ); - let _t = thread::scoped(|| x("hello from third spawned fn".to_string(), 67) ); + let t1 = thread::spawn(|| x("hello from first spawned fn".to_string(), 65) ); + let t2 = thread::spawn(|| x("hello from second spawned fn".to_string(), 66) ); + let t3 = thread::spawn(|| x("hello from third spawned fn".to_string(), 67) ); let mut i = 30; while i > 0 { i = i - 1; println!("parent sleeping"); thread::yield_now(); } + t1.join(); + t2.join(); + t3.join(); } diff --git a/src/test/run-pass/task-comm-0.rs b/src/test/run-pass/task-comm-0.rs index 786dd2c7612..1409caf9c70 100644 --- a/src/test/run-pass/task-comm-0.rs +++ b/src/test/run-pass/task-comm-0.rs @@ -26,7 +26,7 @@ fn test05_start(tx : &Sender) { fn test05() { let (tx, rx) = channel(); - let _t = thread::scoped(move|| { test05_start(&tx) }); + let t = thread::spawn(move|| { test05_start(&tx) }); let mut value: isize = rx.recv().unwrap(); println!("{}", value); value = rx.recv().unwrap(); @@ -34,4 +34,5 @@ fn test05() { value = rx.recv().unwrap(); println!("{}", value); assert_eq!(value, 30); + t.join(); } diff --git a/src/test/run-pass/task-comm-1.rs b/src/test/run-pass/task-comm-1.rs index 9c3466f162b..b3327d82c3e 100644 --- a/src/test/run-pass/task-comm-1.rs +++ b/src/test/run-pass/task-comm-1.rs @@ -17,6 +17,6 @@ pub fn main() { test00(); } fn start() { println!("Started / Finished task."); } fn test00() { - let _ = thread::scoped(move|| start() ).join(); + thread::spawn(move|| start() ).join(); println!("Completing."); } diff --git a/src/test/run-pass/task-comm-10.rs b/src/test/run-pass/task-comm-10.rs index f25bb3ff71a..a796750ef88 100644 --- a/src/test/run-pass/task-comm-10.rs +++ b/src/test/run-pass/task-comm-10.rs @@ -29,10 +29,12 @@ fn start(tx: &Sender>) { pub fn main() { let (tx, rx) = channel(); - let _child = thread::scoped(move|| { start(&tx) }); + let child = thread::spawn(move|| { start(&tx) }); let mut c = rx.recv().unwrap(); c.send("A".to_string()).unwrap(); c.send("B".to_string()).unwrap(); thread::yield_now(); + + child.join(); } diff --git a/src/test/run-pass/task-comm-11.rs b/src/test/run-pass/task-comm-11.rs index ec9ed53c1dc..7af8f5d3b35 100644 --- a/src/test/run-pass/task-comm-11.rs +++ b/src/test/run-pass/task-comm-11.rs @@ -22,8 +22,9 @@ fn start(tx: &Sender>) { pub fn main() { let (tx, rx) = channel(); - let _child = thread::scoped(move|| { + let child = thread::spawn(move|| { start(&tx) }); let _tx = rx.recv().unwrap(); + child.join(); } diff --git a/src/test/run-pass/task-comm-12.rs b/src/test/run-pass/task-comm-12.rs index 03305091a2d..f8d608d3168 100644 --- a/src/test/run-pass/task-comm-12.rs +++ b/src/test/run-pass/task-comm-12.rs @@ -18,7 +18,7 @@ fn start(_task_number: isize) { println!("Started / Finished task."); } fn test00() { let i: isize = 0; - let mut result = thread::scoped(move|| { + let mut result = thread::spawn(move|| { start(i) }); diff --git a/src/test/run-pass/task-comm-13.rs b/src/test/run-pass/task-comm-13.rs index 15ceacd672f..156ddd9c77f 100644 --- a/src/test/run-pass/task-comm-13.rs +++ b/src/test/run-pass/task-comm-13.rs @@ -21,6 +21,6 @@ fn start(tx: &Sender, start: isize, number_of_messages: isize) { pub fn main() { println!("Check that we don't deadlock."); let (tx, rx) = channel(); - let _t = thread::scoped(move|| { start(&tx, 0, 10) }).join(); + let _ = thread::spawn(move|| { start(&tx, 0, 10) }).join(); println!("Joined task"); } diff --git a/src/test/run-pass/task-comm-14.rs b/src/test/run-pass/task-comm-14.rs index 1e2d9fe52df..0048d7d2d73 100644 --- a/src/test/run-pass/task-comm-14.rs +++ b/src/test/run-pass/task-comm-14.rs @@ -21,7 +21,7 @@ pub fn main() { while (i > 0) { println!("{}", i); let tx = tx.clone(); - thread::scoped({let i = i; move|| { child(i, &tx) }}); + thread::spawn({let i = i; move|| { child(i, &tx) }}); i = i - 1; } diff --git a/src/test/run-pass/task-comm-15.rs b/src/test/run-pass/task-comm-15.rs index 2663595aecf..1d853b3e67f 100644 --- a/src/test/run-pass/task-comm-15.rs +++ b/src/test/run-pass/task-comm-15.rs @@ -29,8 +29,9 @@ pub fn main() { // the child's point of view the receiver may die. We should // drop messages on the floor in this case, and not crash! let (tx, rx) = channel(); - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { start(&tx, 10) }); rx.recv(); + t.join(); } diff --git a/src/test/run-pass/task-comm-17.rs b/src/test/run-pass/task-comm-17.rs index de334c77aa3..8f6f971ce35 100644 --- a/src/test/run-pass/task-comm-17.rs +++ b/src/test/run-pass/task-comm-17.rs @@ -22,5 +22,5 @@ fn f() { } pub fn main() { - let _t = thread::scoped(move|| f() ).join(); + thread::spawn(move|| f() ).join(); } diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index 254ad653c48..25f40757b7b 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -42,7 +42,7 @@ fn test00() { let mut results = Vec::new(); while i < number_of_tasks { let tx = tx.clone(); - results.push(thread::scoped({ + results.push(thread::spawn({ let i = i; move|| { test00_start(&tx, i, number_of_messages) diff --git a/src/test/run-pass/task-comm-7.rs b/src/test/run-pass/task-comm-7.rs index a5282b1097e..e37160f979c 100644 --- a/src/test/run-pass/task-comm-7.rs +++ b/src/test/run-pass/task-comm-7.rs @@ -30,19 +30,19 @@ fn test00() { let number_of_messages: isize = 10; let tx2 = tx.clone(); - let _t = thread::scoped(move|| { + let t1 = thread::spawn(move|| { test00_start(&tx2, number_of_messages * 0, number_of_messages); }); let tx2 = tx.clone(); - let _t = thread::scoped(move|| { + let t2 = thread::spawn(move|| { test00_start(&tx2, number_of_messages * 1, number_of_messages); }); let tx2 = tx.clone(); - let _t = thread::scoped(move|| { + let t3 = thread::spawn(move|| { test00_start(&tx2, number_of_messages * 2, number_of_messages); }); let tx2 = tx.clone(); - let _t = thread::scoped(move|| { + let t4 = thread::spawn(move|| { test00_start(&tx2, number_of_messages * 3, number_of_messages); }); @@ -60,4 +60,9 @@ fn test00() { } assert_eq!(sum, number_of_messages * 4 * (number_of_messages * 4 - 1) / 2); + + t1.join(); + t2.join(); + t3.join(); + t4.join(); } diff --git a/src/test/run-pass/task-comm-9.rs b/src/test/run-pass/task-comm-9.rs index 758764aa9fd..d8eec4169e3 100644 --- a/src/test/run-pass/task-comm-9.rs +++ b/src/test/run-pass/task-comm-9.rs @@ -26,7 +26,7 @@ fn test00() { let (tx, rx) = channel(); let number_of_messages: isize = 10; - let result = thread::scoped(move|| { + let result = thread::spawn(move|| { test00_start(&tx, number_of_messages); }); diff --git a/src/test/run-pass/task-life-0.rs b/src/test/run-pass/task-life-0.rs index b97f4355b3e..ba8819fd0b0 100644 --- a/src/test/run-pass/task-life-0.rs +++ b/src/test/run-pass/task-life-0.rs @@ -15,7 +15,7 @@ use std::thread; pub fn main() { - let _t = thread::scoped(move|| child("Hello".to_string()) ); + thread::spawn(move|| child("Hello".to_string()) ).join(); } fn child(_s: String) { diff --git a/src/test/run-pass/task-spawn-move-and-copy.rs b/src/test/run-pass/task-spawn-move-and-copy.rs index 3f18c0c7464..6a84ec47c93 100644 --- a/src/test/run-pass/task-spawn-move-and-copy.rs +++ b/src/test/run-pass/task-spawn-move-and-copy.rs @@ -21,11 +21,13 @@ pub fn main() { let x: Box = box 1; let x_in_parent = &(*x) as *const isize as usize; - let _t = thread::scoped(move || { + let t = thread::spawn(move || { let x_in_child = &(*x) as *const isize as usize; tx.send(x_in_child).unwrap(); }); let x_in_child = rx.recv().unwrap(); assert_eq!(x_in_parent, x_in_child); + + t.join(); } 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 00467e56334..00000000000 --- 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 64f07a60b35..00000000000 --- 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 f6952ad64f1..c47b95bec2b 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 49fac24d0b3..00000000000 --- 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/threads.rs b/src/test/run-pass/threads.rs index 969a42a6f87..184338c3294 100644 --- a/src/test/run-pass/threads.rs +++ b/src/test/run-pass/threads.rs @@ -15,7 +15,7 @@ use std::thread; pub fn main() { let mut i = 10; while i > 0 { - thread::scoped({let i = i; move|| child(i)}); + thread::spawn({let i = i; move|| child(i)}).join(); i = i - 1; } println!("main thread exiting"); diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 02ea7037056..21205a2d7fa 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -83,16 +83,19 @@ pub fn main() { box dogge2 as Box)); let (tx1, rx1) = channel(); let arc1 = arc.clone(); - let _t1 = thread::scoped(move|| { check_legs(arc1); tx1.send(()); }); + let t1 = thread::spawn(move|| { check_legs(arc1); tx1.send(()); }); let (tx2, rx2) = channel(); let arc2 = arc.clone(); - let _t2 = thread::scoped(move|| { check_names(arc2); tx2.send(()); }); + let t2 = thread::spawn(move|| { check_names(arc2); tx2.send(()); }); let (tx3, rx3) = channel(); let arc3 = arc.clone(); - let _t3 = thread::scoped(move|| { check_pedigree(arc3); tx3.send(()); }); + let t3 = thread::spawn(move|| { check_pedigree(arc3); tx3.send(()); }); rx1.recv(); rx2.recv(); rx3.recv(); + t1.join(); + t2.join(); + t3.join(); } fn check_legs(arc: Arc>>) { diff --git a/src/test/run-pass/ufcs-polymorphic-paths.rs b/src/test/run-pass/ufcs-polymorphic-paths.rs index db3581976bb..eec852ae181 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/unique-send-2.rs b/src/test/run-pass/unique-send-2.rs index d80d0e82f4f..c32483f629e 100644 --- a/src/test/run-pass/unique-send-2.rs +++ b/src/test/run-pass/unique-send-2.rs @@ -23,10 +23,10 @@ pub fn main() { let (tx, rx) = channel(); let n = 100; let mut expected = 0; - let _t = (0..n).map(|i| { + let ts = (0..n).map(|i| { expected += i; let tx = tx.clone(); - thread::scoped(move|| { + thread::spawn(move|| { child(&tx, i) }) }).collect::>(); @@ -38,4 +38,6 @@ pub fn main() { } assert_eq!(expected, actual); + + for t in ts { t.join(); } } diff --git a/src/test/run-pass/vector-sort-panic-safe.rs b/src/test/run-pass/vector-sort-panic-safe.rs index acb29d284b9..a51274199b6 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 998360f08ba..1d0004bafa3 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 7fc460c16ef..00000000000 --- 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 196447d71ef..00000000000 --- 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 fd1df49473e..00000000000 --- 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 b55d1f4db07..00000000000 --- 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 e1037f26b7f..00000000000 --- 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 b4924c7b78b..00000000000 --- 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 94faa5540bb..00000000000 --- 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 312e1c814dc..00000000000 --- 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 f8cba044443..00000000000 --- 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 818c8e76d60..00000000000 --- 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 2dee90e9a66..00000000000 --- 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 af63be2aa9e..00000000000 --- 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 65aad38a2b4..00000000000 --- 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/path.rs b/src/libstd/path.rs index 4471b5afa84..b7160df6c92 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -312,7 +312,7 @@ impl<'a> Prefix<'a> { } - /// Determine if the prefix is verbatim, i.e. begins `\\?\`. + /// Determines if the prefix is verbatim, i.e. begins `\\?\`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_verbatim(&self) -> bool { @@ -341,7 +341,7 @@ impl<'a> Prefix<'a> { // Exposed parsing helpers //////////////////////////////////////////////////////////////////////////////// -/// Determine whether the character is one of the permitted path +/// Determines whether the character is one of the permitted path /// separators for the current platform. /// /// # Examples @@ -524,7 +524,7 @@ pub enum Component<'a> { } impl<'a> Component<'a> { - /// Extract the underlying `OsStr` slice + /// Extracts the underlying `OsStr` slice #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { @@ -629,7 +629,7 @@ impl<'a> Components<'a> { } } - /// Extract a slice corresponding to the portion of the path remaining for iteration. + /// Extracts a slice corresponding to the portion of the path remaining for iteration. /// /// # Examples /// @@ -750,7 +750,7 @@ impl<'a> AsRef for Components<'a> { } impl<'a> Iter<'a> { - /// Extract a slice corresponding to the portion of the path remaining for iteration. + /// Extracts a slice corresponding to the portion of the path remaining for iteration. #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { self.inner.as_path() @@ -941,19 +941,19 @@ impl PathBuf { unsafe { mem::transmute(self) } } - /// Allocate an empty `PathBuf`. + /// Allocates an empty `PathBuf`. #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> PathBuf { PathBuf { inner: OsString::new() } } - /// Coerce to a `Path` slice. + /// Coerces to a `Path` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &Path { self } - /// Extend `self` with `path`. + /// Extends `self` with `path`. /// /// If `path` is absolute, it replaces the current path. /// @@ -1064,7 +1064,7 @@ impl PathBuf { true } - /// Consume the `PathBuf`, yielding its internal `OsString` storage + /// Consumes the `PathBuf`, yielding its internal `OsString` storage. #[stable(feature = "rust1", since = "1.0.0")] pub fn into_os_string(self) -> OsString { self.inner @@ -1254,7 +1254,7 @@ impl Path { unsafe { mem::transmute(s.as_ref()) } } - /// Yield the underlying `OsStr` slice. + /// Yields the underlying `OsStr` slice. /// /// # Examples /// @@ -1268,7 +1268,7 @@ impl Path { &self.inner } - /// Yield a `&str` slice if the `Path` is valid unicode. + /// Yields a `&str` slice if the `Path` is valid unicode. /// /// This conversion may entail doing a check for UTF-8 validity. /// @@ -1284,7 +1284,7 @@ impl Path { self.inner.to_str() } - /// Convert a `Path` to a `Cow`. + /// Converts a `Path` to a `Cow`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. /// @@ -1300,7 +1300,7 @@ impl Path { self.inner.to_string_lossy() } - /// Convert a `Path` to an owned `PathBuf`. + /// Converts a `Path` to an owned `PathBuf`. /// /// # Examples /// @@ -1477,7 +1477,7 @@ impl Path { iter_after(self.components().rev(), child.as_ref().components().rev()).is_some() } - /// Extract the stem (non-extension) portion of `self.file()`. + /// Extracts the stem (non-extension) portion of `self.file()`. /// /// The stem is: /// @@ -1500,7 +1500,7 @@ impl Path { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) } - /// Extract the extension of `self.file()`, if possible. + /// Extracts the extension of `self.file()`, if possible. /// /// The extension is: /// @@ -1570,11 +1570,12 @@ impl Path { /// # Examples /// /// ``` - /// use std::path::Path; + /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("/tmp/foo.rs"); /// - /// let new_path = path.with_extension("foo.txt"); + /// let new_path = path.with_extension("txt"); + /// assert_eq!(new_path, PathBuf::from("/tmp/foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { @@ -1714,7 +1715,7 @@ impl cmp::Ord for Path { #[unstable(feature = "std_misc")] #[deprecated(since = "1.0.0", reason = "use std::convert::AsRef instead")] pub trait AsPath { - /// Convert to a `Path`. + /// Converts to a `Path`. #[unstable(feature = "std_misc")] fn as_path(&self) -> &Path; } diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 84a45086767..c93fc13284b 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 cac1540d0ec..610b3b3c019 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -194,7 +194,7 @@ impl Command { self } - /// Set the working directory for the child process. + /// Sets the working directory for the child process. #[stable(feature = "process", since = "1.0.0")] pub fn current_dir>(&mut self, dir: P) -> &mut Command { self.inner.cwd(dir.as_ref().as_ref()); @@ -396,7 +396,7 @@ impl ExitStatus { self.0.success() } - /// Return the exit code of the process, if any. + /// Returns the exit code of the process, if any. /// /// On Unix, this will return `None` if the process was terminated /// by a signal; `std::os::unix` provides an extension trait for @@ -453,7 +453,7 @@ impl Child { unsafe { self.handle.kill() } } - /// Wait for the child to exit completely, returning the status that it + /// Waits 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. /// @@ -474,7 +474,7 @@ impl Child { } } - /// Simultaneously wait for the child to exit and collect all remaining + /// Simultaneously waits for the child to exit and collect all remaining /// output on the stdout/stderr handles, returning a `Output` /// instance. /// @@ -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 fad57323d34..e11a5818966 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 38c57eec684..6c107590237 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 ece6867ddca..60645707c6a 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/sync/barrier.rs b/src/libstd/sync/barrier.rs index ebf4d337749..34fcf6cdadd 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -49,7 +49,7 @@ struct BarrierState { pub struct BarrierWaitResult(bool); impl Barrier { - /// Create a new barrier that can block a given number of threads. + /// Creates a new barrier that can block a given number of threads. /// /// A barrier will block `n`-1 threads which call `wait` and then wake up /// all threads at once when the `n`th thread calls `wait`. @@ -65,7 +65,7 @@ impl Barrier { } } - /// Block the current thread until all threads has rendezvoused here. + /// Blocks the current thread until all threads has rendezvoused here. /// /// Barriers are re-usable after all threads have rendezvoused once, and can /// be used continuously. @@ -97,7 +97,7 @@ impl Barrier { } impl BarrierWaitResult { - /// Return whether this thread from `wait` is the "leader thread". + /// Returns whether this thread from `wait` is the "leader thread". /// /// Only one thread will have `true` returned from their result, all other /// threads will have `false` returned. diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 654b33f1a57..fcb0d2c0b2d 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -102,7 +102,7 @@ impl Condvar { } } - /// Block the current thread until this condition variable receives a + /// Blocks the current thread until this condition variable receives a /// notification. /// /// This function will atomically unlock the mutex specified (represented by @@ -137,7 +137,7 @@ impl Condvar { } } - /// Wait on this condition variable for a notification, timing out after a + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// /// The semantics of this function are equivalent to `wait()` @@ -169,7 +169,7 @@ impl Condvar { self.wait_timeout_ms(guard, dur.num_milliseconds() as u32) } - /// Wait on this condition variable for a notification, timing out after a + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// /// The semantics of this function are equivalent to `wait_timeout` except @@ -189,7 +189,7 @@ impl Condvar { } } - /// Wake up one blocked thread on this condvar. + /// Wakes up one blocked thread on this condvar. /// /// If there is a blocked thread on this condition variable, then it will /// be woken up from its call to `wait` or `wait_timeout`. Calls to @@ -199,7 +199,7 @@ impl Condvar { #[stable(feature = "rust1", since = "1.0.0")] pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } } - /// Wake up all blocked threads on this condvar. + /// Wakes up all blocked threads on this condvar. /// /// This method will ensure that any current waiters on the condition /// variable are awoken. Calls to `notify_all()` are not buffered in any @@ -218,7 +218,7 @@ impl Drop for Condvar { } impl StaticCondvar { - /// Block the current thread until this condition variable receives a + /// Blocks the current thread until this condition variable receives a /// notification. /// /// See `Condvar::wait`. @@ -239,7 +239,7 @@ impl StaticCondvar { } } - /// Wait on this condition variable for a notification, timing out after a + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// /// See `Condvar::wait_timeout`. @@ -260,7 +260,7 @@ impl StaticCondvar { } } - /// Wait on this condition variable for a notification, timing out after a + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// /// The implementation will repeatedly wait while the duration has not @@ -306,21 +306,21 @@ impl StaticCondvar { poison::map_result(guard_result, |g| (g, true)) } - /// Wake up one blocked thread on this condvar. + /// Wakes up one blocked thread on this condvar. /// /// See `Condvar::notify_one`. #[unstable(feature = "std_misc", reason = "may be merged with Condvar in the future")] pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } } - /// Wake up all blocked threads on this condvar. + /// Wakes up all blocked threads on this condvar. /// /// See `Condvar::notify_all`. #[unstable(feature = "std_misc", reason = "may be merged with Condvar in the future")] pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } } - /// Deallocate all resources associated with this static condvar. + /// Deallocates all resources associated with this static condvar. /// /// This method is unsafe to call as there is no guarantee that there are no /// active users of the condvar, and this also doesn't prevent any future diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 93b27b6ce9e..422439fadc1 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -750,7 +750,7 @@ impl Receiver { } } - /// Attempt to wait for a value on this receiver, returning an error if the + /// Attempts to wait for a value on this receiver, returning an error if the /// corresponding channel has hung up. /// /// This function will always block the current thread if there is no data diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index b509b3472ee..b8ad92841f2 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -254,11 +254,11 @@ impl Select { } impl<'rx, T: Send> Handle<'rx, T> { - /// Retrieve the id of this handle. + /// Retrieves the id of this handle. #[inline] pub fn id(&self) -> usize { self.id } - /// Block to receive a value on the underlying receiver, returning `Some` on + /// Blocks to receive a value on the underlying receiver, returning `Some` on /// success or `None` if the channel disconnects. This function has the same /// semantics as `Receiver.recv` pub fn recv(&mut self) -> Result { self.rx.recv() } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 46fb20cd6a2..7896870ea07 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -232,7 +232,7 @@ impl Mutex { } } - /// Determine whether the lock is poisoned. + /// Determines whether the lock is poisoned. /// /// If another thread is active, the lock can still become poisoned at any /// time. You should not trust a `false` value for program correctness diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 258cf1d38a8..948965f5efa 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -51,7 +51,7 @@ pub const ONCE_INIT: Once = Once { }; impl Once { - /// Perform an initialization routine once and only once. The given closure + /// Performs an initialization routine once and only once. The given closure /// will be executed if this is the first time `call_once` has been called, /// and otherwise the routine will *not* be invoked. /// diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index eb6d46a5dda..1ea92d5eff7 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -169,7 +169,7 @@ impl RwLock { RwLockReadGuard::new(&*self.inner, &self.data) } - /// Attempt to acquire this lock with shared read access. + /// Attempts to acquire this lock with shared read access. /// /// This function will never block and will return immediately if `read` /// would otherwise succeed. Returns `Some` of an RAII guard which will @@ -194,7 +194,7 @@ impl RwLock { } } - /// Lock this rwlock with exclusive write access, blocking the current + /// Locks this rwlock with exclusive write access, blocking the current /// thread until it can be acquired. /// /// This function will not return while other writers or other readers @@ -215,7 +215,7 @@ impl RwLock { RwLockWriteGuard::new(&*self.inner, &self.data) } - /// Attempt to lock this rwlock with exclusive write access. + /// Attempts to lock this rwlock with exclusive write access. /// /// This function does not ever block, and it will return `None` if a call /// to `write` would otherwise block. If successful, an RAII guard is @@ -237,7 +237,7 @@ impl RwLock { } } - /// Determine whether the lock is poisoned. + /// Determines whether the lock is poisoned. /// /// If another thread is active, the lock can still become poisoned at any /// time. You should not trust a `false` value for program correctness @@ -287,7 +287,7 @@ impl StaticRwLock { RwLockReadGuard::new(self, &DUMMY.0) } - /// Attempt to acquire this lock with shared read access. + /// Attempts to acquire this lock with shared read access. /// /// See `RwLock::try_read`. #[inline] @@ -302,7 +302,7 @@ impl StaticRwLock { } } - /// Lock this rwlock with exclusive write access, blocking the current + /// Locks this rwlock with exclusive write access, blocking the current /// thread until it can be acquired. /// /// See `RwLock::write`. @@ -314,7 +314,7 @@ impl StaticRwLock { RwLockWriteGuard::new(self, &DUMMY.0) } - /// Attempt to lock this rwlock with exclusive write access. + /// Attempts to lock this rwlock with exclusive write access. /// /// See `RwLock::try_write`. #[inline] @@ -329,7 +329,7 @@ impl StaticRwLock { } } - /// Deallocate all resources associated with this static lock. + /// Deallocates all resources associated with this static lock. /// /// This method is unsafe to call as there is no guarantee that there are no /// active users of the lock, and this also doesn't prevent any future users diff --git a/src/libstd/sys/common/condvar.rs b/src/libstd/sys/common/condvar.rs index 32fa6ec5903..9f46b0c3824 100644 --- a/src/libstd/sys/common/condvar.rs +++ b/src/libstd/sys/common/condvar.rs @@ -31,15 +31,15 @@ impl Condvar { #[inline] pub unsafe fn new() -> Condvar { Condvar(imp::Condvar::new()) } - /// Signal one waiter on this condition variable to wake up. + /// Signals one waiter on this condition variable to wake up. #[inline] pub unsafe fn notify_one(&self) { self.0.notify_one() } - /// Awaken all current waiters on this condition variable. + /// Awakens all current waiters on this condition variable. #[inline] pub unsafe fn notify_all(&self) { self.0.notify_all() } - /// Wait for a signal on the specified mutex. + /// Waits for a signal on the specified mutex. /// /// Behavior is undefined if the mutex is not locked by the current thread. /// Behavior is also undefined if more than one mutex is used concurrently @@ -47,7 +47,7 @@ impl Condvar { #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { self.0.wait(mutex::raw(mutex)) } - /// Wait for a signal on the specified mutex with a timeout duration + /// Waits for a signal on the specified mutex with a timeout duration /// specified by `dur` (a relative time into the future). /// /// Behavior is undefined if the mutex is not locked by the current thread. @@ -58,7 +58,7 @@ impl Condvar { self.0.wait_timeout(mutex::raw(mutex), dur) } - /// Deallocate all resources associated with this condition variable. + /// Deallocates all resources associated with this condition variable. /// /// Behavior is undefined if there are current or will be future users of /// this condition variable. diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 8a01eace889..95294b813ea 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/common/mutex.rs b/src/libstd/sys/common/mutex.rs index 0ca22826700..1f9dd54192c 100644 --- a/src/libstd/sys/common/mutex.rs +++ b/src/libstd/sys/common/mutex.rs @@ -24,14 +24,14 @@ unsafe impl Sync for Mutex {} pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT); impl Mutex { - /// Lock the mutex blocking the current thread until it is available. + /// Locks the mutex blocking the current thread until it is available. /// /// Behavior is undefined if the mutex has been moved between this and any /// previous function call. #[inline] pub unsafe fn lock(&self) { self.0.lock() } - /// Attempt to lock the mutex without blocking, returning whether it was + /// Attempts to lock the mutex without blocking, returning whether it was /// successfully acquired or not. /// /// Behavior is undefined if the mutex has been moved between this and any @@ -39,14 +39,14 @@ impl Mutex { #[inline] pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() } - /// Unlock the mutex. + /// Unlocks the mutex. /// /// Behavior is undefined if the current thread does not actually hold the /// mutex. #[inline] pub unsafe fn unlock(&self) { self.0.unlock() } - /// Deallocate all resources associated with this mutex. + /// Deallocates all resources associated with this mutex. /// /// Behavior is undefined if there are current or will be future users of /// this mutex. diff --git a/src/libstd/sys/common/poison.rs b/src/libstd/sys/common/poison.rs index 347cd0b464e..6deb4a48007 100644 --- a/src/libstd/sys/common/poison.rs +++ b/src/libstd/sys/common/poison.rs @@ -116,7 +116,7 @@ impl Error for PoisonError { } impl PoisonError { - /// Create a `PoisonError`. + /// Creates a `PoisonError`. #[unstable(feature = "std_misc")] pub fn new(guard: T) -> PoisonError { PoisonError { guard: guard } diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys/common/rwlock.rs index f7d7a5715bc..725a09bcc86 100644 --- a/src/libstd/sys/common/rwlock.rs +++ b/src/libstd/sys/common/rwlock.rs @@ -21,7 +21,7 @@ pub struct RWLock(imp::RWLock); pub const RWLOCK_INIT: RWLock = RWLock(imp::RWLOCK_INIT); impl RWLock { - /// Acquire shared access to the underlying lock, blocking the current + /// Acquires shared access to the underlying lock, blocking the current /// thread to do so. /// /// Behavior is undefined if the rwlock has been moved between this and any @@ -29,7 +29,7 @@ impl RWLock { #[inline] pub unsafe fn read(&self) { self.0.read() } - /// Attempt to acquire shared access to this lock, returning whether it + /// Attempts to acquire shared access to this lock, returning whether it /// succeeded or not. /// /// This function does not block the current thread. @@ -39,7 +39,7 @@ impl RWLock { #[inline] pub unsafe fn try_read(&self) -> bool { self.0.try_read() } - /// Acquire write access to the underlying lock, blocking the current thread + /// Acquires write access to the underlying lock, blocking the current thread /// to do so. /// /// Behavior is undefined if the rwlock has been moved between this and any @@ -47,7 +47,7 @@ impl RWLock { #[inline] pub unsafe fn write(&self) { self.0.write() } - /// Attempt to acquire exclusive access to this lock, returning whether it + /// Attempts to acquire exclusive access to this lock, returning whether it /// succeeded or not. /// /// This function does not block the current thread. @@ -57,20 +57,20 @@ impl RWLock { #[inline] pub unsafe fn try_write(&self) -> bool { self.0.try_write() } - /// Unlock previously acquired shared access to this lock. + /// Unlocks previously acquired shared access to this lock. /// /// Behavior is undefined if the current thread does not have shared access. #[inline] pub unsafe fn read_unlock(&self) { self.0.read_unlock() } - /// Unlock previously acquired exclusive access to this lock. + /// Unlocks previously acquired exclusive access to this lock. /// /// Behavior is undefined if the current thread does not currently have /// exclusive access. #[inline] pub unsafe fn write_unlock(&self) { self.0.write_unlock() } - /// Destroy OS-related resources with this RWLock. + /// Destroys OS-related resources with this RWLock. /// /// Behavior is undefined if there are any currently active users of this /// lock. diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index 5995d7ac10f..618a389110a 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -207,7 +207,7 @@ impl StaticKey { } impl Key { - /// Create a new managed OS TLS key. + /// Creates a new managed OS TLS key. /// /// This key will be deallocated when the key falls out of scope. /// diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 987a12293da..34a4a773f8e 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -69,7 +69,7 @@ impl fmt::Debug for CodePoint { } impl CodePoint { - /// Unsafely create a new `CodePoint` without checking the value. + /// Unsafely creates a new `CodePoint` without checking the value. /// /// Only use when `value` is known to be less than or equal to 0x10FFFF. #[inline] @@ -77,9 +77,9 @@ impl CodePoint { CodePoint { value: value } } - /// Create a new `CodePoint` if the value is a valid code point. + /// Creates a new `CodePoint` if the value is a valid code point. /// - /// Return `None` if `value` is above 0x10FFFF. + /// Returns `None` if `value` is above 0x10FFFF. #[inline] pub fn from_u32(value: u32) -> Option { match value { @@ -88,7 +88,7 @@ impl CodePoint { } } - /// Create a new `CodePoint` from a `char`. + /// Creates a new `CodePoint` from a `char`. /// /// Since all Unicode scalar values are code points, this always succeeds. #[inline] @@ -96,15 +96,15 @@ impl CodePoint { CodePoint { value: value as u32 } } - /// Return the numeric value of the code point. + /// Returns the numeric value of the code point. #[inline] pub fn to_u32(&self) -> u32 { self.value } - /// Optionally return a Unicode scalar value for the code point. + /// Optionally returns a Unicode scalar value for the code point. /// - /// Return `None` if the code point is a surrogate (from U+D800 to U+DFFF). + /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). #[inline] pub fn to_char(&self) -> Option { match self.value { @@ -113,9 +113,9 @@ impl CodePoint { } } - /// Return a Unicode scalar value for the code point. + /// Returns a Unicode scalar value for the code point. /// - /// Return `'\u{FFFD}'` (the replacement character “�”) + /// Returns `'\u{FFFD}'` (the replacement character “�”) /// if the code point is a surrogate (from U+D800 to U+DFFF). #[inline] pub fn to_char_lossy(&self) -> char { @@ -151,19 +151,19 @@ impl fmt::Debug for Wtf8Buf { } impl Wtf8Buf { - /// Create an new, empty WTF-8 string. + /// Creates an new, empty WTF-8 string. #[inline] pub fn new() -> Wtf8Buf { Wtf8Buf { bytes: Vec::new() } } - /// Create an new, empty WTF-8 string with pre-allocated capacity for `n` bytes. + /// Creates an new, empty WTF-8 string with pre-allocated capacity for `n` bytes. #[inline] pub fn with_capacity(n: usize) -> Wtf8Buf { Wtf8Buf { bytes: Vec::with_capacity(n) } } - /// Create a WTF-8 string from an UTF-8 `String`. + /// Creates a WTF-8 string from an UTF-8 `String`. /// /// This takes ownership of the `String` and does not copy. /// @@ -173,7 +173,7 @@ impl Wtf8Buf { Wtf8Buf { bytes: string.into_bytes() } } - /// Create a WTF-8 string from an UTF-8 `&str` slice. + /// Creates a WTF-8 string from an UTF-8 `&str` slice. /// /// This copies the content of the slice. /// @@ -183,7 +183,7 @@ impl Wtf8Buf { Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()) } } - /// Create a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. + /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. /// /// This is lossless: calling `.encode_wide()` on the resulting string /// will always return the original code units. @@ -319,7 +319,7 @@ impl Wtf8Buf { self.bytes.truncate(new_len) } - /// Consume the WTF-8 string and try to convert it to UTF-8. + /// Consumes the WTF-8 string and tries to convert it to UTF-8. /// /// This does not copy the data. /// @@ -333,7 +333,7 @@ impl Wtf8Buf { } } - /// Consume the WTF-8 string and convert it lossily to UTF-8. + /// Consumes the WTF-8 string and converts it lossily to UTF-8. /// /// This does not copy the data (but may overwrite parts of it in place). /// @@ -454,7 +454,7 @@ impl fmt::Debug for Wtf8 { } impl Wtf8 { - /// Create a WTF-8 slice from a UTF-8 `&str` slice. + /// Creates a WTF-8 slice from a UTF-8 `&str` slice. /// /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] @@ -462,13 +462,13 @@ impl Wtf8 { unsafe { mem::transmute(value.as_bytes()) } } - /// Return the length, in WTF-8 bytes. + /// Returns the length, in WTF-8 bytes. #[inline] pub fn len(&self) -> usize { self.bytes.len() } - /// Return the code point at `position` if it is in the ASCII range, + /// Returns the code point at `position` if it is in the ASCII range, /// or `b'\xFF' otherwise. /// /// # Panics @@ -482,7 +482,7 @@ impl Wtf8 { } } - /// Return the code point at `position`. + /// Returns the code point at `position`. /// /// # Panics /// @@ -494,7 +494,7 @@ impl Wtf8 { code_point } - /// Return the code point at `position` + /// Returns the code point at `position` /// and the position of the next code point. /// /// # Panics @@ -507,15 +507,15 @@ impl Wtf8 { (CodePoint { value: c }, n) } - /// Return an iterator for the string’s code points. + /// Returns an iterator for the string’s code points. #[inline] pub fn code_points(&self) -> Wtf8CodePoints { Wtf8CodePoints { bytes: self.bytes.iter() } } - /// Try to convert the string to UTF-8 and return a `&str` slice. + /// Tries to convert the string to UTF-8 and return a `&str` slice. /// - /// Return `None` if the string contains surrogates. + /// Returns `None` if the string contains surrogates. /// /// This does not copy the data. #[inline] @@ -528,8 +528,8 @@ impl Wtf8 { } } - /// Lossily convert the string to UTF-8. - /// Return an UTF-8 `&str` slice if the contents are well-formed in UTF-8. + /// Lossily converts the string to UTF-8. + /// Returns an UTF-8 `&str` slice if the contents are well-formed in UTF-8. /// /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). /// @@ -559,7 +559,7 @@ impl Wtf8 { } } - /// Convert the WTF-8 string to potentially ill-formed UTF-16 + /// Converts the WTF-8 string to potentially ill-formed UTF-16 /// and return an iterator of 16-bit code units. /// /// This is lossless: diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs index fa0f14b4807..032fd33b1d3 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; @@ -53,7 +50,7 @@ pub mod io { /// and `AsRawSocket` set of traits. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawFd { - /// Extract the raw file descriptor. + /// Extracts the raw file descriptor. /// /// This method does **not** pass ownership of the raw file descriptor /// to the caller. The descriptor is only guarantee to be valid while @@ -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() } @@ -219,11 +144,11 @@ pub mod ffi { /// Unix-specific extensions to `OsString`. #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { - /// Create an `OsString` from a byte vector. + /// Creates an `OsString` from a byte vector. #[stable(feature = "rust1", since = "1.0.0")] fn from_vec(vec: Vec) -> Self; - /// Yield the underlying byte vector of this `OsString`. + /// Yields the underlying byte vector of this `OsString`. #[stable(feature = "rust1", since = "1.0.0")] fn into_vec(self) -> Vec; } @@ -244,7 +169,7 @@ pub mod ffi { #[stable(feature = "rust1", since = "1.0.0")] fn from_bytes(slice: &[u8]) -> &Self; - /// Get the underlying byte view of the `OsStr` slice. + /// Gets the underlying byte view of the `OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] fn as_bytes(&self) -> &[u8]; } @@ -283,7 +208,7 @@ pub mod fs { /// Unix-specific extensions to `OpenOptions` pub trait OpenOptionsExt { - /// Set the mode bits that a new file will be created with. + /// Sets the mode bits that a new file will be created with. /// /// If a new file is created as part of a `File::open_opts` call then this /// specified `mode` will be used as the permission bits for the new file. diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index d86c77624e8..e5bdb554359 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -28,7 +28,7 @@ impl FileDesc { pub fn raw(&self) -> c_int { self.fd } - /// Extract the actual filedescriptor without closing it. + /// Extracts the actual filedescriptor without closing it. pub fn into_raw(self) -> c_int { let fd = self.fd; unsafe { mem::forget(self) }; diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs deleted file mode 100644 index 6121105f10b..00000000000 --- 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 e8409bb4fd4..a8a6219f398 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 d2220bdec32..5919502abde 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; @@ -86,7 +84,7 @@ pub fn errno() -> i32 { } } -/// Get a detailed string description for the given error number +/// Gets a detailed string description for the given error number. pub fn error_string(errno: i32) -> String { #[cfg(target_os = "linux")] extern { @@ -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 f0071295bf2..00000000000 --- 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 8095325f83d..00000000000 --- 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