]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #26966 - nagisa:tail-init, r=alexcrichton
authorbors <bors@rust-lang.org>
Sun, 12 Jul 2015 13:16:24 +0000 (13:16 +0000)
committerbors <bors@rust-lang.org>
Sun, 12 Jul 2015 13:16:24 +0000 (13:16 +0000)
Fixes #26906

33 files changed:
mk/cfg/i686-unknown-freebsd.mk [new file with mode: 0644]
src/liballoc/boxed.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollections/vec_deque.rs
src/libcollectionstest/lib.rs
src/libcollectionstest/str.rs
src/libcollectionstest/string.rs
src/libcore/fmt/builders.rs
src/libcore/fmt/mod.rs
src/libcore/num/mod.rs
src/libcore/option.rs
src/liblibc/lib.rs
src/librustc/diagnostics.rs
src/librustc_back/target/i686_unknown_freebsd.rs [new file with mode: 0644]
src/librustc_back/target/mod.rs
src/librustdoc/html/layout.rs
src/librustdoc/html/static/main.css
src/librustdoc/html/static/main.js
src/librustdoc/html/static/playpen.js
src/libstd/array.rs
src/libstd/ffi/c_str.rs
src/libstd/fs.rs
src/libstd/io/buffered.rs
src/libstd/io/error.rs
src/libstd/io/prelude.rs
src/libstd/io/stdio.rs
src/libstd/io/util.rs
src/libstd/sys/common/stack.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/windows/c.rs
src/libstd/sys/windows/fs.rs
src/rust-installer

diff --git a/mk/cfg/i686-unknown-freebsd.mk b/mk/cfg/i686-unknown-freebsd.mk
new file mode 100644 (file)
index 0000000..0ac0ca9
--- /dev/null
@@ -0,0 +1,22 @@
+# i686-unknown-freebsd configuration
+CC_i686-unknown-freebsd=$(CC)
+CXX_i686-unknown-freebsd=$(CXX)
+CPP_i686-unknown-freebsd=$(CPP)
+AR_i686-unknown-freebsd=$(AR)
+CFG_LIB_NAME_i686-unknown-freebsd=lib$(1).so
+CFG_STATIC_LIB_NAME_i686-unknown-freebsd=lib$(1).a
+CFG_LIB_GLOB_i686-unknown-freebsd=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_i686-unknown-freebsd=$(1)-*.dylib.dSYM
+CFG_JEMALLOC_CFLAGS_i686-unknown-freebsd := -m32 -arch i386 -I/usr/local/include $(CFLAGS)
+CFG_GCCISH_CFLAGS_i686-unknown-freebsd := -Wall -Werror -g -fPIC -m32 -arch i386 -I/usr/local/include $(CFLAGS)
+CFG_GCCISH_LINK_FLAGS_i686-unknown-freebsd := -m32 -shared -fPIC -g -pthread -lrt
+CFG_GCCISH_DEF_FLAG_i686-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list=
+CFG_LLC_FLAGS_i686-unknown-freebsd :=
+CFG_INSTALL_NAME_i686-unknown-freebsd =
+CFG_EXE_SUFFIX_i686-unknown-freebsd :=
+CFG_WINDOWSY_i686-unknown-freebsd :=
+CFG_UNIXY_i686-unknown-freebsd := 1
+CFG_LDPATH_i686-unknown-freebsd :=
+CFG_RUN_i686-unknown-freebsd=$(2)
+CFG_RUN_TARG_i686-unknown-freebsd=$(call CFG_RUN_i686-unknown-freebsd,,$(2))
+CFG_GNU_TRIPLE_i686-unknown-freebsd := i686-unknown-freebsd
index c941629b871ef418566ee87c4dda4ef4ba3bac7d..3dfd10f09167be7b6c3a26d6841284c74e986471 100644 (file)
@@ -71,7 +71,7 @@
 /// The following two examples are equivalent:
 ///
 /// ```
-/// # #![feature(box_heap)]
+/// #![feature(box_heap)]
 /// #![feature(box_syntax)]
 /// use std::boxed::HEAP;
 ///
@@ -162,7 +162,7 @@ pub fn into_raw(b: Box<T>) -> *mut T {
 ///
 /// # Examples
 /// ```
-/// # #![feature(box_raw)]
+/// #![feature(box_raw)]
 /// use std::boxed;
 ///
 /// let seventeen = Box::new(17u32);
index 7e72ad1569a1f56035e69f3f702a41c91b6d4003..7f86209bd2ac9c514f5def488724cb726fb163c7 100644 (file)
@@ -61,6 +61,7 @@
 use core::str as core_str;
 use core::str::pattern::Pattern;
 use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
+use core::mem;
 use rustc_unicode::str::{UnicodeStr, Utf16Encoder};
 
 use vec_deque::VecDeque;
@@ -69,6 +70,7 @@
 use rustc_unicode;
 use vec::Vec;
 use slice::SliceConcatExt;
+use boxed::Box;
 
 pub use core::str::{FromStr, Utf8Error};
 pub use core::str::{Lines, LinesAny, CharRange};
 pub use rustc_unicode::str::{SplitWhitespace, Words, Graphemes, GraphemeIndices};
 pub use core::str::pattern;
 
-/*
-Section: Creating a string
-*/
-
 impl<S: Borrow<str>> SliceConcatExt<str> for [S] {
     type Output = String;
 
@@ -134,10 +132,6 @@ fn connect(&self, sep: &str) -> String {
     }
 }
 
-/*
-Section: Iterators
-*/
-
 // Helper functions used for Unicode normalization
 fn canonical_sort(comb: &mut [(char, u8)]) {
     let len = comb.len();
@@ -382,10 +376,6 @@ fn next(&mut self) -> Option<u16> { self.encoder.next() }
     fn size_hint(&self) -> (usize, Option<usize>) { self.encoder.size_hint() }
 }
 
-/*
-Section: Misc
-*/
-
 // Return the initial codepoint accumulator for the first byte.
 // The first byte is special, only want bottom 5 bits for width 2, 4 bits
 // for width 3, and 3 bits for width 4
@@ -414,15 +404,6 @@ fn to_owned(&self) -> String {
     }
 }
 
-/*
-Section: CowString
-*/
-
-/*
-Section: Trait implementations
-*/
-
-
 /// Any string that can be represented as a slice.
 #[lang = "str"]
 #[cfg(not(test))]
@@ -1924,4 +1905,14 @@ pub fn escape_default(&self) -> String {
     pub fn escape_unicode(&self) -> String {
         self.chars().flat_map(|c| c.escape_unicode()).collect()
     }
+
+    /// Converts the `Box<str>` into a `String` without copying or allocating.
+    #[unstable(feature = "box_str",
+               reason = "recently added, matches RFC")]
+    pub fn into_string(self: Box<str>) -> String {
+        unsafe {
+            let slice = mem::transmute::<Box<str>, Box<[u8]>>(self);
+            String::from_utf8_unchecked(slice.into_vec())
+        }
+    }
 }
index 6b20d6e2a3f9b99587acdae98ef3ae69a8165439..ef1d9b08b4a9a6d4b5b5328c5529f9c71bd4db62 100644 (file)
@@ -29,6 +29,7 @@
 use range::RangeArgument;
 use str::{self, FromStr, Utf8Error, Chars};
 use vec::{DerefVec, Vec, as_vec};
+use boxed::Box;
 
 /// A growable string stored as a UTF-8 encoded buffer.
 #[derive(Clone, PartialOrd, Eq, Ord)]
@@ -741,6 +742,16 @@ pub fn drain<R>(&mut self, range: R) -> Drain where R: RangeArgument<usize> {
             string: self_ptr,
         }
     }
