From 02ae1e10605dccf29c77f94dbbf916b28d2b7c54 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Sun, 8 Jan 2017 16:35:13 +0530 Subject: Support unprivileged symlink creation in Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symlink creation on Windows has in the past basically required admin; it’s being opened up a bit in the Creators Update, so that at least people who have put their computers into Developer Mode will be able to create symlinks without special privileges. (Microsoft are being cautious about it all; the Developer Mode requirement makes it so that it this won’t be as helpful as I’d like, but it’s still an improvement over requiring admin.) Because of compatibility concerns, they’ve hidden this new functionality behind a new flag in the CreateSymbolicLink dwFlags: SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE. So we add this flag in order to join the party. Older Windows doesn’t like this new flag, though, so if we encounter ERROR_INVALID_PARAMETER we try again without the new flag. Sources: - https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/ is the official announcement (search for CreateSymbolicLink) - https://news.ycombinator.com/item?id=13096354 on why the new flag. - https://twitter.com/richturn_ms/status/818167548269051905 confirming that Developer Mode will still be required. --- src/libstd/sys/windows/c.rs | 1 + src/libstd/sys/windows/fs.rs | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 910d802f059..7b8575f9ec4 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -166,6 +166,7 @@ pub const SYMLINK_FLAG_RELATIVE: DWORD = 0x00000001; pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1; +pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2; // Note that these are not actually HANDLEs, just values to pass to GetStdHandle pub const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index c410fcd1ee0..4efc68afdc4 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -646,9 +646,25 @@ pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { let src = to_u16s(src)?; let dst = to_u16s(dst)?; let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 }; - cvt(unsafe { - c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL - })?; + // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10 + // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the + // computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be + // added to dwFlags to opt into this behaviour. + let result = cvt(unsafe { + c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), + flags | c::SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) as c::BOOL + }); + if let Err(err) = result { + if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) { + // Older Windows objects to SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE, + // so if we encounter ERROR_INVALID_PARAMETER, retry without that flag. + cvt(unsafe { + c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL + })?; + } else { + return Err(err); + } + } Ok(()) } -- cgit 1.4.1-3-g733a5 From c2eab73788a066384f3d1facca1ca7b9fc214962 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 21 Dec 2016 21:42:07 +0200 Subject: Expand documentation of process::exit and exec Show a conventional way to use process::exit when destructors are considered important and also mention that the same caveats wrt destructors apply to exec as well. --- src/libstd/process.rs | 21 +++++++++++++++++++-- src/libstd/sys/unix/ext/process.rs | 10 ++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index aa76b792535..011d4d81b89 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -924,10 +924,27 @@ impl Child { /// /// # Examples /// +/// Due to this function’s behavior regarding destructors, a conventional way +/// to use the function is to extract the actual computation to another +/// function and compute the exit code from its return value: +/// /// ``` -/// use std::process; +/// use std::io::{self, Write}; +/// +/// fn run_app() -> Result<(), ()> { +/// // Application logic here +/// Ok(()) +/// } /// -/// process::exit(0); +/// fn main() { +/// ::std::process::exit(match run_app() { +/// Ok(_) => 0, +/// Err(err) => { +/// writeln!(io::stderr(), "error: {:?}", err).unwrap(); +/// 1 +/// } +/// }); +/// } /// ``` /// /// Due to [platform-specific behavior], the exit code for this example will be diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 585dcbb9a34..2961c4ec582 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -67,10 +67,20 @@ pub trait CommandExt { /// an error indicating why the exec (or another part of the setup of the /// `Command`) failed. /// + /// `exec` not returning has the same implications as calling + /// [`process::exit`] – no destructors on the current stack or any other + /// thread’s stack will be run. Therefore, it is recommended to only call + /// `exec` at a point where it is fine to not run any destructors. Note, + /// that the `execvp` syscall independently guarantees that all memory is + /// freed and all file descriptors with the `CLOEXEC` option (set by default + /// on all file descriptors opened by the standard library) are closed. + /// /// This function, unlike `spawn`, will **not** `fork` the process to create /// a new child. Like spawn, however, the default behavior for the stdio /// descriptors will be to inherited from the current process. /// + /// [`process::exit`]: ../../../process/fn.exit.html + /// /// # Notes /// /// The process may be in a "broken state" if this function returns in -- cgit 1.4.1-3-g733a5 From 9128f6100c9bfe2c2c22d85ccec92f01166f5d25 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sun, 29 Jan 2017 13:31:47 +0000 Subject: Fix a few impl stability attributes The versions show up in rustdoc. --- src/libcollections/binary_heap.rs | 4 ++-- src/libcore/char.rs | 6 +++--- src/libcore/internal_macros.rs | 16 ++++++++++++---- src/libcore/iter/traits.rs | 18 +++++++++++------- src/libcore/num/int_macros.rs | 6 +++--- src/libcore/num/uint_macros.rs | 6 +++--- src/libcore/num/wrapping.rs | 30 ++++++++++++++++++++---------- src/libcore/slice.rs | 14 +++++++------- src/libstd/ascii.rs | 2 +- src/libstd/collections/hash/map.rs | 16 ++++++++-------- src/libstd/collections/hash/set.rs | 14 +++++++------- src/libstd/env.rs | 10 +++++----- src/libstd/fs.rs | 2 +- src/libstd/io/mod.rs | 2 +- src/libstd/io/stdio.rs | 12 ++++++------ src/libstd/io/util.rs | 6 +++--- src/libstd/net/mod.rs | 5 ++++- src/libstd/os/raw.rs | 2 +- src/libstd/panic.rs | 2 +- src/libstd/process.rs | 10 +++++----- src/libstd/sync/barrier.rs | 4 ++-- src/libstd/sync/condvar.rs | 2 +- src/libstd/sync/mutex.rs | 2 +- src/libstd/sync/once.rs | 2 +- src/libstd/sync/rwlock.rs | 4 ++-- src/libstd/thread/local.rs | 3 +-- src/libstd/thread/mod.rs | 4 ++-- src/libstd_unicode/char.rs | 5 ++--- 28 files changed, 116 insertions(+), 93 deletions(-) (limited to 'src/libstd') diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index b7c2a708baf..23e0295ba54 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -1088,7 +1088,7 @@ impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for BinaryHeap { fn from(vec: Vec) -> BinaryHeap { let mut heap = BinaryHeap { data: vec }; @@ -1097,7 +1097,7 @@ impl From> for BinaryHeap { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for Vec { fn from(heap: BinaryHeap) -> Vec { heap.data diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 367422f5536..78764091cf0 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -588,7 +588,7 @@ impl ExactSizeIterator for EscapeUnicode { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for EscapeUnicode {} -#[stable(feature = "char_struct_display", since = "1.17.0")] +#[stable(feature = "char_struct_display", since = "1.16.0")] impl fmt::Display for EscapeUnicode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for c in self.clone() { @@ -701,7 +701,7 @@ impl ExactSizeIterator for EscapeDefault { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for EscapeDefault {} -#[stable(feature = "char_struct_display", since = "1.17.0")] +#[stable(feature = "char_struct_display", since = "1.16.0")] impl fmt::Display for EscapeDefault { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for c in self.clone() { @@ -735,7 +735,7 @@ impl ExactSizeIterator for EscapeDebug { } #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for EscapeDebug {} -#[stable(feature = "char_struct_display", since = "1.17.0")] +#[unstable(feature = "char_escape_debug", issue = "35068")] impl fmt::Display for EscapeDebug { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs index f2cdc9d6a98..9a7914064fd 100644 --- a/src/libcore/internal_macros.rs +++ b/src/libcore/internal_macros.rs @@ -13,7 +13,11 @@ // based on "op T" where T is expected to be `Copy`able macro_rules! forward_ref_unop { (impl $imp:ident, $method:ident for $t:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] + forward_ref_unop!(impl $imp, $method for $t, + #[stable(feature = "rust1", since = "1.0.0")]); + }; + (impl $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => { + #[$attr] impl<'a> $imp for &'a $t { type Output = <$t as $imp>::Output; @@ -29,7 +33,11 @@ macro_rules! forward_ref_unop { // based on "T op U" where T and U are expected to be `Copy`able macro_rules! forward_ref_binop { (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] + forward_ref_binop!(impl $imp, $method for $t, $u, + #[stable(feature = "rust1", since = "1.0.0")]); + }; + (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => { + #[$attr] impl<'a> $imp<$u> for &'a $t { type Output = <$t as $imp<$u>>::Output; @@ -39,7 +47,7 @@ macro_rules! forward_ref_binop { } } - #[stable(feature = "rust1", since = "1.0.0")] + #[$attr] impl<'a> $imp<&'a $u> for $t { type Output = <$t as $imp<$u>>::Output; @@ -49,7 +57,7 @@ macro_rules! forward_ref_binop { } } - #[stable(feature = "rust1", since = "1.0.0")] + #[$attr] impl<'a, 'b> $imp<&'a $u> for &'b $t { type Output = <$t as $imp<$u>>::Output; diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 1e127148300..3e8d0600e19 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -603,29 +603,29 @@ pub trait Product: Sized { // NB: explicitly use Add and Mul here to inherit overflow checks macro_rules! integer_sum_product { - (@impls $zero:expr, $one:expr, $($a:ty)*) => ($( - #[stable(feature = "iter_arith_traits", since = "1.12.0")] + (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($( + #[$attr] impl Sum for $a { fn sum>(iter: I) -> $a { iter.fold($zero, Add::add) } } - #[stable(feature = "iter_arith_traits", since = "1.12.0")] + #[$attr] impl Product for $a { fn product>(iter: I) -> $a { iter.fold($one, Mul::mul) } } - #[stable(feature = "iter_arith_traits", since = "1.12.0")] + #[$attr] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { iter.fold($zero, Add::add) } } - #[stable(feature = "iter_arith_traits", since = "1.12.0")] + #[$attr] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { iter.fold($one, Mul::mul) @@ -633,8 +633,12 @@ macro_rules! integer_sum_product { } )*); ($($a:ty)*) => ( - integer_sum_product!(@impls 0, 1, $($a)+); - integer_sum_product!(@impls Wrapping(0), Wrapping(1), $(Wrapping<$a>)+); + integer_sum_product!(@impls 0, 1, + #[stable(feature = "iter_arith_traits", since = "1.12.0")], + $($a)+); + integer_sum_product!(@impls Wrapping(0), Wrapping(1), + #[stable(feature = "wrapping_iter_arith", since = "1.14.0")], + $(Wrapping<$a>)+); ); } diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index 04311d687ea..3b1612a4ee2 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -12,12 +12,12 @@ macro_rules! int_module { ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]);); - ($T:ident, $($attr: tt)*) => ( + ($T:ident, #[$attr:meta]) => ( /// The smallest value that can be represented by this integer type. - $($attr)* + #[$attr] pub const MIN: $T = $T::min_value(); /// The largest value that can be represented by this integer type. - $($attr)* + #[$attr] pub const MAX: $T = $T::max_value(); ) } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 2e59b39278a..f7e1f78d69e 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -12,12 +12,12 @@ macro_rules! uint_module { ($T:ident) => (uint_module!($T, #[stable(feature = "rust1", since = "1.0.0")]);); - ($T:ident, $($attr: tt)*) => ( + ($T:ident, #[$attr:meta]) => ( /// The smallest value that can be represented by this integer type. - $($attr)* + #[$attr] pub const MIN: $T = $T::min_value(); /// The largest value that can be represented by this integer type. - $($attr)* + #[$attr] pub const MAX: $T = $T::max_value(); ) } diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index b3c2c25551e..5d9e6ab1294 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -131,7 +131,8 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_add(other.0)) } } - forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t> } + forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl AddAssign for Wrapping<$t> { @@ -150,7 +151,8 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_sub(other.0)) } } - forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t> } + forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl SubAssign for Wrapping<$t> { @@ -169,7 +171,8 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_mul(other.0)) } } - forward_ref_binop! { impl Mul, mul for Wrapping<$t>, Wrapping<$t> } + forward_ref_binop! { impl Mul, mul for Wrapping<$t>, Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl MulAssign for Wrapping<$t> { @@ -188,7 +191,8 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_div(other.0)) } } - forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t> } + forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl DivAssign for Wrapping<$t> { @@ -207,7 +211,8 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_rem(other.0)) } } - forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t> } + forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl RemAssign for Wrapping<$t> { @@ -226,7 +231,8 @@ macro_rules! wrapping_impl { Wrapping(!self.0) } } - forward_ref_unop! { impl Not, not for Wrapping<$t> } + forward_ref_unop! { impl Not, not for Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } #[stable(feature = "rust1", since = "1.0.0")] impl BitXor for Wrapping<$t> { @@ -237,7 +243,8 @@ macro_rules! wrapping_impl { Wrapping(self.0 ^ other.0) } } - forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t> } + forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl BitXorAssign for Wrapping<$t> { @@ -256,7 +263,8 @@ macro_rules! wrapping_impl { Wrapping(self.0 | other.0) } } - forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t> } + forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl BitOrAssign for Wrapping<$t> { @@ -275,7 +283,8 @@ macro_rules! wrapping_impl { Wrapping(self.0 & other.0) } } - forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t> } + forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl BitAndAssign for Wrapping<$t> { @@ -293,7 +302,8 @@ macro_rules! wrapping_impl { Wrapping(0) - self } } - forward_ref_unop! { impl Neg, neg for Wrapping<$t> } + forward_ref_unop! { impl Neg, neg for Wrapping<$t>, + #[stable(feature = "wrapping_ref", since = "1.14.0")] } )*) } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index b942d85f980..1a482b75731 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -616,7 +616,7 @@ pub trait SliceIndex { fn index_mut(self, slice: &mut [T]) -> &mut Self::Output; } -#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +#[stable(feature = "slice-get-slice-impls", since = "1.15.0")] impl SliceIndex for usize { type Output = T; @@ -665,7 +665,7 @@ impl SliceIndex for usize { } } -#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +#[stable(feature = "slice-get-slice-impls", since = "1.15.0")] impl SliceIndex for ops::Range { type Output = [T]; @@ -726,7 +726,7 @@ impl SliceIndex for ops::Range { } } -#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +#[stable(feature = "slice-get-slice-impls", since = "1.15.0")] impl SliceIndex for ops::RangeTo { type Output = [T]; @@ -761,7 +761,7 @@ impl SliceIndex for ops::RangeTo { } } -#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +#[stable(feature = "slice-get-slice-impls", since = "1.15.0")] impl SliceIndex for ops::RangeFrom { type Output = [T]; @@ -796,7 +796,7 @@ impl SliceIndex for ops::RangeFrom { } } -#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +#[stable(feature = "slice-get-slice-impls", since = "1.15.0")] impl SliceIndex for ops::RangeFull { type Output = [T]; @@ -832,7 +832,7 @@ impl SliceIndex for ops::RangeFull { } -#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] impl SliceIndex for ops::RangeInclusive { type Output = [T]; @@ -895,7 +895,7 @@ impl SliceIndex for ops::RangeInclusive { } } -#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] impl SliceIndex for ops::RangeToInclusive { type Output = [T]; diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index b220504d2b4..35c388ba076 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -399,7 +399,7 @@ impl ExactSizeIterator for EscapeDefault {} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for EscapeDefault {} -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for EscapeDefault { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("EscapeDefault { .. }") diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a314717a877..2a4826f8045 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1276,7 +1276,7 @@ impl<'a, K, V> Clone for Iter<'a, K, V> { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list() @@ -1311,7 +1311,7 @@ impl<'a, K, V> Clone for Keys<'a, K, V> { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K: Debug, V: Debug> fmt::Debug for Keys<'a, K, V> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list() @@ -1334,7 +1334,7 @@ impl<'a, K, V> Clone for Values<'a, K, V> { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K: Debug, V: Debug> fmt::Debug for Values<'a, K, V> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list() @@ -1584,7 +1584,7 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K, V> fmt::Debug for IterMut<'a, K, V> where K: fmt::Debug, V: fmt::Debug, @@ -1619,7 +1619,7 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list() @@ -1697,7 +1697,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K, V> fmt::Debug for ValuesMut<'a, K, V> where K: fmt::Debug, V: fmt::Debug, @@ -1732,7 +1732,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K, V> fmt::Debug for Drain<'a, K, V> where K: fmt::Debug, V: fmt::Debug, @@ -2220,7 +2220,7 @@ impl Default for RandomState { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for RandomState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("RandomState { .. }") diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 341b050862f..a3f7e13bbf9 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -948,7 +948,7 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K> FusedIterator for Iter<'a, K> {} -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K: fmt::Debug> fmt::Debug for Iter<'a, K> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list() @@ -977,7 +977,7 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let entries_iter = self.iter.inner.iter().map(|(k, _)| k); @@ -1007,7 +1007,7 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K> FusedIterator for Drain<'a, K> {} -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K: fmt::Debug> fmt::Debug for Drain<'a, K> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let entries_iter = self.iter.inner.iter().map(|(k, _)| k); @@ -1050,7 +1050,7 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S> } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher, @@ -1109,7 +1109,7 @@ impl<'a, T, S> FusedIterator for Difference<'a, T, S> { } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T, S> fmt::Debug for Difference<'a, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher, @@ -1150,7 +1150,7 @@ impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> { } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T, S> fmt::Debug for SymmetricDifference<'a, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher, @@ -1176,7 +1176,7 @@ impl<'a, T, S> FusedIterator for Union<'a, T, S> { } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T, S> fmt::Debug for Union<'a, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher, diff --git a/src/libstd/env.rs b/src/libstd/env.rs index c3a6b2433ed..29f2ac6ab44 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -145,7 +145,7 @@ impl Iterator for Vars { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Vars { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Vars { .. }") @@ -159,7 +159,7 @@ impl Iterator for VarsOs { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for VarsOs { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("VarsOs { .. }") @@ -382,7 +382,7 @@ impl<'a> Iterator for SplitPaths<'a> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a> fmt::Debug for SplitPaths<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("SplitPaths { .. }") @@ -665,7 +665,7 @@ impl DoubleEndedIterator for Args { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Args { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Args { .. }") @@ -690,7 +690,7 @@ impl DoubleEndedIterator for ArgsOs { fn next_back(&mut self) -> Option { self.inner.next_back() } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ArgsOs { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("ArgsOs { .. }") diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 249627c430c..e5562d05f10 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -869,7 +869,7 @@ impl Metadata { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Metadata { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Metadata") diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index de5fc5bfad1..8cb7b2bda75 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1450,7 +1450,7 @@ pub struct Chain { done_first: bool, } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Chain { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Chain") diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 83a675eb512..e16e8019b5f 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -282,7 +282,7 @@ impl Stdin { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stdin { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Stdin { .. }") @@ -321,7 +321,7 @@ impl<'a> BufRead for StdinLock<'a> { fn consume(&mut self, n: usize) { self.inner.consume(n) } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a> fmt::Debug for StdinLock<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("StdinLock { .. }") @@ -438,7 +438,7 @@ impl Stdout { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stdout { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Stdout { .. }") @@ -470,7 +470,7 @@ impl<'a> Write for StdoutLock<'a> { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a> fmt::Debug for StdoutLock<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("StdoutLock { .. }") @@ -573,7 +573,7 @@ impl Stderr { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stderr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Stderr { .. }") @@ -605,7 +605,7 @@ impl<'a> Write for StderrLock<'a> { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a> fmt::Debug for StderrLock<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("StderrLock { .. }") diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index e50665120eb..4163187488e 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -98,7 +98,7 @@ impl BufRead for Empty { fn consume(&mut self, _n: usize) {} } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Empty { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Empty { .. }") @@ -141,7 +141,7 @@ impl Read for Repeat { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Repeat { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Repeat { .. }") @@ -180,7 +180,7 @@ impl Write for Sink { fn flush(&mut self) -> io::Result<()> { Ok(()) } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Sink { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Sink { .. }") diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 2b60fc38198..b0d2e3e4687 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -106,7 +106,10 @@ impl Iterator for LookupHost { fn next(&mut self) -> Option { self.0.next() } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[unstable(feature = "lookup_host", reason = "unsure about the returned \ + iterator and returning socket \ + addresses", + issue = "27705")] impl fmt::Debug for LookupHost { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("LookupHost { .. }") diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs index cc154f7ab41..68d4ca90019 100644 --- a/src/libstd/os/raw.rs +++ b/src/libstd/os/raw.rs @@ -73,7 +73,7 @@ pub enum c_void { #[doc(hidden)] __variant2, } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for c_void { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("c_void") diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index faf4949e861..ac0d0d2afb8 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -297,7 +297,7 @@ impl R> FnOnce<()> for AssertUnwindSafe { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for AssertUnwindSafe { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("AssertUnwindSafe") diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 5af4ba53bf9..e44c01e32a1 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -114,7 +114,7 @@ impl IntoInner for Child { fn into_inner(self) -> imp::Process { self.handle } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Child { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Child") @@ -160,7 +160,7 @@ impl FromInner for ChildStdin { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ChildStdin { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("ChildStdin { .. }") @@ -201,7 +201,7 @@ impl FromInner for ChildStdout { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ChildStdout { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("ChildStdout { .. }") @@ -242,7 +242,7 @@ impl FromInner for ChildStderr { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ChildStderr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("ChildStderr { .. }") @@ -696,7 +696,7 @@ impl FromInner for Stdio { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stdio { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Stdio { .. }") diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index b8e83dced8d..fc4fd4ce92b 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -55,7 +55,7 @@ struct BarrierState { #[stable(feature = "rust1", since = "1.0.0")] pub struct BarrierWaitResult(bool); -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Barrier { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Barrier { .. }") @@ -110,7 +110,7 @@ impl Barrier { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for BarrierWaitResult { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("BarrierWaitResult") diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 8ab30c51b28..d5bfc331c4e 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -240,7 +240,7 @@ impl Condvar { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Condvar { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Condvar { .. }") diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 2efddeb4610..0d6ad5e38e9 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -428,7 +428,7 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MutexGuard") diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index a9747639aac..ba993751391 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -330,7 +330,7 @@ impl Once { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Once { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Once { .. }") diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index adbb98e4b1f..a3db0adeda0 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -361,7 +361,7 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T: fmt::Debug> fmt::Debug for RwLockReadGuard<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("RwLockReadGuard") @@ -370,7 +370,7 @@ impl<'a, T: fmt::Debug> fmt::Debug for RwLockReadGuard<'a, T> { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("RwLockWriteGuard") diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 01584979aab..5166ddf8a21 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -99,7 +99,7 @@ pub struct LocalKey { init: fn() -> T, } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for LocalKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("LocalKey { .. }") @@ -332,7 +332,6 @@ pub mod os { marker: marker::PhantomData>, } - #[stable(feature = "std_debug", since = "1.15.0")] impl fmt::Debug for Key { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Key { .. }") diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 8789006436c..93e320c4522 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -698,7 +698,7 @@ impl ThreadId { } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[unstable(feature = "thread_id", issue = "21507")] impl fmt::Debug for ThreadId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("ThreadId { .. }") @@ -1002,7 +1002,7 @@ impl IntoInner for JoinHandle { fn into_inner(self) -> imp::Thread { self.0.native.unwrap() } } -#[stable(feature = "std_debug", since = "1.15.0")] +#[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for JoinHandle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("JoinHandle { .. }") diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index f2c53efda17..4269ce8534b 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -131,7 +131,6 @@ impl Iterator for CaseMappingIter { } } -#[stable(feature = "char_struct_display", since = "1.17.0")] impl fmt::Display for CaseMappingIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -152,14 +151,14 @@ impl fmt::Display for CaseMappingIter { } } -#[stable(feature = "char_struct_display", since = "1.17.0")] +#[stable(feature = "char_struct_display", since = "1.16.0")] impl fmt::Display for ToLowercase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } -#[stable(feature = "char_struct_display", since = "1.17.0")] +#[stable(feature = "char_struct_display", since = "1.16.0")] impl fmt::Display for ToUppercase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) -- cgit 1.4.1-3-g733a5 From a40be0857c7bf48e39f815417b0b5293cd8ed1aa Mon Sep 17 00:00:00 2001 From: Tyler Julian Date: Tue, 10 Jan 2017 19:11:56 -0800 Subject: libstd/net: Add `peek` APIs to UdpSocket and TcpStream These methods enable socket reads without side-effects. That is, repeated calls to peek() return identical data. This is accomplished by providing the POSIX flag MSG_PEEK to the underlying socket read operations. This also moves the current implementation of recv_from out of the platform-independent sys_common and into respective sys/windows and sys/unix implementations. This allows for more platform-dependent implementations. --- src/liblibc | 2 +- src/libstd/lib.rs | 1 + src/libstd/net/tcp.rs | 54 ++++++++++++++++++++++++ src/libstd/net/udp.rs | 97 +++++++++++++++++++++++++++++++++++++++++++ src/libstd/sys/unix/net.rs | 45 ++++++++++++++++++-- src/libstd/sys/windows/c.rs | 1 + src/libstd/sys/windows/net.rs | 44 +++++++++++++++++++- src/libstd/sys_common/net.rs | 24 ++++++----- 8 files changed, 251 insertions(+), 17 deletions(-) (limited to 'src/libstd') diff --git a/src/liblibc b/src/liblibc index 7d57bdcdbb5..cb7f6673217 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc +Subproject commit cb7f66732175e6171587ed69656b7aae7dd2e6ec diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9557c520c50..3c06409e3b1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -275,6 +275,7 @@ #![feature(oom)] #![feature(optin_builtin_traits)] #![feature(panic_unwind)] +#![feature(peek)] #![feature(placement_in_syntax)] #![feature(prelude_import)] #![feature(pub_restricted)] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index ed1f08f9c90..ba6160cc723 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -296,6 +296,29 @@ impl TcpStream { self.0.write_timeout() } + /// Receives data on the socket from the remote adress to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peek)] + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8000") + /// .expect("couldn't bind to address"); + /// let mut buf = [0; 10]; + /// let len = stream.peek(&mut buf).expect("peek failed"); + /// ``` + #[unstable(feature = "peek", issue = "38980")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + /// Sets the value of the `TCP_NODELAY` option on this socket. /// /// If set, this option disables the Nagle algorithm. This means that @@ -1405,4 +1428,35 @@ mod tests { Err(e) => panic!("unexpected error {}", e), } } + + #[test] + fn peek() { + each_ip(&mut |addr| { + let (txdone, rxdone) = channel(); + + let srv = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move|| { + let mut cl = t!(srv.accept()).0; + cl.write(&[1,3,3,7]).unwrap(); + t!(rxdone.recv()); + }); + + let mut c = t!(TcpStream::connect(&addr)); + let mut b = [0; 10]; + for _ in 1..3 { + let len = c.peek(&mut b).unwrap(); + assert_eq!(len, 4); + } + let len = c.read(&mut b).unwrap(); + assert_eq!(len, 4); + + t!(c.set_nonblocking(true)); + match c.peek(&mut b) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } + t!(txdone.send(())); + }) + } } diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index f8a5ec0b379..2f28f475dc8 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -83,6 +83,30 @@ impl UdpSocket { self.0.recv_from(buf) } + /// Receives data from the socket, without removing it from the queue. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// On success, returns the number of bytes peeked and the address from + /// whence the data came. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peek)] + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// let mut buf = [0; 10]; + /// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf) + /// .expect("Didn't receive data"); + /// ``` + #[unstable(feature = "peek", issue = "38980")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0.peek_from(buf) + } + /// Sends data on the socket to the given address. On success, returns the /// number of bytes written. /// @@ -579,6 +603,37 @@ impl UdpSocket { self.0.recv(buf) } + /// Receives data on the socket from the remote adress to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Errors + /// + /// This method will fail if the socket is not connected. The `connect` method + /// will connect this socket to a remote address. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peek)] + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.connect("127.0.0.1:8080").expect("connect function failed"); + /// let mut buf = [0; 10]; + /// match socket.peek(&mut buf) { + /// Ok(received) => println!("received {} bytes", received), + /// Err(e) => println!("peek function failed: {:?}", e), + /// } + /// ``` + #[unstable(feature = "peek", issue = "38980")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + /// Moves this UDP socket into or out of nonblocking mode. /// /// On Unix this corresponds to calling fcntl, and on Windows this @@ -869,6 +924,48 @@ mod tests { assert_eq!(b"hello world", &buf[..]); } + #[test] + fn connect_send_peek_recv() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.connect(addr)); + + t!(socket.send(b"hello world")); + + for _ in 1..3 { + let mut buf = [0; 11]; + let size = t!(socket.peek(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + } + + let mut buf = [0; 11]; + let size = t!(socket.recv(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + }) + } + + #[test] + fn peek_from() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.send_to(b"hello world", &addr)); + + for _ in 1..3 { + let mut buf = [0; 11]; + let (size, _) = t!(socket.peek_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + } + + let mut buf = [0; 11]; + let (size, _) = t!(socket.recv_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + }) + } + #[test] fn ttl() { let ttl = 100; diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index ad287bbec38..5efddca110f 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -10,12 +10,13 @@ use ffi::CStr; use io; -use libc::{self, c_int, size_t, sockaddr, socklen_t, EAI_SYSTEM}; +use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK}; +use mem; use net::{SocketAddr, Shutdown}; use str; use sys::fd::FileDesc; use sys_common::{AsInner, FromInner, IntoInner}; -use sys_common::net::{getsockopt, setsockopt}; +use sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; use time::Duration; pub use sys::{cvt, cvt_r}; @@ -155,8 +156,46 @@ impl Socket { self.0.duplicate().map(Socket) } + fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { + let ret = cvt(unsafe { + libc::recv(self.0.raw(), + buf.as_mut_ptr() as *mut c_void, + buf.len(), + flags) + })?; + Ok(ret as usize) + } + pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) + self.recv_with_flags(buf, 0) + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.recv_with_flags(buf, MSG_PEEK) + } + + fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int) + -> io::Result<(usize, SocketAddr)> { + let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t; + + let n = cvt(unsafe { + libc::recvfrom(self.0.raw(), + buf.as_mut_ptr() as *mut c_void, + buf.len(), + flags, + &mut storage as *mut _ as *mut _, + &mut addrlen) + })?; + Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, 0) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, MSG_PEEK) } pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index dc7b2fc9a6b..9f03f5c9717 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -244,6 +244,7 @@ pub const IP_ADD_MEMBERSHIP: c_int = 12; pub const IP_DROP_MEMBERSHIP: c_int = 13; pub const IPV6_ADD_MEMBERSHIP: c_int = 12; pub const IPV6_DROP_MEMBERSHIP: c_int = 13; +pub const MSG_PEEK: c_int = 0x2; #[repr(C)] pub struct ip_mreq { diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index aca6994503f..adf6210d82e 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -147,12 +147,12 @@ impl Socket { Ok(socket) } - pub fn read(&self, buf: &mut [u8]) -> io::Result { + fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> 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. let len = cmp::min(buf.len(), i32::max_value() as usize) as i32; unsafe { - match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, 0) { + match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) { -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), -1 => Err(last_error()), n => Ok(n as usize) @@ -160,6 +160,46 @@ impl Socket { } } + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.recv_with_flags(buf, 0) + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.recv_with_flags(buf, c::MSG_PEEK) + } + + fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int) + -> io::Result<(usize, SocketAddr)> { + let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() }; + let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; + let len = cmp::min(buf.len(), ::max_value() as usize) as wrlen_t; + + // 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 c::recvfrom(self.0, + buf.as_mut_ptr() as *mut c_void, + len, + flags, + &mut storage as *mut _ as *mut _, + &mut addrlen) { + -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => { + Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?)) + }, + -1 => Err(last_error()), + n => Ok((n as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)), + } + } + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, 0) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, c::MSG_PEEK) + } + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { let mut me = self; (&mut me).read_to_end(buf) diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 10ad61f4c80..3cdeb511945 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -91,7 +91,7 @@ fn sockname(f: F) -> io::Result } } -fn sockaddr_to_addr(storage: &c::sockaddr_storage, +pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, len: usize) -> io::Result { match storage.ss_family as c_int { c::AF_INET => { @@ -222,6 +222,10 @@ impl TcpStream { self.inner.timeout(c::SO_SNDTIMEO) } + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.inner.peek(buf) + } + pub fn read(&self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } @@ -441,17 +445,11 @@ impl UdpSocket { } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; - let len = cmp::min(buf.len(), ::max_value() as usize) as wrlen_t; + self.inner.recv_from(buf) + } - let n = cvt(unsafe { - c::recvfrom(*self.inner.as_inner(), - buf.as_mut_ptr() as *mut c_void, - len, 0, - &mut storage as *mut _ as *mut _, &mut addrlen) - })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.inner.peek_from(buf) } pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result { @@ -578,6 +576,10 @@ impl UdpSocket { self.inner.read(buf) } + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.inner.peek(buf) + } + pub fn send(&self, buf: &[u8]) -> io::Result { let len = cmp::min(buf.len(), ::max_value() as usize) as wrlen_t; let ret = cvt(unsafe { -- cgit 1.4.1-3-g733a5