diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 3c92fa02f2040..385f1b9e79154 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -14,7 +14,6 @@ #![feature(collections)] #![feature(int_uint)] #![feature(io)] -#![feature(os)] #![feature(path)] #![feature(rustc_private)] #![feature(slicing_syntax, unboxed_closures)] @@ -48,8 +47,7 @@ pub mod common; pub mod errors; pub fn main() { - let args = env::args().map(|s| s.into_string().unwrap()).collect();; - let config = parse_config(args); + let config = parse_config(env::args().collect()); if config.valgrind_path.is_none() && config.force_valgrind { panic!("Can't find Valgrind to run Valgrind tests"); diff --git a/src/compiletest/util.rs b/src/compiletest/util.rs index 078eb7bba20a4..c046a89cba55f 100644 --- a/src/compiletest/util.rs +++ b/src/compiletest/util.rs @@ -40,7 +40,7 @@ pub fn make_new_path(path: &str) -> String { // Windows just uses PATH as the library search path, so we have to // maintain the current value while adding our own - match env::var_string(lib_path_env_var()) { + match env::var(lib_path_env_var()) { Ok(curr) => { format!("{}{}{}", path, path_div(), curr) } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0e6266f9cbc57..87106041c69d7 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -71,6 +71,7 @@ #![feature(box_syntax)] #![feature(optin_builtin_traits)] #![feature(unboxed_closures)] +#![feature(unsafe_no_drop_flag)] #![feature(core)] #![feature(hash)] #![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")), diff --git a/src/libcollections/bench.rs b/src/libcollections/bench.rs index b0a5911720a40..107f6031c1156 100644 --- a/src/libcollections/bench.rs +++ b/src/libcollections/bench.rs @@ -8,103 +8,115 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::*; -use std::rand; -use std::rand::Rng; -use test::{Bencher, black_box}; - -pub fn insert_rand_n(n: usize, - map: &mut M, - b: &mut Bencher, - mut insert: I, - mut remove: R) where - I: FnMut(&mut M, usize), - R: FnMut(&mut M, usize), -{ - // setup - let mut rng = rand::weak_rng(); - - for _ in 0..n { - insert(map, rng.gen::() % n); - } - - // measure - b.iter(|| { - let k = rng.gen::() % n; - insert(map, k); - remove(map, k); - }); - black_box(map); +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 test::black_box; + + let n: usize = $n; + let mut map = $map::new(); + // setup + let mut rng = rand::weak_rng(); + + for _ in 0..n { + let i = rng.gen() % n; + map.insert(i, i); + } + + // measure + b.iter(|| { + let k = rng.gen() % n; + map.insert(k, k); + map.remove(&k); + }); + black_box(map); + } + ) } -pub fn insert_seq_n(n: usize, - map: &mut M, - b: &mut Bencher, - mut insert: I, - mut remove: R) where - I: FnMut(&mut M, usize), - R: FnMut(&mut M, usize), -{ - // setup - for i in 0..n { - insert(map, i * 2); - } - - // measure - let mut i = 1; - b.iter(|| { - insert(map, i); - remove(map, i); - i = (i + 2) % n; - }); - black_box(map); +macro_rules! map_insert_seq_bench { + ($name: ident, $n: expr, $map: ident) => ( + #[bench] + pub fn $name(b: &mut ::test::Bencher) { + use test::black_box; + + let mut map = $map::new(); + let n: usize = $n; + // setup + for i in 0..n { + map.insert(i * 2, i * 2); + } + + // measure + let mut i = 1; + b.iter(|| { + map.insert(i, i); + map.remove(&i); + i = (i + 2) % n; + }); + black_box(map); + } + ) } -pub fn find_rand_n(n: usize, - map: &mut M, - b: &mut Bencher, - mut insert: I, - mut find: F) where - I: FnMut(&mut M, usize), - F: FnMut(&M, usize) -> T, -{ - // setup - let mut rng = rand::weak_rng(); - let mut keys: Vec<_> = (0..n).map(|_| rng.gen::() % n).collect(); - - for k in &keys { - insert(map, *k); - } - - rng.shuffle(&mut keys); - - // measure - let mut i = 0; - b.iter(|| { - let t = find(map, keys[i]); - i = (i + 1) % n; - black_box(t); - }) +macro_rules! map_find_rand_bench { + ($name: ident, $n: expr, $map: ident) => ( + #[bench] + pub fn $name(b: &mut ::test::Bencher) { + use std::rand; + use std::iter::IteratorExt; + use std::rand::Rng; + use test::black_box; + use vec::Vec; + + let mut map = $map::new(); + let n: usize = $n; + + // setup + let mut rng = rand::weak_rng(); + let mut keys: Vec<_> = (0..n).map(|_| rng.gen() % n).collect(); + + for &k in &keys { + map.insert(k, k); + } + + rng.shuffle(&mut keys); + + // measure + let mut i = 0; + b.iter(|| { + let t = map.get(&keys[i]); + i = (i + 1) % n; + black_box(t); + }) + } + ) } -pub fn find_seq_n(n: usize, - map: &mut M, - b: &mut Bencher, - mut insert: I, - mut find: F) where - I: FnMut(&mut M, usize), - F: FnMut(&M, usize) -> T, -{ - // setup - for i in 0..n { - insert(map, i); - } - - // measure - let mut i = 0; - b.iter(|| { - let x = find(map, i); - i = (i + 1) % n; - black_box(x); - }) +macro_rules! map_find_seq_bench { + ($name: ident, $n: expr, $map: ident) => ( + #[bench] + pub fn $name(b: &mut ::test::Bencher) { + use test::black_box; + + let mut map = $map::new(); + let n: usize = $n; + + // setup + for i in 0..n { + map.insert(i, i); + } + + // measure + let mut i = 0; + b.iter(|| { + let x = map.get(&i); + i = (i + 1) % n; + black_box(x); + }) + } + ) } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 2cef08725a2f6..0e4a4002d6a09 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1843,74 +1843,18 @@ mod bench { use test::{Bencher, black_box}; use super::BTreeMap; - use bench::{insert_rand_n, insert_seq_n, find_rand_n, find_seq_n}; - #[bench] - pub fn insert_rand_100(b: &mut Bencher) { - let mut m = BTreeMap::new(); - insert_rand_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - #[bench] - pub fn insert_rand_10_000(b: &mut Bencher) { - let mut m = BTreeMap::new(); - insert_rand_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - // Insert seq - #[bench] - pub fn insert_seq_100(b: &mut Bencher) { - let mut m = BTreeMap::new(); - insert_seq_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - #[bench] - pub fn insert_seq_10_000(b: &mut Bencher) { - let mut m = BTreeMap::new(); - insert_seq_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } + map_insert_rand_bench!{insert_rand_100, 100, BTreeMap} + map_insert_rand_bench!{insert_rand_10_000, 10_000, BTreeMap} - // Find rand - #[bench] - pub fn find_rand_100(b: &mut Bencher) { - let mut m = BTreeMap::new(); - find_rand_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } - - #[bench] - pub fn find_rand_10_000(b: &mut Bencher) { - let mut m = BTreeMap::new(); - find_rand_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_insert_seq_bench!{insert_seq_100, 100, BTreeMap} + map_insert_seq_bench!{insert_seq_10_000, 10_000, BTreeMap} - // Find seq - #[bench] - pub fn find_seq_100(b: &mut Bencher) { - let mut m = BTreeMap::new(); - find_seq_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_find_rand_bench!{find_rand_100, 100, BTreeMap} + map_find_rand_bench!{find_rand_10_000, 10_000, BTreeMap} - #[bench] - pub fn find_seq_10_000(b: &mut Bencher) { - let mut m = BTreeMap::new(); - find_seq_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_find_seq_bench!{find_seq_100, 100, BTreeMap} + map_find_seq_bench!{find_seq_10_000, 10_000, BTreeMap} fn bench_iter(b: &mut Bencher, size: i32) { let mut map = BTreeMap::::new(); diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 5f337528d7807..8f02f9fd580fa 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -401,7 +401,7 @@ //! them with the same character. For example, the `{` character is escaped with //! `{{` and the `}` character is escaped with `}}`. -#![unstable(feature = "std_misc")] +#![stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Formatter, Result, Writer, rt}; pub use core::fmt::{Show, String, Octal, Binary}; diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 0dd48fcfab6e5..460c897b6ad36 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -27,10 +27,12 @@ #![feature(box_patterns)] #![feature(core)] #![feature(hash)] +#![feature(slicing_syntax)] #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(unicode)] -#![feature(unsafe_destructor, slicing_syntax)] +#![feature(unsafe_destructor)] +#![feature(unsafe_no_drop_flag)] #![cfg_attr(test, feature(rand, rustc_private, test))] #![cfg_attr(test, allow(deprecated))] // rand @@ -65,6 +67,8 @@ pub use alloc::boxed; #[macro_use] mod macros; +#[cfg(test)] #[macro_use] mod bench; + pub mod binary_heap; mod bit; mod btree; @@ -102,8 +106,6 @@ pub mod btree_set { } -#[cfg(test)] mod bench; - // FIXME(#14344) this shouldn't be necessary #[doc(hidden)] pub fn fixme_14344_be_sure_to_link_to_collections() {} diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 679754be7490e..b3f398b9cdf49 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -2508,6 +2508,18 @@ mod tests { let wins: &[&[_]] = &[&[1,2,3], &[2,3,4]]; assert_eq!(v.windows(3).collect::>(), wins); assert!(v.windows(6).next().is_none()); + + let wins: &[&[_]] = &[&[3,4], &[2,3], &[1,2]]; + assert_eq!(v.windows(2).rev().collect::>(), wins); + let mut it = v.windows(2); + assert_eq!(it.indexable(), 3); + let win: &[_] = &[1,2]; + assert_eq!(it.idx(0).unwrap(), win); + let win: &[_] = &[2,3]; + assert_eq!(it.idx(1).unwrap(), win); + let win: &[_] = &[3,4]; + assert_eq!(it.idx(2).unwrap(), win); + assert_eq!(it.idx(3), None); } #[test] diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 93d02de9b550e..ba358ada0adac 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -1321,74 +1321,17 @@ mod test_map { #[cfg(test)] mod bench { - use test::Bencher; use super::VecMap; - use bench::{insert_rand_n, insert_seq_n, find_rand_n, find_seq_n}; - #[bench] - pub fn insert_rand_100(b: &mut Bencher) { - let mut m = VecMap::new(); - insert_rand_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - #[bench] - pub fn insert_rand_10_000(b: &mut Bencher) { - let mut m = VecMap::new(); - insert_rand_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - // Insert seq - #[bench] - pub fn insert_seq_100(b: &mut Bencher) { - let mut m = VecMap::new(); - insert_seq_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - #[bench] - pub fn insert_seq_10_000(b: &mut Bencher) { - let mut m = VecMap::new(); - insert_seq_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } + map_insert_rand_bench!{insert_rand_100, 100, VecMap} + map_insert_rand_bench!{insert_rand_10_000, 10_000, VecMap} - // Find rand - #[bench] - pub fn find_rand_100(b: &mut Bencher) { - let mut m = VecMap::new(); - find_rand_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } - - #[bench] - pub fn find_rand_10_000(b: &mut Bencher) { - let mut m = VecMap::new(); - find_rand_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_insert_seq_bench!{insert_seq_100, 100, VecMap} + map_insert_seq_bench!{insert_seq_10_000, 10_000, VecMap} - // Find seq - #[bench] - pub fn find_seq_100(b: &mut Bencher) { - let mut m = VecMap::new(); - find_seq_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_find_rand_bench!{find_rand_100, 100, VecMap} + map_find_rand_bench!{find_rand_10_000, 10_000, VecMap} - #[bench] - pub fn find_seq_10_000(b: &mut Bencher) { - let mut m = VecMap::new(); - find_seq_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_find_seq_bench!{find_seq_100, 100, VecMap} + map_find_seq_bench!{find_seq_10_000, 10_000, VecMap} } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0357b723b3c7a..f940300a26945 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -268,6 +268,7 @@ pub trait Debug { fn fmt(&self, &mut Formatter) -> Result; } +#[allow(deprecated)] impl Debug for T { #[allow(deprecated)] fn fmt(&self, f: &mut Formatter) -> Result { Show::fmt(self, f) } @@ -295,6 +296,7 @@ pub trait Display { fn fmt(&self, &mut Formatter) -> Result; } +#[allow(deprecated)] impl Display for T { #[allow(deprecated)] fn fmt(&self, f: &mut Formatter) -> Result { String::fmt(self, f) } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 5562845e11d6f..050c144b74299 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -262,11 +262,12 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// Beyond requiring that both regions of memory be allocated, it is Undefined Behaviour - /// for source and destination to overlap. Care must also be taken with the ownership of - /// `src` and `dst`. This method semantically moves the values of `src` into `dst`. - /// However it does not drop the contents of `dst`, or prevent the contents of `src` - /// from being dropped or used. + /// Beyond requiring that the program must be allowed to access both regions + /// of memory, it is Undefined Behaviour for source and destination to + /// overlap. Care must also be taken with the ownership of `src` and + /// `dst`. This method semantically moves the values of `src` into `dst`. + /// However it does not drop the contents of `dst`, or prevent the contents + /// of `src` from being dropped or used. /// /// # Examples /// diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 782483a34fc89..a46536e341edd 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1119,8 +1119,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T { /// A version of the call operator that takes an immutable receiver. #[lang="fn"] -#[unstable(feature = "core", - reason = "uncertain about variadic generics, input versus associated types")] +#[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] pub trait Fn { type Output; @@ -1131,8 +1130,7 @@ pub trait Fn { /// A version of the call operator that takes a mutable receiver. #[lang="fn_mut"] -#[unstable(feature = "core", - reason = "uncertain about variadic generics, input versus associated types")] +#[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] pub trait FnMut { type Output; @@ -1143,8 +1141,7 @@ pub trait FnMut { /// A version of the call operator that takes a by-value receiver. #[lang="fn_once"] -#[unstable(feature = "core", - reason = "uncertain about variadic generics, input versus associated types")] +#[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] pub trait FnOnce { type Output; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 459addb09fd72..cf1df4ac423ca 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -41,7 +41,6 @@ use cmp::Ordering::{Less, Equal, Greater}; use cmp; use default::Default; use iter::*; -use num::Int; use ops::{FnMut, self, Index}; use ops::RangeFull; use option::Option; @@ -1179,8 +1178,42 @@ impl<'a, T> Iterator for Windows<'a, T> { if self.size > self.v.len() { (0, Some(0)) } else { - let x = self.v.len() - self.size; - (x.saturating_add(1), x.checked_add(1)) + let size = self.v.len() - self.size + 1; + (size, Some(size)) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Windows<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.size > self.v.len() { + None + } else { + let ret = Some(&self.v[self.v.len()-self.size..]); + self.v = &self.v[..self.v.len()-1]; + ret + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> ExactSizeIterator for Windows<'a, T> {} + +#[unstable(feature = "core", reason = "trait is experimental")] +impl<'a, T> RandomAccessIterator for Windows<'a, T> { + #[inline] + fn indexable(&self) -> uint { + self.size_hint().0 + } + + #[inline] + fn idx(&mut self, index: uint) -> Option<&'a [T]> { + if index + self.size > self.v.len() { + None + } else { + Some(&self.v[index .. index+self.size]) } } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 013b7f27839da..747152a824496 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -34,7 +34,7 @@ use ptr::PtrExt; use raw::{Repr, Slice}; use result::Result::{self, Ok, Err}; use slice::{self, SliceExt}; -use uint; +use usize; macro_rules! delegate_iter { (exact $te:ty : $ti:ty) => { @@ -783,7 +783,7 @@ impl TwoWaySearcher { byteset: byteset, position: 0, - memory: uint::MAX // Dummy value to signify that the period is long + memory: usize::MAX // Dummy value to signify that the period is long } } } @@ -911,7 +911,7 @@ impl Searcher { Naive(NaiveSearcher::new()) } else { let searcher = TwoWaySearcher::new(needle); - if searcher.memory == uint::MAX { // If the period is long + if searcher.memory == usize::MAX { // If the period is long TwoWayLong(searcher) } else { TwoWay(searcher) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 94e4012c5ee13..1dec23059e51d 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -2457,6 +2457,7 @@ pub mod consts { pub const SHUT_RDWR: c_int = 2; } pub mod extra { + use SOCKET; use types::os::arch::c95::{c_int, c_long}; use types::os::arch::extra::{WORD, DWORD, BOOL, HANDLE}; @@ -2663,7 +2664,7 @@ pub mod consts { pub const MAX_PROTOCOL_CHAIN: DWORD = 7; pub const WSAPROTOCOL_LEN: DWORD = 255; - pub const INVALID_SOCKET: DWORD = !0; + pub const INVALID_SOCKET: SOCKET = !0; pub const DETACHED_PROCESS: DWORD = 0x00000008; pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200; diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 15f50188919b0..1fedf49738cdf 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -397,7 +397,7 @@ fn enabled(level: u32, /// This is not threadsafe at all, so initialization is performed through a /// `Once` primitive (and this function is called from that primitive). fn init() { - let (mut directives, filter) = match env::var_string("RUST_LOG") { + let (mut directives, filter) = match env::var("RUST_LOG") { Ok(spec) => directive::parse_logging_spec(&spec[]), Err(..) => (Vec::new(), None), }; diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index e204a2a65958f..20af4dadfcae9 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -130,7 +130,7 @@ impl fmt::Display for Error { pub mod reader { use std::char; - use std::int; + use std::isize; use std::old_io::extensions::u64_from_be_bytes; use std::mem::transmute; use std::num::Int; @@ -440,7 +440,7 @@ pub mod reader { fn read_u8 (&mut self) -> DecodeResult { Ok(doc_as_u8 (try!(self.next_doc(EsU8 )))) } fn read_uint(&mut self) -> DecodeResult { let v = doc_as_u64(try!(self.next_doc(EsUint))); - if v > (::std::uint::MAX as u64) { + if v > (::std::usize::MAX as u64) { Err(IntTooBig(v as uint)) } else { Ok(v as uint) @@ -461,7 +461,7 @@ pub mod reader { } fn read_int(&mut self) -> DecodeResult { let v = doc_as_u64(try!(self.next_doc(EsInt))) as i64; - if v > (int::MAX as i64) || v < (int::MIN as i64) { + if v > (isize::MAX as i64) || v < (isize::MIN as i64) { debug!("FIXME \\#6122: Removing this makes this function miscompile"); Err(IntTooBig(v as uint)) } else { @@ -738,7 +738,6 @@ pub mod writer { }) } - // FIXME (#2741): Provide a function to write the standard rbml header. impl<'a, W: Writer + Seek> Encoder<'a, W> { pub fn new(w: &'a mut W) -> Encoder<'a, W> { Encoder { diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 638ecf4572d5d..a415ff3ed7165 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1768,6 +1768,11 @@ impl LintPass for Stability { stability::check_expr(cx.tcx, e, &mut |id, sp, stab| self.lint(cx, id, sp, stab)); } + + fn check_path(&mut self, cx: &Context, path: &ast::Path, id: ast::NodeId) { + stability::check_path(cx.tcx, path, id, + &mut |id, sp, stab| self.lint(cx, id, sp, stab)); + } } declare_lint! { @@ -2080,12 +2085,26 @@ declare_lint! { "functions marked #[no_mangle] should be exported" } +declare_lint! { + PRIVATE_NO_MANGLE_STATICS, + Warn, + "statics marked #[no_mangle] should be exported" +} + +declare_lint! { + NO_MANGLE_CONST_ITEMS, + Deny, + "const items will not have their symbols exported" +} + #[derive(Copy)] -pub struct PrivateNoMangleFns; +pub struct InvalidNoMangleItems; -impl LintPass for PrivateNoMangleFns { +impl LintPass for InvalidNoMangleItems { fn get_lints(&self) -> LintArray { - lint_array!(PRIVATE_NO_MANGLE_FNS) + lint_array!(PRIVATE_NO_MANGLE_FNS, + PRIVATE_NO_MANGLE_STATICS, + NO_MANGLE_CONST_ITEMS) } fn check_item(&mut self, cx: &Context, it: &ast::Item) { @@ -2098,6 +2117,23 @@ impl LintPass for PrivateNoMangleFns { cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg); } }, + ast::ItemStatic(..) => { + if attr::contains_name(it.attrs.as_slice(), "no_mangle") && + !cx.exported_items.contains(&it.id) { + let msg = format!("static {} is marked #[no_mangle], but not exported", + it.ident); + cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, msg.as_slice()); + } + }, + ast::ItemConst(..) => { + if attr::contains_name(it.attrs.as_slice(), "no_mangle") { + // Const items do not refer to a particular location in memory, and therefore + // don't have anything to attach a symbol to + let msg = "const items should never be #[no_mangle], consider instead using \ + `pub static`"; + cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg); + } + } _ => {}, } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 18628f6903f5d..616af79326d9a 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -213,7 +213,7 @@ impl LintStore { UnstableFeatures, Stability, UnconditionalRecursion, - PrivateNoMangleFns, + InvalidNoMangleItems, ); add_builtin_with_new!(sess, diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 1b2d82e68c19f..3caa0f5b4db4c 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -207,7 +207,7 @@ static PATH_ENTRY_SEPARATOR: &'static str = ":"; /// Returns RUST_PATH as a string, without default paths added pub fn get_rust_path() -> Option { - env::var_string("RUST_PATH").ok() + env::var("RUST_PATH").ok() } /// Returns the value of RUST_PATH, as a list diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 7ba83c62496f3..b792a44d4d89a 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -20,7 +20,7 @@ use middle::cfg; use middle::cfg::CFGIndex; use middle::ty; use std::old_io; -use std::uint; +use std::usize; use std::iter::repeat; use syntax::ast; use syntax::ast_util::IdRange; @@ -48,7 +48,7 @@ pub struct DataFlowContext<'a, 'tcx: 'a, O> { bits_per_id: uint, /// number of words we will use to store bits_per_id. - /// equal to bits_per_id/uint::BITS rounded up. + /// equal to bits_per_id/usize::BITS rounded up. words_per_id: uint, // mapping from node to cfg node index @@ -193,7 +193,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { oper: O, id_range: IdRange, bits_per_id: uint) -> DataFlowContext<'a, 'tcx, O> { - let words_per_id = (bits_per_id + uint::BITS - 1) / uint::BITS; + let words_per_id = (bits_per_id + usize::BITS - 1) / usize::BITS; let num_nodes = cfg.graph.all_nodes().len(); debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \ @@ -202,7 +202,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { analysis_name, id_range, bits_per_id, words_per_id, num_nodes); - let entry = if oper.initial_value() { uint::MAX } else {0}; + let entry = if oper.initial_value() { usize::MAX } else {0}; let gens: Vec<_> = repeat(0).take(num_nodes * words_per_id).collect(); let kills: Vec<_> = repeat(0).take(num_nodes * words_per_id).collect(); @@ -351,13 +351,13 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { for (word_index, &word) in words.iter().enumerate() { if word != 0 { - let base_index = word_index * uint::BITS; - for offset in 0..uint::BITS { + let base_index = word_index * usize::BITS; + for offset in 0..usize::BITS { let bit = 1 << offset; if (word & bit) != 0 { // NB: we round up the total number of bits // that we store in any given bit set so that - // it is an even multiple of uint::BITS. This + // it is an even multiple of usize::BITS. This // means that there may be some stray bits at // the end that do not correspond to any // actual value. So before we callback, check @@ -500,7 +500,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { } fn reset(&mut self, bits: &mut [uint]) { - let e = if self.dfcx.oper.initial_value() {uint::MAX} else {0}; + let e = if self.dfcx.oper.initial_value() {usize::MAX} else {0}; for b in bits { *b = e; } @@ -552,7 +552,7 @@ fn bits_to_string(words: &[uint]) -> String { for &word in words { let mut v = word; - for _ in 0..uint::BYTES { + for _ in 0..usize::BYTES { result.push(sep); result.push_str(&format!("{:02x}", v & 0xFF)[]); v >>= 8; @@ -581,8 +581,8 @@ fn bitwise(out_vec: &mut [uint], fn set_bit(words: &mut [uint], bit: uint) -> bool { debug!("set_bit: words={} bit={}", mut_bits_to_string(words), bit_str(bit)); - let word = bit / uint::BITS; - let bit_in_word = bit % uint::BITS; + let word = bit / usize::BITS; + let bit_in_word = bit % usize::BITS; let bit_mask = 1 << bit_in_word; debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, word); let oldv = words[word]; diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index a157d5d712b58..b2335f91ad986 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -234,7 +234,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { ast_map::NodeImplItem(impl_item) => { match *impl_item { ast::MethodImplItem(ref method) => { - visit::walk_block(self, method.pe_body()); + visit::walk_method_helper(self, method); } ast::TypeImplItem(_) => {} } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index b5904f23ef364..0ce9db1c80f3f 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -50,10 +50,7 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { let any_exe = session.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeExecutable }); - let emit_link = session.opts.output_types.iter().any(|ty| { - *ty == config::OutputTypeExe - }); - if !any_exe || !emit_link { + if !any_exe { // No need to find a main function return } diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 989efdd235dff..4dd7a4a226629 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -33,7 +33,7 @@ #![allow(dead_code)] // still WIP use std::fmt::{Formatter, Error, Debug}; -use std::uint; +use std::usize; use std::collections::BitvSet; pub struct Graph { @@ -64,12 +64,12 @@ impl Debug for Edge { #[derive(Clone, Copy, PartialEq, Debug)] pub struct NodeIndex(pub uint); #[allow(non_upper_case_globals)] -pub const InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX); +pub const InvalidNodeIndex: NodeIndex = NodeIndex(usize::MAX); #[derive(Copy, PartialEq, Debug)] pub struct EdgeIndex(pub uint); #[allow(non_upper_case_globals)] -pub const InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX); +pub const InvalidEdgeIndex: EdgeIndex = EdgeIndex(usize::MAX); // Use a private field here to guarantee no more instances are created: #[derive(Copy, Debug)] diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs index 362919755c35d..67875ae225224 100644 --- a/src/librustc/middle/infer/region_inference/graphviz.rs +++ b/src/librustc/middle/infer/region_inference/graphviz.rs @@ -61,13 +61,13 @@ pub fn maybe_print_constraints_for<'a, 'tcx>(region_vars: &RegionVarBindings<'a, } let requested_node : Option = - env::var_string("RUST_REGION_GRAPH_NODE").ok().and_then(|s| s.parse().ok()); + env::var("RUST_REGION_GRAPH_NODE").ok().and_then(|s| s.parse().ok()); if requested_node.is_some() && requested_node != Some(subject_node) { return; } - let requested_output = env::var_string("RUST_REGION_GRAPH").ok(); + let requested_output = env::var("RUST_REGION_GRAPH").ok(); debug!("requested_output: {:?} requested_node: {:?}", requested_output, requested_node); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 0ed672baf56e6..a086e91f4d9f2 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -13,6 +13,7 @@ use session::Session; use lint; +use middle::def; use middle::ty; use middle::privacy::PublicItems; use metadata::csearch; @@ -277,6 +278,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { fn visit_item(&mut self, item: &ast::Item) { + // When compiling with --test we don't enforce stability on the + // compiler-generated test module, demarcated with `DUMMY_SP` plus the + // name `__test` + if item.span == DUMMY_SP && item.ident.as_str() == "__test" { return } + check_item(self.tcx, item, &mut |id, sp, stab| self.check(id, sp, stab)); visit::walk_item(self, item); @@ -287,6 +293,12 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { &mut |id, sp, stab| self.check(id, sp, stab)); visit::walk_expr(self, ex); } + + fn visit_path(&mut self, path: &ast::Path, id: ast::NodeId) { + check_path(self.tcx, path, id, + &mut |id, sp, stab| self.check(id, sp, stab)); + visit::walk_path(self, path) + } } /// Helper for discovering nodes to check for stability @@ -304,18 +316,6 @@ pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID }; maybe_do_stability_check(tcx, id, item.span, cb); } - ast::ItemTrait(_, _, ref supertraits, _) => { - for t in &**supertraits { - if let ast::TraitTyParamBound(ref t, _) = *t { - let id = ty::trait_ref_to_def_id(tcx, &t.trait_ref); - maybe_do_stability_check(tcx, id, t.trait_ref.path.span, cb); - } - } - } - ast::ItemImpl(_, _, _, Some(ref t), _, _) => { - let id = ty::trait_ref_to_def_id(tcx, t); - maybe_do_stability_check(tcx, id, t.path.span, cb); - } _ => (/* pass */) } } @@ -325,15 +325,8 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, cb: &mut FnMut(ast::DefId, Span, &Option)) { if is_internal(tcx, e.span) { return; } - let mut span = e.span; - + let span; let id = match e.node { - ast::ExprPath(..) | ast::ExprQPath(..) | ast::ExprStruct(..) => { - match tcx.def_map.borrow().get(&e.id) { - Some(&def) => def.def_id(), - None => return - } - } ast::ExprMethodCall(i, _, _) => { span = i.span; let method_call = ty::MethodCall::expr(e.id); @@ -369,6 +362,16 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, maybe_do_stability_check(tcx, id, span, cb); } +pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId, + cb: &mut FnMut(ast::DefId, Span, &Option)) { + let did = match tcx.def_map.borrow().get(&id) { + Some(&def::DefPrimTy(..)) => return, + Some(def) => def.def_id(), + None => return + }; + maybe_do_stability_check(tcx, did, path.span, cb) +} + fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span, cb: &mut FnMut(ast::DefId, Span, &Option)) { if !is_staged_api(tcx, id) { return } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index f69bf31626f62..bddbb7c02baa7 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -63,7 +63,7 @@ mod util; /// either identifying an `impl` (e.g., `impl Eq for int`) that /// provides the required vtable, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Obligation<'tcx, T> { pub cause: ObligationCause<'tcx>, pub recursion_depth: uint, @@ -74,7 +74,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; /// Why did we incur this obligation? Used for error reporting. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -89,7 +89,7 @@ pub struct ObligationCause<'tcx> { pub code: ObligationCauseCode<'tcx> } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, @@ -129,7 +129,7 @@ pub enum ObligationCauseCode<'tcx> { CompareImplMethodObligation, } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct DerivedObligationCause<'tcx> { /// The trait reference of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to @@ -251,7 +251,7 @@ pub enum Vtable<'tcx, N> { /// is `Obligation`, as one might expect. During trans, however, this /// is `()`, because trans only requires a shallow resolution of an /// impl, and nested obligations are satisfied later. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct VtableImplData<'tcx, N> { pub impl_def_id: ast::DefId, pub substs: subst::Substs<'tcx>, diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 9d3ad28e6138b..7d02adea1fa5c 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -54,6 +54,7 @@ pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::type_err<'tcx> } +#[derive(PartialEq, Eq)] enum ProjectionTyCandidate<'tcx> { ParamEnv(ty::PolyProjectionPredicate<'tcx>), Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>), @@ -481,6 +482,25 @@ fn project_type<'cx,'tcx>( // We probably need some winnowing logic similar to select here. + // Drop duplicates. + // + // Note: `candidates.vec` seems to be on the critical path of the + // compiler. Replacing it with an hash set was also tried, which would + // render the following dedup unnecessary. It led to cleaner code but + // prolonged compiling time of `librustc` from 5m30s to 6m in one test, or + // ~9% performance lost. + if candidates.vec.len() > 1 { + let mut i = 0; + while i < candidates.vec.len() { + let has_dup = (0..i).any(|j| candidates.vec[i] == candidates.vec[j]); + if has_dup { + candidates.vec.swap_remove(i); + } else { + i += 1; + } + } + } + if candidates.ambiguous || candidates.vec.len() > 1 { return Err(ProjectionTyError::TooManyCandidates); } diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs index a2ce474eda840..b46454bfdd04e 100644 --- a/src/librustc/plugin/load.rs +++ b/src/librustc/plugin/load.rs @@ -17,7 +17,7 @@ use plugin::registry::Registry; use std::mem; use std::env; use std::dynamic_lib::DynamicLibrary; -use std::collections::HashSet; +use std::collections::{HashSet, HashMap}; use std::borrow::ToOwned; use syntax::ast; use syntax::attr; @@ -116,6 +116,8 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate, return loader.plugins; } +pub type MacroSelection = HashMap; + // note that macros aren't expanded yet, and therefore macros can't add plugins. impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { fn visit_item(&mut self, item: &ast::Item) { @@ -128,9 +130,9 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { } } - // Parse the attributes relating to macro / plugin loading. - let mut macro_selection = Some(HashSet::new()); // None => load all - let mut reexport = HashSet::new(); + // Parse the attributes relating to macro loading. + let mut import = Some(HashMap::new()); // None => load all + let mut reexport = HashMap::new(); for attr in &item.attrs { let mut used = true; match &attr.name()[] { @@ -147,14 +149,14 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { let names = attr.meta_item_list(); if names.is_none() { // no names => load all - macro_selection = None; + import = None; } - if let (Some(sel), Some(names)) = (macro_selection.as_mut(), names) { - for name in names { - if let ast::MetaWord(ref name) = name.node { - sel.insert(name.clone()); + if let (Some(sel), Some(names)) = (import.as_mut(), names) { + for attr in names { + if let ast::MetaWord(ref name) = attr.node { + sel.insert(name.clone(), attr.span); } else { - self.sess.span_err(name.span, "bad macro import"); + self.sess.span_err(attr.span, "bad macro import"); } } } @@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { } }; - for name in names { - if let ast::MetaWord(ref name) = name.node { - reexport.insert(name.clone()); + for attr in names { + if let ast::MetaWord(ref name) = attr.node { + reexport.insert(name.clone(), attr.span); } else { - self.sess.span_err(name.span, "bad macro reexport"); + self.sess.span_err(attr.span, "bad macro reexport"); } } } @@ -183,7 +185,7 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { } } - self.load_macros(item, macro_selection, Some(reexport)) + self.load_macros(item, import, reexport) } fn visit_mac(&mut self, _: &ast::Mac) { @@ -195,10 +197,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { impl<'a> PluginLoader<'a> { pub fn load_macros<'b>(&mut self, vi: &ast::Item, - macro_selection: Option>, - reexport: Option>) { - if let (Some(sel), Some(re)) = (macro_selection.as_ref(), reexport.as_ref()) { - if sel.is_empty() && re.is_empty() { + import: Option, + reexport: MacroSelection) { + if let Some(sel) = import.as_ref() { + if sel.is_empty() && reexport.is_empty() { return; } } @@ -211,19 +213,32 @@ impl<'a> PluginLoader<'a> { let pmd = self.reader.read_plugin_metadata(CrateOrString::Krate(vi)); + let mut seen = HashSet::new(); for mut def in pmd.exported_macros() { let name = token::get_ident(def.ident); - def.use_locally = match macro_selection.as_ref() { + seen.insert(name.clone()); + + def.use_locally = match import.as_ref() { None => true, - Some(sel) => sel.contains(&name), - }; - def.export = if let Some(ref re) = reexport { - re.contains(&name) - } else { - false // Don't reexport macros from crates loaded from the command line + Some(sel) => sel.contains_key(&name), }; + def.export = reexport.contains_key(&name); self.plugins.macros.push(def); } + + if let Some(sel) = import.as_ref() { + for (name, span) in sel.iter() { + if !seen.contains(name) { + self.sess.span_err(*span, "imported macro not found"); + } + } + } + + for (name, span) in reexport.iter() { + if !seen.contains(name) { + self.sess.span_err(*span, "reexported macro not found"); + } + } } pub fn load_plugin<'b>(&mut self, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 949fee45517e2..8340a49b92ae3 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1052,7 +1052,7 @@ pub fn get_unstable_features_setting() -> UnstableFeatures { // subverting the unstable features lints let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY"); // The matching key to the above, only known by the build system - let bootstrap_provided_key = env::var_string("RUSTC_BOOTSTRAP_KEY").ok(); + let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok(); match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) { (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat, (true, _, _) => UnstableFeatures::Disallow, diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index afb5c948f1885..4d90c492fa240 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -384,7 +384,7 @@ impl Target { Path::new(target) }; - let target_path = env::var("RUST_TARGET_PATH") + let target_path = env::var_os("RUST_TARGET_PATH") .unwrap_or(OsString::from_str("")); // FIXME 16351: add a sane default search path? diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 6607b5cac9c1d..9c5ddc06519b9 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -24,7 +24,7 @@ use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc::util::ppaux::Repr; use std::cell::RefCell; use std::rc::Rc; -use std::uint; +use std::usize; use syntax::ast; use syntax::ast_util; use syntax::codemap::Span; @@ -92,7 +92,7 @@ impl Clone for MovePathIndex { #[allow(non_upper_case_globals)] static InvalidMovePathIndex: MovePathIndex = - MovePathIndex(uint::MAX); + MovePathIndex(usize::MAX); /// Index into `MoveData.moves`, used like a pointer #[derive(Copy, PartialEq)] @@ -106,7 +106,7 @@ impl MoveIndex { #[allow(non_upper_case_globals)] static InvalidMoveIndex: MoveIndex = - MoveIndex(uint::MAX); + MoveIndex(usize::MAX); pub struct MovePath<'tcx> { /// Loan path corresponding to this move path diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d82c160fdee9b..12f5041cad14f 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -464,7 +464,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, // compiler, not for the target. let mut _old_path = OsString::from_str(""); if cfg!(windows) { - _old_path = env::var("PATH").unwrap_or(_old_path); + _old_path = env::var_os("PATH").unwrap_or(_old_path); let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths(); new_path.extend(env::split_paths(&_old_path)); env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap()); @@ -737,7 +737,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session, pub fn phase_6_link_output(sess: &Session, trans: &trans::CrateTranslation, outputs: &OutputFilenames) { - let old_path = env::var("PATH").unwrap_or(OsString::from_str("")); + let old_path = env::var_os("PATH").unwrap_or(OsString::from_str("")); let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(); new_path.extend(env::split_paths(&old_path)); env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap()); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index ef6e84d3a7641..b087c0c2aa1c9 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -771,7 +771,7 @@ pub fn monitor(f: F) { // FIXME: Hacks on hacks. If the env is trying to override the stack size // then *don't* set it explicitly. - if env::var("RUST_MIN_STACK").is_none() { + if env::var_os("RUST_MIN_STACK").is_none() { cfg = cfg.stack_size(STACK_SIZE); } @@ -835,8 +835,7 @@ pub fn diagnostics_registry() -> diagnostics::registry::Registry { } pub fn main() { - let args = env::args().map(|s| s.into_string().unwrap()); - let result = run(args.collect()); + let result = run(env::args().collect()); std::env::set_exit_status(result as i32); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0913a245c1b50..dc1e91cd14bbd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -101,7 +101,7 @@ use std::cell::{Cell, RefCell}; use std::fmt; use std::mem::replace; use std::rc::{Rc, Weak}; -use std::uint; +use std::usize; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -4370,7 +4370,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { for rib in this.value_ribs.iter().rev() { for (&k, _) in &rib.bindings { maybes.push(token::get_name(k)); - values.push(uint::MAX); + values.push(usize::MAX); } } @@ -4384,7 +4384,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if values.len() > 0 && - values[smallest] != uint::MAX && + values[smallest] != usize::MAX && values[smallest] < name.len() + 2 && values[smallest] <= max_distance && name != &maybes[smallest][] { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 8a30806f3b601..68f413eff85c6 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -658,14 +658,18 @@ pub fn run_passes(sess: &Session, } // Produce final compile outputs. + let copy_gracefully = |from: &Path, to: &Path| { + if let Err(e) = fs::copy(from, to) { + sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e)); + } + }; let copy_if_one_unit = |ext: &str, output_type: config::OutputType, keep_numbered: bool| { // Three cases: if sess.opts.cg.codegen_units == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - fs::copy(&crate_output.with_extension(ext), - &crate_output.path(output_type)).unwrap(); + copy_gracefully(&crate_output.with_extension(ext), &crate_output.path(output_type)); if !sess.opts.cg.save_temps && !keep_numbered { // The user just wants `foo.x`, not `foo.0.x`. remove(sess, &crate_output.with_extension(ext)); @@ -687,8 +691,7 @@ pub fn run_passes(sess: &Session, let link_obj = |output_path: &Path| { // Running `ld -r` on a single input is kind of pointless. if sess.opts.cg.codegen_units == 1 { - fs::copy(&crate_output.with_extension("0.o"), - output_path).unwrap(); + copy_gracefully(&crate_output.with_extension("0.o"), output_path); // Leave the .0.o file around, to mimic the behavior of the normal // code path. return; diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index e80564097df23..cdcd917ee5eb4 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -1551,7 +1551,7 @@ pub fn process_crate(sess: &Session, info!("Dumping crate {}", cratename); // find a path to dump our data to - let mut root_path = match env::var_string("DXR_RUST_TEMP_FOLDER") { + let mut root_path = match env::var("DXR_RUST_TEMP_FOLDER") { Ok(val) => Path::new(val), Err(..) => match odir { Some(val) => val.join("dxr"), diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d490ea5408d77..5ad2dc2871c52 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -79,6 +79,7 @@ This API is completely unstable and subject to change. #![feature(collections)] #![feature(core)] #![feature(int_uint)] +#![feature(std_misc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0253aaa31ca36..9d45caf76696a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -122,10 +122,10 @@ struct Output { } pub fn main() { - static STACK_SIZE: uint = 32000000; // 32MB + const STACK_SIZE: usize = 32000000; // 32MB let res = std::thread::Builder::new().stack_size(STACK_SIZE).scoped(move || { - let s = env::args().map(|s| s.into_string().unwrap()); - main_args(&s.collect::>()) + let s = env::args().collect::>(); + main_args(&s) }).join(); env::set_exit_status(res.ok().unwrap() as i32); } diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 4e023039de7c8..abd73fcfb7028 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -12,7 +12,7 @@ use std::collections::HashSet; use rustc::util::nodemap::NodeSet; use std::cmp; use std::string::String; -use std::uint; +use std::usize; use syntax::ast; use syntax::ast_util; @@ -310,7 +310,7 @@ pub fn unindent(s: &str) -> String { let lines = s.lines_any().collect:: >(); let mut saw_first_line = false; let mut saw_second_line = false; - let min_indent = lines.iter().fold(uint::MAX, |min_indent, line| { + let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| { // After we see the first non-whitespace line, look at // the line we have. If it is not whitespace, and therefore @@ -322,7 +322,7 @@ pub fn unindent(s: &str) -> String { !line.chars().all(|c| c.is_whitespace()); let min_indent = if ignore_previous_indents { - uint::MAX + usize::MAX } else { min_indent }; diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index 53d3b069467d3..f81edca837198 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -10,7 +10,7 @@ //! Implementations of serialization for structures found in libcollections -use std::uint; +use std::usize; use std::default::Default; use std::hash::{Hash, Hasher}; use std::collections::hash_state::HashState; @@ -148,7 +148,7 @@ impl< fn decode(d: &mut D) -> Result, D::Error> { let bits = try!(d.read_uint()); let mut set = EnumSet::new(); - for bit in 0..uint::BITS { + for bit in 0..usize::BITS { if bits & (1 << bit) != 0 { set.insert(CLike::from_usize(1 << bit)); } diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index e86ee4a73cea9..4579d1f19d3f0 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -31,6 +31,7 @@ Core encoding and decoding interfaces. #![feature(int_uint)] #![feature(io)] #![feature(path)] +#![feature(hash)] #![feature(rustc_private)] #![feature(slicing_syntax)] #![feature(staged_api)] diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index bee9a0d00337b..c5dd66630b420 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -101,7 +101,7 @@ impl DynamicLibrary { /// Returns the current search path for dynamic libraries being used by this /// process pub fn search_path() -> Vec { - match env::var(DynamicLibrary::envvar()) { + match env::var_os(DynamicLibrary::envvar()) { Some(var) => env::split_paths(&var).collect(), None => Vec::new(), } diff --git a/src/libstd/env.rs b/src/libstd/env.rs index e73797bc66c7f..ea18838211f26 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -71,17 +71,29 @@ static ENV_LOCK: StaticMutex = MUTEX_INIT; /// An iterator over a snapshot of the environment variables of this process. /// -/// This iterator is created through `std::env::vars()` and yields `(OsString, -/// OsString)` pairs. -pub struct Vars { inner: os_imp::Env } +/// This iterator is created through `std::env::vars()` and yields `(String, +/// String)` pairs. +pub struct Vars { inner: VarsOs } -/// Returns an iterator of (variable, value) pairs, for all the environment -/// variables of the current process. +/// An iterator over a snapshot of the environment variables of this process. +/// +/// This iterator is created through `std::env::vars_os()` and yields +/// `(OsString, OsString)` pairs. +pub struct VarsOs { inner: os_imp::Env } + +/// Returns an iterator of (variable, value) pairs of strings, for all the +/// environment variables of the current process. /// /// The returned iterator contains a snapshot of the process's environment /// variables at the time of this invocation, modifications to environment /// variables afterwards will not be reflected in the returned iterator. /// +/// # Panics +/// +/// While iterating, the returned iterator will panic if any key or value in the +/// environment is not valid unicode. If this is not desired, consider using the +/// `env::vars_os` function. +/// /// # Example /// /// ```rust @@ -90,37 +102,50 @@ pub struct Vars { inner: os_imp::Env } /// // We will iterate through the references to the element returned by /// // env::vars(); /// for (key, value) in env::vars() { -/// println!("{:?}: {:?}", key, value); +/// println!("{}: {}", key, value); /// } /// ``` pub fn vars() -> Vars { - let _g = ENV_LOCK.lock(); - Vars { inner: os_imp::env() } -} - -impl Iterator for Vars { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() } - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + Vars { inner: vars_os() } } -/// Fetches the environment variable `key` from the current process, returning -/// None if the variable isn't set. +/// Returns an iterator of (variable, value) pairs of OS strings, for all the +/// environment variables of the current process. +/// +/// The returned iterator contains a snapshot of the process's environment +/// variables at the time of this invocation, modifications to environment +/// variables afterwards will not be reflected in the returned iterator. /// /// # Example /// /// ```rust /// use std::env; /// -/// let key = "HOME"; -/// match env::var(key) { -/// Some(val) => println!("{}: {:?}", key, val), -/// None => println!("{} is not defined in the environment.", key) +/// // We will iterate through the references to the element returned by +/// // env::vars_os(); +/// for (key, value) in env::vars_os() { +/// println!("{:?}: {:?}", key, value); /// } /// ``` -pub fn var(key: &K) -> Option where K: AsOsStr { +pub fn vars_os() -> VarsOs { let _g = ENV_LOCK.lock(); - os_imp::getenv(key.as_os_str()) + VarsOs { inner: os_imp::env() } +} + +impl Iterator for Vars { + type Item = (String, String); + fn next(&mut self) -> Option<(String, String)> { + self.inner.next().map(|(a, b)| { + (a.into_string().unwrap(), b.into_string().unwrap()) + }) + } + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } +} + +impl Iterator for VarsOs { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() } + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } /// Fetches the environment variable `key` from the current process. @@ -135,18 +160,37 @@ pub fn var(key: &K) -> Option where K: AsOsStr { /// use std::env; /// /// let key = "HOME"; -/// match env::var_string(key) { +/// match env::var(key) { /// Ok(val) => println!("{}: {:?}", key, val), /// Err(e) => println!("couldn't interpret {}: {}", key, e), /// } /// ``` -pub fn var_string(key: &K) -> Result where K: AsOsStr { - match var(key) { +pub fn var(key: &K) -> Result where K: AsOsStr { + match var_os(key) { Some(s) => s.into_string().map_err(VarError::NotUnicode), None => Err(VarError::NotPresent) } } +/// Fetches the environment variable `key` from the current process, returning +/// None if the variable isn't set. +/// +/// # Example +/// +/// ```rust +/// use std::env; +/// +/// let key = "HOME"; +/// match env::var_os(key) { +/// Some(val) => println!("{}: {:?}", key, val), +/// None => println!("{} is not defined in the environment.", key) +/// } +/// ``` +pub fn var_os(key: &K) -> Option where K: AsOsStr { + let _g = ENV_LOCK.lock(); + os_imp::getenv(key.as_os_str()) +} + /// Possible errors from the `env::var` method. #[derive(Debug, PartialEq, Eq, Clone)] pub enum VarError { @@ -190,7 +234,7 @@ impl Error for VarError { /// /// let key = "KEY"; /// env::set_var(key, "VALUE"); -/// assert_eq!(env::var_string(key), Ok("VALUE".to_string())); +/// assert_eq!(env::var(key), Ok("VALUE".to_string())); /// ``` pub fn set_var(k: &K, v: &V) where K: AsOsStr, V: AsOsStr @@ -222,7 +266,7 @@ pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> } /// use std::env; /// /// let key = "PATH"; -/// match env::var(key) { +/// match env::var_os(key) { /// Some(paths) => { /// for path in env::split_paths(&paths) { /// println!("'{}'", path.display()); @@ -262,7 +306,7 @@ pub struct JoinPathsError { /// ```rust /// use std::env; /// -/// if let Some(path) = env::var("PATH") { +/// if let Some(path) = env::var_os("PATH") { /// let mut paths = env::split_paths(&path).collect::>(); /// paths.push(Path::new("/home/xyz/bin")); /// let new_path = env::join_paths(paths.iter()).unwrap(); @@ -376,11 +420,17 @@ pub fn get_exit_status() -> i32 { EXIT_STATUS.load(Ordering::SeqCst) as i32 } -/// An iterator over the arguments of a process, yielding an `OsString` value +/// An iterator over the arguments of a process, yielding an `String` value /// for each argument. /// /// This structure is created through the `std::env::args` method. -pub struct Args { inner: os_imp::Args } +pub struct Args { inner: ArgsOs } + +/// An iterator over the arguments of a process, yielding an `OsString` value +/// for each argument. +/// +/// This structure is created through the `std::env::args_os` method. +pub struct ArgsOs { inner: os_imp::Args } /// Returns the arguments which this program was started with (normally passed /// via the command line). @@ -389,6 +439,12 @@ pub struct Args { inner: os_imp::Args } /// set to arbitrary text, and it may not even exist, so this property should /// not be relied upon for security purposes. /// +/// # Panics +/// +/// The returned iterator will panic during iteration if any argument to the +/// process is not valid unicode. If this is not desired it is recommended to +/// use the `args_os` function instead. +/// /// # Example /// /// ```rust @@ -396,14 +452,43 @@ pub struct Args { inner: os_imp::Args } /// /// // Prints each argument on a separate line /// for argument in env::args() { -/// println!("{:?}", argument); +/// println!("{}", argument); /// } /// ``` pub fn args() -> Args { - Args { inner: os_imp::args() } + Args { inner: args_os() } +} + +/// Returns the arguments which this program was started with (normally passed +/// via the command line). +/// +/// The first element is traditionally the path to the executable, but it can be +/// set to arbitrary text, and it may not even exist, so this property should +/// not be relied upon for security purposes. +/// +/// # Example +/// +/// ```rust +/// use std::env; +/// +/// // Prints each argument on a separate line +/// for argument in env::args_os() { +/// println!("{:?}", argument); +/// } +/// ``` +pub fn args_os() -> ArgsOs { + ArgsOs { inner: os_imp::args() } } impl Iterator for Args { + type Item = String; + fn next(&mut self) -> Option { + self.inner.next().map(|s| s.into_string().unwrap()) + } + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } +} + +impl Iterator for ArgsOs { type Item = OsString; fn next(&mut self) -> Option { self.inner.next() } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } @@ -706,7 +791,7 @@ mod tests { let n = format!("TEST{}", rng.gen_ascii_chars().take(10) .collect::()); let n = OsString::from_string(n); - assert!(var(&n).is_none()); + assert!(var_os(&n).is_none()); n } @@ -718,7 +803,7 @@ mod tests { fn test_set_var() { let n = make_rand_name(); set_var(&n, "VALUE"); - eq(var(&n), Some("VALUE")); + eq(var_os(&n), Some("VALUE")); } #[test] @@ -726,7 +811,7 @@ mod tests { let n = make_rand_name(); set_var(&n, "VALUE"); remove_var(&n); - eq(var(&n), None); + eq(var_os(&n), None); } #[test] @@ -734,9 +819,9 @@ mod tests { let n = make_rand_name(); set_var(&n, "1"); set_var(&n, "2"); - eq(var(&n), Some("2")); + eq(var_os(&n), Some("2")); set_var(&n, ""); - eq(var(&n), Some("")); + eq(var_os(&n), Some("")); } #[test] @@ -749,7 +834,7 @@ mod tests { } let n = make_rand_name(); set_var(&n, s.as_slice()); - eq(var(&n), Some(s.as_slice())); + eq(var_os(&n), Some(s.as_slice())); } #[test] @@ -767,22 +852,22 @@ mod tests { let n = make_rand_name(); let s = repeat("x").take(10000).collect::(); set_var(&n, &s); - eq(var(&n), Some(s.as_slice())); + eq(var_os(&n), Some(s.as_slice())); remove_var(&n); - eq(var(&n), None); + eq(var_os(&n), None); } #[test] fn test_env_set_var() { let n = make_rand_name(); - let mut e = vars(); + let mut e = vars_os(); set_var(&n, "VALUE"); assert!(!e.any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); - assert!(vars().any(|(k, v)| { + assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 967789dd41144..83f0b7bc0e92b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -111,7 +111,7 @@ #![feature(core)] #![feature(hash)] #![feature(int_uint)] -#![feature(lang_items, unsafe_destructor)] +#![feature(lang_items)] #![feature(libc)] #![feature(linkage, thread_local, asm)] #![feature(old_impl_check)] @@ -120,6 +120,8 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(unicode)] +#![feature(unsafe_destructor)] +#![feature(unsafe_no_drop_flag)] #![feature(macro_reexport)] #![cfg_attr(test, feature(test))] @@ -164,6 +166,7 @@ pub use core::cell; pub use core::clone; #[cfg(not(test))] pub use core::cmp; pub use core::default; +#[allow(deprecated)] pub use core::finally; pub use core::hash; pub use core::intrinsics; @@ -250,6 +253,7 @@ pub mod ffi; pub mod old_io; pub mod io; pub mod fs; +pub mod net; pub mod os; pub mod env; pub mod path; @@ -306,8 +310,8 @@ mod std { pub use marker; // used for tls! pub use ops; // used for bitflags! - // The test runner calls ::std::os::args() but really wants realstd - #[cfg(test)] pub use realstd::os as os; + // The test runner calls ::std::env::args() but really wants realstd + #[cfg(test)] pub use realstd::env as env; // The test runner requires std::slice::Vector, so re-export std::slice just for it. // // It is also used in vec![] diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs new file mode 100644 index 0000000000000..66d4d34f8eb54 --- /dev/null +++ b/src/libstd/net/addr.rs @@ -0,0 +1,592 @@ +// 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. + +use prelude::v1::*; + +use fmt; +use hash; +use io; +use libc::{self, socklen_t, sa_family_t}; +use mem; +use net::{IpAddr, lookup_host, ntoh, hton}; +use option; +use sys_common::{FromInner, AsInner, IntoInner}; +use vec; + +/// Representation of a socket address for networking applications +/// +/// A socket address consists of at least an (ip, port) pair and may also +/// contain other information depending on the protocol. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct SocketAddr { + repr: Repr, +} + +#[derive(Copy)] +enum Repr { + V4(libc::sockaddr_in), + V6(libc::sockaddr_in6), +} + +impl SocketAddr { + /// Creates a new socket address from the (ip, port) pair. + pub fn new(ip: IpAddr, port: u16) -> SocketAddr { + let repr = match ip { + IpAddr::V4(ref ip) => { + Repr::V4(libc::sockaddr_in { + sin_family: libc::AF_INET as sa_family_t, + sin_port: hton(port), + sin_addr: *ip.as_inner(), + .. unsafe { mem::zeroed() } + }) + } + IpAddr::V6(ref ip) => { + Repr::V6(libc::sockaddr_in6 { + sin6_family: libc::AF_INET6 as sa_family_t, + sin6_port: hton(port), + sin6_addr: *ip.as_inner(), + .. unsafe { mem::zeroed() } + }) + } + }; + SocketAddr { repr: repr } + } + + /// Gets the IP address associated with this socket address. + pub fn ip(&self) -> IpAddr { + match self.repr { + Repr::V4(ref sa) => IpAddr::V4(FromInner::from_inner(sa.sin_addr)), + Repr::V6(ref sa) => IpAddr::V6(FromInner::from_inner(sa.sin6_addr)), + } + } + + /// Gets the port number associated with this socket address + pub fn port(&self) -> u16 { + match self.repr { + Repr::V4(ref sa) => ntoh(sa.sin_port), + Repr::V6(ref sa) => ntoh(sa.sin6_port), + } + } + + fn set_port(&mut self, port: u16) { + match self.repr { + Repr::V4(ref mut sa) => sa.sin_port = hton(port), + Repr::V6(ref mut sa) => sa.sin6_port = hton(port), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for SocketAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.repr { + Repr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()), + Repr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()), + } + } +} + +impl FromInner for SocketAddr { + fn from_inner(addr: libc::sockaddr_in) -> SocketAddr { + SocketAddr { repr: Repr::V4(addr) } + } +} + +impl FromInner for SocketAddr { + fn from_inner(addr: libc::sockaddr_in6) -> SocketAddr { + SocketAddr { repr: Repr::V6(addr) } + } +} + +impl<'a> IntoInner<(*const libc::sockaddr, socklen_t)> for &'a SocketAddr { + fn into_inner(self) -> (*const libc::sockaddr, socklen_t) { + match self.repr { + Repr::V4(ref a) => { + (a as *const _ as *const _, mem::size_of_val(a) as socklen_t) + } + Repr::V6(ref a) => { + (a as *const _ as *const _, mem::size_of_val(a) as socklen_t) + } + } + } +} + +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +impl Clone for Repr { + fn clone(&self) -> Repr { *self } +} + +impl PartialEq for Repr { + fn eq(&self, other: &Repr) -> bool { + match (*self, *other) { + (Repr::V4(ref a), Repr::V4(ref b)) => { + a.sin_port == b.sin_port && + a.sin_addr.s_addr == b.sin_addr.s_addr + } + (Repr::V6(ref a), Repr::V6(ref b)) => { + a.sin6_port == b.sin6_port && + a.sin6_addr.s6_addr == b.sin6_addr.s6_addr && + a.sin6_flowinfo == b.sin6_flowinfo && + a.sin6_scope_id == b.sin6_scope_id + } + _ => false, + } + } +} +impl Eq for Repr {} + +impl hash::Hash for Repr { + fn hash(&self, s: &mut S) { + match *self { + Repr::V4(ref a) => { + (a.sin_family, a.sin_port, a.sin_addr.s_addr).hash(s) + } + Repr::V6(ref a) => { + (a.sin6_family, a.sin6_port, &a.sin6_addr.s6_addr, + a.sin6_flowinfo, a.sin6_scope_id).hash(s) + } + } + } +} + +/// A trait for objects which can be converted or resolved to one or more +/// `SocketAddr` values. +/// +/// This trait is used for generic address resolution when constructing network +/// objects. By default it is implemented for the following types: +/// +/// * `SocketAddr` - `to_socket_addrs` is identity function. +/// +/// * `(IpAddr, u16)` - `to_socket_addrs` 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. +/// +/// * `&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. +/// +/// 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: +/// +/// ```no_run +/// use std::net::{IpAddr, SocketAddr, TcpStream, UdpSocket, TcpListener}; +/// +/// fn main() { +/// let ip = IpAddr::new_v4(127, 0, 0, 1); +/// let port = 12345; +/// +/// // The following lines are equivalent modulo possible "localhost" name +/// // resolution differences +/// let tcp_s = TcpStream::connect(&SocketAddr::new(ip, port)); +/// let tcp_s = TcpStream::connect(&(ip, port)); +/// let tcp_s = TcpStream::connect(&("127.0.0.1", port)); +/// let tcp_s = TcpStream::connect(&("localhost", port)); +/// 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", port)).unwrap(); +/// udp_s.send_to(&[7], &(ip, 23451)); +/// } +/// ``` +pub trait ToSocketAddrs { + /// Returned iterator over socket addresses which this type may correspond + /// to. + type Iter: Iterator; + + /// Converts this object to an iterator of resolved `SocketAddr`s. + /// + /// The returned iterator may not actually yield any values depending on the + /// outcome of any resolution performed. + /// + /// Note that this function may block the current thread while resolution is + /// performed. + /// + /// # Errors + /// + /// Any errors encountered during resolution will be returned as an `Err`. + fn to_socket_addrs(&self) -> io::Result; +} + +impl ToSocketAddrs for SocketAddr { + type Iter = option::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + Ok(Some(*self).into_iter()) + } +} + +impl ToSocketAddrs for (IpAddr, u16) { + type Iter = option::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + let (ip, port) = *self; + Ok(Some(SocketAddr::new(ip, port)).into_iter()) + } +} + +fn resolve_socket_addr(s: &str, p: u16) -> io::Result> { + let ips = try!(lookup_host(s)); + let v: Vec<_> = try!(ips.map(|a| { + a.map(|mut a| { a.set_port(p); a }) + }).collect()); + Ok(v.into_iter()) +} + +impl<'a> ToSocketAddrs for (&'a str, u16) { + type Iter = vec::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + let (host, port) = *self; + + // try to parse the host as a regular IpAddr first + match host.parse().ok() { + Some(addr) => return Ok(vec![SocketAddr::new(addr, port)].into_iter()), + None => {} + } + + resolve_socket_addr(host, port) + } +} + +// accepts strings like 'localhost:12345' +impl ToSocketAddrs for str { + type Iter = vec::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + // try to parse as a regular SocketAddr first + match self.parse().ok() { + Some(addr) => return Ok(vec![addr].into_iter()), + None => {} + } + + macro_rules! try_opt { + ($e:expr, $msg:expr) => ( + match $e { + Some(r) => r, + None => return Err(io::Error::new(io::ErrorKind::InvalidInput, + $msg, None)), + } + ) + } + + // split the string by ':' and convert the second part to u16 + let mut parts_iter = self.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, T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'a T { + type Iter = T::Iter; + fn to_socket_addrs(&self) -> io::Result { + (**self).to_socket_addrs() + } +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use io; + use net::*; + use net::Ipv6MulticastScope::*; + + #[test] + fn test_from_str_ipv4() { + assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); + assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); + assert_eq!(Ok(Ipv4Addr::new(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::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); + + assert_eq!(Ok(Ipv6Addr::new(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::new(0, 0, 0, 0, 0, 0, 49152, 545)), + "::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), + "::FFFF:192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + "64:ff9b::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(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::new(IpAddr::new_v4(77, 88, 21, 11), 80)), + "77.88.21.11:80".parse()); + assert_eq!(Ok(SocketAddr::new(IpAddr::new_v6(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), + "[2a02:6b8:0:1::1]:53".parse()); + assert_eq!(Ok(SocketAddr::new(IpAddr::new_v6(0, 0, 0, 0, 0, 0, 0x7F00, 1), 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() { + // ipv4-mapped address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); + + // ipv4-compatible address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::192.0.2.128"); + + // v6 address with no zero segments + assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), + "8:9:a:b:c:d:e:f"); + + // reduce a single run of zeros + assert_eq!("ae::ffff:102:304", + Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()); + + // don't reduce just a single zero segment + assert_eq!("1:2:3:4:5:6:0:8", + Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); + + // 'any' address + assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // loopback address + assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); + + // ends in zeros + assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // two runs of zeros, second one is longer + assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); + + // two runs of zeros, equal length + assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); + } + + #[test] + fn ipv4_to_ipv6() { + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()); + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()); + } + + #[test] + fn ipv6_to_ipv4() { + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); + assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), + None); + } + + #[test] + fn ipv4_properties() { + fn check(octets: &[u8; 4], unspec: bool, loopback: bool, + private: bool, link_local: bool, global: bool, + multicast: bool) { + let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]); + assert_eq!(octets, &ip.octets()); + + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_private(), private); + assert_eq!(ip.is_link_local(), link_local); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_multicast(), multicast); + } + + // 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); + } + + #[test] + fn ipv6_properties() { + fn check(str_addr: &str, unspec: bool, loopback: bool, + unique_local: bool, global: bool, + u_link_local: bool, u_site_local: bool, u_global: bool, + m_scope: Option) { + let ip: Ipv6Addr = str_addr.parse().ok().unwrap(); + assert_eq!(str_addr, ip.to_string()); + + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_unique_local(), unique_local); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_unicast_link_local(), u_link_local); + assert_eq!(ip.is_unicast_site_local(), u_site_local); + assert_eq!(ip.is_unicast_global(), u_global); + assert_eq!(ip.multicast_scope(), m_scope); + assert_eq!(ip.is_multicast(), m_scope.is_some()); + } + + // unspec loopbk uniqlo global unill unisl uniglo mscope + check("::", + true, false, false, true, false, false, true, None); + check("::1", + false, true, false, false, false, false, false, None); + check("::0.0.0.2", + false, false, false, true, false, false, true, None); + check("1::", + false, false, false, true, false, false, true, None); + check("fc00::", + false, false, true, false, false, false, false, None); + check("fdff:ffff::", + false, false, true, false, false, false, false, None); + check("fe80:ffff::", + false, false, false, false, true, false, false, None); + check("febf:ffff::", + false, false, false, false, true, false, false, None); + check("fec0::", + false, false, false, false, false, true, false, None); + check("ff01::", + false, false, false, false, false, false, false, Some(InterfaceLocal)); + check("ff02::", + false, false, false, false, false, false, false, Some(LinkLocal)); + check("ff03::", + false, false, false, false, false, false, false, Some(RealmLocal)); + check("ff04::", + false, false, false, false, false, false, false, Some(AdminLocal)); + check("ff05::", + false, false, false, false, false, false, false, Some(SiteLocal)); + check("ff08::", + false, false, false, false, false, false, false, Some(OrganizationLocal)); + check("ff0e::", + false, false, false, true, false, false, false, Some(Global)); + } + + fn tsa(a: A) -> io::Result> { + Ok(try!(a.to_socket_addrs()).collect()) + } + + #[test] + fn to_socket_addr_socketaddr() { + let a = SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 12345); + assert_eq!(Ok(vec![a]), tsa(a)); + } + + #[test] + fn to_socket_addr_ipaddr_u16() { + let a = IpAddr::new_v4(77, 88, 21, 11); + let p = 12345u16; + let e = SocketAddr::new(a, p); + assert_eq!(Ok(vec![e]), tsa((a, p))); + } + + #[test] + fn to_socket_addr_str_u16() { + let a = SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352u16))); + + let a = SocketAddr::new(IpAddr::new_v6(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); + assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53))); + + let a = SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1), 23924); + assert!(tsa(("localhost", 23924u16)).unwrap().contains(&a)); + } + + #[test] + fn to_socket_addr_str() { + let a = SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352")); + + let a = SocketAddr::new(IpAddr::new_v6(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); + assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53")); + + let a = SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1), 23924); + assert!(tsa("localhost:23924").unwrap().contains(&a)); + } +} diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs new file mode 100644 index 0000000000000..08f7a6e2e9636 --- /dev/null +++ b/src/libstd/net/ip.rs @@ -0,0 +1,449 @@ +// 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. + +use prelude::v1::*; + +use cmp::Ordering; +use hash; +use fmt; +use libc; +use sys_common::{AsInner, FromInner}; +use net::{hton, ntoh}; + +/// Representation of an IPv4 address. +#[derive(Copy)] +pub struct Ipv4Addr { + inner: libc::in_addr, +} + +/// Representation of an IPv6 address. +#[derive(Copy)] +pub struct Ipv6Addr { + inner: libc::in6_addr, +} + +#[allow(missing_docs)] +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +pub enum Ipv6MulticastScope { + InterfaceLocal, + LinkLocal, + RealmLocal, + AdminLocal, + SiteLocal, + OrganizationLocal, + Global +} + +/// Enumeration of possible IP addresses +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +pub enum IpAddr { + /// An IPv4 address. + V4(Ipv4Addr), + /// An IPv6 address. + V6(Ipv6Addr) +} + +impl IpAddr { + /// Create a new IpAddr that contains an IPv4 address. + /// + /// The result will represent the IP address a.b.c.d + pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { + IpAddr::V4(Ipv4Addr::new(a, b, c, d)) + } + + /// Create a new IpAddr that contains an IPv6 address. + /// + /// The result will represent the IP address a:b:c:d:e:f + pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, + h: u16) -> IpAddr { + IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for IpAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + IpAddr::V4(v4) => v4.fmt(f), + IpAddr::V6(v6) => v6.fmt(f) + } + } +} + +impl Ipv4Addr { + /// Create a new IPv4 address from four eight-bit octets. + /// + /// The result will represent the IP address a.b.c.d + pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + Ipv4Addr { + inner: libc::in_addr { + s_addr: hton(((a as u32) << 24) | + ((b as u32) << 16) | + ((c as u32) << 8) | + (d as u32)), + } + } + } + + /// Returns the four eight-bit integers that make up this address + pub fn octets(&self) -> [u8; 4] { + let bits = ntoh(self.inner.s_addr); + [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] + } + + /// Returns true for the special 'unspecified' address 0.0.0.0 + pub fn is_unspecified(&self) -> bool { + self.inner.s_addr == 0 + } + + /// Returns true if this is a loopback address (127.0.0.0/8) + pub fn is_loopback(&self) -> bool { + self.octets()[0] == 127 + } + + /// Returns true if this is a private address. + /// + /// The private address ranges are defined in RFC1918 and include: + /// + /// - 10.0.0.0/8 + /// - 172.16.0.0/12 + /// - 192.168.0.0/16 + pub fn is_private(&self) -> bool { + match (self.octets()[0], self.octets()[1]) { + (10, _) => true, + (172, b) if b >= 16 && b <= 31 => true, + (192, 168) => true, + _ => false + } + } + + /// Returns true if the address is link-local (169.254.0.0/16) + pub fn is_link_local(&self) -> bool { + self.octets()[0] == 169 && self.octets()[1] == 254 + } + + /// Returns true if the address appears to be globally routable. + /// + /// 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). + pub fn is_global(&self) -> bool { + !self.is_private() && !self.is_loopback() && !self.is_link_local() + } + + /// Returns true if this is a multicast address. + /// + /// Multicast addresses have a most significant octet between 224 and 239. + pub fn is_multicast(&self) -> bool { + self.octets()[0] >= 224 && self.octets()[0] <= 239 + } + + /// Convert this address to an IPv4-compatible IPv6 address + /// + /// a.b.c.d becomes ::a.b.c.d + pub fn to_ipv6_compatible(&self) -> Ipv6Addr { + Ipv6Addr::new(0, 0, 0, 0, 0, 0, + ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16, + ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) + } + + /// Convert this address to an IPv4-mapped IPv6 address + /// + /// a.b.c.d becomes ::ffff:a.b.c.d + pub fn to_ipv6_mapped(&self) -> Ipv6Addr { + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, + ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16, + ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) + } + +} + +impl fmt::Display for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let octets = self.octets(); + write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) + } +} + +impl fmt::Debug for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +impl Clone for Ipv4Addr { + fn clone(&self) -> Ipv4Addr { *self } +} + +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &Ipv4Addr) -> bool { + self.inner.s_addr == other.inner.s_addr + } +} +impl Eq for Ipv4Addr {} + +impl hash::Hash for Ipv4Addr { + fn hash(&self, s: &mut S) { + self.inner.s_addr.hash(s) + } +} + +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Ipv4Addr { + fn cmp(&self, other: &Ipv4Addr) -> Ordering { + self.inner.s_addr.cmp(&other.inner.s_addr) + } +} + +impl AsInner for Ipv4Addr { + fn as_inner(&self) -> &libc::in_addr { &self.inner } +} +impl FromInner for Ipv4Addr { + fn from_inner(addr: libc::in_addr) -> Ipv4Addr { + Ipv4Addr { inner: addr } + } +} + +impl Ipv6Addr { + /// Create a new IPv6 address from eight 16-bit segments. + /// + /// The result will represent the IP address a:b:c:d:e:f + pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, + h: u16) -> Ipv6Addr { + Ipv6Addr { + inner: libc::in6_addr { + s6_addr: [hton(a), hton(b), hton(c), hton(d), + hton(e), hton(f), hton(g), hton(h)] + } + } + } + + /// Return the eight 16-bit segments that make up this address + pub fn segments(&self) -> [u16; 8] { + [ntoh(self.inner.s6_addr[0]), + ntoh(self.inner.s6_addr[1]), + ntoh(self.inner.s6_addr[2]), + ntoh(self.inner.s6_addr[3]), + ntoh(self.inner.s6_addr[4]), + ntoh(self.inner.s6_addr[5]), + ntoh(self.inner.s6_addr[6]), + ntoh(self.inner.s6_addr[7])] + } + + /// Returns true for the special 'unspecified' address :: + pub fn is_unspecified(&self) -> bool { + self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] + } + + /// Returns true if this is a loopback address (::1) + pub fn is_loopback(&self) -> bool { + self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] + } + + /// Returns true if the address appears to be globally routable. + /// + /// Non-globally-routable networks include the loopback address; the + /// link-local, site-local, and unique local unicast addresses; and the + /// interface-, link-, realm-, admin- and site-local multicast addresses. + pub fn is_global(&self) -> bool { + match self.multicast_scope() { + Some(Ipv6MulticastScope::Global) => true, + None => self.is_unicast_global(), + _ => false + } + } + + /// Returns true if this is a unique local address (IPv6) + /// + /// Unique local addresses are defined in RFC4193 and have the form fc00::/7 + pub fn is_unique_local(&self) -> bool { + (self.segments()[0] & 0xfe00) == 0xfc00 + } + + /// Returns true if the address is unicast and link-local (fe80::/10) + pub fn is_unicast_link_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfe80 + } + + /// Returns true if this is a deprecated unicast site-local address (IPv6 + /// fec0::/10) + pub fn is_unicast_site_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfec0 + } + + /// Returns true if the address is a globally routable unicast address + /// + /// Non-globally-routable unicast addresses include the loopback address, + /// the link-local addresses, the deprecated site-local addresses and the + /// unique local addresses. + pub fn is_unicast_global(&self) -> bool { + !self.is_multicast() + && !self.is_loopback() && !self.is_unicast_link_local() + && !self.is_unicast_site_local() && !self.is_unique_local() + } + + /// Returns the address's multicast scope if the address is multicast. + pub fn multicast_scope(&self) -> Option { + if self.is_multicast() { + match self.segments()[0] & 0x000f { + 1 => Some(Ipv6MulticastScope::InterfaceLocal), + 2 => Some(Ipv6MulticastScope::LinkLocal), + 3 => Some(Ipv6MulticastScope::RealmLocal), + 4 => Some(Ipv6MulticastScope::AdminLocal), + 5 => Some(Ipv6MulticastScope::SiteLocal), + 8 => Some(Ipv6MulticastScope::OrganizationLocal), + 14 => Some(Ipv6MulticastScope::Global), + _ => None + } + } else { + None + } + } + + /// Returns true if this is a multicast address. + /// + /// Multicast addresses have the form ff00::/8. + pub fn is_multicast(&self) -> bool { + (self.segments()[0] & 0xff00) == 0xff00 + } + + /// Convert 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 + pub fn to_ipv4(&self) -> Option { + match self.segments() { + [0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => { + Some(Ipv4Addr::new((g >> 8) as u8, g as u8, + (h >> 8) as u8, h as u8)) + }, + _ => None + } + } +} + +impl fmt::Display for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.segments() { + // We need special cases for :: and ::1, otherwise they're formatted + // as ::0.0.0.[01] + [0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"), + [0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"), + // Ipv4 Compatible address + [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 + [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) + }, + _ => { + fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) { + let mut longest_span_len = 0; + let mut longest_span_at = 0; + let mut cur_span_len = 0; + let mut cur_span_at = 0; + + for i in range(0, 8) { + if segments[i] == 0 { + if cur_span_len == 0 { + cur_span_at = i; + } + + cur_span_len += 1; + + if cur_span_len > longest_span_len { + longest_span_len = cur_span_len; + longest_span_at = cur_span_at; + } + } else { + cur_span_len = 0; + cur_span_at = 0; + } + } + + (longest_span_at, longest_span_len) + } + + let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); + + if zeros_len > 1 { + fn fmt_subslice(segments: &[u16]) -> String { + segments + .iter() + .map(|&seg| format!("{:x}", seg)) + .collect::>() + .as_slice() + .connect(":") + } + + write!(fmt, "{}::{}", + fmt_subslice(&self.segments()[..zeros_at]), + fmt_subslice(&self.segments()[zeros_at + zeros_len..])) + } else { + let &[a, b, c, d, e, f, g, h] = &self.segments(); + write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", + a, b, c, d, e, f, g, h) + } + } + } + } +} + +impl fmt::Debug for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +impl Clone for Ipv6Addr { + fn clone(&self) -> Ipv6Addr { *self } +} + +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &Ipv6Addr) -> bool { + self.inner.s6_addr == other.inner.s6_addr + } +} +impl Eq for Ipv6Addr {} + +impl hash::Hash for Ipv6Addr { + fn hash(&self, s: &mut S) { + self.inner.s6_addr.hash(s) + } +} + +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Ipv6Addr { + fn cmp(&self, other: &Ipv6Addr) -> Ordering { + self.inner.s6_addr.cmp(&other.inner.s6_addr) + } +} + +impl AsInner for Ipv6Addr { + fn as_inner(&self) -> &libc::in6_addr { &self.inner } +} +impl FromInner for Ipv6Addr { + fn from_inner(addr: libc::in6_addr) -> Ipv6Addr { + Ipv6Addr { inner: addr } + } +} diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs new file mode 100644 index 0000000000000..d73c06a2549e1 --- /dev/null +++ b/src/libstd/net/mod.rs @@ -0,0 +1,99 @@ +// 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. + +//! Networking primitives for TCP/UDP communication +//! +//! > **NOTE**: This module is very much a work in progress and is under active +//! > development. At this time it is still recommended to use the `old_io` +//! > module while the details of this module shake out. + +#![unstable(feature = "net")] + +use prelude::v1::*; + +use io::{self, Error, ErrorKind}; +use num::Int; +use sys_common::net2 as net_imp; + +pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; +pub use self::addr::{SocketAddr, ToSocketAddrs}; +pub use self::tcp::{TcpStream, TcpListener}; +pub use self::udp::UdpSocket; + +mod ip; +mod addr; +mod tcp; +mod udp; +mod parser; +#[cfg(test)] mod test; + +/// Possible values which can be passed to the `shutdown` method of `TcpStream` +/// and `UdpSocket`. +#[derive(Copy, Clone, PartialEq)] +pub enum Shutdown { + /// Indicates that the reading portion of this stream/socket should be shut + /// down. All currently blocked and future reads will return `Ok(0)`. + Read, + /// Indicates that the writing portion of this stream/socket should be shut + /// down. All currently blocked and future writes will return an error. + Write, + /// Shut down both the reading and writing portions of this stream. + /// + /// See `Shutdown::Read` and `Shutdown::Write` for more information. + Both +} + +fn hton(i: I) -> I { i.to_be() } +fn ntoh(i: I) -> I { Int::from_be(i) } + +fn each_addr(addr: &A, mut f: F) -> io::Result + where F: FnMut(&SocketAddr) -> io::Result +{ + let mut last_err = None; + for addr in try!(addr.to_socket_addrs()) { + match f(&addr) { + Ok(l) => return Ok(l), + Err(e) => last_err = Some(e), + } + } + Err(last_err.unwrap_or_else(|| { + Error::new(ErrorKind::InvalidInput, + "could not resolve to any addresses", None) + })) +} + +/// An iterator over `SocketAddr` values returned from a host lookup operation. +pub struct LookupHost(net_imp::LookupHost); + +impl Iterator for LookupHost { + type Item = io::Result; + fn next(&mut self) -> Option> { self.0.next() } +} + +/// Resolve the host specified by `host` as a number of `SocketAddr` instances. +/// +/// This method may perform a DNS query to resolve `host` and may also inspect +/// system configuration to resolve the specified hostname. +/// +/// # Example +/// +/// ```no_run +/// use std::net; +/// +/// # fn foo() -> std::io::Result<()> { +/// for host in try!(net::lookup_host("rust-lang.org")) { +/// println!("found address: {}", try!(host)); +/// } +/// # Ok(()) +/// # } +/// ``` +pub fn lookup_host(host: &str) -> io::Result { + net_imp::lookup_host(host).map(LookupHost) +} diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs new file mode 100644 index 0000000000000..e82dc88cddd7b --- /dev/null +++ b/src/libstd/net/parser.rs @@ -0,0 +1,330 @@ +// 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. + +//! A private parser implementation of IPv4, IPv6, and socket addresses. +//! +//! This module is "publicly exported" through the `FromStr` implementations +//! below. + +use prelude::v1::*; + +use str::FromStr; +use net::{Ipv4Addr, Ipv6Addr, IpAddr, SocketAddr}; + +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.iter_mut() { + match self.read_atomically(|p: &mut Parser| pf(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 = 0u32; + 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 = [0u8; 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::new(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]) -> Ipv6Addr { + assert!(head.len() + tail.len() <= 8); + let mut gs = [0u16; 8]; + gs.clone_from_slice(head); + gs[(8 - tail.len()) .. 8].clone_from_slice(tail); + Ipv6Addr::new(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 + } + }); + if let Some(v4_addr) = ipv4 { + let octets = v4_addr.octets(); + groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16); + groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] 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 = [0u16; 8]; + let (head_size, head_ipv4) = read_groups(self, &mut head, 8); + + if head_size == 8 { + return Some(Ipv6Addr::new( + 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 = [0u16; 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 = |p: &mut Parser| p.read_ipv4_addr().map(|v4| IpAddr::V4(v4)); + let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(|v6| IpAddr::V6(v6)); + self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)]) + } + + fn read_socket_addr(&mut self) -> Option { + let ip_addr = |p: &mut Parser| { + let ipv4_p = |p: &mut Parser| p.read_ip_addr(); + let ipv6_p = |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, _) => IpAddr::V6(ip) }) + }; + p.read_or(&mut [Box::new(ipv4_p), Box::new(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::new(ip, 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 Ipv4Addr { + type Err = ParseError; + fn from_str(s: &str) -> Result { + match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) { + Some(s) => Ok(s), + None => Err(ParseError) + } + } +} + +impl FromStr for Ipv6Addr { + type Err = ParseError; + fn from_str(s: &str) -> Result { + match Parser::new(s).read_till_eof(|p| p.read_ipv6_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; diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs new file mode 100644 index 0000000000000..50eafdfc5c238 --- /dev/null +++ b/src/libstd/net/tcp.rs @@ -0,0 +1,792 @@ +// 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. + +use prelude::v1::*; +use io::prelude::*; + +use io; +use net::{ToSocketAddrs, SocketAddr, Shutdown}; +use sys_common::net2 as net_imp; +use sys_common::AsInner; + +/// 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. +/// +/// # Example +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::net::TcpStream; +/// +/// { +/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// +/// // ignore the Result +/// let _ = stream.write(&[1]); +/// let _ = stream.read(&mut [0; 128]); // ignore here too +/// } // the stream is closed here +/// ``` +pub struct TcpStream(net_imp::TcpStream); + +/// A structure representing a socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::net::{TcpListener, TcpStream}; +/// use std::thread::Thread; +/// +/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); +/// +/// fn handle_client(stream: TcpStream) { +/// // ... +/// } +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// Thread::spawn(move|| { +/// // connection succeeded +/// handle_client(stream) +/// }); +/// } +/// Err(e) => { /* connection failed */ } +/// } +/// } +/// +/// // close the socket server +/// drop(listener); +/// ``` +pub struct TcpListener(net_imp::TcpListener); + +/// An infinite iterator over the connections from a `TcpListener`. +/// +/// This iterator will infinitely yield `Some` of the accepted connections. It +/// is equivalent to calling `accept` in a loop. +pub struct Incoming<'a> { listener: &'a TcpListener } + +impl TcpStream { + /// Open 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 + /// documentation for concrete examples. + pub fn connect(addr: &A) -> io::Result { + super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream) + } + + /// Returns the socket address of the remote peer of this TCP connection. + pub fn peer_addr(&self) -> io::Result { + self.0.peer_addr() + } + + /// Returns the socket address of the local half of this TCP connection. + pub fn socket_addr(&self) -> io::Result { + self.0.socket_addr() + } + + /// Shut 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 + /// documentation of `Shutdown`). + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Create 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 + /// data, and options set on one stream will be propagated to the other + /// stream. + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(TcpStream) + } + + /// Sets the nodelay flag on this connection to the boolean specified + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + self.0.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. + pub fn set_keepalive(&self, seconds: Option) -> io::Result<()> { + self.0.set_keepalive(seconds) + } +} + +impl Read for TcpStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } +} +impl Write for TcpStream { + fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} +impl<'a> Read for &'a TcpStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } +} +impl<'a> Write for &'a TcpStream { + fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +impl AsInner for TcpStream { + fn as_inner(&self) -> &net_imp::TcpStream { &self.0 } +} + +impl TcpListener { + /// Creates a new `TcpListener` which will be bound to the specified + /// address. + /// + /// The returned listener is ready for accepting connections. + /// + /// 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_addr` function. + /// + /// The address type can be any implementer of `ToSocketAddrs` trait. See + /// its documentation for concrete examples. + pub fn bind(addr: &A) -> io::Result { + super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) + } + + /// Returns the local socket address of this listener. + pub fn socket_addr(&self) -> io::Result { + self.0.socket_addr() + } + + /// Create 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 + /// connections and options set on one listener will affect the other. + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(TcpListener) + } + + /// Accept a new incoming connection from this listener. + /// + /// This function will block the calling thread until a new TCP connection + /// is established. When established, the corresponding `TcpStream` and the + /// remote peer's address will be returned. + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + self.0.accept().map(|(a, b)| (TcpStream(a), b)) + } + + /// Returns an iterator over the connections being received on this + /// listener. + /// + /// The returned iterator will never returned `None` and will also not yield + /// the peer's `SocketAddr` structure. + pub fn incoming(&self) -> Incoming { + Incoming { listener: self } + } +} + +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|p| p.0)) + } +} + +impl AsInner for TcpListener { + fn as_inner(&self) -> &net_imp::TcpListener { &self.0 } +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + + use io::ErrorKind; + use io::prelude::*; + use net::*; + use net::test::{next_test_ip4, next_test_ip6}; + use sync::mpsc::channel; + use thread::Thread; + + fn each_ip(f: &mut FnMut(SocketAddr)) { + f(next_test_ip4()); + f(next_test_ip6()); + } + + macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + } + } + + // 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(), ErrorKind::PermissionDenied), + } + } + + #[test] + fn connect_error() { + match TcpStream::connect("0.0.0.0:1") { + Ok(..) => panic!(), + Err(e) => assert_eq!(e.kind(), ErrorKind::ConnectionRefused), + } + } + + #[test] + fn listen_localhost() { + let socket_addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&socket_addr)); + + let _t = Thread::scoped(move || { + let mut stream = t!(TcpStream::connect(&("localhost", + socket_addr.port()))); + t!(stream.write(&[144])); + }); + + let mut stream = t!(listener.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 144); + } + + #[test] + fn connect_ip4_loopback() { + let addr = next_test_ip4(); + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = Thread::scoped(move|| { + let mut stream = t!(TcpStream::connect(&("127.0.0.1", addr.port()))); + t!(stream.write(&[44])); + }); + + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 44); + } + + #[test] + fn connect_ip6_loopback() { + let addr = next_test_ip6(); + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = Thread::scoped(move|| { + let mut stream = t!(TcpStream::connect(&("::1", addr.port()))); + t!(stream.write(&[66])); + }); + + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 66); + } + + #[test] + fn smoke_test_ip6() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let (tx, rx) = channel(); + let _t = Thread::scoped(move|| { + let mut stream = t!(TcpStream::connect(&addr)); + t!(stream.write(&[99])); + tx.send(t!(stream.socket_addr())).unwrap(); + }); + + let (mut stream, addr) = t!(acceptor.accept()); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 99); + assert_eq!(addr, t!(rx.recv())); + }) + } + + #[test] + fn read_eof_ip4() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = Thread::scoped(move|| { + let _stream = t!(TcpStream::connect(&addr)); + // Close + }); + + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + let nread = t!(stream.read(&mut buf)); + assert_eq!(nread, 0); + let nread = t!(stream.read(&mut buf)); + assert_eq!(nread, 0); + }) + } + + #[test] + fn write_close() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let (tx, rx) = channel(); + let _t = Thread::scoped(move|| { + drop(t!(TcpStream::connect(&addr))); + tx.send(()).unwrap(); + }); + + let mut stream = t!(acceptor.accept()).0; + rx.recv().unwrap(); + let buf = [0]; + match stream.write(&buf) { + Ok(..) => {} + Err(e) => { + assert!(e.kind() == ErrorKind::ConnectionReset || + e.kind() == ErrorKind::BrokenPipe || + e.kind() == ErrorKind::ConnectionAborted, + "unknown error: {}", e); + } + } + }) + } + + #[test] + fn multiple_connect_serial_ip4() { + each_ip(&mut |addr| { + let max = 10; + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = Thread::scoped(move|| { + for _ in 0..max { + let mut stream = t!(TcpStream::connect(&addr)); + t!(stream.write(&[99])); + } + }); + + for stream in acceptor.incoming().take(max) { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert_eq!(buf[0], 99); + } + }) + } + + #[test] + fn multiple_connect_interleaved_greedy_schedule() { + static MAX: usize = 10; + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = Thread::scoped(move|| { + let acceptor = acceptor; + for (i, stream) in acceptor.incoming().enumerate().take(MAX) { + // Start another task to handle the connection + let _t = Thread::scoped(move|| { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == i as u8); + }); + } + }); + + connect(0, addr); + }); + + fn connect(i: usize, addr: SocketAddr) { + if i == MAX { return } + + let t = Thread::scoped(move|| { + let mut stream = t!(TcpStream::connect(&addr)); + // Connect again before writing + connect(i + 1, addr); + t!(stream.write(&[i as u8])); + }); + t.join().ok().unwrap(); + } + } + + #[test] + fn multiple_connect_interleaved_lazy_schedule_ip4() { + static MAX: usize = 10; + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = Thread::scoped(move|| { + for stream in acceptor.incoming().take(MAX) { + // Start another task to handle the connection + let _t = Thread::scoped(move|| { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 99); + }); + } + }); + + connect(0, addr); + }); + + fn connect(i: usize, addr: SocketAddr) { + if i == MAX { return } + + let t = Thread::scoped(move|| { + let mut stream = t!(TcpStream::connect(&addr)); + connect(i + 1, addr); + t!(stream.write(&[99])); + }); + t.join().ok().unwrap(); + } + } + + pub fn socket_name(addr: SocketAddr) { + } + + pub fn peer_name(addr: SocketAddr) { + } + + #[test] + fn socket_and_peer_name_ip4() { + each_ip(&mut |addr| { + let listener = t!(TcpListener::bind(&addr)); + let so_name = t!(listener.socket_addr()); + assert_eq!(addr, so_name); + let _t = Thread::scoped(move|| { + t!(listener.accept()); + }); + + let stream = t!(TcpStream::connect(&addr)); + assert_eq!(addr, t!(stream.peer_addr())); + }) + } + + #[test] + fn partial_read() { + each_ip(&mut |addr| { + let (tx, rx) = channel(); + let srv = t!(TcpListener::bind(&addr)); + let _t = Thread::scoped(move|| { + let mut cl = t!(srv.accept()).0; + cl.write(&[10]).unwrap(); + let mut b = [0]; + t!(cl.read(&mut b)); + tx.send(()).unwrap(); + }); + + let mut c = t!(TcpStream::connect(&addr)); + let mut b = [0; 10]; + assert_eq!(c.read(&mut b), Ok(1)); + t!(c.write(&[1])); + rx.recv().unwrap(); + }) + } + + #[test] + fn double_bind() { + each_ip(&mut |addr| { + let _listener = t!(TcpListener::bind(&addr)); + match TcpListener::bind(&addr) { + Ok(..) => panic!(), + Err(e) => { + assert!(e.kind() == ErrorKind::ConnectionRefused || + e.kind() == ErrorKind::Other, + "unknown error: {} {:?}", e, e.kind()); + } + } + }) + } + + #[test] + fn fast_rebind() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = Thread::scoped(move|| { + t!(TcpStream::connect(&addr)); + }); + + t!(acceptor.accept()); + drop(acceptor); + t!(TcpListener::bind(&addr)); + }); + } + + #[test] + fn tcp_clone_smoke() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = Thread::scoped(move|| { + let mut s = t!(TcpStream::connect(&addr)); + let mut buf = [0, 0]; + assert_eq!(s.read(&mut buf), Ok(1)); + assert_eq!(buf[0], 1); + t!(s.write(&[2])); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let _t = Thread::scoped(move|| { + let mut s2 = s2; + rx1.recv().unwrap(); + t!(s2.write(&[1])); + 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() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + let (tx1, rx) = channel(); + let tx2 = tx1.clone(); + + let _t = Thread::scoped(move|| { + let mut s = t!(TcpStream::connect(&addr)); + t!(s.write(&[1])); + rx.recv().unwrap(); + t!(s.write(&[2])); + rx.recv().unwrap(); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (done, rx) = channel(); + let _t = Thread::scoped(move|| { + let mut s2 = s2; + let mut buf = [0, 0]; + t!(s2.read(&mut buf)); + tx2.send(()).unwrap(); + done.send(()).unwrap(); + }); + let mut buf = [0, 0]; + t!(s1.read(&mut buf)); + tx1.send(()).unwrap(); + + rx.recv().unwrap(); + }) + } + + #[test] + fn tcp_clone_two_write() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = Thread::scoped(move|| { + let mut s = t!(TcpStream::connect(&addr)); + let mut buf = [0, 1]; + t!(s.read(&mut buf)); + t!(s.read(&mut buf)); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (done, rx) = channel(); + let _t = Thread::scoped(move|| { + let mut s2 = s2; + t!(s2.write(&[1])); + done.send(()).unwrap(); + }); + t!(s1.write(&[2])); + + rx.recv().unwrap(); + }) + } + + #[test] + fn shutdown_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let _t = Thread::scoped(move|| { + let mut c = t!(a.accept()).0; + let mut b = [0]; + assert_eq!(c.read(&mut b), Ok(0)); + t!(c.write(&[1])); + }); + + let mut s = t!(TcpStream::connect(&addr)); + t!(s.shutdown(Shutdown::Write)); + assert!(s.write(&[1]).is_err()); + let mut b = [0, 0]; + assert_eq!(t!(s.read(&mut b)), 1); + assert_eq!(b[0], 1); + }) + } + + #[test] + fn close_readwrite_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let (tx, rx) = channel::<()>(); + let _t = Thread::scoped(move|| { + let _s = t!(a.accept()); + let _ = rx.recv(); + }); + + let mut b = [0]; + let mut s = t!(TcpStream::connect(&addr)); + let mut s2 = t!(s.try_clone()); + + // closing should prevent reads/writes + t!(s.shutdown(Shutdown::Write)); + assert!(s.write(&[0]).is_err()); + t!(s.shutdown(Shutdown::Read)); + assert_eq!(s.read(&mut b), Ok(0)); + + // closing should affect previous handles + assert!(s2.write(&[0]).is_err()); + assert_eq!(s2.read(&mut b), Ok(0)); + + // closing should affect new handles + let mut s3 = t!(s.try_clone()); + assert!(s3.write(&[0]).is_err()); + assert_eq!(s3.read(&mut b), Ok(0)); + + // make sure these don't die + let _ = s2.shutdown(Shutdown::Read); + let _ = s2.shutdown(Shutdown::Write); + let _ = s3.shutdown(Shutdown::Read); + let _ = s3.shutdown(Shutdown::Write); + drop(tx); + }) + } + + #[test] + fn close_read_wakes_up() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let (tx1, rx) = channel::<()>(); + let _t = Thread::scoped(move|| { + let _s = t!(a.accept()); + let _ = rx.recv(); + }); + + let s = t!(TcpStream::connect(&addr)); + let s2 = t!(s.try_clone()); + let (tx, rx) = channel(); + let _t = Thread::scoped(move|| { + let mut s2 = s2; + assert_eq!(t!(s2.read(&mut [0])), 0); + tx.send(()).unwrap(); + }); + // this should wake up the child task + t!(s.shutdown(Shutdown::Read)); + + // this test will never finish if the child doesn't wake up + rx.recv().unwrap(); + drop(tx1); + }) + } + + #[test] + fn clone_while_reading() { + each_ip(&mut |addr| { + let accept = t!(TcpListener::bind(&addr)); + + // Enqueue a task to write to a socket + let (tx, rx) = channel(); + let (txdone, rxdone) = channel(); + let txdone2 = txdone.clone(); + let _t = Thread::scoped(move|| { + let mut tcp = t!(TcpStream::connect(&addr)); + rx.recv().unwrap(); + t!(tcp.write(&[0])); + txdone2.send(()).unwrap(); + }); + + // Spawn off a reading clone + let tcp = t!(accept.accept()).0; + let tcp2 = t!(tcp.try_clone()); + let txdone3 = txdone.clone(); + let _t = Thread::scoped(move|| { + let mut tcp2 = tcp2; + t!(tcp2.read(&mut [0])); + 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 _ = t!(tcp.try_clone()); + tx.send(()).unwrap(); + rxdone.recv().unwrap(); + rxdone.recv().unwrap(); + }) + } + + #[test] + fn clone_accept_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let a2 = t!(a.try_clone()); + + let _t = Thread::scoped(move|| { + let _ = TcpStream::connect(&addr); + }); + let _t = Thread::scoped(move|| { + let _ = TcpStream::connect(&addr); + }); + + t!(a.accept()); + t!(a2.accept()); + }) + } + + #[test] + fn clone_accept_concurrent() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let a2 = t!(a.try_clone()); + + let (tx, rx) = channel(); + let tx2 = tx.clone(); + + let _t = Thread::scoped(move|| { + tx.send(t!(a.accept())).unwrap(); + }); + let _t = Thread::scoped(move|| { + tx2.send(t!(a2.accept())).unwrap(); + }); + + let _t = Thread::scoped(move|| { + let _ = TcpStream::connect(&addr); + }); + let _t = Thread::scoped(move|| { + let _ = TcpStream::connect(&addr); + }); + + rx.recv().unwrap(); + rx.recv().unwrap(); + }) + } +} diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs new file mode 100644 index 0000000000000..971fb4b69c8ef --- /dev/null +++ b/src/libstd/net/test.rs @@ -0,0 +1,39 @@ +// 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. + +use prelude::v1::*; + +use env; +use net::{SocketAddr, IpAddr}; +use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + +pub fn next_test_ip4() -> SocketAddr { + static PORT: AtomicUsize = ATOMIC_USIZE_INIT; + SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1), + PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port()) +} + +pub fn next_test_ip6() -> SocketAddr { + static PORT: AtomicUsize = ATOMIC_USIZE_INIT; + SocketAddr::new(IpAddr::new_v6(0, 0, 0, 0, 0, 0, 0, 1), + PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port()) +} + +// 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 cwd = env::current_dir().unwrap(); + let dirs = ["32-opt", "32-nopt", "64-opt", "64-nopt", "64-opt-vg", + "all-opt", "snap3", "dist"]; + dirs.iter().enumerate().find(|&(i, dir)| { + cwd.as_str().unwrap().contains(dir) + }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600 +} diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs new file mode 100644 index 0000000000000..d162a29790ea1 --- /dev/null +++ b/src/libstd/net/udp.rs @@ -0,0 +1,291 @@ +// 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. + +use prelude::v1::*; + +use io::{self, Error, ErrorKind}; +use net::{ToSocketAddrs, SocketAddr, IpAddr}; +use sys_common::net2 as net_imp; +use sys_common::AsInner; + +/// 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. +/// +/// # Example +/// +/// ```no_run +/// use std::net::UdpSocket; +/// +/// # fn foo() -> std::io::Result<()> { +/// let mut socket = try!(UdpSocket::bind("127.0.0.1:34254")); +/// +/// let mut buf = [0; 10]; +/// let (amt, src) = try!(socket.recv_from(&mut buf)); +/// +/// // Send a reply to the socket we received data from +/// let buf = &mut buf[..amt]; +/// buf.reverse(); +/// try!(socket.send_to(buf, &src)); +/// +/// drop(socket); // close the socket +/// # Ok(()) +/// # } +/// ``` +pub struct UdpSocket(net_imp::UdpSocket); + +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) -> io::Result { + super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) + } + + /// 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(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0.recv_from(buf) + } + + /// Sends data on the socket to the given address. Returns nothing on + /// success. + /// + /// Address type can be any implementor of `ToSocketAddrs` trait. See its + /// documentation for concrete examples. + pub fn send_to(&self, buf: &[u8], addr: &A) + -> io::Result { + match try!(addr.to_socket_addrs()).next() { + Some(addr) => self.0.send_to(buf, &addr), + None => Err(Error::new(ErrorKind::InvalidInput, + "no addresses to send data to", None)), + } + } + + /// Returns the socket address that this socket was created from. + pub fn socket_addr(&self) -> io::Result { + self.0.socket_addr() + } + + /// Create 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 + /// options set on one socket will be propagated to the other. + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UdpSocket) + } + + /// Sets the broadcast flag on or off + pub fn set_broadcast(&self, on: bool) -> io::Result<()> { + self.0.set_broadcast(on) + } + + /// Set 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<()> { + self.0.set_multicast_loop(on) + } + + /// Joins a multicast IP address (becomes a member of it) + pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> { + self.0.join_multicast(multi) + } + + /// Leaves a multicast IP address (drops membership from it) + pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> { + self.0.leave_multicast(multi) + } + + /// Sets the multicast TTL + pub fn set_multicast_time_to_live(&self, ttl: i32) -> io::Result<()> { + self.0.multicast_time_to_live(ttl) + } + + /// Sets this socket's TTL + pub fn set_time_to_live(&self, ttl: i32) -> io::Result<()> { + self.0.time_to_live(ttl) + } +} + +impl AsInner for UdpSocket { + fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 } +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + + use io::ErrorKind; + use net::*; + use net::test::{next_test_ip4, next_test_ip6}; + use sync::mpsc::channel; + use thread::Thread; + + fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) { + f(next_test_ip4(), next_test_ip4()); + f(next_test_ip6(), next_test_ip6()); + } + + macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + } + } + + // 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::new(IpAddr::new_v4(0, 0, 0, 0), 1); + match UdpSocket::bind(&addr) { + Ok(..) => panic!(), + Err(e) => assert_eq!(e.kind(), ErrorKind::PermissionDenied), + } + } + + #[test] + fn socket_smoke_test_ip4() { + each_ip(&mut |server_ip, client_ip| { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + + let _t = Thread::spawn(move|| { + let client = t!(UdpSocket::bind(&client_ip)); + rx1.recv().unwrap(); + t!(client.send_to(&[99], &server_ip)); + tx2.send(()).unwrap(); + }); + + let server = t!(UdpSocket::bind(&server_ip)); + tx1.send(()).unwrap(); + let mut buf = [0]; + let (nread, src) = t!(server.recv_from(&mut buf)); + assert_eq!(nread, 1); + assert_eq!(buf[0], 99); + assert_eq!(src, client_ip); + rx2.recv().unwrap(); + }) + } + + #[test] + fn socket_name_ip4() { + each_ip(&mut |addr, _| { + let server = t!(UdpSocket::bind(&addr)); + assert_eq!(addr, t!(server.socket_addr())); + }) + } + + #[test] + fn udp_clone_smoke() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + + let _t = Thread::spawn(move|| { + let mut buf = [0, 0]; + assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1))); + assert_eq!(buf[0], 1); + t!(sock2.send_to(&[2], &addr1)); + }); + + let sock3 = t!(sock1.try_clone()); + + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let _t = Thread::spawn(move|| { + rx1.recv().unwrap(); + t!(sock3.send_to(&[1], &addr2)); + 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() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + let (tx1, rx) = channel(); + let tx2 = tx1.clone(); + + let _t = Thread::spawn(move|| { + t!(sock2.send_to(&[1], &addr1)); + rx.recv().unwrap(); + t!(sock2.send_to(&[2], &addr1)); + rx.recv().unwrap(); + }); + + let sock3 = t!(sock1.try_clone()); + + let (done, rx) = channel(); + let _t = Thread::spawn(move|| { + let mut buf = [0, 0]; + t!(sock3.recv_from(&mut buf)); + tx2.send(()).unwrap(); + done.send(()).unwrap(); + }); + let mut buf = [0, 0]; + t!(sock1.recv_from(&mut buf)); + tx1.send(()).unwrap(); + + rx.recv().unwrap(); + }) + } + + #[test] + fn udp_clone_two_write() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + + let (tx, rx) = channel(); + let (serv_tx, serv_rx) = channel(); + + let _t = Thread::spawn(move|| { + let mut buf = [0, 1]; + rx.recv().unwrap(); + t!(sock2.recv_from(&mut buf)); + serv_tx.send(()).unwrap(); + }); + + let sock3 = t!(sock1.try_clone()); + + let (done, rx) = channel(); + let tx2 = tx.clone(); + let _t = Thread::spawn(move|| { + 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(); + }) + } +} diff --git a/src/libstd/old_io/mem.rs b/src/libstd/old_io/mem.rs index 8f32703f20055..0f4d9c8b4ea45 100644 --- a/src/libstd/old_io/mem.rs +++ b/src/libstd/old_io/mem.rs @@ -66,6 +66,7 @@ impl Writer for Vec { #[deprecated(since = "1.0.0", reason = "use the Vec Writer implementation directly")] #[derive(Clone)] +#[allow(deprecated)] pub struct MemWriter { buf: Vec, } diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs index 219da8f44eb31..94f4af8e558ad 100644 --- a/src/libstd/old_io/mod.rs +++ b/src/libstd/old_io/mod.rs @@ -250,7 +250,7 @@ use char::CharExt; use default::Default; use error::Error; use fmt; -use int; +use isize; use iter::{Iterator, IteratorExt}; use marker::Sized; use mem::transmute; @@ -266,7 +266,7 @@ use slice::SliceExt; use str::StrExt; use str; use string::String; -use uint; +use usize; use unicode; use vec::Vec; @@ -712,28 +712,28 @@ pub trait Reader { /// /// The number of bytes returned is system-dependent. fn read_le_uint(&mut self) -> IoResult { - self.read_le_uint_n(uint::BYTES).map(|i| i as uint) + self.read_le_uint_n(usize::BYTES).map(|i| i as uint) } /// 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(int::BYTES).map(|i| i as int) + self.read_le_int_n(isize::BYTES).map(|i| i as int) } /// 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(uint::BYTES).map(|i| i as uint) + self.read_be_uint_n(usize::BYTES).map(|i| i as uint) } /// 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(int::BYTES).map(|i| i as int) + self.read_be_int_n(isize::BYTES).map(|i| i as int) } /// Reads a big-endian `u64`. @@ -1096,25 +1096,25 @@ pub trait Writer { /// Write a little-endian uint (number of bytes depends on system). #[inline] fn write_le_uint(&mut self, n: uint) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, uint::BYTES, |v| self.write_all(v)) + extensions::u64_to_le_bytes(n as u64, usize::BYTES, |v| self.write_all(v)) } /// Write a little-endian int (number of bytes depends on system). #[inline] fn write_le_int(&mut self, n: int) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, int::BYTES, |v| self.write_all(v)) + extensions::u64_to_le_bytes(n as u64, isize::BYTES, |v| self.write_all(v)) } /// Write a big-endian uint (number of bytes depends on system). #[inline] fn write_be_uint(&mut self, n: uint) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, uint::BYTES, |v| self.write_all(v)) + extensions::u64_to_be_bytes(n as u64, usize::BYTES, |v| self.write_all(v)) } /// Write a big-endian int (number of bytes depends on system). #[inline] fn write_be_int(&mut self, n: int) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, int::BYTES, |v| self.write_all(v)) + extensions::u64_to_be_bytes(n as u64, isize::BYTES, |v| self.write_all(v)) } /// Write a big-endian u64 (8 bytes). @@ -1844,7 +1844,7 @@ mod tests { use self::BadReaderBehavior::*; use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput, Writer}; use prelude::v1::{Ok, Vec, Buffer, SliceExt}; - use uint; + use usize; #[derive(Clone, PartialEq, Debug)] enum BadReaderBehavior { @@ -1891,24 +1891,24 @@ mod tests { #[test] fn test_read_at_least() { let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![GoodBehavior(uint::MAX)]); + vec![GoodBehavior(usize::MAX)]); let buf = &mut [0u8; 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(uint::MAX)]); + 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(uint::MAX)]); + 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(uint::MAX)]); + 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()); @@ -1919,23 +1919,23 @@ mod tests { #[test] fn test_push_at_least() { let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![GoodBehavior(uint::MAX)]); + 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(uint::MAX)]); + 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(uint::MAX)]); + 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(uint::MAX)]); + 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()); diff --git a/src/libstd/old_io/stdio.rs b/src/libstd/old_io/stdio.rs index 4b3811bbe38da..8e55251d285b5 100644 --- a/src/libstd/old_io/stdio.rs +++ b/src/libstd/old_io/stdio.rs @@ -48,7 +48,7 @@ use str::StrExt; use string::String; use sys::{fs, tty}; use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT}; -use uint; +use usize; use vec::Vec; // And so begins the tale of acquiring a uv handle to a stdio stream on all @@ -384,12 +384,14 @@ pub fn println(s: &str) { /// 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)) } @@ -511,7 +513,7 @@ impl Writer for StdWriter { // // [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 {uint::MAX}; + 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), diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 526b5edd4cbde..2a0206d9ff08e 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -125,7 +125,7 @@ pub fn getcwd() -> IoResult { #[deprecated(since = "1.0.0", reason = "use env::vars instead")] #[unstable(feature = "os")] pub fn env() -> Vec<(String,String)> { - env::vars().map(|(k, v)| { + env::vars_os().map(|(k, v)| { (k.to_string_lossy().into_owned(), v.to_string_lossy().into_owned()) }).collect() } @@ -135,7 +135,7 @@ pub fn env() -> Vec<(String,String)> { #[deprecated(since = "1.0.0", reason = "use env::vars instead")] #[unstable(feature = "os")] pub fn env_as_bytes() -> Vec<(Vec, Vec)> { - env::vars().map(|(k, v)| (byteify(k), byteify(v))).collect() + env::vars_os().map(|(k, v)| (byteify(k), byteify(v))).collect() } /// Fetches the environment variable `n` from the current process, returning @@ -159,10 +159,10 @@ pub fn env_as_bytes() -> Vec<(Vec, Vec)> { /// None => println!("{} is not defined in the environment.", key) /// } /// ``` -#[deprecated(since = "1.0.0", reason = "use env::var or env::var_string instead")] +#[deprecated(since = "1.0.0", reason = "use env::var or env::var_os instead")] #[unstable(feature = "os")] pub fn getenv(n: &str) -> Option { - env::var_string(n).ok() + env::var(n).ok() } /// Fetches the environment variable `n` byte vector from the current process, @@ -174,7 +174,7 @@ pub fn getenv(n: &str) -> Option { #[deprecated(since = "1.0.0", reason = "use env::var instead")] #[unstable(feature = "os")] pub fn getenv_as_bytes(n: &str) -> Option> { - env::var(n).map(byteify) + env::var_os(n).map(byteify) } #[cfg(unix)] @@ -317,6 +317,7 @@ pub unsafe fn pipe() -> IoResult { #[cfg(not(target_os="ios"))] #[deprecated(since = "1.0.0", reason = "this function will be removed, use the constants directly")] #[unstable(feature = "os")] +#[allow(deprecated)] pub fn dll_filename(base: &str) -> String { format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX) } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 776fa27086781..4984b4f9aba78 100755 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -878,7 +878,8 @@ impl PathBuf { /// Truncate `self` to `self.parent()`. /// - /// Returns `None` and does nothing if `self.parent()` is `None`. + /// Returns `false` and does nothing if `self.parent()` is `None`. + /// Otherwise, returns `true`. pub fn pop(&mut self) -> bool { match self.parent().map(|p| p.as_u8_slice().len()) { Some(len) => { diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 2af5a486d0d78..ced84d7551eef 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -29,7 +29,7 @@ pub fn log_enabled() -> bool { _ => {} } - let val = match env::var("RUST_BACKTRACE") { + let val = match env::var_os("RUST_BACKTRACE") { Some(..) => 2, None => 1, }; diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index e064663b9e76f..659e787a9ff8f 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -494,6 +494,7 @@ pub extern fn rust_begin_unwind(msg: fmt::Arguments, /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. #[inline(never)] #[cold] +#[stable(since = "1.0.0", feature = "rust1")] pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, uint)) -> ! { use fmt::Writer; @@ -509,6 +510,7 @@ pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, uint)) - /// This is the entry point of unwinding for panic!() and assert!(). #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible +#[stable(since = "1.0.0", feature = "rust1")] pub fn begin_unwind(msg: M, file_line: &(&'static str, uint)) -> ! { // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 703dca4d29bf9..bb57d19ed2666 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -52,7 +52,7 @@ pub fn min_stack() -> uint { 0 => {} n => return n - 1, } - let amt = env::var_string("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()); + let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()); let amt = amt.unwrap_or(2 * 1024 * 1024); // 0 is our sentinel value, so ensure that we'll never see 0 after // initialization has run @@ -63,7 +63,7 @@ pub fn min_stack() -> uint { /// Get's the number of scheduler threads requested by the environment /// either `RUST_THREADS` or `num_cpus`. pub fn default_sched_threads() -> uint { - match env::var_string("RUST_THREADS") { + match env::var("RUST_THREADS") { Ok(nstr) => { let opt_n: Option = nstr.parse().ok(); match opt_n { diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index 85c7572404b95..babae93b2d440 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -61,7 +61,7 @@ use core::cell::Cell; use core::marker; use core::mem; use core::ptr; -use core::uint; +use core::usize; use sync::mpsc::{Receiver, RecvError}; use sync::mpsc::blocking::{self, SignalToken}; @@ -228,7 +228,7 @@ impl Select { // A rewrite should focus on avoiding a yield loop, and for now this // implementation is tying us over to a more efficient "don't // iterate over everything every time" implementation. - let mut ready_id = uint::MAX; + let mut ready_id = usize::MAX; for handle in self.iter() { if (*handle).packet.abort_selection() { ready_id = (*handle).id; @@ -236,7 +236,7 @@ impl Select { } // We must have found a ready receiver - assert!(ready_id != uint::MAX); + assert!(ready_id != usize::MAX); return ready_id; } } diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index c97af4c6bca36..6c31fb925911e 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -23,7 +23,7 @@ pub use self::Failure::*; use core::prelude::*; use core::cmp; -use core::int; +use core::isize; use sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering}; use sync::mpsc::blocking::{self, SignalToken}; @@ -33,17 +33,17 @@ use sync::mpsc::select::StartResult; use sync::{Mutex, MutexGuard}; use thread::Thread; -const DISCONNECTED: int = int::MIN; -const FUDGE: int = 1024; +const DISCONNECTED: isize = isize::MIN; +const FUDGE: isize = 1024; #[cfg(test)] -const MAX_STEALS: int = 5; +const MAX_STEALS: isize = 5; #[cfg(not(test))] -const MAX_STEALS: int = 1 << 20; +const MAX_STEALS: isize = 1 << 20; pub struct Packet { queue: mpsc::Queue, cnt: AtomicIsize, // How many items are on this channel - steals: int, // How many times has a port received without blocking? + steals: isize, // How many times has a port received without blocking? to_wake: AtomicUsize, // SignalToken for wake up // The number of channels which are currently using this packet. diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index a03add8c53255..ab9bd6b2ed7f6 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -25,7 +25,7 @@ use self::Message::*; use core::prelude::*; use core::cmp; -use core::int; +use core::isize; use thread::Thread; use sync::atomic::{AtomicIsize, AtomicUsize, Ordering, AtomicBool}; @@ -33,11 +33,11 @@ use sync::mpsc::Receiver; use sync::mpsc::blocking::{self, SignalToken}; use sync::mpsc::spsc_queue as spsc; -const DISCONNECTED: int = int::MIN; +const DISCONNECTED: isize = isize::MIN; #[cfg(test)] -const MAX_STEALS: int = 5; +const MAX_STEALS: isize = 5; #[cfg(not(test))] -const MAX_STEALS: int = 1 << 20; +const MAX_STEALS: isize = 1 << 20; pub struct Packet { queue: spsc::Queue>, // internal queue for all message diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 2df211f37687f..29c2051e5adc4 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -13,7 +13,7 @@ //! This primitive is meant to be used to run one-time initialization. An //! example use case would be for initializing an FFI library. -use int; +use isize; use marker::Sync; use mem::drop; use ops::FnOnce; @@ -99,9 +99,9 @@ impl Once { let prev = self.cnt.fetch_add(1, Ordering::SeqCst); if prev < 0 { - // Make sure we never overflow, we'll never have int::MIN + // Make sure we never overflow, we'll never have isize::MIN // simultaneous calls to `call_once` to make this value go back to 0 - self.cnt.store(int::MIN, Ordering::SeqCst); + self.cnt.store(isize::MIN, Ordering::SeqCst); return } @@ -111,7 +111,7 @@ impl Once { let guard = self.mutex.lock(); if self.cnt.load(Ordering::SeqCst) > 0 { f(); - let prev = self.cnt.swap(int::MIN, Ordering::SeqCst); + let prev = self.cnt.swap(isize::MIN, Ordering::SeqCst); self.lock_cnt.store(prev, Ordering::SeqCst); } drop(guard); diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 80fa5f64597e9..5054f72ea9879 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -24,6 +24,7 @@ pub mod condvar; pub mod helper_thread; pub mod mutex; pub mod net; +pub mod net2; pub mod rwlock; pub mod stack; pub mod thread; diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs new file mode 100644 index 0000000000000..5af59ec6d2b14 --- /dev/null +++ b/src/libstd/sys/common/net2.rs @@ -0,0 +1,393 @@ +// 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. + +use prelude::v1::*; + +use ffi::CString; +use io::{self, Error, ErrorKind}; +use libc::{self, c_int, c_char, c_void, socklen_t}; +use mem; +use net::{IpAddr, SocketAddr, Shutdown}; +use num::Int; +use sys::c; +use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t}; +use sys_common::{AsInner, FromInner, IntoInner}; + +//////////////////////////////////////////////////////////////////////////////// +// sockaddr and misc bindings +//////////////////////////////////////////////////////////////////////////////// + +fn hton(i: I) -> I { i.to_be() } +fn ntoh(i: I) -> I { Int::from_be(i) } + +fn setsockopt(sock: &Socket, opt: c_int, val: c_int, + payload: T) -> io::Result<()> { + unsafe { + let payload = &payload as *const T as *const c_void; + try!(cvt(libc::setsockopt(*sock.as_inner(), opt, val, payload, + mem::size_of::() as socklen_t))); + Ok(()) + } +} + +#[allow(dead_code)] +fn getsockopt(sock: &Socket, opt: c_int, + val: c_int) -> io::Result { + unsafe { + let mut slot: T = mem::zeroed(); + let mut len = mem::size_of::() as socklen_t; + let ret = try!(cvt(c::getsockopt(*sock.as_inner(), opt, val, + &mut slot as *mut _ as *mut _, + &mut len))); + assert_eq!(ret as usize, mem::size_of::()); + Ok(slot) + } +} + +fn sockname(f: F) -> io::Result + where F: FnOnce(*mut libc::sockaddr, *mut socklen_t) -> c_int +{ + unsafe { + let mut storage: libc::sockaddr_storage = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as socklen_t; + try!(cvt(f(&mut storage as *mut _ as *mut _, &mut len))); + sockaddr_to_addr(&storage, len as usize) + } +} + +fn sockaddr_to_addr(storage: &libc::sockaddr_storage, + len: usize) -> io::Result { + match storage.ss_family as libc::c_int { + libc::AF_INET => { + assert!(len as usize >= mem::size_of::()); + Ok(FromInner::from_inner(unsafe { + *(storage as *const _ as *const libc::sockaddr_in) + })) + } + libc::AF_INET6 => { + assert!(len as usize >= mem::size_of::()); + Ok(FromInner::from_inner(unsafe { + *(storage as *const _ as *const libc::sockaddr_in6) + })) + } + _ => { + Err(Error::new(ErrorKind::InvalidInput, "invalid argument", None)) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// get_host_addresses +//////////////////////////////////////////////////////////////////////////////// + +extern "system" { + fn getaddrinfo(node: *const c_char, service: *const c_char, + hints: *const libc::addrinfo, + res: *mut *mut libc::addrinfo) -> c_int; + fn freeaddrinfo(res: *mut libc::addrinfo); +} + +pub struct LookupHost { + original: *mut libc::addrinfo, + cur: *mut libc::addrinfo, +} + +impl Iterator for LookupHost { + type Item = io::Result; + fn next(&mut self) -> Option> { + unsafe { + if self.cur.is_null() { return None } + let ret = sockaddr_to_addr(mem::transmute((*self.cur).ai_addr), + (*self.cur).ai_addrlen as usize); + self.cur = (*self.cur).ai_next as *mut libc::addrinfo; + Some(ret) + } + } +} + +impl Drop for LookupHost { + fn drop(&mut self) { + unsafe { freeaddrinfo(self.original) } + } +} + +pub fn lookup_host(host: &str) -> io::Result { + init(); + + let c_host = CString::from_slice(host.as_bytes()); + let mut res = 0 as *mut _; + unsafe { + try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _, + &mut res))); + Ok(LookupHost { original: res, cur: res }) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// TCP streams +//////////////////////////////////////////////////////////////////////////////// + +pub struct TcpStream { + inner: Socket, +} + +impl TcpStream { + pub fn connect(addr: &SocketAddr) -> io::Result { + init(); + + let sock = try!(Socket::new(addr, libc::SOCK_STREAM)); + + let (addrp, len) = addr.into_inner(); + try!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) })); + Ok(TcpStream { inner: sock }) + } + + pub fn socket(&self) -> &Socket { &self.inner } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY, + nodelay as c_int) + } + + pub fn set_keepalive(&self, seconds: Option) -> io::Result<()> { + let ret = setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_KEEPALIVE, + seconds.is_some() as c_int); + match seconds { + Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)), + None => ret, + } + } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, + seconds as c_int) + } + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, + seconds as c_int) + } + #[cfg(not(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly")))] + fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> { + Ok(()) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + let ret = try!(cvt(unsafe { + libc::send(*self.inner.as_inner(), + buf.as_ptr() as *const c_void, + buf.len() as wrlen_t, + 0) + })); + Ok(ret as usize) + } + + pub fn peer_addr(&self) -> io::Result { + sockname(|buf, len| unsafe { + libc::getpeername(*self.inner.as_inner(), buf, len) + }) + } + + pub fn socket_addr(&self) -> io::Result { + sockname(|buf, len| unsafe { + libc::getsockname(*self.inner.as_inner(), buf, len) + }) + } + + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + use libc::consts::os::bsd44::SHUT_RDWR; + + let how = match how { + Shutdown::Write => libc::SHUT_WR, + Shutdown::Read => libc::SHUT_RD, + Shutdown::Both => SHUT_RDWR, + }; + try!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) })); + Ok(()) + } + + pub fn duplicate(&self) -> io::Result { + self.inner.duplicate().map(|s| TcpStream { inner: s }) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// TCP listeners +//////////////////////////////////////////////////////////////////////////////// + +pub struct TcpListener { + inner: Socket, +} + +impl TcpListener { + pub fn bind(addr: &SocketAddr) -> io::Result { + init(); + + let sock = try!(Socket::new(addr, libc::SOCK_STREAM)); + + // 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. + if !cfg!(windows) { + try!(setsockopt(&sock, libc::SOL_SOCKET, libc::SO_REUSEADDR, + 1 as c_int)); + } + + // Bind our new socket + let (addrp, len) = addr.into_inner(); + try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) })); + + // Start listening + try!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) })); + Ok(TcpListener { inner: sock }) + } + + pub fn socket(&self) -> &Socket { &self.inner } + + pub fn socket_addr(&self) -> io::Result { + sockname(|buf, len| unsafe { + libc::getsockname(*self.inner.as_inner(), buf, len) + }) + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as socklen_t; + let sock = try!(self.inner.accept(&mut storage as *mut _ as *mut _, + &mut len)); + let addr = try!(sockaddr_to_addr(&storage, len as usize)); + Ok((TcpStream { inner: sock, }, addr)) + } + + pub fn duplicate(&self) -> io::Result { + self.inner.duplicate().map(|s| TcpListener { inner: s }) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// UDP +//////////////////////////////////////////////////////////////////////////////// + +pub struct UdpSocket { + inner: Socket, +} + +impl UdpSocket { + pub fn bind(addr: &SocketAddr) -> io::Result { + init(); + + let sock = try!(Socket::new(addr, libc::SOCK_DGRAM)); + let (addrp, len) = addr.into_inner(); + try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) })); + Ok(UdpSocket { inner: sock }) + } + + pub fn socket(&self) -> &Socket { &self.inner } + + pub fn socket_addr(&self) -> io::Result { + sockname(|buf, len| unsafe { + libc::getsockname(*self.inner.as_inner(), buf, len) + }) + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut addrlen = mem::size_of_val(&storage) as socklen_t; + + let n = try!(cvt(unsafe { + libc::recvfrom(*self.inner.as_inner(), + buf.as_mut_ptr() as *mut c_void, + buf.len() as wrlen_t, 0, + &mut storage as *mut _ as *mut _, &mut addrlen) + })); + Ok((n as usize, try!(sockaddr_to_addr(&storage, addrlen as usize)))) + } + + pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result { + let (dstp, dstlen) = dst.into_inner(); + let ret = try!(cvt(unsafe { + libc::sendto(*self.inner.as_inner(), + buf.as_ptr() as *const c_void, buf.len() as wrlen_t, + 0, dstp, dstlen) + })); + Ok(ret as usize) + } + + pub fn set_broadcast(&self, on: bool) -> io::Result<()> { + setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_BROADCAST, + on as c_int) + } + + pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_IP, + libc::IP_MULTICAST_LOOP, on as c_int) + } + + pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> { + match *multi { + IpAddr::V4(..) => { + self.set_membership(multi, libc::IP_ADD_MEMBERSHIP) + } + IpAddr::V6(..) => { + self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP) + } + } + } + pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> { + match *multi { + IpAddr::V4(..) => { + self.set_membership(multi, libc::IP_DROP_MEMBERSHIP) + } + IpAddr::V6(..) => { + self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP) + } + } + } + fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> { + match *addr { + IpAddr::V4(ref addr) => { + let mreq = libc::ip_mreq { + imr_multiaddr: *addr.as_inner(), + // interface == INADDR_ANY + imr_interface: libc::in_addr { s_addr: 0x0 }, + }; + setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq) + } + IpAddr::V6(ref addr) => { + let mreq = libc::ip6_mreq { + ipv6mr_multiaddr: *addr.as_inner(), + ipv6mr_interface: 0, + }; + setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq) + } + } + } + + pub fn multicast_time_to_live(&self, ttl: i32) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, + ttl as c_int) + } + + pub fn time_to_live(&self, ttl: i32) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) + } + + pub fn duplicate(&self) -> io::Result { + self.inner.duplicate().map(|s| UdpSocket { inner: s }) + } +} diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys/common/thread.rs index 048e33399a3c4..b725b6c7e6e93 100644 --- a/src/libstd/sys/common/thread.rs +++ b/src/libstd/sys/common/thread.rs @@ -12,7 +12,7 @@ use core::prelude::*; use boxed::Box; use mem; -use uint; +use usize; use libc; use thunk::Thunk; use sys_common::stack; @@ -25,7 +25,7 @@ use sys::{thread, stack_overflow}; #[no_stack_check] pub fn start_thread(main: *mut libc::c_void) -> thread::rust_thread_return { unsafe { - stack::record_os_managed_stack_bounds(0, uint::MAX); + stack::record_os_managed_stack_bounds(0, usize::MAX); let handler = stack_overflow::Handler::new(); let f: Box = mem::transmute(main); f.invoke(()); diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index edd16e0c0629e..905fac07c5d5d 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -84,14 +84,17 @@ use sys::thread_local as imp; /// KEY.set(1 as *mut u8); /// } /// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub struct StaticKey { /// Inner static TLS key (internals), created with by `INIT_INNER` in this /// module. + #[stable(feature = "rust1", since = "1.0.0")] pub inner: StaticKeyInner, /// Destructor for the TLS value. /// /// See `Key::new` for information about when the destructor runs and how /// it runs. + #[stable(feature = "rust1", since = "1.0.0")] pub dtor: Option, } @@ -128,6 +131,7 @@ pub struct Key { /// Constant initialization value for static TLS keys. /// /// This value specifies no destructor by default. +#[stable(feature = "rust1", since = "1.0.0")] pub const INIT: StaticKey = StaticKey { inner: INIT_INNER, dtor: None, @@ -136,6 +140,7 @@ pub const INIT: StaticKey = StaticKey { /// Constant initialization value for the inner part of static TLS keys. /// /// This value allows specific configuration of the destructor for a TLS key. +#[stable(feature = "rust1", since = "1.0.0")] pub const INIT_INNER: StaticKeyInner = StaticKeyInner { key: atomic::ATOMIC_USIZE_INIT, }; diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index cf05733cc18af..345808189a0ce 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -157,6 +157,7 @@ extern { pub fn utimes(filename: *const libc::c_char, times: *const libc::timeval) -> libc::c_int; + pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char; } #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -179,20 +180,20 @@ mod select { target_os = "openbsd", target_os = "linux"))] mod select { - use uint; + use usize; use libc; - pub const FD_SETSIZE: uint = 1024; + pub const FD_SETSIZE: usize = 1024; #[repr(C)] pub struct fd_set { // FIXME: shouldn't this be a c_ulong? - fds_bits: [libc::uintptr_t; (FD_SETSIZE / uint::BITS)] + fds_bits: [libc::uintptr_t; (FD_SETSIZE / usize::BITS)] } pub fn fd_set(set: &mut fd_set, fd: i32) { let fd = fd as uint; - set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS); + set.fds_bits[fd / usize::BITS] |= 1 << (fd % usize::BITS); } } diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs index 689bbda832229..1d95f1cce7e1b 100644 --- a/src/libstd/sys/unix/ext.rs +++ b/src/libstd/sys/unix/ext.rs @@ -32,8 +32,8 @@ #![unstable(feature = "std_misc")] use ffi::{OsStr, OsString}; -use fs::{Permissions, OpenOptions}; -use fs; +use fs::{self, Permissions, OpenOptions}; +use net; use libc; use mem; use sys::os_str::Buf; @@ -111,6 +111,16 @@ impl AsRawFd for old_io::net::udp::UdpSocket { } } +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() } +} +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() } +} +impl AsRawFd for net::UdpSocket { + fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() } +} + // Unix-specific extensions to `OsString`. pub trait OsStringExt { /// Create an `OsString` from a byte vector. diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index f0943de537809..327d117823ee3 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -15,8 +15,7 @@ use io; use libc::{self, c_int, size_t, c_void}; use mem; use sys::cvt; - -pub type fd_t = c_int; +use sys_common::AsInner; pub struct FileDesc { fd: c_int, @@ -55,6 +54,10 @@ impl FileDesc { } } +impl AsInner for FileDesc { + fn as_inner(&self) -> &c_int { &self.fd } +} + impl Drop for FileDesc { fn drop(&mut self) { // closing stdio file handles makes no sense, so never do it. Also, note diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs index 070b32483499a..77d5503b68367 100644 --- a/src/libstd/sys/unix/fs2.rs +++ b/src/libstd/sys/unix/fs2.rs @@ -159,7 +159,7 @@ impl OpenOptions { flags: 0, read: false, write: false, - mode: libc::S_IRUSR | libc::S_IWUSR, + mode: 0o666, } } diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index b5a24278a206e..96a18a956c6a6 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -18,12 +18,11 @@ use prelude::v1::*; use ffi; -use io::ErrorKind; +use io::{self, ErrorKind}; use libc; use num::{Int, SignedInt}; use num; use old_io::{self, IoResult, IoError}; -use io; use str; use sys_common::mkerr_libc; @@ -47,6 +46,7 @@ pub mod fs; // support for std::old_io pub mod fs2; // support for std::fs pub mod helper_signal; pub mod mutex; +pub mod net; pub mod os; pub mod os_str; pub mod pipe; diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs new file mode 100644 index 0000000000000..54aec7cf4b193 --- /dev/null +++ b/src/libstd/sys/unix/net.rs @@ -0,0 +1,74 @@ +// 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. + +use prelude::v1::*; + +use ffi; +use io; +use libc::{self, c_int, size_t}; +use str; +use sys::c; +use net::{SocketAddr, IpAddr}; +use sys::fd::FileDesc; +use sys_common::AsInner; + +pub use sys::{cvt, cvt_r}; + +pub type wrlen_t = size_t; + +pub struct Socket(FileDesc); + +pub fn init() {} + +pub fn cvt_gai(err: c_int) -> io::Result<()> { + if err == 0 { return Ok(()) } + + let detail = unsafe { + str::from_utf8(ffi::c_str_to_bytes(&c::gai_strerror(err))).unwrap() + .to_string() + }; + Err(io::Error::new(io::ErrorKind::Other, + "failed to lookup address information", Some(detail))) +} + +impl Socket { + pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { + let fam = match addr.ip() { + IpAddr::V4(..) => libc::AF_INET, + IpAddr::V6(..) => libc::AF_INET6, + }; + unsafe { + let fd = try!(cvt(libc::socket(fam, ty, 0))); + Ok(Socket(FileDesc::new(fd))) + } + } + + pub fn accept(&self, storage: *mut libc::sockaddr, + len: *mut libc::socklen_t) -> io::Result { + let fd = try!(cvt_r(|| unsafe { + libc::accept(self.0.raw(), storage, len) + })); + Ok(Socket(FileDesc::new(fd))) + } + + pub fn duplicate(&self) -> io::Result { + cvt(unsafe { libc::dup(self.0.raw()) }).map(|fd| { + Socket(FileDesc::new(fd)) + }) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } +} + +impl AsInner for Socket { + fn as_inner(&self) -> &c_int { self.0.as_inner() } +} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 0355565cf00f2..3a1b797eeb461 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -19,7 +19,9 @@ pub use self::FILE_INFO_BY_HANDLE_CLASS::*; pub use libc::consts::os::extra::{ FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_DIRECTORY, + WSAPROTOCOL_LEN, }; +pub use libc::types::os::arch::extra::{GROUP, GUID, WSAPROTOCOLCHAIN}; pub const WSADESCRIPTION_LEN: usize = 256; pub const WSASYS_STATUS_LEN: usize = 128; @@ -41,6 +43,7 @@ pub const WSA_INFINITE: libc::DWORD = libc::INFINITE; pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT; pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0; pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED; +pub const WSAESHUTDOWN: libc::c_int = 10058; pub const ERROR_NO_MORE_FILES: libc::DWORD = 18; pub const TOKEN_READ: libc::DWORD = 0x20008; @@ -80,6 +83,33 @@ pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS; pub type WSAEVENT = libc::HANDLE; +#[repr(C)] +#[derive(Copy)] +pub struct WSAPROTOCOL_INFO { + pub dwServiceFlags1: libc::DWORD, + pub dwServiceFlags2: libc::DWORD, + pub dwServiceFlags3: libc::DWORD, + pub dwServiceFlags4: libc::DWORD, + pub dwProviderFlags: libc::DWORD, + pub ProviderId: GUID, + pub dwCatalogEntryId: libc::DWORD, + pub ProtocolChain: WSAPROTOCOLCHAIN, + pub iVersion: libc::c_int, + pub iAddressFamily: libc::c_int, + pub iMaxSockAddr: libc::c_int, + pub iMinSockAddr: libc::c_int, + pub iSocketType: libc::c_int, + pub iProtocol: libc::c_int, + pub iProtocolMaxOffset: libc::c_int, + pub iNetworkByteOrder: libc::c_int, + pub iSecurityScheme: libc::c_int, + pub dwMessageSize: libc::DWORD, + pub dwProviderReserved: libc::DWORD, + pub szProtocol: [u16; (WSAPROTOCOL_LEN as usize) + 1us], +} + +pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; + #[repr(C)] pub struct fd_set { fd_count: libc::c_uint, @@ -184,6 +214,7 @@ pub struct FILE_END_OF_FILE_INFO { extern "system" { pub fn WSAStartup(wVersionRequested: libc::WORD, lpWSAData: LPWSADATA) -> libc::c_int; + pub fn WSACleanup() -> libc::c_int; pub fn WSAGetLastError() -> libc::c_int; pub fn WSACloseEvent(hEvent: WSAEVENT) -> libc::BOOL; pub fn WSACreateEvent() -> WSAEVENT; @@ -200,6 +231,17 @@ extern "system" { hEventObject: WSAEVENT, lpNetworkEvents: LPWSANETWORKEVENTS) -> libc::c_int; + pub fn WSADuplicateSocketW(s: libc::SOCKET, + dwProcessId: libc::DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFO) + -> libc::c_int; + pub fn GetCurrentProcessId() -> libc::DWORD; + pub fn WSASocketW(af: libc::c_int, + kind: libc::c_int, + protocol: libc::c_int, + lpProtocolInfo: LPWSAPROTOCOL_INFO, + g: GROUP, + dwFlags: libc::DWORD) -> libc::SOCKET; pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long, argp: *mut libc::c_ulong) -> libc::c_int; diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs index dc874c2c7913c..ac1006e653f09 100644 --- a/src/libstd/sys/windows/ext.rs +++ b/src/libstd/sys/windows/ext.rs @@ -21,6 +21,7 @@ pub use sys_common::wtf8::{Wtf8Buf, EncodeWide}; use ffi::{OsStr, OsString}; use fs::{self, OpenOptions}; use libc; +use net; use sys::os_str::Buf; use sys_common::{AsInner, FromInner, AsInnerMut}; @@ -103,6 +104,16 @@ impl AsRawSocket for old_io::net::udp::UdpSocket { } } +impl AsRawSocket for net::TcpStream { + fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() } +} +impl AsRawSocket for net::TcpListener { + fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() } +} +impl AsRawSocket for net::UdpSocket { + fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() } +} + // Windows-specific extensions to `OsString`. pub trait OsStringExt { /// Create an `OsString` from a potentially ill-formed UTF-16 slice of 16-bit code units. diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 140bdb1450102..0fa9aaf432355 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -43,6 +43,7 @@ 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; diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs new file mode 100644 index 0000000000000..3451232f40ab8 --- /dev/null +++ b/src/libstd/sys/windows/net.rs @@ -0,0 +1,121 @@ +// 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. + +use prelude::v1::*; + +use io; +use libc::consts::os::extra::INVALID_SOCKET; +use libc::{self, c_int, c_void}; +use mem; +use net::{SocketAddr, IpAddr}; +use num::{SignedInt, Int}; +use rt; +use sync::{Once, ONCE_INIT}; +use sys::c; +use sys_common::AsInner; + +pub type wrlen_t = i32; + +pub struct Socket(libc::SOCKET); + +pub fn init() { + static START: Once = ONCE_INIT; + + START.call_once(|| unsafe { + let mut data: c::WSADATA = mem::zeroed(); + let ret = c::WSAStartup(0x202, // version 2.2 + &mut data); + assert_eq!(ret, 0); + + rt::at_exit(|| { c::WSACleanup(); }) + }); +} + +fn last_error() -> io::Error { + io::Error::from_os_error(unsafe { c::WSAGetLastError() }) +} + +pub fn cvt(t: T) -> io::Result { + let one: T = Int::one(); + if t == -one { + Err(last_error()) + } else { + Ok(t) + } +} + +pub fn cvt_gai(err: c_int) -> io::Result<()> { + if err == 0 { return Ok(()) } + cvt(err).map(|_| ()) +} + +pub fn cvt_r(mut f: F) -> io::Result where F: FnMut() -> T { + cvt(f()) +} + +impl Socket { + pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { + let fam = match addr.ip() { + IpAddr::V4(..) => libc::AF_INET, + IpAddr::V6(..) => libc::AF_INET6, + }; + match unsafe { libc::socket(fam, ty, 0) } { + INVALID_SOCKET => Err(last_error()), + n => Ok(Socket(n)), + } + } + + pub fn accept(&self, storage: *mut libc::sockaddr, + len: *mut libc::socklen_t) -> io::Result { + match unsafe { libc::accept(self.0, storage, len) } { + INVALID_SOCKET => Err(last_error()), + n => Ok(Socket(n)), + } + } + + pub fn duplicate(&self) -> io::Result { + unsafe { + let mut info: c::WSAPROTOCOL_INFO = mem::zeroed(); + try!(cvt(c::WSADuplicateSocketW(self.0, + c::GetCurrentProcessId(), + &mut info))); + match c::WSASocketW(info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, 0, 0) { + INVALID_SOCKET => Err(last_error()), + n => Ok(Socket(n)), + } + } + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + // On unix when a socket is shut down all further reads return 0, so we + // do the same on windows to map a shut down socket to returning EOF. + unsafe { + match libc::recv(self.0, buf.as_mut_ptr() as *mut c_void, + buf.len() as i32, 0) { + -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), + -1 => Err(last_error()), + n => Ok(n as usize) + } + } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { let _ = libc::closesocket(self.0); } + } +} + +impl AsInner for Socket { + fn as_inner(&self) -> &libc::SOCKET { &self.0 } +} diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index 9de5fd1c770ec..eab9cd84539ed 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -335,6 +335,7 @@ mod imp { use ptr; #[doc(hidden)] + #[stable(since = "1.0.0", feature = "rust1")] pub struct Key { // Place the inner bits in an `UnsafeCell` to currently get around the // "only Sync statics" restriction. This allows any type to be placed in @@ -342,11 +343,14 @@ mod imp { // // Note that all access requires `T: 'static` so it can't be a type with // any borrowed pointers still. + #[stable(since = "1.0.0", feature = "rust1")] pub inner: UnsafeCell, // Metadata to keep track of the state of the destructor. Remember that // these variables are thread-local, not global. + #[stable(since = "1.0.0", feature = "rust1")] pub dtor_registered: UnsafeCell, // should be Cell + #[stable(since = "1.0.0", feature = "rust1")] pub dtor_running: UnsafeCell, // should be Cell } @@ -448,6 +452,7 @@ mod imp { } #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] pub unsafe extern fn destroy_value(ptr: *mut u8) { let ptr = ptr as *mut Key; // Right before we run the user destructor be sure to flag the @@ -468,12 +473,15 @@ mod imp { use sys_common::thread_local::StaticKey as OsStaticKey; #[doc(hidden)] + #[stable(since = "1.0.0", feature = "rust1")] pub struct Key { // Statically allocated initialization expression, using an `UnsafeCell` // for the same reasons as above. + #[stable(since = "1.0.0", feature = "rust1")] pub inner: UnsafeCell, // OS-TLS key that we'll use to key off. + #[stable(since = "1.0.0", feature = "rust1")] pub os: OsStaticKey, } @@ -516,6 +524,7 @@ mod imp { } #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] pub unsafe extern fn destroy_value(ptr: *mut u8) { // The OS TLS ensures that this key contains a NULL value when this // destructor starts to run. We set it back to a sentinel value of 1 to diff --git a/src/libstd/thread_local/scoped.rs b/src/libstd/thread_local/scoped.rs index 1a20612d60a84..01220e7bc1fe1 100644 --- a/src/libstd/thread_local/scoped.rs +++ b/src/libstd/thread_local/scoped.rs @@ -81,6 +81,7 @@ macro_rules! __scoped_thread_local_inner { #[cfg_attr(not(any(windows, target_os = "android", target_os = "ios", + target_os = "openbsd", target_arch = "aarch64")), thread_local)] static $name: ::std::thread_local::scoped::Key<$t> = @@ -90,6 +91,7 @@ macro_rules! __scoped_thread_local_inner { #[cfg_attr(not(any(windows, target_os = "android", target_os = "ios", + target_os = "openbsd", target_arch = "aarch64")), thread_local)] pub static $name: ::std::thread_local::scoped::Key<$t> = @@ -98,14 +100,22 @@ macro_rules! __scoped_thread_local_inner { ($t:ty) => ({ use std::thread_local::scoped::Key as __Key; - #[cfg(not(any(windows, target_os = "android", target_os = "ios", target_arch = "aarch64")))] + #[cfg(not(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64")))] const _INIT: __Key<$t> = __Key { inner: ::std::thread_local::scoped::__impl::KeyInner { inner: ::std::cell::UnsafeCell { value: 0 as *mut _ }, } }; - #[cfg(any(windows, target_os = "android", target_os = "ios", target_arch = "aarch64"))] + #[cfg(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64"))] const _INIT: __Key<$t> = __Key { inner: ::std::thread_local::scoped::__impl::KeyInner { inner: ::std::thread_local::scoped::__impl::OS_INIT, @@ -205,7 +215,11 @@ impl Key { } } -#[cfg(not(any(windows, target_os = "android", target_os = "ios", target_arch = "aarch64")))] +#[cfg(not(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64")))] mod imp { use std::cell::UnsafeCell; @@ -223,7 +237,11 @@ mod imp { } } -#[cfg(any(windows, target_os = "android", target_os = "ios", target_arch = "aarch64"))] +#[cfg(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64"))] mod imp { use marker; use sys_common::thread_local::StaticKey as OsStaticKey; diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index ef9d379987932..5d56707c87a47 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -30,7 +30,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT Some(v) => v }; - let e = match env::var_string(&var[]) { + let e = match env::var(&var[]) { Err(..) => { cx.expr_path(cx.path_all(sp, true, @@ -101,7 +101,7 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } } - let e = match env::var_string(&var[]) { + let e = match env::var(&var[]) { Err(_) => { cx.span_err(sp, &msg); cx.expr_usize(sp, 0) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1a328f87c1968..ca7ae32f09ec9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -129,6 +129,10 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows using `box` in patterns; RFC 469 ("box_patterns", "1.0.0", Active), + + // Allows using the unsafe_no_drop_flag attribute (unlikely to + // switch to Accepted; see RFC 320) + ("unsafe_no_drop_flag", "1.0.0", Active), ]; enum Status { @@ -477,6 +481,12 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { self.gate_feature("no_std", attr.span, "no_std is experimental"); } + + if attr.check_name("unsafe_no_drop_flag") { + self.gate_feature("unsafe_no_drop_flag", attr.span, + "unsafe_no_drop_flag has unstable semantics \ + and may be removed in the future"); + } } fn visit_pat(&mut self, pattern: &ast::Pat) { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 1a8cb2b376aeb..6511dffa6bf8b 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -436,40 +436,28 @@ fn mk_main(cx: &mut TestCtxt) -> P { let sp = ignored_span(cx, DUMMY_SP); let ecx = &cx.ext_cx; - // std::slice::AsSlice - let as_slice_path = ecx.path(sp, vec![token::str_to_ident("std"), - token::str_to_ident("slice"), - token::str_to_ident("AsSlice")]); // test::test_main_static let test_main_path = ecx.path(sp, vec![token::str_to_ident("test"), token::str_to_ident("test_main_static")]); - // ::std::os::args + // ::std::env::args let os_args_path = ecx.path_global(sp, vec![token::str_to_ident("std"), - token::str_to_ident("os"), + token::str_to_ident("env"), token::str_to_ident("args")]); - // use std::slice::AsSlice - let as_slice_path = P(nospan(ast::ViewPathSimple(token::str_to_ident("AsSlice"), - as_slice_path))); - let use_as_slice = ecx.item_use(sp, ast::Inherited, as_slice_path); - let use_as_slice = ecx.stmt_item(sp, use_as_slice); - // ::std::os::args() + // ::std::env::args() let os_args_path_expr = ecx.expr_path(os_args_path); let call_os_args = ecx.expr_call(sp, os_args_path_expr, vec![]); - // ::std::os::args().as_slice() - let call_as_slice = ecx.expr_method_call(sp, call_os_args, - token::str_to_ident("as_slice"), vec![]); // test::test_main_static(...) let test_main_path_expr = ecx.expr_path(test_main_path); let tests_ident_expr = ecx.expr_ident(sp, token::str_to_ident("TESTS")); let call_test_main = ecx.expr_call(sp, test_main_path_expr, - vec![call_as_slice, tests_ident_expr]); + vec![call_os_args, tests_ident_expr]); let call_test_main = ecx.stmt_expr(call_test_main); // #![main] let main_meta = ecx.meta_word(sp, token::intern_and_get_ident("main")); let main_attr = ecx.attribute(sp, main_meta); // pub fn main() { ... } let main_ret_ty = ecx.ty(sp, ast::TyTup(vec![])); - let main_body = ecx.block_all(sp, vec![use_as_slice, call_test_main], None); + let main_body = ecx.block_all(sp, vec![call_test_main], None); let main = ast::ItemFn(ecx.fn_decl(vec![], main_ret_ty), ast::Unsafety::Normal, ::abi::Rust, empty_generics(), main_body); let main = P(ast::Item { diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index 084152f107c1d..1bb038603c39c 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -50,6 +50,7 @@ html_playground_url = "http://play.rust-lang.org/")] #![deny(missing_docs)] +#![feature(core)] #![feature(box_syntax)] #![feature(collections)] #![feature(int_uint)] diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs index 0a1439ebee0f1..758191a6e1107 100644 --- a/src/libterm/terminfo/mod.rs +++ b/src/libterm/terminfo/mod.rs @@ -172,7 +172,7 @@ impl TerminfoTerminal { /// Returns `None` whenever the terminal cannot be created for some /// reason. pub fn new(out: T) -> Option+Send+'static>> { - let term = match env::var_string("TERM") { + let term = match env::var("TERM") { Ok(t) => t, Err(..) => { debug!("TERM environment variable not defined"); @@ -182,7 +182,7 @@ impl TerminfoTerminal { let entry = open(&term[]); if entry.is_err() { - if env::var_string("MSYSCON").ok().map_or(false, |s| { + if env::var("MSYSCON").ok().map_or(false, |s| { "mintty.exe" == s }) { // msys terminal diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs index 6ee477fc80823..fd6e6a843e1f3 100644 --- a/src/libterm/terminfo/searcher.rs +++ b/src/libterm/terminfo/searcher.rs @@ -28,14 +28,14 @@ pub fn get_dbpath_for_term(term: &str) -> Option> { let first_char = term.char_at(0); // Find search directory - match env::var_string("TERMINFO") { + match env::var("TERMINFO") { Ok(dir) => dirs_to_search.push(Path::new(dir)), Err(..) => { if homedir.is_some() { // ncurses compatibility; dirs_to_search.push(homedir.unwrap().join(".terminfo")) } - match env::var_string("TERMINFO_DIRS") { + match env::var("TERMINFO_DIRS") { Ok(dirs) => for i in dirs.split(':') { if i == "" { dirs_to_search.push(Path::new("/usr/share/terminfo")); diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index f3edd90b4fa5b..cc468df87f383 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -265,7 +265,8 @@ pub fn test_main(args: &[String], tests: Vec ) { // a ~[TestDescAndFn] is used in order to effect ownership-transfer // semantics into parallel test runners, which in turn requires a ~[] // rather than a &[]. -pub fn test_main_static(args: &[String], tests: &[TestDescAndFn]) { +pub fn test_main_static(args: env::Args, tests: &[TestDescAndFn]) { + let args = args.collect::>(); let owned_tests = tests.iter().map(|t| { match t.testfn { StaticTestFn(f) => TestDescAndFn { testfn: StaticTestFn(f), desc: t.desc.clone() }, @@ -273,7 +274,7 @@ pub fn test_main_static(args: &[String], tests: &[TestDescAndFn]) { _ => panic!("non-static tests passed to test::test_main_static") } }).collect(); - test_main(args, owned_tests) + test_main(&args, owned_tests) } #[derive(Copy)] @@ -385,7 +386,7 @@ pub fn parse_opts(args: &[String]) -> Option { let mut nocapture = matches.opt_present("nocapture"); if !nocapture { - nocapture = env::var("RUST_TEST_NOCAPTURE").is_some(); + nocapture = env::var("RUST_TEST_NOCAPTURE").is_ok(); } let color = match matches.opt_str("color").as_ref().map(|s| &**s) { @@ -811,7 +812,7 @@ fn run_tests(opts: &TestOpts, fn get_concurrency() -> uint { use std::rt; - match env::var_string("RUST_TEST_TASKS") { + match env::var("RUST_TEST_TASKS") { Ok(s) => { let opt_n: Option = s.parse().ok(); match opt_n { diff --git a/src/test/auxiliary/issue-10028.rs b/src/test/auxiliary/issue-10028.rs index 00fdb3e40b975..a21deb44fcc83 100644 --- a/src/test/auxiliary/issue-10028.rs +++ b/src/test/auxiliary/issue-10028.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unsafe_no_drop_flag)] + #[unsafe_no_drop_flag] pub struct ZeroLengthThingWithDestructor; impl Drop for ZeroLengthThingWithDestructor { diff --git a/src/test/compile-fail/feature-gate-simd-ffi.rs b/src/test/compile-fail/feature-gate-simd-ffi.rs index 409c85b719804..9ee3fcee02355 100644 --- a/src/test/compile-fail/feature-gate-simd-ffi.rs +++ b/src/test/compile-fail/feature-gate-simd-ffi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(simd)] +#![feature(simd, core)] #![allow(dead_code)] use std::simd::f32x4; diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 4cf75bf15de27..5c187176fb2ae 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -98,12 +98,10 @@ mod cross_crate { // Eventually, we will want to lint the contents of the // macro in the module *defining* it. Also, stability levels // on macros themselves are not yet linted. - macro_test!(); macro_test_arg!(deprecated_text()); //~ ERROR use of deprecated item: text macro_test_arg!(deprecated_unstable_text()); //~ ERROR use of deprecated item: text //~^ WARNING use of unstable library feature macro_test_arg!(macro_test_arg!(deprecated_text())); //~ ERROR use of deprecated item: text - macro_test_arg_nested!(deprecated_text); } fn test_method_param(foo: F) { @@ -139,7 +137,7 @@ mod cross_crate { mod inheritance { extern crate inherited_stability; //~ WARNING: use of unstable library feature - use self::inherited_stability::*; + use self::inherited_stability::*; //~ WARNING: use of unstable library feature fn test_inheritance() { unstable(); //~ WARNING use of unstable library feature diff --git a/src/test/compile-fail/lint-stability2.rs b/src/test/compile-fail/lint-stability2.rs new file mode 100644 index 0000000000000..d2ec00d649506 --- /dev/null +++ b/src/test/compile-fail/lint-stability2.rs @@ -0,0 +1,23 @@ +// 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. + +// aux-build:lint_stability.rs +// error-pattern: use of deprecated item + +#![deny(deprecated)] + +#[macro_use] +extern crate lint_stability; + +use lint_stability::*; + +fn main() { + macro_test!(); +} diff --git a/src/test/compile-fail/lint-stability3.rs b/src/test/compile-fail/lint-stability3.rs new file mode 100644 index 0000000000000..88a93134b47c0 --- /dev/null +++ b/src/test/compile-fail/lint-stability3.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:lint_stability.rs +// error-pattern: use of deprecated item + +#![deny(deprecated)] +#![allow(warnings)] + +#[macro_use] +extern crate lint_stability; + +use lint_stability::*; + +fn main() { + macro_test_arg_nested!(deprecated_text); +} + diff --git a/src/test/compile-fail/lint-unexported-no-mangle.rs b/src/test/compile-fail/lint-unexported-no-mangle.rs index 3227a78c2ef00..216fcf9353578 100644 --- a/src/test/compile-fail/lint-unexported-no-mangle.rs +++ b/src/test/compile-fail/lint-unexported-no-mangle.rs @@ -8,17 +8,32 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags:-F private_no_mangle_fns +// compile-flags:-F private_no_mangle_fns -F no_mangle_const_items -F private_no_mangle_statics // FIXME(#19495) no_mangle'ing main ICE's. #[no_mangle] fn foo() { //~ ERROR function foo is marked #[no_mangle], but not exported } +#[allow(dead_code)] +#[no_mangle] +const FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle] + +#[no_mangle] +pub const PUB_FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle] + #[no_mangle] pub fn bar() { } +#[no_mangle] +pub static BAR: u64 = 1; + +#[allow(dead_code)] +#[no_mangle] +static PRIVATE_BAR: u64 = 1; //~ ERROR static PRIVATE_BAR is marked #[no_mangle], but not exported + + fn main() { foo(); bar(); diff --git a/src/test/compile-fail/macro-reexport-undef.rs b/src/test/compile-fail/macro-reexport-undef.rs new file mode 100644 index 0000000000000..e9b3ceff83de4 --- /dev/null +++ b/src/test/compile-fail/macro-reexport-undef.rs @@ -0,0 +1,20 @@ +// 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. + +// aux-build:two_macros.rs +// ignore-stage1 + +#[macro_use(macro_two)] +#[macro_reexport(no_way)] //~ ERROR reexported macro not found +extern crate two_macros; + +pub fn main() { + macro_two!(); +} diff --git a/src/test/compile-fail/macro-use-undef.rs b/src/test/compile-fail/macro-use-undef.rs new file mode 100644 index 0000000000000..a5a350bd30e1a --- /dev/null +++ b/src/test/compile-fail/macro-use-undef.rs @@ -0,0 +1,19 @@ +// 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. + +// aux-build:two_macros.rs +// ignore-stage1 + +#[macro_use(macro_two, no_way)] //~ ERROR imported macro not found +extern crate two_macros; + +pub fn main() { + macro_two!(); +} diff --git a/src/test/run-make/empty-file/Makefile b/src/test/run-make/empty-file/Makefile deleted file mode 100644 index f55a2cc3bb158..0000000000000 --- a/src/test/run-make/empty-file/Makefile +++ /dev/null @@ -1,5 +0,0 @@ --include ../tools.mk - -all: - $(RUSTC) --emit=asm,llvm-bc,llvm-ir,obj,dep-info empty.rs - $(RUSTC) --emit=link --crate-type=rlib,dylib,staticlib empty.rs diff --git a/src/test/run-make/empty-file/empty.rs b/src/test/run-make/empty-file/empty.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/test/run-pass/attr-no-drop-flag-size.rs b/src/test/run-pass/attr-no-drop-flag-size.rs index b3fb162790072..bd799917842b1 100644 --- a/src/test/run-pass/attr-no-drop-flag-size.rs +++ b/src/test/run-pass/attr-no-drop-flag-size.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(unsafe_destructor)] +#![feature(unsafe_no_drop_flag)] use std::mem::size_of; diff --git a/src/test/run-pass/env-vars.rs b/src/test/run-pass/env-vars.rs index 892041b964889..659e5b3a8c2f8 100644 --- a/src/test/run-pass/env-vars.rs +++ b/src/test/run-pass/env-vars.rs @@ -11,8 +11,8 @@ use std::env::*; fn main() { - for (k, v) in vars() { - let v2 = var(&k); + for (k, v) in vars_os() { + let v2 = var_os(&k); // MingW seems to set some funky environment variables like // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned // from vars() but not visible from var(). diff --git a/src/test/run-pass/issue-10734.rs b/src/test/run-pass/issue-10734.rs index 1c267f4833752..a6af2327c9e80 100644 --- a/src/test/run-pass/issue-10734.rs +++ b/src/test/run-pass/issue-10734.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unsafe_no_drop_flag)] + static mut drop_count: uint = 0; #[unsafe_no_drop_flag] diff --git a/src/test/run-pass/issue-20343.rs b/src/test/run-pass/issue-20343.rs new file mode 100644 index 0000000000000..79034a4a4a6d6 --- /dev/null +++ b/src/test/run-pass/issue-20343.rs @@ -0,0 +1,38 @@ +// 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. + +// Regression test for Issue #20343. + +#![deny(dead_code)] + +struct B { b: u32 } +struct C; +struct D; + +trait T {} +impl T for () {} + +impl B { + // test for unused code in arguments + fn foo(B { b }: B) -> u32 { b } + + // test for unused code in return type + fn bar() -> C { unsafe { ::std::mem::transmute(()) } } + + // test for unused code in generics + fn baz>() {} +} + +pub fn main() { + let b = B { b: 3 }; + B::foo(b); + B::bar(); + B::baz::<()>(); +} diff --git a/src/test/run-pass/issue-22036.rs b/src/test/run-pass/issue-22036.rs new file mode 100644 index 0000000000000..c06a29c09f78e --- /dev/null +++ b/src/test/run-pass/issue-22036.rs @@ -0,0 +1,33 @@ +// 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. + +trait DigitCollection: Sized { + type Iter: Iterator; + fn digit_iter(self) -> Self::Iter; + + fn digit_sum(self) -> u32 { + self.digit_iter() + .map(|digit: u8| digit as u32) + .fold(0, |sum, digit| sum + digit) + } +} + +impl DigitCollection for I where I: Iterator { + type Iter = I; + + fn digit_iter(self) -> I { + self + } +} + +fn main() { + let xs = vec![1u8, 2, 3, 4, 5]; + assert_eq!(xs.into_iter().digit_sum(), 15); +} diff --git a/src/test/run-pass/zero-size-type-destructors.rs b/src/test/run-pass/zero-size-type-destructors.rs index fd272a47de9c2..f4d03a5cda400 100644 --- a/src/test/run-pass/zero-size-type-destructors.rs +++ b/src/test/run-pass/zero-size-type-destructors.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unsafe_no_drop_flag)] + static mut destructions : int = 3; pub fn foo() {