+
+    /// Converts the string into `Box<str>`.
+    ///
+    /// Note that this will drop any excess capacity.
+    #[unstable(feature = "box_str",
+               reason = "recently added, matches RFC")]
+    pub fn into_boxed_slice(self) -> Box<str> {
+        let slice = self.vec.into_boxed_slice();
+        unsafe { mem::transmute::<Box<[u8]>, Box<str>>(slice) }
+    }
 }
 
 impl FromUtf8Error {
index 2aeb303068bdf108c474e786ff7e618a04572161..117b3544f0269a68cc6c86fbd24dea7e0986534c 100644 (file)
@@ -108,7 +108,7 @@ unsafe fn buffer_write(&mut self, off: usize, t: T) {
         ptr::write(self.ptr.offset(off as isize), t);
     }
 
-    /// Returns true iff the buffer is at capacity
+    /// Returns true if and only if the buffer is at capacity
     #[inline]
     fn is_full(&self) -> bool { self.cap - self.len() == 1 }
 
index de6dcc9adcb87c4c952e5702e5d91433b4a3d348..6bf7380fdeb500138cc923157607184a17f7c39d 100644 (file)
@@ -44,6 +44,7 @@
 #![feature(str_escape)]
 #![feature(str_match_indices)]
 #![feature(str_utf16)]
+#![feature(box_str)]
 #![feature(subslice_offset)]
 #![feature(test)]
 #![feature(unboxed_closures)]
index 87a018ced195accee2164df7b341a5c85d1913a3..4eee99f2bc91284137d97f77499af643718bbdba 100644 (file)
@@ -1746,6 +1746,14 @@ fn to_uppercase() {
     assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ");
 }
 
+#[test]
+fn test_into_string() {
+    // The only way to acquire a Box<str> in the first place is through a String, so just
+    // test that we can round-trip between Box<str> and String.
+    let string = String::from("Some text goes here");
+    assert_eq!(string.clone().into_boxed_slice().into_string(), string);
+}
+
 mod pattern {
     use std::str::pattern::Pattern;
     use std::str::pattern::{Searcher, ReverseSearcher};
index 257caca4016df28e8cef0f826544a4d16649bceb..7b69601f010ba4af2435ed40410b4614a637eb2d 100644 (file)
@@ -374,6 +374,13 @@ fn test_extend_ref() {
     assert_eq!(&a, "foobar");
 }
 
+#[test]
+fn test_into_boxed_slice() {
+    let xs = String::from("hello my name is bob");
+    let ys = xs.into_boxed_slice();
+    assert_eq!(&*ys, "hello my name is bob");
+}
+
 #[bench]
 fn bench_with_capacity(b: &mut Bencher) {
     b.iter(|| {
index 32d6aa19c64566e90212673866f8a25d573e23e8..22f0215f0aded53311cf7898c27eb23acedcf681 100644 (file)
@@ -175,6 +175,12 @@ pub fn finish(&mut self) -> fmt::Result {
     fn is_pretty(&self) -> bool {
         self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
     }
+
+    /// Returns the wrapped `Formatter`.
+    #[unstable(feature = "debug_builder_formatter", reason = "recently added")]
+    pub fn formatter(&mut self) -> &mut fmt::Formatter<'b> {
+        &mut self.fmt
+    }
 }
 
 struct DebugInner<'a, 'b: 'a> {
index 47030bf0fb31efc989952e8f53fcf9b1122eb44a..29a2f76ef290b4dcee37738e1781fd4bb195a412 100644 (file)
@@ -1488,20 +1488,19 @@ macro_rules! tuple {
         impl<$($name:Debug),*> Debug for ($($name,)*) {
             #[allow(non_snake_case, unused_assignments)]
             fn fmt(&self, f: &mut Formatter) -> Result {
-                try!(write!(f, "("));
+                let mut builder = f.debug_tuple("");
                 let ($(ref $name,)*) = *self;
                 let mut n = 0;
                 $(
-                    if n > 0 {
-                        try!(write!(f, ", "));
-                    }
-                    try!(write!(f, "{:?}", *$name));
+                    builder.field($name);
                     n += 1;
                 )*
+
                 if n == 1 {
-                    try!(write!(f, ","));
+                    try!(write!(builder.formatter(), ","));
                 }
-                write!(f, ")")
+
+                builder.finish()
             }
         }
         peel! { $($name,)* }
index fd5ef4b1ccccaab3a384cf2b28e7047621f92776..3fd3d4a42b208adf61a6b997264227cfce5c709f 100644 (file)
@@ -1126,7 +1126,7 @@ pub fn pow(self, mut exp: u32) -> Self {
             acc
         }
 
-        /// Returns `true` iff `self == 2^k` for some `k`.
+        /// Returns `true` if and only if `self == 2^k` for some `k`.
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
         pub fn is_power_of_two(self) -> bool {
index c5203c5111b64ab5e3ab7fa306eca86b12062ccd..9ccba7ad78d45a785278ab64b02e34300812ae23 100644 (file)
@@ -46,7 +46,7 @@
 //!     // The division was valid
 //!     Some(x) => println!("Result: {}", x),
 //!     // The division was invalid
-//!     None    => println!("Cannot divide by 0")
+//!     None    => println!("Cannot divide by 0"),
 //! }
 //! ```
 //!
@@ -75,7 +75,7 @@
 //! fn check_optional(optional: &Option<Box<i32>>) {
 //!     match *optional {
 //!         Some(ref p) => println!("have value {}", p),
-//!         None => println!("have no value")
+//!         None => println!("have no value"),
 //!     }
 //! }
 //! ```
 //! // Take a reference to the contained string
 //! match msg {
 //!     Some(ref m) => println!("{}", *m),
-//!     None => ()
+//!     None => (),
 //! }
 //!
 //! // Remove the contained string, destroying the Option
 //! let unwrapped_msg = match msg {
 //!     Some(m) => m,
-//!     None => "default message"
+//!     None => "default message",
 //! };
 //! ```
 //!
 //!
 //! match name_of_biggest_animal {
 //!     Some(name) => println!("the biggest animal is {}", name),
-//!     None => println!("there are no animals :(")
+//!     None => println!("there are no animals :("),
 //! }
 //! ```
 
@@ -198,7 +198,7 @@ impl<T> Option<T> {
     pub fn is_some(&self) -> bool {
         match *self {
             Some(_) => true,
-            None => false
+            None => false,
         }
     }
 
@@ -244,7 +244,7 @@ pub fn is_none(&self) -> bool {
     pub fn as_ref<'r>(&'r self) -> Option<&'r T> {
         match *self {
             Some(ref x) => Some(x),
-            None => None
+            None => None,
         }
     }
 
@@ -265,7 +265,7 @@ pub fn as_ref<'r>(&'r self) -> Option<&'r T> {
     pub fn as_mut<'r>(&'r mut self) -> Option<&'r mut T> {
         match *self {
             Some(ref mut x) => Some(x),
-            None => None
+            None => None,
         }
     }
 
@@ -376,7 +376,7 @@ pub fn unwrap(self) -> T {
     pub fn unwrap_or(self, def: T) -> T {
         match self {
             Some(x) => x,
-            None => def
+            None => def,
         }
     }
 
@@ -394,7 +394,7 @@ pub fn unwrap_or(self, def: T) -> T {
     pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
         match self {
             Some(x) => x,
-            None => f()
+            None => f(),
         }
     }
 
@@ -420,7 +420,7 @@ pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
     pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
         match self {
             Some(x) => Some(f(x)),
-            None => None
+            None => None,
         }
     }
 
@@ -464,7 +464,7 @@ pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
     pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
         match self {
             Some(t) => f(t),
-            None => default()
+            None => default(),
         }
     }
 
@@ -637,7 +637,7 @@ pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> {
     pub fn or(self, optb: Option<T>) -> Option<T> {
         match self {
             Some(_) => self,
-            None => optb
+            None => optb,
         }
     }
 
@@ -659,7 +659,7 @@ pub fn or(self, optb: Option<T>) -> Option<T> {
     pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
         match self {
             Some(_) => self,
-            None => f()
+            None => f(),
         }
     }
 
@@ -736,7 +736,7 @@ impl<T: Default> Option<T> {
     pub fn unwrap_or_default(self) -> T {
         match self {
             Some(x) => x,
-            None => Default::default()
+            None => Default::default(),
         }
     }
 }
index 0a32c73a848d0dccd0f121dab06c441040ec61a3..dfcd08b69907aab6a1fae17e504c7245f6f7c9c7 100644 (file)
@@ -960,6 +960,100 @@ fn clone(&self) -> sockaddr_un { *self }
             }
         }
 
+        #[cfg(target_arch = "x86")]
+        pub mod arch {
+            pub mod c95 {
+                pub type c_char = i8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i32;
+                pub type c_ulong = u32;
+                pub type c_float = f32;
+                pub type c_double = f64;
+                pub type size_t = u32;
+                pub type ptrdiff_t = i32;
+                pub type clock_t = i32;
+                pub type time_t = i32;
+                pub type suseconds_t = i32;
+                pub type wchar_t = i32;
+            }
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+                pub type intptr_t = i32;
+                pub type uintptr_t = u32;
+                pub type intmax_t = i64;
+                pub type uintmax_t = u64;
+            }
+            pub mod posix88 {
+                pub type off_t = i64;
+                pub type dev_t = u32;
+                pub type ino_t = u32;
+                pub type pid_t = i32;
+                pub type uid_t = u32;
+                pub type gid_t = u32;
+                pub type useconds_t = u32;
+                pub type mode_t = u16;
+                pub type ssize_t = i32;
+            }
+            pub mod posix01 {
+                use types::common::c95::{c_void};
+                use types::common::c99::{uint8_t, uint32_t, int32_t};
+                use types::os::arch::c95::{c_long, time_t};
+                use types::os::arch::posix88::{dev_t, gid_t, ino_t};
+                use types::os::arch::posix88::{mode_t, off_t};
+                use types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = u16;
+                pub type blksize_t = i32;
+                pub type blkcnt_t = i64;
+                pub type fflags_t = u32;
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: dev_t,
+                    pub st_ino: ino_t,
+                    pub st_mode: mode_t,
+                    pub st_nlink: nlink_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: dev_t,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub st_size: off_t,
+                    pub st_blocks: blkcnt_t,
+                    pub st_blksize: blksize_t,
+                    pub st_flags: fflags_t,
+                    pub st_gen: uint32_t,
+                    pub st_lspare: int32_t,
+                    pub st_birthtime: time_t,
+                    pub st_birthtime_nsec: c_long,
+                    pub __unused: [uint8_t; 2],
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                pub type pthread_attr_t = *mut c_void;
+            }
+            pub mod posix08 {
+            }
+            pub mod bsd44 {
+            }
+            pub mod extra {
+            }
+        }
+
         #[cfg(target_arch = "x86_64")]
         pub mod arch {
             pub mod c95 {
@@ -4978,6 +5072,8 @@ pub mod posix01 {
             pub const F_GETFL : c_int = 3;
             pub const F_SETFL : c_int = 4;
 
+            pub const O_ACCMODE : c_int = 3;
+
             pub const SIGTRAP : c_int = 5;
             pub const SIG_IGN: size_t = 1;
 
@@ -5130,6 +5226,7 @@ pub mod extra {
             pub const O_DSYNC : c_int = 4194304;
             pub const O_SYNC : c_int = 128;
             pub const O_NONBLOCK : c_int = 4;
+            pub const F_GETPATH : c_int = 50;
             pub const F_FULLFSYNC : c_int = 51;
 
             pub const MAP_COPY : c_int = 0x0002;
@@ -5151,6 +5248,8 @@ pub mod extra {
             pub const SO_DONTTRUNC: c_int = 0x2000;
             pub const SO_WANTMORE: c_int = 0x4000;
             pub const SO_WANTOOBFLAG: c_int = 0x8000;
+
+            pub const PATH_MAX: c_int = 1024;
         }
         pub mod sysconf {
             use types::os::arch::c95::c_int;
index 3dbc80d352d15598adc357cfc16c47c6e2a34a3e..9aa5daa3a0a275aae3742183ac4f3aa69fe1a68e 100644 (file)
@@ -791,8 +791,7 @@ trait Foo {
     fn bar(&self);
 }
 
-// we now declare a function which takes an object with Foo trait implemented
-// as parameter
+// we now declare a function which takes an object implementing the Foo trait
 fn some_func<T: Foo>(foo: T) {
     foo.bar();
 }
@@ -1006,7 +1005,7 @@ fn baz() {
 
 E0308: r##"
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. This error can occur for several cases, the most common of which is a
+variable. It can occur for several cases, the most common of which is a
 mismatch in the expected type that the compiler inferred for a variable's
 initializing expression, and the actual type explicitly assigned to the
 variable.
diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs
new file mode 100644 (file)
index 0000000..d347740
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::freebsd_base::opts();
+    base.cpu = "pentium4".to_string();
+    base.pre_link_args.push("-m32".to_string());
+    base.morestack = false;
+
+    Target {
+        data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(),
+        llvm_target: "i686-unknown-freebsd".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        arch: "x86".to_string(),
+        target_os: "freebsd".to_string(),
+        target_env: "".to_string(),
+        options: base,
+    }
+}
index 8ecee61621941a7eb735028f8e234ce8fd0e6e68..185d1c9428e86106f00b37499b9c7632fd6a150c 100644 (file)
@@ -368,6 +368,7 @@ macro_rules! load_specific {
             arm_linux_androideabi,
             aarch64_linux_android,
 
+            i686_unknown_freebsd,
             x86_64_unknown_freebsd,
 
             i686_unknown_dragonfly,
index 798cc6a612cde239ce60be7f158839e549bbdaab..2c6f62060b2307f2c96cc1a05a10dc80509efc4e 100644 (file)
@@ -72,7 +72,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
             <div class="search-container">
                 <input class="search-input" name="search"
                        autocomplete="off"
-                       placeholder="Click or press 'S' to search, '?' for more options..."
+                       placeholder="Click or press ‘S’ to search, ‘?’ for more options…"
                        type="search">
             </div>
         </form>
@@ -85,7 +85,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
 
     <div id="help" class="hidden">
         <div class="shortcuts">
-            <h1>Keyboard shortcuts</h1>
+            <h1>Keyboard Shortcuts</h1>
             <dl>
                 <dt>?</dt>
                 <dd>Show this help dialog</dd>
@@ -100,7 +100,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
             </dl>
         </div>
         <div class="infos">
-            <h1>Search tricks</h1>
+            <h1>Search Tricks</h1>
             <p>
                 Prefix searches with a type followed by a colon (e.g.
                 <code>fn:</code>) to restrict the search to a given type.
index aaebdc34cd464729ca782eea957780be535fbbc6..21f1ccc555506ddbb442aafe38c412d5e0bc69e2 100644 (file)
@@ -447,7 +447,6 @@ tr.result span.primitive::after { content: ' (primitive type)'; font-style: ital
 
 #help {
     background: #e9e9e9;
-    border-radius: 4px;
     box-shadow: 0 0 6px rgba(0,0,0,.2);
     position: absolute;
     top: 300px;
@@ -461,7 +460,7 @@ tr.result span.primitive::after { content: ' (primitive type)'; font-style: ital
 
 #help dt {
     float: left;
-    border-radius: 3px;
+    border-radius: 4px;
     border: 1px solid #bfbfbf;
     background: #fff;
     width: 23px;
index 4a033452774666d272202816643a7da7a4f972d4..c77cdd4d021837b645f868253783c939cb5893a9 100644 (file)
     highlightSourceLines(null);
     $(window).on('hashchange', highlightSourceLines);
 
-    // Helper function for Keyboard events,
-    // Get's the char from the keypress event
+    // Gets the human-readable string for the virtual-key code of the
+    // given KeyboardEvent, ev.
     //
-    // This method is used because e.wich === x is not
-    // compatible with non-english keyboard layouts
+    // This function is meant as a polyfill for KeyboardEvent#key,
+    // since it is not supported in Trident.  We also test for
+    // KeyboardEvent#keyCode because the handleShortcut handler is
+    // also registered for the keydown event, because Blink doesn't fire
+    // keypress on hitting the Escape key.
     //
-    // Note: event.type must be keypress !
-    function getChar(event) {
-      if (event.which == null) {
-        return String.fromCharCode(event.keyCode) // IE
-      } else if (event.which!=0 && event.charCode!=0) {
-        return String.fromCharCode(event.which)   // the rest
-      } else {
-        return null // special key
-      }
+    // So I guess you could say things are getting pretty interoperable.
+    function getVirtualKey(ev) {
+        if ("key" in ev && typeof ev.key != "undefined")
+            return ev.key;
+
+        var c = ev.charCode || ev.keyCode;
+        if (c == 27)
+            return "Escape";
+        return String.fromCharCode(c);
     }
 
-    $(document).on('keypress', function handleKeyboardShortcut(e) {
-        if (document.activeElement.tagName === 'INPUT') {
+    function handleShortcut(ev) {
+        if (document.activeElement.tagName == "INPUT")
             return;
-        }
 
-        if (getChar(e) === '?') {
-            if (e.shiftKey && $('#help').hasClass('hidden')) {
-                e.preventDefault();
-                $('#help').removeClass('hidden');
+        switch (getVirtualKey(ev)) {
+        case "Escape":
+            if (!$("#help").hasClass("hidden")) {
+                ev.preventDefault();
+                $("#help").addClass("hidden");
+            } else if (!$("#search").hasClass("hidden")) {
+                ev.preventDefault();
+                $("#search").addClass("hidden");
+                $("#main").removeClass("hidden");
             }
-        } else if (getChar(e) === 's' || getChar(e) === 'S') {
-            e.preventDefault();
-            $('.search-input').focus();
-        }
-    }).on('keydown', function(e) {
-        // The escape key event has to be captured with the keydown event.
-        // Because keypressed has no keycode for the escape key
-        // (and other special keys in general)...
-        if (document.activeElement.tagName === 'INPUT') {
-            return;
-        }
-
-        if (e.keyCode === 27) { // escape key
-            if (!$('#help').hasClass('hidden')) {
-                e.preventDefault();
-                $('#help').addClass('hidden');
-            } else if (!$('#search').hasClass('hidden')) {
-                e.preventDefault();
-                $('#search').addClass('hidden');
-                $('#main').removeClass('hidden');
+            break;
+
+        case "s":
+        case "S":
+            ev.preventDefault();
+            $(".search-input").focus();
+            break;
+
+        case "?":
+            if (ev.shiftKey && $("#help").hasClass("hidden")) {
+                ev.preventDefault();
+                $("#help").removeClass("hidden");
             }
+            break;
         }
-    }).on('click', function(e) {
-        if (!$(e.target).closest('#help').length) {
-            $('#help').addClass('hidden');
+    }
+
+    $(document).on("keypress", handleShortcut);
+    $(document).on("keydown", handleShortcut);
+    $(document).on("click", function(ev) {
+        if (!$(ev.target).closest("#help").length) {
+            $("#help").addClass("hidden");
         }
     });
 
-
     $('.version-selector').on('change', function() {
         var i, match,
             url = document.location.href,
 
         document.location.href = url;
     });
+
     /**
      * A function to compute the Levenshtein distance between two strings
      * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
index ff947d93fca16786e56fff3a4dd5ce22316439b6..ef8bdf5e2ce9738146d429b227f1c8a5b817777d 100644 (file)
@@ -16,7 +16,8 @@ document.addEventListener('DOMContentLoaded', function() {
         return;
     }
 
-    var elements = document.querySelectorAll('pre.rust');
+    var featureRegexp = new RegExp('^\s*#!\\[feature\\(\.*?\\)\\]');
+    var elements = document.querySelectorAll('pre.rust-example-rendered');
 
     Array.prototype.forEach.call(elements, function(el) {
         el.onmouseover = function(e) {
@@ -29,8 +30,14 @@ document.addEventListener('DOMContentLoaded', function() {
             a.setAttribute('class', 'test-arrow');
 
             var code = el.previousElementSibling.textContent;
+
+            var channel = '';
+            if (featureRegexp.test(code)) {
+                channel = '&version=nightly';
+            }
+
             a.setAttribute('href', window.playgroundUrl + '?code=' +
-                           encodeURIComponent(code));
+                           encodeURIComponent(code) + channel);
             a.setAttribute('target', '_blank');
 
             el.appendChild(a);
index e79e5d5a680f60bc3a8b2284adeb59eef252c0a7..0dfcc72e3791025cef9ae217059cbf03d97918f2 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 //! A fixed-size array is denoted `[T; N]` for the element type `T` and
-//! the compile time constant size `N`. The size should be zero or positive.
+//! the compile time constant size `N`. The size must be zero or positive.
 //!
 //! Arrays values are created either with an explicit expression that lists
 //! each element: `[x, y, z]` or a repeat expression: `[x; N]`. The repeat
@@ -32,7 +32,9 @@
 //!
 //! [slice]: primitive.slice.html
 //!
-//! ## Examples
+//! Rust does not currently support generics over the size of an array type.
+//!
+//! # Examples
 //!
 //! ```
 //! let mut array: [i32; 3] = [0; 3];
@@ -49,7 +51,5 @@
 //!
 //! ```
 //!
-//! Rust does not currently support generics over the size of an array type.
-//!
 
 #![doc(primitive = "array")]
index f13c10156f579acd7b01801ba1f29a0d415d5584..c9fe6e7e0b123d8e35267eb25347f09f9805c927 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use ascii;
 use borrow::{Cow, ToOwned, Borrow};
 use boxed::Box;
 use clone::Clone;
 use convert::{Into, From};
 use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
 use error::Error;
-use fmt;
+use fmt::{self, Write};
 use io;
 use iter::Iterator;
 use libc;
@@ -268,7 +269,18 @@ fn deref(&self) -> &CStr {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Debug for CString {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&String::from_utf8_lossy(self.as_bytes()), f)
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+#[stable(feature = "cstr_debug", since = "1.3.0")]
+impl fmt::Debug for CStr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        try!(write!(f, "\""));
+        for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
+            try!(f.write_char(byte as char));
+        }
+        write!(f, "\"")
     }
 }
 
@@ -501,8 +513,8 @@ fn build_with_zero3() {
 
     #[test]
     fn formatted() {
-        let s = CString::new(&b"12"[..]).unwrap();
-        assert_eq!(format!("{:?}", s), "\"12\"");
+        let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
+        assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
     }
 
     #[test]
index 2458838bc9d362422eb0bfd43adab65ad541d0f3..7598a1c7a48f0e8b80ede49836e3a4add5edc70e 100644 (file)
@@ -269,14 +269,18 @@ pub fn sync_data(&self) -> io::Result<()> {
     /// will be extended to `size` and have all of the intermediate data filled
     /// in with 0s.
     ///
+    /// # Errors
+    ///
+    /// This function will return an error if the file is not opened for writing.
+    ///
     /// # Examples
     ///
     /// ```no_run
     /// use std::fs::File;
     ///
     /// # fn foo() -> std::io::Result<()> {
-    /// let mut f = try!(File::open("foo.txt"));
-    /// try!(f.set_len(0));
+    /// let mut f = try!(File::create("foo.txt"));
+    /// try!(f.set_len(10));
     /// # Ok(())
     /// # }
     /// ```
index 98d8bc6bdaf723975326cbf22f87e612183914f5..44541b7875423a235fe010717a37368bb32511ae 100644 (file)
@@ -20,7 +20,7 @@
 use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
 use ptr;
 
-/// Wraps a `Read` and buffers input from it.
+/// The `BufReader` struct adds buffering to any reader.
 ///
 /// It can be excessively inefficient to work directly with a `Read` instance.
 /// For example, every call to `read` on `TcpStream` results in a system call.
@@ -29,7 +29,7 @@
 ///
 /// # Examples
 ///
-/// ```no_run
+/// ```
 /// use std::io::prelude::*;
 /// use std::io::BufReader;
 /// use std::fs::File;
@@ -54,12 +54,40 @@ pub struct BufReader<R> {
 
 impl<R: Read> BufReader<R> {
     /// Creates a new `BufReader` with a default buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let mut f = try!(File::open("log.txt"));
+    /// let mut reader = BufReader::new(f);
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(inner: R) -> BufReader<R> {
         BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
     }
 
     /// Creates a new `BufReader` with the specified buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// Creating a buffer with ten bytes of capacity:
+    ///
+    /// ```
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let mut f = try!(File::open("log.txt"));
+    /// let mut reader = BufReader::with_capacity(10, f);
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
         BufReader {
@@ -71,20 +99,65 @@ pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
     }
 
     /// Gets a reference to the underlying reader.
+    ///
+    /// It is inadvisable to directly read from the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let mut f1 = try!(File::open("log.txt"));
+    /// let mut reader = BufReader::new(f1);
+    ///
+    /// let f2 = reader.get_ref();
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_ref(&self) -> &R { &self.inner }
 
     /// Gets a mutable reference to the underlying reader.
     ///
-    /// # Warning
-    ///
     /// It is inadvisable to directly read from the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let mut f1 = try!(File::open("log.txt"));
+    /// let mut reader = BufReader::new(f1);
+    ///
+    /// let f2 = reader.get_mut();
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
 
     /// Unwraps this `BufReader`, returning the underlying reader.
     ///
     /// Note that any leftover data in the internal buffer is lost.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let mut f1 = try!(File::open("log.txt"));
+    /// let mut reader = BufReader::new(f1);
+    ///
+    /// let f2 = reader.into_inner();
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_inner(self) -> R { self.inner }
 }
index a66789bf2873dc01b08e86e6ad6fd745a6ceee6e..3b48ff3096043d4dfb58443ba79c760d0571ad4a 100644 (file)
 use result;
 use sys;
 
-/// A type for results generated by I/O related functions where the `Err` type
-/// is hard-wired to `io::Error`.
+/// A specialized [`Result`][result] type for I/O operations.
+///
+/// [result]: ../result/enum.Result.html
+///
+/// This type is broadly used across `std::io` for any operation which may
+/// produce an error.
 ///
 /// This typedef is generally used to avoid writing out `io::Error` directly and
-/// is otherwise a direct mapping to `std::result::Result`.
+/// is otherwise a direct mapping to `Result`.
+///
+/// While usual Rust style is to import types directly, aliases of `Result`
+/// often are not, to make it easier to distinguish between them. `Result` is
+/// generally assumed to be `std::result::Result`, and so users of this alias
+/// will generally use `io::Result` instead of shadowing the prelude's import
+/// of `std::result::Result`.
+///
+/// # Examples
+///
+/// A convenience function that bubbles an `io::Result` to its caller:
+///
+/// ```
+/// use std::io;
+///
+/// fn get_string() -> io::Result<String> {
+///     let mut buffer = String::new();
+///
+///     try!(io::stdin().read_line(&mut buffer));
+///
+///     Ok(buffer)
+/// }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub type Result<T> = result::Result<T, Error>;
 
index 880770eb41485b15f05427f5ebf4a5aa84e2eec5..db5c1da8a42274af24c1560bfa8e17b2b20696f9 100644 (file)
 //! # #![allow(unused_imports)]
 //! use std::io::prelude::*;
 //! ```
-//!
-//! This module contains reexports of many core I/O traits such as `Read`,
-//! `Write` and `BufRead`. Structures and functions are not
-//! contained in this module.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index 2a64d0f6e8c19ea8d96faf3f482ff7ada0a9d19f..62bbb939a71f5dcd8aeddb44772e94c444bf1868 100644 (file)
@@ -154,15 +154,42 @@ pub struct StdinLock<'a> {
     inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>,
 }
 
-/// Creates a new handle to the global standard input stream of this process.
+/// Constructs a new handle to the standard input of the current process.
 ///
-/// The handle returned refers to a globally shared buffer between all threads.
-/// Access is synchronized and can be explicitly controlled with the `lock()`
-/// method.
+/// Each handle returned is a reference to a shared global buffer whose access
+/// is synchronized via a mutex. If you need more explicit control over
+/// locking, see the [lock() method][lock].
+///
+/// [lock]: struct.Stdin.html#method.lock
+///
+/// # Examples
+///
+/// Using implicit synchronization:
+///
+/// ```
+/// use std::io::{self, Read};
+///
+/// # fn foo() -> io::Result<String> {
+/// let mut buffer = String::new();
+/// try!(io::stdin().read_to_string(&mut buffer));
+/// # Ok(buffer)
+/// # }
+/// ```
+///
+/// Using explicit synchronization:
 ///
-/// The `Read` trait is implemented for the returned value but the `BufRead`
-/// trait is not due to the global nature of the standard input stream. The
-/// locked version, `StdinLock`, implements both `Read` and `BufRead`, however.
+/// ```
+/// use std::io::{self, Read};
+///
+/// # fn foo() -> io::Result<String> {
+/// let mut buffer = String::new();
+/// let stdin = io::stdin();
+/// let mut handle = stdin.lock();
+///
+/// try!(handle.read_to_string(&mut buffer));
+/// # Ok(buffer)
+/// # }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stdin() -> Stdin {
     static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init);
@@ -298,13 +325,42 @@ pub struct StdoutLock<'a> {
     inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>,
 }
 
-/// Constructs a new reference to the standard output of the current process.
+/// Constructs a new handle to the standard output of the current process.
 ///
 /// Each handle returned is a reference to a shared global buffer whose access
-/// is synchronized via a mutex. Explicit control over synchronization is
-/// provided via the `lock` method.
+/// is synchronized via a mutex. If you need more explicit control over
+/// locking, see the [lock() method][lock].
+///
+/// [lock]: struct.Stdout.html#method.lock
+///
+/// # Examples
+///
+/// Using implicit synchronization:
+///
+/// ```
+/// use std::io::{self, Write};
+///
+/// # fn foo() -> io::Result<()> {
+/// try!(io::stdout().write(b"hello world"));
 ///
-/// The returned handle implements the `Write` trait.
+/// # Ok(())
+/// # }
+/// ```
+///
+/// Using explicit synchronization:
+///
+/// ```
+/// use std::io::{self, Write};
+///
+/// # fn foo() -> io::Result<()> {
+/// let stdout = io::stdout();
+/// let mut handle = stdout.lock();
+///
+/// try!(handle.write(b"hello world"));
+///
+/// # Ok(())
+/// # }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stdout() -> Stdout {
     static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
@@ -376,12 +432,38 @@ pub struct StderrLock<'a> {
     inner: ReentrantMutexGuard<'a, RefCell<Maybe<StderrRaw>>>,
 }
 
-/// Constructs a new reference to the standard error stream of a process.
+/// Constructs a new handle to the standard error of the current process.
+///
+/// This handle is not buffered.
+///
+/// # Examples
+///
+/// Using implicit synchronization:
+///
+/// ```
+/// use std::io::{self, Write};
+///
+/// # fn foo() -> io::Result<()> {
+/// try!(io::stderr().write(b"hello world"));
+///
+/// # Ok(())
+/// # }
+/// ```
+///
+/// Using explicit synchronization:
+///
+/// ```
+/// use std::io::{self, Write};
+///
+/// # fn foo() -> io::Result<()> {
+/// let stderr = io::stderr();
+/// let mut handle = stderr.lock();
 ///
-/// Each returned handle is synchronized amongst all other handles created from
-/// this function. No handles are buffered, however.
+/// try!(handle.write(b"hello world"));
 ///
-/// The returned handle implements the `Write` trait.
+/// # Ok(())
+/// # }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stderr() -> Stderr {
     static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init);
index d8c999f8948379eb9c80c325606bf438a32c1654..c0bced26beffafce9c5c78483aaaa3c2efaf0fe1 100644 (file)
 /// This function will return an error immediately if any call to `read` or
 /// `write` returns an error. All instances of `ErrorKind::Interrupted` are
 /// handled by this function and the underlying operation is retried.
+///
+/// # Examples
+///
+/// ```
+/// use std::io;
+///
+/// # fn foo() -> io::Result<()> {
+/// let mut reader: &[u8] = b"hello";
+/// let mut writer: Vec<u8> = vec![];
+///
+/// try!(io::copy(&mut reader, &mut writer));
+///
+/// assert_eq!(reader, &writer[..]);
+/// # Ok(())
+/// # }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn copy<R: Read, W: Write>(reader: &mut R, writer: &mut W) -> io::Result<u64> {
     let mut buf = [0; super::DEFAULT_BUF_SIZE];
@@ -48,9 +64,24 @@ pub fn copy<R: Read, W: Write>(reader: &mut R, writer: &mut W) -> io::Result<u64
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Empty { _priv: () }
 
-/// Creates an instance of an empty reader.
+/// Constructs a new handle to an empty reader.
 ///
 /// All reads from the returned reader will return `Ok(0)`.
+///
+/// # Examples
+///
+/// A slightly sad example of not reading anything into a buffer:
+///
+/// ```
+/// use std::io;
+/// use std::io::Read;
+///
+/// # fn foo() -> io::Result<String> {
+/// let mut buffer = String::new();
+/// try!(io::empty().read_to_string(&mut buffer));
+/// # Ok(buffer)
+/// # }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn empty() -> Empty { Empty { _priv: () } }
 
index 002e3b20c354222cff5c7f39eefa0b03ce906790..41c8ac4aed30d1653b74f4acf3bcd9a5d1827022 100644 (file)
@@ -170,8 +170,7 @@ unsafe fn target_record_sp_limit(limit: usize) {
         asm!("movl $$0x48+90*4, %eax
               movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile")
     }
-    #[cfg(all(target_arch = "x86",
-              any(target_os = "linux", target_os = "freebsd")))]
+    #[cfg(all(target_arch = "x86", target_os = "linux"))]
     #[inline(always)]
     unsafe fn target_record_sp_limit(limit: usize) {
         asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile")
@@ -197,10 +196,12 @@ unsafe fn target_record_sp_limit(limit: usize) {
     // aarch64 - FIXME(AARCH64): missing...
     // powerpc - FIXME(POWERPC): missing...
     // arm-ios - iOS segmented stack is disabled for now, see related notes
-    // openbsd - segmented stack is disabled
+    // openbsd/bitrig/netbsd - no segmented stacks.
+    // x86-freebsd - no segmented stacks.
     #[cfg(any(target_arch = "aarch64",
               target_arch = "powerpc",
               all(target_arch = "arm", target_os = "ios"),
+              all(target_arch = "x86", target_os = "freebsd"),
               target_os = "bitrig",
               target_os = "netbsd",
               target_os = "openbsd"))]
@@ -262,8 +263,7 @@ unsafe fn target_get_sp_limit() -> usize {
               movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile");
         return limit;
     }
-    #[cfg(all(target_arch = "x86",
-              any(target_os = "linux", target_os = "freebsd")))]
+    #[cfg(all(target_arch = "x86", target_os = "linux"))]
     #[inline(always)]
     unsafe fn target_get_sp_limit() -> usize {
         let limit;
@@ -291,14 +291,16 @@ unsafe fn target_get_sp_limit() -> usize {
 
     // aarch64 - FIXME(AARCH64): missing...
     // powerpc - FIXME(POWERPC): missing...
-    // arm-ios - iOS doesn't support segmented stacks yet.
-    // openbsd - OpenBSD doesn't support segmented stacks.
+    // arm-ios - no segmented stacks.
+    // openbsd/bitrig/netbsd - no segmented stacks.
+    // x86-freebsd - no segmented stacks..
     //
     // This function might be called by runtime though
     // so it is unsafe to unreachable, let's return a fixed constant.
     #[cfg(any(target_arch = "aarch64",
               target_arch = "powerpc",
               all(target_arch = "arm", target_os = "ios"),
+              all(target_arch = "x86", target_os = "freebsd"),
               target_os = "bitrig",
               target_os = "netbsd",
               target_os = "openbsd"))]
index 8113d0ea8479cd98e7e41d301e8cea8719c8eb3d..867cdcbab94cb88750c0453ac1141a718ec3be42 100644 (file)
@@ -370,13 +370,25 @@ fn get_path(fd: c_int) -> Option<PathBuf> {
             readlink(&p).ok()
         }
 
-        #[cfg(not(target_os = "linux"))]
+        #[cfg(target_os = "macos")]
+        fn get_path(fd: c_int) -> Option<PathBuf> {
+            let mut buf = vec![0;libc::PATH_MAX as usize];
+            let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
+            if n == -1 {
+                return None;
+            }
+            let l = buf.iter().position(|&c| c == 0).unwrap();
+            buf.truncate(l as usize);
+            Some(PathBuf::from(OsString::from_vec(buf)))
+        }
+
+        #[cfg(not(any(target_os = "linux", target_os = "macos")))]
         fn get_path(_fd: c_int) -> Option<PathBuf> {
             // FIXME(#24570): implement this for other Unix platforms
             None
         }
 
-        #[cfg(target_os = "linux")]
+        #[cfg(any(target_os = "linux", target_os = "macos"))]
         fn get_mode(fd: c_int) -> Option<(bool, bool)> {
             let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
             if mode == -1 {
@@ -390,7 +402,7 @@ fn get_mode(fd: c_int) -> Option<(bool, bool)> {
             }
         }
 
-        #[cfg(not(target_os = "linux"))]
+        #[cfg(not(any(target_os = "linux", target_os = "macos")))]
         fn get_mode(_fd: c_int) -> Option<(bool, bool)> {
             // FIXME(#24570): implement this for other Unix platforms
             None
index 16563be2cfb79ee1dbb9656bd5e34fe88eb2a121..06c14b39e124a640e9b6f85be6b565f1b6cb5af5 100644 (file)
 pub const ERROR_NO_MORE_FILES: libc::DWORD = 18;
 pub const TOKEN_READ: libc::DWORD = 0x20008;
 pub const FILE_FLAG_OPEN_REPARSE_POINT: libc::DWORD = 0x00200000;
+pub const FILE_FLAG_BACKUP_SEMANTICS: libc::DWORD = 0x02000000;
 pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;
 pub const FSCTL_GET_REPARSE_POINT: libc::DWORD = 0x900a8;
 pub const IO_REPARSE_TAG_SYMLINK: libc::DWORD = 0xa000000c;
+pub const IO_REPARSE_TAG_MOUNT_POINT: libc::DWORD = 0xa0000003;
+pub const FSCTL_SET_REPARSE_POINT: libc::DWORD = 0x900a4;
+pub const FSCTL_DELETE_REPARSE_POINT: libc::DWORD = 0x900ac;
 
 pub const SYMBOLIC_LINK_FLAG_DIRECTORY: libc::DWORD = 0x1;
 
@@ -71,6 +75,9 @@
 pub const PROGRESS_STOP: libc::DWORD = 2;
 pub const PROGRESS_QUIET: libc::DWORD = 3;
 
+pub const TOKEN_ADJUST_PRIVILEGES: libc::DWORD = 0x0020;
+pub const SE_PRIVILEGE_ENABLED: libc::DWORD = 2;
+
 #[repr(C)]
 #[cfg(target_arch = "x86")]
 pub struct WSADATA {
@@ -287,6 +294,40 @@ pub struct CRITICAL_SECTION {
 };
 pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: 0 as *mut _ };
 
+#[repr(C)]
+pub struct LUID {
+    pub LowPart: libc::DWORD,
+    pub HighPart: libc::c_long,
+}
+
+pub type PLUID = *mut LUID;
+
+#[repr(C)]
+pub struct TOKEN_PRIVILEGES {
+    pub PrivilegeCount: libc::DWORD,
+    pub Privileges: [LUID_AND_ATTRIBUTES; 1],
+}
+
+pub type PTOKEN_PRIVILEGES = *mut TOKEN_PRIVILEGES;
+
+#[repr(C)]
+pub struct LUID_AND_ATTRIBUTES {
+    pub Luid: LUID,
+    pub Attributes: libc::DWORD,
+}
+
+#[repr(C)]
+pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
+    pub ReparseTag: libc::DWORD,
+    pub ReparseDataLength: libc::DWORD,
+    pub Reserved: libc::WORD,
+    pub ReparseTargetLength: libc::WORD,
+    pub ReparseTargetMaximumLength: libc::WORD,
+    pub Reserved1: libc::WORD,
+    pub ReparseTarget: libc::WCHAR,
+}
+
+
 #[link(name = "ws2_32")]
 #[link(name = "userenv")]
 extern "system" {
@@ -437,6 +478,15 @@ pub fn CopyFileExW(lpExistingFileName: libc::LPCWSTR,
                        lpData: libc::LPVOID,
                        pbCancel: LPBOOL,
                        dwCopyFlags: libc::DWORD) -> libc::BOOL;
+    pub fn LookupPrivilegeValueW(lpSystemName: libc::LPCWSTR,
+                                 lpName: libc::LPCWSTR,
+                                 lpLuid: PLUID) -> libc::BOOL;
+    pub fn AdjustTokenPrivileges(TokenHandle: libc::HANDLE,
+                                 DisableAllPrivileges: libc::BOOL,
+                                 NewState: PTOKEN_PRIVILEGES,
+                                 BufferLength: libc::DWORD,
+                                 PreviousState: PTOKEN_PRIVILEGES,
+                                 ReturnLength: *mut libc::DWORD) -> libc::BOOL;
 }
 
 // Functions that aren't available on Windows XP, but we still use them and just
index ae6b20de63910079d53270f749ece6c32bfa446a..890cc455d5df2a2816e3b2eeb9531e337b4a392e 100644 (file)
@@ -30,12 +30,12 @@ pub struct File { handle: Handle }
 
 pub struct FileAttr {
     data: c::WIN32_FILE_ATTRIBUTE_DATA,
-    is_symlink: bool,
+    reparse_tag: libc::DWORD,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub enum FileType {
-    Dir, File, Symlink, ReparsePoint
+    Dir, File, Symlink, ReparsePoint, MountPoint,
 }
 
 pub struct ReadDir {
@@ -133,7 +133,7 @@ pub fn file_name(&self) -> OsString {
 
     pub fn file_type(&self) -> io::Result<FileType> {
         Ok(FileType::new(self.data.dwFileAttributes,
-                         self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK))
+                         /* reparse_tag = */ self.data.dwReserved0))
     }
 
     pub fn metadata(&self) -> io::Result<FileAttr> {
@@ -146,7 +146,7 @@ pub fn metadata(&self) -> io::Result<FileAttr> {
                 nFileSizeHigh: self.data.nFileSizeHigh,
                 nFileSizeLow: self.data.nFileSizeLow,
             },
-            is_symlink: self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK,
+            reparse_tag: self.data.dwReserved0,
         })
     }
 }
@@ -218,10 +218,12 @@ fn get_flags_and_attributes(&self) -> libc::DWORD {
 }
 
 impl File {
-    fn open_reparse_point(path: &Path) -> io::Result<File> {
+    fn open_reparse_point(path: &Path, write: bool) -> io::Result<File> {
         let mut opts = OpenOptions::new();
-        opts.read(true);
-        opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT);
+        opts.read(!write);
+        opts.write(write);
+        opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT |
+                                  c::FILE_FLAG_BACKUP_SEMANTICS);
         File::open(path, &opts)
     }
 
@@ -278,10 +280,13 @@ pub fn file_attr(&self) -> io::Result<FileAttr> {
                     nFileSizeHigh: info.nFileSizeHigh,
                     nFileSizeLow: info.nFileSizeLow,
                 },
-                is_symlink: false,
+                reparse_tag: 0,
             };
             if attr.is_reparse_point() {
-                attr.is_symlink = self.is_symlink();
+                let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+                if let Ok((_, buf)) = self.reparse_point(&mut b) {
+                    attr.reparse_tag = buf.ReparseTag;
+                }
             }
             Ok(attr)
         }
@@ -314,15 +319,11 @@ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
 
     pub fn handle(&self) -> &Handle { &self.handle }
 
-    fn is_symlink(&self) -> bool {
-        self.readlink().is_ok()
-    }
-
-    fn readlink(&self) -> io::Result<PathBuf> {
-        let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
-        let mut bytes = 0;
-
+    fn reparse_point<'a>(&self,
+                         space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE])
+                         -> io::Result<(libc::DWORD, &'a c::REPARSE_DATA_BUFFER)> {
         unsafe {
+            let mut bytes = 0;
             try!(cvt({
                 c::DeviceIoControl(self.handle.raw(),
                                    c::FSCTL_GET_REPARSE_POINT,
@@ -333,12 +334,20 @@ fn readlink(&self) -> io::Result<PathBuf> {
                                    &mut bytes,
                                    0 as *mut _)
             }));
-            let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _;
-            if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK {
-                return Err(io::Error::new(io::ErrorKind::Other, "not a symlink"))
-            }
+            Ok((bytes, &*(space.as_ptr() as *const c::REPARSE_DATA_BUFFER)))
+        }
+    }
+
+    fn readlink(&self) -> io::Result<PathBuf> {
+        let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+        let (_bytes, buf) = try!(self.reparse_point(&mut space));
+        if buf.ReparseTag != c::IO_REPARSE_TAG_SYMLINK {
+            return Err(io::Error::new(io::ErrorKind::Other, "not a symlink"))
+        }
+
+        unsafe {
             let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
-                    &(*buf).rest as *const _ as *const _;
+                    &buf.rest as *const _ as *const _;
             let path_buffer = &(*info).PathBuffer as *const _ as *const u16;
             let subst_off = (*info).SubstituteNameOffset / 2;
             let subst_ptr = path_buffer.offset(subst_off as isize);
@@ -383,7 +392,7 @@ pub fn perm(&self) -> FilePermissions {
     pub fn attrs(&self) -> u32 { self.data.dwFileAttributes as u32 }
 
     pub fn file_type(&self) -> FileType {
-        FileType::new(self.data.dwFileAttributes, self.is_symlink)
+        FileType::new(self.data.dwFileAttributes, self.reparse_tag)
     }
 
     pub fn created(&self) -> u64 { self.to_u64(&self.data.ftCreationTime) }
@@ -414,12 +423,12 @@ pub fn set_readonly(&mut self, readonly: bool) {
 }
 
 impl FileType {
-    fn new(attrs: libc::DWORD, is_symlink: bool) -> FileType {
+    fn new(attrs: libc::DWORD, reparse_tag: libc::DWORD) -> FileType {
         if attrs & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-            if is_symlink {
-                FileType::Symlink
-            } else {
-                FileType::ReparsePoint
+            match reparse_tag {
+                c::IO_REPARSE_TAG_SYMLINK => FileType::Symlink,
+                c::IO_REPARSE_TAG_MOUNT_POINT => FileType::MountPoint,
+                _ => FileType::ReparsePoint,
             }
         } else if attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0 {
             FileType::Dir
@@ -430,7 +439,9 @@ fn new(attrs: libc::DWORD, is_symlink: bool) -> FileType {
 
     pub fn is_dir(&self) -> bool { *self == FileType::Dir }
     pub fn is_file(&self) -> bool { *self == FileType::File }
-    pub fn is_symlink(&self) -> bool { *self == FileType::Symlink }
+    pub fn is_symlink(&self) -> bool {
+        *self == FileType::Symlink || *self == FileType::MountPoint
+    }
 }
 
 impl DirBuilder {
@@ -488,7 +499,7 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    let file = try!(File::open_reparse_point(p));
+    let file = try!(File::open_reparse_point(p, false));
     file.readlink()
 }
 
@@ -517,8 +528,15 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
     let attr = try!(lstat(p));
-    if attr.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-        let opts = OpenOptions::new();
+
+    // If this is a reparse point, then we need to reopen the file to get the
+    // actual destination. We also pass the FILE_FLAG_BACKUP_SEMANTICS flag to
+    // ensure that we can open directories (this path may be a directory
+    // junction). Once the file is opened we ask the opened handle what its
+    // metadata information is.
+    if attr.is_reparse_point() {
+        let mut opts = OpenOptions::new();
+        opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS);
         let file = try!(File::open(p, &opts));
         file.file_attr()
     } else {
@@ -534,9 +552,10 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
                                          c::GetFileExInfoStandard,
                                          &mut attr.data as *mut _ as *mut _)));
         if attr.is_reparse_point() {
-            attr.is_symlink = File::open_reparse_point(p).map(|f| {
-                f.is_symlink()
-            }).unwrap_or(false);
+            attr.reparse_tag = File::open_reparse_point(p, false).and_then(|f| {
+                let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+                f.reparse_point(&mut b).map(|(_, b)| b.ReparseTag)
+            }).unwrap_or(0);
         }
         Ok(attr)
     }
@@ -600,3 +619,124 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     }));
     Ok(size as u64)
 }
+
+#[test]
+fn directory_junctions_are_directories() {
+    use ffi::OsStr;
+    use env;
+    use rand::{self, StdRng, Rng};
+
+    macro_rules! t {
+        ($e:expr) => (match $e {
+            Ok(e) => e,
+            Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+        })
+    }
+
+    let d = DirBuilder::new();
+    let p = env::temp_dir();
+    let mut r = rand::thread_rng();
+    let ret = p.join(&format!("rust-{}", r.next_u32()));
+    let foo = ret.join("foo");
+    let bar = ret.join("bar");
+    t!(d.mkdir(&ret));
+    t!(d.mkdir(&foo));
+    t!(d.mkdir(&bar));
+
+    t!(create_junction(&bar, &foo));
+    let metadata = stat(&bar);
+    t!(delete_junction(&bar));
+
+    t!(rmdir(&foo));
+    t!(rmdir(&bar));
+    t!(rmdir(&ret));
+
+    let metadata = t!(metadata);
+    assert!(metadata.file_type().is_dir());
+
+    // Creating a directory junction on windows involves dealing with reparse
+    // points and the DeviceIoControl function, and this code is a skeleton of
+    // what can be found here:
+    //
+    // http://www.flexhex.com/docs/articles/hard-links.phtml
+    fn create_junction(src: &Path, dst: &Path) -> io::Result<()> {
+        let f = try!(opendir(src, true));
+        let h = f.handle().raw();
+
+        unsafe {
+            let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+            let mut db = data.as_mut_ptr()
+                            as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
+            let mut buf = &mut (*db).ReparseTarget as *mut _;
+            let mut i = 0;
+            let v = br"\??\";
+            let v = v.iter().map(|x| *x as u16);
+            for c in v.chain(dst.as_os_str().encode_wide()) {
+                *buf.offset(i) = c;
+                i += 1;
+            }
+            *buf.offset(i) = 0;
+            i += 1;
+            (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT;
+            (*db).ReparseTargetMaximumLength = (i * 2) as libc::WORD;
+            (*db).ReparseTargetLength = ((i - 1) * 2) as libc::WORD;
+            (*db).ReparseDataLength =
+                    (*db).ReparseTargetLength as libc::DWORD + 12;
+
+            let mut ret = 0;
+            cvt(c::DeviceIoControl(h as *mut _,
+                                   c::FSCTL_SET_REPARSE_POINT,
+                                   data.as_ptr() as *mut _,
+                                   (*db).ReparseDataLength + 8,
+                                   0 as *mut _, 0,
+                                   &mut ret,
+                                   0 as *mut _)).map(|_| ())
+        }
+    }
+
+    fn opendir(p: &Path, write: bool) -> io::Result<File> {
+        unsafe {
+            let mut token = 0 as *mut _;
+            let mut tp: c::TOKEN_PRIVILEGES = mem::zeroed();
+            try!(cvt(c::OpenProcessToken(c::GetCurrentProcess(),
+                                         c::TOKEN_ADJUST_PRIVILEGES,
+                                         &mut token)));
+            let name: &OsStr = if write {
+                "SeRestorePrivilege".as_ref()
+            } else {
+                "SeBackupPrivilege".as_ref()
+            };
+            let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
+            try!(cvt(c::LookupPrivilegeValueW(0 as *const _,
+                                              name.as_ptr(),
+                                              &mut tp.Privileges[0].Luid)));
+            tp.PrivilegeCount = 1;
+            tp.Privileges[0].Attributes = c::SE_PRIVILEGE_ENABLED;
+            let size = mem::size_of::<c::TOKEN_PRIVILEGES>() as libc::DWORD;
+            try!(cvt(c::AdjustTokenPrivileges(token, libc::FALSE, &mut tp, size,
+                                              0 as *mut _, 0 as *mut _)));
+            try!(cvt(libc::CloseHandle(token)));
+
+            File::open_reparse_point(p, write)
+        }
+    }
+
+    fn delete_junction(p: &Path) -> io::Result<()> {
+        unsafe {
+            let f = try!(opendir(p, true));
+            let h = f.handle().raw();
+            let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+            let mut db = data.as_mut_ptr()
+                            as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
+            (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT;
+            let mut bytes = 0;
+            cvt(c::DeviceIoControl(h as *mut _,
+                                   c::FSCTL_DELETE_REPARSE_POINT,
+                                   data.as_ptr() as *mut _,
+                                   (*db).ReparseDataLength + 8,
+                                   0 as *mut _, 0,
+                                   &mut bytes,
+                                   0 as *mut _)).map(|_| ())
+        }
+    }
+}
index 0da191a30ba385215c5eb1dc97c2b5f076f93b07..c37d3747da75c280237dc2d6b925078e69555499 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0da191a30ba385215c5eb1dc97c2b5f076f93b07
+Subproject commit c37d3747da75c280237dc2d6b925078e69555499