aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-01-21 14:06:28 -0700
committerFenrirWolf <[email protected]>2018-01-21 19:16:33 -0700
commit23be3f4885688e5e0011005e2295c75168854c0a (patch)
treedd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src
parentUpdate CI for Rust nightly-2017-12-01 + other fixes (diff)
downloadctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.tar.xz
ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.zip
Recreate ctr-std from latest nightly
Diffstat (limited to 'ctr-std/src')
-rw-r--r--ctr-std/src/ascii.rs848
-rw-r--r--ctr-std/src/collections/hash/map.rs50
-rw-r--r--ctr-std/src/collections/hash/set.rs53
-rw-r--r--ctr-std/src/collections/hash/table.rs9
-rw-r--r--ctr-std/src/env.rs1065
-rw-r--r--ctr-std/src/error.rs75
-rw-r--r--ctr-std/src/f32.rs403
-rw-r--r--ctr-std/src/f64.rs347
-rw-r--r--ctr-std/src/ffi/c_str.rs738
-rw-r--r--ctr-std/src/ffi/mod.rs151
-rw-r--r--ctr-std/src/ffi/os_str.rs416
-rw-r--r--ctr-std/src/fs.rs612
-rw-r--r--ctr-std/src/heap.rs14
-rw-r--r--ctr-std/src/io/buffered.rs281
-rw-r--r--ctr-std/src/io/cursor.rs197
-rw-r--r--ctr-std/src/io/error.rs81
-rw-r--r--ctr-std/src/io/impls.rs47
-rw-r--r--ctr-std/src/io/lazy.rs2
-rw-r--r--ctr-std/src/io/mod.rs708
-rw-r--r--ctr-std/src/io/stdio.rs90
-rw-r--r--ctr-std/src/io/util.rs67
-rw-r--r--ctr-std/src/lib.rs371
-rw-r--r--ctr-std/src/macros.rs367
-rw-r--r--ctr-std/src/memchr.rs8
-rw-r--r--ctr-std/src/net/addr.rs1067
-rw-r--r--ctr-std/src/net/ip.rs1835
-rw-r--r--ctr-std/src/net/mod.rs186
-rw-r--r--ctr-std/src/net/parser.rs398
-rw-r--r--ctr-std/src/net/tcp.rs1662
-rw-r--r--ctr-std/src/net/test.rs57
-rw-r--r--ctr-std/src/net/udp.rs1116
-rw-r--r--ctr-std/src/num.rs7
-rw-r--r--ctr-std/src/os/linux/fs.rs390
-rw-r--r--ctr-std/src/os/linux/mod.rs16
-rw-r--r--ctr-std/src/os/linux/raw.rs275
-rw-r--r--ctr-std/src/os/macos/fs.rs160
-rw-r--r--ctr-std/src/os/macos/mod.rs16
-rw-r--r--ctr-std/src/os/macos/raw.rs83
-rw-r--r--ctr-std/src/os/mod.rs49
-rw-r--r--ctr-std/src/os/raw.rs108
-rw-r--r--ctr-std/src/panic.rs24
-rw-r--r--ctr-std/src/panicking.rs90
-rw-r--r--ctr-std/src/path.rs785
-rw-r--r--ctr-std/src/prelude/mod.rs32
-rw-r--r--ctr-std/src/prelude/v1.rs6
-rw-r--r--ctr-std/src/primitive_docs.rs1086
-rw-r--r--ctr-std/src/process.rs1846
-rw-r--r--ctr-std/src/rt.rs63
-rw-r--r--ctr-std/src/sync/barrier.rs11
-rw-r--r--ctr-std/src/sync/condvar.rs86
-rw-r--r--ctr-std/src/sync/mpsc/blocking.rs2
-rw-r--r--ctr-std/src/sync/mpsc/cache_aligned.rs37
-rw-r--r--ctr-std/src/sync/mpsc/mod.rs774
-rw-r--r--ctr-std/src/sync/mpsc/mpsc_queue.rs35
-rw-r--r--ctr-std/src/sync/mpsc/select.rs22
-rw-r--r--ctr-std/src/sync/mpsc/spsc_queue.rs192
-rw-r--r--ctr-std/src/sync/mpsc/stream.rs105
-rw-r--r--ctr-std/src/sync/mpsc/sync.rs2
-rw-r--r--ctr-std/src/sync/mutex.rs89
-rw-r--r--ctr-std/src/sync/once.rs117
-rw-r--r--ctr-std/src/sync/rwlock.rs202
-rw-r--r--ctr-std/src/sys/mod.rs67
-rw-r--r--ctr-std/src/sys/unix/args.rs60
-rw-r--r--ctr-std/src/sys/unix/backtrace.rs37
-rw-r--r--ctr-std/src/sys/unix/cmath.rs43
-rw-r--r--ctr-std/src/sys/unix/condvar.rs4
-rw-r--r--ctr-std/src/sys/unix/env.rs19
-rw-r--r--ctr-std/src/sys/unix/ext/ffi.rs60
-rw-r--r--ctr-std/src/sys/unix/ext/io.rs108
-rw-r--r--ctr-std/src/sys/unix/ext/mod.rs31
-rw-r--r--ctr-std/src/sys/unix/ext/raw.rs33
-rw-r--r--ctr-std/src/sys/unix/fd.rs104
-rw-r--r--ctr-std/src/sys/unix/fs.rs131
-rw-r--r--ctr-std/src/sys/unix/io.rs81
-rw-r--r--ctr-std/src/sys/unix/memchr.rs14
-rw-r--r--ctr-std/src/sys/unix/mod.rs53
-rw-r--r--ctr-std/src/sys/unix/mutex.rs30
-rw-r--r--ctr-std/src/sys/unix/net.rs418
-rw-r--r--ctr-std/src/sys/unix/os.rs94
-rw-r--r--ctr-std/src/sys/unix/os_str.rs81
-rw-r--r--ctr-std/src/sys/unix/path.rs2
-rw-r--r--ctr-std/src/sys/unix/pipe.rs35
-rw-r--r--ctr-std/src/sys/unix/process.rs151
-rw-r--r--ctr-std/src/sys/unix/stack_overflow.rs23
-rw-r--r--ctr-std/src/sys/unix/stdio.rs12
-rw-r--r--ctr-std/src/sys/unix/thread.rs53
-rw-r--r--ctr-std/src/sys/unix/thread_local.rs7
-rw-r--r--ctr-std/src/sys/unix/time.rs12
-rw-r--r--ctr-std/src/sys_common/backtrace.rs461
-rw-r--r--ctr-std/src/sys_common/bytestring.rs56
-rw-r--r--ctr-std/src/sys_common/gnu/libbacktrace.rs216
-rw-r--r--ctr-std/src/sys_common/gnu/mod.rs15
-rw-r--r--ctr-std/src/sys_common/io.rs129
-rw-r--r--ctr-std/src/sys_common/memchr.rs230
-rw-r--r--ctr-std/src/sys_common/mod.rs38
-rw-r--r--ctr-std/src/sys_common/net.rs630
-rw-r--r--ctr-std/src/sys_common/poison.rs88
-rw-r--r--ctr-std/src/sys_common/process.rs124
-rw-r--r--ctr-std/src/sys_common/remutex.rs13
-rw-r--r--ctr-std/src/sys_common/thread.rs26
-rw-r--r--ctr-std/src/sys_common/thread_info.rs4
-rw-r--r--ctr-std/src/sys_common/thread_local.rs82
-rw-r--r--ctr-std/src/sys_common/util.rs29
-rw-r--r--ctr-std/src/sys_common/wtf8.rs1284
-rw-r--r--ctr-std/src/termination.rs80
-rw-r--r--ctr-std/src/thread/local.rs87
-rw-r--r--ctr-std/src/thread/mod.rs201
-rw-r--r--ctr-std/src/time/duration.rs247
-rw-r--r--ctr-std/src/time/mod.rs178
109 files changed, 23070 insertions, 2942 deletions
diff --git a/ctr-std/src/ascii.rs b/ctr-std/src/ascii.rs
index a063b85..82e1a34 100644
--- a/ctr-std/src/ascii.rs
+++ b/ctr-std/src/ascii.rs
@@ -9,14 +9,28 @@
// except according to those terms.
//! Operations on ASCII strings and characters.
+//!
+//! Most string operations in Rust act on UTF-8 strings. However, at times it
+//! makes more sense to only consider the ASCII character set for a specific
+//! operation.
+//!
+//! The [`AsciiExt`] trait provides methods that allow for character
+//! operations that only act on the ASCII subset and leave non-ASCII characters
+//! alone.
+//!
+//! The [`escape_default`] function provides an iterator over the bytes of an
+//! escaped version of the character given.
+//!
+//! [`AsciiExt`]: trait.AsciiExt.html
+//! [`escape_default`]: fn.escape_default.html
#![stable(feature = "rust1", since = "1.0.0")]
-use mem;
+use fmt;
use ops::Range;
use iter::FusedIterator;
-/// Extension methods for ASCII-subset only operations on string slices.
+/// Extension methods for ASCII-subset only operations.
///
/// Be aware that operations on seemingly non-ASCII characters can sometimes
/// have unexpected results. Consider this example:
@@ -24,8 +38,8 @@ use iter::FusedIterator;
/// ```
/// use std::ascii::AsciiExt;
///
-/// assert_eq!("café".to_ascii_uppercase(), "CAFÉ");
-/// assert_eq!("café".to_ascii_uppercase(), "CAFé");
+/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFÉ");
+/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFé");
/// ```
///
/// In the first example, the lowercased string is represented `"cafe\u{301}"`
@@ -46,259 +60,436 @@ pub trait AsciiExt {
/// Checks if the value is within the ASCII range.
///
- /// # Examples
+ /// # Note
///
- /// ```
- /// use std::ascii::AsciiExt;
- ///
- /// let ascii = 'a';
- /// let utf8 = '❤';
- ///
- /// assert!(ascii.is_ascii());
- /// assert!(!utf8.is_ascii());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[stable(feature = "rust1", since = "1.0.0")]
fn is_ascii(&self) -> bool;
- /// Makes a copy of the string in ASCII upper case.
+ /// Makes a copy of the value in its ASCII upper case equivalent.
///
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
/// but non-ASCII letters are unchanged.
///
- /// # Examples
+ /// To uppercase the value in-place, use [`make_ascii_uppercase`].
+ ///
+ /// To uppercase ASCII characters in addition to non-ASCII characters, use
+ /// [`str::to_uppercase`].
///
- /// ```
- /// use std::ascii::AsciiExt;
+ /// # Note
///
- /// let ascii = 'a';
- /// let utf8 = '❤';
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
///
- /// assert_eq!('A', ascii.to_ascii_uppercase());
- /// assert_eq!('❤', utf8.to_ascii_uppercase());
- /// ```
+ /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase
+ /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase
#[stable(feature = "rust1", since = "1.0.0")]
fn to_ascii_uppercase(&self) -> Self::Owned;
- /// Makes a copy of the string in ASCII lower case.
+ /// Makes a copy of the value in its ASCII lower case equivalent.
///
/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
/// but non-ASCII letters are unchanged.
///
- /// # Examples
+ /// To lowercase the value in-place, use [`make_ascii_lowercase`].
///
- /// ```
- /// use std::ascii::AsciiExt;
+ /// To lowercase ASCII characters in addition to non-ASCII characters, use
+ /// [`str::to_lowercase`].
///
- /// let ascii = 'A';
- /// let utf8 = '❤';
+ /// # Note
///
- /// assert_eq!('a', ascii.to_ascii_lowercase());
- /// assert_eq!('❤', utf8.to_ascii_lowercase());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ ///
+ /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase
+ /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase
#[stable(feature = "rust1", since = "1.0.0")]
fn to_ascii_lowercase(&self) -> Self::Owned;
- /// Checks that two strings are an ASCII case-insensitive match.
+ /// Checks that two values are an ASCII case-insensitive match.
///
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
- /// but without allocating and copying temporary strings.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ascii::AsciiExt;
+ /// but without allocating and copying temporaries.
///
- /// let ascii1 = 'A';
- /// let ascii2 = 'a';
- /// let ascii3 = 'A';
- /// let ascii4 = 'z';
+ /// # Note
///
- /// assert!(ascii1.eq_ignore_ascii_case(&ascii2));
- /// assert!(ascii1.eq_ignore_ascii_case(&ascii3));
- /// assert!(!ascii1.eq_ignore_ascii_case(&ascii4));
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[stable(feature = "rust1", since = "1.0.0")]
fn eq_ignore_ascii_case(&self, other: &Self) -> bool;
/// Converts this type to its ASCII upper case equivalent in-place.
///
- /// See `to_ascii_uppercase` for more information.
- ///
- /// # Examples
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
///
- /// ```
- /// use std::ascii::AsciiExt;
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
///
- /// let mut ascii = 'a';
+ /// # Note
///
- /// ascii.make_ascii_uppercase();
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
///
- /// assert_eq!('A', ascii);
- /// ```
+ /// [`to_ascii_uppercase`]: #tymethod.to_ascii_uppercase
#[stable(feature = "ascii", since = "1.9.0")]
fn make_ascii_uppercase(&mut self);
/// Converts this type to its ASCII lower case equivalent in-place.
///
- /// See `to_ascii_lowercase` for more information.
- ///
- /// # Examples
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
///
- /// ```
- /// use std::ascii::AsciiExt;
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
///
- /// let mut ascii = 'A';
+ /// # Note
///
- /// ascii.make_ascii_lowercase();
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
///
- /// assert_eq!('a', ascii);
- /// ```
+ /// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase
#[stable(feature = "ascii", since = "1.9.0")]
fn make_ascii_lowercase(&mut self);
+
+ /// Checks if the value is an ASCII alphabetic character:
+ /// U+0041 'A' ... U+005A 'Z' or U+0061 'a' ... U+007A 'z'.
+ /// For strings, true if all characters in the string are
+ /// ASCII alphabetic.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); }
+
+ /// Checks if the value is an ASCII uppercase character:
+ /// U+0041 'A' ... U+005A 'Z'.
+ /// For strings, true if all characters in the string are
+ /// ASCII uppercase.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_uppercase(&self) -> bool { unimplemented!(); }
+
+ /// Checks if the value is an ASCII lowercase character:
+ /// U+0061 'a' ... U+007A 'z'.
+ /// For strings, true if all characters in the string are
+ /// ASCII lowercase.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_lowercase(&self) -> bool { unimplemented!(); }
+
+ /// Checks if the value is an ASCII alphanumeric character:
+ /// U+0041 'A' ... U+005A 'Z', U+0061 'a' ... U+007A 'z', or
+ /// U+0030 '0' ... U+0039 '9'.
+ /// For strings, true if all characters in the string are
+ /// ASCII alphanumeric.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); }
+
+ /// Checks if the value is an ASCII decimal digit:
+ /// U+0030 '0' ... U+0039 '9'.
+ /// For strings, true if all characters in the string are
+ /// ASCII digits.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_digit(&self) -> bool { unimplemented!(); }
+
+ /// Checks if the value is an ASCII hexadecimal digit:
+ /// U+0030 '0' ... U+0039 '9', U+0041 'A' ... U+0046 'F', or
+ /// U+0061 'a' ... U+0066 'f'.
+ /// For strings, true if all characters in the string are
+ /// ASCII hex digits.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); }
+
+ /// Checks if the value is an ASCII punctuation character:
+ ///
+ /// U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`
+ /// U+003A ... U+0040 `: ; < = > ? @`
+ /// U+005B ... U+0060 ``[ \\ ] ^ _ ` ``
+ /// U+007B ... U+007E `{ | } ~`
+ ///
+ /// For strings, true if all characters in the string are
+ /// ASCII punctuation.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_punctuation(&self) -> bool { unimplemented!(); }
+
+ /// Checks if the value is an ASCII graphic character:
+ /// U+0021 '@' ... U+007E '~'.
+ /// For strings, true if all characters in the string are
+ /// ASCII graphic characters.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_graphic(&self) -> bool { unimplemented!(); }
+
+ /// Checks if the value is an ASCII whitespace character:
+ /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED,
+ /// U+000C FORM FEED, or U+000D CARRIAGE RETURN.
+ /// For strings, true if all characters in the string are
+ /// ASCII whitespace.
+ ///
+ /// Rust uses the WhatWG Infra Standard's [definition of ASCII
+ /// whitespace][infra-aw]. There are several other definitions in
+ /// wide use. For instance, [the POSIX locale][pct] includes
+ /// U+000B VERTICAL TAB as well as all the above characters,
+ /// but—from the very same specification—[the default rule for
+ /// "field splitting" in the Bourne shell][bfs] considers *only*
+ /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
+ ///
+ /// If you are writing a program that will process an existing
+ /// file format, check what that format's definition of whitespace is
+ /// before using this function.
+ ///
+ /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
+ /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
+ /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_whitespace(&self) -> bool { unimplemented!(); }
+
+ /// Checks if the value is an ASCII control character:
+ /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE.
+ /// Note that most ASCII whitespace characters are control
+ /// characters, but SPACE is not.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ fn is_ascii_control(&self) -> bool { unimplemented!(); }
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsciiExt for str {
- type Owned = String;
+macro_rules! delegating_ascii_methods {
+ () => {
+ #[inline]
+ fn is_ascii(&self) -> bool { self.is_ascii() }
- #[inline]
- fn is_ascii(&self) -> bool {
- self.bytes().all(|b| b.is_ascii())
+ #[inline]
+ fn to_ascii_uppercase(&self) -> Self::Owned { self.to_ascii_uppercase() }
+
+ #[inline]
+ fn to_ascii_lowercase(&self) -> Self::Owned { self.to_ascii_lowercase() }
+
+ #[inline]
+ fn eq_ignore_ascii_case(&self, o: &Self) -> bool { self.eq_ignore_ascii_case(o) }
+
+ #[inline]
+ fn make_ascii_uppercase(&mut self) { self.make_ascii_uppercase(); }
+
+ #[inline]
+ fn make_ascii_lowercase(&mut self) { self.make_ascii_lowercase(); }
}
+}
- #[inline]
- fn to_ascii_uppercase(&self) -> String {
- let mut bytes = self.as_bytes().to_vec();
- bytes.make_ascii_uppercase();
- // make_ascii_uppercase() preserves the UTF-8 invariant.
- unsafe { String::from_utf8_unchecked(bytes) }
+macro_rules! delegating_ascii_ctype_methods {
+ () => {
+ #[inline]
+ fn is_ascii_alphabetic(&self) -> bool { self.is_ascii_alphabetic() }
+
+ #[inline]
+ fn is_ascii_uppercase(&self) -> bool { self.is_ascii_uppercase() }
+
+ #[inline]
+ fn is_ascii_lowercase(&self) -> bool { self.is_ascii_lowercase() }
+
+ #[inline]
+ fn is_ascii_alphanumeric(&self) -> bool { self.is_ascii_alphanumeric() }
+
+ #[inline]
+ fn is_ascii_digit(&self) -> bool { self.is_ascii_digit() }
+
+ #[inline]
+ fn is_ascii_hexdigit(&self) -> bool { self.is_ascii_hexdigit() }
+
+ #[inline]
+ fn is_ascii_punctuation(&self) -> bool { self.is_ascii_punctuation() }
+
+ #[inline]
+ fn is_ascii_graphic(&self) -> bool { self.is_ascii_graphic() }
+
+ #[inline]
+ fn is_ascii_whitespace(&self) -> bool { self.is_ascii_whitespace() }
+
+ #[inline]
+ fn is_ascii_control(&self) -> bool { self.is_ascii_control() }
}
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsciiExt for u8 {
+ type Owned = u8;
+
+ delegating_ascii_methods!();
+ delegating_ascii_ctype_methods!();
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsciiExt for char {
+ type Owned = char;
+
+ delegating_ascii_methods!();
+ delegating_ascii_ctype_methods!();
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsciiExt for [u8] {
+ type Owned = Vec<u8>;
+
+ delegating_ascii_methods!();
#[inline]
- fn to_ascii_lowercase(&self) -> String {
- let mut bytes = self.as_bytes().to_vec();
- bytes.make_ascii_lowercase();
- // make_ascii_uppercase() preserves the UTF-8 invariant.
- unsafe { String::from_utf8_unchecked(bytes) }
+ fn is_ascii_alphabetic(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_alphabetic())
}
#[inline]
- fn eq_ignore_ascii_case(&self, other: &str) -> bool {
- self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
+ fn is_ascii_uppercase(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_uppercase())
}
- fn make_ascii_uppercase(&mut self) {
- let me: &mut [u8] = unsafe { mem::transmute(self) };
- me.make_ascii_uppercase()
+ #[inline]
+ fn is_ascii_lowercase(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_lowercase())
}
- fn make_ascii_lowercase(&mut self) {
- let me: &mut [u8] = unsafe { mem::transmute(self) };
- me.make_ascii_lowercase()
+ #[inline]
+ fn is_ascii_alphanumeric(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_alphanumeric())
}
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsciiExt for [u8] {
- type Owned = Vec<u8>;
#[inline]
- fn is_ascii(&self) -> bool {
- self.iter().all(|b| b.is_ascii())
+ fn is_ascii_digit(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_digit())
}
#[inline]
- fn to_ascii_uppercase(&self) -> Vec<u8> {
- let mut me = self.to_vec();
- me.make_ascii_uppercase();
- return me
+ fn is_ascii_hexdigit(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_hexdigit())
}
#[inline]
- fn to_ascii_lowercase(&self) -> Vec<u8> {
- let mut me = self.to_vec();
- me.make_ascii_lowercase();
- return me
+ fn is_ascii_punctuation(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_punctuation())
}
#[inline]
- fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
- self.len() == other.len() &&
- self.iter().zip(other).all(|(a, b)| {
- a.eq_ignore_ascii_case(b)
- })
+ fn is_ascii_graphic(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_graphic())
}
- fn make_ascii_uppercase(&mut self) {
- for byte in self {
- byte.make_ascii_uppercase();
- }
+ #[inline]
+ fn is_ascii_whitespace(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_whitespace())
}
- fn make_ascii_lowercase(&mut self) {
- for byte in self {
- byte.make_ascii_lowercase();
- }
+ #[inline]
+ fn is_ascii_control(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_control())
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl AsciiExt for u8 {
- type Owned = u8;
- #[inline]
- fn is_ascii(&self) -> bool { *self & 128 == 0 }
- #[inline]
- fn to_ascii_uppercase(&self) -> u8 { ASCII_UPPERCASE_MAP[*self as usize] }
+impl AsciiExt for str {
+ type Owned = String;
+
+ delegating_ascii_methods!();
+
#[inline]
- fn to_ascii_lowercase(&self) -> u8 { ASCII_LOWERCASE_MAP[*self as usize] }
+ fn is_ascii_alphabetic(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_alphabetic())
+ }
+
#[inline]
- fn eq_ignore_ascii_case(&self, other: &u8) -> bool {
- self.to_ascii_lowercase() == other.to_ascii_lowercase()
+ fn is_ascii_uppercase(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_uppercase())
}
+
#[inline]
- fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
+ fn is_ascii_lowercase(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_lowercase())
+ }
+
#[inline]
- fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
-}
+ fn is_ascii_alphanumeric(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_alphanumeric())
+ }
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsciiExt for char {
- type Owned = char;
#[inline]
- fn is_ascii(&self) -> bool {
- *self as u32 <= 0x7F
+ fn is_ascii_digit(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_digit())
}
#[inline]
- fn to_ascii_uppercase(&self) -> char {
- if self.is_ascii() {
- (*self as u8).to_ascii_uppercase() as char
- } else {
- *self
- }
+ fn is_ascii_hexdigit(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_hexdigit())
}
#[inline]
- fn to_ascii_lowercase(&self) -> char {
- if self.is_ascii() {
- (*self as u8).to_ascii_lowercase() as char
- } else {
- *self
- }
+ fn is_ascii_punctuation(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_punctuation())
}
#[inline]
- fn eq_ignore_ascii_case(&self, other: &char) -> bool {
- self.to_ascii_lowercase() == other.to_ascii_lowercase()
+ fn is_ascii_graphic(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_graphic())
}
#[inline]
- fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
+ fn is_ascii_whitespace(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_whitespace())
+ }
+
#[inline]
- fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
+ fn is_ascii_control(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_control())
+ }
}
-/// An iterator over the escaped version of a byte, constructed via
-/// `std::ascii::escape_default`.
+/// An iterator over the escaped version of a byte.
+///
+/// This `struct` is created by the [`escape_default`] function. See its
+/// documentation for more.
+///
+/// [`escape_default`]: fn.escape_default.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct EscapeDefault {
range: Range<usize>,
@@ -329,6 +520,38 @@ pub struct EscapeDefault {
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b't', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\r');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'r', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\n');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'n', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\'');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'\'', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'"');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'"', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\\');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'\\', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\x9d');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'x', escaped.next().unwrap());
+/// assert_eq!(b'9', escaped.next().unwrap());
+/// assert_eq!(b'd', escaped.next().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn escape_default(c: u8) -> EscapeDefault {
@@ -370,89 +593,20 @@ impl ExactSizeIterator for EscapeDefault {}
#[unstable(feature = "fused", issue = "35602")]
impl FusedIterator for EscapeDefault {}
-
-static ASCII_LOWERCASE_MAP: [u8; 256] = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
- b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
- b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
- b'@',
-
- b'a', b'b', b'c', b'd', b'e', b'f', b'g',
- b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
- b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
- b'x', b'y', b'z',
-
- b'[', b'\\', b']', b'^', b'_',
- b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g',
- b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
- b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
- b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
- 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
- 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-];
-
-static ASCII_UPPERCASE_MAP: [u8; 256] = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
- b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
- b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
- b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
- b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
- b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
- b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
- b'`',
-
- b'A', b'B', b'C', b'D', b'E', b'F', b'G',
- b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
- b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
- b'X', b'Y', b'Z',
-
- b'{', b'|', b'}', b'~', 0x7f,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
- 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
- 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-];
+#[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 { .. }")
+ }
+}
#[cfg(test)]
mod tests {
- use super::*;
+ //! Note that most of these tests are not testing `AsciiExt` methods, but
+ //! test inherent ascii methods of char, u8, str and [u8]. `AsciiExt` is
+ //! just using those methods, though.
+ use super::AsciiExt;
use char::from_u32;
#[test]
@@ -570,4 +724,236 @@ mod tests {
let x = "a".to_string();
x.eq_ignore_ascii_case("A");
}
+
+ // Shorthands used by the is_ascii_* tests.
+ macro_rules! assert_all {
+ ($what:ident, $($str:tt),+) => {{
+ $(
+ for b in $str.chars() {
+ if !b.$what() {
+ panic!("expected {}({}) but it isn't",
+ stringify!($what), b);
+ }
+ }
+ for b in $str.as_bytes().iter() {
+ if !b.$what() {
+ panic!("expected {}(0x{:02x})) but it isn't",
+ stringify!($what), b);
+ }
+ }
+ assert!($str.$what());
+ assert!($str.as_bytes().$what());
+ )+
+ }};
+ ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+))
+ }
+ macro_rules! assert_none {
+ ($what:ident, $($str:tt),+) => {{
+ $(
+ for b in $str.chars() {
+ if b.$what() {
+ panic!("expected not-{}({}) but it is",
+ stringify!($what), b);
+ }
+ }
+ for b in $str.as_bytes().iter() {
+ if b.$what() {
+ panic!("expected not-{}(0x{:02x})) but it is",
+ stringify!($what), b);
+ }
+ }
+ )*
+ }};
+ ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+))
+ }
+
+ #[test]
+ fn test_is_ascii_alphabetic() {
+ assert_all!(is_ascii_alphabetic,
+ "",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ );
+ assert_none!(is_ascii_alphabetic,
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ }
+
+ #[test]
+ fn test_is_ascii_uppercase() {
+ assert_all!(is_ascii_uppercase,
+ "",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ );
+ assert_none!(is_ascii_uppercase,
+ "abcdefghijklmnopqrstuvwxyz",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ }
+
+ #[test]
+ fn test_is_ascii_lowercase() {
+ assert_all!(is_ascii_lowercase,
+ "abcdefghijklmnopqrstuvwxyz",
+ );
+ assert_none!(is_ascii_lowercase,
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ }
+
+ #[test]
+ fn test_is_ascii_alphanumeric() {
+ assert_all!(is_ascii_alphanumeric,
+ "",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ );
+ assert_none!(is_ascii_alphanumeric,
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ }
+
+ #[test]
+ fn test_is_ascii_digit() {
+ assert_all!(is_ascii_digit,
+ "",
+ "0123456789",
+ );
+ assert_none!(is_ascii_digit,
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ }
+
+ #[test]
+ fn test_is_ascii_hexdigit() {
+ assert_all!(is_ascii_hexdigit,
+ "",
+ "0123456789",
+ "abcdefABCDEF",
+ );
+ assert_none!(is_ascii_hexdigit,
+ "ghijklmnopqrstuvwxyz",
+ "GHIJKLMNOQPRSTUVWXYZ",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ }
+
+ #[test]
+ fn test_is_ascii_punctuation() {
+ assert_all!(is_ascii_punctuation,
+ "",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ );
+ assert_none!(is_ascii_punctuation,
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ }
+
+ #[test]
+ fn test_is_ascii_graphic() {
+ assert_all!(is_ascii_graphic,
+ "",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ );
+ assert_none!(is_ascii_graphic,
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ }
+
+ #[test]
+ fn test_is_ascii_whitespace() {
+ assert_all!(is_ascii_whitespace,
+ "",
+ " \t\n\x0c\r",
+ );
+ assert_none!(is_ascii_whitespace,
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x0b\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ }
+
+ #[test]
+ fn test_is_ascii_control() {
+ assert_all!(is_ascii_control,
+ "",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ assert_none!(is_ascii_control,
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " ",
+ );
+ }
}
diff --git a/ctr-std/src/collections/hash/map.rs b/ctr-std/src/collections/hash/map.rs
index 7a79a47..4e5385c 100644
--- a/ctr-std/src/collections/hash/map.rs
+++ b/ctr-std/src/collections/hash/map.rs
@@ -1241,6 +1241,46 @@ impl<K, V, S> HashMap<K, V, S>
self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1)
}
+ /// Removes a key from the map, returning the stored key and value if the
+ /// key was previously in the map.
+ ///
+ /// The key may be any borrowed form of the map's key type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the key type.
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(hash_map_remove_entry)]
+ /// use std::collections::HashMap;
+ ///
+ /// # fn main() {
+ /// let mut map = HashMap::new();
+ /// map.insert(1, "a");
+ /// assert_eq!(map.remove_entry(&1), Some((1, "a")));
+ /// assert_eq!(map.remove(&1), None);
+ /// # }
+ /// ```
+ #[unstable(feature = "hash_map_remove_entry", issue = "46344")]
+ pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ if self.table.size() == 0 {
+ return None;
+ }
+
+ self.search_mut(k)
+ .into_occupied_bucket()
+ .map(|bucket| {
+ let (k, v, _) = pop_internal(bucket);
+ (k, v)
+ })
+ }
+
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns `false`.
@@ -3040,7 +3080,7 @@ mod test_map {
}
#[test]
- fn test_pop() {
+ fn test_remove() {
let mut m = HashMap::new();
m.insert(1, 2);
assert_eq!(m.remove(&1), Some(2));
@@ -3048,6 +3088,14 @@ mod test_map {
}
#[test]
+ fn test_remove_entry() {
+ let mut m = HashMap::new();
+ m.insert(1, 2);
+ assert_eq!(m.remove_entry(&1), Some((1, 2)));
+ assert_eq!(m.remove(&1), None);
+ }
+
+ #[test]
fn test_iterate() {
let mut m = HashMap::with_capacity(4);
for i in 0..32 {
diff --git a/ctr-std/src/collections/hash/set.rs b/ctr-std/src/collections/hash/set.rs
index 51698ce..e9427fb 100644
--- a/ctr-std/src/collections/hash/set.rs
+++ b/ctr-std/src/collections/hash/set.rs
@@ -527,6 +527,16 @@ impl<T, S> HashSet<T, S>
/// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
/// the value type.
///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// assert_eq!(set.get(&2), Some(&2));
+ /// assert_eq!(set.get(&4), None);
+ /// ```
+ ///
/// [`Eq`]: ../../std/cmp/trait.Eq.html
/// [`Hash`]: ../../std/hash/trait.Hash.html
#[stable(feature = "set_recovery", since = "1.9.0")]
@@ -631,6 +641,19 @@ impl<T, S> HashSet<T, S>
/// Adds a value to the set, replacing the existing value, if any, that is equal to the given
/// one. Returns the replaced value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut set = HashSet::new();
+ /// set.insert(Vec::<i32>::new());
+ ///
+ /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0);
+ /// set.replace(Vec::with_capacity(10));
+ /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10);
+ /// ```
#[stable(feature = "set_recovery", since = "1.9.0")]
pub fn replace(&mut self, value: T) -> Option<T> {
Recover::replace(&mut self.map, value)
@@ -671,6 +694,16 @@ impl<T, S> HashSet<T, S>
/// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
/// the value type.
///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// assert_eq!(set.take(&2), Some(2));
+ /// assert_eq!(set.take(&2), None);
+ /// ```
+ ///
/// [`Eq`]: ../../std/cmp/trait.Eq.html
/// [`Hash`]: ../../std/hash/trait.Hash.html
#[stable(feature = "set_recovery", since = "1.9.0")]
@@ -1152,13 +1185,9 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S>
fn next(&mut self) -> Option<&'a T> {
loop {
- match self.iter.next() {
- None => return None,
- Some(elt) => {
- if self.other.contains(elt) {
- return Some(elt);
- }
- }
+ let elt = self.iter.next()?;
+ if self.other.contains(elt) {
+ return Some(elt);
}
}
}
@@ -1202,13 +1231,9 @@ impl<'a, T, S> Iterator for Difference<'a, T, S>
fn next(&mut self) -> Option<&'a T> {
loop {
- match self.iter.next() {
- None => return None,
- Some(elt) => {
- if !self.other.contains(elt) {
- return Some(elt);
- }
- }
+ let elt = self.iter.next()?;
+ if !self.other.contains(elt) {
+ return Some(elt);
}
}
}
diff --git a/ctr-std/src/collections/hash/table.rs b/ctr-std/src/collections/hash/table.rs
index 7e623a0..73bd574 100644
--- a/ctr-std/src/collections/hash/table.rs
+++ b/ctr-std/src/collections/hash/table.rs
@@ -16,7 +16,7 @@ use marker;
use mem::{align_of, size_of, needs_drop};
use mem;
use ops::{Deref, DerefMut};
-use ptr::{self, Unique, Shared};
+use ptr::{self, Unique, NonNull};
use self::BucketState::*;
@@ -123,9 +123,6 @@ pub struct RawTable<K, V> {
marker: marker::PhantomData<(K, V)>,
}
-unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {}
-unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {}
-
// An unsafe view of a RawTable bucket
// Valid indexes are within [0..table_capacity)
pub struct RawBucket<K, V> {
@@ -876,7 +873,7 @@ impl<K, V> RawTable<K, V> {
elems_left,
marker: marker::PhantomData,
},
- table: Shared::from(self),
+ table: NonNull::from(self),
marker: marker::PhantomData,
}
}
@@ -1023,7 +1020,7 @@ impl<K, V> IntoIter<K, V> {
/// Iterator over the entries in a table, clearing the table.
pub struct Drain<'a, K: 'a, V: 'a> {
- table: Shared<RawTable<K, V>>,
+ table: NonNull<RawTable<K, V>>,
iter: RawBuckets<'static, K, V>,
marker: marker::PhantomData<&'a RawTable<K, V>>,
}
diff --git a/ctr-std/src/env.rs b/ctr-std/src/env.rs
new file mode 100644
index 0000000..27bf326
--- /dev/null
+++ b/ctr-std/src/env.rs
@@ -0,0 +1,1065 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! Inspection and manipulation of the process's environment.
+//!
+//! This module contains functions to inspect various aspects such as
+//! environment variables, process arguments, the current directory, and various
+//! other important directories.
+//!
+//! There are several functions and structs in this module that have a
+//! counterpart ending in `os`. Those ending in `os` will return an [`OsString`]
+//! and those without will be returning a [`String`].
+//!
+//! [`OsString`]: ../../std/ffi/struct.OsString.html
+//! [`String`]: ../string/struct.String.html
+
+#![stable(feature = "env", since = "1.0.0")]
+
+use error::Error;
+use ffi::{OsStr, OsString};
+use fmt;
+use io;
+use path::{Path, PathBuf};
+use sys;
+use sys::os as os_imp;
+
+/// Returns the current working directory as a [`PathBuf`].
+///
+/// # Errors
+///
+/// Returns an [`Err`] if the current working directory value is invalid.
+/// Possible cases:
+///
+/// * Current directory does not exist.
+/// * There are insufficient permissions to access the current directory.
+///
+/// [`PathBuf`]: ../../std/path/struct.PathBuf.html
+/// [`Err`]: ../../std/result/enum.Result.html#method.err
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// // We assume that we are in a valid directory.
+/// let path = env::current_dir().unwrap();
+/// println!("The current directory is {}", path.display());
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn current_dir() -> io::Result<PathBuf> {
+ os_imp::getcwd()
+}
+
+/// Changes the current working directory to the specified path.
+///
+/// Returns an [`Err`] if the operation fails.
+///
+/// [`Err`]: ../../std/result/enum.Result.html#method.err
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+/// use std::path::Path;
+///
+/// let root = Path::new("/");
+/// assert!(env::set_current_dir(&root).is_ok());
+/// println!("Successfully changed working directory to {}!", root.display());
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ os_imp::chdir(path.as_ref())
+}
+
+/// An iterator over a snapshot of the environment variables of this process.
+///
+/// This structure is created by the [`std::env::vars`] function. See its
+/// documentation for more.
+///
+/// [`std::env::vars`]: fn.vars.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct Vars { inner: VarsOs }
+
+/// An iterator over a snapshot of the environment variables of this process.
+///
+/// This structure is created by the [`std::env::vars_os`] function. See
+/// its documentation for more.
+///
+/// [`std::env::vars_os`]: fn.vars_os.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct VarsOs { inner: os_imp::Env }
+
+/// Returns an iterator of (variable, value) pairs of strings, for all the
+/// environment variables of the current process.
+///
+/// The returned iterator contains a snapshot of the process's environment
+/// variables at the time of this invocation. Modifications to environment
+/// variables afterwards will not be reflected in the returned iterator.
+///
+/// # Panics
+///
+/// While iterating, the returned iterator will panic if any key or value in the
+/// environment is not valid unicode. If this is not desired, consider using the
+/// [`env::vars_os`] function.
+///
+/// [`env::vars_os`]: fn.vars_os.html
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// // We will iterate through the references to the element returned by
+/// // env::vars();
+/// for (key, value) in env::vars() {
+/// println!("{}: {}", key, value);
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn vars() -> Vars {
+ Vars { inner: vars_os() }
+}
+
+/// Returns an iterator of (variable, value) pairs of OS strings, for all the
+/// environment variables of the current process.
+///
+/// The returned iterator contains a snapshot of the process's environment
+/// variables at the time of this invocation. Modifications to environment
+/// variables afterwards will not be reflected in the returned iterator.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// // We will iterate through the references to the element returned by
+/// // env::vars_os();
+/// for (key, value) in env::vars_os() {
+/// println!("{:?}: {:?}", key, value);
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn vars_os() -> VarsOs {
+ VarsOs { inner: os_imp::env() }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Iterator for Vars {
+ type Item = (String, String);
+ fn next(&mut self) -> Option<(String, String)> {
+ self.inner.next().map(|(a, b)| {
+ (a.into_string().unwrap(), b.into_string().unwrap())
+ })
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[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 { .. }")
+ }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Iterator for VarsOs {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[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 { .. }")
+ }
+}
+
+/// Fetches the environment variable `key` from the current process.
+///
+/// # Errors
+///
+/// * Environment variable is not present
+/// * Environment variable is not valid unicode
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "HOME";
+/// match env::var(key) {
+/// Ok(val) => println!("{}: {:?}", key, val),
+/// Err(e) => println!("couldn't interpret {}: {}", key, e),
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn var<K: AsRef<OsStr>>(key: K) -> Result<String, VarError> {
+ _var(key.as_ref())
+}
+
+fn _var(key: &OsStr) -> Result<String, VarError> {
+ match var_os(key) {
+ Some(s) => s.into_string().map_err(VarError::NotUnicode),
+ None => Err(VarError::NotPresent),
+ }
+}
+
+/// Fetches the environment variable `key` from the current process, returning
+/// [`None`] if the variable isn't set.
+///
+/// [`None`]: ../option/enum.Option.html#variant.None
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "HOME";
+/// match env::var_os(key) {
+/// Some(val) => println!("{}: {:?}", key, val),
+/// None => println!("{} is not defined in the environment.", key)
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
+ _var_os(key.as_ref())
+}
+
+fn _var_os(key: &OsStr) -> Option<OsString> {
+ os_imp::getenv(key).unwrap_or_else(|e| {
+ panic!("failed to get environment variable `{:?}`: {}", key, e)
+ })
+}
+
+/// The error type for operations interacting with environment variables.
+/// Possibly returned from the [`env::var`] function.
+///
+/// [`env::var`]: fn.var.html
+#[derive(Debug, PartialEq, Eq, Clone)]
+#[stable(feature = "env", since = "1.0.0")]
+pub enum VarError {
+ /// The specified environment variable was not present in the current
+ /// process's environment.
+ #[stable(feature = "env", since = "1.0.0")]
+ NotPresent,
+
+ /// The specified environment variable was found, but it did not contain
+ /// valid unicode data. The found data is returned as a payload of this
+ /// variant.
+ #[stable(feature = "env", since = "1.0.0")]
+ NotUnicode(#[stable(feature = "env", since = "1.0.0")] OsString),
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl fmt::Display for VarError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ VarError::NotPresent => write!(f, "environment variable not found"),
+ VarError::NotUnicode(ref s) => {
+ write!(f, "environment variable was not valid unicode: {:?}", s)
+ }
+ }
+ }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Error for VarError {
+ fn description(&self) -> &str {
+ match *self {
+ VarError::NotPresent => "environment variable not found",
+ VarError::NotUnicode(..) => "environment variable was not valid unicode",
+ }
+ }
+}
+
+/// Sets the environment variable `k` to the value `v` for the currently running
+/// process.
+///
+/// Note that while concurrent access to environment variables is safe in Rust,
+/// some platforms only expose inherently unsafe non-threadsafe APIs for
+/// inspecting the environment. As a result extra care needs to be taken when
+/// auditing calls to unsafe external FFI functions to ensure that any external
+/// environment accesses are properly synchronized with accesses in Rust.
+///
+/// Discussion of this unsafety on Unix may be found in:
+///
+/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188)
+/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
+///
+/// # Panics
+///
+/// This function may panic if `key` is empty, contains an ASCII equals sign
+/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
+/// character.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "KEY";
+/// env::set_var(key, "VALUE");
+/// assert_eq!(env::var(key), Ok("VALUE".to_string()));
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(k: K, v: V) {
+ _set_var(k.as_ref(), v.as_ref())
+}
+
+fn _set_var(k: &OsStr, v: &OsStr) {
+ os_imp::setenv(k, v).unwrap_or_else(|e| {
+ panic!("failed to set environment variable `{:?}` to `{:?}`: {}",
+ k, v, e)
+ })
+}
+
+/// Removes an environment variable from the environment of the currently running process.
+///
+/// Note that while concurrent access to environment variables is safe in Rust,
+/// some platforms only expose inherently unsafe non-threadsafe APIs for
+/// inspecting the environment. As a result extra care needs to be taken when
+/// auditing calls to unsafe external FFI functions to ensure that any external
+/// environment accesses are properly synchronized with accesses in Rust.
+///
+/// Discussion of this unsafety on Unix may be found in:
+///
+/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188)
+/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
+///
+/// # Panics
+///
+/// This function may panic if `key` is empty, contains an ASCII equals sign
+/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
+/// character.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "KEY";
+/// env::set_var(key, "VALUE");
+/// assert_eq!(env::var(key), Ok("VALUE".to_string()));
+///
+/// env::remove_var(key);
+/// assert!(env::var(key).is_err());
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn remove_var<K: AsRef<OsStr>>(k: K) {
+ _remove_var(k.as_ref())
+}
+
+fn _remove_var(k: &OsStr) {
+ os_imp::unsetenv(k).unwrap_or_else(|e| {
+ panic!("failed to remove environment variable `{:?}`: {}", k, e)
+ })
+}
+
+/// An iterator that splits an environment variable into paths according to
+/// platform-specific conventions.
+///
+/// This structure is created by the [`std::env::split_paths`] function. See its
+/// documentation for more.
+///
+/// [`std::env::split_paths`]: fn.split_paths.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> }
+
+/// Parses input according to platform conventions for the `PATH`
+/// environment variable.
+///
+/// Returns an iterator over the paths contained in `unparsed`.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "PATH";
+/// match env::var_os(key) {
+/// Some(paths) => {
+/// for path in env::split_paths(&paths) {
+/// println!("'{}'", path.display());
+/// }
+/// }
+/// None => println!("{} is not defined in the environment.", key)
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn split_paths<T: AsRef<OsStr> + ?Sized>(unparsed: &T) -> SplitPaths {
+ SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> { self.inner.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[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 { .. }")
+ }
+}
+
+/// The error type for operations on the `PATH` variable. Possibly returned from
+/// the [`env::join_paths`] function.
+///
+/// [`env::join_paths`]: fn.join_paths.html
+#[derive(Debug)]
+#[stable(feature = "env", since = "1.0.0")]
+pub struct JoinPathsError {
+ inner: os_imp::JoinPathsError
+}
+
+/// Joins a collection of [`Path`]s appropriately for the `PATH`
+/// environment variable.
+///
+/// # Errors
+///
+/// Returns an [`Err`][err] (containing an error message) if one of the input
+/// [`Path`]s contains an invalid character for constructing the `PATH`
+/// variable (a double quote on Windows or a colon on Unix).
+///
+/// [`Path`]: ../../std/path/struct.Path.html
+/// [`OsString`]: ../../std/ffi/struct.OsString.html
+/// [err]: ../../std/result/enum.Result.html#variant.Err
+///
+/// # Examples
+///
+/// Joining paths on a Unix-like platform:
+///
+/// ```
+/// # if cfg!(unix) {
+/// use std::env;
+/// use std::ffi::OsString;
+/// use std::path::Path;
+///
+/// let paths = [Path::new("/bin"), Path::new("/usr/bin")];
+/// let path_os_string = env::join_paths(paths.iter()).unwrap();
+/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin"));
+/// # }
+/// ```
+///
+/// Joining a path containing a colon on a Unix-like platform results in an error:
+///
+/// ```
+/// # if cfg!(unix) {
+/// use std::env;
+/// use std::path::Path;
+///
+/// let paths = [Path::new("/bin"), Path::new("/usr/bi:n")];
+/// assert!(env::join_paths(paths.iter()).is_err());
+/// # }
+/// ```
+///
+/// Using `env::join_paths` with `env::spit_paths` to append an item to the `PATH` environment
+/// variable:
+///
+/// ```
+/// use std::env;
+/// use std::path::PathBuf;
+///
+/// if let Some(path) = env::var_os("PATH") {
+/// let mut paths = env::split_paths(&path).collect::<Vec<_>>();
+/// paths.push(PathBuf::from("/home/xyz/bin"));
+/// let new_path = env::join_paths(paths).unwrap();
+/// env::set_var("PATH", &new_path);
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+ where I: IntoIterator<Item=T>, T: AsRef<OsStr>
+{
+ os_imp::join_paths(paths.into_iter()).map_err(|e| {
+ JoinPathsError { inner: e }
+ })
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Error for JoinPathsError {
+ fn description(&self) -> &str { self.inner.description() }
+}
+
+/// Returns the path of the current user's home directory if known.
+///
+/// # Unix
+///
+/// Returns the value of the 'HOME' environment variable if it is set
+/// and not equal to the empty string. Otherwise, it tries to determine the
+/// home directory by invoking the `getpwuid_r` function on the UID of the
+/// current user.
+///
+/// # Windows
+///
+/// Returns the value of the 'HOME' environment variable if it is
+/// set and not equal to the empty string. Otherwise, returns the value of the
+/// 'USERPROFILE' environment variable if it is set and not equal to the empty
+/// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to
+/// return the appropriate path.
+///
+/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// match env::home_dir() {
+/// Some(path) => println!("{}", path.display()),
+/// None => println!("Impossible to get your home dir!"),
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn home_dir() -> Option<PathBuf> {
+ os_imp::home_dir()
+}
+
+/// Returns the path of a temporary directory.
+///
+/// # Unix
+///
+/// Returns the value of the `TMPDIR` environment variable if it is
+/// set, otherwise for non-Android it returns `/tmp`. If Android, since there
+/// is no global temporary folder (it is usually allocated per-app), it returns
+/// `/data/local/tmp`.
+///
+/// # Windows
+///
+/// Returns the value of, in order, the `TMP`, `TEMP`,
+/// `USERPROFILE` environment variable if any are set and not the empty
+/// string. Otherwise, `temp_dir` returns the path of the Windows directory.
+/// This behavior is identical to that of [`GetTempPath`][msdn], which this
+/// function uses internally.
+///
+/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx
+///
+/// ```
+/// use std::env;
+/// use std::fs::File;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut dir = env::temp_dir();
+/// dir.push("foo.txt");
+///
+/// let f = File::create(dir)?;
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn temp_dir() -> PathBuf {
+ os_imp::temp_dir()
+}
+
+/// Returns the full filesystem path of the current running executable.
+///
+/// # Platform-specific behavior
+///
+/// If the executable was invoked through a symbolic link, some platforms will
+/// return the path of the symbolic link and other platforms will return the
+/// path of the symbolic link’s target.
+///
+/// # Errors
+///
+/// Acquiring the path of the current executable is a platform-specific operation
+/// that can fail for a good number of reasons. Some errors can include, but not
+/// be limited to, filesystem operations failing or general syscall failures.
+///
+/// # Security
+///
+/// The output of this function should not be used in anything that might have
+/// security implications. For example:
+///
+/// ```
+/// fn main() {
+/// println!("{:?}", std::env::current_exe());
+/// }
+/// ```
+///
+/// On Linux systems, if this is compiled as `foo`:
+///
+/// ```bash
+/// $ rustc foo.rs
+/// $ ./foo
+/// Ok("/home/alex/foo")
+/// ```
+///
+/// And you make a hard link of the program:
+///
+/// ```bash
+/// $ ln foo bar
+/// ```
+///
+/// When you run it, you won’t get the path of the original executable, you’ll
+/// get the path of the hard link:
+///
+/// ```bash
+/// $ ./bar
+/// Ok("/home/alex/bar")
+/// ```
+///
+/// This sort of behavior has been known to [lead to privilege escalation] when
+/// used incorrectly.
+///
+/// [lead to privilege escalation]: https://securityvulns.com/Wdocument183.html
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// match env::current_exe() {
+/// Ok(exe_path) => println!("Path of this executable is: {}",
+/// exe_path.display()),
+/// Err(e) => println!("failed to get current exe path: {}", e),
+/// };
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn current_exe() -> io::Result<PathBuf> {
+ os_imp::current_exe()
+}
+
+/// An iterator over the arguments of a process, yielding a [`String`] value for
+/// each argument.
+///
+/// This struct is created by the [`std::env::args`] function. See its
+/// documentation for more.
+///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and may not even exist. This means this property
+/// should not be relied upon for security purposes.
+///
+/// [`String`]: ../string/struct.String.html
+/// [`std::env::args`]: ./fn.args.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct Args { inner: ArgsOs }
+
+/// An iterator over the arguments of a process, yielding an [`OsString`] value
+/// for each argument.
+///
+/// This struct is created by the [`std::env::args_os`] function. See its
+/// documentation for more.
+///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and may not even exist. This means this property
+/// should not be relied upon for security purposes.
+///
+/// [`OsString`]: ../ffi/struct.OsString.html
+/// [`std::env::args_os`]: ./fn.args_os.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct ArgsOs { inner: sys::args::Args }
+
+/// Returns the arguments which this program was started with (normally passed
+/// via the command line).
+///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and may not even exist. This means this property should
+/// not be relied upon for security purposes.
+///
+/// On Unix systems shell usually expands unquoted arguments with glob patterns
+/// (such as `*` and `?`). On Windows this is not done, and such arguments are
+/// passed as-is.
+///
+/// # Panics
+///
+/// The returned iterator will panic during iteration if any argument to the
+/// process is not valid unicode. If this is not desired,
+/// use the [`args_os`] function instead.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// // Prints each argument on a separate line
+/// for argument in env::args() {
+/// println!("{}", argument);
+/// }
+/// ```
+///
+/// [`args_os`]: ./fn.args_os.html
+#[stable(feature = "env", since = "1.0.0")]
+pub fn args() -> Args {
+ Args { inner: args_os() }
+}
+
+/// Returns the arguments which this program was started with (normally passed
+/// via the command line).
+///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and it may not even exist, so this property should
+/// not be relied upon for security purposes.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// // Prints each argument on a separate line
+/// for argument in env::args_os() {
+/// println!("{:?}", argument);
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn args_os() -> ArgsOs {
+ ArgsOs { inner: sys::args::args() }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Iterator for Args {
+ type Item = String;
+ fn next(&mut self) -> Option<String> {
+ self.inner.next().map(|s| s.into_string().unwrap())
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize { self.inner.len() }
+ fn is_empty(&self) -> bool { self.inner.is_empty() }
+}
+
+#[stable(feature = "env_iterators", since = "1.12.0")]
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<String> {
+ self.inner.next_back().map(|s| s.into_string().unwrap())
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Args {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Args")
+ .field("inner", &self.inner.inner.inner_debug())
+ .finish()
+ }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Iterator for ArgsOs {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> { self.inner.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl ExactSizeIterator for ArgsOs {
+ fn len(&self) -> usize { self.inner.len() }
+ fn is_empty(&self) -> bool { self.inner.is_empty() }
+}
+
+#[stable(feature = "env_iterators", since = "1.12.0")]
+impl DoubleEndedIterator for ArgsOs {
+ fn next_back(&mut self) -> Option<OsString> { self.inner.next_back() }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for ArgsOs {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("ArgsOs")
+ .field("inner", &self.inner.inner_debug())
+ .finish()
+ }
+}
+
+/// Constants associated with the current target
+#[stable(feature = "env", since = "1.0.0")]
+pub mod consts {
+ use sys::env::os;
+
+ /// A string describing the architecture of the CPU that is currently
+ /// in use.
+ ///
+ /// Some possible values:
+ ///
+ /// - x86
+ /// - x86_64
+ /// - arm
+ /// - aarch64
+ /// - mips
+ /// - mips64
+ /// - powerpc
+ /// - powerpc64
+ /// - s390x
+ /// - sparc64
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const ARCH: &'static str = super::arch::ARCH;
+
+ /// The family of the operating system. Example value is `unix`.
+ ///
+ /// Some possible values:
+ ///
+ /// - unix
+ /// - windows
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const FAMILY: &'static str = os::FAMILY;
+
+ /// A string describing the specific operating system in use.
+ /// Example value is `linux`.
+ ///
+ /// Some possible values:
+ ///
+ /// - linux
+ /// - macos
+ /// - ios
+ /// - freebsd
+ /// - dragonfly
+ /// - bitrig
+ /// - netbsd
+ /// - openbsd
+ /// - solaris
+ /// - android
+ /// - windows
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const OS: &'static str = os::OS;
+
+ /// Specifies the filename prefix used for shared libraries on this
+ /// platform. Example value is `lib`.
+ ///
+ /// Some possible values:
+ ///
+ /// - lib
+ /// - `""` (an empty string)
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const DLL_PREFIX: &'static str = os::DLL_PREFIX;
+
+ /// Specifies the filename suffix used for shared libraries on this
+ /// platform. Example value is `.so`.
+ ///
+ /// Some possible values:
+ ///
+ /// - .so
+ /// - .dylib
+ /// - .dll
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const DLL_SUFFIX: &'static str = os::DLL_SUFFIX;
+
+ /// Specifies the file extension used for shared libraries on this
+ /// platform that goes after the dot. Example value is `so`.
+ ///
+ /// Some possible values:
+ ///
+ /// - so
+ /// - dylib
+ /// - dll
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const DLL_EXTENSION: &'static str = os::DLL_EXTENSION;
+
+ /// Specifies the filename suffix used for executable binaries on this
+ /// platform. Example value is `.exe`.
+ ///
+ /// Some possible values:
+ ///
+ /// - .exe
+ /// - .nexe
+ /// - .pexe
+ /// - `""` (an empty string)
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const EXE_SUFFIX: &'static str = os::EXE_SUFFIX;
+
+ /// Specifies the file extension, if any, used for executable binaries
+ /// on this platform. Example value is `exe`.
+ ///
+ /// Some possible values:
+ ///
+ /// - exe
+ /// - `""` (an empty string)
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const EXE_EXTENSION: &'static str = os::EXE_EXTENSION;
+}
+
+#[cfg(target_arch = "x86")]
+mod arch {
+ pub const ARCH: &'static str = "x86";
+}
+
+#[cfg(target_arch = "x86_64")]
+mod arch {
+ pub const ARCH: &'static str = "x86_64";
+}
+
+#[cfg(target_arch = "arm")]
+mod arch {
+ pub const ARCH: &'static str = "arm";
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ pub const ARCH: &'static str = "aarch64";
+}
+
+#[cfg(target_arch = "mips")]
+mod arch {
+ pub const ARCH: &'static str = "mips";
+}
+
+#[cfg(target_arch = "mips64")]
+mod arch {
+ pub const ARCH: &'static str = "mips64";
+}
+
+#[cfg(target_arch = "powerpc")]
+mod arch {
+ pub const ARCH: &'static str = "powerpc";
+}
+
+#[cfg(target_arch = "powerpc64")]
+mod arch {
+ pub const ARCH: &'static str = "powerpc64";
+}
+
+#[cfg(target_arch = "s390x")]
+mod arch {
+ pub const ARCH: &'static str = "s390x";
+}
+
+#[cfg(target_arch = "sparc64")]
+mod arch {
+ pub const ARCH: &'static str = "sparc64";
+}
+
+#[cfg(target_arch = "le32")]
+mod arch {
+ pub const ARCH: &'static str = "le32";
+}
+
+#[cfg(target_arch = "asmjs")]
+mod arch {
+ pub const ARCH: &'static str = "asmjs";
+}
+
+#[cfg(target_arch = "wasm32")]
+mod arch {
+ pub const ARCH: &'static str = "wasm32";
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use path::Path;
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn test_self_exe_path() {
+ let path = current_exe();
+ assert!(path.is_ok());
+ let path = path.unwrap();
+
+ // Hard to test this function
+ assert!(path.is_absolute());
+ }
+
+ #[test]
+ fn test() {
+ assert!((!Path::new("test-path").is_absolute()));
+
+ current_dir().unwrap();
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn split_paths_windows() {
+ use path::PathBuf;
+
+ fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+ split_paths(unparsed).collect::<Vec<_>>() ==
+ parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
+ }
+
+ assert!(check_parse("", &mut [""]));
+ assert!(check_parse(r#""""#, &mut [""]));
+ assert!(check_parse(";;", &mut ["", "", ""]));
+ assert!(check_parse(r"c:\", &mut [r"c:\"]));
+ assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
+ assert!(check_parse(r"c:\;c:\Program Files\",
+ &mut [r"c:\", r"c:\Program Files\"]));
+ assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
+ assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
+ &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn split_paths_unix() {
+ use path::PathBuf;
+
+ fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+ split_paths(unparsed).collect::<Vec<_>>() ==
+ parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
+ }
+
+ assert!(check_parse("", &mut [""]));
+ assert!(check_parse("::", &mut ["", "", ""]));
+ assert!(check_parse("/", &mut ["/"]));
+ assert!(check_parse("/:", &mut ["/", ""]));
+ assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn join_paths_unix() {
+ use ffi::OsStr;
+
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ &*join_paths(input.iter().cloned()).unwrap() ==
+ OsStr::new(output)
+ }
+
+ assert!(test_eq(&[], ""));
+ assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"],
+ "/bin:/usr/bin:/usr/local/bin"));
+ assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""],
+ ":/bin:::/usr/bin:"));
+ assert!(join_paths(["/te:st"].iter().cloned()).is_err());
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn join_paths_windows() {
+ use ffi::OsStr;
+
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ &*join_paths(input.iter().cloned()).unwrap() ==
+ OsStr::new(output)
+ }
+
+ assert!(test_eq(&[], ""));
+ assert!(test_eq(&[r"c:\windows", r"c:\"],
+ r"c:\windows;c:\"));
+ assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""],
+ r";c:\windows;;;c:\;"));
+ assert!(test_eq(&[r"c:\te;st", r"c:\"],
+ r#""c:\te;st";c:\"#));
+ assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
+ }
+
+ #[test]
+ fn args_debug() {
+ assert_eq!(
+ format!("Args {{ inner: {:?} }}", args().collect::<Vec<_>>()),
+ format!("{:?}", args()));
+ assert_eq!(
+ format!("ArgsOs {{ inner: {:?} }}", args_os().collect::<Vec<_>>()),
+ format!("{:?}", args_os()));
+ }
+}
diff --git a/ctr-std/src/error.rs b/ctr-std/src/error.rs
index 454fa47..eb5022a 100644
--- a/ctr-std/src/error.rs
+++ b/ctr-std/src/error.rs
@@ -51,9 +51,13 @@
// coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in.
+use alloc::allocator;
use any::TypeId;
+use borrow::Cow;
use cell;
use char;
+use convert;
+use core::array;
use fmt::{self, Debug, Display};
use mem::transmute;
use num;
@@ -109,7 +113,7 @@ pub trait Error: Debug + Display {
///
/// impl Error for SuperError {
/// fn description(&self) -> &str {
- /// "I'm the superhero of errors!"
+ /// "I'm the superhero of errors"
/// }
///
/// fn cause(&self) -> Option<&Error> {
@@ -128,7 +132,7 @@ pub trait Error: Debug + Display {
///
/// impl Error for SuperErrorSideKick {
/// fn description(&self) -> &str {
- /// "I'm SuperError side kick!"
+ /// "I'm SuperError side kick"
/// }
/// }
///
@@ -193,7 +197,7 @@ impl From<String> for Box<Error + Send + Sync> {
}
}
-#[stable(feature = "string_box_error", since = "1.7.0")]
+#[stable(feature = "string_box_error", since = "1.6.0")]
impl From<String> for Box<Error> {
fn from(str_err: String) -> Box<Error> {
let err1: Box<Error + Send + Sync> = From::from(str_err);
@@ -209,13 +213,50 @@ impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> {
}
}
-#[stable(feature = "string_box_error", since = "1.7.0")]
+#[stable(feature = "string_box_error", since = "1.6.0")]
impl<'a> From<&'a str> for Box<Error> {
fn from(err: &'a str) -> Box<Error> {
From::from(String::from(err))
}
}
+#[stable(feature = "cow_box_error", since = "1.22.0")]
+impl<'a, 'b> From<Cow<'b, str>> for Box<Error + Send + Sync + 'a> {
+ fn from(err: Cow<'b, str>) -> Box<Error + Send + Sync + 'a> {
+ From::from(String::from(err))
+ }
+}
+
+#[stable(feature = "cow_box_error", since = "1.22.0")]
+impl<'a> From<Cow<'a, str>> for Box<Error> {
+ fn from(err: Cow<'a, str>) -> Box<Error> {
+ From::from(String::from(err))
+ }
+}
+
+#[unstable(feature = "never_type", issue = "35121")]
+impl Error for ! {
+ fn description(&self) -> &str { *self }
+}
+
+#[unstable(feature = "allocator_api",
+ reason = "the precise API and guarantees it provides may be tweaked.",
+ issue = "32838")]
+impl Error for allocator::AllocErr {
+ fn description(&self) -> &str {
+ allocator::AllocErr::description(self)
+ }
+}
+
+#[unstable(feature = "allocator_api",
+ reason = "the precise API and guarantees it provides may be tweaked.",
+ issue = "32838")]
+impl Error for allocator::CannotReallocInPlace {
+ fn description(&self) -> &str {
+ allocator::CannotReallocInPlace::description(self)
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl Error for str::ParseBoolError {
fn description(&self) -> &str { "failed to parse bool" }
@@ -242,6 +283,13 @@ impl Error for num::TryFromIntError {
}
}
+#[unstable(feature = "try_from", issue = "33417")]
+impl Error for array::TryFromSliceError {
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl Error for num::ParseFloatError {
fn description(&self) -> &str {
@@ -277,7 +325,7 @@ impl Error for char::DecodeUtf16Error {
}
}
-#[stable(feature = "box_error", since = "1.7.0")]
+#[stable(feature = "box_error", since = "1.8.0")]
impl<T: Error> Error for Box<T> {
fn description(&self) -> &str {
Error::description(&**self)
@@ -316,6 +364,21 @@ impl Error for char::CharTryFromError {
}
}
+#[stable(feature = "char_from_str", since = "1.20.0")]
+impl Error for char::ParseCharError {
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[unstable(feature = "try_from", issue = "33417")]
+impl Error for convert::Infallible {
+ fn description(&self) -> &str {
+ match *self {
+ }
+ }
+}
+
// copied from any.rs
impl Error + 'static {
/// Returns true if the boxed type is the same as `T`
@@ -482,7 +545,7 @@ mod tests {
#[test]
fn downcasting() {
let mut a = A;
- let mut a = &mut a as &mut (Error + 'static);
+ let a = &mut a as &mut (Error + 'static);
assert_eq!(a.downcast_ref::<A>(), Some(&A));
assert_eq!(a.downcast_ref::<B>(), None);
assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
diff --git a/ctr-std/src/f32.rs b/ctr-std/src/f32.rs
index f793909..5e5695f 100644
--- a/ctr-std/src/f32.rs
+++ b/ctr-std/src/f32.rs
@@ -8,9 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! The 32-bit floating point type.
+//! This module provides constants which are specific to the implementation
+//! of the `f32` floating point data type.
//!
-//! *[See also the `f32` primitive type](../primitive.f32.html).*
+//! Mathematically significant numbers are provided in the `consts` sub-module.
+//!
+//! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
@@ -20,10 +23,9 @@ use core::num;
#[cfg(not(test))]
use intrinsics;
#[cfg(not(test))]
-use libc::c_int;
-#[cfg(not(test))]
use num::FpCategory;
-
+#[cfg(not(test))]
+use sys::cmath;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON};
@@ -36,110 +38,6 @@ pub use core::f32::{MIN, MIN_POSITIVE, MAX};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::f32::consts;
-#[allow(dead_code)]
-mod cmath {
- use libc::{c_float, c_int};
-
- extern {
- pub fn cbrtf(n: c_float) -> c_float;
- pub fn erff(n: c_float) -> c_float;
- pub fn erfcf(n: c_float) -> c_float;
- pub fn expm1f(n: c_float) -> c_float;
- pub fn fdimf(a: c_float, b: c_float) -> c_float;
- pub fn fmaxf(a: c_float, b: c_float) -> c_float;
- pub fn fminf(a: c_float, b: c_float) -> c_float;
- pub fn fmodf(a: c_float, b: c_float) -> c_float;
- pub fn ilogbf(n: c_float) -> c_int;
- pub fn logbf(n: c_float) -> c_float;
- pub fn log1pf(n: c_float) -> c_float;
- pub fn modff(n: c_float, iptr: &mut c_float) -> c_float;
- pub fn nextafterf(x: c_float, y: c_float) -> c_float;
- pub fn tgammaf(n: c_float) -> c_float;
-
- #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgammaf_r")]
- pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float;
- #[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypotf")]
- pub fn hypotf(x: c_float, y: c_float) -> c_float;
- }
-
- // See the comments in the `floor` function for why MSVC is special
- // here.
- #[cfg(not(target_env = "msvc"))]
- extern {
- pub fn acosf(n: c_float) -> c_float;
- pub fn asinf(n: c_float) -> c_float;
- pub fn atan2f(a: c_float, b: c_float) -> c_float;
- pub fn atanf(n: c_float) -> c_float;
- pub fn coshf(n: c_float) -> c_float;
- pub fn frexpf(n: c_float, value: &mut c_int) -> c_float;
- pub fn ldexpf(x: c_float, n: c_int) -> c_float;
- pub fn sinhf(n: c_float) -> c_float;
- pub fn tanf(n: c_float) -> c_float;
- pub fn tanhf(n: c_float) -> c_float;
- }
-
- #[cfg(target_env = "msvc")]
- pub use self::shims::*;
- #[cfg(target_env = "msvc")]
- mod shims {
- use libc::{c_float, c_int};
-
- #[inline]
- pub unsafe fn acosf(n: c_float) -> c_float {
- f64::acos(n as f64) as c_float
- }
-
- #[inline]
- pub unsafe fn asinf(n: c_float) -> c_float {
- f64::asin(n as f64) as c_float
- }
-
- #[inline]
- pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float {
- f64::atan2(n as f64, b as f64) as c_float
- }
-
- #[inline]
- pub unsafe fn atanf(n: c_float) -> c_float {
- f64::atan(n as f64) as c_float
- }
-
- #[inline]
- pub unsafe fn coshf(n: c_float) -> c_float {
- f64::cosh(n as f64) as c_float
- }
-
- #[inline]
- #[allow(deprecated)]
- pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float {
- let (a, b) = f64::frexp(x as f64);
- *value = b as c_int;
- a as c_float
- }
-
- #[inline]
- #[allow(deprecated)]
- pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float {
- f64::ldexp(x as f64, n as isize) as c_float
- }
-
- #[inline]
- pub unsafe fn sinhf(n: c_float) -> c_float {
- f64::sinh(n as f64) as c_float
- }
-
- #[inline]
- pub unsafe fn tanf(n: c_float) -> c_float {
- f64::tan(n as f64) as c_float
- }
-
- #[inline]
- pub unsafe fn tanhf(n: c_float) -> c_float {
- f64::tanh(n as f64) as c_float
- }
- }
-}
-
#[cfg(not(test))]
#[lang = "f32"]
impl f32 {
@@ -381,39 +279,29 @@ impl f32 {
#[inline]
pub fn signum(self) -> f32 { num::Float::signum(self) }
- /// Returns `true` if `self`'s sign bit is positive, including
- /// `+0.0` and `INFINITY`.
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
///
/// ```
- /// use std::f32;
- ///
- /// let nan = f32::NAN;
/// let f = 7.0_f32;
/// let g = -7.0_f32;
///
/// assert!(f.is_sign_positive());
/// assert!(!g.is_sign_positive());
- /// // Requires both tests to determine if is `NaN`
- /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
- /// Returns `true` if `self`'s sign is negative, including `-0.0`
- /// and `NEG_INFINITY`.
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
///
/// ```
- /// use std::f32;
- ///
- /// let nan = f32::NAN;
/// let f = 7.0f32;
/// let g = -7.0f32;
///
/// assert!(!f.is_sign_negative());
/// assert!(g.is_sign_negative());
- /// // Requires both tests to determine if is `NaN`.
- /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -584,20 +472,19 @@ impl f32 {
/// Returns the logarithm of the number with respect to an arbitrary base.
///
+ /// The result may not be correctly rounded owing to implementation details;
+ /// `self.log2()` can produce more accurate results for base 2, and
+ /// `self.log10()` can produce more accurate results for base 10.
+ ///
/// ```
/// use std::f32;
///
- /// let ten = 10.0f32;
- /// let two = 2.0f32;
- ///
- /// // log10(10) - 1 == 0
- /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs();
+ /// let five = 5.0f32;
///
- /// // log2(2) - 1 == 0
- /// let abs_difference_2 = (two.log(2.0) - 1.0).abs();
+ /// // log5(5) - 1 == 0
+ /// let abs_difference = (five.log(5.0) - 1.0).abs();
///
- /// assert!(abs_difference_10 <= f32::EPSILON);
- /// assert!(abs_difference_2 <= f32::EPSILON);
+ /// assert!(abs_difference <= f32::EPSILON);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -676,89 +563,6 @@ impl f32 {
#[inline]
pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
- /// Constructs a floating point number of `x*2^exp`.
- ///
- /// ```
- /// #![feature(float_extras)]
- ///
- /// use std::f32;
- /// // 3*2^2 - 12 == 0
- /// let abs_difference = (f32::ldexp(3.0, 2) - 12.0).abs();
- ///
- /// assert!(abs_difference <= f32::EPSILON);
- /// ```
- #[unstable(feature = "float_extras",
- reason = "pending integer conventions",
- issue = "27752")]
- #[rustc_deprecated(since = "1.11.0",
- reason = "never really came to fruition and easily \
- implementable outside the standard library")]
- #[inline]
- pub fn ldexp(x: f32, exp: isize) -> f32 {
- unsafe { cmath::ldexpf(x, exp as c_int) }
- }
-
- /// Breaks the number into a normalized fraction and a base-2 exponent,
- /// satisfying:
- ///
- /// * `self = x * 2^exp`
- /// * `0.5 <= abs(x) < 1.0`
- ///
- /// ```
- /// #![feature(float_extras)]
- ///
- /// use std::f32;
- ///
- /// let x = 4.0f32;
- ///
- /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0
- /// let f = x.frexp();
- /// let abs_difference_0 = (f.0 - 0.5).abs();
- /// let abs_difference_1 = (f.1 as f32 - 3.0).abs();
- ///
- /// assert!(abs_difference_0 <= f32::EPSILON);
- /// assert!(abs_difference_1 <= f32::EPSILON);
- /// ```
- #[unstable(feature = "float_extras",
- reason = "pending integer conventions",
- issue = "27752")]
- #[rustc_deprecated(since = "1.11.0",
- reason = "never really came to fruition and easily \
- implementable outside the standard library")]
- #[inline]
- pub fn frexp(self) -> (f32, isize) {
- unsafe {
- let mut exp = 0;
- let x = cmath::frexpf(self, &mut exp);
- (x, exp as isize)
- }
- }
-
- /// Returns the next representable floating-point value in the direction of
- /// `other`.
- ///
- /// ```
- /// #![feature(float_extras)]
- ///
- /// use std::f32;
- ///
- /// let x = 1.0f32;
- ///
- /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs();
- ///
- /// assert!(abs_diff <= f32::EPSILON);
- /// ```
- #[unstable(feature = "float_extras",
- reason = "unsure about its place in the world",
- issue = "27752")]
- #[rustc_deprecated(since = "1.11.0",
- reason = "never really came to fruition and easily \
- implementable outside the standard library")]
- #[inline]
- pub fn next_after(self, other: f32) -> f32 {
- unsafe { cmath::nextafterf(self, other) }
- }
-
/// Returns the maximum of the two numbers.
///
/// ```
@@ -772,7 +576,7 @@ impl f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn max(self, other: f32) -> f32 {
- unsafe { cmath::fmaxf(self, other) }
+ num::Float::max(self, other)
}
/// Returns the minimum of the two numbers.
@@ -788,7 +592,7 @@ impl f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn min(self, other: f32) -> f32 {
- unsafe { cmath::fminf(self, other) }
+ num::Float::min(self, other)
}
/// The positive difference of two numbers.
@@ -1190,6 +994,74 @@ impl f32 {
pub fn atanh(self) -> f32 {
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
}
+
+ /// Raw transmutation to `u32`.
+ ///
+ /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
+ ///
+ /// See `from_bits` for some discussion of the portability of this operation
+ /// (there are almost no issues).
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting!
+ /// assert_eq!((12.5f32).to_bits(), 0x41480000);
+ ///
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn to_bits(self) -> u32 {
+ unsafe { ::mem::transmute(self) }
+ }
+
+ /// Raw transmutation from `u32`.
+ ///
+ /// This is currently identical to `transmute::<u32, f32>(v)` on all platforms.
+ /// It turns out this is incredibly portable, for two reasons:
+ ///
+ /// * Floats and Ints have the same endianess on all supported platforms.
+ /// * IEEE-754 very precisely specifies the bit layout of floats.
+ ///
+ /// However there is one caveat: prior to the 2008 version of IEEE-754, how
+ /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
+ /// (notably x86 and ARM) picked the interpretation that was ultimately
+ /// standardized in 2008, but some didn't (notably MIPS). As a result, all
+ /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
+ ///
+ /// Rather than trying to preserve signaling-ness cross-platform, this
+ /// implementation favours preserving the exact bits. This means that
+ /// any payloads encoded in NaNs will be preserved even if the result of
+ /// this method is sent over the network from an x86 machine to a MIPS one.
+ ///
+ /// If the results of this method are only manipulated by the same
+ /// architecture that produced them, then there is no portability concern.
+ ///
+ /// If the input isn't NaN, then there is no portability concern.
+ ///
+ /// If you don't care about signalingness (very likely), then there is no
+ /// portability concern.
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ /// let v = f32::from_bits(0x41480000);
+ /// let difference = (v - 12.5).abs();
+ /// assert!(difference <= 1e-5);
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn from_bits(v: u32) -> Self {
+ // It turns out the safety issues with sNaN were overblown! Hooray!
+ unsafe { ::mem::transmute(v) }
+ }
}
#[cfg(test)]
@@ -1223,7 +1095,7 @@ mod tests {
assert!(!nan.is_infinite());
assert!(!nan.is_finite());
assert!(!nan.is_normal());
- assert!(!nan.is_sign_positive());
+ assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
}
@@ -1365,23 +1237,6 @@ mod tests {
}
#[test]
- #[allow(deprecated)]
- fn test_integer_decode() {
- assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
- assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
- assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1));
- assert_eq!(0f32.integer_decode(), (0, -150, 1));
- assert_eq!((-0f32).integer_decode(), (0, -150, -1));
- assert_eq!(INFINITY.integer_decode(), (8388608, 105, 1));
- assert_eq!(NEG_INFINITY.integer_decode(), (8388608, 105, -1));
-
- // Ignore the "sign" (quiet / signalling flag) of NAN.
- // It can vary between runtime operations and LLVM folding.
- let (nan_m, nan_e, _nan_s) = NAN.integer_decode();
- assert_eq!((nan_m, nan_e), (12582912, 105));
- }
-
- #[test]
fn test_floor() {
assert_approx_eq!(1.0f32.floor(), 1.0f32);
assert_approx_eq!(1.3f32.floor(), 1.0f32);
@@ -1484,7 +1339,8 @@ mod tests {
assert!(!(-1f32).is_sign_positive());
assert!(!NEG_INFINITY.is_sign_positive());
assert!(!(1f32/NEG_INFINITY).is_sign_positive());
- assert!(!NAN.is_sign_positive());
+ assert!(NAN.is_sign_positive());
+ assert!(!(-NAN).is_sign_positive());
}
#[test]
@@ -1497,6 +1353,7 @@ mod tests {
assert!(NEG_INFINITY.is_sign_negative());
assert!((1f32/NEG_INFINITY).is_sign_negative());
assert!(!NAN.is_sign_negative());
+ assert!((-NAN).is_sign_negative());
}
#[test]
@@ -1693,58 +1550,6 @@ mod tests {
}
#[test]
- #[allow(deprecated)]
- fn test_ldexp() {
- let f1 = 2.0f32.powi(-123);
- let f2 = 2.0f32.powi(-111);
- let f3 = 1.75 * 2.0f32.powi(-12);
- assert_eq!(f32::ldexp(1f32, -123), f1);
- assert_eq!(f32::ldexp(1f32, -111), f2);
- assert_eq!(f32::ldexp(1.75f32, -12), f3);
-
- assert_eq!(f32::ldexp(0f32, -123), 0f32);
- assert_eq!(f32::ldexp(-0f32, -123), -0f32);
-
- let inf: f32 = f32::INFINITY;
- let neg_inf: f32 = f32::NEG_INFINITY;
- let nan: f32 = f32::NAN;
- assert_eq!(f32::ldexp(inf, -123), inf);
- assert_eq!(f32::ldexp(neg_inf, -123), neg_inf);
- assert!(f32::ldexp(nan, -123).is_nan());
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_frexp() {
- let f1 = 2.0f32.powi(-123);
- let f2 = 2.0f32.powi(-111);
- let f3 = 1.75 * 2.0f32.powi(-123);
- let (x1, exp1) = f1.frexp();
- let (x2, exp2) = f2.frexp();
- let (x3, exp3) = f3.frexp();
- assert_eq!((x1, exp1), (0.5f32, -122));
- assert_eq!((x2, exp2), (0.5f32, -110));
- assert_eq!((x3, exp3), (0.875f32, -122));
- assert_eq!(f32::ldexp(x1, exp1), f1);
- assert_eq!(f32::ldexp(x2, exp2), f2);
- assert_eq!(f32::ldexp(x3, exp3), f3);
-
- assert_eq!(0f32.frexp(), (0f32, 0));
- assert_eq!((-0f32).frexp(), (-0f32, 0));
- }
-
- #[test] #[cfg_attr(windows, ignore)] // FIXME #8755
- #[allow(deprecated)]
- fn test_frexp_nowin() {
- let inf: f32 = f32::INFINITY;
- let neg_inf: f32 = f32::NEG_INFINITY;
- let nan: f32 = f32::NAN;
- assert_eq!(match inf.frexp() { (x, _) => x }, inf);
- assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf);
- assert!(match nan.frexp() { (x, _) => x.is_nan() })
- }
-
- #[test]
fn test_asinh() {
assert_eq!(0.0f32.asinh(), 0.0f32);
assert_eq!((-0.0f32).asinh(), -0.0f32);
@@ -1834,4 +1639,26 @@ mod tests {
assert_approx_eq!(ln_2, 2f32.ln());
assert_approx_eq!(ln_10, 10f32.ln());
}
+
+ #[test]
+ fn test_float_bits_conv() {
+ assert_eq!((1f32).to_bits(), 0x3f800000);
+ assert_eq!((12.5f32).to_bits(), 0x41480000);
+ assert_eq!((1337f32).to_bits(), 0x44a72000);
+ assert_eq!((-14.25f32).to_bits(), 0xc1640000);
+ assert_approx_eq!(f32::from_bits(0x3f800000), 1.0);
+ assert_approx_eq!(f32::from_bits(0x41480000), 12.5);
+ assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
+ assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
+
+ // Check that NaNs roundtrip their bits regardless of signalingness
+ // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+ let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA;
+ let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
+ assert!(f32::from_bits(masked_nan1).is_nan());
+ assert!(f32::from_bits(masked_nan2).is_nan());
+
+ assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1);
+ assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2);
+ }
}
diff --git a/ctr-std/src/f64.rs b/ctr-std/src/f64.rs
index 55b85cd..e4eea74 100644
--- a/ctr-std/src/f64.rs
+++ b/ctr-std/src/f64.rs
@@ -8,9 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! The 64-bit floating point type.
+//! This module provides constants which are specific to the implementation
+//! of the `f64` floating point data type.
//!
-//! *[See also the `f64` primitive type](../primitive.f64.html).*
+//! Mathematically significant numbers are provided in the `consts` sub-module.
+//!
+//! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
@@ -20,9 +23,9 @@ use core::num;
#[cfg(not(test))]
use intrinsics;
#[cfg(not(test))]
-use libc::c_int;
-#[cfg(not(test))]
use num::FpCategory;
+#[cfg(not(test))]
+use sys::cmath;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON};
@@ -35,55 +38,6 @@ pub use core::f64::{MIN, MIN_POSITIVE, MAX};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::f64::consts;
-#[allow(dead_code)]
-mod cmath {
- use libc::{c_double, c_int};
-
- #[link_name = "m"]
- extern {
- pub fn acos(n: c_double) -> c_double;
- pub fn asin(n: c_double) -> c_double;
- pub fn atan(n: c_double) -> c_double;
- pub fn atan2(a: c_double, b: c_double) -> c_double;
- pub fn cbrt(n: c_double) -> c_double;
- pub fn cosh(n: c_double) -> c_double;
- pub fn erf(n: c_double) -> c_double;
- pub fn erfc(n: c_double) -> c_double;
- pub fn expm1(n: c_double) -> c_double;
- pub fn fdim(a: c_double, b: c_double) -> c_double;
- pub fn fmax(a: c_double, b: c_double) -> c_double;
- pub fn fmin(a: c_double, b: c_double) -> c_double;
- pub fn fmod(a: c_double, b: c_double) -> c_double;
- pub fn frexp(n: c_double, value: &mut c_int) -> c_double;
- pub fn ilogb(n: c_double) -> c_int;
- pub fn ldexp(x: c_double, n: c_int) -> c_double;
- pub fn logb(n: c_double) -> c_double;
- pub fn log1p(n: c_double) -> c_double;
- pub fn nextafter(x: c_double, y: c_double) -> c_double;
- pub fn modf(n: c_double, iptr: &mut c_double) -> c_double;
- pub fn sinh(n: c_double) -> c_double;
- pub fn tan(n: c_double) -> c_double;
- pub fn tanh(n: c_double) -> c_double;
- pub fn tgamma(n: c_double) -> c_double;
-
- // These are commonly only available for doubles
-
- pub fn j0(n: c_double) -> c_double;
- pub fn j1(n: c_double) -> c_double;
- pub fn jn(i: c_int, n: c_double) -> c_double;
-
- pub fn y0(n: c_double) -> c_double;
- pub fn y1(n: c_double) -> c_double;
- pub fn yn(i: c_int, n: c_double) -> c_double;
-
- #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgamma_r")]
- pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double;
-
- #[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypot")]
- pub fn hypot(x: c_double, y: c_double) -> c_double;
- }
-}
-
#[cfg(not(test))]
#[lang = "f64"]
impl f64 {
@@ -303,21 +257,15 @@ impl f64 {
#[inline]
pub fn signum(self) -> f64 { num::Float::signum(self) }
- /// Returns `true` if `self`'s sign bit is positive, including
- /// `+0.0` and `INFINITY`.
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
///
/// ```
- /// use std::f64;
- ///
- /// let nan: f64 = f64::NAN;
- ///
/// let f = 7.0_f64;
/// let g = -7.0_f64;
///
/// assert!(f.is_sign_positive());
/// assert!(!g.is_sign_positive());
- /// // Requires both tests to determine if is `NaN`
- /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -328,21 +276,15 @@ impl f64 {
#[inline]
pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) }
- /// Returns `true` if `self`'s sign is negative, including `-0.0`
- /// and `NEG_INFINITY`.
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
///
/// ```
- /// use std::f64;
- ///
- /// let nan = f64::NAN;
- ///
/// let f = 7.0_f64;
/// let g = -7.0_f64;
///
/// assert!(!f.is_sign_negative());
/// assert!(g.is_sign_negative());
- /// // Requires both tests to determine if is `NaN`.
- /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -490,18 +432,17 @@ impl f64 {
/// Returns the logarithm of the number with respect to an arbitrary base.
///
- /// ```
- /// let ten = 10.0_f64;
- /// let two = 2.0_f64;
+ /// The result may not be correctly rounded owing to implementation details;
+ /// `self.log2()` can produce more accurate results for base 2, and
+ /// `self.log10()` can produce more accurate results for base 10.
///
- /// // log10(10) - 1 == 0
- /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs();
+ /// ```
+ /// let five = 5.0_f64;
///
- /// // log2(2) - 1 == 0
- /// let abs_difference_2 = (two.log(2.0) - 1.0).abs();
+ /// // log5(5) - 1 == 0
+ /// let abs_difference = (five.log(5.0) - 1.0).abs();
///
- /// assert!(abs_difference_10 < 1e-10);
- /// assert!(abs_difference_2 < 1e-10);
+ /// assert!(abs_difference < 1e-10);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -574,84 +515,6 @@ impl f64 {
#[inline]
pub fn to_radians(self) -> f64 { num::Float::to_radians(self) }
- /// Constructs a floating point number of `x*2^exp`.
- ///
- /// ```
- /// #![feature(float_extras)]
- ///
- /// // 3*2^2 - 12 == 0
- /// let abs_difference = (f64::ldexp(3.0, 2) - 12.0).abs();
- ///
- /// assert!(abs_difference < 1e-10);
- /// ```
- #[unstable(feature = "float_extras",
- reason = "pending integer conventions",
- issue = "27752")]
- #[rustc_deprecated(since = "1.11.0",
- reason = "never really came to fruition and easily \
- implementable outside the standard library")]
- #[inline]
- pub fn ldexp(x: f64, exp: isize) -> f64 {
- unsafe { cmath::ldexp(x, exp as c_int) }
- }
-
- /// Breaks the number into a normalized fraction and a base-2 exponent,
- /// satisfying:
- ///
- /// * `self = x * 2^exp`
- /// * `0.5 <= abs(x) < 1.0`
- ///
- /// ```
- /// #![feature(float_extras)]
- ///
- /// let x = 4.0_f64;
- ///
- /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0
- /// let f = x.frexp();
- /// let abs_difference_0 = (f.0 - 0.5).abs();
- /// let abs_difference_1 = (f.1 as f64 - 3.0).abs();
- ///
- /// assert!(abs_difference_0 < 1e-10);
- /// assert!(abs_difference_1 < 1e-10);
- /// ```
- #[unstable(feature = "float_extras",
- reason = "pending integer conventions",
- issue = "27752")]
- #[rustc_deprecated(since = "1.11.0",
- reason = "never really came to fruition and easily \
- implementable outside the standard library")]
- #[inline]
- pub fn frexp(self) -> (f64, isize) {
- unsafe {
- let mut exp = 0;
- let x = cmath::frexp(self, &mut exp);
- (x, exp as isize)
- }
- }
-
- /// Returns the next representable floating-point value in the direction of
- /// `other`.
- ///
- /// ```
- /// #![feature(float_extras)]
- ///
- /// let x = 1.0f64;
- ///
- /// let abs_diff = (x.next_after(2.0) - 1.0000000000000002220446049250313_f64).abs();
- ///
- /// assert!(abs_diff < 1e-10);
- /// ```
- #[unstable(feature = "float_extras",
- reason = "unsure about its place in the world",
- issue = "27752")]
- #[rustc_deprecated(since = "1.11.0",
- reason = "never really came to fruition and easily \
- implementable outside the standard library")]
- #[inline]
- pub fn next_after(self, other: f64) -> f64 {
- unsafe { cmath::nextafter(self, other) }
- }
-
/// Returns the maximum of the two numbers.
///
/// ```
@@ -665,7 +528,7 @@ impl f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn max(self, other: f64) -> f64 {
- unsafe { cmath::fmax(self, other) }
+ num::Float::max(self, other)
}
/// Returns the minimum of the two numbers.
@@ -681,7 +544,7 @@ impl f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn min(self, other: f64) -> f64 {
- unsafe { cmath::fmin(self, other) }
+ num::Float::min(self, other)
}
/// The positive difference of two numbers.
@@ -1086,6 +949,74 @@ impl f64 {
}
}
}
+
+ /// Raw transmutation to `u64`.
+ ///
+ /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
+ ///
+ /// See `from_bits` for some discussion of the portability of this operation
+ /// (there are almost no issues).
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting!
+ /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
+ ///
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn to_bits(self) -> u64 {
+ unsafe { ::mem::transmute(self) }
+ }
+
+ /// Raw transmutation from `u64`.
+ ///
+ /// This is currently identical to `transmute::<u64, f64>(v)` on all platforms.
+ /// It turns out this is incredibly portable, for two reasons:
+ ///
+ /// * Floats and Ints have the same endianess on all supported platforms.
+ /// * IEEE-754 very precisely specifies the bit layout of floats.
+ ///
+ /// However there is one caveat: prior to the 2008 version of IEEE-754, how
+ /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
+ /// (notably x86 and ARM) picked the interpretation that was ultimately
+ /// standardized in 2008, but some didn't (notably MIPS). As a result, all
+ /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
+ ///
+ /// Rather than trying to preserve signaling-ness cross-platform, this
+ /// implementation favours preserving the exact bits. This means that
+ /// any payloads encoded in NaNs will be preserved even if the result of
+ /// this method is sent over the network from an x86 machine to a MIPS one.
+ ///
+ /// If the results of this method are only manipulated by the same
+ /// architecture that produced them, then there is no portability concern.
+ ///
+ /// If the input isn't NaN, then there is no portability concern.
+ ///
+ /// If you don't care about signalingness (very likely), then there is no
+ /// portability concern.
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ /// let v = f64::from_bits(0x4029000000000000);
+ /// let difference = (v - 12.5).abs();
+ /// assert!(difference <= 1e-5);
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn from_bits(v: u64) -> Self {
+ // It turns out the safety issues with sNaN were overblown! Hooray!
+ unsafe { ::mem::transmute(v) }
+ }
}
#[cfg(test)]
@@ -1119,7 +1050,7 @@ mod tests {
assert!(!nan.is_infinite());
assert!(!nan.is_finite());
assert!(!nan.is_normal());
- assert!(!nan.is_sign_positive());
+ assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
}
@@ -1174,6 +1105,7 @@ mod tests {
assert_eq!(Fp::Zero, neg_zero.classify());
}
+ #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn test_one() {
let one: f64 = 1.0f64;
@@ -1226,6 +1158,7 @@ mod tests {
assert!((-109.2f64).is_finite());
}
+ #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn test_is_normal() {
let nan: f64 = NAN;
@@ -1243,6 +1176,7 @@ mod tests {
assert!(!1e-308f64.is_normal());
}
+ #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn test_classify() {
let nan: f64 = NAN;
@@ -1260,23 +1194,6 @@ mod tests {
}
#[test]
- #[allow(deprecated)]
- fn test_integer_decode() {
- assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
- assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
- assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1));
- assert_eq!(0f64.integer_decode(), (0, -1075, 1));
- assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
- assert_eq!(INFINITY.integer_decode(), (4503599627370496, 972, 1));
- assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1));
-
- // Ignore the "sign" (quiet / signalling flag) of NAN.
- // It can vary between runtime operations and LLVM folding.
- let (nan_m, nan_e, _nan_s) = NAN.integer_decode();
- assert_eq!((nan_m, nan_e), (6755399441055744, 972));
- }
-
- #[test]
fn test_floor() {
assert_approx_eq!(1.0f64.floor(), 1.0f64);
assert_approx_eq!(1.3f64.floor(), 1.0f64);
@@ -1379,7 +1296,8 @@ mod tests {
assert!(!(-1f64).is_sign_positive());
assert!(!NEG_INFINITY.is_sign_positive());
assert!(!(1f64/NEG_INFINITY).is_sign_positive());
- assert!(!NAN.is_sign_positive());
+ assert!(NAN.is_sign_positive());
+ assert!(!(-NAN).is_sign_positive());
}
#[test]
@@ -1392,6 +1310,7 @@ mod tests {
assert!(NEG_INFINITY.is_sign_negative());
assert!((1f64/NEG_INFINITY).is_sign_negative());
assert!(!NAN.is_sign_negative());
+ assert!((-NAN).is_sign_negative());
}
#[test]
@@ -1588,58 +1507,6 @@ mod tests {
}
#[test]
- #[allow(deprecated)]
- fn test_ldexp() {
- let f1 = 2.0f64.powi(-123);
- let f2 = 2.0f64.powi(-111);
- let f3 = 1.75 * 2.0f64.powi(-12);
- assert_eq!(f64::ldexp(1f64, -123), f1);
- assert_eq!(f64::ldexp(1f64, -111), f2);
- assert_eq!(f64::ldexp(1.75f64, -12), f3);
-
- assert_eq!(f64::ldexp(0f64, -123), 0f64);
- assert_eq!(f64::ldexp(-0f64, -123), -0f64);
-
- let inf: f64 = INFINITY;
- let neg_inf: f64 = NEG_INFINITY;
- let nan: f64 = NAN;
- assert_eq!(f64::ldexp(inf, -123), inf);
- assert_eq!(f64::ldexp(neg_inf, -123), neg_inf);
- assert!(f64::ldexp(nan, -123).is_nan());
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_frexp() {
- let f1 = 2.0f64.powi(-123);
- let f2 = 2.0f64.powi(-111);
- let f3 = 1.75 * 2.0f64.powi(-123);
- let (x1, exp1) = f1.frexp();
- let (x2, exp2) = f2.frexp();
- let (x3, exp3) = f3.frexp();
- assert_eq!((x1, exp1), (0.5f64, -122));
- assert_eq!((x2, exp2), (0.5f64, -110));
- assert_eq!((x3, exp3), (0.875f64, -122));
- assert_eq!(f64::ldexp(x1, exp1), f1);
- assert_eq!(f64::ldexp(x2, exp2), f2);
- assert_eq!(f64::ldexp(x3, exp3), f3);
-
- assert_eq!(0f64.frexp(), (0f64, 0));
- assert_eq!((-0f64).frexp(), (-0f64, 0));
- }
-
- #[test] #[cfg_attr(windows, ignore)] // FIXME #8755
- #[allow(deprecated)]
- fn test_frexp_nowin() {
- let inf: f64 = INFINITY;
- let neg_inf: f64 = NEG_INFINITY;
- let nan: f64 = NAN;
- assert_eq!(match inf.frexp() { (x, _) => x }, inf);
- assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf);
- assert!(match nan.frexp() { (x, _) => x.is_nan() })
- }
-
- #[test]
fn test_asinh() {
assert_eq!(0.0f64.asinh(), 0.0f64);
assert_eq!((-0.0f64).asinh(), -0.0f64);
@@ -1723,4 +1590,26 @@ mod tests {
assert_approx_eq!(ln_2, 2f64.ln());
assert_approx_eq!(ln_10, 10f64.ln());
}
+
+ #[test]
+ fn test_float_bits_conv() {
+ assert_eq!((1f64).to_bits(), 0x3ff0000000000000);
+ assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
+ assert_eq!((1337f64).to_bits(), 0x4094e40000000000);
+ assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000);
+ assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0);
+ assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5);
+ assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
+ assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
+
+ // Check that NaNs roundtrip their bits regardless of signalingness
+ // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+ let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
+ let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
+ assert!(f64::from_bits(masked_nan1).is_nan());
+ assert!(f64::from_bits(masked_nan2).is_nan());
+
+ assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1);
+ assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2);
+ }
}
diff --git a/ctr-std/src/ffi/c_str.rs b/ctr-std/src/ffi/c_str.rs
index ad40660..a19fe82 100644
--- a/ctr-std/src/ffi/c_str.rs
+++ b/ctr-std/src/ffi/c_str.rs
@@ -14,27 +14,80 @@ use cmp::Ordering;
use error::Error;
use fmt::{self, Write};
use io;
-use libc::{self, c_char};
use mem;
use memchr;
use ops;
+use os::raw::c_char;
use ptr;
+use rc::Rc;
use slice;
use str::{self, Utf8Error};
+use sync::Arc;
+use sys;
-/// A type representing an owned C-compatible string
+/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
+/// middle.
///
-/// This type serves the primary purpose of being able to safely generate a
+/// This type serves the purpose of being able to safely generate a
/// C-compatible string from a Rust byte slice or vector. An instance of this
/// type is a static guarantee that the underlying bytes contain no interior 0
-/// bytes and the final byte is 0.
+/// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
///
-/// A `CString` is created from either a byte slice or a byte vector. After
-/// being created, a `CString` predominately inherits all of its methods from
-/// the `Deref` implementation to `[c_char]`. Note that the underlying array
-/// is represented as an array of `c_char` as opposed to `u8`. A `u8` slice
-/// can be obtained with the `as_bytes` method. Slices produced from a `CString`
-/// do *not* contain the trailing nul terminator unless otherwise specified.
+/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
+///
+/// # Creating a `CString`
+///
+/// A `CString` is created from either a byte slice or a byte vector,
+/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for
+/// example, you can build a `CString` straight out of a [`String`] or
+/// a [`&str`], since both implement that trait).
+///
+/// The [`new`] method will actually check that the provided `&[u8]`
+/// does not have 0 bytes in the middle, and return an error if it
+/// finds one.
+///
+/// # Extracting a raw pointer to the whole C string
+///
+/// `CString` implements a [`as_ptr`] method through the [`Deref`]
+/// trait. This method will give you a `*const c_char` which you can
+/// feed directly to extern functions that expect a nul-terminated
+/// string, like C's `strdup()`.
+///
+/// # Extracting a slice of the whole C string
+///
+/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a
+/// `CString` with the [`as_bytes`] method. Slices produced in this
+/// way do *not* contain the trailing nul terminator. This is useful
+/// when you will be calling an extern function that takes a `*const
+/// u8` argument which is not necessarily nul-terminated, plus another
+/// argument with the length of the string — like C's `strndup()`.
+/// You can of course get the slice's length with its
+/// [`len`][slice.len] method.
+///
+/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you
+/// can use [`as_bytes_with_nul`] instead.
+///
+/// Once you have the kind of slice you need (with or without a nul
+/// terminator), you can call the slice's own
+/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to
+/// extern functions. See the documentation for that function for a
+/// discussion on ensuring the lifetime of the raw pointer.
+///
+/// [`Into`]: ../convert/trait.Into.html
+/// [`Vec`]: ../vec/struct.Vec.html
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
+/// [`u8`]: ../primitive.u8.html
+/// [`new`]: #method.new
+/// [`as_bytes`]: #method.as_bytes
+/// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
+/// [`as_ptr`]: #method.as_ptr
+/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr
+/// [slice.len]: ../primitive.slice.html#method.len
+/// [`Deref`]: ../ops/trait.Deref.html
+/// [`CStr`]: struct.CStr.html
///
/// # Examples
///
@@ -47,6 +100,8 @@ use str::{self, Utf8Error};
/// fn my_printer(s: *const c_char);
/// }
///
+/// // We are certain that our string doesn't have 0 bytes in the middle,
+/// // so we can .unwrap()
/// let c_to_print = CString::new("Hello, world!").unwrap();
/// unsafe {
/// my_printer(c_to_print.as_ptr());
@@ -57,7 +112,7 @@ use str::{self, Utf8Error};
/// # Safety
///
/// `CString` is intended for working with traditional C-style strings
-/// (a sequence of non-null bytes terminated by a single null byte); the
+/// (a sequence of non-nul bytes terminated by a single nul byte); the
/// primary use case for these kinds of strings is interoperating with C-like
/// code. Often you will need to transfer ownership to/from that external
/// code. It is strongly recommended that you thoroughly read through the
@@ -76,18 +131,24 @@ pub struct CString {
/// Representation of a borrowed C string.
///
-/// This dynamically sized type is only safely constructed via a borrowed
-/// version of an instance of `CString`. This type can be constructed from a raw
-/// C string as well and represents a C string borrowed from another location.
+/// This type represents a borrowed reference to a nul-terminated
+/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]`
+/// slice, or unsafely from a raw `*const c_char`. It can then be
+/// converted to a Rust [`&str`] by performing UTF-8 validation, or
+/// into an owned [`CString`].
+///
+/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
+/// in each pair are borrowed references; the latter are owned
+/// strings.
///
/// Note that this structure is **not** `repr(C)` and is not recommended to be
-/// placed in the signatures of FFI functions. Instead safe wrappers of FFI
-/// functions may leverage the unsafe `from_ptr` constructor to provide a safe
+/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
+/// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe
/// interface to other consumers.
///
/// # Examples
///
-/// Inspecting a foreign C string
+/// Inspecting a foreign C string:
///
/// ```no_run
/// use std::ffi::CStr;
@@ -97,11 +158,11 @@ pub struct CString {
///
/// unsafe {
/// let slice = CStr::from_ptr(my_string());
-/// println!("string length: {}", slice.to_bytes().len());
+/// println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
/// }
/// ```
///
-/// Passing a Rust-originating C string
+/// Passing a Rust-originating C string:
///
/// ```no_run
/// use std::ffi::{CString, CStr};
@@ -117,7 +178,7 @@ pub struct CString {
/// work(&s);
/// ```
///
-/// Converting a foreign C string into a Rust `String`
+/// Converting a foreign C string into a Rust [`String`]:
///
/// ```no_run
/// use std::ffi::CStr;
@@ -133,6 +194,12 @@ pub struct CString {
///
/// println!("string: {}", my_string_safe());
/// ```
+///
+/// [`u8`]: ../primitive.u8.html
+/// [`&str`]: ../primitive.str.html
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
+/// [`from_ptr`]: #method.from_ptr
#[derive(Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct CStr {
@@ -143,20 +210,85 @@ pub struct CStr {
inner: [c_char]
}
-/// An error returned from `CString::new` to indicate that a nul byte was found
-/// in the vector provided.
+/// An error indicating that an interior nul byte was found.
+///
+/// While Rust strings may contain nul bytes in the middle, C strings
+/// can't, as that byte would effectively truncate the string.
+///
+/// This error is created by the [`new`][`CString::new`] method on
+/// [`CString`]. See its documentation for more.
+///
+/// [`CString`]: struct.CString.html
+/// [`CString::new`]: struct.CString.html#method.new
+///
+/// # Examples
+///
+/// ```
+/// use std::ffi::{CString, NulError};
+///
+/// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err();
+/// ```
#[derive(Clone, PartialEq, Eq, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct NulError(usize, Vec<u8>);
-/// An error returned from `CStr::from_bytes_with_nul` to indicate that a nul
-/// byte was found too early in the slice provided or one wasn't found at all.
+/// An error indicating that a nul byte was not in the expected position.
+///
+/// The slice used to create a [`CStr`] must have one and only one nul
+/// byte at the end of the slice.
+///
+/// This error is created by the
+/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on
+/// [`CStr`]. See its documentation for more.
+///
+/// [`CStr`]: struct.CStr.html
+/// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
+///
+/// # Examples
+///
+/// ```
+/// use std::ffi::{CStr, FromBytesWithNulError};
+///
+/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
+/// ```
#[derive(Clone, PartialEq, Eq, Debug)]
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-pub struct FromBytesWithNulError { _a: () }
+pub struct FromBytesWithNulError {
+ kind: FromBytesWithNulErrorKind,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum FromBytesWithNulErrorKind {
+ InteriorNul(usize),
+ NotNulTerminated,
+}
-/// An error returned from `CString::into_string` to indicate that a UTF-8 error
-/// was encountered during the conversion.
+impl FromBytesWithNulError {
+ fn interior_nul(pos: usize) -> FromBytesWithNulError {
+ FromBytesWithNulError {
+ kind: FromBytesWithNulErrorKind::InteriorNul(pos),
+ }
+ }
+ fn not_nul_terminated() -> FromBytesWithNulError {
+ FromBytesWithNulError {
+ kind: FromBytesWithNulErrorKind::NotNulTerminated,
+ }
+ }
+}
+
+/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
+///
+/// `CString` is just a wrapper over a buffer of bytes with a nul
+/// terminator; [`into_string`][`CString::into_string`] performs UTF-8
+/// validation on those bytes and may return this error.
+///
+/// This `struct` is created by the
+/// [`into_string`][`CString::into_string`] method on [`CString`]. See
+/// its documentation for more.
+///
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
+/// [`CString::into_string`]: struct.CString.html#method.into_string
#[derive(Clone, PartialEq, Eq, Debug)]
#[stable(feature = "cstring_into", since = "1.7.0")]
pub struct IntoStringError {
@@ -167,8 +299,11 @@ pub struct IntoStringError {
impl CString {
/// Creates a new C-compatible string from a container of bytes.
///
- /// This method will consume the provided data and use the underlying bytes
- /// to construct a new string, ensuring that there is a trailing 0 byte.
+ /// This function will consume the provided data and use the
+ /// underlying bytes to construct a new string, ensuring that
+ /// there is a trailing 0 byte. This trailing 0 byte will be
+ /// appended by this function; the provided data should *not*
+ /// contain any 0 bytes in it.
///
/// # Examples
///
@@ -186,9 +321,11 @@ impl CString {
///
/// # Errors
///
- /// This function will return an error if the bytes yielded contain an
- /// internal 0 byte. The error returned will contain the bytes as well as
+ /// This function will return an error if the supplied bytes contain an
+ /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as
/// the position of the nul byte.
+ ///
+ /// [`NulError`]: struct.NulError.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
Self::_new(t.into())
@@ -201,13 +338,15 @@ impl CString {
}
}
- /// Creates a C-compatible string from a byte vector without checking for
- /// interior 0 bytes.
+ /// Creates a C-compatible string by consuming a byte vector,
+ /// without checking for interior 0 bytes.
///
- /// This method is equivalent to `new` except that no runtime assertion
+ /// This method is equivalent to [`new`] except that no runtime assertion
/// is made that `v` contains no 0 bytes, and it requires an actual
/// byte vector, not anything that can be converted to one with Into.
///
+ /// [`new`]: #method.new
+ ///
/// # Examples
///
/// ```
@@ -225,39 +364,110 @@ impl CString {
CString { inner: v.into_boxed_slice() }
}
- /// Retakes ownership of a `CString` that was transferred to C.
+ /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`].
///
/// Additionally, the length of the string will be recalculated from the pointer.
///
/// # Safety
///
/// This should only ever be called with a pointer that was earlier
- /// obtained by calling `into_raw` on a `CString`. Other usage (e.g. trying to take
+ /// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g. trying to take
/// ownership of a string that was allocated by foreign code) is likely to lead
/// to undefined behavior or allocator corruption.
+ ///
+ /// > **Note:** If you need to borrow a string that was allocated by
+ /// > foreign code, use [`CStr`]. If you need to take ownership of
+ /// > a string that was allocated by foreign code, you will need to
+ /// > make your own provisions for freeing it appropriately, likely
+ /// > with the foreign code's API to do that.
+ ///
+ /// [`into_raw`]: #method.into_raw
+ /// [`CStr`]: struct.CStr.html
+ ///
+ /// # Examples
+ ///
+ /// Create a `CString`, pass ownership to an `extern` function (via raw pointer), then retake
+ /// ownership with `from_raw`:
+ ///
+ /// ```no_run
+ /// use std::ffi::CString;
+ /// use std::os::raw::c_char;
+ ///
+ /// extern {
+ /// fn some_extern_function(s: *mut c_char);
+ /// }
+ ///
+ /// let c_string = CString::new("Hello!").unwrap();
+ /// let raw = c_string.into_raw();
+ /// unsafe {
+ /// some_extern_function(raw);
+ /// let c_string = CString::from_raw(raw);
+ /// }
+ /// ```
#[stable(feature = "cstr_memory", since = "1.4.0")]
pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
- let len = libc::strlen(ptr) + 1; // Including the NUL byte
- let slice = slice::from_raw_parts(ptr, len as usize);
- CString { inner: mem::transmute(slice) }
+ let len = sys::strlen(ptr) + 1; // Including the NUL byte
+ let slice = slice::from_raw_parts_mut(ptr, len as usize);
+ CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
}
- /// Transfers ownership of the string to a C caller.
+ /// Consumes the `CString` and transfers ownership of the string to a C caller.
///
- /// The pointer must be returned to Rust and reconstituted using
- /// `from_raw` to be properly deallocated. Specifically, one
- /// should *not* use the standard C `free` function to deallocate
+ /// The pointer which this function returns must be returned to Rust and reconstituted using
+ /// [`from_raw`] to be properly deallocated. Specifically, one
+ /// should *not* use the standard C `free()` function to deallocate
/// this string.
///
- /// Failure to call `from_raw` will lead to a memory leak.
+ /// Failure to call [`from_raw`] will lead to a memory leak.
+ ///
+ /// [`from_raw`]: #method.from_raw
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new("foo").unwrap();
+ ///
+ /// let ptr = c_string.into_raw();
+ ///
+ /// unsafe {
+ /// assert_eq!(b'f', *ptr as u8);
+ /// assert_eq!(b'o', *ptr.offset(1) as u8);
+ /// assert_eq!(b'o', *ptr.offset(2) as u8);
+ /// assert_eq!(b'\0', *ptr.offset(3) as u8);
+ ///
+ /// // retake pointer to free memory
+ /// let _ = CString::from_raw(ptr);
+ /// }
+ /// ```
+ #[inline]
#[stable(feature = "cstr_memory", since = "1.4.0")]
pub fn into_raw(self) -> *mut c_char {
Box::into_raw(self.into_inner()) as *mut c_char
}
- /// Converts the `CString` into a `String` if it contains valid Unicode data.
+ /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data.
///
/// On failure, ownership of the original `CString` is returned.
+ ///
+ /// [`String`]: ../string/struct.String.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let valid_utf8 = vec![b'f', b'o', b'o'];
+ /// let cstring = CString::new(valid_utf8).unwrap();
+ /// assert_eq!(cstring.into_string().unwrap(), "foo");
+ ///
+ /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o'];
+ /// let cstring = CString::new(invalid_utf8).unwrap();
+ /// let err = cstring.into_string().err().unwrap();
+ /// assert_eq!(err.utf8_error().valid_up_to(), 1);
+ /// ```
+
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn into_string(self) -> Result<String, IntoStringError> {
String::from_utf8(self.into_bytes())
@@ -267,10 +477,21 @@ impl CString {
})
}
- /// Returns the underlying byte buffer.
+ /// Consumes the `CString` and returns the underlying byte buffer.
+ ///
+ /// The returned buffer does **not** contain the trailing nul
+ /// terminator, and it is guaranteed to not have any interior nul
+ /// bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
///
- /// The returned buffer does **not** contain the trailing nul separator and
- /// it is guaranteed to not have any interior nul bytes.
+ /// let c_string = CString::new("foo").unwrap();
+ /// let bytes = c_string.into_bytes();
+ /// assert_eq!(bytes, vec![b'f', b'o', b'o']);
+ /// ```
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn into_bytes(self) -> Vec<u8> {
let mut vec = self.into_inner().into_vec();
@@ -279,8 +500,20 @@ impl CString {
vec
}
- /// Equivalent to the `into_bytes` function except that the returned vector
- /// includes the trailing nul byte.
+ /// Equivalent to the [`into_bytes`] function except that the returned vector
+ /// includes the trailing nul terminator.
+ ///
+ /// [`into_bytes`]: #method.into_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new("foo").unwrap();
+ /// let bytes = c_string.into_bytes_with_nul();
+ /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']);
+ /// ```
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn into_bytes_with_nul(self) -> Vec<u8> {
self.into_inner().into_vec()
@@ -288,21 +521,88 @@ impl CString {
/// Returns the contents of this `CString` as a slice of bytes.
///
- /// The returned slice does **not** contain the trailing nul separator and
- /// it is guaranteed to not have any interior nul bytes.
+ /// The returned slice does **not** contain the trailing nul
+ /// terminator, and it is guaranteed to not have any interior nul
+ /// bytes. If you need the nul terminator, use
+ /// [`as_bytes_with_nul`] instead.
+ ///
+ /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new("foo").unwrap();
+ /// let bytes = c_string.as_bytes();
+ /// assert_eq!(bytes, &[b'f', b'o', b'o']);
+ /// ```
+ #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_bytes(&self) -> &[u8] {
&self.inner[..self.inner.len() - 1]
}
- /// Equivalent to the `as_bytes` function except that the returned slice
- /// includes the trailing nul byte.
+ /// Equivalent to the [`as_bytes`] function except that the returned slice
+ /// includes the trailing nul terminator.
+ ///
+ /// [`as_bytes`]: #method.as_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new("foo").unwrap();
+ /// let bytes = c_string.as_bytes_with_nul();
+ /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']);
+ /// ```
+ #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_bytes_with_nul(&self) -> &[u8] {
&self.inner
}
- // Bypass "move out of struct which implements `Drop` trait" restriction.
+ /// Extracts a [`CStr`] slice containing the entire string.
+ ///
+ /// [`CStr`]: struct.CStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{CString, CStr};
+ ///
+ /// let c_string = CString::new(b"foo".to_vec()).unwrap();
+ /// let c_str = c_string.as_c_str();
+ /// assert_eq!(c_str, CStr::from_bytes_with_nul(b"foo\0").unwrap());
+ /// ```
+ #[inline]
+ #[stable(feature = "as_c_str", since = "1.20.0")]
+ pub fn as_c_str(&self) -> &CStr {
+ &*self
+ }
+
+ /// Converts this `CString` into a boxed [`CStr`].
+ ///
+ /// [`CStr`]: struct.CStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{CString, CStr};
+ ///
+ /// let c_string = CString::new(b"foo".to_vec()).unwrap();
+ /// let boxed = c_string.into_boxed_c_str();
+ /// assert_eq!(&*boxed, CStr::from_bytes_with_nul(b"foo\0").unwrap());
+ /// ```
+ #[stable(feature = "into_boxed_c_str", since = "1.20.0")]
+ pub fn into_boxed_c_str(self) -> Box<CStr> {
+ unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) }
+ }
+
+ // Bypass "move out of struct which implements [`Drop`] trait" restriction.
+ ///
+ /// [`Drop`]: ../ops/trait.Drop.html
fn into_inner(self) -> Box<[u8]> {
unsafe {
let result = ptr::read(&self.inner);
@@ -327,8 +627,9 @@ impl Drop for CString {
impl ops::Deref for CString {
type Target = CStr;
+ #[inline]
fn deref(&self) -> &CStr {
- unsafe { mem::transmute(self.as_bytes_with_nul()) }
+ unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
}
}
@@ -341,6 +642,7 @@ impl fmt::Debug for CString {
#[stable(feature = "cstring_into", since = "1.7.0")]
impl From<CString> for Vec<u8> {
+ #[inline]
fn from(s: CString) -> Vec<u8> {
s.into_bytes()
}
@@ -360,7 +662,7 @@ impl fmt::Debug for CStr {
#[stable(feature = "cstr_default", since = "1.10.0")]
impl<'a> Default for &'a CStr {
fn default() -> &'a CStr {
- static SLICE: &'static [c_char] = &[0];
+ const SLICE: &'static [c_char] = &[0];
unsafe { CStr::from_ptr(SLICE.as_ptr()) }
}
}
@@ -376,12 +678,83 @@ impl Default for CString {
#[stable(feature = "cstr_borrow", since = "1.3.0")]
impl Borrow<CStr> for CString {
+ #[inline]
fn borrow(&self) -> &CStr { self }
}
+#[stable(feature = "box_from_c_str", since = "1.17.0")]
+impl<'a> From<&'a CStr> for Box<CStr> {
+ fn from(s: &'a CStr) -> Box<CStr> {
+ let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
+ unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
+ }
+}
+
+#[stable(feature = "c_string_from_box", since = "1.18.0")]
+impl From<Box<CStr>> for CString {
+ #[inline]
+ fn from(s: Box<CStr>) -> CString {
+ s.into_c_string()
+ }
+}
+
+#[stable(feature = "box_from_c_string", since = "1.20.0")]
+impl From<CString> for Box<CStr> {
+ #[inline]
+ fn from(s: CString) -> Box<CStr> {
+ s.into_boxed_c_str()
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<CString> for Arc<CStr> {
+ #[inline]
+ fn from(s: CString) -> Arc<CStr> {
+ let arc: Arc<[u8]> = Arc::from(s.into_inner());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl<'a> From<&'a CStr> for Arc<CStr> {
+ #[inline]
+ fn from(s: &CStr) -> Arc<CStr> {
+ let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<CString> for Rc<CStr> {
+ #[inline]
+ fn from(s: CString) -> Rc<CStr> {
+ let rc: Rc<[u8]> = Rc::from(s.into_inner());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl<'a> From<&'a CStr> for Rc<CStr> {
+ #[inline]
+ fn from(s: &CStr) -> Rc<CStr> {
+ let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
+ }
+}
+
+#[stable(feature = "default_box_extra", since = "1.17.0")]
+impl Default for Box<CStr> {
+ fn default() -> Box<CStr> {
+ let boxed: Box<[u8]> = Box::from([0]);
+ unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
+ }
+}
+
impl NulError {
- /// Returns the position of the nul byte in the slice that was provided to
- /// `CString::new`.
+ /// Returns the position of the nul byte in the slice that caused
+ /// [`CString::new`] to fail.
+ ///
+ /// [`CString::new`]: struct.CString.html#method.new
///
/// # Examples
///
@@ -432,9 +805,34 @@ impl From<NulError> for io::Error {
}
}
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl Error for FromBytesWithNulError {
+ fn description(&self) -> &str {
+ match self.kind {
+ FromBytesWithNulErrorKind::InteriorNul(..) =>
+ "data provided contains an interior nul byte",
+ FromBytesWithNulErrorKind::NotNulTerminated =>
+ "data provided is not nul terminated",
+ }
+ }
+}
+
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl fmt::Display for FromBytesWithNulError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(self.description())?;
+ if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
+ write!(f, " at byte pos {}", pos)?;
+ }
+ Ok(())
+ }
+}
+
impl IntoStringError {
- /// Consumes this error, returning original `CString` which generated the
+ /// Consumes this error, returning original [`CString`] which generated the
/// error.
+ ///
+ /// [`CString`]: struct.CString.html
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn into_cstring(self) -> CString {
self.inner
@@ -466,15 +864,15 @@ impl fmt::Display for IntoStringError {
}
impl CStr {
- /// Casts a raw C string to a safe C string wrapper.
+ /// Wraps a raw C string with a safe C string wrapper.
///
- /// This function will cast the provided `ptr` to the `CStr` wrapper which
+ /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
/// allows inspection and interoperation of non-owned C strings. This method
/// is unsafe for a number of reasons:
///
- /// * There is no guarantee to the validity of `ptr`
+ /// * There is no guarantee to the validity of `ptr`.
/// * The returned lifetime is not guaranteed to be the actual lifetime of
- /// `ptr`
+ /// `ptr`.
/// * There is no guarantee that the memory pointed to by `ptr` contains a
/// valid nul terminator byte at the end of the string.
///
@@ -501,15 +899,16 @@ impl CStr {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
- let len = libc::strlen(ptr);
- mem::transmute(slice::from_raw_parts(ptr, len as usize + 1))
+ let len = sys::strlen(ptr);
+ let ptr = ptr as *const u8;
+ CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
}
/// Creates a C string wrapper from a byte slice.
///
- /// This function will cast the provided `bytes` to a `CStr` wrapper after
- /// ensuring that it is null terminated and does not contain any interior
- /// nul bytes.
+ /// This function will cast the provided `bytes` to a `CStr`
+ /// wrapper after ensuring that the byte slice is nul-terminated
+ /// and does not contain any interior nul bytes.
///
/// # Examples
///
@@ -519,20 +918,42 @@ impl CStr {
/// let cstr = CStr::from_bytes_with_nul(b"hello\0");
/// assert!(cstr.is_ok());
/// ```
+ ///
+ /// Creating a `CStr` without a trailing nul terminator is an error:
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"hello");
+ /// assert!(c_str.is_err());
+ /// ```
+ ///
+ /// Creating a `CStr` with an interior nul byte is an error:
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"he\0llo\0");
+ /// assert!(c_str.is_err());
+ /// ```
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
pub fn from_bytes_with_nul(bytes: &[u8])
-> Result<&CStr, FromBytesWithNulError> {
- if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) {
- Err(FromBytesWithNulError { _a: () })
+ let nul_pos = memchr::memchr(0, bytes);
+ if let Some(nul_pos) = nul_pos {
+ if nul_pos + 1 != bytes.len() {
+ return Err(FromBytesWithNulError::interior_nul(nul_pos));
+ }
+ Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) })
} else {
- Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+ Err(FromBytesWithNulError::not_nul_terminated())
}
}
/// Unsafely creates a C string wrapper from a byte slice.
///
/// This function will cast the provided `bytes` to a `CStr` wrapper without
- /// performing any sanity checks. The provided slice must be null terminated
+ /// performing any sanity checks. The provided slice **must** be nul-terminated
/// and not contain any interior nul bytes.
///
/// # Examples
@@ -546,14 +967,15 @@ impl CStr {
/// assert_eq!(cstr, &*cstring);
/// }
/// ```
+ #[inline]
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
- mem::transmute(bytes)
+ &*(bytes as *const [u8] as *const CStr)
}
/// Returns the inner pointer to this C string.
///
- /// The returned pointer will be valid for as long as `self` is and points
+ /// The returned pointer will be valid for as long as `self` is, and points
/// to a contiguous region of memory terminated with a 0 byte to represent
/// the end of the string.
///
@@ -561,7 +983,7 @@ impl CStr {
///
/// It is your responsibility to make sure that the underlying memory is not
/// freed too early. For example, the following code will cause undefined
- /// behaviour when `ptr` is used inside the `unsafe` block:
+ /// behavior when `ptr` is used inside the `unsafe` block:
///
/// ```no_run
/// use std::ffi::{CString};
@@ -574,9 +996,9 @@ impl CStr {
/// ```
///
/// This happens because the pointer returned by `as_ptr` does not carry any
- /// lifetime information and the string is deallocated immediately after
+ /// lifetime information and the [`CString`] is deallocated immediately after
/// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated.
- /// To fix the problem, bind the string to a local variable:
+ /// To fix the problem, bind the `CString` to a local variable:
///
/// ```no_run
/// use std::ffi::{CString};
@@ -588,6 +1010,12 @@ impl CStr {
/// *ptr;
/// }
/// ```
+ ///
+ /// This way, the lifetime of the `CString` in `hello` encompasses
+ /// the lifetime of `ptr` and the `unsafe` block.
+ ///
+ /// [`CString`]: struct.CString.html
+ #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_ptr(&self) -> *const c_char {
self.inner.as_ptr()
@@ -595,16 +1023,22 @@ impl CStr {
/// Converts this C string to a byte slice.
///
- /// This function will calculate the length of this string (which normally
- /// requires a linear amount of work to be done) and then return the
- /// resulting slice of `u8` elements.
- ///
- /// The returned slice will **not** contain the trailing nul that this C
+ /// The returned slice will **not** contain the trailing nul terminator that this C
/// string has.
///
/// > **Note**: This method is currently implemented as a 0-cost cast, but
/// > it is planned to alter its definition in the future to perform the
/// > length calculation whenever this method is called.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+ /// assert_eq!(c_str.to_bytes(), b"foo");
+ /// ```
+ #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
@@ -613,26 +1047,50 @@ impl CStr {
/// Converts this C string to a byte slice containing the trailing 0 byte.
///
- /// This function is the equivalent of `to_bytes` except that it will retain
- /// the trailing nul instead of chopping it off.
+ /// This function is the equivalent of [`to_bytes`] except that it will retain
+ /// the trailing nul terminator instead of chopping it off.
///
/// > **Note**: This method is currently implemented as a 0-cost cast, but
/// > it is planned to alter its definition in the future to perform the
/// > length calculation whenever this method is called.
+ ///
+ /// [`to_bytes`]: #method.to_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+ /// assert_eq!(c_str.to_bytes_with_nul(), b"foo\0");
+ /// ```
+ #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_bytes_with_nul(&self) -> &[u8] {
- unsafe { mem::transmute(&self.inner) }
+ unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
}
- /// Yields a `&str` slice if the `CStr` contains valid UTF-8.
+ /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8.
///
- /// This function will calculate the length of this string and check for
- /// UTF-8 validity, and then return the `&str` if it's valid.
+ /// If the contents of the `CStr` are valid UTF-8 data, this
+ /// function will return the corresponding [`&str`] slice. Otherwise,
+ /// it will return an error with details of where UTF-8 validation failed.
///
/// > **Note**: This method is currently implemented to check for validity
/// > after a 0-cost cast, but it is planned to alter its definition in the
/// > future to perform the length calculation in addition to the UTF-8
/// > check whenever this method is called.
+ ///
+ /// [`&str`]: ../primitive.str.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+ /// assert_eq!(c_str.to_str(), Ok("foo"));
+ /// ```
#[stable(feature = "cstr_to_str", since = "1.4.0")]
pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
// NB: When CStr is changed to perform the length check in .to_bytes()
@@ -642,21 +1100,73 @@ impl CStr {
str::from_utf8(self.to_bytes())
}
- /// Converts a `CStr` into a `Cow<str>`.
+ /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`.
///
- /// This function will calculate the length of this string (which normally
- /// requires a linear amount of work to be done) and then return the
- /// resulting slice as a `Cow<str>`, replacing any invalid UTF-8 sequences
- /// with `U+FFFD REPLACEMENT CHARACTER`.
+ /// If the contents of the `CStr` are valid UTF-8 data, this
+ /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)`
+ /// with the the corresponding [`&str`] slice. Otherwise, it will
+ /// replace any invalid UTF-8 sequences with `U+FFFD REPLACEMENT
+ /// CHARACTER` and return a [`Cow`]`::`[`Owned`]`(`[`String`]`)`
+ /// with the result.
///
/// > **Note**: This method is currently implemented to check for validity
/// > after a 0-cost cast, but it is planned to alter its definition in the
/// > future to perform the length calculation in addition to the UTF-8
/// > check whenever this method is called.
+ ///
+ /// [`Cow`]: ../borrow/enum.Cow.html
+ /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
+ /// [`str`]: ../primitive.str.html
+ /// [`String`]: ../string/struct.String.html
+ ///
+ /// # Examples
+ ///
+ /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8:
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"Hello World\0").unwrap();
+ /// assert_eq!(c_str.to_string_lossy(), Cow::Borrowed("Hello World"));
+ /// ```
+ ///
+ /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8:
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0").unwrap();
+ /// assert_eq!(
+ /// c_str.to_string_lossy(),
+ /// Cow::Owned(String::from("Hello �World")) as Cow<str>
+ /// );
+ /// ```
#[stable(feature = "cstr_to_str", since = "1.4.0")]
pub fn to_string_lossy(&self) -> Cow<str> {
String::from_utf8_lossy(self.to_bytes())
}
+
+ /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`CString`]: struct.CString.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new(b"foo".to_vec()).unwrap();
+ /// let boxed = c_string.into_boxed_c_str();
+ /// assert_eq!(boxed.into_c_string(), CString::new("foo").unwrap());
+ /// ```
+ #[stable(feature = "into_boxed_c_str", since = "1.20.0")]
+ pub fn into_c_string(self: Box<CStr>) -> CString {
+ let raw = Box::into_raw(self) as *mut [u8];
+ CString { inner: unsafe { Box::from_raw(raw) } }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -685,7 +1195,7 @@ impl ToOwned for CStr {
type Owned = CString;
fn to_owned(&self) -> CString {
- unsafe { CString::from_vec_unchecked(self.to_bytes().to_vec()) }
+ CString { inner: self.to_bytes_with_nul().into() }
}
}
@@ -708,6 +1218,7 @@ impl ops::Index<ops::RangeFull> for CString {
#[stable(feature = "cstring_asref", since = "1.7.0")]
impl AsRef<CStr> for CStr {
+ #[inline]
fn as_ref(&self) -> &CStr {
self
}
@@ -715,6 +1226,7 @@ impl AsRef<CStr> for CStr {
#[stable(feature = "cstring_asref", since = "1.7.0")]
impl AsRef<CStr> for CString {
+ #[inline]
fn as_ref(&self) -> &CStr {
self
}
@@ -727,6 +1239,8 @@ mod tests {
use borrow::Cow::{Borrowed, Owned};
use hash::{Hash, Hasher};
use collections::hash_map::DefaultHasher;
+ use rc::Rc;
+ use sync::Arc;
#[test]
fn c_to_rust() {
@@ -846,4 +1360,38 @@ mod tests {
let cstr = CStr::from_bytes_with_nul(data);
assert!(cstr.is_err());
}
+
+ #[test]
+ fn into_boxed() {
+ let orig: &[u8] = b"Hello, world!\0";
+ let cstr = CStr::from_bytes_with_nul(orig).unwrap();
+ let boxed: Box<CStr> = Box::from(cstr);
+ let cstring = cstr.to_owned().into_boxed_c_str().into_c_string();
+ assert_eq!(cstr, &*boxed);
+ assert_eq!(&*boxed, &*cstring);
+ assert_eq!(&*cstring, cstr);
+ }
+
+ #[test]
+ fn boxed_default() {
+ let boxed = <Box<CStr>>::default();
+ assert_eq!(boxed.to_bytes_with_nul(), &[0]);
+ }
+
+ #[test]
+ fn into_rc() {
+ let orig: &[u8] = b"Hello, world!\0";
+ let cstr = CStr::from_bytes_with_nul(orig).unwrap();
+ let rc: Rc<CStr> = Rc::from(cstr);
+ let arc: Arc<CStr> = Arc::from(cstr);
+
+ assert_eq!(&*rc, cstr);
+ assert_eq!(&*arc, cstr);
+
+ let rc2: Rc<CStr> = Rc::from(cstr.to_owned());
+ let arc2: Arc<CStr> = Arc::from(cstr.to_owned());
+
+ assert_eq!(&*rc2, cstr);
+ assert_eq!(&*arc2, cstr);
+ }
}
diff --git a/ctr-std/src/ffi/mod.rs b/ctr-std/src/ffi/mod.rs
index ca1ff18..a37a5e8 100644
--- a/ctr-std/src/ffi/mod.rs
+++ b/ctr-std/src/ffi/mod.rs
@@ -9,6 +9,157 @@
// except according to those terms.
//! Utilities related to FFI bindings.
+//!
+//! This module provides utilities to handle data across non-Rust
+//! interfaces, like other programming languages and the underlying
+//! operating system. It is mainly of use for FFI (Foreign Function
+//! Interface) bindings and code that needs to exchange C-like strings
+//! with other languages.
+//!
+//! # Overview
+//!
+//! Rust represents owned strings with the [`String`] type, and
+//! borrowed slices of strings with the [`str`] primitive. Both are
+//! always in UTF-8 encoding, and may contain nul bytes in the middle,
+//! i.e. if you look at the bytes that make up the string, there may
+//! be a `\0` among them. Both `String` and `str` store their length
+//! explicitly; there are no nul terminators at the end of strings
+//! like in C.
+//!
+//! C strings are different from Rust strings:
+//!
+//! * **Encodings** - Rust strings are UTF-8, but C strings may use
+//! other encodings. If you are using a string from C, you should
+//! check its encoding explicitly, rather than just assuming that it
+//! is UTF-8 like you can do in Rust.
+//!
+//! * **Character size** - C strings may use `char` or `wchar_t`-sized
+//! characters; please **note** that C's `char` is different from Rust's.
+//! The C standard leaves the actual sizes of those types open to
+//! interpretation, but defines different APIs for strings made up of
+//! each character type. Rust strings are always UTF-8, so different
+//! Unicode characters will be encoded in a variable number of bytes
+//! each. The Rust type [`char`] represents a '[Unicode scalar
+//! value]', which is similar to, but not the same as, a '[Unicode
+//! code point]'.
+//!
+//! * **Nul terminators and implicit string lengths** - Often, C
+//! strings are nul-terminated, i.e. they have a `\0` character at the
+//! end. The length of a string buffer is not stored, but has to be
+//! calculated; to compute the length of a string, C code must
+//! manually call a function like `strlen()` for `char`-based strings,
+//! or `wcslen()` for `wchar_t`-based ones. Those functions return
+//! the number of characters in the string excluding the nul
+//! terminator, so the buffer length is really `len+1` characters.
+//! Rust strings don't have a nul terminator; their length is always
+//! stored and does not need to be calculated. While in Rust
+//! accessing a string's length is a O(1) operation (because the
+//! length is stored); in C it is an O(length) operation because the
+//! length needs to be computed by scanning the string for the nul
+//! terminator.
+//!
+//! * **Internal nul characters** - When C strings have a nul
+//! terminator character, this usually means that they cannot have nul
+//! characters in the middle — a nul character would essentially
+//! truncate the string. Rust strings *can* have nul characters in
+//! the middle, because nul does not have to mark the end of the
+//! string in Rust.
+//!
+//! # Representations of non-Rust strings
+//!
+//! [`CString`] and [`CStr`] are useful when you need to transfer
+//! UTF-8 strings to and from languages with a C ABI, like Python.
+//!
+//! * **From Rust to C:** [`CString`] represents an owned, C-friendly
+//! string: it is nul-terminated, and has no internal nul characters.
+//! Rust code can create a `CString` out of a normal string (provided
+//! that the string doesn't have nul characters in the middle), and
+//! then use a variety of methods to obtain a raw `*mut u8` that can
+//! then be passed as an argument to functions which use the C
+//! conventions for strings.
+//!
+//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
+//! is what you would use to wrap a raw `*const u8` that you got from
+//! a C function. A `CStr` is guaranteed to be a nul-terminated array
+//! of bytes. Once you have a `CStr`, you can convert it to a Rust
+//! `&str` if it's valid UTF-8, or lossily convert it by adding
+//! replacement characters.
+//!
+//! [`OsString`] and [`OsStr`] are useful when you need to transfer
+//! strings to and from the operating system itself, or when capturing
+//! the output of external commands. Conversions between `OsString`,
+//! `OsStr` and Rust strings work similarly to those for [`CString`]
+//! and [`CStr`].
+//!
+//! * [`OsString`] represents an owned string in whatever
+//! representation the operating system prefers. In the Rust standard
+//! library, various APIs that transfer strings to/from the operating
+//! system use `OsString` instead of plain strings. For example,
+//! [`env::var_os()`] is used to query environment variables; it
+//! returns an `Option<OsString>`. If the environment variable exists
+//! you will get a `Some(os_string)`, which you can *then* try to
+//! convert to a Rust string. This yields a [`Result<>`], so that
+//! your code can detect errors in case the environment variable did
+//! not in fact contain valid Unicode data.
+//!
+//! * [`OsStr`] represents a borrowed reference to a string in a
+//! format that can be passed to the operating system. It can be
+//! converted into an UTF-8 Rust string slice in a similar way to
+//! `OsString`.
+//!
+//! # Conversions
+//!
+//! ## On Unix
+//!
+//! On Unix, [`OsStr`] implements the
+//! `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which
+//! augments it with two methods, [`from_bytes`] and [`as_bytes`].
+//! These do inexpensive conversions from and to UTF-8 byte slices.
+//!
+//! Additionally, on Unix [`OsString`] implements the
+//! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait,
+//! which provides [`from_vec`] and [`into_vec`] methods that consume
+//! their arguments, and take or produce vectors of [`u8`].
+//!
+//! ## On Windows
+//!
+//! On Windows, [`OsStr`] implements the
+//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait,
+//! which provides an [`encode_wide`] method. This provides an
+//! iterator that can be [`collect`]ed into a vector of [`u16`].
+//!
+//! Additionally, on Windows [`OsString`] implements the
+//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
+//! trait, which provides a [`from_wide`] method. The result of this
+//! method is an `OsString` which can be round-tripped to a Windows
+//! string losslessly.
+//!
+//! [`String`]: ../string/struct.String.html
+//! [`str`]: ../primitive.str.html
+//! [`char`]: ../primitive.char.html
+//! [`u8`]: ../primitive.u8.html
+//! [`u16`]: ../primitive.u16.html
+//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
+//! [Unicode code point]: http://www.unicode.org/glossary/#code_point
+//! [`CString`]: struct.CString.html
+//! [`CStr`]: struct.CStr.html
+//! [`OsString`]: struct.OsString.html
+//! [`OsStr`]: struct.OsStr.html
+//! [`env::set_var()`]: ../env/fn.set_var.html
+//! [`env::var_os()`]: ../env/fn.var_os.html
+//! [`Result<>`]: ../result/enum.Result.html
+//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html
+//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec
+//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec
+//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html
+//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes
+//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes
+//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html
+//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html
+//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide
+//! [`collect`]: ../iter/trait.Iterator.html#method.collect
+//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html
+//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide
#![stable(feature = "rust1", since = "1.0.0")]
diff --git a/ctr-std/src/ffi/os_str.rs b/ctr-std/src/ffi/os_str.rs
index 84b50f0..3959e85 100644
--- a/ctr-std/src/ffi/os_str.rs
+++ b/ctr-std/src/ffi/os_str.rs
@@ -9,11 +9,12 @@
// except according to those terms.
use borrow::{Borrow, Cow};
-use fmt::{self, Debug};
-use mem;
+use fmt;
use ops;
use cmp;
use hash::{Hash, Hasher};
+use rc::Rc;
+use sync::Arc;
use sys::os_str::{Buf, Slice};
use sys_common::{AsInner, IntoInner, FromInner};
@@ -29,18 +30,71 @@ use sys_common::{AsInner, IntoInner, FromInner};
/// * On Windows, strings are often arbitrary sequences of non-zero 16-bit
/// values, interpreted as UTF-16 when it is valid to do so.
///
-/// * In Rust, strings are always valid UTF-8, but may contain zeros.
+/// * In Rust, strings are always valid UTF-8, which may contain zeros.
///
-/// `OsString` and `OsStr` bridge this gap by simultaneously representing Rust
+/// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust
/// and platform-native string values, and in particular allowing a Rust string
-/// to be converted into an "OS" string with no cost.
+/// to be converted into an "OS" string with no cost if possible.
+///
+/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
+///
+/// # Creating an `OsString`
+///
+/// **From a Rust string**: `OsString` implements
+/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to
+/// create an `OsString` from a normal Rust string.
+///
+/// **From slices:** Just like you can start with an empty Rust
+/// [`String`] and then [`push_str`][String.push_str] `&str`
+/// sub-string slices into it, you can create an empty `OsString` with
+/// the [`new`] method and then push string slices into it with the
+/// [`push`] method.
+///
+/// # Extracting a borrowed reference to the whole OS string
+///
+/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from
+/// an `OsString`; this is effectively a borrowed reference to the
+/// whole string.
+///
+/// # Conversions
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsString` implements for conversions from/to native representations.
+///
+/// [`OsStr`]: struct.OsStr.html
+/// [`&OsStr`]: struct.OsStr.html
+/// [`From`]: ../convert/trait.From.html
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
+/// [`u8`]: ../primitive.u8.html
+/// [`u16`]: ../primitive.u16.html
+/// [String.push_str]: ../string/struct.String.html#method.push_str
+/// [`new`]: #method.new
+/// [`push`]: #method.push
+/// [`as_os_str`]: #method.as_os_str
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OsString {
inner: Buf
}
-/// Slices into OS strings (see `OsString`).
+/// Borrowed reference to an OS string (see [`OsString`]).
+///
+/// This type represents a borrowed reference to a string in the operating system's preferred
+/// representation.
+///
+/// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed
+/// references; the latter are owned strings.
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsStr` implements for conversions from/to native representations.
+///
+/// [`OsString`]: struct.OsString.html
+/// [`&str`]: ../primitive.str.html
+/// [`String`]: ../string/struct.String.html
+/// [conversions]: index.html#conversions
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OsStr {
inner: Slice
@@ -48,26 +102,70 @@ pub struct OsStr {
impl OsString {
/// Constructs a new empty `OsString`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let os_string = OsString::new();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> OsString {
OsString { inner: Buf::from_string(String::new()) }
}
- /// Converts to an `OsStr` slice.
+ /// Converts to an [`OsStr`] slice.
+ ///
+ /// [`OsStr`]: struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{OsString, OsStr};
+ ///
+ /// let os_string = OsString::from("foo");
+ /// let os_str = OsStr::new("foo");
+ /// assert_eq!(os_string.as_os_str(), os_str);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_os_str(&self) -> &OsStr {
self
}
- /// Converts the `OsString` into a `String` if it contains valid Unicode data.
+ /// Converts the `OsString` into a [`String`] if it contains valid Unicode data.
///
/// On failure, ownership of the original `OsString` is returned.
+ ///
+ /// [`String`]: ../../std/string/struct.String.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let os_string = OsString::from("foo");
+ /// let string = os_string.into_string();
+ /// assert_eq!(string, Ok(String::from("foo")));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_string(self) -> Result<String, OsString> {
self.inner.into_string().map_err(|buf| OsString { inner: buf} )
}
- /// Extends the string with the given `&OsStr` slice.
+ /// Extends the string with the given [`&OsStr`] slice.
+ ///
+ /// [`&OsStr`]: struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::from("foo");
+ /// os_string.push("bar");
+ /// assert_eq!(&os_string, "foobar");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
self.inner.push_slice(&s.as_ref().inner)
@@ -75,11 +173,25 @@ impl OsString {
/// Creates a new `OsString` with the given capacity.
///
- /// The string will be able to hold exactly `capacity` lenth units of other
+ /// The string will be able to hold exactly `capacity` length units of other
/// OS strings without reallocating. If `capacity` is 0, the string will not
/// allocate.
///
/// See main `OsString` documentation information about encoding.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::with_capacity(10);
+ /// let capacity = os_string.capacity();
+ ///
+ /// // This push is done without reallocating
+ /// os_string.push("foo");
+ ///
+ /// assert_eq!(capacity, os_string.capacity());
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn with_capacity(capacity: usize) -> OsString {
OsString {
@@ -88,6 +200,18 @@ impl OsString {
}
/// Truncates the `OsString` to zero length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::from("foo");
+ /// assert_eq!(&os_string, "foo");
+ ///
+ /// os_string.clear();
+ /// assert_eq!(&os_string, "");
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn clear(&mut self) {
self.inner.clear()
@@ -96,6 +220,15 @@ impl OsString {
/// Returns the capacity this `OsString` can hold without reallocating.
///
/// See `OsString` introduction for information about encoding.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::with_capacity(10);
+ /// assert!(os_string.capacity() >= 10);
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn capacity(&self) -> usize {
self.inner.capacity()
@@ -105,6 +238,16 @@ impl OsString {
/// in the given `OsString`.
///
/// The collection may reserve more space to avoid frequent reallocations.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::new();
+ /// s.reserve(10);
+ /// assert!(s.capacity() >= 10);
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional)
@@ -117,10 +260,59 @@ impl OsString {
/// Note that the allocator may give the collection more space than it
/// requests. Therefore capacity can not be relied upon to be precisely
/// minimal. Prefer reserve if future insertions are expected.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::new();
+ /// s.reserve_exact(10);
+ /// assert!(s.capacity() >= 10);
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn reserve_exact(&mut self, additional: usize) {
self.inner.reserve_exact(additional)
}
+
+ /// Shrinks the capacity of the `OsString` to match its length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::from("foo");
+ ///
+ /// s.reserve(100);
+ /// assert!(s.capacity() >= 100);
+ ///
+ /// s.shrink_to_fit();
+ /// assert_eq!(3, s.capacity());
+ /// ```
+ #[stable(feature = "osstring_shrink_to_fit", since = "1.19.0")]
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
+ /// Converts this `OsString` into a boxed [`OsStr`].
+ ///
+ /// [`OsStr`]: struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{OsString, OsStr};
+ ///
+ /// let s = OsString::from("hello");
+ ///
+ /// let b: Box<OsStr> = s.into_boxed_os_str();
+ /// ```
+ #[stable(feature = "into_boxed_os_str", since = "1.20.0")]
+ pub fn into_boxed_os_str(self) -> Box<OsStr> {
+ let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr;
+ unsafe { Box::from_raw(rw) }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -167,8 +359,8 @@ impl Default for OsString {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl Debug for OsString {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl fmt::Debug for OsString {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, formatter)
}
}
@@ -253,26 +445,66 @@ impl OsStr {
}
fn from_inner(inner: &Slice) -> &OsStr {
- unsafe { mem::transmute(inner) }
+ unsafe { &*(inner as *const Slice as *const OsStr) }
}
- /// Yields a `&str` slice if the `OsStr` is valid Unicode.
+ /// Yields a [`&str`] slice if the `OsStr` is valid Unicode.
///
/// This conversion may entail doing a check for UTF-8 validity.
+ ///
+ /// [`&str`]: ../../std/primitive.str.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// assert_eq!(os_str.to_str(), Some("foo"));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_str(&self) -> Option<&str> {
self.inner.to_str()
}
- /// Converts an `OsStr` to a `Cow<str>`.
+ /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`.
///
/// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
+ ///
+ /// [`Cow`]: ../../std/borrow/enum.Cow.html
+ /// [`str`]: ../../std/primitive.str.html
+ ///
+ /// # Examples
+ ///
+ /// Calling `to_string_lossy` on an `OsStr` with valid unicode:
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// assert_eq!(os_str.to_string_lossy(), "foo");
+ /// ```
+ ///
+ /// Had `os_str` contained invalid unicode, the `to_string_lossy` call might
+ /// have returned `"fo�"`.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_string_lossy(&self) -> Cow<str> {
self.inner.to_string_lossy()
}
- /// Copies the slice into an owned `OsString`.
+ /// Copies the slice into an owned [`OsString`].
+ ///
+ /// [`OsString`]: struct.OsString.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{OsStr, OsString};
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// let os_string = os_str.to_os_string();
+ /// assert_eq!(os_string, OsString::from("foo"));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_os_string(&self) -> OsString {
OsString { inner: self.inner.to_owned() }
@@ -299,12 +531,15 @@ impl OsStr {
/// Returns the length of this `OsStr`.
///
/// Note that this does **not** return the number of bytes in this string
- /// as, for example, OS strings on Windows are encoded as a list of `u16`
+ /// as, for example, OS strings on Windows are encoded as a list of [`u16`]
/// rather than a list of bytes. This number is simply useful for passing to
- /// other methods like `OsString::with_capacity` to avoid reallocations.
+ /// other methods like [`OsString::with_capacity`] to avoid reallocations.
///
/// See `OsStr` introduction for more information about encoding.
///
+ /// [`u16`]: ../primitive.u16.html
+ /// [`OsString::with_capacity`]: struct.OsString.html#method.with_capacity
+ ///
/// # Examples
///
/// ```
@@ -321,12 +556,88 @@ impl OsStr {
self.inner.inner.len()
}
+ /// Converts a [`Box`]`<OsStr>` into an [`OsString`] without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`OsString`]: struct.OsString.html
+ #[stable(feature = "into_boxed_os_str", since = "1.20.0")]
+ pub fn into_os_string(self: Box<OsStr>) -> OsString {
+ let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
+ OsString { inner: Buf::from_box(boxed) }
+ }
+
/// Gets the underlying byte representation.
///
/// Note: it is *crucial* that this API is private, to avoid
/// revealing the internal, platform-specific encodings.
fn bytes(&self) -> &[u8] {
- unsafe { mem::transmute(&self.inner) }
+ unsafe { &*(&self.inner as *const _ as *const [u8]) }
+ }
+}
+
+#[stable(feature = "box_from_os_str", since = "1.17.0")]
+impl<'a> From<&'a OsStr> for Box<OsStr> {
+ fn from(s: &'a OsStr) -> Box<OsStr> {
+ let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr;
+ unsafe { Box::from_raw(rw) }
+ }
+}
+
+#[stable(feature = "os_string_from_box", since = "1.18.0")]
+impl From<Box<OsStr>> for OsString {
+ fn from(boxed: Box<OsStr>) -> OsString {
+ boxed.into_os_string()
+ }
+}
+
+#[stable(feature = "box_from_os_string", since = "1.20.0")]
+impl From<OsString> for Box<OsStr> {
+ fn from(s: OsString) -> Box<OsStr> {
+ s.into_boxed_os_str()
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<OsString> for Arc<OsStr> {
+ #[inline]
+ fn from(s: OsString) -> Arc<OsStr> {
+ let arc = s.inner.into_arc();
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl<'a> From<&'a OsStr> for Arc<OsStr> {
+ #[inline]
+ fn from(s: &OsStr) -> Arc<OsStr> {
+ let arc = s.inner.into_arc();
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<OsString> for Rc<OsStr> {
+ #[inline]
+ fn from(s: OsString) -> Rc<OsStr> {
+ let rc = s.inner.into_rc();
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl<'a> From<&'a OsStr> for Rc<OsStr> {
+ #[inline]
+ fn from(s: &OsStr) -> Rc<OsStr> {
+ let rc = s.inner.into_rc();
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) }
+ }
+}
+
+#[stable(feature = "box_default_extra", since = "1.17.0")]
+impl Default for Box<OsStr> {
+ fn default() -> Box<OsStr> {
+ let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr;
+ unsafe { Box::from_raw(rw) }
}
}
@@ -443,9 +754,15 @@ impl Hash for OsStr {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl Debug for OsStr {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- self.inner.fmt(formatter)
+impl fmt::Debug for OsStr {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, formatter)
+ }
+}
+
+impl OsStr {
+ pub(crate) fn display(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.inner, formatter)
}
}
@@ -457,7 +774,13 @@ impl Borrow<OsStr> for OsString {
#[stable(feature = "rust1", since = "1.0.0")]
impl ToOwned for OsStr {
type Owned = OsString;
- fn to_owned(&self) -> OsString { self.to_os_string() }
+ fn to_owned(&self) -> OsString {
+ self.to_os_string()
+ }
+ fn clone_into(&self, target: &mut OsString) {
+ target.clear();
+ target.push(self);
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -511,6 +834,9 @@ mod tests {
use super::*;
use sys_common::{AsInner, IntoInner};
+ use rc::Rc;
+ use sync::Arc;
+
#[test]
fn test_os_string_with_capacity() {
let os_string = OsString::with_capacity(0);
@@ -626,4 +952,48 @@ mod tests {
let os_str: &OsStr = Default::default();
assert_eq!("", os_str);
}
+
+ #[test]
+ fn into_boxed() {
+ let orig = "Hello, world!";
+ let os_str = OsStr::new(orig);
+ let boxed: Box<OsStr> = Box::from(os_str);
+ let os_string = os_str.to_owned().into_boxed_os_str().into_os_string();
+ assert_eq!(os_str, &*boxed);
+ assert_eq!(&*boxed, &*os_string);
+ assert_eq!(&*os_string, os_str);
+ }
+
+ #[test]
+ fn boxed_default() {
+ let boxed = <Box<OsStr>>::default();
+ assert!(boxed.is_empty());
+ }
+
+ #[test]
+ fn test_os_str_clone_into() {
+ let mut os_string = OsString::with_capacity(123);
+ os_string.push("hello");
+ let os_str = OsStr::new("bonjour");
+ os_str.clone_into(&mut os_string);
+ assert_eq!(os_str, os_string);
+ assert!(os_string.capacity() >= 123);
+ }
+
+ #[test]
+ fn into_rc() {
+ let orig = "Hello, world!";
+ let os_str = OsStr::new(orig);
+ let rc: Rc<OsStr> = Rc::from(os_str);
+ let arc: Arc<OsStr> = Arc::from(os_str);
+
+ assert_eq!(&*rc, os_str);
+ assert_eq!(&*arc, os_str);
+
+ let rc2: Rc<OsStr> = Rc::from(os_str.to_owned());
+ let arc2: Arc<OsStr> = Arc::from(os_str.to_owned());
+
+ assert_eq!(&*rc2, os_str);
+ assert_eq!(&*arc2, os_str);
+ }
}
diff --git a/ctr-std/src/fs.rs b/ctr-std/src/fs.rs
index e91e808..d1f3ccb 100644
--- a/ctr-std/src/fs.rs
+++ b/ctr-std/src/fs.rs
@@ -19,7 +19,7 @@
use fmt;
use ffi::OsString;
-use io::{self, SeekFrom, Seek, Read, Write};
+use io::{self, SeekFrom, Seek, Read, Initializer, Write};
use path::{Path, PathBuf};
use sys::fs as fs_imp;
use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
@@ -28,28 +28,63 @@ use time::SystemTime;
/// A reference to an open file on the filesystem.
///
/// An instance of a `File` can be read and/or written depending on what options
-/// it was opened with. Files also implement `Seek` to alter the logical cursor
+/// it was opened with. Files also implement [`Seek`] to alter the logical cursor
/// that the file contains internally.
///
/// Files are automatically closed when they go out of scope.
///
/// # Examples
///
+/// Create a new file and write bytes to it:
+///
/// ```no_run
+/// use std::fs::File;
/// use std::io::prelude::*;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut file = File::create("foo.txt")?;
+/// file.write_all(b"Hello, world!")?;
+/// # Ok(())
+/// # }
+/// ```
+///
+/// Read the contents of a file into a [`String`]:
+///
+/// ```no_run
/// use std::fs::File;
+/// use std::io::prelude::*;
///
/// # fn foo() -> std::io::Result<()> {
-/// let mut f = try!(File::create("foo.txt"));
-/// try!(f.write_all(b"Hello, world!"));
+/// let mut file = File::open("foo.txt")?;
+/// let mut contents = String::new();
+/// file.read_to_string(&mut contents)?;
+/// assert_eq!(contents, "Hello, world!");
+/// # Ok(())
+/// # }
+/// ```
+///
+/// It can be more efficient to read the contents of a file with a buffered
+/// [`Read`]er. This can be accomplished with [`BufReader<R>`]:
///
-/// let mut f = try!(File::open("foo.txt"));
-/// let mut s = String::new();
-/// try!(f.read_to_string(&mut s));
-/// assert_eq!(s, "Hello, world!");
+/// ```no_run
+/// use std::fs::File;
+/// use std::io::BufReader;
+/// use std::io::prelude::*;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let file = File::open("foo.txt")?;
+/// let mut buf_reader = BufReader::new(file);
+/// let mut contents = String::new();
+/// buf_reader.read_to_string(&mut contents)?;
+/// assert_eq!(contents, "Hello, world!");
/// # Ok(())
/// # }
/// ```
+///
+/// [`Seek`]: ../io/trait.Seek.html
+/// [`String`]: ../string/struct.String.html
+/// [`Read`]: ../io/trait.Read.html
+/// [`BufReader<R>`]: ../io/struct.BufReader.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct File {
inner: fs_imp::File,
@@ -57,11 +92,13 @@ pub struct File {
/// Metadata information about a file.
///
-/// This structure is returned from the [`metadata`] function or method and
-/// represents known metadata about a file such as its permissions, size,
-/// modification times, etc.
+/// This structure is returned from the [`metadata`] or
+/// [`symlink_metadata`] function or method and represents known
+/// metadata about a file such as its permissions, size, modification
+/// times, etc.
///
/// [`metadata`]: fn.metadata.html
+/// [`symlink_metadata`]: fn.symlink_metadata.html
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct Metadata(fs_imp::FileAttr);
@@ -69,19 +106,19 @@ pub struct Metadata(fs_imp::FileAttr);
/// Iterator over the entries in a directory.
///
/// This iterator is returned from the [`read_dir`] function of this module and
-/// will yield instances of `io::Result<DirEntry>`. Through a [`DirEntry`]
+/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`]
/// information like the entry's path and possibly other metadata can be
/// learned.
///
-/// [`read_dir`]: fn.read_dir.html
-/// [`DirEntry`]: struct.DirEntry.html
-///
/// # Errors
///
-/// This [`io::Result`] will be an `Err` if there's some sort of intermittent
+/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent
/// IO error during iteration.
///
+/// [`read_dir`]: fn.read_dir.html
+/// [`DirEntry`]: struct.DirEntry.html
/// [`io::Result`]: ../io/type.Result.html
+/// [`Err`]: ../result/enum.Result.html#variant.Err
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct ReadDir(fs_imp::ReadDir);
@@ -107,14 +144,14 @@ pub struct DirEntry(fs_imp::DirEntry);
/// [`File::open`]: struct.File.html#method.open
/// [`File::create`]: struct.File.html#method.create
///
-/// Generally speaking, when using `OpenOptions`, you'll first call [`new()`],
-/// then chain calls to methods to set each option, then call [`open()`],
+/// Generally speaking, when using `OpenOptions`, you'll first call [`new`],
+/// then chain calls to methods to set each option, then call [`open`],
/// passing the path of the file you're trying to open. This will give you a
/// [`io::Result`][result] with a [`File`][file] inside that you can further
/// operate on.
///
-/// [`new()`]: struct.OpenOptions.html#method.new
-/// [`open()`]: struct.OpenOptions.html#method.open
+/// [`new`]: struct.OpenOptions.html#method.new
+/// [`open`]: struct.OpenOptions.html#method.open
/// [result]: ../io/type.Result.html
/// [file]: struct.File.html
///
@@ -140,7 +177,7 @@ pub struct DirEntry(fs_imp::DirEntry);
/// .create(true)
/// .open("foo.txt");
/// ```
-#[derive(Clone)]
+#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OpenOptions(fs_imp::OpenOptions);
@@ -168,11 +205,131 @@ pub struct FileType(fs_imp::FileType);
///
/// This builder also supports platform-specific options.
#[stable(feature = "dir_builder", since = "1.6.0")]
+#[derive(Debug)]
pub struct DirBuilder {
inner: fs_imp::DirBuilder,
recursive: bool,
}
+/// How large a buffer to pre-allocate before reading the entire file.
+fn initial_buffer_size(file: &File) -> usize {
+ // Allocate one extra byte so the buffer doesn't need to grow before the
+ // final `read` call at the end of the file. Don't worry about `usize`
+ // overflow because reading will fail regardless in that case.
+ file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0)
+}
+
+/// Read the entire contents of a file into a bytes vector.
+///
+/// This is a convenience function for using [`File::open`] and [`read_to_end`]
+/// with fewer imports and without an intermediate variable.
+///
+/// [`File::open`]: struct.File.html#method.open
+/// [`read_to_end`]: ../io/trait.Read.html#method.read_to_end
+///
+/// # Errors
+///
+/// This function will return an error if `path` does not already exist.
+/// Other errors may also be returned according to [`OpenOptions::open`].
+///
+/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
+///
+/// It will also return an error if it encounters while reading an error
+/// of a kind other than [`ErrorKind::Interrupted`].
+///
+/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(fs_read_write)]
+///
+/// use std::fs;
+/// use std::net::SocketAddr;
+///
+/// # fn foo() -> Result<(), Box<std::error::Error + 'static>> {
+/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?;
+/// # Ok(())
+/// # }
+/// ```
+#[unstable(feature = "fs_read_write", issue = "46588")]
+pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
+ let mut file = File::open(path)?;
+ let mut bytes = Vec::with_capacity(initial_buffer_size(&file));
+ file.read_to_end(&mut bytes)?;
+ Ok(bytes)
+}
+
+/// Read the entire contents of a file into a string.
+///
+/// This is a convenience function for using [`File::open`] and [`read_to_string`]
+/// with fewer imports and without an intermediate variable.
+///
+/// [`File::open`]: struct.File.html#method.open
+/// [`read_to_string`]: ../io/trait.Read.html#method.read_to_string
+///
+/// # Errors
+///
+/// This function will return an error if `path` does not already exist.
+/// Other errors may also be returned according to [`OpenOptions::open`].
+///
+/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
+///
+/// It will also return an error if it encounters while reading an error
+/// of a kind other than [`ErrorKind::Interrupted`],
+/// or if the contents of the file are not valid UTF-8.
+///
+/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(fs_read_write)]
+///
+/// use std::fs;
+/// use std::net::SocketAddr;
+///
+/// # fn foo() -> Result<(), Box<std::error::Error + 'static>> {
+/// let foo: SocketAddr = fs::read_string("address.txt")?.parse()?;
+/// # Ok(())
+/// # }
+/// ```
+#[unstable(feature = "fs_read_write", issue = "46588")]
+pub fn read_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
+ let mut file = File::open(path)?;
+ let mut string = String::with_capacity(initial_buffer_size(&file));
+ file.read_to_string(&mut string)?;
+ Ok(string)
+}
+
+/// Write a slice as the entire contents of a file.
+///
+/// This function will create a file if it does not exist,
+/// and will entirely replace its contents if it does.
+///
+/// This is a convenience function for using [`File::create`] and [`write_all`]
+/// with fewer imports.
+///
+/// [`File::create`]: struct.File.html#method.create
+/// [`write_all`]: ../io/trait.Write.html#method.write_all
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(fs_read_write)]
+///
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// fs::write("foo.txt", b"Lorem ipsum")?;
+/// # Ok(())
+/// # }
+/// ```
+#[unstable(feature = "fs_read_write", issue = "46588")]
+pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
+ File::create(path)?.write_all(contents.as_ref())
+}
+
impl File {
/// Attempts to open a file in read-only mode.
///
@@ -191,7 +348,7 @@ impl File {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("foo.txt"));
+ /// let mut f = File::open("foo.txt")?;
/// # Ok(())
/// # }
/// ```
@@ -215,7 +372,7 @@ impl File {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
+ /// let mut f = File::create("foo.txt")?;
/// # Ok(())
/// # }
/// ```
@@ -236,10 +393,10 @@ impl File {
/// use std::io::prelude::*;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// try!(f.write_all(b"Hello, world!"));
+ /// let mut f = File::create("foo.txt")?;
+ /// f.write_all(b"Hello, world!")?;
///
- /// try!(f.sync_all());
+ /// f.sync_all()?;
/// # Ok(())
/// # }
/// ```
@@ -267,10 +424,10 @@ impl File {
/// use std::io::prelude::*;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// try!(f.write_all(b"Hello, world!"));
+ /// let mut f = File::create("foo.txt")?;
+ /// f.write_all(b"Hello, world!")?;
///
- /// try!(f.sync_data());
+ /// f.sync_data()?;
/// # Ok(())
/// # }
/// ```
@@ -297,8 +454,8 @@ impl File {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// try!(f.set_len(10));
+ /// let mut f = File::create("foo.txt")?;
+ /// f.set_len(10)?;
/// # Ok(())
/// # }
/// ```
@@ -315,8 +472,8 @@ impl File {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("foo.txt"));
- /// let metadata = try!(f.metadata());
+ /// let mut f = File::open("foo.txt")?;
+ /// let metadata = f.metadata()?;
/// # Ok(())
/// # }
/// ```
@@ -337,8 +494,8 @@ impl File {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("foo.txt"));
- /// let file_copy = try!(f.try_clone());
+ /// let mut f = File::open("foo.txt")?;
+ /// let file_copy = f.try_clone()?;
/// # Ok(())
/// # }
/// ```
@@ -368,7 +525,6 @@ impl File {
/// # Examples
///
/// ```
- /// #![feature(set_permissions_atomic)]
/// # fn foo() -> std::io::Result<()> {
/// use std::fs::File;
///
@@ -379,7 +535,7 @@ impl File {
/// # Ok(())
/// # }
/// ```
- #[unstable(feature = "set_permissions_atomic", issue="37916")]
+ #[stable(feature = "set_permissions_atomic", since = "1.16.0")]
pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
self.inner.set_permissions(perm.0)
}
@@ -411,8 +567,10 @@ impl Read for File {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.inner.read_to_end(buf)
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -433,8 +591,10 @@ impl<'a> Read for &'a File {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.inner.read_to_end(buf)
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -519,14 +679,26 @@ impl OpenOptions {
///
/// One maybe obvious note when using append-mode: make sure that all data
/// that belongs together is written to the file in one operation. This
- /// can be done by concatenating strings before passing them to `write()`,
+ /// can be done by concatenating strings before passing them to [`write()`],
/// or using a buffered writer (with a buffer of adequate size),
- /// and calling `flush()` when the message is complete.
+ /// and calling [`flush()`] when the message is complete.
///
/// If a file is opened with both read and append access, beware that after
/// opening, and after every write, the position for reading may be set at the
/// end of the file. So, before writing, save the current position (using
- /// `seek(SeekFrom::Current(0))`, and restore it before the next read.
+ /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`, and restore it before the next read.
+ ///
+ /// ## Note
+ ///
+ /// This function doesn't create the file if it doesn't exist. Use the [`create`]
+ /// method to do so.
+ ///
+ /// [`write()`]: ../../std/fs/struct.File.html#method.write
+ /// [`flush()`]: ../../std/fs/struct.File.html#method.flush
+ /// [`seek`]: ../../std/fs/struct.File.html#method.seek
+ /// [`SeekFrom`]: ../../std/io/enum.SeekFrom.html
+ /// [`Current`]: ../../std/io/enum.SeekFrom.html#variant.Current
+ /// [`create`]: #method.create
///
/// # Examples
///
@@ -564,9 +736,12 @@ impl OpenOptions {
/// This option indicates whether a new file will be created if the file
/// does not yet already exist.
///
- /// In order for the file to be created, `write` or `append` access must
+ /// In order for the file to be created, [`write`] or [`append`] access must
/// be used.
///
+ /// [`write`]: #method.write
+ /// [`append`]: #method.append
+ ///
/// # Examples
///
/// ```no_run
@@ -589,12 +764,15 @@ impl OpenOptions {
/// whether a file exists and creating a new one, the file may have been
/// created by another process (a TOCTOU race condition / attack).
///
- /// If `.create_new(true)` is set, `.create()` and `.truncate()` are
+ /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
/// ignored.
///
/// The file must be opened with write or append access in order to create
/// a new file.
///
+ /// [`.create()`]: #method.create
+ /// [`.truncate()`]: #method.truncate
+ ///
/// # Examples
///
/// ```no_run
@@ -614,15 +792,29 @@ impl OpenOptions {
/// # Errors
///
/// This function will return an error under a number of different
- /// circumstances, to include but not limited to:
- ///
- /// * Opening a file that does not exist without setting `create` or
- /// `create_new`.
- /// * Attempting to open a file with access that the user lacks
- /// permissions for
- /// * Filesystem-level errors (full disk, etc)
- /// * Invalid combinations of open options (truncate without write access,
- /// no access mode set, etc)
+ /// circumstances. Some of these error conditions are listed here, together
+ /// with their [`ErrorKind`]. The mapping to [`ErrorKind`]s is not part of
+ /// the compatibility contract of the function, especially the `Other` kind
+ /// might change to more specific kinds in the future.
+ ///
+ /// * [`NotFound`]: The specified file does not exist and neither `create`
+ /// or `create_new` is set.
+ /// * [`NotFound`]: One of the directory components of the file path does
+ /// not exist.
+ /// * [`PermissionDenied`]: The user lacks permission to get the specified
+ /// access rights for the file.
+ /// * [`PermissionDenied`]: The user lacks permission to open one of the
+ /// directory components of the specified path.
+ /// * [`AlreadyExists`]: `create_new` was specified and the file already
+ /// exists.
+ /// * [`InvalidInput`]: Invalid combinations of open options (truncate
+ /// without write access, no access mode set, etc.).
+ /// * [`Other`]: One of the directory components of the specified file path
+ /// was not, in fact, a directory.
+ /// * [`Other`]: Filesystem-level errors: full disk, write permission
+ /// requested on a read-only file system, exceeded disk quota, too many
+ /// open files, too long filename, too many symbolic links in the
+ /// specified path (Unix-like systems only), etc.
///
/// # Examples
///
@@ -631,6 +823,13 @@ impl OpenOptions {
///
/// let file = OpenOptions::new().open("foo.txt");
/// ```
+ ///
+ /// [`ErrorKind`]: ../io/enum.ErrorKind.html
+ /// [`AlreadyExists`]: ../io/enum.ErrorKind.html#variant.AlreadyExists
+ /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput
+ /// [`NotFound`]: ../io/enum.ErrorKind.html#variant.NotFound
+ /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other
+ /// [`PermissionDenied`]: ../io/enum.ErrorKind.html#variant.PermissionDenied
#[stable(feature = "rust1", since = "1.0.0")]
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
self._open(path.as_ref())
@@ -655,7 +854,7 @@ impl Metadata {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
///
/// println!("{:?}", metadata.file_type());
/// # Ok(())
@@ -674,7 +873,7 @@ impl Metadata {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
///
/// assert!(!metadata.is_dir());
/// # Ok(())
@@ -691,7 +890,7 @@ impl Metadata {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
///
/// assert!(metadata.is_file());
/// # Ok(())
@@ -708,7 +907,7 @@ impl Metadata {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
///
/// assert_eq!(0, metadata.len());
/// # Ok(())
@@ -725,7 +924,7 @@ impl Metadata {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
///
/// assert!(!metadata.permissions().readonly());
/// # Ok(())
@@ -752,7 +951,7 @@ impl Metadata {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
///
/// if let Ok(time) = metadata.modified() {
/// println!("{:?}", time);
@@ -787,7 +986,7 @@ impl Metadata {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
///
/// if let Ok(time) = metadata.accessed() {
/// println!("{:?}", time);
@@ -818,7 +1017,7 @@ impl Metadata {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
///
/// if let Ok(time) = metadata.created() {
/// println!("{:?}", time);
@@ -834,12 +1033,27 @@ impl Metadata {
}
}
+#[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")
+ .field("file_type", &self.file_type())
+ .field("is_dir", &self.is_dir())
+ .field("is_file", &self.is_file())
+ .field("permissions", &self.permissions())
+ .field("modified", &self.modified())
+ .field("accessed", &self.accessed())
+ .field("created", &self.created())
+ .finish()
+ }
+}
+
impl AsInner<fs_imp::FileAttr> for Metadata {
fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 }
}
impl Permissions {
- /// Returns whether these permissions describe a readonly file.
+ /// Returns whether these permissions describe a readonly (unwritable) file.
///
/// # Examples
///
@@ -847,8 +1061,8 @@ impl Permissions {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// let metadata = try!(f.metadata());
+ /// let mut f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
///
/// assert_eq!(false, metadata.permissions().readonly());
/// # Ok(())
@@ -857,7 +1071,11 @@ impl Permissions {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn readonly(&self) -> bool { self.0.readonly() }
- /// Modifies the readonly flag for this set of permissions.
+ /// Modifies the readonly flag for this set of permissions. If the
+ /// `readonly` argument is `true`, using the resulting `Permission` will
+ /// update file permissions to forbid writing. Conversely, if it's `false`,
+ /// using the resulting `Permission` will update file permissions to allow
+ /// writing.
///
/// This operation does **not** modify the filesystem. To modify the
/// filesystem use the `fs::set_permissions` function.
@@ -868,8 +1086,8 @@ impl Permissions {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let f = try!(File::create("foo.txt"));
- /// let metadata = try!(f.metadata());
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
/// let mut permissions = metadata.permissions();
///
/// permissions.set_readonly(true);
@@ -897,7 +1115,7 @@ impl FileType {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
/// let file_type = metadata.file_type();
///
/// assert_eq!(file_type.is_dir(), false);
@@ -915,7 +1133,7 @@ impl FileType {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::metadata("foo.txt")?;
/// let file_type = metadata.file_type();
///
/// assert_eq!(file_type.is_file(), true);
@@ -927,13 +1145,24 @@ impl FileType {
/// Test whether this file type represents a symbolic link.
///
+ /// The underlying [`Metadata`] struct needs to be retrieved
+ /// with the [`fs::symlink_metadata`] function and not the
+ /// [`fs::metadata`] function. The [`fs::metadata`] function
+ /// follows symbolic links, so [`is_symlink`] would always
+ /// return false for the target file.
+ ///
+ /// [`Metadata`]: struct.Metadata.html
+ /// [`fs::metadata`]: fn.metadata.html
+ /// [`fs::symlink_metadata`]: fn.symlink_metadata.html
+ /// [`is_symlink`]: struct.FileType.html#method.is_symlink
+ ///
/// # Examples
///
/// ```
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
- /// let metadata = try!(fs::metadata("foo.txt"));
+ /// let metadata = fs::symlink_metadata("foo.txt")?;
/// let file_type = metadata.file_type();
///
/// assert_eq!(file_type.is_symlink(), false);
@@ -978,8 +1207,8 @@ impl DirEntry {
/// ```
/// use std::fs;
/// # fn foo() -> std::io::Result<()> {
- /// for entry in try!(fs::read_dir(".")) {
- /// let dir = try!(entry);
+ /// for entry in fs::read_dir(".")? {
+ /// let dir = entry?;
/// println!("{:?}", dir.path());
/// }
/// # Ok(())
@@ -1115,6 +1344,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
/// This function currently corresponds to the `unlink` function on Unix
/// and the `DeleteFile` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1131,7 +1361,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// try!(fs::remove_file("a.txt"));
+/// fs::remove_file("a.txt")?;
/// # Ok(())
/// # }
/// ```
@@ -1151,6 +1381,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// This function currently corresponds to the `stat` function on Unix
/// and the `GetFileAttributesEx` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1167,7 +1398,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
-/// let attr = try!(fs::metadata("/some/file/path.txt"));
+/// let attr = fs::metadata("/some/file/path.txt")?;
/// // inspect attr ...
/// # Ok(())
/// # }
@@ -1184,6 +1415,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
/// This function currently corresponds to the `lstat` function on Unix
/// and the `GetFileAttributesEx` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1200,7 +1432,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
-/// let attr = try!(fs::symlink_metadata("/some/file/path.txt"));
+/// let attr = fs::symlink_metadata("/some/file/path.txt")?;
/// // inspect attr ...
/// # Ok(())
/// # }
@@ -1226,6 +1458,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
/// on Windows, `from` can be anything, but `to` must *not* be a directory.
///
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1243,7 +1476,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// try!(fs::rename("a.txt", "b.txt")); // Rename a.txt to b.txt
+/// fs::rename("a.txt", "b.txt")?; // Rename a.txt to b.txt
/// # Ok(())
/// # }
/// ```
@@ -1260,15 +1493,19 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
/// Note that if `from` and `to` both point to the same file, then the file
/// will likely get truncated by this operation.
///
-/// On success, the total number of bytes copied is returned.
+/// On success, the total number of bytes copied is returned and it is equal to
+/// the length of the `to` file as reported by `metadata`.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `open` function in Unix
/// with `O_RDONLY` for `from` and `O_WRONLY`, `O_CREAT`, and `O_TRUNC` for `to`.
/// `O_CLOEXEC` is set for returned file descriptors.
-/// On Windows, this function currently corresponds to `CopyFileEx`.
+/// On Windows, this function currently corresponds to `CopyFileEx`. Alternate
+/// NTFS streams are copied but only the size of the main stream is returned by
+/// this function.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1287,7 +1524,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// try!(fs::copy("foo.txt", "bar.txt")); // Copy foo.txt to bar.txt
+/// fs::copy("foo.txt", "bar.txt")?; // Copy foo.txt to bar.txt
/// # Ok(()) }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1305,6 +1542,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
/// This function currently corresponds to the `link` function on Unix
/// and the `CreateHardLink` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1320,7 +1558,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// try!(fs::hard_link("a.txt", "b.txt")); // Hard link a.txt to b.txt
+/// fs::hard_link("a.txt", "b.txt")?; // Hard link a.txt to b.txt
/// # Ok(())
/// # }
/// ```
@@ -1343,7 +1581,7 @@ pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<(
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// try!(fs::soft_link("a.txt", "b.txt"));
+/// fs::soft_link("a.txt", "b.txt")?;
/// # Ok(())
/// # }
/// ```
@@ -1363,6 +1601,7 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<(
/// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and
/// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1379,7 +1618,7 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<(
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// let path = try!(fs::read_link("a.txt"));
+/// let path = fs::read_link("a.txt")?;
/// # Ok(())
/// # }
/// ```
@@ -1396,6 +1635,7 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
/// This function currently corresponds to the `realpath` function on Unix
/// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1412,7 +1652,7 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// let path = try!(fs::canonicalize("../a/../foo.txt"));
+/// let path = fs::canonicalize("../a/../foo.txt")?;
/// # Ok(())
/// # }
/// ```
@@ -1428,6 +1668,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
/// This function currently corresponds to the `mkdir` function on Unix
/// and the `CreateDirectory` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1444,7 +1685,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// try!(fs::create_dir("/some/dir"));
+/// fs::create_dir("/some/dir")?;
/// # Ok(())
/// # }
/// ```
@@ -1461,6 +1702,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// This function currently corresponds to the `mkdir` function on Unix
/// and the `CreateDirectory` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1473,13 +1715,19 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// error conditions for when a directory is being created (after it is
/// determined to not exist) are outlined by `fs::create_dir`.
///
+/// Notable exception is made for situations where any of the directories
+/// specified in the `path` could not be created as it was being created concurrently.
+/// Such cases are considered to be successful. That is, calling `create_dir_all`
+/// concurrently from multiple threads or processes is guaranteed not to fail
+/// due to a race condition with itself.
+///
/// # Examples
///
/// ```
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// try!(fs::create_dir_all("/some/dir"));
+/// fs::create_dir_all("/some/dir")?;
/// # Ok(())
/// # }
/// ```
@@ -1495,6 +1743,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// This function currently corresponds to the `rmdir` function on Unix
/// and the `RemoveDirectory` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1511,7 +1760,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// try!(fs::remove_dir("/some/dir"));
+/// fs::remove_dir("/some/dir")?;
/// # Ok(())
/// # }
/// ```
@@ -1532,6 +1781,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
/// on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1544,7 +1794,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// use std::fs;
///
/// # fn foo() -> std::io::Result<()> {
-/// try!(fs::remove_dir_all("/some/dir"));
+/// fs::remove_dir_all("/some/dir")?;
/// # Ok(())
/// # }
/// ```
@@ -1566,6 +1816,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// This function currently corresponds to the `opendir` function on Unix
/// and the `FindFirstFile` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1587,11 +1838,11 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// // one possible implementation of walking a directory only visiting files
/// fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
/// if dir.is_dir() {
-/// for entry in try!(fs::read_dir(dir)) {
-/// let entry = try!(entry);
+/// for entry in fs::read_dir(dir)? {
+/// let entry = entry?;
/// let path = entry.path();
/// if path.is_dir() {
-/// try!(visit_dirs(&path, cb));
+/// visit_dirs(&path, cb)?;
/// } else {
/// cb(&entry);
/// }
@@ -1612,6 +1863,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
/// This function currently corresponds to the `chmod` function on Unix
/// and the `SetFileAttributes` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1628,9 +1880,9 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
-/// let mut perms = try!(fs::metadata("foo.txt")).permissions();
+/// let mut perms = fs::metadata("foo.txt")?.permissions();
/// perms.set_readonly(true);
-/// try!(fs::set_permissions("foo.txt", perms));
+/// fs::set_permissions("foo.txt", perms)?;
/// # Ok(())
/// # }
/// ```
@@ -1659,9 +1911,9 @@ impl DirBuilder {
}
}
- /// Indicate that directories create should be created recursively, creating
- /// all parent directories if they do not exist with the same security and
- /// permissions settings.
+ /// Indicates that directories should be created recursively, creating all
+ /// parent directories. Parents that do not exist are created with the same
+ /// security and permissions settings.
///
/// This option defaults to `false`.
///
@@ -1682,6 +1934,9 @@ impl DirBuilder {
/// Create the specified directory with the options configured in this
/// builder.
///
+ /// It is considered an error if the directory already exists unless
+ /// recursive mode is enabled.
+ ///
/// # Examples
///
/// ```no_run
@@ -1708,11 +1963,25 @@ impl DirBuilder {
}
fn create_dir_all(&self, path: &Path) -> io::Result<()> {
- if path == Path::new("") || path.is_dir() { return Ok(()) }
- if let Some(p) = path.parent() {
- self.create_dir_all(p)?
+ if path == Path::new("") {
+ return Ok(())
+ }
+
+ match self.inner.mkdir(path) {
+ Ok(()) => return Ok(()),
+ Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
+ Err(_) if path.is_dir() => return Ok(()),
+ Err(e) => return Err(e),
+ }
+ match path.parent() {
+ Some(p) => try!(self.create_dir_all(p)),
+ None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")),
+ }
+ match self.inner.mkdir(path) {
+ Ok(()) => Ok(()),
+ Err(_) if path.is_dir() => Ok(()),
+ Err(e) => Err(e),
}
- self.inner.mkdir(path)
}
}
@@ -1722,7 +1991,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
}
}
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
mod tests {
use io::prelude::*;
@@ -1732,6 +2001,7 @@ mod tests {
use rand::{StdRng, Rng};
use str;
use sys_common::io::test::{TempDir, tmpdir};
+ use thread;
#[cfg(windows)]
use os::windows::fs::{symlink_dir, symlink_file};
@@ -1751,9 +2021,21 @@ mod tests {
}
) }
+ #[cfg(windows)]
macro_rules! error { ($e:expr, $s:expr) => (
match $e {
Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
+ Err(ref err) => assert!(err.raw_os_error() == Some($s),
+ format!("`{}` did not have a code of `{}`", err, $s))
+ }
+ ) }
+
+ #[cfg(unix)]
+ macro_rules! error { ($e:expr, $s:expr) => ( error_contains!($e, $s) ) }
+
+ macro_rules! error_contains { ($e:expr, $s:expr) => (
+ match $e {
+ Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
Err(ref err) => assert!(err.to_string().contains($s),
format!("`{}` did not contain `{}`", err, $s))
}
@@ -1771,12 +2053,9 @@ mod tests {
match symlink_file(r"nonexisting_target", link) {
Ok(_) => true,
- Err(ref err) =>
- if err.to_string().contains("A required privilege is not held by the client.") {
- false
- } else {
- true
- }
+ // ERROR_PRIVILEGE_NOT_HELD = 1314
+ Err(ref err) if err.raw_os_error() == Some(1314) => false,
+ Err(_) => true,
}
}
@@ -1807,12 +2086,10 @@ mod tests {
let filename = &tmpdir.join("file_that_does_not_exist.txt");
let result = File::open(filename);
- if cfg!(unix) {
- error!(result, "No such file or directory");
- }
- if cfg!(windows) {
- error!(result, "The system cannot find the file specified");
- }
+ #[cfg(unix)]
+ error!(result, "No such file or directory");
+ #[cfg(windows)]
+ error!(result, 2); // ERROR_FILE_NOT_FOUND
}
#[test]
@@ -1822,12 +2099,10 @@ mod tests {
let result = fs::remove_file(filename);
- if cfg!(unix) {
- error!(result, "No such file or directory");
- }
- if cfg!(windows) {
- error!(result, "The system cannot find the file specified");
- }
+ #[cfg(unix)]
+ error!(result, "No such file or directory");
+ #[cfg(windows)]
+ error!(result, 2); // ERROR_FILE_NOT_FOUND
}
#[test]
@@ -2010,6 +2285,27 @@ mod tests {
}
#[test]
+ #[cfg(unix)]
+ fn set_get_unix_permissions() {
+ use os::unix::fs::PermissionsExt;
+
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("set_get_unix_permissions");
+ check!(fs::create_dir(filename));
+ let mask = 0o7777;
+
+ check!(fs::set_permissions(filename,
+ fs::Permissions::from_mode(0)));
+ let metadata0 = check!(fs::metadata(filename));
+ assert_eq!(mask & metadata0.permissions().mode(), 0);
+
+ check!(fs::set_permissions(filename,
+ fs::Permissions::from_mode(0o1777)));
+ let metadata1 = check!(fs::metadata(filename));
+ assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
+ }
+
+ #[test]
#[cfg(windows)]
fn file_test_io_seek_read_write() {
use os::windows::fs::FileExt;
@@ -2197,8 +2493,39 @@ mod tests {
}
#[test]
+ fn concurrent_recursive_mkdir() {
+ for _ in 0..100 {
+ let dir = tmpdir();
+ let mut dir = dir.join("a");
+ for _ in 0..40 {
+ dir = dir.join("a");
+ }
+ let mut join = vec!();
+ for _ in 0..8 {
+ let dir = dir.clone();
+ join.push(thread::spawn(move || {
+ check!(fs::create_dir_all(&dir));
+ }))
+ }
+
+ // No `Display` on result of `join()`
+ join.drain(..).map(|join| join.join().unwrap()).count();
+ }
+ }
+
+ #[test]
fn recursive_mkdir_slash() {
- check!(fs::create_dir_all(&Path::new("/")));
+ check!(fs::create_dir_all(Path::new("/")));
+ }
+
+ #[test]
+ fn recursive_mkdir_dot() {
+ check!(fs::create_dir_all(Path::new(".")));
+ }
+
+ #[test]
+ fn recursive_mkdir_empty() {
+ check!(fs::create_dir_all(Path::new("")));
}
#[test]
@@ -2279,7 +2606,7 @@ mod tests {
let tmpdir = tmpdir();
let unicode = tmpdir.path();
- let unicode = unicode.join(&format!("test-각丁ー再见"));
+ let unicode = unicode.join("test-각丁ー再见");
check!(fs::create_dir(&unicode));
assert!(unicode.exists());
assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
@@ -2386,7 +2713,7 @@ mod tests {
fn copy_file_preserves_streams() {
let tmp = tmpdir();
check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
- assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 6);
+ assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0);
assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0);
let mut v = Vec::new();
check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v));
@@ -2394,6 +2721,18 @@ mod tests {
}
#[test]
+ fn copy_file_returns_metadata_len() {
+ let tmp = tmpdir();
+ let in_path = tmp.join("in.txt");
+ let out_path = tmp.join("out.txt");
+ check!(check!(File::create(&in_path)).write(b"lettuce"));
+ #[cfg(windows)]
+ check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot"));
+ let copied_len = check!(fs::copy(&in_path, &out_path));
+ assert_eq!(check!(out_path.metadata()).len(), copied_len);
+ }
+
+ #[test]
fn symlinks_work() {
let tmpdir = tmpdir();
if !got_symlink_permission(&tmpdir) { return };
@@ -2582,8 +2921,10 @@ mod tests {
let mut a = OO::new(); a.append(true);
let mut ra = OO::new(); ra.read(true).append(true);
- let invalid_options = if cfg!(windows) { "The parameter is incorrect" }
- else { "Invalid argument" };
+ #[cfg(windows)]
+ let invalid_options = 87; // ERROR_INVALID_PARAMETER
+ #[cfg(unix)]
+ let invalid_options = "Invalid argument";
// Test various combinations of creation modes and access modes.
//
@@ -2702,6 +3043,27 @@ mod tests {
}
#[test]
+ fn write_then_read() {
+ let mut bytes = [0; 1024];
+ StdRng::new().unwrap().fill_bytes(&mut bytes);
+
+ let tmpdir = tmpdir();
+
+ check!(fs::write(&tmpdir.join("test"), &bytes[..]));
+ let v = check!(fs::read(&tmpdir.join("test")));
+ assert!(v == &bytes[..]);
+
+ check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
+ error_contains!(fs::read_string(&tmpdir.join("not-utf8")),
+ "stream did not contain valid UTF-8");
+
+ let s = "𐁁𐀓𐀠𐀴𐀍";
+ check!(fs::write(&tmpdir.join("utf8"), s.as_bytes()));
+ let string = check!(fs::read_string(&tmpdir.join("utf8")));
+ assert_eq!(string, s);
+ }
+
+ #[test]
fn file_try_clone() {
let tmpdir = tmpdir();
diff --git a/ctr-std/src/heap.rs b/ctr-std/src/heap.rs
index 83bd3b0..4d5e4df 100644
--- a/ctr-std/src/heap.rs
+++ b/ctr-std/src/heap.rs
@@ -13,11 +13,11 @@
#![unstable(issue = "32838", feature = "allocator_api")]
pub use alloc::heap::{Heap, Alloc, Layout, Excess, CannotReallocInPlace, AllocErr};
-#[cfg(not(stage0))]
pub use alloc_system::System;
-#[cfg(all(not(stage0), not(test)))]
+#[cfg(not(test))]
#[doc(hidden)]
+#[allow(unused_attributes)]
pub mod __default_lib_allocator {
use super::{System, Layout, Alloc, AllocErr};
use ptr;
@@ -29,6 +29,7 @@ pub mod __default_lib_allocator {
// ABI
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc(size: usize,
align: usize,
err: *mut u8) -> *mut u8 {
@@ -43,11 +44,13 @@ pub mod __default_lib_allocator {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_oom(err: *const u8) -> ! {
System.oom((*(err as *const AllocErr)).clone())
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
size: usize,
align: usize) {
@@ -55,6 +58,7 @@ pub mod __default_lib_allocator {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_usable_size(layout: *const u8,
min: *mut usize,
max: *mut usize) {
@@ -64,6 +68,7 @@ pub mod __default_lib_allocator {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
old_size: usize,
old_align: usize,
@@ -82,6 +87,7 @@ pub mod __default_lib_allocator {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_zeroed(size: usize,
align: usize,
err: *mut u8) -> *mut u8 {
@@ -96,6 +102,7 @@ pub mod __default_lib_allocator {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_excess(size: usize,
align: usize,
excess: *mut usize,
@@ -114,6 +121,7 @@ pub mod __default_lib_allocator {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8,
old_size: usize,
old_align: usize,
@@ -136,6 +144,7 @@ pub mod __default_lib_allocator {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
@@ -150,6 +159,7 @@ pub mod __default_lib_allocator {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
diff --git a/ctr-std/src/io/buffered.rs b/ctr-std/src/io/buffered.rs
index 44dd4e9..4e7db5f 100644
--- a/ctr-std/src/io/buffered.rs
+++ b/ctr-std/src/io/buffered.rs
@@ -15,18 +15,18 @@ use io::prelude::*;
use cmp;
use error;
use fmt;
-use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
+use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
use memchr;
/// 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.
-/// A `BufReader` performs large, infrequent reads on the underlying [`Read`]
-/// and maintains an in-memory buffer of the results.
+/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
+/// results in a system call. A `BufReader` performs large, infrequent reads on
+/// the underlying [`Read`] and maintains an in-memory buffer of the results.
///
/// [`Read`]: ../../std/io/trait.Read.html
-/// [`read`]: ../../std/net/struct.TcpStream.html#method.read
+/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
///
/// # Examples
@@ -37,11 +37,11 @@ use memchr;
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
-/// let mut f = try!(File::open("log.txt"));
+/// let f = File::open("log.txt")?;
/// let mut reader = BufReader::new(f);
///
/// let mut line = String::new();
-/// let len = try!(reader.read_line(&mut line));
+/// let len = reader.read_line(&mut line)?;
/// println!("First line is {} bytes long", len);
/// # Ok(())
/// # }
@@ -64,8 +64,8 @@ impl<R: Read> BufReader<R> {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("log.txt"));
- /// let mut reader = BufReader::new(f);
+ /// let f = File::open("log.txt")?;
+ /// let reader = BufReader::new(f);
/// # Ok(())
/// # }
/// ```
@@ -85,18 +85,23 @@ impl<R: Read> BufReader<R> {
/// 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);
+ /// let f = File::open("log.txt")?;
+ /// let 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 {
- inner: inner,
- buf: vec![0; cap].into_boxed_slice(),
- pos: 0,
- cap: 0,
+ unsafe {
+ let mut buffer = Vec::with_capacity(cap);
+ buffer.set_len(cap);
+ inner.initializer().initialize(&mut buffer);
+ BufReader {
+ inner,
+ buf: buffer.into_boxed_slice(),
+ pos: 0,
+ cap: 0,
+ }
}
}
@@ -111,8 +116,8 @@ impl<R: Read> BufReader<R> {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f1 = try!(File::open("log.txt"));
- /// let mut reader = BufReader::new(f1);
+ /// let f1 = File::open("log.txt")?;
+ /// let reader = BufReader::new(f1);
///
/// let f2 = reader.get_ref();
/// # Ok(())
@@ -132,7 +137,7 @@ impl<R: Read> BufReader<R> {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f1 = try!(File::open("log.txt"));
+ /// let f1 = File::open("log.txt")?;
/// let mut reader = BufReader::new(f1);
///
/// let f2 = reader.get_mut();
@@ -142,6 +147,31 @@ impl<R: Read> BufReader<R> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
+ /// Returns `true` if there are no bytes in the internal buffer.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(bufreader_is_empty)]
+ /// use std::io::BufReader;
+ /// use std::io::BufRead;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let f1 = File::open("log.txt")?;
+ /// let mut reader = BufReader::new(f1);
+ /// assert!(reader.is_empty());
+ ///
+ /// if reader.fill_buf()?.len() > 0 {
+ /// assert!(!reader.is_empty());
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")]
+ pub fn is_empty(&self) -> bool {
+ self.pos == self.cap
+ }
+
/// Unwraps this `BufReader`, returning the underlying reader.
///
/// Note that any leftover data in the internal buffer is lost.
@@ -153,8 +183,8 @@ impl<R: Read> BufReader<R> {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f1 = try!(File::open("log.txt"));
- /// let mut reader = BufReader::new(f1);
+ /// let f1 = File::open("log.txt")?;
+ /// let reader = BufReader::new(f1);
///
/// let f2 = reader.into_inner();
/// # Ok(())
@@ -164,6 +194,31 @@ impl<R: Read> BufReader<R> {
pub fn into_inner(self) -> R { self.inner }
}
+impl<R: Seek> BufReader<R> {
+ /// Seeks relative to the current position. If the new position lies within the buffer,
+ /// the buffer will not be flushed, allowing for more efficient seeks.
+ /// This method does not return the location of the underlying reader, so the caller
+ /// must track this information themselves if it is required.
+ #[unstable(feature = "bufreader_seek_relative", issue = "31100")]
+ pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
+ let pos = self.pos as u64;
+ if offset < 0 {
+ if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
+ self.pos = new_pos as usize;
+ return Ok(())
+ }
+ } else {
+ if let Some(new_pos) = pos.checked_add(offset as u64) {
+ if new_pos <= self.cap as u64 {
+ self.pos = new_pos as usize;
+ return Ok(())
+ }
+ }
+ }
+ self.seek(SeekFrom::Current(offset)).map(|_|())
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@@ -180,6 +235,11 @@ impl<R: Read> Read for BufReader<R> {
self.consume(nread);
Ok(nread)
}
+
+ // we can't skip unconditionally because of the large buffer case in read.
+ unsafe fn initializer(&self) -> Initializer {
+ self.inner.initializer()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -187,7 +247,10 @@ impl<R: Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
// If we've reached the end of our internal buffer then we need to fetch
// some more data from the underlying reader.
- if self.pos == self.cap {
+ // Branch using `>=` instead of the more correct `==`
+ // to tell the compiler that the pos..cap slice is always valid.
+ if self.pos >= self.cap {
+ debug_assert!(self.pos == self.cap);
self.cap = self.inner.read(&mut self.buf)?;
self.pos = 0;
}
@@ -222,13 +285,17 @@ impl<R: Seek> Seek for BufReader<R> {
/// `.into_inner()` immediately after a seek yields the underlying reader
/// at the same position.
///
+ /// To seek without discarding the internal buffer, use [`seek_relative`].
+ ///
/// See `std::io::Seek` for more details.
///
/// Note: In the edge case where you're seeking with `SeekFrom::Current(n)`
- /// where `n` minus the internal buffer length underflows an `i64`, two
+ /// where `n` minus the internal buffer length overflows an `i64`, two
/// seeks will be performed instead of one. If the second seek returns
/// `Err`, the underlying reader will be left at the same position it would
/// have if you seeked to `SeekFrom::Current(0)`.
+ ///
+ /// [`seek_relative`]: #method.seek_relative
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let result: u64;
if let SeekFrom::Current(n) = pos {
@@ -258,11 +325,15 @@ impl<R: Seek> Seek for BufReader<R> {
/// Wraps a writer and buffers its output.
///
/// It can be excessively inefficient to work directly with something that
-/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`]
-/// results in a system call. A `BufWriter` keeps an in-memory buffer of data
-/// and writes it to an underlying writer in large, infrequent batches.
+/// implements [`Write`]. For example, every call to
+/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A
+/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
+/// writer in large, infrequent batches.
///
-/// The buffer will be written out when the writer is dropped.
+/// When the `BufWriter` is dropped, the contents of its buffer will be written
+/// out. However, any errors that happen in the process of flushing the buffer
+/// when the writer is dropped will be ignored. Code that wishes to handle such
+/// errors must manually call [`flush`] before the writer is dropped.
///
/// # Examples
///
@@ -274,8 +345,8 @@ impl<R: Seek> Seek for BufReader<R> {
///
/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
///
-/// for i in 1..10 {
-/// stream.write(&[i]).unwrap();
+/// for i in 0..10 {
+/// stream.write(&[i+1]).unwrap();
/// }
/// ```
///
@@ -290,8 +361,8 @@ impl<R: Seek> Seek for BufReader<R> {
///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
-/// for i in 1..10 {
-/// stream.write(&[i]).unwrap();
+/// for i in 0..10 {
+/// stream.write(&[i+1]).unwrap();
/// }
/// ```
///
@@ -300,8 +371,9 @@ impl<R: Seek> Seek for BufReader<R> {
/// the `stream` is dropped.
///
/// [`Write`]: ../../std/io/trait.Write.html
-/// [`write`]: ../../std/net/struct.TcpStream.html#method.write
+/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write
/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+/// [`flush`]: #method.flush
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufWriter<W: Write> {
inner: Option<W>,
@@ -443,6 +515,10 @@ impl<W: Write> BufWriter<W> {
///
/// The buffer is written out before returning the writer.
///
+ /// # Errors
+ ///
+ /// An `Err` will be returned if an error occurs while flushing the buffer.
+ ///
/// # Examples
///
/// ```no_run
@@ -607,6 +683,9 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
/// does exactly that.
///
+/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
+/// `LineWriter` goes out of scope or when its internal buffer is full.
+///
/// [bufwriter]: struct.BufWriter.html
///
/// If there's still a partial line in the buffer when the `LineWriter` is
@@ -629,7 +708,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// I took the one less traveled by,
/// And that has made all the difference.";
///
-/// let file = try!(File::create("poem.txt"));
+/// let file = File::create("poem.txt")?;
/// let mut file = LineWriter::new(file);
///
/// for &byte in road_not_taken.iter() {
@@ -637,10 +716,10 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// }
///
/// // let's check we did the right thing.
-/// let mut file = try!(File::open("poem.txt"));
+/// let mut file = File::open("poem.txt")?;
/// let mut contents = String::new();
///
-/// try!(file.read_to_string(&mut contents));
+/// file.read_to_string(&mut contents)?;
///
/// assert_eq!(contents.as_bytes(), &road_not_taken[..]);
/// # Ok(())
@@ -649,6 +728,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LineWriter<W: Write> {
inner: BufWriter<W>,
+ need_flush: bool,
}
impl<W: Write> LineWriter<W> {
@@ -661,7 +741,7 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
/// let file = LineWriter::new(file);
/// # Ok(())
/// # }
@@ -682,14 +762,17 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
/// let file = LineWriter::with_capacity(100, file);
/// # Ok(())
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> {
- LineWriter { inner: BufWriter::with_capacity(cap, inner) }
+ LineWriter {
+ inner: BufWriter::with_capacity(cap, inner),
+ need_flush: false,
+ }
}
/// Gets a reference to the underlying writer.
@@ -701,7 +784,7 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
/// let file = LineWriter::new(file);
///
/// let reference = file.get_ref();
@@ -723,7 +806,7 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
/// let mut file = LineWriter::new(file);
///
/// // we can use reference just like file
@@ -738,6 +821,10 @@ impl<W: Write> LineWriter<W> {
///
/// The internal buffer is written out before returning the writer.
///
+ // # Errors
+ ///
+ /// An `Err` will be returned if an error occurs while flushing the buffer.
+ ///
/// # Examples
///
/// ```
@@ -745,18 +832,21 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
///
/// let writer: LineWriter<File> = LineWriter::new(file);
///
- /// let file: File = try!(writer.into_inner());
+ /// let file: File = writer.into_inner()?;
/// # Ok(())
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
- IntoInnerError(LineWriter { inner: buf }, e)
+ IntoInnerError(LineWriter {
+ inner: buf,
+ need_flush: false,
+ }, e)
})
}
}
@@ -764,20 +854,46 @@ impl<W: Write> LineWriter<W> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Write for LineWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- match memchr::memrchr(b'\n', buf) {
- Some(i) => {
- let n = self.inner.write(&buf[..i + 1])?;
- if n != i + 1 || self.inner.flush().is_err() {
- // Do not return errors on partial writes.
- return Ok(n);
- }
- self.inner.write(&buf[i + 1..]).map(|i| n + i)
- }
- None => self.inner.write(buf),
+ if self.need_flush {
+ self.flush()?;
+ }
+
+ // Find the last newline character in the buffer provided. If found then
+ // we're going to write all the data up to that point and then flush,
+ // otherewise we just write the whole block to the underlying writer.
+ let i = match memchr::memrchr(b'\n', buf) {
+ Some(i) => i,
+ None => return self.inner.write(buf),
+ };
+
+
+ // Ok, we're going to write a partial amount of the data given first
+ // followed by flushing the newline. After we've successfully written
+ // some data then we *must* report that we wrote that data, so future
+ // errors are ignored. We set our internal `need_flush` flag, though, in
+ // case flushing fails and we need to try it first next time.
+ let n = self.inner.write(&buf[..i + 1])?;
+ self.need_flush = true;
+ if self.flush().is_err() || n != i + 1 {
+ return Ok(n)
+ }
+
+ // At this point we successfully wrote `i + 1` bytes and flushed it out,
+ // meaning that the entire line is now flushed out on the screen. While
+ // we can attempt to finish writing the rest of the data provided.
+ // Remember though that we ignore errors here as we've successfully
+ // written data, so we need to report that.
+ match self.inner.write(&buf[i + 1..]) {
+ Ok(i) => Ok(n + i),
+ Err(_) => Ok(n),
}
}
- fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.flush()?;
+ self.need_flush = false;
+ Ok(())
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -867,6 +983,23 @@ mod tests {
}
#[test]
+ fn test_buffered_reader_seek_relative() {
+ let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+ let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
+
+ assert!(reader.seek_relative(3).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert!(reader.seek_relative(0).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert!(reader.seek_relative(1).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[1][..]));
+ assert!(reader.seek_relative(-1).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert!(reader.seek_relative(2).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..]));
+ }
+
+ #[test]
fn test_buffered_reader_seek_underflow() {
// gimmick reader that yields its position modulo 256 for each byte
struct PositionReader {
@@ -1150,4 +1283,44 @@ mod tests {
BufWriter::new(io::sink())
});
}
+
+ struct AcceptOneThenFail {
+ written: bool,
+ flushed: bool,
+ }
+
+ impl Write for AcceptOneThenFail {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ if !self.written {
+ assert_eq!(data, b"a\nb\n");
+ self.written = true;
+ Ok(data.len())
+ } else {
+ Err(io::Error::new(io::ErrorKind::NotFound, "test"))
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ assert!(self.written);
+ assert!(!self.flushed);
+ self.flushed = true;
+ Err(io::Error::new(io::ErrorKind::Other, "test"))
+ }
+ }
+
+ #[test]
+ fn erroneous_flush_retried() {
+ let a = AcceptOneThenFail {
+ written: false,
+ flushed: false,
+ };
+
+ let mut l = LineWriter::new(a);
+ assert_eq!(l.write(b"a\nb\na").unwrap(), 4);
+ assert!(l.get_ref().written);
+ assert!(l.get_ref().flushed);
+ l.get_mut().flushed = false;
+
+ assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other)
+ }
}
diff --git a/ctr-std/src/io/cursor.rs b/ctr-std/src/io/cursor.rs
index 1b50233..c844770 100644
--- a/ctr-std/src/io/cursor.rs
+++ b/ctr-std/src/io/cursor.rs
@@ -12,7 +12,7 @@ use io::prelude::*;
use core::convert::TryInto;
use cmp;
-use io::{self, SeekFrom, Error, ErrorKind};
+use io::{self, Initializer, SeekFrom, Error, ErrorKind};
/// A `Cursor` wraps another type and provides it with a
/// [`Seek`] implementation.
@@ -45,10 +45,10 @@ use io::{self, SeekFrom, Error, ErrorKind};
///
/// // a library function we've written
/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
-/// try!(writer.seek(SeekFrom::End(-10)));
+/// writer.seek(SeekFrom::End(-10))?;
///
/// for i in 0..10 {
-/// try!(writer.write(&[i]));
+/// writer.write(&[i])?;
/// }
///
/// // all went well
@@ -60,16 +60,16 @@ use io::{self, SeekFrom, Error, ErrorKind};
/// //
/// // We might want to use a BufReader here for efficiency, but let's
/// // keep this example focused.
-/// let mut file = try!(File::create("foo.txt"));
+/// let mut file = File::create("foo.txt")?;
///
-/// try!(write_ten_bytes_at_end(&mut file));
+/// write_ten_bytes_at_end(&mut file)?;
/// # Ok(())
/// # }
///
/// // now let's write a test
/// #[test]
/// fn test_writes_bytes() {
-/// // setting up a real File is much more slow than an in-memory buffer,
+/// // setting up a real File is much slower than an in-memory buffer,
/// // let's use a cursor instead
/// use std::io::Cursor;
/// let mut buff = Cursor::new(vec![0; 15]);
@@ -89,6 +89,10 @@ pub struct Cursor<T> {
impl<T> Cursor<T> {
/// Creates a new cursor wrapping the provided underlying I/O object.
///
+ /// Cursor initial position is `0` even if underlying object (e.
+ /// g. `Vec`) is not empty. So writing to cursor starts with
+ /// overwriting `Vec` content, not with appending to it.
+ ///
/// # Examples
///
/// ```
@@ -200,18 +204,20 @@ impl<T> Cursor<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> io::Seek for Cursor<T> where T: AsRef<[u8]> {
fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
- let pos = match style {
- SeekFrom::Start(n) => { self.pos = n; return Ok(n) }
- SeekFrom::End(n) => self.inner.as_ref().len() as i64 + n,
- SeekFrom::Current(n) => self.pos as i64 + n,
+ let (base_pos, offset) = match style {
+ SeekFrom::Start(n) => { self.pos = n; return Ok(n); }
+ SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
+ SeekFrom::Current(n) => (self.pos, n),
};
-
- if pos < 0 {
- Err(Error::new(ErrorKind::InvalidInput,
- "invalid seek to a negative position"))
+ let new_pos = if offset >= 0 {
+ base_pos.checked_add(offset as u64)
} else {
- self.pos = pos as u64;
- Ok(self.pos)
+ base_pos.checked_sub((offset.wrapping_neg()) as u64)
+ };
+ match new_pos {
+ Some(n) => {self.pos = n; Ok(self.pos)}
+ None => Err(Error::new(ErrorKind::InvalidInput,
+ "invalid seek to a negative or overflowing position"))
}
}
}
@@ -223,6 +229,18 @@ impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
self.pos += n as u64;
Ok(n)
}
+
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ let n = buf.len();
+ Read::read_exact(&mut self.fill_buf()?, buf)?;
+ self.pos += n as u64;
+ Ok(())
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -234,14 +252,54 @@ impl<T> BufRead for Cursor<T> where T: AsRef<[u8]> {
fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
}
+// Non-resizing write implementation
+fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<usize> {
+ let pos = cmp::min(*pos_mut, slice.len() as u64);
+ let amt = (&mut slice[(pos as usize)..]).write(buf)?;
+ *pos_mut += amt as u64;
+ Ok(amt)
+}
+
+// Resizing write implementation
+fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
+ let pos: usize = (*pos_mut).try_into().map_err(|_| {
+ Error::new(ErrorKind::InvalidInput,
+ "cursor position exceeds maximum possible vector length")
+ })?;
+ // Make sure the internal buffer is as least as big as where we
+ // currently are
+ let len = vec.len();
+ if len < pos {
+ // use `resize` so that the zero filling is as efficient as possible
+ vec.resize(pos, 0);
+ }
+ // Figure out what bytes will be used to overwrite what's currently
+ // there (left), and what will be appended on the end (right)
+ {
+ let space = vec.len() - pos;
+ let (left, right) = buf.split_at(cmp::min(space, buf.len()));
+ vec[pos..pos + left.len()].copy_from_slice(left);
+ vec.extend_from_slice(right);
+ }
+
+ // Bump us forward
+ *pos_mut = (pos + buf.len()) as u64;
+ Ok(buf.len())
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for Cursor<&'a mut [u8]> {
#[inline]
- fn write(&mut self, data: &[u8]) -> io::Result<usize> {
- let pos = cmp::min(self.pos, self.inner.len() as u64);
- let amt = (&mut self.inner[(pos as usize)..]).write(data)?;
- self.pos += amt as u64;
- Ok(amt)
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ slice_write(&mut self.pos, self.inner, buf)
+ }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[unstable(feature = "cursor_mut_vec", issue = "30132")]
+impl<'a> Write for Cursor<&'a mut Vec<u8>> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ vec_write(&mut self.pos, self.inner, buf)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
@@ -249,29 +307,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> {
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Cursor<Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- let pos: usize = self.position().try_into().map_err(|_| {
- Error::new(ErrorKind::InvalidInput,
- "cursor position exceeds maximum possible vector length")
- })?;
- // Make sure the internal buffer is as least as big as where we
- // currently are
- let len = self.inner.len();
- if len < pos {
- // use `resize` so that the zero filling is as efficient as possible
- self.inner.resize(pos, 0);
- }
- // Figure out what bytes will be used to overwrite what's currently
- // there (left), and what will be appended on the end (right)
- {
- let space = self.inner.len() - pos;
- let (left, right) = buf.split_at(cmp::min(space, buf.len()));
- self.inner[pos..pos + left.len()].copy_from_slice(left);
- self.inner.extend_from_slice(right);
- }
-
- // Bump us forward
- self.set_position((pos + buf.len()) as u64);
- Ok(buf.len())
+ vec_write(&mut self.pos, &mut self.inner, buf)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
@@ -280,10 +316,7 @@ impl Write for Cursor<Vec<u8>> {
impl Write for Cursor<Box<[u8]>> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- let pos = cmp::min(self.pos, self.inner.len() as u64);
- let amt = (&mut self.inner[(pos as usize)..]).write(buf)?;
- self.pos += amt as u64;
- Ok(amt)
+ slice_write(&mut self.pos, &mut self.inner, buf)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
@@ -314,6 +347,17 @@ mod tests {
}
#[test]
+ fn test_mem_mut_writer() {
+ let mut vec = Vec::new();
+ let mut writer = Cursor::new(&mut vec);
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+ assert_eq!(&writer.get_ref()[..], b);
+ }
+
+ #[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
@@ -445,7 +489,7 @@ mod tests {
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
- let mut reader = &mut &in_buf[..];
+ let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
let mut buf = [0];
@@ -465,6 +509,24 @@ mod tests {
}
#[test]
+ fn test_read_exact() {
+ let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+ let reader = &mut &in_buf[..];
+ let mut buf = [];
+ assert!(reader.read_exact(&mut buf).is_ok());
+ let mut buf = [8];
+ assert!(reader.read_exact(&mut buf).is_ok());
+ assert_eq!(buf[0], 0);
+ assert_eq!(reader.len(), 7);
+ let mut buf = [0, 0, 0, 0, 0, 0, 0];
+ assert!(reader.read_exact(&mut buf).is_ok());
+ assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]);
+ assert_eq!(reader.len(), 0);
+ let mut buf = [0];
+ assert!(reader.read_exact(&mut buf).is_err());
+ }
+
+ #[test]
fn test_buf_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = Cursor::new(&in_buf[..]);
@@ -527,6 +589,43 @@ mod tests {
}
#[test]
+ fn seek_past_i64() {
+ let buf = [0xff];
+ let mut r = Cursor::new(&buf[..]);
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+ let mut r = Cursor::new(vec![10]);
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+ let mut buf = [0];
+ let mut r = Cursor::new(&mut buf[..]);
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+ let mut r = Cursor::new(vec![10].into_boxed_slice());
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+ }
+
+ #[test]
fn seek_before_0() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
diff --git a/ctr-std/src/io/error.rs b/ctr-std/src/io/error.rs
index 795c89c..f0b41f3 100644
--- a/ctr-std/src/io/error.rs
+++ b/ctr-std/src/io/error.rs
@@ -17,17 +17,21 @@ use convert::From;
/// A specialized [`Result`](../result/enum.Result.html) type for I/O
/// operations.
///
-/// This type is broadly used across `std::io` for any operation which may
+/// 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 `Result`.
+/// This typedef is generally used to avoid writing out [`io::Error`] directly and
+/// 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
+/// 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`][`Result`], and so users of this alias
/// will generally use `io::Result` instead of shadowing the prelude's import
-/// of `std::result::Result`.
+/// of [`std::result::Result`][`Result`].
+///
+/// [`std::io`]: ../io/index.html
+/// [`io::Error`]: ../io/struct.Error.html
+/// [`Result`]: ../result/enum.Result.html
///
/// # Examples
///
@@ -39,7 +43,7 @@ use convert::From;
/// fn get_string() -> io::Result<String> {
/// let mut buffer = String::new();
///
-/// try!(io::stdin().read_line(&mut buffer));
+/// io::stdin().read_line(&mut buffer)?;
///
/// Ok(buffer)
/// }
@@ -47,20 +51,29 @@ use convert::From;
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = result::Result<T, Error>;
-/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
+/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// [`ErrorKind`].
///
+/// [`Read`]: ../io/trait.Read.html
+/// [`Write`]: ../io/trait.Write.html
+/// [`Seek`]: ../io/trait.Seek.html
/// [`ErrorKind`]: enum.ErrorKind.html
-#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Error {
repr: Repr,
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.repr, f)
+ }
+}
+
enum Repr {
Os(i32),
Simple(ErrorKind),
@@ -140,13 +153,13 @@ pub enum ErrorKind {
#[stable(feature = "rust1", since = "1.0.0")]
TimedOut,
/// An error returned when an operation could not be completed because a
- /// call to [`write()`] returned [`Ok(0)`].
+ /// call to [`write`] returned [`Ok(0)`].
///
/// This typically means that an operation could only succeed if it wrote a
/// particular number of bytes but only a smaller number of bytes could be
/// written.
///
- /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
/// [`Ok(0)`]: ../../std/io/type.Result.html
#[stable(feature = "rust1", since = "1.0.0")]
WriteZero,
@@ -208,6 +221,7 @@ impl ErrorKind {
/// the heap (for normal construction via Error::new) is too costly.
#[stable(feature = "io_error_from_errorkind", since = "1.14.0")]
impl From<ErrorKind> for Error {
+ #[inline]
fn from(kind: ErrorKind) -> Error {
Error {
repr: Repr::Simple(kind)
@@ -244,8 +258,8 @@ impl Error {
fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
Error {
repr: Repr::Custom(Box::new(Custom {
- kind: kind,
- error: error,
+ kind,
+ error,
}))
}
}
@@ -388,12 +402,12 @@ impl Error {
/// impl MyError {
/// fn new() -> MyError {
/// MyError {
- /// v: "oh no!".to_owned()
+ /// v: "oh no!".to_string()
/// }
/// }
///
/// fn change_message(&mut self, new_message: &str) {
- /// self.v = new_message.to_owned();
+ /// self.v = new_message.to_string();
/// }
/// }
///
@@ -503,10 +517,12 @@ impl Error {
impl fmt::Debug for Repr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
- Repr::Os(ref code) =>
- fmt.debug_struct("Os").field("code", code)
- .field("message", &sys::os::error_string(*code)).finish(),
- Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
+ Repr::Os(code) =>
+ fmt.debug_struct("Os")
+ .field("code", &code)
+ .field("kind", &sys::decode_error_kind(code))
+ .field("message", &sys::os::error_string(code)).finish(),
+ Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
}
}
@@ -551,17 +567,36 @@ fn _assert_error_is_sync_send() {
#[cfg(test)]
mod test {
- use super::{Error, ErrorKind};
+ use super::{Error, ErrorKind, Repr, Custom};
use error;
use fmt;
use sys::os::error_string;
+ use sys::decode_error_kind;
#[test]
fn test_debug_error() {
let code = 6;
let msg = error_string(code);
- let err = Error { repr: super::Repr::Os(code) };
- let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg);
+ let kind = decode_error_kind(code);
+ let err = Error {
+ repr: Repr::Custom(box Custom {
+ kind: ErrorKind::InvalidInput,
+ error: box Error {
+ repr: super::Repr::Os(code)
+ },
+ })
+ };
+ let expected = format!(
+ "Custom {{ \
+ kind: InvalidInput, \
+ error: Os {{ \
+ code: {:?}, \
+ kind: {:?}, \
+ message: {:?} \
+ }} \
+ }}",
+ code, kind, msg
+ );
assert_eq!(format!("{:?}", err), expected);
}
diff --git a/ctr-std/src/io/impls.rs b/ctr-std/src/io/impls.rs
index 6b26c01..fe1179a 100644
--- a/ctr-std/src/io/impls.rs
+++ b/ctr-std/src/io/impls.rs
@@ -9,7 +9,7 @@
// except according to those terms.
use cmp;
-use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
+use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind};
use fmt;
use mem;
@@ -24,6 +24,11 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R {
}
#[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ (**self).initializer()
+ }
+
+ #[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
@@ -88,6 +93,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
}
#[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ (**self).initializer()
+ }
+
+ #[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
@@ -157,22 +167,53 @@ impl<'a> Read for &'a [u8] {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let amt = cmp::min(buf.len(), self.len());
let (a, b) = self.split_at(amt);
- buf[..amt].copy_from_slice(a);
+
+ // First check if the amount of bytes we want to read is small:
+ // `copy_from_slice` will generally expand to a call to `memcpy`, and
+ // for a single byte the overhead is significant.
+ if amt == 1 {
+ buf[0] = a[0];
+ } else {
+ buf[..amt].copy_from_slice(a);
+ }
+
*self = b;
Ok(amt)
}
#[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+
+ #[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.len() {
return Err(Error::new(ErrorKind::UnexpectedEof,
"failed to fill whole buffer"));
}
let (a, b) = self.split_at(buf.len());
- buf.copy_from_slice(a);
+
+ // First check if the amount of bytes we want to read is small:
+ // `copy_from_slice` will generally expand to a call to `memcpy`, and
+ // for a single byte the overhead is significant.
+ if buf.len() == 1 {
+ buf[0] = a[0];
+ } else {
+ buf.copy_from_slice(a);
+ }
+
*self = b;
Ok(())
}
+
+ #[inline]
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ buf.extend_from_slice(*self);
+ let len = self.len();
+ *self = &self[len..];
+ Ok(len)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/ctr-std/src/io/lazy.rs b/ctr-std/src/io/lazy.rs
index ce205c3..9cef4e3 100644
--- a/ctr-std/src/io/lazy.rs
+++ b/ctr-std/src/io/lazy.rs
@@ -27,7 +27,7 @@ impl<T: Send + Sync + 'static> Lazy<T> {
Lazy {
lock: Mutex::new(),
ptr: Cell::new(ptr::null_mut()),
- init: init
+ init,
}
}
diff --git a/ctr-std/src/io/mod.rs b/ctr-std/src/io/mod.rs
index 58788cd..33d11eb 100644
--- a/ctr-std/src/io/mod.rs
+++ b/ctr-std/src/io/mod.rs
@@ -21,7 +21,8 @@
//! of other types, and you can implement them for your types too. As such,
//! you'll see a few different types of I/O throughout the documentation in
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
-//! example, [`Read`] adds a [`read()`] method, which we can use on `File`s:
+//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
+//! [`File`]s:
//!
//! ```
//! use std::io;
@@ -106,7 +107,7 @@
//! ```
//!
//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
-//! to [`write()`]:
+//! to [`write`][`Write::write`]:
//!
//! ```
//! use std::io;
@@ -145,6 +146,18 @@
//! # }
//! ```
//!
+//! Note that you cannot use the [`?` operator] in functions that do not return
+//! a [`Result<T, E>`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`]
+//! or `match` on the return value to catch any possible errors:
+//!
+//! ```
+//! use std::io;
+//!
+//! let mut input = String::new();
+//!
+//! io::stdin().read_line(&mut input).unwrap();
+//! ```
+//!
//! And a very common source of output is standard output:
//!
//! ```
@@ -157,7 +170,7 @@
//! # }
//! ```
//!
-//! Of course, using [`io::stdout()`] directly is less common than something like
+//! Of course, using [`io::stdout`] directly is less common than something like
//! [`println!`].
//!
//! ## Iterator types
@@ -245,13 +258,15 @@
//! [`Vec<T>`]: ../vec/struct.Vec.html
//! [`BufReader`]: struct.BufReader.html
//! [`BufWriter`]: struct.BufWriter.html
-//! [`write()`]: trait.Write.html#tymethod.write
-//! [`io::stdout()`]: fn.stdout.html
+//! [`Write::write`]: trait.Write.html#tymethod.write
+//! [`io::stdout`]: fn.stdout.html
//! [`println!`]: ../macro.println.html
//! [`Lines`]: struct.Lines.html
//! [`io::Result`]: type.Result.html
-//! [`?` operator]: ../../book/syntax-index.html
-//! [`read()`]: trait.Read.html#tymethod.read
+//! [`?` operator]: ../../book/first-edition/syntax-index.html
+//! [`Read::read`]: trait.Read.html#tymethod.read
+//! [`Result`]: ../result/enum.Result.html
+//! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap
#![stable(feature = "rust1", since = "1.0.0")]
@@ -262,6 +277,7 @@ use fmt;
use result;
use str;
use memchr;
+use ptr;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::buffered::{BufReader, BufWriter, LineWriter};
@@ -274,10 +290,12 @@ pub use self::error::{Result, Error, ErrorKind};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::stdio::{stdin, stdout, stderr, _print, Stdin, Stdout, Stderr};
+pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::stdio::{StdoutLock, StderrLock, StdinLock};
-#[unstable(feature = "libstd_io_internals", issue = "0")]
+#[unstable(feature = "print_internals", issue = "0")]
+pub use self::stdio::{_print, _eprint};
+#[unstable(feature = "libstd_io_internals", issue = "42788")]
#[doc(no_inline, hidden)]
pub use self::stdio::{set_panic, set_print};
@@ -292,6 +310,14 @@ mod stdio;
const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
+struct Guard<'a> { buf: &'a mut Vec<u8>, len: usize }
+
+impl<'a> Drop for Guard<'a> {
+ fn drop(&mut self) {
+ unsafe { self.buf.set_len(self.len); }
+ }
+}
+
// A few methods below (read_to_string, read_line) will append data into a
// `String` buffer, but we need to be pretty careful when doing this. The
// implementation will just call `.as_mut_vec()` and then delegate to a
@@ -313,23 +339,16 @@ const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
where F: FnOnce(&mut Vec<u8>) -> Result<usize>
{
- struct Guard<'a> { s: &'a mut Vec<u8>, len: usize }
- impl<'a> Drop for Guard<'a> {
- fn drop(&mut self) {
- unsafe { self.s.set_len(self.len); }
- }
- }
-
unsafe {
- let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() };
- let ret = f(g.s);
- if str::from_utf8(&g.s[g.len..]).is_err() {
+ let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() };
+ let ret = f(g.buf);
+ if str::from_utf8(&g.buf[g.len..]).is_err() {
ret.and_then(|_| {
Err(Error::new(ErrorKind::InvalidData,
"stream did not contain valid UTF-8"))
})
} else {
- g.len = g.s.len();
+ g.len = g.buf.len();
ret
}
}
@@ -341,25 +360,29 @@ fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
// time is 4,500 times (!) slower than this if the reader has a very small
// amount of data to return.
+//
+// Because we're extending the buffer with uninitialized data for trusted
+// readers, we need to make sure to truncate that if any of this panics.
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
let start_len = buf.len();
- let mut len = start_len;
- let mut new_write_size = 16;
+ let mut g = Guard { len: buf.len(), buf: buf };
let ret;
loop {
- if len == buf.len() {
- if new_write_size < DEFAULT_BUF_SIZE {
- new_write_size *= 2;
+ if g.len == g.buf.len() {
+ unsafe {
+ g.buf.reserve(32);
+ let capacity = g.buf.capacity();
+ g.buf.set_len(capacity);
+ r.initializer().initialize(&mut g.buf[g.len..]);
}
- buf.resize(len + new_write_size, 0);
}
- match r.read(&mut buf[len..]) {
+ match r.read(&mut g.buf[g.len..]) {
Ok(0) => {
- ret = Ok(len - start_len);
+ ret = Ok(g.len - start_len);
break;
}
- Ok(n) => len += n,
+ Ok(n) => g.len += n,
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => {
ret = Err(e);
@@ -368,39 +391,33 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
}
}
- buf.truncate(len);
ret
}
/// The `Read` trait allows for reading bytes from a source.
///
-/// Implementors of the `Read` trait are sometimes called 'readers'.
+/// Implementors of the `Read` trait are called 'readers'.
///
-/// Readers are defined by one required method, `read()`. Each call to `read`
+/// Readers are defined by one required method, [`read()`]. Each call to [`read()`]
/// will attempt to pull bytes from this source into a provided buffer. A
-/// number of other methods are implemented in terms of `read()`, giving
+/// number of other methods are implemented in terms of [`read()`], giving
/// implementors a number of ways to read bytes while only needing to implement
/// a single method.
///
/// Readers are intended to be composable with one another. Many implementors
-/// throughout `std::io` take and provide types which implement the `Read`
+/// throughout [`std::io`] take and provide types which implement the `Read`
/// trait.
///
-/// Please note that each call to `read` may involve a system call, and
-/// therefore, using something that implements [`BufRead`][bufread], such as
-/// [`BufReader`][bufreader], will be more efficient.
-///
-/// [bufread]: trait.BufRead.html
-/// [bufreader]: struct.BufReader.html
+/// Please note that each call to [`read()`] may involve a system call, and
+/// therefore, using something that implements [`BufRead`], such as
+/// [`BufReader`], will be more efficient.
///
/// # Examples
///
-/// [`File`][file]s implement `Read`:
-///
-/// [file]: ../fs/struct.File.html
+/// [`File`]s implement `Read`:
///
/// ```
-/// use std::io;
+/// # use std::io;
/// use std::io::prelude::*;
/// use std::fs::File;
///
@@ -423,16 +440,43 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
/// # Ok(())
/// # }
/// ```
+///
+/// Read from [`&str`] because [`&[u8]`][slice] implements `Read`:
+///
+/// ```
+/// # use std::io;
+/// use std::io::prelude::*;
+///
+/// # fn foo() -> io::Result<()> {
+/// let mut b = "This string will be read".as_bytes();
+/// let mut buffer = [0; 10];
+///
+/// // read up to 10 bytes
+/// b.read(&mut buffer)?;
+///
+/// // etc... it works exactly as a File does!
+/// # Ok(())
+/// # }
+/// ```
+///
+/// [`read()`]: trait.Read.html#tymethod.read
+/// [`std::io`]: ../../std/io/index.html
+/// [`File`]: ../fs/struct.File.html
+/// [`BufRead`]: trait.BufRead.html
+/// [`BufReader`]: struct.BufReader.html
+/// [`&str`]: ../../std/primitive.str.html
+/// [slice]: ../../std/primitive.slice.html
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(spotlight)]
pub trait Read {
/// Pull some bytes from this source into the specified buffer, returning
/// how many bytes were read.
///
/// This function does not provide any guarantees about whether it blocks
/// waiting for data, but if an object needs to block for a read but cannot
- /// it will typically signal this via an `Err` return value.
+ /// it will typically signal this via an [`Err`] return value.
///
- /// If the return value of this method is `Ok(n)`, then it must be
+ /// If the return value of this method is [`Ok(n)`], then it must be
/// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates
/// that the buffer `buf` has been filled in with `n` bytes of data from this
/// source. If `n` is `0`, then it can indicate one of two scenarios:
@@ -453,11 +497,17 @@ pub trait Read {
/// variant will be returned. If an error is returned then it must be
/// guaranteed that no bytes were read.
///
+ /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read
+ /// operation should be retried if there is nothing else to do.
+ ///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`File`]: ../fs/struct.File.html
///
/// ```
/// use std::io;
@@ -468,7 +518,7 @@ pub trait Read {
/// let mut f = File::open("foo.txt")?;
/// let mut buffer = [0; 10];
///
- /// // read 10 bytes
+ /// // read up to 10 bytes
/// f.read(&mut buffer[..])?;
/// # Ok(())
/// # }
@@ -476,19 +526,47 @@ pub trait Read {
#[stable(feature = "rust1", since = "1.0.0")]
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
+ /// Determines if this `Read`er can work with buffers of uninitialized
+ /// memory.
+ ///
+ /// The default implementation returns an initializer which will zero
+ /// buffers.
+ ///
+ /// If a `Read`er guarantees that it can work properly with uninitialized
+ /// memory, it should call [`Initializer::nop()`]. See the documentation for
+ /// [`Initializer`] for details.
+ ///
+ /// The behavior of this method must be independent of the state of the
+ /// `Read`er - the method only takes `&self` so that it can be used through
+ /// trait objects.
+ ///
+ /// # Safety
+ ///
+ /// This method is unsafe because a `Read`er could otherwise return a
+ /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
+ /// block.
+ ///
+ /// [`Initializer::nop()`]: ../../std/io/struct.Initializer.html#method.nop
+ /// [`Initializer`]: ../../std/io/struct.Initializer.html
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::zeroing()
+ }
+
/// Read all bytes until EOF in this source, placing them into `buf`.
///
/// All bytes read from this source will be appended to the specified buffer
- /// `buf`. This function will continuously call `read` to append more data to
- /// `buf` until `read` returns either `Ok(0)` or an error of
- /// non-`ErrorKind::Interrupted` kind.
+ /// `buf`. This function will continuously call [`read()`] to append more data to
+ /// `buf` until [`read()`] returns either [`Ok(0)`] or an error of
+ /// non-[`ErrorKind::Interrupted`] kind.
///
/// If successful, this function will return the total number of bytes read.
///
/// # Errors
///
/// If this function encounters an error of the kind
- /// `ErrorKind::Interrupted` then the error is ignored and the operation
+ /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
/// will continue.
///
/// If any other read error is encountered then this function immediately
@@ -497,9 +575,12 @@ pub trait Read {
///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`read()`]: trait.Read.html#tymethod.read
+ /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`File`]: ../fs/struct.File.html
///
/// ```
/// use std::io;
@@ -520,7 +601,7 @@ pub trait Read {
read_to_end(self, buf)
}
- /// Read all bytes until EOF in this source, placing them into `buf`.
+ /// Read all bytes until EOF in this source, appending them to `buf`.
///
/// If successful, this function returns the number of bytes which were read
/// and appended to `buf`.
@@ -530,7 +611,7 @@ pub trait Read {
/// If the data in this stream is *not* valid UTF-8 then an error is
/// returned and `buf` is unchanged.
///
- /// See [`read_to_end()`][readtoend] for other error semantics.
+ /// See [`read_to_end`][readtoend] for other error semantics.
///
/// [readtoend]: #method.read_to_end
///
@@ -580,11 +661,11 @@ pub trait Read {
/// # Errors
///
/// If this function encounters an error of the kind
- /// `ErrorKind::Interrupted` then the error is ignored and the operation
+ /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
/// will continue.
///
/// If this function encounters an "end of file" before completely filling
- /// the buffer, it returns an error of the kind `ErrorKind::UnexpectedEof`.
+ /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
/// The contents of `buf` are unspecified in this case.
///
/// If any other read error is encountered then this function immediately
@@ -596,9 +677,11 @@ pub trait Read {
///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`File`]: ../fs/struct.File.html
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`ErrorKind::UnexpectedEof`]: ../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
///
/// ```
/// use std::io;
@@ -669,18 +752,25 @@ pub trait Read {
#[stable(feature = "rust1", since = "1.0.0")]
fn by_ref(&mut self) -> &mut Self where Self: Sized { self }
- /// Transforms this `Read` instance to an `Iterator` over its bytes.
+ /// Transforms this `Read` instance to an [`Iterator`] over its bytes.
///
- /// The returned type implements `Iterator` where the `Item` is `Result<u8,
- /// R::Err>`. The yielded item is `Ok` if a byte was successfully read and
- /// `Err` otherwise for I/O errors. EOF is mapped to returning `None` from
- /// this iterator.
+ /// The returned type implements [`Iterator`] where the `Item` is
+ /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`.
+ /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`]
+ /// otherwise. EOF is mapped to returning [`None`] from this iterator.
///
/// # Examples
///
/// [`File`][file]s implement `Read`:
///
/// [file]: ../fs/struct.File.html
+ /// [`Iterator`]: ../../std/iter/trait.Iterator.html
+ /// [`Result`]: ../../std/result/enum.Result.html
+ /// [`io::Error`]: ../../std/io/struct.Error.html
+ /// [`u8`]: ../../std/primitive.u8.html
+ /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// ```
/// use std::io;
@@ -701,12 +791,12 @@ pub trait Read {
Bytes { inner: self }
}
- /// Transforms this `Read` instance to an `Iterator` over `char`s.
+ /// Transforms this `Read` instance to an [`Iterator`] over [`char`]s.
///
/// This adaptor will attempt to interpret this reader as a UTF-8 encoded
- /// sequence of characters. The returned iterator will return `None` once
+ /// sequence of characters. The returned iterator will return [`None`] once
/// EOF is reached for this reader. Otherwise each element yielded will be a
- /// `Result<char, E>` where `E` may contain information about what I/O error
+ /// [`Result`]`<`[`char`]`, E>` where `E` may contain information about what I/O error
/// occurred or where decoding failed.
///
/// Currently this adaptor will discard intermediate data read, and should
@@ -714,9 +804,13 @@ pub trait Read {
///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`File`]: ../fs/struct.File.html
+ /// [`Iterator`]: ../../std/iter/trait.Iterator.html
+ /// [`Result`]: ../../std/result/enum.Result.html
+ /// [`char`]: ../../std/primitive.char.html
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// ```
/// #![feature(io)]
@@ -779,15 +873,17 @@ pub trait Read {
/// Creates an adaptor which will read at most `limit` bytes from it.
///
/// This function returns a new instance of `Read` which will read at most
- /// `limit` bytes, after which it will always return EOF (`Ok(0)`). Any
+ /// `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any
/// read errors will not count towards the number of bytes read and future
- /// calls to `read` may succeed.
+ /// calls to [`read()`] may succeed.
///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`File`]: ../fs/struct.File.html
+ /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`read()`]: trait.Read.html#tymethod.read
///
/// ```
/// use std::io;
@@ -811,16 +907,60 @@ pub trait Read {
}
}
+/// A type used to conditionally initialize buffers passed to `Read` methods.
+#[unstable(feature = "read_initializer", issue = "42788")]
+#[derive(Debug)]
+pub struct Initializer(bool);
+
+impl Initializer {
+ /// Returns a new `Initializer` which will zero out buffers.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub fn zeroing() -> Initializer {
+ Initializer(true)
+ }
+
+ /// Returns a new `Initializer` which will not zero out buffers.
+ ///
+ /// # Safety
+ ///
+ /// This may only be called by `Read`ers which guarantee that they will not
+ /// read from buffers passed to `Read` methods, and that the return value of
+ /// the method accurately reflects the number of bytes that have been
+ /// written to the head of the buffer.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub unsafe fn nop() -> Initializer {
+ Initializer(false)
+ }
+
+ /// Indicates if a buffer should be initialized.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub fn should_initialize(&self) -> bool {
+ self.0
+ }
+
+ /// Initializes a buffer if necessary.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub fn initialize(&self, buf: &mut [u8]) {
+ if self.should_initialize() {
+ unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
+ }
+ }
+}
+
/// A trait for objects which are byte-oriented sinks.
///
/// Implementors of the `Write` trait are sometimes called 'writers'.
///
-/// Writers are defined by two required methods, [`write()`] and [`flush()`]:
+/// Writers are defined by two required methods, [`write`] and [`flush`]:
///
-/// * The [`write()`] method will attempt to write some data into the object,
+/// * The [`write`] method will attempt to write some data into the object,
/// returning how many bytes were successfully written.
///
-/// * The [`flush()`] method is useful for adaptors and explicit buffers
+/// * The [`flush`] method is useful for adaptors and explicit buffers
/// themselves for ensuring that all buffered data has been pushed out to the
/// 'true sink'.
///
@@ -828,8 +968,8 @@ pub trait Read {
/// throughout [`std::io`] take and provide types which implement the `Write`
/// trait.
///
-/// [`write()`]: #tymethod.write
-/// [`flush()`]: #tymethod.flush
+/// [`write`]: #tymethod.write
+/// [`flush`]: #tymethod.flush
/// [`std::io`]: index.html
///
/// # Examples
@@ -846,6 +986,7 @@ pub trait Read {
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(spotlight)]
pub trait Write {
/// Write a buffer into this object, returning how many bytes were written.
///
@@ -856,9 +997,9 @@ pub trait Write {
///
/// Calls to `write` are not guaranteed to block waiting for data to be
/// written, and a write which would otherwise block can be indicated through
- /// an `Err` variant.
+ /// an [`Err`] variant.
///
- /// If the return value is `Ok(n)` then it must be guaranteed that
+ /// If the return value is [`Ok(n)`] then it must be guaranteed that
/// `0 <= n <= buf.len()`. A return value of `0` typically means that the
/// underlying object is no longer able to accept bytes and will likely not
/// be able to in the future as well, or that the buffer provided is empty.
@@ -872,6 +1013,13 @@ pub trait Write {
/// It is **not** considered an error if the entire buffer could not be
/// written to this writer.
///
+ /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the
+ /// write operation should be retried if there is nothing else to do.
+ ///
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ ///
/// # Examples
///
/// ```
@@ -881,6 +1029,7 @@ pub trait Write {
/// # fn foo() -> std::io::Result<()> {
/// let mut buffer = File::create("foo.txt")?;
///
+ /// // Writes some prefix of the byte string, not necessarily all of it.
/// buffer.write(b"some bytes")?;
/// # Ok(())
/// # }
@@ -916,14 +1065,20 @@ pub trait Write {
/// Attempts to write an entire buffer into this write.
///
- /// This method will continuously call `write` while there is more data to
- /// write. This method will not return until the entire buffer has been
- /// successfully written or an error occurs. The first error generated from
- /// this method will be returned.
+ /// This method will continuously call [`write`] until there is no more data
+ /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+ /// returned. This method will not return until the entire buffer has been
+ /// successfully written or such an error occurs. The first error that is
+ /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+ /// returned.
///
/// # Errors
///
- /// This function will return the first error that `write` returns.
+ /// This function will return the first error of
+ /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns.
+ ///
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`write`]: #tymethod.write
///
/// # Examples
///
@@ -1159,7 +1314,7 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
///
/// For example, reading line-by-line is inefficient without using a buffer, so
/// if you want to read by line, you'll need `BufRead`, which includes a
-/// [`read_line()`] method as well as a [`lines()`] iterator.
+/// [`read_line`] method as well as a [`lines`] iterator.
///
/// # Examples
///
@@ -1183,8 +1338,8 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
///
/// [`BufReader`]: struct.BufReader.html
/// [`File`]: ../fs/struct.File.html
-/// [`read_line()`]: #method.read_line
-/// [`lines()`]: #method.lines
+/// [`read_line`]: #method.read_line
+/// [`lines`]: #method.lines
/// [`Read`]: trait.Read.html
///
/// ```
@@ -1209,13 +1364,13 @@ pub trait BufRead: Read {
/// Fills the internal buffer of this object, returning the buffer contents.
///
/// This function is a lower-level call. It needs to be paired with the
- /// [`consume()`] method to function properly. When calling this
+ /// [`consume`] method to function properly. When calling this
/// method, none of the contents will be "read" in the sense that later
- /// calling `read` may return the same contents. As such, [`consume()`] must
+ /// calling `read` may return the same contents. As such, [`consume`] must
/// be called with the number of bytes that are consumed from this buffer to
/// ensure that the bytes are never returned twice.
///
- /// [`consume()`]: #tymethod.consume
+ /// [`consume`]: #tymethod.consume
///
/// An empty buffer returned indicates that the stream has reached EOF.
///
@@ -1256,21 +1411,21 @@ pub trait BufRead: Read {
/// so they should no longer be returned in calls to `read`.
///
/// This function is a lower-level call. It needs to be paired with the
- /// [`fill_buf()`] method to function properly. This function does
+ /// [`fill_buf`] method to function properly. This function does
/// not perform any I/O, it simply informs this object that some amount of
- /// its buffer, returned from [`fill_buf()`], has been consumed and should
+ /// its buffer, returned from [`fill_buf`], has been consumed and should
/// no longer be returned. As such, this function may do odd things if
- /// [`fill_buf()`] isn't called before calling it.
+ /// [`fill_buf`] isn't called before calling it.
///
/// The `amt` must be `<=` the number of bytes in the buffer returned by
- /// [`fill_buf()`].
+ /// [`fill_buf`].
///
/// # Examples
///
- /// Since `consume()` is meant to be used with [`fill_buf()`],
+ /// Since `consume()` is meant to be used with [`fill_buf`],
/// that method's example includes an example of `consume()`.
///
- /// [`fill_buf()`]: #tymethod.fill_buf
+ /// [`fill_buf`]: #tymethod.fill_buf
#[stable(feature = "rust1", since = "1.0.0")]
fn consume(&mut self, amt: usize);
@@ -1282,36 +1437,52 @@ pub trait BufRead: Read {
///
/// If successful, this function will return the total number of bytes read.
///
+ /// An empty buffer returned indicates that the stream has reached EOF.
+ ///
/// # Errors
///
/// This function will ignore all instances of [`ErrorKind::Interrupted`] and
- /// will otherwise return any errors returned by [`fill_buf()`].
+ /// will otherwise return any errors returned by [`fill_buf`].
///
/// If an I/O error is encountered then all bytes read so far will be
/// present in `buf` and its length will have been adjusted appropriately.
///
- /// # Examples
- ///
- /// A locked standard input implements `BufRead`. In this example, we'll
- /// read from standard input until we see an `a` byte.
- ///
- /// [`fill_buf()`]: #tymethod.fill_buf
+ /// [`fill_buf`]: #tymethod.fill_buf
/// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted
///
- /// ```
- /// use std::io;
- /// use std::io::prelude::*;
+ /// # Examples
///
- /// fn foo() -> io::Result<()> {
- /// let stdin = io::stdin();
- /// let mut stdin = stdin.lock();
- /// let mut buffer = Vec::new();
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to read all the bytes in a byte slice
+ /// in hyphen delimited segments:
///
- /// stdin.read_until(b'a', &mut buffer)?;
+ /// [`Cursor`]: struct.Cursor.html
///
- /// println!("{:?}", buffer);
- /// # Ok(())
- /// # }
+ /// ```
+ /// use std::io::{self, BufRead};
+ ///
+ /// let mut cursor = io::Cursor::new(b"lorem-ipsum");
+ /// let mut buf = vec![];
+ ///
+ /// // cursor is at 'l'
+ /// let num_bytes = cursor.read_until(b'-', &mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 6);
+ /// assert_eq!(buf, b"lorem-");
+ /// buf.clear();
+ ///
+ /// // cursor is at 'i'
+ /// let num_bytes = cursor.read_until(b'-', &mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 5);
+ /// assert_eq!(buf, b"ipsum");
+ /// buf.clear();
+ ///
+ /// // cursor is at EOF
+ /// let num_bytes = cursor.read_until(b'-', &mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 0);
+ /// assert_eq!(buf, b"");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
@@ -1328,37 +1499,47 @@ pub trait BufRead: Read {
///
/// If successful, this function will return the total number of bytes read.
///
+ /// An empty buffer returned indicates that the stream has reached EOF.
+ ///
/// # Errors
///
- /// This function has the same error semantics as [`read_until()`] and will
+ /// This function has the same error semantics as [`read_until`] and will
/// also return an error if the read bytes are not valid UTF-8. If an I/O
/// error is encountered then `buf` may contain some bytes already read in
/// the event that all data read so far was valid UTF-8.
///
/// # Examples
///
- /// A locked standard input implements `BufRead`. In this example, we'll
- /// read all of the lines from standard input. If we were to do this in
- /// an actual project, the [`lines()`] method would be easier, of
- /// course.
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to read all the lines in a byte slice:
///
- /// [`lines()`]: #method.lines
- /// [`read_until()`]: #method.read_until
+ /// [`Cursor`]: struct.Cursor.html
///
/// ```
- /// use std::io;
- /// use std::io::prelude::*;
- ///
- /// let stdin = io::stdin();
- /// let mut stdin = stdin.lock();
- /// let mut buffer = String::new();
- ///
- /// while stdin.read_line(&mut buffer).unwrap() > 0 {
- /// // work with buffer
- /// println!("{:?}", buffer);
- ///
- /// buffer.clear();
- /// }
+ /// use std::io::{self, BufRead};
+ ///
+ /// let mut cursor = io::Cursor::new(b"foo\nbar");
+ /// let mut buf = String::new();
+ ///
+ /// // cursor is at 'f'
+ /// let num_bytes = cursor.read_line(&mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 4);
+ /// assert_eq!(buf, "foo\n");
+ /// buf.clear();
+ ///
+ /// // cursor is at 'b'
+ /// let num_bytes = cursor.read_line(&mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 3);
+ /// assert_eq!(buf, "bar");
+ /// buf.clear();
+ ///
+ /// // cursor is at EOF
+ /// let num_bytes = cursor.read_line(&mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 0);
+ /// assert_eq!(buf, "");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn read_line(&mut self, buf: &mut String) -> Result<usize> {
@@ -1375,27 +1556,31 @@ pub trait BufRead: Read {
/// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
/// the delimiter byte at the end.
///
- /// This function will yield errors whenever [`read_until()`] would have
+ /// This function will yield errors whenever [`read_until`] would have
/// also yielded an error.
///
+ /// [`io::Result`]: type.Result.html
+ /// [`Vec<u8>`]: ../vec/struct.Vec.html
+ /// [`read_until`]: #method.read_until
+ ///
/// # Examples
///
- /// A locked standard input implements `BufRead`. In this example, we'll
- /// read some input from standard input, splitting on commas.
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to iterate over all hyphen delimited
+ /// segments in a byte slice
///
- /// [`io::Result`]: type.Result.html
- /// [`Vec<u8>`]: ../vec/struct.Vec.html
- /// [`read_until()`]: #method.read_until
+ /// [`Cursor`]: struct.Cursor.html
///
/// ```
- /// use std::io;
- /// use std::io::prelude::*;
+ /// use std::io::{self, BufRead};
///
- /// let stdin = io::stdin();
+ /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor");
///
- /// for content in stdin.lock().split(b',') {
- /// println!("{:?}", content.unwrap());
- /// }
+ /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap());
+ /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec()));
+ /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec()));
+ /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec()));
+ /// assert_eq!(split_iter.next(), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn split(self, byte: u8) -> Split<Self> where Self: Sized {
@@ -1413,24 +1598,29 @@ pub trait BufRead: Read {
///
/// # Examples
///
- /// A locked standard input implements `BufRead`:
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to iterate over all the lines in a byte
+ /// slice.
+ ///
+ /// [`Cursor`]: struct.Cursor.html
///
/// ```
- /// use std::io;
- /// use std::io::prelude::*;
+ /// use std::io::{self, BufRead};
///
- /// let stdin = io::stdin();
+ /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor");
///
- /// for line in stdin.lock().lines() {
- /// println!("{}", line.unwrap());
- /// }
+ /// let mut lines_iter = cursor.lines().map(|l| l.unwrap());
+ /// assert_eq!(lines_iter.next(), Some(String::from("lorem")));
+ /// assert_eq!(lines_iter.next(), Some(String::from("ipsum")));
+ /// assert_eq!(lines_iter.next(), Some(String::from("dolor")));
+ /// assert_eq!(lines_iter.next(), None);
/// ```
///
/// # Errors
///
- /// Each line of the iterator has the same error semantics as [`BufRead::read_line()`].
+ /// Each line of the iterator has the same error semantics as [`BufRead::read_line`].
///
- /// [`BufRead::read_line()`]: trait.BufRead.html#method.read_line
+ /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line
#[stable(feature = "rust1", since = "1.0.0")]
fn lines(self) -> Lines<Self> where Self: Sized {
Lines { buf: self }
@@ -1439,10 +1629,10 @@ pub trait BufRead: Read {
/// Adaptor to chain together two readers.
///
-/// This struct is generally created by calling [`chain()`] on a reader.
-/// Please see the documentation of [`chain()`] for more details.
+/// This struct is generally created by calling [`chain`] on a reader.
+/// Please see the documentation of [`chain`] for more details.
///
-/// [`chain()`]: trait.Read.html#method.chain
+/// [`chain`]: trait.Read.html#method.chain
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chain<T, U> {
first: T,
@@ -1450,6 +1640,81 @@ pub struct Chain<T, U> {
done_first: bool,
}
+impl<T, U> Chain<T, U> {
+ /// Consumes the `Chain`, returning the wrapped readers.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut foo_file = File::open("foo.txt")?;
+ /// let mut bar_file = File::open("bar.txt")?;
+ ///
+ /// let chain = foo_file.chain(bar_file);
+ /// let (foo_file, bar_file) = chain.into_inner();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn into_inner(self) -> (T, U) {
+ (self.first, self.second)
+ }
+
+ /// Gets references to the underlying readers in this `Chain`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut foo_file = File::open("foo.txt")?;
+ /// let mut bar_file = File::open("bar.txt")?;
+ ///
+ /// let chain = foo_file.chain(bar_file);
+ /// let (foo_file, bar_file) = chain.get_ref();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_ref(&self) -> (&T, &U) {
+ (&self.first, &self.second)
+ }
+
+ /// Gets mutable references to the underlying readers in this `Chain`.
+ ///
+ /// Care should be taken to avoid modifying the internal I/O state of the
+ /// underlying readers as doing so may corrupt the internal state of this
+ /// `Chain`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut foo_file = File::open("foo.txt")?;
+ /// let mut bar_file = File::open("bar.txt")?;
+ ///
+ /// let mut chain = foo_file.chain(bar_file);
+ /// let (foo_file, bar_file) = chain.get_mut();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_mut(&mut self) -> (&mut T, &mut U) {
+ (&mut self.first, &mut self.second)
+ }
+}
+
#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -1471,6 +1736,15 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
}
self.second.read(buf)
}
+
+ unsafe fn initializer(&self) -> Initializer {
+ let initializer = self.first.initializer();
+ if initializer.should_initialize() {
+ initializer
+ } else {
+ self.second.initializer()
+ }
+ }
}
#[stable(feature = "chain_bufread", since = "1.9.0")]
@@ -1496,10 +1770,10 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
/// Reader adaptor which limits the bytes read from an underlying reader.
///
-/// This struct is generally created by calling [`take()`] on a reader.
-/// Please see the documentation of [`take()`] for more details.
+/// This struct is generally created by calling [`take`] on a reader.
+/// Please see the documentation of [`take`] for more details.
///
-/// [`take()`]: trait.Read.html#method.take
+/// [`take`]: trait.Read.html#method.take
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Take<T> {
@@ -1538,6 +1812,35 @@ impl<T> Take<T> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn limit(&self) -> u64 { self.limit }
+ /// Sets the number of bytes that can be read before this instance will
+ /// return EOF. This is the same as constructing a new `Take` instance, so
+ /// the amount of bytes read and the previous limit value don't matter when
+ /// calling this method.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(take_set_limit)]
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let f = File::open("foo.txt")?;
+ ///
+ /// // read at most five bytes
+ /// let mut handle = f.take(5);
+ /// handle.set_limit(10);
+ ///
+ /// assert_eq!(handle.limit(), 10);
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[unstable(feature = "take_set_limit", issue = "42781")]
+ pub fn set_limit(&mut self, limit: u64) {
+ self.limit = limit;
+ }
+
/// Consumes the `Take`, returning the wrapped reader.
///
/// # Examples
@@ -1562,6 +1865,60 @@ impl<T> Take<T> {
pub fn into_inner(self) -> T {
self.inner
}
+
+ /// Gets a reference to the underlying reader.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ ///
+ /// let mut buffer = [0; 5];
+ /// let mut handle = file.take(5);
+ /// handle.read(&mut buffer)?;
+ ///
+ /// let file = handle.get_ref();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_ref(&self) -> &T {
+ &self.inner
+ }
+
+ /// Gets a mutable reference to the underlying reader.
+ ///
+ /// Care should be taken to avoid modifying the internal I/O state of the
+ /// underlying reader as doing so may corrupt the internal limit of this
+ /// `Take`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ ///
+ /// let mut buffer = [0; 5];
+ /// let mut handle = file.take(5);
+ /// handle.read(&mut buffer)?;
+ ///
+ /// let file = handle.get_mut();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_mut(&mut self) -> &mut T {
+ &mut self.inner
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1577,6 +1934,10 @@ impl<T: Read> Read for Take<T> {
self.limit -= n as u64;
Ok(n)
}
+
+ unsafe fn initializer(&self) -> Initializer {
+ self.inner.initializer()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1614,10 +1975,10 @@ fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> {
/// An iterator over `u8` values of a reader.
///
-/// This struct is generally created by calling [`bytes()`] on a reader.
-/// Please see the documentation of [`bytes()`] for more details.
+/// This struct is generally created by calling [`bytes`] on a reader.
+/// Please see the documentation of [`bytes`] for more details.
///
-/// [`bytes()`]: trait.Read.html#method.bytes
+/// [`bytes`]: trait.Read.html#method.bytes
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Bytes<R> {
@@ -1635,7 +1996,7 @@ impl<R: Read> Iterator for Bytes<R> {
/// An iterator over the `char`s of a reader.
///
-/// This struct is generally created by calling [`chars()`][chars] on a reader.
+/// This struct is generally created by calling [`chars`][chars] on a reader.
/// Please see the documentation of `chars()` for more details.
///
/// [chars]: trait.Read.html#method.chars
@@ -1666,10 +2027,9 @@ impl<R: Read> Iterator for Chars<R> {
type Item = result::Result<char, CharsError>;
fn next(&mut self) -> Option<result::Result<char, CharsError>> {
- let first_byte = match read_one_byte(&mut self.inner) {
- None => return None,
- Some(Ok(b)) => b,
- Some(Err(e)) => return Some(Err(CharsError::Other(e))),
+ let first_byte = match read_one_byte(&mut self.inner)? {
+ Ok(b) => b,
+ Err(e) => return Some(Err(CharsError::Other(e))),
};
let width = core_str::utf8_char_width(first_byte);
if width == 1 { return Some(Ok(first_byte as char)) }
@@ -1726,7 +2086,7 @@ impl fmt::Display for CharsError {
/// An iterator over the contents of an instance of `BufRead` split on a
/// particular byte.
///
-/// This struct is generally created by calling [`split()`][split] on a
+/// This struct is generally created by calling [`split`][split] on a
/// `BufRead`. Please see the documentation of `split()` for more details.
///
/// [split]: trait.BufRead.html#method.split
@@ -1758,7 +2118,7 @@ impl<B: BufRead> Iterator for Split<B> {
/// An iterator over the lines of an instance of `BufRead`.
///
-/// This struct is generally created by calling [`lines()`][lines] on a
+/// This struct is generally created by calling [`lines`][lines] on a
/// `BufRead`. Please see the documentation of `lines()` for more details.
///
/// [lines]: trait.BufRead.html#method.lines
diff --git a/ctr-std/src/io/stdio.rs b/ctr-std/src/io/stdio.rs
index e16e801..831688b 100644
--- a/ctr-std/src/io/stdio.rs
+++ b/ctr-std/src/io/stdio.rs
@@ -13,11 +13,11 @@ use io::prelude::*;
use cell::RefCell;
use fmt;
use io::lazy::Lazy;
-use io::{self, BufReader, LineWriter};
+use io::{self, Initializer, BufReader, LineWriter};
use sync::{Arc, Mutex, MutexGuard};
use sys::stdio;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
-use thread::LocalKeyState;
+use thread::{LocalKey, LocalKeyState};
/// Stdout used by print! and println! macros
thread_local! {
@@ -75,8 +75,10 @@ fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
impl Read for StdinRaw {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.0.read_to_end(buf)
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
}
}
impl Write for StdoutRaw {
@@ -116,19 +118,11 @@ impl<R: io::Read> io::Read for Maybe<R> {
Maybe::Fake => Ok(0)
}
}
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- match *self {
- Maybe::Real(ref mut r) => handle_ebadf(r.read_to_end(buf), 0),
- Maybe::Fake => Ok(0)
- }
- }
}
fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
- use sys::stdio::EBADF_ERR;
-
match r {
- Err(ref e) if e.raw_os_error() == Some(EBADF_ERR) => Ok(default),
+ Err(ref e) if stdio::is_ebadf(e) => Ok(default),
r => r
}
}
@@ -294,6 +288,10 @@ impl Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.lock().read(buf)
}
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.lock().read_to_end(buf)
}
@@ -310,8 +308,9 @@ impl<'a> Read for StdinLock<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.inner.read_to_end(buf)
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
}
}
@@ -332,11 +331,11 @@ impl<'a> fmt::Debug for StdinLock<'a> {
///
/// Each handle shares a global buffer of data to be written to the standard
/// output stream. Access is also synchronized via a lock and explicit control
-/// over locking is available via the [`lock()`] method.
+/// over locking is available via the [`lock`] method.
///
/// Created by the [`io::stdout`] method.
///
-/// [`lock()`]: #method.lock
+/// [`lock`]: #method.lock
/// [`io::stdout`]: fn.stdout.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stdout {
@@ -659,41 +658,56 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
})
}
-#[unstable(feature = "print",
- reason = "implementation detail which may disappear or be replaced at any time",
- issue = "0")]
-#[doc(hidden)]
-pub fn _print(args: fmt::Arguments) {
- // As an implementation of the `println!` macro, we want to try our best to
- // not panic wherever possible and get the output somewhere. There are
- // currently two possible vectors for panics we take care of here:
- //
- // 1. If the TLS key for the local stdout has been destroyed, accessing it
- // would cause a panic. Note that we just lump in the uninitialized case
- // here for convenience, we're not trying to avoid a panic.
- // 2. If the local stdout is currently in use (e.g. we're in the middle of
- // already printing) then accessing again would cause a panic.
- //
- // If, however, the actual I/O causes an error, we do indeed panic.
- let result = match LOCAL_STDOUT.state() {
+/// Write `args` to output stream `local_s` if possible, `global_s`
+/// otherwise. `label` identifies the stream in a panic message.
+///
+/// This function is used to print error messages, so it takes extra
+/// care to avoid causing a panic when `local_stream` is unusable.
+/// For instance, if the TLS key for the local stream is uninitialized
+/// or already destroyed, or if the local stream is locked by another
+/// thread, it will just fall back to the global stream.
+///
+/// However, if the actual I/O causes an error, this function does panic.
+fn print_to<T>(args: fmt::Arguments,
+ local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
+ global_s: fn() -> T,
+ label: &str) where T: Write {
+ let result = match local_s.state() {
LocalKeyState::Uninitialized |
- LocalKeyState::Destroyed => stdout().write_fmt(args),
+ LocalKeyState::Destroyed => global_s().write_fmt(args),
LocalKeyState::Valid => {
- LOCAL_STDOUT.with(|s| {
+ local_s.with(|s| {
if let Ok(mut borrowed) = s.try_borrow_mut() {
if let Some(w) = borrowed.as_mut() {
return w.write_fmt(args);
}
}
- stdout().write_fmt(args)
+ global_s().write_fmt(args)
})
}
};
if let Err(e) = result {
- panic!("failed printing to stdout: {}", e);
+ panic!("failed printing to {}: {}", label, e);
}
}
+#[unstable(feature = "print_internals",
+ reason = "implementation detail which may disappear or be replaced at any time",
+ issue = "0")]
+#[doc(hidden)]
+pub fn _print(args: fmt::Arguments) {
+ print_to(args, &LOCAL_STDOUT, stdout, "stdout");
+}
+
+#[unstable(feature = "print_internals",
+ reason = "implementation detail which may disappear or be replaced at any time",
+ issue = "0")]
+#[doc(hidden)]
+pub fn _eprint(args: fmt::Arguments) {
+ use panicking::LOCAL_STDERR;
+ print_to(args, &LOCAL_STDERR, stderr, "stderr");
+}
+
#[cfg(test)]
mod tests {
use thread;
diff --git a/ctr-std/src/io/util.rs b/ctr-std/src/io/util.rs
index 2c68802..45d281e 100644
--- a/ctr-std/src/io/util.rs
+++ b/ctr-std/src/io/util.rs
@@ -10,7 +10,9 @@
#![allow(missing_copy_implementations)]
-use io::{self, Read, Write, ErrorKind, BufRead};
+use fmt;
+use io::{self, Read, Initializer, Write, ErrorKind, BufRead};
+use mem;
/// Copies the entire contents of a reader into a writer.
///
@@ -36,17 +38,23 @@ use io::{self, Read, Write, ErrorKind, BufRead};
/// let mut reader: &[u8] = b"hello";
/// let mut writer: Vec<u8> = vec![];
///
-/// try!(io::copy(&mut reader, &mut writer));
+/// io::copy(&mut reader, &mut writer)?;
///
-/// assert_eq!(reader, &writer[..]);
+/// assert_eq!(&b"hello"[..], &writer[..]);
/// # Ok(())
/// # }
+/// # foo().unwrap();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
where R: Read, W: Write
{
- let mut buf = [0; super::DEFAULT_BUF_SIZE];
+ let mut buf = unsafe {
+ let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
+ reader.initializer().initialize(&mut buf);
+ buf
+ };
+
let mut written = 0;
loop {
let len = match reader.read(&mut buf) {
@@ -62,16 +70,18 @@ pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<
/// A reader which is always at EOF.
///
-/// This struct is generally created by calling [`empty()`][empty]. Please see
-/// the documentation of `empty()` for more details.
+/// This struct is generally created by calling [`empty`]. Please see
+/// the documentation of [`empty()`][`empty`] for more details.
///
-/// [empty]: fn.empty.html
+/// [`empty`]: fn.empty.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Empty { _priv: () }
/// Constructs a new handle to an empty reader.
///
-/// All reads from the returned reader will return `Ok(0)`.
+/// All reads from the returned reader will return [`Ok`]`(0)`.
+///
+/// [`Ok`]: ../result/enum.Result.html#variant.Ok
///
/// # Examples
///
@@ -89,17 +99,32 @@ pub fn empty() -> Empty { Empty { _priv: () } }
#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Empty {
+ #[inline]
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl BufRead for Empty {
+ #[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
+ #[inline]
fn consume(&mut self, _n: usize) {}
}
+#[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 { .. }")
+ }
+}
+
/// A reader which yields one byte over and over and over and over and over and...
///
-/// This struct is generally created by calling [`repeat()`][repeat]. Please
+/// This struct is generally created by calling [`repeat`][repeat]. Please
/// see the documentation of `repeat()` for more details.
///
/// [repeat]: fn.repeat.html
@@ -125,17 +150,30 @@ pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }
#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Repeat {
+ #[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
for slot in &mut *buf {
*slot = self.byte;
}
Ok(buf.len())
}
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[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 { .. }")
+ }
}
/// A writer which will move data into the void.
///
-/// This struct is generally created by calling [`sink()`][sink]. Please
+/// This struct is generally created by calling [`sink`][sink]. Please
/// see the documentation of `sink()` for more details.
///
/// [sink]: fn.sink.html
@@ -161,10 +199,19 @@ pub fn sink() -> Sink { Sink { _priv: () } }
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Sink {
+ #[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
+ #[inline]
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
+#[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 { .. }")
+ }
+}
+
#[cfg(test)]
mod tests {
use io::prelude::*;
diff --git a/ctr-std/src/lib.rs b/ctr-std/src/lib.rs
index 4c08fe2..f8245c5 100644
--- a/ctr-std/src/lib.rs
+++ b/ctr-std/src/lib.rs
@@ -1,65 +1,358 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! # The Rust Standard Library
+//!
+//! The Rust Standard Library is the foundation of portable Rust software, a
+//! set of minimal and battle-tested shared abstractions for the [broader Rust
+//! ecosystem][crates.io]. It offers core types, like [`Vec<T>`] and
+//! [`Option<T>`], library-defined [operations on language
+//! primitives](#primitives), [standard macros](#macros), [I/O] and
+//! [multithreading], among [many other things][other].
+//!
+//! `std` is available to all Rust crates by default, just as if each one
+//! contained an `extern crate std;` import at the [crate root]. Therefore the
+//! standard library can be accessed in [`use`] statements through the path
+//! `std`, as in [`use std::env`], or in expressions through the absolute path
+//! `::std`, as in [`::std::env::args`].
+//!
+//! # How to read this documentation
+//!
+//! If you already know the name of what you are looking for, the fastest way to
+//! find it is to use the <a href="#" onclick="focusSearchBar();">search
+//! bar</a> at the top of the page.
+//!
+//! Otherwise, you may want to jump to one of these useful sections:
+//!
+//! * [`std::*` modules](#modules)
+//! * [Primitive types](#primitives)
+//! * [Standard macros](#macros)
+//! * [The Rust Prelude](prelude/index.html)
+//!
+//! If this is your first time, the documentation for the standard library is
+//! written to be casually perused. Clicking on interesting things should
+//! generally lead you to interesting places. Still, there are important bits
+//! you don't want to miss, so read on for a tour of the standard library and
+//! its documentation!
+//!
+//! Once you are familiar with the contents of the standard library you may
+//! begin to find the verbosity of the prose distracting. At this stage in your
+//! development you may want to press the **[-]** button near the top of the
+//! page to collapse it into a more skimmable view.
+//!
+//! While you are looking at that **[-]** button also notice the **[src]**
+//! button. Rust's API documentation comes with the source code and you are
+//! encouraged to read it. The standard library source is generally high
+//! quality and a peek behind the curtains is often enlightening.
+//!
+//! # What is in the standard library documentation?
+//!
+//! First of all, The Rust Standard Library is divided into a number of focused
+//! modules, [all listed further down this page](#modules). These modules are
+//! the bedrock upon which all of Rust is forged, and they have mighty names
+//! like [`std::slice`] and [`std::cmp`]. Modules' documentation typically
+//! includes an overview of the module along with examples, and are a smart
+//! place to start familiarizing yourself with the library.
+//!
+//! Second, implicit methods on [primitive types] are documented here. This can
+//! be a source of confusion for two reasons:
+//!
+//! 1. While primitives are implemented by the compiler, the standard library
+//! implements methods directly on the primitive types (and it is the only
+//! library that does so), which are [documented in the section on
+//! primitives](#primitives).
+//! 2. The standard library exports many modules *with the same name as
+//! primitive types*. These define additional items related to the primitive
+//! type, but not the all-important methods.
+//!
+//! So for example there is a [page for the primitive type
+//! `i32`](primitive.i32.html) that lists all the methods that can be called on
+//! 32-bit integers (very useful), and there is a [page for the module
+//! `std::i32`](i32/index.html) that documents the constant values [`MIN`] and
+//! [`MAX`](i32/constant.MAX.html) (rarely useful).
+//!
+//! Note the documentation for the primitives [`str`] and [`[T]`][slice] (also
+//! called 'slice'). Many method calls on [`String`] and [`Vec<T>`] are actually
+//! calls to methods on [`str`] and [`[T]`][slice] respectively, via [deref
+//! coercions][deref-coercions].
+//!
+//! Third, the standard library defines [The Rust Prelude], a small collection
+//! of items - mostly traits - that are imported into every module of every
+//! crate. The traits in the prelude are pervasive, making the prelude
+//! documentation a good entry point to learning about the library.
+//!
+//! And finally, the standard library exports a number of standard macros, and
+//! [lists them on this page](#macros) (technically, not all of the standard
+//! macros are defined by the standard library - some are defined by the
+//! compiler - but they are documented here the same). Like the prelude, the
+//! standard macros are imported by default into all crates.
+//!
+//! # Contributing changes to the documentation
+//!
+//! Check out the rust contribution guidelines [here](
+//! https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md).
+//! The source for this documentation can be found on [Github](https://github.com/rust-lang).
+//! To contribute changes, make sure you read the guidelines first, then submit
+//! pull-requests for your suggested changes.
+//!
+//! Contributions are appreciated! If you see a part of the docs that can be
+//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust-docs.
+//!
+//! # A Tour of The Rust Standard Library
+//!
+//! The rest of this crate documentation is dedicated to pointing out notable
+//! features of The Rust Standard Library.
+//!
+//! ## Containers and collections
+//!
+//! The [`option`] and [`result`] modules define optional and error-handling
+//! types, [`Option<T>`] and [`Result<T, E>`]. The [`iter`] module defines
+//! Rust's iterator trait, [`Iterator`], which works with the [`for`] loop to
+//! access collections.
+//!
+//! The standard library exposes three common ways to deal with contiguous
+//! regions of memory:
+//!
+//! * [`Vec<T>`] - A heap-allocated *vector* that is resizable at runtime.
+//! * [`[T; n]`][array] - An inline *array* with a fixed size at compile time.
+//! * [`[T]`][slice] - A dynamically sized *slice* into any other kind of contiguous
+//! storage, whether heap-allocated or not.
+//!
+//! Slices can only be handled through some kind of *pointer*, and as such come
+//! in many flavors such as:
+//!
+//! * `&[T]` - *shared slice*
+//! * `&mut [T]` - *mutable slice*
+//! * [`Box<[T]>`][owned slice] - *owned slice*
+//!
+//! [`str`], a UTF-8 string slice, is a primitive type, and the standard library
+//! defines many methods for it. Rust [`str`]s are typically accessed as
+//! immutable references: `&str`. Use the owned [`String`] for building and
+//! mutating strings.
+//!
+//! For converting to strings use the [`format!`] macro, and for converting from
+//! strings use the [`FromStr`] trait.
+//!
+//! Data may be shared by placing it in a reference-counted box or the [`Rc`]
+//! type, and if further contained in a [`Cell`] or [`RefCell`], may be mutated
+//! as well as shared. Likewise, in a concurrent setting it is common to pair an
+//! atomically-reference-counted box, [`Arc`], with a [`Mutex`] to get the same
+//! effect.
+//!
+//! The [`collections`] module defines maps, sets, linked lists and other
+//! typical collection types, including the common [`HashMap<K, V>`].
+//!
+//! ## Platform abstractions and I/O
+//!
+//! Besides basic data types, the standard library is largely concerned with
+//! abstracting over differences in common platforms, most notably Windows and
+//! Unix derivatives.
+//!
+//! Common types of I/O, including [files], [TCP], [UDP], are defined in the
+//! [`io`], [`fs`], and [`net`] modules.
+//!
+//! The [`thread`] module contains Rust's threading abstractions. [`sync`]
+//! contains further primitive shared memory types, including [`atomic`] and
+//! [`mpsc`], which contains the channel types for message passing.
+//!
+//! [I/O]: io/index.html
+//! [`MIN`]: i32/constant.MIN.html
+//! [TCP]: net/struct.TcpStream.html
+//! [The Rust Prelude]: prelude/index.html
+//! [UDP]: net/struct.UdpSocket.html
+//! [`::std::env::args`]: env/fn.args.html
+//! [`Arc`]: sync/struct.Arc.html
+//! [owned slice]: boxed/index.html
+//! [`Cell`]: cell/struct.Cell.html
+//! [`FromStr`]: str/trait.FromStr.html
+//! [`HashMap<K, V>`]: collections/struct.HashMap.html
+//! [`Iterator`]: iter/trait.Iterator.html
+//! [`Mutex`]: sync/struct.Mutex.html
+//! [`Option<T>`]: option/enum.Option.html
+//! [`Rc`]: rc/index.html
+//! [`RefCell`]: cell/struct.RefCell.html
+//! [`Result<T, E>`]: result/enum.Result.html
+//! [`String`]: string/struct.String.html
+//! [`Vec<T>`]: vec/index.html
+//! [array]: primitive.array.html
+//! [slice]: primitive.slice.html
+//! [`atomic`]: sync/atomic/index.html
+//! [`collections`]: collections/index.html
+//! [`for`]: ../book/first-edition/loops.html#for
+//! [`format!`]: macro.format.html
+//! [`fs`]: fs/index.html
+//! [`io`]: io/index.html
+//! [`iter`]: iter/index.html
+//! [`mpsc`]: sync/mpsc/index.html
+//! [`net`]: net/index.html
+//! [`option`]: option/index.html
+//! [`result`]: result/index.html
+//! [`std::cmp`]: cmp/index.html
+//! [`std::slice`]: slice/index.html
+//! [`str`]: primitive.str.html
+//! [`sync`]: sync/index.html
+//! [`thread`]: thread/index.html
+//! [`use std::env`]: env/index.html
+//! [`use`]: ../book/first-edition/crates-and-modules.html#importing-modules-with-use
+//! [crate root]: ../book/first-edition/crates-and-modules.html#basic-terminology-crates-and-modules
+//! [crates.io]: https://crates.io
+//! [deref-coercions]: ../book/second-edition/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods
+//! [files]: fs/struct.File.html
+//! [multithreading]: thread/index.html
+//! [other]: #what-is-in-the-standard-library-documentation
+//! [primitive types]: ../book/first-edition/primitive-types.html
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "https://doc.rust-lang.org/nightly/",
+ html_playground_url = "https://play.rust-lang.org/",
+ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
+ test(no_crate_inject, attr(deny(warnings))),
+ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
+
+// Don't link to std. We are std.
+#![no_std]
+
+//#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+
+// Tell the compiler to link to either panic_abort or panic_unwind
+#![needs_panic_runtime]
+
+// Turn warnings into errors, but only after stage0, where it can be useful for
+// code to emit warnings during language transitions
+//#![cfg_attr(not(stage0), deny(warnings))]
+
+// std may use features in a platform-specific way
+#![allow(unused_features)]
+
+// std is implemented with unstable features, many of which are internal
+// compiler details that will never be stable
#![feature(alloc)]
#![feature(allocator_api)]
-#![feature(allocator_internals)]
#![feature(alloc_system)]
+#![feature(allocator_internals)]
+#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
+#![feature(align_offset)]
+#![feature(array_error_internals)]
+#![feature(ascii_ctype)]
+#![feature(asm)]
+#![feature(attr_literals)]
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(cfg_target_thread_local)]
-#![feature(collections)]
+#![feature(cfg_target_vendor)]
+#![feature(char_error_internals)]
+#![feature(char_internals)]
#![feature(collections_range)]
-#![feature(core_float)]
-#![feature(const_fn)]
#![feature(compiler_builtins_lib)]
+#![feature(const_fn)]
+#![feature(core_float)]
#![feature(core_intrinsics)]
-#![feature(char_escape_debug)]
#![feature(dropck_eyepatch)]
-#![feature(dropck_parametricity)]
-#![feature(float_extras)]
+#![feature(exact_size_is_empty)]
+#![feature(fs_read_write)]
+#![feature(fixed_size_array)]
+#![feature(float_from_str_radix)]
#![feature(fn_traits)]
#![feature(fnbox)]
#![feature(fused)]
#![feature(generic_param_attrs)]
+#![feature(hashmap_hasher)]
#![feature(heap_api)]
+#![feature(i128)]
+#![feature(i128_type)]
+#![feature(inclusive_range)]
#![feature(int_error_internals)]
#![feature(integer_atomics)]
+#![feature(into_cow)]
#![feature(lang_items)]
+#![feature(libc)]
+#![feature(link_args)]
+#![feature(linkage)]
#![feature(macro_reexport)]
-#![feature(needs_drop)]
+#![feature(macro_vis_matcher)]
#![feature(needs_panic_runtime)]
-#![feature(oom)]
+#![feature(never_type)]
+#![feature(num_bits_bytes)]
+#![feature(old_wrapping)]
#![feature(on_unimplemented)]
+#![feature(oom)]
#![feature(optin_builtin_traits)]
+#![feature(panic_unwind)]
+#![feature(peek)]
+#![feature(placement_in_syntax)]
#![feature(placement_new_protocol)]
#![feature(prelude_import)]
-#![feature(raw)]
+#![feature(ptr_internals)]
#![feature(rand)]
-#![feature(shared)]
+#![feature(raw)]
+#![feature(repr_align)]
+#![feature(rustc_attrs)]
#![feature(sip_hash_13)]
+#![feature(slice_bytes)]
#![feature(slice_concat_ext)]
+#![feature(slice_internals)]
#![feature(slice_patterns)]
#![feature(staged_api)]
+#![feature(stmt_expr_attributes)]
+#![feature(str_char)]
#![feature(str_internals)]
+#![feature(str_utf16)]
+#![feature(termination_trait)]
+#![feature(test, rustc_private)]
#![feature(thread_local)]
+#![feature(toowned_clone_into)]
#![feature(try_from)]
#![feature(unboxed_closures)]
#![feature(unicode)]
-#![feature(unique)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
-#![feature(zero_one)]
-#![allow(non_camel_case_types, dead_code, unused_features)]
-#![no_std]
+#![feature(vec_push_all)]
+#![feature(doc_cfg)]
+#![feature(doc_masked)]
+#![feature(doc_spotlight)]
+#![cfg_attr(test, feature(update_panic_count))]
+#![cfg_attr(windows, feature(used))]
-#![needs_panic_runtime]
+#![default_lib_allocator]
-#![cfg_attr(not(stage0), default_lib_allocator)]
-#![stable(feature = "rust1", since = "1.0.0")]
+// Always use alloc_system during stage0 since we don't know if the alloc_*
+// crate the stage0 compiler will pick by default is enabled (e.g.
+// if the user has disabled jemalloc in `./configure`).
+// `force_alloc_system` is *only* intended as a workaround for local rebuilds
+// with a rustc without jemalloc.
+// FIXME(#44236) shouldn't need MSVC logic
+#![cfg_attr(all(not(target_env = "msvc"),
+ any(stage0, feature = "force_alloc_system")),
+ feature(global_allocator))]
+#[cfg(all(not(target_env = "msvc"),
+ any(stage0, feature = "force_alloc_system")))]
+#[global_allocator]
+static ALLOC: alloc_system::System = alloc_system::System;
+// Explicitly import the prelude. The compiler uses this same unstable attribute
+// to import the prelude implicitly when building crates that depend on std.
#[prelude_import]
#[allow(unused)]
use prelude::v1::*;
+// Access to Bencher, etc.
+#[cfg(test)] extern crate test;
+#[cfg(test)] extern crate rand;
+
+// We want to re-export a few macros from core but libcore has already been
+// imported by the compiler (via our #[no_std] attribute) In this case we just
+// add a new crate name so we can attach the re-exports to it.
#[macro_reexport(assert, assert_eq, assert_ne, debug_assert, debug_assert_eq,
debug_assert_ne, unreachable, unimplemented, write, writeln, try)]
extern crate core as __core;
@@ -67,15 +360,30 @@ extern crate core as __core;
#[macro_use]
#[macro_reexport(vec, format)]
extern crate alloc;
-extern crate std_unicode;
extern crate alloc_system;
+extern crate std_unicode;
+#[doc(masked)]
extern crate libc;
+// 3DS-specific dependency
+extern crate ctru_sys as libctru;
+
+// We always need an unwinder currently for backtraces
+#[doc(masked)]
+#[allow(unused_extern_crates)]
+extern crate unwind;
+
// compiler-rt intrinsics
+#[doc(masked)]
extern crate compiler_builtins;
-// 3ds-specific dependencies
-extern crate ctru_sys as libctru;
+// During testing, this crate is not actually the "real" std library, but rather
+// it links to the real std library, which was compiled from this same source
+// code. So any lang items std defines are conditionally excluded (or else they
+// wolud generate duplicate lang item errors), and any globals it defines are
+// _not_ the globals used by "real" std. So this import, defined only during
+// testing gives test-std access to real-std lang items and globals. See #2912
+#[cfg(test)] extern crate std as realstd;
// The standard macros that are not built-in to the compiler.
#[macro_use]
@@ -84,7 +392,7 @@ mod macros;
// The Rust prelude
pub mod prelude;
-// Public module declarations and reexports
+// Public module declarations and re-exports
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::any;
#[stable(feature = "rust1", since = "1.0.0")]
@@ -127,6 +435,8 @@ pub use core::i16;
pub use core::i32;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::i64;
+#[unstable(feature = "i128", issue = "35118")]
+pub use core::i128;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::usize;
#[stable(feature = "rust1", since = "1.0.0")]
@@ -155,6 +465,8 @@ pub use alloc::string;
pub use alloc::vec;
#[stable(feature = "rust1", since = "1.0.0")]
pub use std_unicode::char;
+#[unstable(feature = "i128", issue = "35118")]
+pub use core::u128;
pub mod f32;
pub mod f64;
@@ -162,15 +474,18 @@ pub mod f64;
#[macro_use]
pub mod thread;
pub mod ascii;
-pub mod fs;
pub mod collections;
+pub mod env;
pub mod error;
pub mod ffi;
+pub mod fs;
pub mod io;
+pub mod net;
pub mod num;
pub mod os;
pub mod panic;
pub mod path;
+pub mod process;
pub mod sync;
pub mod time;
pub mod heap;
@@ -187,3 +502,13 @@ mod memchr;
// The runtime entry point and a few unstable public functions used by the
// compiler
pub mod rt;
+// The trait to support returning arbitrary types in the main function
+mod termination;
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+pub use self::termination::Termination;
+
+// Include a number of private modules that exist solely to provide
+// the rustdoc documentation for primitive types. Using `include!`
+// because rustdoc only looks for these modules at the crate level.
+include!("primitive_docs.rs");
diff --git a/ctr-std/src/macros.rs b/ctr-std/src/macros.rs
index 21a7da9..f058b1c 100644
--- a/ctr-std/src/macros.rs
+++ b/ctr-std/src/macros.rs
@@ -16,13 +16,38 @@
/// The entry point for panic of Rust threads.
///
+/// This allows a program to to terminate immediately and provide feedback
+/// to the caller of the program. `panic!` should be used when a program reaches
+/// an unrecoverable problem.
+///
+/// This macro is the perfect way to assert conditions in example code and in
+/// tests. `panic!` is closely tied with the `unwrap` method of both [`Option`]
+/// and [`Result`][runwrap] enums. Both implementations call `panic!` when they are set
+/// to None or Err variants.
+///
/// This macro is used to inject panic into a Rust thread, causing the thread to
/// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type,
/// and the single-argument form of the `panic!` macro will be the value which
/// is transmitted.
///
+/// [`Result`] enum is often a better solution for recovering from errors than
+/// using the `panic!` macro. This macro should be used to avoid proceeding using
+/// incorrect values, such as from external sources. Detailed information about
+/// error handling is found in the [book].
+///
/// The multi-argument form of this macro panics with a string and has the
-/// `format!` syntax for building a string.
+/// [`format!`] syntax for building a string.
+///
+/// [runwrap]: ../std/result/enum.Result.html#method.unwrap
+/// [`Option`]: ../std/option/enum.Option.html#method.unwrap
+/// [`Result`]: ../std/result/enum.Result.html
+/// [`format!`]: ../std/macro.format.html
+/// [book]: ../book/second-edition/ch09-01-unrecoverable-errors-with-panic.html
+///
+/// # Current implementation
+///
+/// If the main thread panics it will terminate all your threads and end your
+/// program with code `101`.
///
/// # Examples
///
@@ -41,33 +66,30 @@ macro_rules! panic {
panic!("explicit panic")
});
($msg:expr) => ({
- $crate::rt::begin_panic($msg, {
- // static requires less code at runtime, more constant data
- static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!());
- &_FILE_LINE_COL
- })
+ $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!()))
});
($fmt:expr, $($arg:tt)+) => ({
- $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), {
- // The leading _'s are to avoid dead code warnings if this is
- // used inside a dead function. Just `#[allow(dead_code)]` is
- // insufficient, since the user may have
- // `#[forbid(dead_code)]` and which cannot be overridden.
- static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!());
- &_FILE_LINE_COL
- })
+ $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+),
+ &(file!(), line!(), __rust_unstable_column!()))
});
}
/// Macro for printing to the standard output.
///
-/// Equivalent to the `println!` macro except that a newline is not printed at
+/// Equivalent to the [`println!`] macro except that a newline is not printed at
/// the end of the message.
///
/// Note that stdout is frequently line-buffered by default so it may be
-/// necessary to use `io::stdout().flush()` to ensure the output is emitted
+/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
/// immediately.
///
+/// Use `print!` only for the primary output of your program. Use
+/// [`eprint!`] instead to print error and progress messages.
+///
+/// [`println!`]: ../std/macro.println.html
+/// [flush]: ../std/io/trait.Write.html#tymethod.flush
+/// [`eprint!`]: ../std/macro.eprint.html
+///
/// # Panics
///
/// Panics if writing to `io::stdout()` fails.
@@ -98,21 +120,28 @@ macro_rules! print {
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
}
-/// Macro for printing to the standard output, with a newline. On all
-/// platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
+/// Macro for printing to the standard output, with a newline.
+///
+/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
/// (no additional CARRIAGE RETURN (`\r`/`U+000D`).
///
-/// Use the `format!` syntax to write data to the standard output.
-/// See `std::fmt` for more information.
+/// Use the [`format!`] syntax to write data to the standard output.
+/// See [`std::fmt`] for more information.
+///
+/// Use `println!` only for the primary output of your program. Use
+/// [`eprintln!`] instead to print error and progress messages.
///
+/// [`format!`]: ../std/macro.format.html
+/// [`std::fmt`]: ../std/fmt/index.html
+/// [`eprintln!`]: ../std/macro.eprint.html
/// # Panics
///
-/// Panics if writing to `io::stdout()` fails.
+/// Panics if writing to `io::stdout` fails.
///
/// # Examples
///
/// ```
-/// println!();
+/// println!(); // prints just a newline
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// ```
@@ -124,6 +153,63 @@ macro_rules! println {
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
+/// Macro for printing to the standard error.
+///
+/// Equivalent to the [`print!`] macro, except that output goes to
+/// [`io::stderr`] instead of `io::stdout`. See [`print!`] for
+/// example usage.
+///
+/// Use `eprint!` only for error and progress messages. Use `print!`
+/// instead for the primary output of your program.
+///
+/// [`io::stderr`]: ../std/io/struct.Stderr.html
+/// [`print!`]: ../std/macro.print.html
+///
+/// # Panics
+///
+/// Panics if writing to `io::stderr` fails.
+///
+/// # Examples
+///
+/// ```
+/// eprint!("Error: Could not complete task");
+/// ```
+#[macro_export]
+#[stable(feature = "eprint", since = "1.19.0")]
+#[allow_internal_unstable]
+macro_rules! eprint {
+ ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*)));
+}
+
+/// Macro for printing to the standard error, with a newline.
+///
+/// Equivalent to the [`println!`] macro, except that output goes to
+/// [`io::stderr`] instead of `io::stdout`. See [`println!`] for
+/// example usage.
+///
+/// Use `eprintln!` only for error and progress messages. Use `println!`
+/// instead for the primary output of your program.
+///
+/// [`io::stderr`]: ../std/io/struct.Stderr.html
+/// [`println!`]: ../std/macro.println.html
+///
+/// # Panics
+///
+/// Panics if writing to `io::stderr` fails.
+///
+/// # Examples
+///
+/// ```
+/// eprintln!("Error: Could not complete task");
+/// ```
+#[macro_export]
+#[stable(feature = "eprint", since = "1.19.0")]
+macro_rules! eprintln {
+ () => (eprint!("\n"));
+ ($fmt:expr) => (eprint!(concat!($fmt, "\n")));
+ ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
+}
+
/// A macro to select an event from a number of receivers.
///
/// This macro is used to wait for the first event to occur on a number of
@@ -193,15 +279,60 @@ macro_rules! assert_approx_eq {
/// into libsyntax itself.
#[cfg(dox)]
pub mod builtin {
+
+ /// Unconditionally causes compilation to fail with the given error message when encountered.
+ ///
+ /// This macro should be used when a crate uses a conditional compilation strategy to provide
+ /// better error messages for erroneous conditions.
+ ///
+ /// # Examples
+ ///
+ /// Two such examples are macros and `#[cfg]` environments.
+ ///
+ /// Emit better compiler error if a macro is passed invalid values.
+ ///
+ /// ```compile_fail
+ /// macro_rules! give_me_foo_or_bar {
+ /// (foo) => {};
+ /// (bar) => {};
+ /// ($x:ident) => {
+ /// compile_error!("This macro only accepts `foo` or `bar`");
+ /// }
+ /// }
+ ///
+ /// give_me_foo_or_bar!(neither);
+ /// // ^ will fail at compile time with message "This macro only accepts `foo` or `bar`"
+ /// ```
+ ///
+ /// Emit compiler error if one of a number of features isn't available.
+ ///
+ /// ```compile_fail
+ /// #[cfg(not(any(feature = "foo", feature = "bar")))]
+ /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.")
+ /// ```
+ #[stable(feature = "compile_error_macro", since = "1.20.0")]
+ #[macro_export]
+ macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) }
+
/// The core macro for formatted string creation & output.
///
+ /// This macro functions by taking a formatting string literal containing
+ /// `{}` for each additional argument passed. `format_args!` prepares the
+ /// additional parameters to ensure the output can be interpreted as a string
+ /// and canonicalizes the arguments into a single type. Any value that implements
+ /// the [`Display`] trait can be passed to `format_args!`, as can any
+ /// [`Debug`] implementation be passed to a `{:?}` within the formatting string.
+ ///
/// This macro produces a value of type [`fmt::Arguments`]. This value can be
- /// passed to the functions in [`std::fmt`] for performing useful functions.
+ /// passed to the macros within [`std::fmt`] for performing useful redirection.
/// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are
- /// proxied through this one.
+ /// proxied through this one. `format_args!`, unlike its derived macros, avoids
+ /// heap allocations.
///
/// For more information, see the documentation in [`std::fmt`].
///
+ /// [`Display`]: ../std/fmt/trait.Display.html
+ /// [`Debug`]: ../std/fmt/trait.Debug.html
/// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html
/// [`std::fmt`]: ../std/fmt/index.html
/// [`format!`]: ../std/macro.format.html
@@ -219,9 +350,10 @@ pub mod builtin {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
- macro_rules! format_args { ($fmt:expr, $($args:tt)*) => ({
- /* compiler built-in */
- }) }
+ macro_rules! format_args {
+ ($fmt:expr) => ({ /* compiler built-in */ });
+ ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ });
+ }
/// Inspect an environment variable at compile time.
///
@@ -229,9 +361,11 @@ pub mod builtin {
/// compile time, yielding an expression of type `&'static str`.
///
/// If the environment variable is not defined, then a compilation error
- /// will be emitted. To not emit a compile error, use the `option_env!`
+ /// will be emitted. To not emit a compile error, use the [`option_env!`]
/// macro instead.
///
+ /// [`option_env!`]: ../std/macro.option_env.html
+ ///
/// # Examples
///
/// ```
@@ -240,18 +374,24 @@ pub mod builtin {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
- macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }) }
+ macro_rules! env {
+ ($name:expr) => ({ /* compiler built-in */ });
+ ($name:expr,) => ({ /* compiler built-in */ });
+ }
/// Optionally inspect an environment variable at compile time.
///
/// If the named environment variable is present at compile time, this will
/// expand into an expression of type `Option<&'static str>` whose value is
/// `Some` of the value of the environment variable. If the environment
- /// variable is not present, then this will expand to `None`.
+ /// variable is not present, then this will expand to `None`. See
+ /// [`Option<T>`][option] for more information on this type.
///
/// A compile time error is never emitted when using this macro regardless
/// of whether the environment variable is present or not.
///
+ /// [option]: ../std/option/enum.Option.html
+ ///
/// # Examples
///
/// ```
@@ -289,7 +429,8 @@ pub mod builtin {
#[unstable(feature = "concat_idents_macro", issue = "29599")]
#[macro_export]
macro_rules! concat_idents {
- ($($e:ident),*) => ({ /* compiler built-in */ })
+ ($($e:ident),*) => ({ /* compiler built-in */ });
+ ($($e:ident,)*) => ({ /* compiler built-in */ });
}
/// Concatenates literals into a static string slice.
@@ -309,13 +450,25 @@ pub mod builtin {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
- macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) }
+ macro_rules! concat {
+ ($($e:expr),*) => ({ /* compiler built-in */ });
+ ($($e:expr,)*) => ({ /* compiler built-in */ });
+ }
/// A macro which expands to the line number on which it was invoked.
///
- /// The expanded expression has type `u32`, and the returned line is not
- /// the invocation of the `line!()` macro itself, but rather the first macro
- /// invocation leading up to the invocation of the `line!()` macro.
+ /// With [`column!`] and [`file!`], these macros provide debugging information for
+ /// developers about the location within the source.
+ ///
+ /// The expanded expression has type `u32` and is 1-based, so the first line
+ /// in each file evaluates to 1, the second to 2, etc. This is consistent
+ /// with error messages by common compilers or popular editors.
+ /// The returned line is not the invocation of the `line!` macro itself,
+ /// but rather the first macro invocation leading up to the invocation
+ /// of the `line!` macro.
+ ///
+ /// [`column!`]: macro.column.html
+ /// [`file!`]: macro.file.html
///
/// # Examples
///
@@ -329,9 +482,18 @@ pub mod builtin {
/// A macro which expands to the column number on which it was invoked.
///
- /// The expanded expression has type `u32`, and the returned column is not
- /// the invocation of the `column!()` macro itself, but rather the first macro
- /// invocation leading up to the invocation of the `column!()` macro.
+ /// With [`line!`] and [`file!`], these macros provide debugging information for
+ /// developers about the location within the source.
+ ///
+ /// The expanded expression has type `u32` and is 1-based, so the first column
+ /// in each line evaluates to 1, the second to 2, etc. This is consistent
+ /// with error messages by common compilers or popular editors.
+ /// The returned column is not the invocation of the `column!` macro itself,
+ /// but rather the first macro invocation leading up to the invocation
+ /// of the `column!` macro.
+ ///
+ /// [`line!`]: macro.line.html
+ /// [`file!`]: macro.file.html
///
/// # Examples
///
@@ -345,11 +507,18 @@ pub mod builtin {
/// A macro which expands to the file name from which it was invoked.
///
+ /// With [`line!`] and [`column!`], these macros provide debugging information for
+ /// developers about the location within the source.
+ ///
+ ///
/// The expanded expression has type `&'static str`, and the returned file
- /// is not the invocation of the `file!()` macro itself, but rather the
- /// first macro invocation leading up to the invocation of the `file!()`
+ /// is not the invocation of the `file!` macro itself, but rather the
+ /// first macro invocation leading up to the invocation of the `file!`
/// macro.
///
+ /// [`line!`]: macro.line.html
+ /// [`column!`]: macro.column.html
+ ///
/// # Examples
///
/// ```
@@ -360,7 +529,7 @@ pub mod builtin {
#[macro_export]
macro_rules! file { () => ({ /* compiler built-in */ }) }
- /// A macro which stringifies its argument.
+ /// A macro which stringifies its arguments.
///
/// This macro will yield an expression of type `&'static str` which is the
/// stringification of all the tokens passed to the macro. No restrictions
@@ -377,7 +546,7 @@ pub mod builtin {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
- macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) }
+ macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) }
/// Includes a utf8-encoded file as a string.
///
@@ -389,9 +558,26 @@ pub mod builtin {
///
/// # Examples
///
- /// ```rust,ignore
- /// let secret_key = include_str!("secret-key.ascii");
+ /// Assume there are two files in the same directory with the following
+ /// contents:
+ ///
+ /// File 'spanish.in':
+ ///
+ /// ```text
+ /// adiós
/// ```
+ ///
+ /// File 'main.rs':
+ ///
+ /// ```ignore (cannot-doctest-external-file-dependency)
+ /// fn main() {
+ /// let my_str = include_str!("spanish.in");
+ /// assert_eq!(my_str, "adiós\n");
+ /// print!("{}", my_str);
+ /// }
+ /// ```
+ ///
+ /// Compiling 'main.rs' and running the resulting binary will print "adiós".
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) }
@@ -406,9 +592,26 @@ pub mod builtin {
///
/// # Examples
///
- /// ```rust,ignore
- /// let secret_key = include_bytes!("secret-key.bin");
+ /// Assume there are two files in the same directory with the following
+ /// contents:
+ ///
+ /// File 'spanish.in':
+ ///
+ /// ```text
+ /// adiós
/// ```
+ ///
+ /// File 'main.rs':
+ ///
+ /// ```ignore (cannot-doctest-external-file-dependency)
+ /// fn main() {
+ /// let bytes = include_bytes!("spanish.in");
+ /// assert_eq!(bytes, b"adi\xc3\xb3s\n");
+ /// print!("{}", String::from_utf8_lossy(bytes));
+ /// }
+ /// ```
+ ///
+ /// Compiling 'main.rs' and running the resulting binary will print "adiós".
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) }
@@ -434,14 +637,14 @@ pub mod builtin {
#[macro_export]
macro_rules! module_path { () => ({ /* compiler built-in */ }) }
- /// Boolean evaluation of configuration flags.
+ /// Boolean evaluation of configuration flags, at compile-time.
///
/// In addition to the `#[cfg]` attribute, this macro is provided to allow
/// boolean expression evaluation of configuration flags. This frequently
/// leads to less duplicated code.
///
/// The syntax given to this macro is the same syntax as [the `cfg`
- /// attribute](../reference.html#conditional-compilation).
+ /// attribute](../book/first-edition/conditional-compilation.html).
///
/// # Examples
///
@@ -458,24 +661,80 @@ pub mod builtin {
/// Parse a file as an expression or an item according to the context.
///
- /// The file is located relative to the current file. (similarly to how
- /// modules are found)
+ /// The file is located relative to the current file (similarly to how
+ /// modules are found).
///
/// Using this macro is often a bad idea, because if the file is
/// parsed as an expression, it is going to be placed in the
- /// surrounding code unhygenically. This could result in variables
+ /// surrounding code unhygienically. This could result in variables
/// or functions being different from what the file expected if
/// there are variables or functions that have the same name in
/// the current file.
///
/// # Examples
///
- /// ```ignore
- /// fn foo() {
- /// include!("/path/to/a/file")
+ /// Assume there are two files in the same directory with the following
+ /// contents:
+ ///
+ /// File 'monkeys.in':
+ ///
+ /// ```ignore (only-for-syntax-highlight)
+ /// ['🙈', '🙊', '🙉']
+ /// .iter()
+ /// .cycle()
+ /// .take(6)
+ /// .collect::<String>()
+ /// ```
+ ///
+ /// File 'main.rs':
+ ///
+ /// ```ignore (cannot-doctest-external-file-dependency)
+ /// fn main() {
+ /// let my_string = include!("monkeys.in");
+ /// assert_eq!("🙈🙊🙉🙈🙊🙉", my_string);
+ /// println!("{}", my_string);
/// }
/// ```
+ ///
+ /// Compiling 'main.rs' and running the resulting binary will print
+ /// "🙈🙊🙉🙈🙊🙉".
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) }
}
+
+/// A macro for defining #[cfg] if-else statements.
+///
+/// This is similar to the `if/elif` C preprocessor macro by allowing definition
+/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
+/// first.
+///
+/// This allows you to conveniently provide a long list #[cfg]'d blocks of code
+/// without having to rewrite each clause multiple times.
+macro_rules! cfg_if {
+ ($(
+ if #[cfg($($meta:meta),*)] { $($it:item)* }
+ ) else * else {
+ $($it2:item)*
+ }) => {
+ __cfg_if_items! {
+ () ;
+ $( ( ($($meta),*) ($($it)*) ), )*
+ ( () ($($it2)*) ),
+ }
+ }
+}
+
+macro_rules! __cfg_if_items {
+ (($($not:meta,)*) ; ) => {};
+ (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
+ __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* }
+ __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
+ }
+}
+
+macro_rules! __cfg_if_apply {
+ ($m:meta, $($it:item)*) => {
+ $(#[$m] $it)*
+ }
+}
diff --git a/ctr-std/src/memchr.rs b/ctr-std/src/memchr.rs
index 7c8c97a..240e820 100644
--- a/ctr-std/src/memchr.rs
+++ b/ctr-std/src/memchr.rs
@@ -20,11 +20,11 @@
/// magnitude faster than `haystack.iter().position(|&b| b == needle)`.
/// (See benchmarks.)
///
-/// # Example
+/// # Examples
///
/// This shows how to find the first position of a byte in a byte string.
///
-/// ```rust,ignore
+/// ```ignore (cannot-doctest-private-modules)
/// use memchr::memchr;
///
/// let haystack = b"the quick brown fox";
@@ -40,11 +40,11 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
/// Returns the index corresponding to the last occurrence of `needle` in
/// `haystack`, or `None` if one is not found.
///
-/// # Example
+/// # Examples
///
/// This shows how to find the last position of a byte in a byte string.
///
-/// ```rust,ignore
+/// ```ignore (cannot-doctest-private-modules)
/// use memchr::memrchr;
///
/// let haystack = b"the quick brown fox";
diff --git a/ctr-std/src/net/addr.rs b/ctr-std/src/net/addr.rs
new file mode 100644
index 0000000..1ca7e66
--- /dev/null
+++ b/ctr-std/src/net/addr.rs
@@ -0,0 +1,1067 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 fmt;
+use hash;
+use io;
+use mem;
+use net::{lookup_host, ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr};
+use option;
+use sys::net::netc as c;
+use sys_common::{FromInner, AsInner, IntoInner};
+use vec;
+use iter;
+use slice;
+
+/// An internet socket address, either IPv4 or IPv6.
+///
+/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well
+/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and
+/// [`SocketAddrV6`]'s respective documentation for more details.
+///
+/// [IP address]: ../../std/net/enum.IpAddr.html
+/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+///
+/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+///
+/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
+/// assert_eq!(socket.port(), 8080);
+/// assert_eq!(socket.is_ipv4(), true);
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum SocketAddr {
+ /// An IPv4 socket address.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4),
+ /// An IPv6 socket address.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6),
+}
+
+/// An IPv4 socket address.
+///
+/// IPv4 socket addresses consist of an [IPv4 address] and a 16-bit port number, as
+/// stated in [IETF RFC 793].
+///
+/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
+///
+/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
+/// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html
+/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{Ipv4Addr, SocketAddrV4};
+///
+/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+///
+/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
+/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+/// assert_eq!(socket.port(), 8080);
+/// ```
+#[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV4 { inner: c::sockaddr_in }
+
+/// An IPv6 socket address.
+///
+/// IPv6 socket addresses consist of an [Ipv6 address], a 16-bit port number, as well
+/// as fields containing the traffic class, the flow label, and a scope identifier
+/// (see [IETF RFC 2553, Section 3.3] for more details).
+///
+/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
+///
+/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+/// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html
+/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{Ipv6Addr, SocketAddrV6};
+///
+/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+///
+/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));
+/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
+/// assert_eq!(socket.port(), 8080);
+/// ```
+#[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV6 { inner: c::sockaddr_in6 }
+
+impl SocketAddr {
+ /// Creates a new socket address from an [IP address] and a port number.
+ ///
+ /// [IP address]: ../../std/net/enum.IpAddr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+ /// assert_eq!(socket.port(), 8080);
+ /// ```
+ #[stable(feature = "ip_addr", since = "1.7.0")]
+ pub fn new(ip: IpAddr, port: u16) -> SocketAddr {
+ match ip {
+ IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
+ IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
+ }
+ }
+
+ /// Returns the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+ /// ```
+ #[stable(feature = "ip_addr", since = "1.7.0")]
+ pub fn ip(&self) -> IpAddr {
+ match *self {
+ SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
+ SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()),
+ }
+ }
+
+ /// Changes the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
+ /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_ip(&mut self, new_ip: IpAddr) {
+ // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
+ match (self, new_ip) {
+ (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
+ (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip),
+ (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()),
+ }
+ }
+
+ /// Returns the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// assert_eq!(socket.port(), 8080);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn port(&self) -> u16 {
+ match *self {
+ SocketAddr::V4(ref a) => a.port(),
+ SocketAddr::V6(ref a) => a.port(),
+ }
+ }
+
+ /// Changes the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// socket.set_port(1025);
+ /// assert_eq!(socket.port(), 1025);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_port(&mut self, new_port: u16) {
+ match *self {
+ SocketAddr::V4(ref mut a) => a.set_port(new_port),
+ SocketAddr::V6(ref mut a) => a.set_port(new_port),
+ }
+ }
+
+ /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
+ /// [IPv4 address], and [`false`] otherwise.
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ /// [IP address]: ../../std/net/enum.IpAddr.html
+ /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// fn main() {
+ /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// assert_eq!(socket.is_ipv4(), true);
+ /// assert_eq!(socket.is_ipv6(), false);
+ /// }
+ /// ```
+ #[stable(feature = "sockaddr_checker", since = "1.16.0")]
+ pub fn is_ipv4(&self) -> bool {
+ match *self {
+ SocketAddr::V4(_) => true,
+ SocketAddr::V6(_) => false,
+ }
+ }
+
+ /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
+ /// [IPv6 address], and [`false`] otherwise.
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ /// [IP address]: ../../std/net/enum.IpAddr.html
+ /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
+ ///
+ /// fn main() {
+ /// let socket = SocketAddr::new(
+ /// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
+ /// assert_eq!(socket.is_ipv4(), false);
+ /// assert_eq!(socket.is_ipv6(), true);
+ /// }
+ /// ```
+ #[stable(feature = "sockaddr_checker", since = "1.16.0")]
+ pub fn is_ipv6(&self) -> bool {
+ match *self {
+ SocketAddr::V4(_) => false,
+ SocketAddr::V6(_) => true,
+ }
+ }
+}
+
+impl SocketAddrV4 {
+ /// Creates a new socket address from an [IPv4 address] and a port number.
+ ///
+ /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
+ SocketAddrV4 {
+ inner: c::sockaddr_in {
+ sin_family: c::AF_INET as c::sa_family_t,
+ sin_port: hton(port),
+ sin_addr: *ip.as_inner(),
+ .. unsafe { mem::zeroed() }
+ },
+ }
+ }
+
+ /// Returns the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn ip(&self) -> &Ipv4Addr {
+ unsafe {
+ &*(&self.inner.sin_addr as *const c::in_addr as *const Ipv4Addr)
+ }
+ }
+
+ /// Changes the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
+ /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
+ self.inner.sin_addr = *new_ip.as_inner()
+ }
+
+ /// Returns the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// assert_eq!(socket.port(), 8080);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn port(&self) -> u16 {
+ ntoh(self.inner.sin_port)
+ }
+
+ /// Changes the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// socket.set_port(4242);
+ /// assert_eq!(socket.port(), 4242);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_port(&mut self, new_port: u16) {
+ self.inner.sin_port = hton(new_port);
+ }
+}
+
+impl SocketAddrV6 {
+ /// Creates a new socket address from an [IPv6 address], a 16-bit port number,
+ /// and the `flowinfo` and `scope_id` fields.
+ ///
+ /// For more information on the meaning and layout of the `flowinfo` and `scope_id`
+ /// parameters, see [IETF RFC 2553, Section 3.3].
+ ///
+ /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+ /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32)
+ -> SocketAddrV6 {
+ SocketAddrV6 {
+ inner: c::sockaddr_in6 {
+ sin6_family: c::AF_INET6 as c::sa_family_t,
+ sin6_port: hton(port),
+ sin6_addr: *ip.as_inner(),
+ sin6_flowinfo: flowinfo,
+ sin6_scope_id: scope_id,
+ .. unsafe { mem::zeroed() }
+ },
+ }
+ }
+
+ /// Returns the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn ip(&self) -> &Ipv6Addr {
+ unsafe {
+ &*(&self.inner.sin6_addr as *const c::in6_addr as *const Ipv6Addr)
+ }
+ }
+
+ /// Changes the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+ /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
+ self.inner.sin6_addr = *new_ip.as_inner()
+ }
+
+ /// Returns the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// assert_eq!(socket.port(), 8080);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn port(&self) -> u16 {
+ ntoh(self.inner.sin6_port)
+ }
+
+ /// Changes the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// socket.set_port(4242);
+ /// assert_eq!(socket.port(), 4242);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_port(&mut self, new_port: u16) {
+ self.inner.sin6_port = hton(new_port);
+ }
+
+ /// Returns the flow information associated with this address.
+ ///
+ /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`,
+ /// as specified in [IETF RFC 2553, Section 3.3].
+ /// It combines information about the flow label and the traffic class as specified
+ /// in [IETF RFC 2460], respectively [Section 6] and [Section 7].
+ ///
+ /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+ /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460
+ /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6
+ /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+ /// assert_eq!(socket.flowinfo(), 10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn flowinfo(&self) -> u32 {
+ self.inner.sin6_flowinfo
+ }
+
+ /// Changes the flow information associated with this socket address.
+ ///
+ /// See the [`flowinfo`] method's documentation for more details.
+ ///
+ /// [`flowinfo`]: #method.flowinfo
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+ /// socket.set_flowinfo(56);
+ /// assert_eq!(socket.flowinfo(), 56);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
+ self.inner.sin6_flowinfo = new_flowinfo;
+ }
+
+ /// Returns the scope ID associated with this address.
+ ///
+ /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`,
+ /// as specified in [IETF RFC 2553, Section 3.3].
+ ///
+ /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+ /// assert_eq!(socket.scope_id(), 78);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn scope_id(&self) -> u32 {
+ self.inner.sin6_scope_id
+ }
+
+ /// Change the scope ID associated with this socket address.
+ ///
+ /// See the [`scope_id`] method's documentation for more details.
+ ///
+ /// [`scope_id`]: #method.scope_id
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+ /// socket.set_scope_id(42);
+ /// assert_eq!(socket.scope_id(), 42);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_scope_id(&mut self, new_scope_id: u32) {
+ self.inner.sin6_scope_id = new_scope_id;
+ }
+}
+
+impl FromInner<c::sockaddr_in> for SocketAddrV4 {
+ fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 {
+ SocketAddrV4 { inner: addr }
+ }
+}
+
+impl FromInner<c::sockaddr_in6> for SocketAddrV6 {
+ fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 {
+ SocketAddrV6 { inner: addr }
+ }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<SocketAddrV4> for SocketAddr {
+ fn from(sock4: SocketAddrV4) -> SocketAddr {
+ SocketAddr::V4(sock4)
+ }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<SocketAddrV6> for SocketAddr {
+ fn from(sock6: SocketAddrV6) -> SocketAddr {
+ SocketAddr::V6(sock6)
+ }
+}
+
+#[stable(feature = "addr_from_into_ip", since = "1.17.0")]
+impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
+ fn from(pieces: (I, u16)) -> SocketAddr {
+ SocketAddr::new(pieces.0.into(), pieces.1)
+ }
+}
+
+impl<'a> IntoInner<(*const c::sockaddr, c::socklen_t)> for &'a SocketAddr {
+ fn into_inner(self) -> (*const c::sockaddr, c::socklen_t) {
+ match *self {
+ SocketAddr::V4(ref a) => {
+ (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t)
+ }
+ SocketAddr::V6(ref a) => {
+ (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t)
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ SocketAddr::V4(ref a) => a.fmt(f),
+ SocketAddr::V6(ref a) => a.fmt(f),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddrV4 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}:{}", self.ip(), self.port())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddrV4 {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddrV6 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "[{}]:{}", self.ip(), self.port())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddrV6 {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for SocketAddrV4 {
+ fn clone(&self) -> SocketAddrV4 { *self }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for SocketAddrV6 {
+ fn clone(&self) -> SocketAddrV6 { *self }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for SocketAddrV4 {
+ fn eq(&self, other: &SocketAddrV4) -> bool {
+ self.inner.sin_port == other.inner.sin_port &&
+ self.inner.sin_addr.s_addr == other.inner.sin_addr.s_addr
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for SocketAddrV6 {
+ fn eq(&self, other: &SocketAddrV6) -> bool {
+ self.inner.sin6_port == other.inner.sin6_port &&
+ self.inner.sin6_addr.s6_addr == other.inner.sin6_addr.s6_addr &&
+ self.inner.sin6_flowinfo == other.inner.sin6_flowinfo &&
+ self.inner.sin6_scope_id == other.inner.sin6_scope_id
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for SocketAddrV4 {}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for SocketAddrV6 {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for SocketAddrV4 {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ (self.inner.sin_port, self.inner.sin_addr.s_addr).hash(s)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for SocketAddrV6 {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ (self.inner.sin6_port, &self.inner.sin6_addr.s6_addr,
+ self.inner.sin6_flowinfo, self.inner.sin6_scope_id).hash(s)
+ }
+}
+
+/// A trait for objects which can be converted or resolved to one or more
+/// [`SocketAddr`] values.
+///
+/// This trait is used for generic address resolution when constructing network
+/// objects. By default it is implemented for the following types:
+///
+/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function.
+///
+/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`,
+/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`:
+/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially.
+///
+/// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation
+/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host
+/// name.
+///
+/// * [`&str`]: the string should be either a string representation of a
+/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like
+/// `<host_name>:<port>` pair where `<port>` is a [`u16`] value.
+///
+/// This trait allows constructing network objects like [`TcpStream`] or
+/// [`UdpSocket`] easily with values of various types for the bind/connection
+/// address. It is needed because sometimes one type is more appropriate than
+/// the other: for simple uses a string like `"localhost:12345"` is much nicer
+/// than manual construction of the corresponding [`SocketAddr`], but sometimes
+/// [`SocketAddr`] value is *the* main source of the address, and converting it to
+/// some other type (e.g. a string) just for it to be converted back to
+/// [`SocketAddr`] in constructor methods is pointless.
+///
+/// Addresses returned by the operating system that are not IP addresses are
+/// silently ignored.
+///
+/// [`FromStr`]: ../../std/str/trait.FromStr.html
+/// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html
+/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html
+/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+/// [`&str`]: ../../std/primitive.str.html
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+/// [`to_socket_addrs`]: #tymethod.to_socket_addrs
+/// [`UdpSocket`]: ../../std/net/struct.UdpSocket.html
+/// [`u16`]: ../../std/primitive.u16.html
+///
+/// # Examples
+///
+/// Creating a [`SocketAddr`] iterator that yields one item:
+///
+/// ```
+/// use std::net::{ToSocketAddrs, SocketAddr};
+///
+/// let addr = SocketAddr::from(([127, 0, 0, 1], 443));
+/// let mut addrs_iter = addr.to_socket_addrs().unwrap();
+///
+/// assert_eq!(Some(addr), addrs_iter.next());
+/// assert!(addrs_iter.next().is_none());
+/// ```
+///
+/// Creating a [`SocketAddr`] iterator from a hostname:
+///
+/// ```no_run
+/// use std::net::{SocketAddr, ToSocketAddrs};
+///
+/// // assuming 'localhost' resolves to 127.0.0.1
+/// let mut addrs_iter = "localhost:443".to_socket_addrs().unwrap();
+/// assert_eq!(addrs_iter.next(), Some(SocketAddr::from(([127, 0, 0, 1], 443))));
+/// assert!(addrs_iter.next().is_none());
+///
+/// // assuming 'foo' does not resolve
+/// assert!("foo:443".to_socket_addrs().is_err());
+/// ```
+///
+/// Creating a [`SocketAddr`] iterator that yields multiple items:
+///
+/// ```
+/// use std::net::{SocketAddr, ToSocketAddrs};
+///
+/// let addr1 = SocketAddr::from(([0, 0, 0, 0], 80));
+/// let addr2 = SocketAddr::from(([127, 0, 0, 1], 443));
+/// let addrs = vec![addr1, addr2];
+///
+/// let mut addrs_iter = (&addrs[..]).to_socket_addrs().unwrap();
+///
+/// assert_eq!(Some(addr1), addrs_iter.next());
+/// assert_eq!(Some(addr2), addrs_iter.next());
+/// assert!(addrs_iter.next().is_none());
+/// ```
+///
+/// Attempting to create a [`SocketAddr`] iterator from an improperly formatted
+/// socket address `&str` (missing the port):
+///
+/// ```
+/// use std::io;
+/// use std::net::ToSocketAddrs;
+///
+/// let err = "127.0.0.1".to_socket_addrs().unwrap_err();
+/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+/// ```
+///
+/// [`TcpStream::connect`] is an example of an function that utilizes
+/// `ToSocketAddrs` as a trait bound on its parameter in order to accept
+/// different types:
+///
+/// ```no_run
+/// use std::net::{TcpStream, Ipv4Addr};
+///
+/// let stream = TcpStream::connect(("127.0.0.1", 443));
+/// // or
+/// let stream = TcpStream::connect("127.0.0.1:443");
+/// // or
+/// let stream = TcpStream::connect((Ipv4Addr::new(127, 0, 0, 1), 443));
+/// ```
+///
+/// [`TcpStream::connect`]: ../../std/net/struct.TcpStream.html#method.connect
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ToSocketAddrs {
+ /// Returned iterator over socket addresses which this type may correspond
+ /// to.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ type Iter: Iterator<Item=SocketAddr>;
+
+ /// Converts this object to an iterator of resolved `SocketAddr`s.
+ ///
+ /// The returned iterator may not actually yield any values depending on the
+ /// outcome of any resolution performed.
+ ///
+ /// Note that this function may block the current thread while resolution is
+ /// performed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn to_socket_addrs(&self) -> io::Result<Self::Iter>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for SocketAddr {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ Ok(Some(*self).into_iter())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for SocketAddrV4 {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ SocketAddr::V4(*self).to_socket_addrs()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for SocketAddrV6 {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ SocketAddr::V6(*self).to_socket_addrs()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for (IpAddr, u16) {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ let (ip, port) = *self;
+ match ip {
+ IpAddr::V4(ref a) => (*a, port).to_socket_addrs(),
+ IpAddr::V6(ref a) => (*a, port).to_socket_addrs(),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for (Ipv4Addr, u16) {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ let (ip, port) = *self;
+ SocketAddrV4::new(ip, port).to_socket_addrs()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for (Ipv6Addr, u16) {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ let (ip, port) = *self;
+ SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs()
+ }
+}
+
+fn resolve_socket_addr(s: &str, p: u16) -> io::Result<vec::IntoIter<SocketAddr>> {
+ let ips = lookup_host(s)?;
+ let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect();
+ Ok(v.into_iter())
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> ToSocketAddrs for (&'a str, u16) {
+ type Iter = vec::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+ let (host, port) = *self;
+
+ // try to parse the host as a regular IP address first
+ if let Ok(addr) = host.parse::<Ipv4Addr>() {
+ let addr = SocketAddrV4::new(addr, port);
+ return Ok(vec![SocketAddr::V4(addr)].into_iter())
+ }
+ if let Ok(addr) = host.parse::<Ipv6Addr>() {
+ let addr = SocketAddrV6::new(addr, port, 0, 0);
+ return Ok(vec![SocketAddr::V6(addr)].into_iter())
+ }
+
+ resolve_socket_addr(host, port)
+ }
+}
+
+// accepts strings like 'localhost:12345'
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for str {
+ type Iter = vec::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+ // try to parse as a regular SocketAddr first
+ if let Some(addr) = self.parse().ok() {
+ return Ok(vec![addr].into_iter());
+ }
+
+ macro_rules! try_opt {
+ ($e:expr, $msg:expr) => (
+ match $e {
+ Some(r) => r,
+ None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ $msg)),
+ }
+ )
+ }
+
+ // split the string by ':' and convert the second part to u16
+ let mut parts_iter = self.rsplitn(2, ':');
+ let port_str = try_opt!(parts_iter.next(), "invalid socket address");
+ let host = try_opt!(parts_iter.next(), "invalid socket address");
+ let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
+ resolve_socket_addr(host, port)
+ }
+}
+
+#[stable(feature = "slice_to_socket_addrs", since = "1.8.0")]
+impl<'a> ToSocketAddrs for &'a [SocketAddr] {
+ type Iter = iter::Cloned<slice::Iter<'a, SocketAddr>>;
+
+ fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
+ Ok(self.iter().cloned())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'a T {
+ type Iter = T::Iter;
+ fn to_socket_addrs(&self) -> io::Result<T::Iter> {
+ (**self).to_socket_addrs()
+ }
+}
+
+#[stable(feature = "string_to_socket_addrs", since = "1.16.0")]
+impl ToSocketAddrs for String {
+ type Iter = vec::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+ (&**self).to_socket_addrs()
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use net::*;
+ use net::test::{tsa, sa6, sa4};
+
+ #[test]
+ fn to_socket_addr_ipaddr_u16() {
+ let a = Ipv4Addr::new(77, 88, 21, 11);
+ let p = 12345;
+ let e = SocketAddr::V4(SocketAddrV4::new(a, p));
+ assert_eq!(Ok(vec![e]), tsa((a, p)));
+ }
+
+ #[test]
+ fn to_socket_addr_str_u16() {
+ let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
+ assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352)));
+
+ let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+ assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53)));
+
+ let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
+ assert!(tsa(("localhost", 23924)).unwrap().contains(&a));
+ }
+
+ #[test]
+ fn to_socket_addr_str() {
+ let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
+ assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352"));
+
+ let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+ assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53"));
+
+ let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
+ assert!(tsa("localhost:23924").unwrap().contains(&a));
+ }
+
+ #[test]
+ fn to_socket_addr_string() {
+ let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
+ assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352")));
+ assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352")));
+ assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352")));
+
+ let s = format!("{}:{}", "77.88.21.11", "24352");
+ assert_eq!(Ok(vec![a]), tsa(s));
+ // s has been moved into the tsa call
+ }
+
+ // FIXME: figure out why this fails on openbsd and bitrig and fix it
+ #[test]
+ #[cfg(not(any(windows, target_os = "openbsd", target_os = "bitrig")))]
+ fn to_socket_addr_str_bad() {
+ assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err());
+ }
+
+ #[test]
+ fn set_ip() {
+ fn ip4(low: u8) -> Ipv4Addr { Ipv4Addr::new(77, 88, 21, low) }
+ fn ip6(low: u16) -> Ipv6Addr { Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) }
+
+ let mut v4 = SocketAddrV4::new(ip4(11), 80);
+ assert_eq!(v4.ip(), &ip4(11));
+ v4.set_ip(ip4(12));
+ assert_eq!(v4.ip(), &ip4(12));
+
+ let mut addr = SocketAddr::V4(v4);
+ assert_eq!(addr.ip(), IpAddr::V4(ip4(12)));
+ addr.set_ip(IpAddr::V4(ip4(13)));
+ assert_eq!(addr.ip(), IpAddr::V4(ip4(13)));
+ addr.set_ip(IpAddr::V6(ip6(14)));
+ assert_eq!(addr.ip(), IpAddr::V6(ip6(14)));
+
+ let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0);
+ assert_eq!(v6.ip(), &ip6(1));
+ v6.set_ip(ip6(2));
+ assert_eq!(v6.ip(), &ip6(2));
+
+ let mut addr = SocketAddr::V6(v6);
+ assert_eq!(addr.ip(), IpAddr::V6(ip6(2)));
+ addr.set_ip(IpAddr::V6(ip6(3)));
+ assert_eq!(addr.ip(), IpAddr::V6(ip6(3)));
+ addr.set_ip(IpAddr::V4(ip4(4)));
+ assert_eq!(addr.ip(), IpAddr::V4(ip4(4)));
+ }
+
+ #[test]
+ fn set_port() {
+ let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80);
+ assert_eq!(v4.port(), 80);
+ v4.set_port(443);
+ assert_eq!(v4.port(), 443);
+
+ let mut addr = SocketAddr::V4(v4);
+ assert_eq!(addr.port(), 443);
+ addr.set_port(8080);
+ assert_eq!(addr.port(), 8080);
+
+ let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0);
+ assert_eq!(v6.port(), 80);
+ v6.set_port(443);
+ assert_eq!(v6.port(), 443);
+
+ let mut addr = SocketAddr::V6(v6);
+ assert_eq!(addr.port(), 443);
+ addr.set_port(8080);
+ assert_eq!(addr.port(), 8080);
+ }
+
+ #[test]
+ fn set_flowinfo() {
+ let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0);
+ assert_eq!(v6.flowinfo(), 10);
+ v6.set_flowinfo(20);
+ assert_eq!(v6.flowinfo(), 20);
+ }
+
+ #[test]
+ fn set_scope_id() {
+ let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10);
+ assert_eq!(v6.scope_id(), 10);
+ v6.set_scope_id(20);
+ assert_eq!(v6.scope_id(), 20);
+ }
+
+ #[test]
+ fn is_v4() {
+ let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80));
+ assert!(v4.is_ipv4());
+ assert!(!v4.is_ipv6());
+ }
+
+ #[test]
+ fn is_v6() {
+ let v6 = SocketAddr::V6(SocketAddrV6::new(
+ Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0));
+ assert!(!v6.is_ipv4());
+ assert!(v6.is_ipv6());
+ }
+}
diff --git a/ctr-std/src/net/ip.rs b/ctr-std/src/net/ip.rs
new file mode 100644
index 0000000..0d73a6f
--- /dev/null
+++ b/ctr-std/src/net/ip.rs
@@ -0,0 +1,1835 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![unstable(feature = "ip", reason = "extra functionality has not been \
+ scrutinized to the level that it should \
+ be to be stable",
+ issue = "27709")]
+
+use cmp::Ordering;
+use fmt;
+use hash;
+use mem;
+use net::{hton, ntoh};
+use sys::net::netc as c;
+use sys_common::{AsInner, FromInner};
+
+/// An IP address, either IPv4 or IPv6.
+///
+/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
+/// respective documentation for more details.
+///
+/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html
+/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+///
+/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
+/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+///
+/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4));
+/// assert_eq!("::1".parse(), Ok(localhost_v6));
+///
+/// assert_eq!(localhost_v4.is_ipv6(), false);
+/// assert_eq!(localhost_v4.is_ipv4(), true);
+/// ```
+#[stable(feature = "ip_addr", since = "1.7.0")]
+#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)]
+pub enum IpAddr {
+ /// An IPv4 address.
+ #[stable(feature = "ip_addr", since = "1.7.0")]
+ V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr),
+ /// An IPv6 address.
+ #[stable(feature = "ip_addr", since = "1.7.0")]
+ V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr),
+}
+
+/// An IPv4 address.
+///
+/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791].
+/// They are usually represented as four octets.
+///
+/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
+///
+/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791
+/// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+///
+/// # Textual representation
+///
+/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
+/// notation, divided by `.` (this is called "dot-decimal notation").
+///
+/// [`FromStr`]: ../../std/str/trait.FromStr.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::Ipv4Addr;
+///
+/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
+/// assert_eq!("127.0.0.1".parse(), Ok(localhost));
+/// assert_eq!(localhost.is_loopback(), true);
+/// ```
+#[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Ipv4Addr {
+ inner: c::in_addr,
+}
+
+/// An IPv6 address.
+///
+/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
+/// They are usually represented as eight 16-bit segments.
+///
+/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
+///
+/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+/// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+///
+/// # Textual representation
+///
+/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent
+/// an IPv6 address in text, but in general, each segments is written in hexadecimal
+/// notation, and segments are separated by `:`. For more information, see
+/// [IETF RFC 5952].
+///
+/// [`FromStr`]: ../../std/str/trait.FromStr.html
+/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952
+///
+/// # Examples
+///
+/// ```
+/// use std::net::Ipv6Addr;
+///
+/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+/// assert_eq!("::1".parse(), Ok(localhost));
+/// assert_eq!(localhost.is_loopback(), true);
+/// ```
+#[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Ipv6Addr {
+ inner: c::in6_addr,
+}
+
+#[allow(missing_docs)]
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+pub enum Ipv6MulticastScope {
+ InterfaceLocal,
+ LinkLocal,
+ RealmLocal,
+ AdminLocal,
+ SiteLocal,
+ OrganizationLocal,
+ Global
+}
+
+impl IpAddr {
+ /// Returns [`true`] for the special 'unspecified' address.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_unspecified`][IPv4] and
+ /// [`Ipv6Addr::is_unspecified`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true);
+ /// ```
+ #[stable(feature = "ip_shared", since = "1.12.0")]
+ pub fn is_unspecified(&self) -> bool {
+ match *self {
+ IpAddr::V4(ref a) => a.is_unspecified(),
+ IpAddr::V6(ref a) => a.is_unspecified(),
+ }
+ }
+
+ /// Returns [`true`] if this is a loopback address.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and
+ /// [`Ipv6Addr::is_loopback`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true);
+ /// ```
+ #[stable(feature = "ip_shared", since = "1.12.0")]
+ pub fn is_loopback(&self) -> bool {
+ match *self {
+ IpAddr::V4(ref a) => a.is_loopback(),
+ IpAddr::V6(ref a) => a.is_loopback(),
+ }
+ }
+
+ /// Returns [`true`] if the address appears to be globally routable.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and
+ /// [`Ipv6Addr::is_global`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// fn main() {
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(),
+ /// true);
+ /// }
+ /// ```
+ pub fn is_global(&self) -> bool {
+ match *self {
+ IpAddr::V4(ref a) => a.is_global(),
+ IpAddr::V6(ref a) => a.is_global(),
+ }
+ }
+
+ /// Returns [`true`] if this is a multicast address.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and
+ /// [`Ipv6Addr::is_multicast`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true);
+ /// ```
+ #[stable(feature = "ip_shared", since = "1.12.0")]
+ pub fn is_multicast(&self) -> bool {
+ match *self {
+ IpAddr::V4(ref a) => a.is_multicast(),
+ IpAddr::V6(ref a) => a.is_multicast(),
+ }
+ }
+
+ /// Returns [`true`] if this address is in a range designated for documentation.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and
+ /// [`Ipv6Addr::is_documentation`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// fn main() {
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0))
+ /// .is_documentation(), true);
+ /// }
+ /// ```
+ pub fn is_documentation(&self) -> bool {
+ match *self {
+ IpAddr::V4(ref a) => a.is_documentation(),
+ IpAddr::V6(ref a) => a.is_documentation(),
+ }
+ }
+
+ /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise.
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ /// [IPv4 address]: #variant.V4
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// fn main() {
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(),
+ /// false);
+ /// }
+ /// ```
+ #[stable(feature = "ipaddr_checker", since = "1.16.0")]
+ pub fn is_ipv4(&self) -> bool {
+ match *self {
+ IpAddr::V4(_) => true,
+ IpAddr::V6(_) => false,
+ }
+ }
+
+ /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise.
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ /// [IPv6 address]: #variant.V6
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// fn main() {
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(),
+ /// true);
+ /// }
+ /// ```
+ #[stable(feature = "ipaddr_checker", since = "1.16.0")]
+ pub fn is_ipv6(&self) -> bool {
+ match *self {
+ IpAddr::V4(_) => false,
+ IpAddr::V6(_) => true,
+ }
+ }
+}
+
+impl Ipv4Addr {
+ /// Creates a new IPv4 address from four eight-bit octets.
+ ///
+ /// The result will represent the IP address `a`.`b`.`c`.`d`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+ Ipv4Addr {
+ inner: c::in_addr {
+ s_addr: hton(((a as u32) << 24) |
+ ((b as u32) << 16) |
+ ((c as u32) << 8) |
+ (d as u32)),
+ }
+ }
+ }
+
+ /// Creates a new IPv4 address with the address pointing to localhost: 127.0.0.1.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_constructors)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::localhost();
+ /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
+ /// ```
+ #[unstable(feature = "ip_constructors",
+ reason = "requires greater scrutiny before stabilization",
+ issue = "44582")]
+ pub fn localhost() -> Ipv4Addr {
+ Ipv4Addr::new(127, 0, 0, 1)
+ }
+
+ /// Creates a new IPv4 address representing an unspecified address: 0.0.0.0
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_constructors)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::unspecified();
+ /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
+ /// ```
+ #[unstable(feature = "ip_constructors",
+ reason = "requires greater scrutiny before stabilization",
+ issue = "44582")]
+ pub fn unspecified() -> Ipv4Addr {
+ Ipv4Addr::new(0, 0, 0, 0)
+ }
+
+ /// Returns the four eight-bit integers that make up this address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+ /// assert_eq!(addr.octets(), [127, 0, 0, 1]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn octets(&self) -> [u8; 4] {
+ let bits = ntoh(self.inner.s_addr);
+ [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
+ }
+
+ /// Returns [`true`] for the special 'unspecified' address (0.0.0.0).
+ ///
+ /// This property is defined in _UNIX Network Programming, Second Edition_,
+ /// W. Richard Stevens, p. 891; see also [ip7].
+ ///
+ /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true);
+ /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
+ /// ```
+ #[stable(feature = "ip_shared", since = "1.12.0")]
+ pub fn is_unspecified(&self) -> bool {
+ self.inner.s_addr == 0
+ }
+
+ /// Returns [`true`] if this is a loopback address (127.0.0.0/8).
+ ///
+ /// This property is defined by [IETF RFC 1122].
+ ///
+ /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true);
+ /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_loopback(&self) -> bool {
+ self.octets()[0] == 127
+ }
+
+ /// Returns [`true`] if this is a private address.
+ ///
+ /// The private address ranges are defined in [IETF RFC 1918] and include:
+ ///
+ /// - 10.0.0.0/8
+ /// - 172.16.0.0/12
+ /// - 192.168.0.0/16
+ ///
+ /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false);
+ /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_private(&self) -> bool {
+ match (self.octets()[0], self.octets()[1]) {
+ (10, _) => true,
+ (172, b) if b >= 16 && b <= 31 => true,
+ (192, 168) => true,
+ _ => false
+ }
+ }
+
+ /// Returns [`true`] if the address is link-local (169.254.0.0/16).
+ ///
+ /// This property is defined by [IETF RFC 3927].
+ ///
+ /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true);
+ /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true);
+ /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_link_local(&self) -> bool {
+ self.octets()[0] == 169 && self.octets()[1] == 254
+ }
+
+ /// Returns [`true`] if the address appears to be globally routable.
+ /// See [iana-ipv4-special-registry][ipv4-sr].
+ ///
+ /// The following return false:
+ ///
+ /// - private address (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16)
+ /// - the loopback address (127.0.0.0/8)
+ /// - the link-local address (169.254.0.0/16)
+ /// - the broadcast address (255.255.255.255/32)
+ /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24)
+ /// - the unspecified address (0.0.0.0)
+ ///
+ /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv4Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
+ /// }
+ /// ```
+ pub fn is_global(&self) -> bool {
+ !self.is_private() && !self.is_loopback() && !self.is_link_local() &&
+ !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified()
+ }
+
+ /// Returns [`true`] if this is a multicast address (224.0.0.0/4).
+ ///
+ /// Multicast addresses have a most significant octet between 224 and 239,
+ /// and is defined by [IETF RFC 5771].
+ ///
+ /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true);
+ /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true);
+ /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_multicast(&self) -> bool {
+ self.octets()[0] >= 224 && self.octets()[0] <= 239
+ }
+
+ /// Returns [`true`] if this is a broadcast address (255.255.255.255).
+ ///
+ /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919].
+ ///
+ /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true);
+ /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_broadcast(&self) -> bool {
+ self.octets()[0] == 255 && self.octets()[1] == 255 &&
+ self.octets()[2] == 255 && self.octets()[3] == 255
+ }
+
+ /// Returns [`true`] if this address is in a range designated for documentation.
+ ///
+ /// This is defined in [IETF RFC 5737]:
+ ///
+ /// - 192.0.2.0/24 (TEST-NET-1)
+ /// - 198.51.100.0/24 (TEST-NET-2)
+ /// - 203.0.113.0/24 (TEST-NET-3)
+ ///
+ /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true);
+ /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true);
+ /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true);
+ /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_documentation(&self) -> bool {
+ match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) {
+ (192, 0, 2, _) => true,
+ (198, 51, 100, _) => true,
+ (203, 0, 113, _) => true,
+ _ => false
+ }
+ }
+
+ /// Converts this address to an IPv4-compatible [IPv6 address].
+ ///
+ /// a.b.c.d becomes ::a.b.c.d
+ ///
+ /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
+ /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_ipv6_compatible(&self) -> Ipv6Addr {
+ Ipv6Addr::new(0, 0, 0, 0, 0, 0,
+ ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16,
+ ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16)
+ }
+
+ /// Converts this address to an IPv4-mapped [IPv6 address].
+ ///
+ /// a.b.c.d becomes ::ffff:a.b.c.d
+ ///
+ /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
+ /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_ipv6_mapped(&self) -> Ipv6Addr {
+ Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff,
+ ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16,
+ ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16)
+ }
+}
+
+#[stable(feature = "ip_addr", since = "1.7.0")]
+impl fmt::Display for IpAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ IpAddr::V4(ref a) => a.fmt(fmt),
+ IpAddr::V6(ref a) => a.fmt(fmt),
+ }
+ }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<Ipv4Addr> for IpAddr {
+ fn from(ipv4: Ipv4Addr) -> IpAddr {
+ IpAddr::V4(ipv4)
+ }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<Ipv6Addr> for IpAddr {
+ fn from(ipv6: Ipv6Addr) -> IpAddr {
+ IpAddr::V6(ipv6)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Ipv4Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let octets = self.octets();
+ write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Ipv4Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for Ipv4Addr {
+ fn clone(&self) -> Ipv4Addr { *self }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for Ipv4Addr {
+ fn eq(&self, other: &Ipv4Addr) -> bool {
+ self.inner.s_addr == other.inner.s_addr
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<Ipv4Addr> for IpAddr {
+ fn eq(&self, other: &Ipv4Addr) -> bool {
+ match *self {
+ IpAddr::V4(ref v4) => v4 == other,
+ IpAddr::V6(_) => false,
+ }
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<IpAddr> for Ipv4Addr {
+ fn eq(&self, other: &IpAddr) -> bool {
+ match *other {
+ IpAddr::V4(ref v4) => self == v4,
+ IpAddr::V6(_) => false,
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for Ipv4Addr {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for Ipv4Addr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ // `inner` is #[repr(packed)], so we need to copy `s_addr`.
+ {self.inner.s_addr}.hash(s)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for Ipv4Addr {
+ fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<Ipv4Addr> for IpAddr {
+ fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+ match *self {
+ IpAddr::V4(ref v4) => v4.partial_cmp(other),
+ IpAddr::V6(_) => Some(Ordering::Greater),
+ }
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<IpAddr> for Ipv4Addr {
+ fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+ match *other {
+ IpAddr::V4(ref v4) => self.partial_cmp(v4),
+ IpAddr::V6(_) => Some(Ordering::Less),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for Ipv4Addr {
+ fn cmp(&self, other: &Ipv4Addr) -> Ordering {
+ ntoh(self.inner.s_addr).cmp(&ntoh(other.inner.s_addr))
+ }
+}
+
+impl AsInner<c::in_addr> for Ipv4Addr {
+ fn as_inner(&self) -> &c::in_addr { &self.inner }
+}
+impl FromInner<c::in_addr> for Ipv4Addr {
+ fn from_inner(addr: c::in_addr) -> Ipv4Addr {
+ Ipv4Addr { inner: addr }
+ }
+}
+
+#[stable(feature = "ip_u32", since = "1.1.0")]
+impl From<Ipv4Addr> for u32 {
+ /// It performs the conversion in network order (big-endian).
+ fn from(ip: Ipv4Addr) -> u32 {
+ let ip = ip.octets();
+ ((ip[0] as u32) << 24) + ((ip[1] as u32) << 16) + ((ip[2] as u32) << 8) + (ip[3] as u32)
+ }
+}
+
+#[stable(feature = "ip_u32", since = "1.1.0")]
+impl From<u32> for Ipv4Addr {
+ /// It performs the conversion in network order (big-endian).
+ fn from(ip: u32) -> Ipv4Addr {
+ Ipv4Addr::new((ip >> 24) as u8, (ip >> 16) as u8, (ip >> 8) as u8, ip as u8)
+ }
+}
+
+#[stable(feature = "from_slice_v4", since = "1.9.0")]
+impl From<[u8; 4]> for Ipv4Addr {
+ fn from(octets: [u8; 4]) -> Ipv4Addr {
+ Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])
+ }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u8; 4]> for IpAddr {
+ fn from(octets: [u8; 4]) -> IpAddr {
+ IpAddr::V4(Ipv4Addr::from(octets))
+ }
+}
+
+impl Ipv6Addr {
+ /// Creates a new IPv6 address from eight 16-bit segments.
+ ///
+ /// The result will represent the IP address a:b:c:d:e:f:g:h.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
+ h: u16) -> Ipv6Addr {
+ let mut addr: c::in6_addr = unsafe { mem::zeroed() };
+ addr.s6_addr = [(a >> 8) as u8, a as u8,
+ (b >> 8) as u8, b as u8,
+ (c >> 8) as u8, c as u8,
+ (d >> 8) as u8, d as u8,
+ (e >> 8) as u8, e as u8,
+ (f >> 8) as u8, f as u8,
+ (g >> 8) as u8, g as u8,
+ (h >> 8) as u8, h as u8];
+ Ipv6Addr { inner: addr }
+ }
+
+ /// Creates a new IPv6 address representing localhost: `::1`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_constructors)]
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::localhost();
+ /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+ /// ```
+ #[unstable(feature = "ip_constructors",
+ reason = "requires greater scrutiny before stabilization",
+ issue = "44582")]
+ pub fn localhost() -> Ipv6Addr {
+ Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)
+ }
+
+ /// Creates a new IPv6 address representing the unspecified address: `::`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_constructors)]
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::unspecified();
+ /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+ /// ```
+ #[unstable(feature = "ip_constructors",
+ reason = "requires greater scrutiny before stabilization",
+ issue = "44582")]
+ pub fn unspecified() -> Ipv6Addr {
+ Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)
+ }
+
+ /// Returns the eight 16-bit segments that make up this address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
+ /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn segments(&self) -> [u16; 8] {
+ let arr = &self.inner.s6_addr;
+ [
+ (arr[0] as u16) << 8 | (arr[1] as u16),
+ (arr[2] as u16) << 8 | (arr[3] as u16),
+ (arr[4] as u16) << 8 | (arr[5] as u16),
+ (arr[6] as u16) << 8 | (arr[7] as u16),
+ (arr[8] as u16) << 8 | (arr[9] as u16),
+ (arr[10] as u16) << 8 | (arr[11] as u16),
+ (arr[12] as u16) << 8 | (arr[13] as u16),
+ (arr[14] as u16) << 8 | (arr[15] as u16),
+ ]
+ }
+
+ /// Returns [`true`] for the special 'unspecified' address (::).
+ ///
+ /// This property is defined in [IETF RFC 4291].
+ ///
+ /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_unspecified(&self) -> bool {
+ self.segments() == [0, 0, 0, 0, 0, 0, 0, 0]
+ }
+
+ /// Returns [`true`] if this is a loopback address (::1).
+ ///
+ /// This property is defined in [IETF RFC 4291].
+ ///
+ /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_loopback(&self) -> bool {
+ self.segments() == [0, 0, 0, 0, 0, 0, 0, 1]
+ }
+
+ /// Returns [`true`] if the address appears to be globally routable.
+ ///
+ /// The following return [`false`]:
+ ///
+ /// - the loopback address
+ /// - link-local, site-local, and unique local unicast addresses
+ /// - interface-, link-, realm-, admin- and site-local multicast addresses
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
+ /// }
+ /// ```
+ pub fn is_global(&self) -> bool {
+ match self.multicast_scope() {
+ Some(Ipv6MulticastScope::Global) => true,
+ None => self.is_unicast_global(),
+ _ => false
+ }
+ }
+
+ /// Returns [`true`] if this is a unique local address (fc00::/7).
+ ///
+ /// This property is defined in [IETF RFC 4193].
+ ///
+ /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(),
+ /// false);
+ /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
+ /// }
+ /// ```
+ pub fn is_unique_local(&self) -> bool {
+ (self.segments()[0] & 0xfe00) == 0xfc00
+ }
+
+ /// Returns [`true`] if the address is unicast and link-local (fe80::/10).
+ ///
+ /// This property is defined in [IETF RFC 4291].
+ ///
+ /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(),
+ /// false);
+ /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
+ /// }
+ /// ```
+ pub fn is_unicast_link_local(&self) -> bool {
+ (self.segments()[0] & 0xffc0) == 0xfe80
+ }
+
+ /// Returns [`true`] if this is a deprecated unicast site-local address
+ /// (fec0::/10).
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(),
+ /// false);
+ /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true);
+ /// }
+ /// ```
+ pub fn is_unicast_site_local(&self) -> bool {
+ (self.segments()[0] & 0xffc0) == 0xfec0
+ }
+
+ /// Returns [`true`] if this is an address reserved for documentation
+ /// (2001:db8::/32).
+ ///
+ /// This property is defined in [IETF RFC 3849].
+ ///
+ /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(),
+ /// false);
+ /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
+ /// }
+ /// ```
+ pub fn is_documentation(&self) -> bool {
+ (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
+ }
+
+ /// Returns [`true`] if the address is a globally routable unicast address.
+ ///
+ /// The following return false:
+ ///
+ /// - the loopback address
+ /// - the link-local addresses
+ /// - the (deprecated) site-local addresses
+ /// - unique local addresses
+ /// - the unspecified address
+ /// - the address range reserved for documentation
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(),
+ /// true);
+ /// }
+ /// ```
+ pub fn is_unicast_global(&self) -> bool {
+ !self.is_multicast()
+ && !self.is_loopback() && !self.is_unicast_link_local()
+ && !self.is_unicast_site_local() && !self.is_unique_local()
+ && !self.is_unspecified() && !self.is_documentation()
+ }
+
+ /// Returns the address's multicast scope if the address is multicast.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::{Ipv6Addr, Ipv6MulticastScope};
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(),
+ /// Some(Ipv6MulticastScope::Global));
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
+ /// }
+ /// ```
+ pub fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
+ if self.is_multicast() {
+ match self.segments()[0] & 0x000f {
+ 1 => Some(Ipv6MulticastScope::InterfaceLocal),
+ 2 => Some(Ipv6MulticastScope::LinkLocal),
+ 3 => Some(Ipv6MulticastScope::RealmLocal),
+ 4 => Some(Ipv6MulticastScope::AdminLocal),
+ 5 => Some(Ipv6MulticastScope::SiteLocal),
+ 8 => Some(Ipv6MulticastScope::OrganizationLocal),
+ 14 => Some(Ipv6MulticastScope::Global),
+ _ => None
+ }
+ } else {
+ None
+ }
+ }
+
+ /// Returns [`true`] if this is a multicast address (ff00::/8).
+ ///
+ /// This property is defined by [IETF RFC 4291].
+ ///
+ /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_multicast(&self) -> bool {
+ (self.segments()[0] & 0xff00) == 0xff00
+ }
+
+ /// Converts this address to an [IPv4 address]. Returns [`None`] if this address is
+ /// neither IPv4-compatible or IPv4-mapped.
+ ///
+ /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d
+ ///
+ /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(),
+ /// Some(Ipv4Addr::new(192, 10, 2, 255)));
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
+ /// Some(Ipv4Addr::new(0, 0, 0, 1)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_ipv4(&self) -> Option<Ipv4Addr> {
+ match self.segments() {
+ [0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => {
+ Some(Ipv4Addr::new((g >> 8) as u8, g as u8,
+ (h >> 8) as u8, h as u8))
+ },
+ _ => None
+ }
+ }
+
+ /// Returns the sixteen eight-bit integers the IPv6 address consists of.
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(),
+ /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+ /// ```
+ #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
+ pub fn octets(&self) -> [u8; 16] {
+ self.inner.s6_addr
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Ipv6Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match self.segments() {
+ // We need special cases for :: and ::1, otherwise they're formatted
+ // as ::0.0.0.[01]
+ [0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"),
+ [0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"),
+ // Ipv4 Compatible address
+ [0, 0, 0, 0, 0, 0, g, h] => {
+ write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8,
+ (h >> 8) as u8, h as u8)
+ }
+ // Ipv4-Mapped address
+ [0, 0, 0, 0, 0, 0xffff, g, h] => {
+ write!(fmt, "::ffff:{}.{}.{}.{}", (g >> 8) as u8, g as u8,
+ (h >> 8) as u8, h as u8)
+ },
+ _ => {
+ fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) {
+ let mut longest_span_len = 0;
+ let mut longest_span_at = 0;
+ let mut cur_span_len = 0;
+ let mut cur_span_at = 0;
+
+ for i in 0..8 {
+ if segments[i] == 0 {
+ if cur_span_len == 0 {
+ cur_span_at = i;
+ }
+
+ cur_span_len += 1;
+
+ if cur_span_len > longest_span_len {
+ longest_span_len = cur_span_len;
+ longest_span_at = cur_span_at;
+ }
+ } else {
+ cur_span_len = 0;
+ cur_span_at = 0;
+ }
+ }
+
+ (longest_span_at, longest_span_len)
+ }
+
+ let (zeros_at, zeros_len) = find_zero_slice(&self.segments());
+
+ if zeros_len > 1 {
+ fn fmt_subslice(segments: &[u16], fmt: &mut fmt::Formatter) -> fmt::Result {
+ if !segments.is_empty() {
+ write!(fmt, "{:x}", segments[0])?;
+ for &seg in &segments[1..] {
+ write!(fmt, ":{:x}", seg)?;
+ }
+ }
+ Ok(())
+ }
+
+ fmt_subslice(&self.segments()[..zeros_at], fmt)?;
+ fmt.write_str("::")?;
+ fmt_subslice(&self.segments()[zeros_at + zeros_len..], fmt)
+ } else {
+ let &[a, b, c, d, e, f, g, h] = &self.segments();
+ write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
+ a, b, c, d, e, f, g, h)
+ }
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Ipv6Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for Ipv6Addr {
+ fn clone(&self) -> Ipv6Addr { *self }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for Ipv6Addr {
+ fn eq(&self, other: &Ipv6Addr) -> bool {
+ self.inner.s6_addr == other.inner.s6_addr
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<IpAddr> for Ipv6Addr {
+ fn eq(&self, other: &IpAddr) -> bool {
+ match *other {
+ IpAddr::V4(_) => false,
+ IpAddr::V6(ref v6) => self == v6,
+ }
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<Ipv6Addr> for IpAddr {
+ fn eq(&self, other: &Ipv6Addr) -> bool {
+ match *self {
+ IpAddr::V4(_) => false,
+ IpAddr::V6(ref v6) => v6 == other,
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for Ipv6Addr {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for Ipv6Addr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ self.inner.s6_addr.hash(s)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for Ipv6Addr {
+ fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<Ipv6Addr> for IpAddr {
+ fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+ match *self {
+ IpAddr::V4(_) => Some(Ordering::Less),
+ IpAddr::V6(ref v6) => v6.partial_cmp(other),
+ }
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<IpAddr> for Ipv6Addr {
+ fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+ match *other {
+ IpAddr::V4(_) => Some(Ordering::Greater),
+ IpAddr::V6(ref v6) => self.partial_cmp(v6),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for Ipv6Addr {
+ fn cmp(&self, other: &Ipv6Addr) -> Ordering {
+ self.segments().cmp(&other.segments())
+ }
+}
+
+impl AsInner<c::in6_addr> for Ipv6Addr {
+ fn as_inner(&self) -> &c::in6_addr { &self.inner }
+}
+impl FromInner<c::in6_addr> for Ipv6Addr {
+ fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
+ Ipv6Addr { inner: addr }
+ }
+}
+
+#[unstable(feature = "i128", issue = "35118")]
+impl From<Ipv6Addr> for u128 {
+ fn from(ip: Ipv6Addr) -> u128 {
+ let ip = ip.segments();
+ ((ip[0] as u128) << 112) + ((ip[1] as u128) << 96) + ((ip[2] as u128) << 80) +
+ ((ip[3] as u128) << 64) + ((ip[4] as u128) << 48) + ((ip[5] as u128) << 32) +
+ ((ip[6] as u128) << 16) + (ip[7] as u128)
+ }
+}
+#[unstable(feature = "i128", issue = "35118")]
+impl From<u128> for Ipv6Addr {
+ fn from(ip: u128) -> Ipv6Addr {
+ Ipv6Addr::new(
+ (ip >> 112) as u16, (ip >> 96) as u16, (ip >> 80) as u16,
+ (ip >> 64) as u16, (ip >> 48) as u16, (ip >> 32) as u16,
+ (ip >> 16) as u16, ip as u16,
+ )
+ }
+}
+
+#[stable(feature = "ipv6_from_octets", since = "1.9.0")]
+impl From<[u8; 16]> for Ipv6Addr {
+ fn from(octets: [u8; 16]) -> Ipv6Addr {
+ let mut inner: c::in6_addr = unsafe { mem::zeroed() };
+ inner.s6_addr = octets;
+ Ipv6Addr::from_inner(inner)
+ }
+}
+
+#[stable(feature = "ipv6_from_segments", since = "1.16.0")]
+impl From<[u16; 8]> for Ipv6Addr {
+ fn from(segments: [u16; 8]) -> Ipv6Addr {
+ let [a, b, c, d, e, f, g, h] = segments;
+ Ipv6Addr::new(a, b, c, d, e, f, g, h)
+ }
+}
+
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u8; 16]> for IpAddr {
+ fn from(octets: [u8; 16]) -> IpAddr {
+ IpAddr::V6(Ipv6Addr::from(octets))
+ }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u16; 8]> for IpAddr {
+ fn from(segments: [u16; 8]) -> IpAddr {
+ IpAddr::V6(Ipv6Addr::from(segments))
+ }
+}
+
+// Tests for this module
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use net::*;
+ use net::Ipv6MulticastScope::*;
+ use net::test::{tsa, sa6, sa4};
+
+ #[test]
+ fn test_from_str_ipv4() {
+ assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
+ assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
+ assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
+
+ // out of range
+ let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
+ assert_eq!(None, none);
+ // too short
+ let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
+ assert_eq!(None, none);
+ // too long
+ let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
+ assert_eq!(None, none);
+ // no number between dots
+ let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
+ assert_eq!(None, none);
+ }
+
+ #[test]
+ fn test_from_str_ipv6() {
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
+
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
+
+ assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)),
+ "2a02:6b8::11:11".parse());
+
+ // too long group
+ let none: Option<Ipv6Addr> = "::00000".parse().ok();
+ assert_eq!(None, none);
+ // too short
+ let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
+ assert_eq!(None, none);
+ // too long
+ let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
+ assert_eq!(None, none);
+ // triple colon
+ let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
+ assert_eq!(None, none);
+ // two double colons
+ let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
+ assert_eq!(None, none);
+ // `::` indicating zero groups of zeros
+ let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
+ assert_eq!(None, none);
+ }
+
+ #[test]
+ fn test_from_str_ipv4_in_ipv6() {
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)),
+ "::192.0.2.33".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)),
+ "::FFFF:192.0.2.33".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
+ "64:ff9b::192.0.2.33".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
+ "2001:db8:122:c000:2:2100:192.0.2.33".parse());
+
+ // colon after v4
+ let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
+ assert_eq!(None, none);
+ // not enough groups
+ let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok();
+ assert_eq!(None, none);
+ // too many groups
+ let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
+ assert_eq!(None, none);
+ }
+
+ #[test]
+ fn test_from_str_socket_addr() {
+ assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)),
+ "77.88.21.11:80".parse());
+ assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)),
+ "77.88.21.11:80".parse());
+ assert_eq!(Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
+ "[2a02:6b8:0:1::1]:53".parse());
+ assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1,
+ 0, 0, 0, 1), 53, 0, 0)),
+ "[2a02:6b8:0:1::1]:53".parse());
+ assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)),
+ "[::127.0.0.1]:22".parse());
+ assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0,
+ 0x7F00, 1), 22, 0, 0)),
+ "[::127.0.0.1]:22".parse());
+
+ // without port
+ let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
+ assert_eq!(None, none);
+ // without port
+ let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
+ assert_eq!(None, none);
+ // wrong brackets around v4
+ let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
+ assert_eq!(None, none);
+ // port out of range
+ let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
+ assert_eq!(None, none);
+ }
+
+ #[test]
+ fn ipv6_addr_to_string() {
+ // ipv4-mapped address
+ let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
+ assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
+
+ // ipv4-compatible address
+ let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
+ assert_eq!(a1.to_string(), "::192.0.2.128");
+
+ // v6 address with no zero segments
+ assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(),
+ "8:9:a:b:c:d:e:f");
+
+ // reduce a single run of zeros
+ assert_eq!("ae::ffff:102:304",
+ Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string());
+
+ // don't reduce just a single zero segment
+ assert_eq!("1:2:3:4:5:6:0:8",
+ Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
+
+ // 'any' address
+ assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+ // loopback address
+ assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
+
+ // ends in zeros
+ assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+ // two runs of zeros, second one is longer
+ assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
+
+ // two runs of zeros, equal length
+ assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
+ }
+
+ #[test]
+ fn ipv4_to_ipv6() {
+ assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
+ Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped());
+ assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
+ Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible());
+ }
+
+ #[test]
+ fn ipv6_to_ipv4() {
+ assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
+ Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)));
+ assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
+ Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)));
+ assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
+ None);
+ }
+
+ #[test]
+ fn ip_properties() {
+ fn check4(octets: &[u8; 4], unspec: bool, loopback: bool,
+ global: bool, multicast: bool, documentation: bool) {
+ let ip = IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]));
+ assert_eq!(ip.is_unspecified(), unspec);
+ assert_eq!(ip.is_loopback(), loopback);
+ assert_eq!(ip.is_global(), global);
+ assert_eq!(ip.is_multicast(), multicast);
+ assert_eq!(ip.is_documentation(), documentation);
+ }
+
+ fn check6(str_addr: &str, unspec: bool, loopback: bool,
+ global: bool, u_doc: bool, mcast: bool) {
+ let ip = IpAddr::V6(str_addr.parse().unwrap());
+ assert_eq!(ip.is_unspecified(), unspec);
+ assert_eq!(ip.is_loopback(), loopback);
+ assert_eq!(ip.is_global(), global);
+ assert_eq!(ip.is_documentation(), u_doc);
+ assert_eq!(ip.is_multicast(), mcast);
+ }
+
+ // address unspec loopbk global multicast doc
+ check4(&[0, 0, 0, 0], true, false, false, false, false);
+ check4(&[0, 0, 0, 1], false, false, true, false, false);
+ check4(&[0, 1, 0, 0], false, false, true, false, false);
+ check4(&[10, 9, 8, 7], false, false, false, false, false);
+ check4(&[127, 1, 2, 3], false, true, false, false, false);
+ check4(&[172, 31, 254, 253], false, false, false, false, false);
+ check4(&[169, 254, 253, 242], false, false, false, false, false);
+ check4(&[192, 0, 2, 183], false, false, false, false, true);
+ check4(&[192, 1, 2, 183], false, false, true, false, false);
+ check4(&[192, 168, 254, 253], false, false, false, false, false);
+ check4(&[198, 51, 100, 0], false, false, false, false, true);
+ check4(&[203, 0, 113, 0], false, false, false, false, true);
+ check4(&[203, 2, 113, 0], false, false, true, false, false);
+ check4(&[224, 0, 0, 0], false, false, true, true, false);
+ check4(&[239, 255, 255, 255], false, false, true, true, false);
+ check4(&[255, 255, 255, 255], false, false, false, false, false);
+
+ // address unspec loopbk global doc mcast
+ check6("::", true, false, false, false, false);
+ check6("::1", false, true, false, false, false);
+ check6("::0.0.0.2", false, false, true, false, false);
+ check6("1::", false, false, true, false, false);
+ check6("fc00::", false, false, false, false, false);
+ check6("fdff:ffff::", false, false, false, false, false);
+ check6("fe80:ffff::", false, false, false, false, false);
+ check6("febf:ffff::", false, false, false, false, false);
+ check6("fec0::", false, false, false, false, false);
+ check6("ff01::", false, false, false, false, true);
+ check6("ff02::", false, false, false, false, true);
+ check6("ff03::", false, false, false, false, true);
+ check6("ff04::", false, false, false, false, true);
+ check6("ff05::", false, false, false, false, true);
+ check6("ff08::", false, false, false, false, true);
+ check6("ff0e::", false, false, true, false, true);
+ check6("2001:db8:85a3::8a2e:370:7334", false, false, false, true, false);
+ check6("102:304:506:708:90a:b0c:d0e:f10", false, false, true, false, false);
+ }
+
+ #[test]
+ fn ipv4_properties() {
+ fn check(octets: &[u8; 4], unspec: bool, loopback: bool,
+ private: bool, link_local: bool, global: bool,
+ multicast: bool, broadcast: bool, documentation: bool) {
+ let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]);
+ assert_eq!(octets, &ip.octets());
+
+ assert_eq!(ip.is_unspecified(), unspec);
+ assert_eq!(ip.is_loopback(), loopback);
+ assert_eq!(ip.is_private(), private);
+ assert_eq!(ip.is_link_local(), link_local);
+ assert_eq!(ip.is_global(), global);
+ assert_eq!(ip.is_multicast(), multicast);
+ assert_eq!(ip.is_broadcast(), broadcast);
+ assert_eq!(ip.is_documentation(), documentation);
+ }
+
+ // address unspec loopbk privt linloc global multicast brdcast doc
+ check(&[0, 0, 0, 0], true, false, false, false, false, false, false, false);
+ check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false);
+ check(&[0, 1, 0, 0], false, false, false, false, true, false, false, false);
+ check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false);
+ check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false);
+ check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false);
+ check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false);
+ check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true);
+ check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false);
+ check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false);
+ check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true);
+ check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true);
+ check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false);
+ check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false);
+ check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false);
+ check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false);
+ }
+
+ #[test]
+ fn ipv6_properties() {
+ fn check(str_addr: &str, octets: &[u8; 16], unspec: bool, loopback: bool,
+ unique_local: bool, global: bool,
+ u_link_local: bool, u_site_local: bool, u_global: bool, u_doc: bool,
+ m_scope: Option<Ipv6MulticastScope>) {
+ let ip: Ipv6Addr = str_addr.parse().unwrap();
+ assert_eq!(str_addr, ip.to_string());
+ assert_eq!(&ip.octets(), octets);
+ assert_eq!(Ipv6Addr::from(*octets), ip);
+
+ assert_eq!(ip.is_unspecified(), unspec);
+ assert_eq!(ip.is_loopback(), loopback);
+ assert_eq!(ip.is_unique_local(), unique_local);
+ assert_eq!(ip.is_global(), global);
+ assert_eq!(ip.is_unicast_link_local(), u_link_local);
+ assert_eq!(ip.is_unicast_site_local(), u_site_local);
+ assert_eq!(ip.is_unicast_global(), u_global);
+ assert_eq!(ip.is_documentation(), u_doc);
+ assert_eq!(ip.multicast_scope(), m_scope);
+ assert_eq!(ip.is_multicast(), m_scope.is_some());
+ }
+
+ // unspec loopbk uniqlo global unill unisl uniglo doc mscope
+ check("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ true, false, false, false, false, false, false, false, None);
+ check("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
+ false, true, false, false, false, false, false, false, None);
+ check("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
+ false, false, false, true, false, false, true, false, None);
+ check("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, true, false, false, true, false, None);
+ check("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, true, false, false, false, false, false, None);
+ check("fdff:ffff::", &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, true, false, false, false, false, false, None);
+ check("fe80:ffff::", &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, true, false, false, false, None);
+ check("febf:ffff::", &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, true, false, false, false, None);
+ check("fec0::", &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, true, false, false, None);
+ check("ff01::", &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(InterfaceLocal));
+ check("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(LinkLocal));
+ check("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(RealmLocal));
+ check("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(AdminLocal));
+ check("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(SiteLocal));
+ check("ff08::", &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(OrganizationLocal));
+ check("ff0e::", &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, true, false, false, false, false, Some(Global));
+ check("2001:db8:85a3::8a2e:370:7334",
+ &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
+ false, false, false, false, false, false, false, true, None);
+ check("102:304:506:708:90a:b0c:d0e:f10",
+ &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
+ false, false, false, true, false, false, true, false, None);
+ }
+
+ #[test]
+ fn to_socket_addr_socketaddr() {
+ let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345);
+ assert_eq!(Ok(vec![a]), tsa(a));
+ }
+
+ #[test]
+ fn test_ipv4_to_int() {
+ let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+ assert_eq!(u32::from(a), 0x11223344);
+ }
+
+ #[test]
+ fn test_int_to_ipv4() {
+ let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+ assert_eq!(Ipv4Addr::from(0x11223344), a);
+ }
+
+ #[test]
+ fn test_ipv6_to_int() {
+ let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+ assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
+ }
+
+ #[test]
+ fn test_int_to_ipv6() {
+ let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+ assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
+ }
+
+ #[test]
+ fn ipv4_from_constructors() {
+ assert_eq!(Ipv4Addr::localhost(), Ipv4Addr::new(127, 0, 0, 1));
+ assert!(Ipv4Addr::localhost().is_loopback());
+ assert_eq!(Ipv4Addr::unspecified(), Ipv4Addr::new(0, 0, 0, 0));
+ assert!(Ipv4Addr::unspecified().is_unspecified());
+ }
+
+ #[test]
+ fn ipv6_from_contructors() {
+ assert_eq!(Ipv6Addr::localhost(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+ assert!(Ipv6Addr::localhost().is_loopback());
+ assert_eq!(Ipv6Addr::unspecified(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+ assert!(Ipv6Addr::unspecified().is_unspecified());
+ }
+
+ #[test]
+ fn ipv4_from_octets() {
+ assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
+ }
+
+ #[test]
+ fn ipv6_from_segments() {
+ let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677,
+ 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+ let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677,
+ 0x8899, 0xaabb, 0xccdd, 0xeeff);
+ assert_eq!(new, from_u16s);
+ }
+
+ #[test]
+ fn ipv6_from_octets() {
+ let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677,
+ 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+ let from_u8s = Ipv6Addr::from([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
+ assert_eq!(from_u16s, from_u8s);
+ }
+
+ #[test]
+ fn cmp() {
+ let v41 = Ipv4Addr::new(100, 64, 3, 3);
+ let v42 = Ipv4Addr::new(192, 0, 2, 2);
+ let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
+ let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
+ assert!(v41 < v42);
+ assert!(v61 < v62);
+
+ assert_eq!(v41, IpAddr::V4(v41));
+ assert_eq!(v61, IpAddr::V6(v61));
+ assert!(v41 != IpAddr::V4(v42));
+ assert!(v61 != IpAddr::V6(v62));
+
+ assert!(v41 < IpAddr::V4(v42));
+ assert!(v61 < IpAddr::V6(v62));
+ assert!(IpAddr::V4(v41) < v42);
+ assert!(IpAddr::V6(v61) < v62);
+
+ assert!(v41 < IpAddr::V6(v61));
+ assert!(IpAddr::V4(v41) < v61);
+ }
+
+ #[test]
+ fn is_v4() {
+ let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
+ assert!(ip.is_ipv4());
+ assert!(!ip.is_ipv6());
+ }
+
+ #[test]
+ fn is_v6() {
+ let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
+ assert!(!ip.is_ipv4());
+ assert!(ip.is_ipv6());
+ }
+}
diff --git a/ctr-std/src/net/mod.rs b/ctr-std/src/net/mod.rs
new file mode 100644
index 0000000..9fcb93e
--- /dev/null
+++ b/ctr-std/src/net/mod.rs
@@ -0,0 +1,186 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! Networking primitives for TCP/UDP communication.
+//!
+//! This module provides networking functionality for the Transmission Control and User
+//! Datagram Protocols, as well as types for IP and socket addresses.
+//!
+//! # Organization
+//!
+//! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP
+//! * [`UdpSocket`] provides functionality for communication over UDP
+//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and
+//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses
+//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`]
+//! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses
+//! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting
+//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`]
+//! * Other types are return or parameter types for various methods in this module
+//!
+//! [`IpAddr`]: ../../std/net/enum.IpAddr.html
+//! [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html
+//! [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html
+//! [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+//! [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+//! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+//! [`TcpListener`]: ../../std/net/struct.TcpListener.html
+//! [`TcpStream`]: ../../std/net/struct.TcpStream.html
+//! [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+//! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fmt;
+use io::{self, Error, ErrorKind};
+use sys_common::net as net_imp;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::tcp::{TcpStream, TcpListener, Incoming};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::udp::UdpSocket;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::parser::AddrParseError;
+
+mod ip;
+mod addr;
+mod tcp;
+mod udp;
+mod parser;
+#[cfg(test)]
+mod test;
+
+/// Possible values which can be passed to the [`shutdown`] method of
+/// [`TcpStream`].
+///
+/// [`shutdown`]: struct.TcpStream.html#method.shutdown
+/// [`TcpStream`]: struct.TcpStream.html
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum Shutdown {
+ /// The reading portion of the [`TcpStream`] should be shut down.
+ ///
+ /// All currently blocked and future [reads] will return [`Ok(0)`].
+ ///
+ /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+ /// [reads]: ../../std/io/trait.Read.html
+ /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Read,
+ /// The writing portion of the [`TcpStream`] should be shut down.
+ ///
+ /// All currently blocked and future [writes] will return an error.
+ ///
+ /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+ /// [writes]: ../../std/io/trait.Write.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Write,
+ /// Both the reading and the writing portions of the [`TcpStream`] should be shut down.
+ ///
+ /// See [`Shutdown::Read`] and [`Shutdown::Write`] for more information.
+ ///
+ /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+ /// [`Shutdown::Read`]: #variant.Read
+ /// [`Shutdown::Write`]: #variant.Write
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Both,
+}
+
+#[doc(hidden)]
+trait NetInt {
+ fn from_be(i: Self) -> Self;
+ fn to_be(&self) -> Self;
+}
+macro_rules! doit {
+ ($($t:ident)*) => ($(impl NetInt for $t {
+ fn from_be(i: Self) -> Self { <$t>::from_be(i) }
+ fn to_be(&self) -> Self { <$t>::to_be(*self) }
+ })*)
+}
+doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
+
+fn hton<I: NetInt>(i: I) -> I { i.to_be() }
+fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }
+
+fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
+ where F: FnMut(&SocketAddr) -> io::Result<T>
+{
+ let mut last_err = None;
+ for addr in addr.to_socket_addrs()? {
+ match f(&addr) {
+ Ok(l) => return Ok(l),
+ Err(e) => last_err = Some(e),
+ }
+ }
+ Err(last_err.unwrap_or_else(|| {
+ Error::new(ErrorKind::InvalidInput,
+ "could not resolve to any addresses")
+ }))
+}
+
+/// An iterator over `SocketAddr` values returned from a host lookup operation.
+#[unstable(feature = "lookup_host", reason = "unsure about the returned \
+ iterator and returning socket \
+ addresses",
+ issue = "27705")]
+pub struct LookupHost(net_imp::LookupHost);
+
+#[unstable(feature = "lookup_host", reason = "unsure about the returned \
+ iterator and returning socket \
+ addresses",
+ issue = "27705")]
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> { self.0.next() }
+}
+
+#[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 { .. }")
+ }
+}
+
+/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
+///
+/// This method may perform a DNS query to resolve `host` and may also inspect
+/// system configuration to resolve the specified hostname.
+///
+/// The returned iterator will skip over any unknown addresses returned by the
+/// operating system.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(lookup_host)]
+///
+/// use std::net;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// for host in net::lookup_host("rust-lang.org")? {
+/// println!("found address: {}", host);
+/// }
+/// # Ok(())
+/// # }
+/// ```
+#[unstable(feature = "lookup_host", reason = "unsure about the returned \
+ iterator and returning socket \
+ addresses",
+ issue = "27705")]
+pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
+ net_imp::lookup_host(host).map(LookupHost)
+}
diff --git a/ctr-std/src/net/parser.rs b/ctr-std/src/net/parser.rs
new file mode 100644
index 0000000..261d44e
--- /dev/null
+++ b/ctr-std/src/net/parser.rs
@@ -0,0 +1,398 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! A private parser implementation of IPv4, IPv6, and socket addresses.
+//!
+//! This module is "publicly exported" through the `FromStr` implementations
+//! below.
+
+use error::Error;
+use fmt;
+use net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+use str::FromStr;
+
+struct Parser<'a> {
+ // parsing as ASCII, so can use byte array
+ s: &'a [u8],
+ pos: usize,
+}
+
+impl<'a> Parser<'a> {
+ fn new(s: &'a str) -> Parser<'a> {
+ Parser {
+ s: s.as_bytes(),
+ pos: 0,
+ }
+ }
+
+ fn is_eof(&self) -> bool {
+ self.pos == self.s.len()
+ }
+
+ // Commit only if parser returns Some
+ fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where
+ F: FnOnce(&mut Parser) -> Option<T>,
+ {
+ let pos = self.pos;
+ let r = cb(self);
+ if r.is_none() {
+ self.pos = pos;
+ }
+ r
+ }
+
+ // Commit only if parser read till EOF
+ fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where
+ F: FnOnce(&mut Parser) -> Option<T>,
+ {
+ self.read_atomically(move |p| {
+ match cb(p) {
+ Some(x) => if p.is_eof() {Some(x)} else {None},
+ None => None,
+ }
+ })
+ }
+
+ // Return result of first successful parser
+ fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T> + 'static>])
+ -> Option<T> {
+ for pf in parsers {
+ if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) {
+ return Some(r);
+ }
+ }
+ None
+ }
+
+ // Apply 3 parsers sequentially
+ fn read_seq_3<A, B, C, PA, PB, PC>(&mut self,
+ pa: PA,
+ pb: PB,
+ pc: PC)
+ -> Option<(A, B, C)> where
+ PA: FnOnce(&mut Parser) -> Option<A>,
+ PB: FnOnce(&mut Parser) -> Option<B>,
+ PC: FnOnce(&mut Parser) -> Option<C>,
+ {
+ self.read_atomically(move |p| {
+ let a = pa(p);
+ let b = if a.is_some() { pb(p) } else { None };
+ let c = if b.is_some() { pc(p) } else { None };
+ match (a, b, c) {
+ (Some(a), Some(b), Some(c)) => Some((a, b, c)),
+ _ => None
+ }
+ })
+ }
+
+ // Read next char
+ fn read_char(&mut self) -> Option<char> {
+ if self.is_eof() {
+ None
+ } else {
+ let r = self.s[self.pos] as char;
+ self.pos += 1;
+ Some(r)
+ }
+ }
+
+ // Return char and advance iff next char is equal to requested
+ fn read_given_char(&mut self, c: char) -> Option<char> {
+ self.read_atomically(|p| {
+ match p.read_char() {
+ Some(next) if next == c => Some(next),
+ _ => None,
+ }
+ })
+ }
+
+ // Read digit
+ fn read_digit(&mut self, radix: u8) -> Option<u8> {
+ fn parse_digit(c: char, radix: u8) -> Option<u8> {
+ let c = c as u8;
+ // assuming radix is either 10 or 16
+ if c >= b'0' && c <= b'9' {
+ Some(c - b'0')
+ } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
+ Some(c - b'a' + 10)
+ } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
+ Some(c - b'A' + 10)
+ } else {
+ None
+ }
+ }
+
+ self.read_atomically(|p| {
+ p.read_char().and_then(|c| parse_digit(c, radix))
+ })
+ }
+
+ fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+ let mut r = 0;
+ let mut digit_count = 0;
+ loop {
+ match self.read_digit(radix) {
+ Some(d) => {
+ r = r * (radix as u32) + (d as u32);
+ digit_count += 1;
+ if digit_count > max_digits || r >= upto {
+ return None
+ }
+ }
+ None => {
+ if digit_count == 0 {
+ return None
+ } else {
+ return Some(r)
+ }
+ }
+ };
+ }
+ }
+
+ // Read number, failing if max_digits of number value exceeded
+ fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+ self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
+ }
+
+ fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> {
+ let mut bs = [0; 4];
+ let mut i = 0;
+ while i < 4 {
+ if i != 0 && self.read_given_char('.').is_none() {
+ return None;
+ }
+
+ bs[i] = self.read_number(10, 3, 0x100).map(|n| n as u8)?;
+ i += 1;
+ }
+ Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
+ }
+
+ // Read IPv4 address
+ fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
+ self.read_atomically(|p| p.read_ipv4_addr_impl())
+ }
+
+ fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> {
+ fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr {
+ assert!(head.len() + tail.len() <= 8);
+ let mut gs = [0; 8];
+ gs[..head.len()].copy_from_slice(head);
+ gs[(8 - tail.len()) .. 8].copy_from_slice(tail);
+ Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
+ }
+
+ fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize)
+ -> (usize, bool) {
+ let mut i = 0;
+ while i < limit {
+ if i < limit - 1 {
+ let ipv4 = p.read_atomically(|p| {
+ if i == 0 || p.read_given_char(':').is_some() {
+ p.read_ipv4_addr()
+ } else {
+ None
+ }
+ });
+ if let Some(v4_addr) = ipv4 {
+ let octets = v4_addr.octets();
+ groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
+ groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
+ return (i + 2, true);
+ }
+ }
+
+ let group = p.read_atomically(|p| {
+ if i == 0 || p.read_given_char(':').is_some() {
+ p.read_number(16, 4, 0x10000).map(|n| n as u16)
+ } else {
+ None
+ }
+ });
+ match group {
+ Some(g) => groups[i] = g,
+ None => return (i, false)
+ }
+ i += 1;
+ }
+ (i, false)
+ }
+
+ let mut head = [0; 8];
+ let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
+
+ if head_size == 8 {
+ return Some(Ipv6Addr::new(
+ head[0], head[1], head[2], head[3],
+ head[4], head[5], head[6], head[7]))
+ }
+
+ // IPv4 part is not allowed before `::`
+ if head_ipv4 {
+ return None
+ }
+
+ // read `::` if previous code parsed less than 8 groups
+ if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
+ return None;
+ }
+
+ let mut tail = [0; 8];
+ // `::` indicates one or more groups of 16 bits of zeros
+ let limit = 8 - (head_size + 1);
+ let (tail_size, _) = read_groups(self, &mut tail, limit);
+ Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
+ }
+
+ fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
+ self.read_atomically(|p| p.read_ipv6_addr_impl())
+ }
+
+ fn read_ip_addr(&mut self) -> Option<IpAddr> {
+ let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(IpAddr::V4);
+ let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(IpAddr::V6);
+ self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
+ }
+
+ fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> {
+ let ip_addr = |p: &mut Parser| p.read_ipv4_addr();
+ let colon = |p: &mut Parser| p.read_given_char(':');
+ let port = |p: &mut Parser| {
+ p.read_number(10, 5, 0x10000).map(|n| n as u16)
+ };
+
+ self.read_seq_3(ip_addr, colon, port).map(|t| {
+ let (ip, _, port): (Ipv4Addr, char, u16) = t;
+ SocketAddrV4::new(ip, port)
+ })
+ }
+
+ fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> {
+ let ip_addr = |p: &mut Parser| {
+ let open_br = |p: &mut Parser| p.read_given_char('[');
+ let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
+ let clos_br = |p: &mut Parser| p.read_given_char(']');
+ p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1)
+ };
+ let colon = |p: &mut Parser| p.read_given_char(':');
+ let port = |p: &mut Parser| {
+ p.read_number(10, 5, 0x10000).map(|n| n as u16)
+ };
+
+ self.read_seq_3(ip_addr, colon, port).map(|t| {
+ let (ip, _, port): (Ipv6Addr, char, u16) = t;
+ SocketAddrV6::new(ip, port, 0, 0)
+ })
+ }
+
+ fn read_socket_addr(&mut self) -> Option<SocketAddr> {
+ let v4 = |p: &mut Parser| p.read_socket_addr_v4().map(SocketAddr::V4);
+ let v6 = |p: &mut Parser| p.read_socket_addr_v6().map(SocketAddr::V6);
+ self.read_or(&mut [Box::new(v4), Box::new(v6)])
+ }
+}
+
+#[stable(feature = "ip_addr", since = "1.7.0")]
+impl FromStr for IpAddr {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(()))
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl FromStr for Ipv4Addr {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(()))
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl FromStr for Ipv6Addr {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(()))
+ }
+ }
+}
+
+#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
+impl FromStr for SocketAddrV4 {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v4()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(())),
+ }
+ }
+}
+
+#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
+impl FromStr for SocketAddrV6 {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v6()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(())),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl FromStr for SocketAddr {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(())),
+ }
+ }
+}
+
+/// An error which can be returned when parsing an IP address or a socket address.
+///
+/// This error is used as the error type for the [`FromStr`] implementation for
+/// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and
+/// [`SocketAddrV6`].
+///
+/// [`FromStr`]: ../../std/str/trait.FromStr.html
+/// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html
+/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html
+/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct AddrParseError(());
+
+#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
+impl fmt::Display for AddrParseError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.write_str(self.description())
+ }
+}
+
+#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
+impl Error for AddrParseError {
+ fn description(&self) -> &str {
+ "invalid IP address syntax"
+ }
+}
diff --git a/ctr-std/src/net/tcp.rs b/ctr-std/src/net/tcp.rs
new file mode 100644
index 0000000..78235ea
--- /dev/null
+++ b/ctr-std/src/net/tcp.rs
@@ -0,0 +1,1662 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 io::prelude::*;
+
+use fmt;
+use io::{self, Initializer};
+use net::{ToSocketAddrs, SocketAddr, Shutdown};
+use sys_common::net as net_imp;
+use sys_common::{AsInner, FromInner, IntoInner};
+use time::Duration;
+
+/// A TCP stream between a local and a remote socket.
+///
+/// After creating a `TcpStream` by either [`connect`]ing to a remote host or
+/// [`accept`]ing a connection on a [`TcpListener`], data can be transmitted
+/// by [reading] and [writing] to it.
+///
+/// The connection will be closed when the value is dropped. The reading and writing
+/// portions of the connection can also be shut down individually with the [`shutdown`]
+/// method.
+///
+/// The Transmission Control Protocol is specified in [IETF RFC 793].
+///
+/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept
+/// [`connect`]: #method.connect
+/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
+/// [reading]: ../../std/io/trait.Read.html
+/// [`shutdown`]: #method.shutdown
+/// [`TcpListener`]: ../../std/net/struct.TcpListener.html
+/// [writing]: ../../std/io/trait.Write.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::net::TcpStream;
+///
+/// {
+/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+///
+/// // ignore the Result
+/// let _ = stream.write(&[1]);
+/// let _ = stream.read(&mut [0; 128]); // ignore here too
+/// } // the stream is closed here
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct TcpStream(net_imp::TcpStream);
+
+/// A TCP socket server, listening for connections.
+///
+/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens
+/// for incoming TCP connections. These can be accepted by calling [`accept`] or by
+/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`].
+///
+/// The socket will be closed when the value is dropped.
+///
+/// The Transmission Control Protocol is specified in [IETF RFC 793].
+///
+/// [`accept`]: #method.accept
+/// [`bind`]: #method.bind
+/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
+/// [`Incoming`]: ../../std/net/struct.Incoming.html
+/// [`TcpListener::incoming`]: #method.incoming
+///
+/// # Examples
+///
+/// ```
+/// # use std::io;
+/// use std::net::{TcpListener, TcpStream};
+///
+/// fn handle_client(stream: TcpStream) {
+/// // ...
+/// }
+///
+/// # fn process() -> io::Result<()> {
+/// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+///
+/// // accept connections and process them serially
+/// for stream in listener.incoming() {
+/// handle_client(stream?);
+/// }
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct TcpListener(net_imp::TcpListener);
+
+/// An iterator that infinitely [`accept`]s connections on a [`TcpListener`].
+///
+/// This `struct` is created by the [`incoming`] method on [`TcpListener`].
+/// See its documentation for more.
+///
+/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept
+/// [`incoming`]: ../../std/net/struct.TcpListener.html#method.incoming
+/// [`TcpListener`]: ../../std/net/struct.TcpListener.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub struct Incoming<'a> { listener: &'a TcpListener }
+
+impl TcpStream {
+ /// Opens a TCP connection to a remote host.
+ ///
+ /// `addr` is an address of the remote host. Anything which implements
+ /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait
+ /// documentation for concrete examples.
+ ///
+ /// If `addr` yields multiple addresses, `connect` will be attempted with
+ /// each of the addresses until a connection is successful. If none of
+ /// the addresses result in a successful connection, the error returned from
+ /// the last connection attempt (the last address) is returned.
+ ///
+ /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+ ///
+ /// # Examples
+ ///
+ /// Open a TCP connection to `127.0.0.1:8080`:
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// if let Ok(stream) = TcpStream::connect("127.0.0.1:8080") {
+ /// println!("Connected to the server!");
+ /// } else {
+ /// println!("Couldn't connect to server...");
+ /// }
+ /// ```
+ ///
+ /// Open a TCP connection to `127.0.0.1:8080`. If the connection fails, open
+ /// a TCP connection to `127.0.0.1:8081`:
+ ///
+ /// ```no_run
+ /// use std::net::{SocketAddr, TcpStream};
+ ///
+ /// let addrs = [
+ /// SocketAddr::from(([127, 0, 0, 1], 8080)),
+ /// SocketAddr::from(([127, 0, 0, 1], 8081)),
+ /// ];
+ /// if let Ok(stream) = TcpStream::connect(&addrs[..]) {
+ /// println!("Connected to the server!");
+ /// } else {
+ /// println!("Couldn't connect to server...");
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
+ super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream)
+ }
+
+ /// Opens a TCP connection to a remote host with a timeout.
+ ///
+ /// Unlike `connect`, `connect_timeout` takes a single [`SocketAddr`] since
+ /// timeout must be applied to individual addresses.
+ ///
+ /// It is an error to pass a zero `Duration` to this function.
+ ///
+ /// Unlike other methods on `TcpStream`, this does not correspond to a
+ /// single system call. It instead calls `connect` in nonblocking mode and
+ /// then uses an OS-specific mechanism to await the completion of the
+ /// connection request.
+ ///
+ /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+ #[stable(feature = "tcpstream_connect_timeout", since = "1.21.0")]
+ pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
+ net_imp::TcpStream::connect_timeout(addr, timeout).map(TcpStream)
+ }
+
+ /// Returns the socket address of the remote peer of this TCP connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream};
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// assert_eq!(stream.peer_addr().unwrap(),
+ /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ self.0.peer_addr()
+ }
+
+ /// Returns the socket address of the local half of this TCP connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{IpAddr, Ipv4Addr, TcpStream};
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// assert_eq!(stream.local_addr().unwrap().ip(),
+ /// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.0.socket_addr()
+ }
+
+ /// Shuts down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O on the specified
+ /// portions to return immediately with an appropriate value (see the
+ /// documentation of [`Shutdown`]).
+ ///
+ /// [`Shutdown`]: ../../std/net/enum.Shutdown.html
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// Calling this function multiple times may result in different behavior,
+ /// depending on the operating system. On Linux, the second call will
+ /// return `Ok(())`, but on macOS, it will return `ErrorKind::NotConnected`.
+ /// This may change in the future.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{Shutdown, TcpStream};
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.shutdown(Shutdown::Both).expect("shutdown call failed");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `TcpStream` is a reference to the same stream that this
+ /// object references. Both handles will read and write the same stream of
+ /// data, and options set on one stream will be propagated to the other
+ /// stream.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// let stream_clone = stream.try_clone().expect("clone failed...");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_clone(&self) -> io::Result<TcpStream> {
+ self.0.duplicate().map(TcpStream)
+ }
+
+ /// Sets the read timeout to the timeout specified.
+ ///
+ /// If the value specified is [`None`], then [`read`] calls will block
+ /// indefinitely. It is an error to pass the zero `Duration` to this
+ /// method.
+ ///
+ /// # Note
+ ///
+ /// Platforms may return a different error code whenever a read times out as
+ /// a result of setting this option. For example Unix typically returns an
+ /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`].
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`read`]: ../../std/io/trait.Read.html#tymethod.read
+ /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock
+ /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_read_timeout(None).expect("set_read_timeout call failed");
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_read_timeout(dur)
+ }
+
+ /// Sets the write timeout to the timeout specified.
+ ///
+ /// If the value specified is [`None`], then [`write`] calls will block
+ /// indefinitely. It is an error to pass the zero [`Duration`] to this
+ /// method.
+ ///
+ /// # Note
+ ///
+ /// Platforms may return a different error code whenever a write times out
+ /// as a result of setting this option. For example Unix typically returns
+ /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`].
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock
+ /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_write_timeout(None).expect("set_write_timeout call failed");
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_write_timeout(dur)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// If the timeout is [`None`], then [`read`] calls will block indefinitely.
+ ///
+ /// # Note
+ ///
+ /// Some platforms do not provide access to the current timeout.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`read`]: ../../std/io/trait.Read.html#tymethod.read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_read_timeout(None).expect("set_read_timeout call failed");
+ /// assert_eq!(stream.read_timeout().unwrap(), None);
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.read_timeout()
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// If the timeout is [`None`], then [`write`] calls will block indefinitely.
+ ///
+ /// # Note
+ ///
+ /// Some platforms do not provide access to the current timeout.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_write_timeout(None).expect("set_write_timeout call failed");
+ /// assert_eq!(stream.write_timeout().unwrap(), None);
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.write_timeout()
+ }
+
+ /// Receives data on the socket from the remote address 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
+ /// 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");
+ /// ```
+ #[stable(feature = "peek", since = "1.18.0")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ 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
+ /// segments are always sent as soon as possible, even if there is only a
+ /// small amount of data. When not set, data is buffered until there is a
+ /// sufficient amount to send out, thereby avoiding the frequent sending of
+ /// small packets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_nodelay(true).expect("set_nodelay call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ self.0.set_nodelay(nodelay)
+ }
+
+ /// Gets the value of the `TCP_NODELAY` option on this socket.
+ ///
+ /// For more information about this option, see [`set_nodelay`][link].
+ ///
+ /// [link]: #method.set_nodelay
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_nodelay(true).expect("set_nodelay call failed");
+ /// assert_eq!(stream.nodelay().unwrap_or(false), true);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn nodelay(&self) -> io::Result<bool> {
+ self.0.nodelay()
+ }
+
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This value sets the time-to-live field that is used in every packet sent
+ /// from this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_ttl(100).expect("set_ttl call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.0.set_ttl(ttl)
+ }
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see [`set_ttl`][link].
+ ///
+ /// [link]: #method.set_ttl
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_ttl(100).expect("set_ttl call failed");
+ /// assert_eq!(stream.ttl().unwrap_or(0), 100);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.0.ttl()
+ }
+
+ /// Get the value of the `SO_ERROR` option on this socket.
+ ///
+ /// This will retrieve the stored error in the underlying socket, clearing
+ /// the field in the process. This can be useful for checking errors between
+ /// calls.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.take_error().expect("No error was expected...");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Moves this TCP stream into or out of nonblocking mode.
+ ///
+ /// This will result in `read`, `write`, `recv` and `send` operations
+ /// becoming nonblocking, i.e. immediately returning from their calls.
+ /// If the IO operation is successful, `Ok` is returned and no further
+ /// action is required. If the IO operation could not be completed and needs
+ /// to be retried, an error with kind [`io::ErrorKind::WouldBlock`] is
+ /// returned.
+ ///
+ /// On Unix platforms, calling this method corresponds to calling `fcntl`
+ /// `FIONBIO`. On Windows calling this method corresponds to calling
+ /// `ioctlsocket` `FIONBIO`.
+ ///
+ /// # Examples
+ ///
+ /// Reading bytes from a TCP stream in non-blocking mode:
+ ///
+ /// ```no_run
+ /// use std::io::{self, Read};
+ /// use std::net::TcpStream;
+ ///
+ /// let mut stream = TcpStream::connect("127.0.0.1:7878")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_nonblocking(true).expect("set_nonblocking call failed");
+ ///
+ /// # fn wait_for_fd() { unimplemented!() }
+ /// let mut buf = vec![];
+ /// loop {
+ /// match stream.read_to_end(&mut buf) {
+ /// Ok(_) => break,
+ /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+ /// // wait until network socket is ready, typically implemented
+ /// // via platform-specific APIs such as epoll or IOCP
+ /// wait_for_fd();
+ /// }
+ /// Err(e) => panic!("encountered IO error: {}", e),
+ /// };
+ /// };
+ /// println!("bytes: {:?}", buf);
+ /// ```
+ ///
+ /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for TcpStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for TcpStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Read for &'a TcpStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Write for &'a TcpStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+impl AsInner<net_imp::TcpStream> for TcpStream {
+ fn as_inner(&self) -> &net_imp::TcpStream { &self.0 }
+}
+
+impl FromInner<net_imp::TcpStream> for TcpStream {
+ fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) }
+}
+
+impl IntoInner<net_imp::TcpStream> for TcpStream {
+ fn into_inner(self) -> net_imp::TcpStream { self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl TcpListener {
+ /// Creates a new `TcpListener` which will be bound to the specified
+ /// address.
+ ///
+ /// The returned listener is ready for accepting connections.
+ ///
+ /// Binding with a port number of 0 will request that the OS assigns a port
+ /// to this listener. The port allocated can be queried via the
+ /// [`local_addr`] method.
+ ///
+ /// The address type can be any implementor of [`ToSocketAddrs`] trait. See
+ /// its documentation for concrete examples.
+ ///
+ /// If `addr` yields multiple addresses, `bind` will be attempted with
+ /// each of the addresses until one succeeds and returns the listener. If
+ /// none of the addresses succeed in creating a listener, the error returned
+ /// from the last attempt (the last address) is returned.
+ ///
+ /// [`local_addr`]: #method.local_addr
+ /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+ ///
+ /// # Examples
+ ///
+ /// Create a TCP listener bound to `127.0.0.1:80`:
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ /// ```
+ ///
+ /// Create a TCP listener bound to `127.0.0.1:80`. If that fails, create a
+ /// TCP listener bound to `127.0.0.1:443`:
+ ///
+ /// ```no_run
+ /// use std::net::{SocketAddr, TcpListener};
+ ///
+ /// let addrs = [
+ /// SocketAddr::from(([127, 0, 0, 1], 80)),
+ /// SocketAddr::from(([127, 0, 0, 1], 443)),
+ /// ];
+ /// let listener = TcpListener::bind(&addrs[..]).unwrap();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
+ super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener)
+ }
+
+ /// Returns the local socket address of this listener.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener};
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
+ /// assert_eq!(listener.local_addr().unwrap(),
+ /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.0.socket_addr()
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned [`TcpListener`] is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one listener will affect the other.
+ ///
+ /// [`TcpListener`]: ../../std/net/struct.TcpListener.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
+ /// let listener_clone = listener.try_clone().unwrap();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_clone(&self) -> io::Result<TcpListener> {
+ self.0.duplicate().map(TcpListener)
+ }
+
+ /// Accept a new incoming connection from this listener.
+ ///
+ /// This function will block the calling thread until a new TCP connection
+ /// is established. When established, the corresponding [`TcpStream`] and the
+ /// remote peer's address will be returned.
+ ///
+ /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
+ /// match listener.accept() {
+ /// Ok((_socket, addr)) => println!("new client: {:?}", addr),
+ /// Err(e) => println!("couldn't get client: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ self.0.accept().map(|(a, b)| (TcpStream(a), b))
+ }
+
+ /// Returns an iterator over the connections being received on this
+ /// listener.
+ ///
+ /// The returned iterator will never return [`None`] and will also not yield
+ /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to
+ /// calling [`accept`] in a loop.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+ /// [`accept`]: #method.accept
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ ///
+ /// for stream in listener.incoming() {
+ /// match stream {
+ /// Ok(stream) => {
+ /// println!("new client!");
+ /// }
+ /// Err(e) => { /* connection failed */ }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn incoming(&self) -> Incoming {
+ Incoming { listener: self }
+ }
+
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This value sets the time-to-live field that is used in every packet sent
+ /// from this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ /// listener.set_ttl(100).expect("could not set TTL");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.0.set_ttl(ttl)
+ }
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see [`set_ttl`][link].
+ ///
+ /// [link]: #method.set_ttl
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ /// listener.set_ttl(100).expect("could not set TTL");
+ /// assert_eq!(listener.ttl().unwrap_or(0), 100);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.0.ttl()
+ }
+
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ #[rustc_deprecated(since = "1.16.0",
+ reason = "this option can only be set before the socket is bound")]
+ #[allow(missing_docs)]
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ self.0.set_only_v6(only_v6)
+ }
+
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ #[rustc_deprecated(since = "1.16.0",
+ reason = "this option can only be set before the socket is bound")]
+ #[allow(missing_docs)]
+ pub fn only_v6(&self) -> io::Result<bool> {
+ self.0.only_v6()
+ }
+
+ /// Get the value of the `SO_ERROR` option on this socket.
+ ///
+ /// This will retrieve the stored error in the underlying socket, clearing
+ /// the field in the process. This can be useful for checking errors between
+ /// calls.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ /// listener.take_error().expect("No error was expected");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Moves this TCP stream into or out of nonblocking mode.
+ ///
+ /// This will result in the `accept` operation becoming nonblocking,
+ /// i.e. immediately returning from their calls. If the IO operation is
+ /// successful, `Ok` is returned and no further action is required. If the
+ /// IO operation could not be completed and needs to be retried, an error
+ /// with kind [`io::ErrorKind::WouldBlock`] is returned.
+ ///
+ /// On Unix platforms, calling this method corresponds to calling `fcntl`
+ /// `FIONBIO`. On Windows calling this method corresponds to calling
+ /// `ioctlsocket` `FIONBIO`.
+ ///
+ /// # Examples
+ ///
+ /// Bind a TCP listener to an address, listen for connections, and read
+ /// bytes in nonblocking mode:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
+ /// listener.set_nonblocking(true).expect("Cannot set non-blocking");
+ ///
+ /// # fn wait_for_fd() { unimplemented!() }
+ /// # fn handle_connection(stream: std::net::TcpStream) { unimplemented!() }
+ /// for stream in listener.incoming() {
+ /// match stream {
+ /// Ok(s) => {
+ /// // do something with the TcpStream
+ /// handle_connection(s);
+ /// }
+ /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+ /// // wait until network socket is ready, typically implemented
+ /// // via platform-specific APIs such as epoll or IOCP
+ /// wait_for_fd();
+ /// continue;
+ /// }
+ /// Err(e) => panic!("encountered IO error: {}", e),
+ /// }
+ /// }
+ /// ```
+ ///
+ /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for Incoming<'a> {
+ type Item = io::Result<TcpStream>;
+ fn next(&mut self) -> Option<io::Result<TcpStream>> {
+ Some(self.listener.accept().map(|p| p.0))
+ }
+}
+
+impl AsInner<net_imp::TcpListener> for TcpListener {
+ fn as_inner(&self) -> &net_imp::TcpListener { &self.0 }
+}
+
+impl FromInner<net_imp::TcpListener> for TcpListener {
+ fn from_inner(inner: net_imp::TcpListener) -> TcpListener {
+ TcpListener(inner)
+ }
+}
+
+impl IntoInner<net_imp::TcpListener> for TcpListener {
+ fn into_inner(self) -> net_imp::TcpListener { self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
+mod tests {
+ use io::ErrorKind;
+ use io::prelude::*;
+ use net::*;
+ use net::test::{next_test_ip4, next_test_ip6};
+ use sync::mpsc::channel;
+ use sys_common::AsInner;
+ use time::{Instant, Duration};
+ use thread;
+
+ fn each_ip(f: &mut FnMut(SocketAddr)) {
+ f(next_test_ip4());
+ f(next_test_ip6());
+ }
+
+ macro_rules! t {
+ ($e:expr) => {
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+ }
+ }
+ }
+
+ #[test]
+ fn bind_error() {
+ match TcpListener::bind("1.1.1.1:9999") {
+ Ok(..) => panic!(),
+ Err(e) =>
+ assert_eq!(e.kind(), ErrorKind::AddrNotAvailable),
+ }
+ }
+
+ #[test]
+ fn connect_error() {
+ match TcpStream::connect("0.0.0.0:1") {
+ Ok(..) => panic!(),
+ Err(e) => assert!(e.kind() == ErrorKind::ConnectionRefused ||
+ e.kind() == ErrorKind::InvalidInput ||
+ e.kind() == ErrorKind::AddrInUse ||
+ e.kind() == ErrorKind::AddrNotAvailable,
+ "bad error: {} {:?}", e, e.kind()),
+ }
+ }
+
+ #[test]
+ fn listen_localhost() {
+ let socket_addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&socket_addr));
+
+ let _t = thread::spawn(move || {
+ let mut stream = t!(TcpStream::connect(&("localhost",
+ socket_addr.port())));
+ t!(stream.write(&[144]));
+ });
+
+ let mut stream = t!(listener.accept()).0;
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == 144);
+ }
+
+ #[test]
+ fn connect_loopback() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let host = match addr {
+ SocketAddr::V4(..) => "127.0.0.1",
+ SocketAddr::V6(..) => "::1",
+ };
+ let mut stream = t!(TcpStream::connect(&(host, addr.port())));
+ t!(stream.write(&[66]));
+ });
+
+ let mut stream = t!(acceptor.accept()).0;
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == 66);
+ })
+ }
+
+ #[test]
+ fn smoke_test() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut stream = t!(TcpStream::connect(&addr));
+ t!(stream.write(&[99]));
+ tx.send(t!(stream.local_addr())).unwrap();
+ });
+
+ let (mut stream, addr) = t!(acceptor.accept());
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == 99);
+ assert_eq!(addr, t!(rx.recv()));
+ })
+ }
+
+ #[test]
+ fn read_eof() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let _stream = t!(TcpStream::connect(&addr));
+ // Close
+ });
+
+ let mut stream = t!(acceptor.accept()).0;
+ let mut buf = [0];
+ let nread = t!(stream.read(&mut buf));
+ assert_eq!(nread, 0);
+ let nread = t!(stream.read(&mut buf));
+ assert_eq!(nread, 0);
+ })
+ }
+
+ #[test]
+ fn write_close() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| {
+ drop(t!(TcpStream::connect(&addr)));
+ tx.send(()).unwrap();
+ });
+
+ let mut stream = t!(acceptor.accept()).0;
+ rx.recv().unwrap();
+ let buf = [0];
+ match stream.write(&buf) {
+ Ok(..) => {}
+ Err(e) => {
+ assert!(e.kind() == ErrorKind::ConnectionReset ||
+ e.kind() == ErrorKind::BrokenPipe ||
+ e.kind() == ErrorKind::ConnectionAborted,
+ "unknown error: {}", e);
+ }
+ }
+ })
+ }
+
+ #[test]
+ fn multiple_connect_serial() {
+ each_ip(&mut |addr| {
+ let max = 10;
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ for _ in 0..max {
+ let mut stream = t!(TcpStream::connect(&addr));
+ t!(stream.write(&[99]));
+ }
+ });
+
+ for stream in acceptor.incoming().take(max) {
+ let mut stream = t!(stream);
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert_eq!(buf[0], 99);
+ }
+ })
+ }
+
+ #[test]
+ fn multiple_connect_interleaved_greedy_schedule() {
+ const MAX: usize = 10;
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let acceptor = acceptor;
+ for (i, stream) in acceptor.incoming().enumerate().take(MAX) {
+ // Start another thread to handle the connection
+ let _t = thread::spawn(move|| {
+ let mut stream = t!(stream);
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == i as u8);
+ });
+ }
+ });
+
+ connect(0, addr);
+ });
+
+ fn connect(i: usize, addr: SocketAddr) {
+ if i == MAX { return }
+
+ let t = thread::spawn(move|| {
+ let mut stream = t!(TcpStream::connect(&addr));
+ // Connect again before writing
+ connect(i + 1, addr);
+ t!(stream.write(&[i as u8]));
+ });
+ t.join().ok().unwrap();
+ }
+ }
+
+ #[test]
+ fn multiple_connect_interleaved_lazy_schedule() {
+ const MAX: usize = 10;
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ for stream in acceptor.incoming().take(MAX) {
+ // Start another thread to handle the connection
+ let _t = thread::spawn(move|| {
+ let mut stream = t!(stream);
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == 99);
+ });
+ }
+ });
+
+ connect(0, addr);
+ });
+
+ fn connect(i: usize, addr: SocketAddr) {
+ if i == MAX { return }
+
+ let t = thread::spawn(move|| {
+ let mut stream = t!(TcpStream::connect(&addr));
+ connect(i + 1, addr);
+ t!(stream.write(&[99]));
+ });
+ t.join().ok().unwrap();
+ }
+ }
+
+ #[test]
+ fn socket_and_peer_name() {
+ each_ip(&mut |addr| {
+ let listener = t!(TcpListener::bind(&addr));
+ let so_name = t!(listener.local_addr());
+ assert_eq!(addr, so_name);
+ let _t = thread::spawn(move|| {
+ t!(listener.accept());
+ });
+
+ let stream = t!(TcpStream::connect(&addr));
+ assert_eq!(addr, t!(stream.peer_addr()));
+ })
+ }
+
+ #[test]
+ fn partial_read() {
+ each_ip(&mut |addr| {
+ let (tx, rx) = channel();
+ let srv = t!(TcpListener::bind(&addr));
+ let _t = thread::spawn(move|| {
+ let mut cl = t!(srv.accept()).0;
+ cl.write(&[10]).unwrap();
+ let mut b = [0];
+ t!(cl.read(&mut b));
+ tx.send(()).unwrap();
+ });
+
+ let mut c = t!(TcpStream::connect(&addr));
+ let mut b = [0; 10];
+ assert_eq!(c.read(&mut b).unwrap(), 1);
+ t!(c.write(&[1]));
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn double_bind() {
+ each_ip(&mut |addr| {
+ let _listener = t!(TcpListener::bind(&addr));
+ match TcpListener::bind(&addr) {
+ Ok(..) => panic!(),
+ Err(e) => {
+ assert!(e.kind() == ErrorKind::ConnectionRefused ||
+ e.kind() == ErrorKind::Other ||
+ e.kind() == ErrorKind::AddrInUse,
+ "unknown error: {} {:?}", e, e.kind());
+ }
+ }
+ })
+ }
+
+ #[test]
+ fn fast_rebind() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ t!(TcpStream::connect(&addr));
+ });
+
+ t!(acceptor.accept());
+ drop(acceptor);
+ t!(TcpListener::bind(&addr));
+ });
+ }
+
+ #[test]
+ fn tcp_clone_smoke() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let mut s = t!(TcpStream::connect(&addr));
+ let mut buf = [0, 0];
+ assert_eq!(s.read(&mut buf).unwrap(), 1);
+ assert_eq!(buf[0], 1);
+ t!(s.write(&[2]));
+ });
+
+ let mut s1 = t!(acceptor.accept()).0;
+ let s2 = t!(s1.try_clone());
+
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+ let _t = thread::spawn(move|| {
+ let mut s2 = s2;
+ rx1.recv().unwrap();
+ t!(s2.write(&[1]));
+ tx2.send(()).unwrap();
+ });
+ tx1.send(()).unwrap();
+ let mut buf = [0, 0];
+ assert_eq!(s1.read(&mut buf).unwrap(), 1);
+ rx2.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn tcp_clone_two_read() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+ let (tx1, rx) = channel();
+ let tx2 = tx1.clone();
+
+ let _t = thread::spawn(move|| {
+ let mut s = t!(TcpStream::connect(&addr));
+ t!(s.write(&[1]));
+ rx.recv().unwrap();
+ t!(s.write(&[2]));
+ rx.recv().unwrap();
+ });
+
+ let mut s1 = t!(acceptor.accept()).0;
+ let s2 = t!(s1.try_clone());
+
+ let (done, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut s2 = s2;
+ let mut buf = [0, 0];
+ t!(s2.read(&mut buf));
+ tx2.send(()).unwrap();
+ done.send(()).unwrap();
+ });
+ let mut buf = [0, 0];
+ t!(s1.read(&mut buf));
+ tx1.send(()).unwrap();
+
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn tcp_clone_two_write() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let mut s = t!(TcpStream::connect(&addr));
+ let mut buf = [0, 1];
+ t!(s.read(&mut buf));
+ t!(s.read(&mut buf));
+ });
+
+ let mut s1 = t!(acceptor.accept()).0;
+ let s2 = t!(s1.try_clone());
+
+ let (done, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut s2 = s2;
+ t!(s2.write(&[1]));
+ done.send(()).unwrap();
+ });
+ t!(s1.write(&[2]));
+
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn shutdown_smoke() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let _t = thread::spawn(move|| {
+ let mut c = t!(a.accept()).0;
+ let mut b = [0];
+ assert_eq!(c.read(&mut b).unwrap(), 0);
+ t!(c.write(&[1]));
+ });
+
+ let mut s = t!(TcpStream::connect(&addr));
+ t!(s.shutdown(Shutdown::Write));
+ assert!(s.write(&[1]).is_err());
+ let mut b = [0, 0];
+ assert_eq!(t!(s.read(&mut b)), 1);
+ assert_eq!(b[0], 1);
+ })
+ }
+
+ #[test]
+ fn close_readwrite_smoke() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let (tx, rx) = channel::<()>();
+ let _t = thread::spawn(move|| {
+ let _s = t!(a.accept());
+ let _ = rx.recv();
+ });
+
+ let mut b = [0];
+ let mut s = t!(TcpStream::connect(&addr));
+ let mut s2 = t!(s.try_clone());
+
+ // closing should prevent reads/writes
+ t!(s.shutdown(Shutdown::Write));
+ assert!(s.write(&[0]).is_err());
+ t!(s.shutdown(Shutdown::Read));
+ assert_eq!(s.read(&mut b).unwrap(), 0);
+
+ // closing should affect previous handles
+ assert!(s2.write(&[0]).is_err());
+ assert_eq!(s2.read(&mut b).unwrap(), 0);
+
+ // closing should affect new handles
+ let mut s3 = t!(s.try_clone());
+ assert!(s3.write(&[0]).is_err());
+ assert_eq!(s3.read(&mut b).unwrap(), 0);
+
+ // make sure these don't die
+ let _ = s2.shutdown(Shutdown::Read);
+ let _ = s2.shutdown(Shutdown::Write);
+ let _ = s3.shutdown(Shutdown::Read);
+ let _ = s3.shutdown(Shutdown::Write);
+ drop(tx);
+ })
+ }
+
+ #[test]
+ #[cfg(unix)] // test doesn't work on Windows, see #31657
+ fn close_read_wakes_up() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let (tx1, rx) = channel::<()>();
+ let _t = thread::spawn(move|| {
+ let _s = t!(a.accept());
+ let _ = rx.recv();
+ });
+
+ let s = t!(TcpStream::connect(&addr));
+ let s2 = t!(s.try_clone());
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut s2 = s2;
+ assert_eq!(t!(s2.read(&mut [0])), 0);
+ tx.send(()).unwrap();
+ });
+ // this should wake up the child thread
+ t!(s.shutdown(Shutdown::Read));
+
+ // this test will never finish if the child doesn't wake up
+ rx.recv().unwrap();
+ drop(tx1);
+ })
+ }
+
+ #[test]
+ fn clone_while_reading() {
+ each_ip(&mut |addr| {
+ let accept = t!(TcpListener::bind(&addr));
+
+ // Enqueue a thread to write to a socket
+ let (tx, rx) = channel();
+ let (txdone, rxdone) = channel();
+ let txdone2 = txdone.clone();
+ let _t = thread::spawn(move|| {
+ let mut tcp = t!(TcpStream::connect(&addr));
+ rx.recv().unwrap();
+ t!(tcp.write(&[0]));
+ txdone2.send(()).unwrap();
+ });
+
+ // Spawn off a reading clone
+ let tcp = t!(accept.accept()).0;
+ let tcp2 = t!(tcp.try_clone());
+ let txdone3 = txdone.clone();
+ let _t = thread::spawn(move|| {
+ let mut tcp2 = tcp2;
+ t!(tcp2.read(&mut [0]));
+ txdone3.send(()).unwrap();
+ });
+
+ // Try to ensure that the reading clone is indeed reading
+ for _ in 0..50 {
+ thread::yield_now();
+ }
+
+ // clone the handle again while it's reading, then let it finish the
+ // read.
+ let _ = t!(tcp.try_clone());
+ tx.send(()).unwrap();
+ rxdone.recv().unwrap();
+ rxdone.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn clone_accept_smoke() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let a2 = t!(a.try_clone());
+
+ let _t = thread::spawn(move|| {
+ let _ = TcpStream::connect(&addr);
+ });
+ let _t = thread::spawn(move|| {
+ let _ = TcpStream::connect(&addr);
+ });
+
+ t!(a.accept());
+ t!(a2.accept());
+ })
+ }
+
+ #[test]
+ fn clone_accept_concurrent() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let a2 = t!(a.try_clone());
+
+ let (tx, rx) = channel();
+ let tx2 = tx.clone();
+
+ let _t = thread::spawn(move|| {
+ tx.send(t!(a.accept())).unwrap();
+ });
+ let _t = thread::spawn(move|| {
+ tx2.send(t!(a2.accept())).unwrap();
+ });
+
+ let _t = thread::spawn(move|| {
+ let _ = TcpStream::connect(&addr);
+ });
+ let _t = thread::spawn(move|| {
+ let _ = TcpStream::connect(&addr);
+ });
+
+ rx.recv().unwrap();
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn debug() {
+ let name = if cfg!(windows) {"socket"} else {"fd"};
+ let socket_addr = next_test_ip4();
+
+ let listener = t!(TcpListener::bind(&socket_addr));
+ let listener_inner = listener.0.socket().as_inner();
+ let compare = format!("TcpListener {{ addr: {:?}, {}: {:?} }}",
+ socket_addr, name, listener_inner);
+ assert_eq!(format!("{:?}", listener), compare);
+
+ let stream = t!(TcpStream::connect(&("localhost",
+ socket_addr.port())));
+ let stream_inner = stream.0.socket().as_inner();
+ let compare = format!("TcpStream {{ addr: {:?}, \
+ peer: {:?}, {}: {:?} }}",
+ stream.local_addr().unwrap(),
+ stream.peer_addr().unwrap(),
+ name,
+ stream_inner);
+ assert_eq!(format!("{:?}", stream), compare);
+ }
+
+ // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code
+ // no longer has rounding errors.
+ #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)]
+ #[test]
+ fn timeouts() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+ let dur = Duration::new(15410, 0);
+
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_read_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.read_timeout()));
+
+ assert_eq!(None, t!(stream.write_timeout()));
+
+ t!(stream.set_write_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.write_timeout()));
+
+ t!(stream.set_read_timeout(None));
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_write_timeout(None));
+ assert_eq!(None, t!(stream.write_timeout()));
+ drop(listener);
+ }
+
+ #[test]
+ fn test_read_timeout() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut buf = [0; 10];
+ let start = Instant::now();
+ let kind = stream.read(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
+ assert!(start.elapsed() > Duration::from_millis(400));
+ drop(listener);
+ }
+
+ #[test]
+ fn test_read_with_timeout() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut other_end = t!(listener.accept()).0;
+ t!(other_end.write_all(b"hello world"));
+
+ let mut buf = [0; 11];
+ t!(stream.read(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+
+ let start = Instant::now();
+ let kind = stream.read(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
+ assert!(start.elapsed() > Duration::from_millis(400));
+ drop(listener);
+ }
+
+ #[test]
+ fn nodelay() {
+ let addr = next_test_ip4();
+ let _listener = t!(TcpListener::bind(&addr));
+
+ let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+ assert_eq!(false, t!(stream.nodelay()));
+ t!(stream.set_nodelay(true));
+ assert_eq!(true, t!(stream.nodelay()));
+ t!(stream.set_nodelay(false));
+ assert_eq!(false, t!(stream.nodelay()));
+ }
+
+ #[test]
+ fn ttl() {
+ let ttl = 100;
+
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ t!(listener.set_ttl(ttl));
+ assert_eq!(ttl, t!(listener.ttl()));
+
+ let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+ t!(stream.set_ttl(ttl));
+ assert_eq!(ttl, t!(stream.ttl()));
+ }
+
+ #[test]
+ fn set_nonblocking() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ t!(listener.set_nonblocking(true));
+ t!(listener.set_nonblocking(false));
+
+ let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+ t!(stream.set_nonblocking(false));
+ t!(stream.set_nonblocking(true));
+
+ let mut buf = [0];
+ match stream.read(&mut buf) {
+ Ok(_) => panic!("expected error"),
+ Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+ 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(()));
+ })
+ }
+
+ #[test]
+ fn connect_timeout_unroutable() {
+ // this IP is unroutable, so connections should always time out,
+ // provided the network is reachable to begin with.
+ let addr = "10.255.255.1:80".parse().unwrap();
+ let e = TcpStream::connect_timeout(&addr, Duration::from_millis(250)).unwrap_err();
+ assert!(e.kind() == io::ErrorKind::TimedOut ||
+ e.kind() == io::ErrorKind::Other,
+ "bad error: {} {:?}", e, e.kind());
+ }
+
+ #[test]
+ fn connect_timeout_unbound() {
+ // bind and drop a socket to track down a "probably unassigned" port
+ let socket = TcpListener::bind("127.0.0.1:0").unwrap();
+ let addr = socket.local_addr().unwrap();
+ drop(socket);
+
+ let timeout = Duration::from_secs(1);
+ let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err();
+ assert!(e.kind() == io::ErrorKind::ConnectionRefused ||
+ e.kind() == io::ErrorKind::TimedOut ||
+ e.kind() == io::ErrorKind::Other,
+ "bad error: {} {:?}", e, e.kind());
+ }
+
+ #[test]
+ fn connect_timeout_valid() {
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let addr = listener.local_addr().unwrap();
+ TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap();
+ }
+}
diff --git a/ctr-std/src/net/test.rs b/ctr-std/src/net/test.rs
new file mode 100644
index 0000000..aec3d90
--- /dev/null
+++ b/ctr-std/src/net/test.rs
@@ -0,0 +1,57 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![allow(warnings)] // not used on emscripten
+
+use env;
+use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
+use sync::atomic::{AtomicUsize, Ordering};
+
+static PORT: AtomicUsize = AtomicUsize::new(0);
+
+pub fn next_test_ip4() -> SocketAddr {
+ let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port();
+ SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port))
+}
+
+pub fn next_test_ip6() -> SocketAddr {
+ let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port();
+ SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1),
+ port, 0, 0))
+}
+
+pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr {
+ SocketAddr::V4(SocketAddrV4::new(a, p))
+}
+
+pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr {
+ SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0))
+}
+
+pub fn tsa<A: ToSocketAddrs>(a: A) -> Result<Vec<SocketAddr>, String> {
+ match a.to_socket_addrs() {
+ Ok(a) => Ok(a.collect()),
+ Err(e) => Err(e.to_string()),
+ }
+}
+
+// The bots run multiple builds at the same time, and these builds
+// all want to use ports. This function figures out which workspace
+// it is running in and assigns a port range based on it.
+fn base_port() -> u16 {
+ let cwd = env::current_dir().unwrap();
+ let dirs = ["32-opt", "32-nopt",
+ "musl-64-opt", "cross-opt",
+ "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt",
+ "all-opt", "snap3", "dist"];
+ dirs.iter().enumerate().find(|&(_, dir)| {
+ cwd.to_str().unwrap().contains(dir)
+ }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600
+}
diff --git a/ctr-std/src/net/udp.rs b/ctr-std/src/net/udp.rs
new file mode 100644
index 0000000..fc7f920
--- /dev/null
+++ b/ctr-std/src/net/udp.rs
@@ -0,0 +1,1116 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 fmt;
+use io::{self, Error, ErrorKind};
+use net::{ToSocketAddrs, SocketAddr, Ipv4Addr, Ipv6Addr};
+use sys_common::net as net_imp;
+use sys_common::{AsInner, FromInner, IntoInner};
+use time::Duration;
+
+/// A UDP socket.
+///
+/// After creating a `UdpSocket` by [`bind`]ing it to a socket address, data can be
+/// [sent to] and [received from] any other socket address.
+///
+/// Although UDP is a connectionless protocol, this implementation provides an interface
+/// to set an address where data should be sent and received from. After setting a remote
+/// address with [`connect`], data can be sent to and received from that address with
+/// [`send`] and [`recv`].
+///
+/// As stated in the User Datagram Protocol's specification in [IETF RFC 768], UDP is
+/// an unordered, unreliable protocol; refer to [`TcpListener`] and [`TcpStream`] for TCP
+/// primitives.
+///
+/// [`bind`]: #method.bind
+/// [`connect`]: #method.connect
+/// [IETF RFC 768]: https://tools.ietf.org/html/rfc768
+/// [`recv`]: #method.recv
+/// [received from]: #method.recv_from
+/// [`send`]: #method.send
+/// [sent to]: #method.send_to
+/// [`TcpListener`]: ../../std/net/struct.TcpListener.html
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::net::UdpSocket;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// {
+/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?;
+///
+/// // Receives a single datagram message on the socket. If `buf` is too small to hold
+/// // the message, it will be cut off.
+/// let mut buf = [0; 10];
+/// let (amt, src) = socket.recv_from(&mut buf)?;
+///
+/// // Redeclare `buf` as slice of the received data and send reverse data back to origin.
+/// let buf = &mut buf[..amt];
+/// buf.reverse();
+/// socket.send_to(buf, &src)?;
+/// # Ok(())
+/// } // the socket is closed here
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct UdpSocket(net_imp::UdpSocket);
+
+impl UdpSocket {
+ /// Creates a UDP socket from the given address.
+ ///
+ /// The address type can be any implementor of [`ToSocketAddrs`] trait. See
+ /// its documentation for concrete examples.
+ ///
+ /// If `addr` yields multiple addresses, `bind` will be attempted with
+ /// each of the addresses until one succeeds and returns the socket. If none
+ /// of the addresses succeed in creating a socket, the error returned from
+ /// the last attempt (the last address) is returned.
+ ///
+ /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+ ///
+ /// # Examples
+ ///
+ /// Create a UDP socket bound to `127.0.0.1:3400`:
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
+ /// ```
+ ///
+ /// Create a UDP socket bound to `127.0.0.1:3400`. If the socket cannot be
+ /// bound to that address, create a UDP socket bound to `127.0.0.1:3401`:
+ ///
+ /// ```no_run
+ /// use std::net::{SocketAddr, UdpSocket};
+ ///
+ /// let addrs = [
+ /// SocketAddr::from(([127, 0, 0, 1], 3400)),
+ /// SocketAddr::from(([127, 0, 0, 1], 3401)),
+ /// ];
+ /// let socket = UdpSocket::bind(&addrs[..]).expect("couldn't bind to address");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
+ super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
+ }
+
+ /// Receives a single datagram message on the socket. On success, returns the number
+ /// of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// 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.recv_from(&mut buf)
+ /// .expect("Didn't receive data");
+ /// let filled_buf = &mut buf[..number_of_bytes];
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.0.recv_from(buf)
+ }
+
+ /// Receives a single datagram message on the socket, without removing it from the
+ /// queue. On success, returns the number of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
+ ///
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// 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");
+ /// let filled_buf = &mut buf[..number_of_bytes];
+ /// ```
+ #[stable(feature = "peek", since = "1.18.0")]
+ 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.
+ ///
+ /// Address type can be any implementor of [`ToSocketAddrs`] trait. See its
+ /// documentation for concrete examples.
+ ///
+ /// It is possible for `addr` to yield multiple addresses, but `send_to`
+ /// will only send data to the first address yielded by `addr`.
+ ///
+ /// This will return an error when the IP version of the local socket
+ /// does not match that returned from [`ToSocketAddrs`].
+ ///
+ /// See <https://github.com/rust-lang/rust/issues/34202> for more details.
+ ///
+ /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A)
+ -> io::Result<usize> {
+ match addr.to_socket_addrs()?.next() {
+ Some(addr) => self.0.send_to(buf, &addr),
+ None => Err(Error::new(ErrorKind::InvalidInput,
+ "no addresses to send data to")),
+ }
+ }
+
+ /// Returns the socket address that this socket was created from.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// assert_eq!(socket.local_addr().unwrap(),
+ /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 34254)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.0.socket_addr()
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UdpSocket` is a reference to the same socket that this
+ /// object references. Both handles will read and write the same port, and
+ /// options set on one socket will be propagated to the other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// let socket_clone = socket.try_clone().expect("couldn't clone the socket");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_clone(&self) -> io::Result<UdpSocket> {
+ self.0.duplicate().map(UdpSocket)
+ }
+
+ /// Sets the read timeout to the timeout specified.
+ ///
+ /// If the value specified is [`None`], then [`read`] calls will block
+ /// indefinitely. It is an error to pass the zero [`Duration`] to this
+ /// method.
+ ///
+ /// # Note
+ ///
+ /// Platforms may return a different error code whenever a read times out as
+ /// a result of setting this option. For example Unix typically returns an
+ /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`].
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`read`]: ../../std/io/trait.Read.html#tymethod.read
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock
+ /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_read_timeout(None).expect("set_read_timeout call failed");
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_read_timeout(dur)
+ }
+
+ /// Sets the write timeout to the timeout specified.
+ ///
+ /// If the value specified is [`None`], then [`write`] calls will block
+ /// indefinitely. It is an error to pass the zero [`Duration`] to this
+ /// method.
+ ///
+ /// # Note
+ ///
+ /// Platforms may return a different error code whenever a write times out
+ /// as a result of setting this option. For example Unix typically returns
+ /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`].
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock
+ /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_write_timeout(None).expect("set_write_timeout call failed");
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_write_timeout(dur)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// If the timeout is [`None`], then [`read`] calls will block indefinitely.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`read`]: ../../std/io/trait.Read.html#tymethod.read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_read_timeout(None).expect("set_read_timeout call failed");
+ /// assert_eq!(socket.read_timeout().unwrap(), None);
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.read_timeout()
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// If the timeout is [`None`], then [`write`] calls will block indefinitely.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_write_timeout(None).expect("set_write_timeout call failed");
+ /// assert_eq!(socket.write_timeout().unwrap(), None);
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.write_timeout()
+ }
+
+ /// Sets the value of the `SO_BROADCAST` option for this socket.
+ ///
+ /// When enabled, this socket is allowed to send packets to a broadcast
+ /// address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_broadcast(false).expect("set_broadcast call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
+ self.0.set_broadcast(broadcast)
+ }
+
+ /// Gets the value of the `SO_BROADCAST` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_broadcast`][link].
+ ///
+ /// [link]: #method.set_broadcast
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_broadcast(false).expect("set_broadcast call failed");
+ /// assert_eq!(socket.broadcast().unwrap(), false);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn broadcast(&self) -> io::Result<bool> {
+ self.0.broadcast()
+ }
+
+ /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket.
+ ///
+ /// If enabled, multicast packets will be looped back to the local socket.
+ /// Note that this may not have any affect on IPv6 sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
+ self.0.set_multicast_loop_v4(multicast_loop_v4)
+ }
+
+ /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_multicast_loop_v4`][link].
+ ///
+ /// [link]: #method.set_multicast_loop_v4
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed");
+ /// assert_eq!(socket.multicast_loop_v4().unwrap(), false);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ self.0.multicast_loop_v4()
+ }
+
+ /// Sets the value of the `IP_MULTICAST_TTL` option for this socket.
+ ///
+ /// Indicates the time-to-live value of outgoing multicast packets for
+ /// this socket. The default value is 1 which means that multicast packets
+ /// don't leave the local network unless explicitly requested.
+ ///
+ /// Note that this may not have any affect on IPv6 sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
+ self.0.set_multicast_ttl_v4(multicast_ttl_v4)
+ }
+
+ /// Gets the value of the `IP_MULTICAST_TTL` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_multicast_ttl_v4`][link].
+ ///
+ /// [link]: #method.set_multicast_ttl_v4
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed");
+ /// assert_eq!(socket.multicast_ttl_v4().unwrap(), 42);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ self.0.multicast_ttl_v4()
+ }
+
+ /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket.
+ ///
+ /// Controls whether this socket sees the multicast packets it sends itself.
+ /// Note that this may not have any affect on IPv4 sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
+ self.0.set_multicast_loop_v6(multicast_loop_v6)
+ }
+
+ /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_multicast_loop_v6`][link].
+ ///
+ /// [link]: #method.set_multicast_loop_v6
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed");
+ /// assert_eq!(socket.multicast_loop_v6().unwrap(), false);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ self.0.multicast_loop_v6()
+ }
+
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This value sets the time-to-live field that is used in every packet sent
+ /// from this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_ttl(42).expect("set_ttl call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.0.set_ttl(ttl)
+ }
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see [`set_ttl`][link].
+ ///
+ /// [link]: #method.set_ttl
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_ttl(42).expect("set_ttl call failed");
+ /// assert_eq!(socket.ttl().unwrap(), 42);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.0.ttl()
+ }
+
+ /// Executes an operation of the `IP_ADD_MEMBERSHIP` type.
+ ///
+ /// This function specifies a new multicast group for this socket to join.
+ /// The address must be a valid multicast address, and `interface` is the
+ /// address of the local interface with which the system should join the
+ /// multicast group. If it's equal to `INADDR_ANY` then an appropriate
+ /// interface is chosen by the system.
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
+ self.0.join_multicast_v4(multiaddr, interface)
+ }
+
+ /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type.
+ ///
+ /// This function specifies a new multicast group for this socket to join.
+ /// The address must be a valid multicast address, and `interface` is the
+ /// index of the interface to join/leave (or 0 to indicate any interface).
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
+ self.0.join_multicast_v6(multiaddr, interface)
+ }
+
+ /// Executes an operation of the `IP_DROP_MEMBERSHIP` type.
+ ///
+ /// For more information about this option, see
+ /// [`join_multicast_v4`][link].
+ ///
+ /// [link]: #method.join_multicast_v4
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
+ self.0.leave_multicast_v4(multiaddr, interface)
+ }
+
+ /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type.
+ ///
+ /// For more information about this option, see
+ /// [`join_multicast_v6`][link].
+ ///
+ /// [link]: #method.join_multicast_v6
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
+ self.0.leave_multicast_v6(multiaddr, interface)
+ }
+
+ /// Get the value of the `SO_ERROR` option on this socket.
+ ///
+ /// This will retrieve the stored error in the underlying socket, clearing
+ /// the field in the process. This can be useful for checking errors between
+ /// calls.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// match socket.take_error() {
+ /// Ok(Some(error)) => println!("UdpSocket error: {:?}", error),
+ /// Ok(None) => println!("No error"),
+ /// Err(error) => println!("UdpSocket.take_error failed: {:?}", error),
+ /// }
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Connects this UDP socket to a remote address, allowing the `send` and
+ /// `recv` syscalls to be used to send data and also applies filters to only
+ /// receive data from the specified address.
+ ///
+ /// If `addr` yields multiple addresses, `connect` will be attempted with
+ /// each of the addresses until the underlying OS function returns no
+ /// error. Note that usually, a successful `connect` call does not specify
+ /// that there is a remote server listening on the port, rather, such an
+ /// error would only be detected after the first send. If the OS returns an
+ /// error for each of the specified addresses, the error returned from the
+ /// last connection attempt (the last address) is returned.
+ ///
+ /// # Examples
+ ///
+ /// Create a UDP socket bound to `127.0.0.1:3400` and connect the socket to
+ /// `127.0.0.1:8080`:
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
+ /// socket.connect("127.0.0.1:8080").expect("connect function failed");
+ /// ```
+ ///
+ /// Unlike in the TCP case, passing an array of addresses to the `connect`
+ /// function of a UDP socket is not a useful thing to do: The OS will be
+ /// unable to determine whether something is listening on the remote
+ /// address without the application sending data.
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
+ super::each_addr(addr, |addr| self.0.connect(addr))
+ }
+
+ /// Sends data on the socket to the remote address to which it is connected.
+ ///
+ /// The [`connect`] method will connect this socket to a remote address. This
+ /// method will fail if the socket is not connected.
+ ///
+ /// [`connect`]: #method.connect
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// 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");
+ /// socket.send(&[0, 1, 2]).expect("couldn't send message");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.send(buf)
+ }
+
+ /// Receives a single datagram message on the socket from the remote address to
+ /// which it is connected. On success, returns the number of bytes read.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// The [`connect`] method will connect this socket to a remote address. This
+ /// method will fail if the socket is not connected.
+ ///
+ /// [`connect`]: #method.connect
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// 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.recv(&mut buf) {
+ /// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]),
+ /// Err(e) => println!("recv function failed: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.recv(buf)
+ }
+
+ /// Receives single datagram on the socket from the remote address to which it is
+ /// connected, without removing the message from input queue. On success, returns
+ /// the number of bytes peeked.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+ ///
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
+ ///
+ /// The [`connect`] method will connect this socket to a remote address. This
+ /// method will fail if the socket is not connected.
+ ///
+ /// [`connect`]: #method.connect
+ ///
+ /// # 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
+ /// 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),
+ /// }
+ /// ```
+ #[stable(feature = "peek", since = "1.18.0")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.peek(buf)
+ }
+
+ /// Moves this UDP socket into or out of nonblocking mode.
+ ///
+ /// This will result in `recv`, `recv_from`, `send`, and `send_to`
+ /// operations becoming nonblocking, i.e. immediately returning from their
+ /// calls. If the IO operation is successful, `Ok` is returned and no
+ /// further action is required. If the IO operation could not be completed
+ /// and needs to be retried, an error with kind
+ /// [`io::ErrorKind::WouldBlock`] is returned.
+ ///
+ /// On Unix platforms, calling this method corresponds to calling `fcntl`
+ /// `FIONBIO`. On Windows calling this method corresponds to calling
+ /// `ioctlsocket` `FIONBIO`.
+ ///
+ /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock
+ ///
+ /// # Examples
+ ///
+ /// Create a UDP socket bound to `127.0.0.1:7878` and read bytes in
+ /// nonblocking mode:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:7878").unwrap();
+ /// socket.set_nonblocking(true).unwrap();
+ ///
+ /// # fn wait_for_fd() { unimplemented!() }
+ /// let mut buf = [0; 10];
+ /// let (num_bytes_read, _) = loop {
+ /// match socket.recv_from(&mut buf) {
+ /// Ok(n) => break n,
+ /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+ /// // wait until network socket is ready, typically implemented
+ /// // via platform-specific APIs such as epoll or IOCP
+ /// wait_for_fd();
+ /// }
+ /// Err(e) => panic!("encountered IO error: {}", e),
+ /// }
+ /// };
+ /// println!("bytes: {:?}", &buf[..num_bytes_read]);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+}
+
+impl AsInner<net_imp::UdpSocket> for UdpSocket {
+ fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 }
+}
+
+impl FromInner<net_imp::UdpSocket> for UdpSocket {
+ fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) }
+}
+
+impl IntoInner<net_imp::UdpSocket> for UdpSocket {
+ fn into_inner(self) -> net_imp::UdpSocket { self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
+mod tests {
+ use io::ErrorKind;
+ use net::*;
+ use net::test::{next_test_ip4, next_test_ip6};
+ use sync::mpsc::channel;
+ use sys_common::AsInner;
+ use time::{Instant, Duration};
+ use thread;
+
+ fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) {
+ f(next_test_ip4(), next_test_ip4());
+ f(next_test_ip6(), next_test_ip6());
+ }
+
+ macro_rules! t {
+ ($e:expr) => {
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+ }
+ }
+ }
+
+ #[test]
+ fn bind_error() {
+ match UdpSocket::bind("1.1.1.1:9999") {
+ Ok(..) => panic!(),
+ Err(e) => {
+ assert_eq!(e.kind(), ErrorKind::AddrNotAvailable)
+ }
+ }
+ }
+
+ #[test]
+ fn socket_smoke_test_ip4() {
+ each_ip(&mut |server_ip, client_ip| {
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+
+ let _t = thread::spawn(move|| {
+ let client = t!(UdpSocket::bind(&client_ip));
+ rx1.recv().unwrap();
+ t!(client.send_to(&[99], &server_ip));
+ tx2.send(()).unwrap();
+ });
+
+ let server = t!(UdpSocket::bind(&server_ip));
+ tx1.send(()).unwrap();
+ let mut buf = [0];
+ let (nread, src) = t!(server.recv_from(&mut buf));
+ assert_eq!(nread, 1);
+ assert_eq!(buf[0], 99);
+ assert_eq!(src, client_ip);
+ rx2.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn socket_name_ip4() {
+ each_ip(&mut |addr, _| {
+ let server = t!(UdpSocket::bind(&addr));
+ assert_eq!(addr, t!(server.local_addr()));
+ })
+ }
+
+ #[test]
+ fn udp_clone_smoke() {
+ each_ip(&mut |addr1, addr2| {
+ let sock1 = t!(UdpSocket::bind(&addr1));
+ let sock2 = t!(UdpSocket::bind(&addr2));
+
+ let _t = thread::spawn(move|| {
+ let mut buf = [0, 0];
+ assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1));
+ assert_eq!(buf[0], 1);
+ t!(sock2.send_to(&[2], &addr1));
+ });
+
+ let sock3 = t!(sock1.try_clone());
+
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+ let _t = thread::spawn(move|| {
+ rx1.recv().unwrap();
+ t!(sock3.send_to(&[1], &addr2));
+ tx2.send(()).unwrap();
+ });
+ tx1.send(()).unwrap();
+ let mut buf = [0, 0];
+ assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2));
+ rx2.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn udp_clone_two_read() {
+ each_ip(&mut |addr1, addr2| {
+ let sock1 = t!(UdpSocket::bind(&addr1));
+ let sock2 = t!(UdpSocket::bind(&addr2));
+ let (tx1, rx) = channel();
+ let tx2 = tx1.clone();
+
+ let _t = thread::spawn(move|| {
+ t!(sock2.send_to(&[1], &addr1));
+ rx.recv().unwrap();
+ t!(sock2.send_to(&[2], &addr1));
+ rx.recv().unwrap();
+ });
+
+ let sock3 = t!(sock1.try_clone());
+
+ let (done, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut buf = [0, 0];
+ t!(sock3.recv_from(&mut buf));
+ tx2.send(()).unwrap();
+ done.send(()).unwrap();
+ });
+ let mut buf = [0, 0];
+ t!(sock1.recv_from(&mut buf));
+ tx1.send(()).unwrap();
+
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn udp_clone_two_write() {
+ each_ip(&mut |addr1, addr2| {
+ let sock1 = t!(UdpSocket::bind(&addr1));
+ let sock2 = t!(UdpSocket::bind(&addr2));
+
+ let (tx, rx) = channel();
+ let (serv_tx, serv_rx) = channel();
+
+ let _t = thread::spawn(move|| {
+ let mut buf = [0, 1];
+ rx.recv().unwrap();
+ t!(sock2.recv_from(&mut buf));
+ serv_tx.send(()).unwrap();
+ });
+
+ let sock3 = t!(sock1.try_clone());
+
+ let (done, rx) = channel();
+ let tx2 = tx.clone();
+ let _t = thread::spawn(move|| {
+ match sock3.send_to(&[1], &addr2) {
+ Ok(..) => { let _ = tx2.send(()); }
+ Err(..) => {}
+ }
+ done.send(()).unwrap();
+ });
+ match sock1.send_to(&[2], &addr2) {
+ Ok(..) => { let _ = tx.send(()); }
+ Err(..) => {}
+ }
+ drop(tx);
+
+ rx.recv().unwrap();
+ serv_rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn debug() {
+ let name = if cfg!(windows) {"socket"} else {"fd"};
+ let socket_addr = next_test_ip4();
+
+ let udpsock = t!(UdpSocket::bind(&socket_addr));
+ let udpsock_inner = udpsock.0.socket().as_inner();
+ let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}",
+ socket_addr, name, udpsock_inner);
+ assert_eq!(format!("{:?}", udpsock), compare);
+ }
+
+ // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code
+ // no longer has rounding errors.
+ #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)]
+ #[test]
+ fn timeouts() {
+ let addr = next_test_ip4();
+
+ let stream = t!(UdpSocket::bind(&addr));
+ let dur = Duration::new(15410, 0);
+
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_read_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.read_timeout()));
+
+ assert_eq!(None, t!(stream.write_timeout()));
+
+ t!(stream.set_write_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.write_timeout()));
+
+ t!(stream.set_read_timeout(None));
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_write_timeout(None));
+ assert_eq!(None, t!(stream.write_timeout()));
+ }
+
+ #[test]
+ fn test_read_timeout() {
+ let addr = next_test_ip4();
+
+ let stream = t!(UdpSocket::bind(&addr));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut buf = [0; 10];
+
+ let start = Instant::now();
+ let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
+ assert!(start.elapsed() > Duration::from_millis(400));
+ }
+
+ #[test]
+ fn test_read_with_timeout() {
+ let addr = next_test_ip4();
+
+ let stream = t!(UdpSocket::bind(&addr));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ t!(stream.send_to(b"hello world", &addr));
+
+ let mut buf = [0; 11];
+ t!(stream.recv_from(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+
+ let start = Instant::now();
+ let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
+ assert!(start.elapsed() > Duration::from_millis(400));
+ }
+
+ #[test]
+ fn connect_send_recv() {
+ let addr = next_test_ip4();
+
+ let socket = t!(UdpSocket::bind(&addr));
+ t!(socket.connect(addr));
+
+ t!(socket.send(b"hello world"));
+
+ let mut buf = [0; 11];
+ t!(socket.recv(&mut buf));
+ 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;
+
+ let addr = next_test_ip4();
+
+ let stream = t!(UdpSocket::bind(&addr));
+
+ t!(stream.set_ttl(ttl));
+ assert_eq!(ttl, t!(stream.ttl()));
+ }
+
+ #[test]
+ fn set_nonblocking() {
+ each_ip(&mut |addr, _| {
+ let socket = t!(UdpSocket::bind(&addr));
+
+ t!(socket.set_nonblocking(true));
+ t!(socket.set_nonblocking(false));
+
+ t!(socket.connect(addr));
+
+ t!(socket.set_nonblocking(false));
+ t!(socket.set_nonblocking(true));
+
+ let mut buf = [0];
+ match socket.recv(&mut buf) {
+ Ok(_) => panic!("expected error"),
+ Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+ Err(e) => panic!("unexpected error {}", e),
+ }
+ })
+ }
+}
diff --git a/ctr-std/src/num.rs b/ctr-std/src/num.rs
index b7618ac..a2c1339 100644
--- a/ctr-std/src/num.rs
+++ b/ctr-std/src/num.rs
@@ -18,7 +18,6 @@
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError};
-
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::num::Wrapping;
@@ -170,10 +169,14 @@ mod tests {
macro_rules! test_checked_next_power_of_two {
($test_name:ident, $T:ident) => (
+ #[cfg_attr(target_os = "emscripten", ignore)] // FIXME(#39119)
fn $test_name() {
#![test]
assert_eq!((0 as $T).checked_next_power_of_two(), Some(1));
- assert!(($T::MAX / 2).checked_next_power_of_two().is_some());
+ let smax = $T::MAX >> 1;
+ assert_eq!(smax.checked_next_power_of_two(), Some(smax+1));
+ assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1));
+ assert_eq!((smax + 2).checked_next_power_of_two(), None);
assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None);
assert_eq!($T::MAX.checked_next_power_of_two(), None);
let mut next_power = 1;
diff --git a/ctr-std/src/os/linux/fs.rs b/ctr-std/src/os/linux/fs.rs
new file mode 100644
index 0000000..d1e0bea
--- /dev/null
+++ b/ctr-std/src/os/linux/fs.rs
@@ -0,0 +1,390 @@
+// Copyright 2016 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.
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use libc;
+
+use fs::Metadata;
+use sys_common::AsInner;
+
+#[allow(deprecated)]
+use os::linux::raw;
+
+/// OS-specific extension methods for `fs::Metadata`
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned [`stat`] are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ ///
+ /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let stat = meta.as_raw_stat();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[rustc_deprecated(since = "1.8.0",
+ reason = "deprecated in favor of the accessor \
+ methods of this trait")]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ /// Returns the device ID on which this file resides.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_dev());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ino());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ /// Returns the file type and mode.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mode());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ /// Returns the number of hard links to file.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_nlink());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ /// Returns the user ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_uid());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ /// Returns the group ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_gid());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ /// Returns the device ID that this file represents. Only relevant for special file.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_rdev());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+ ///
+ /// The size of a symbolic link is the length of the pathname it contains,
+ /// without a terminating null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_size());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ /// Returns the last access time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ /// Returns the last access time, nano seconds part.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime_nsec());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ /// Returns the last modification time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ /// Returns the last modification time, nano seconds part.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime_nsec());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ /// Returns the last status change time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ /// Returns the last status change time, nano seconds part.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ /// Returns the "preferred" blocksize for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// # use std::io;
+ /// # fn f() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe {
+ &*(self.as_inner().as_inner() as *const libc::stat
+ as *const raw::stat)
+ }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ //self.as_inner().as_inner().st_atime_nsec as i64
+ 0
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ //self.as_inner().as_inner().st_mtime_nsec as i64
+ 0
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ //self.as_inner().as_inner().st_ctime_nsec as i64
+ 0
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/ctr-std/src/os/linux/mod.rs b/ctr-std/src/os/linux/mod.rs
new file mode 100644
index 0000000..8ec44b9
--- /dev/null
+++ b/ctr-std/src/os/linux/mod.rs
@@ -0,0 +1,16 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! Linux-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/ctr-std/src/os/linux/raw.rs b/ctr-std/src/os/linux/raw.rs
new file mode 100644
index 0000000..bb1830a
--- /dev/null
+++ b/ctr-std/src/os/linux/raw.rs
@@ -0,0 +1,275 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! Linux-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![rustc_deprecated(since = "1.8.0",
+ reason = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions")]
+#![allow(deprecated)]
+#![allow(missing_debug_implementations)]
+
+use os::raw::c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
+
+#[cfg(any(target_arch = "x86",
+ target_arch = "le32",
+ target_arch = "powerpc",
+ target_arch = "arm",
+ target_arch = "asmjs",
+ target_arch = "wasm32"))]
+mod arch {
+ use os::raw::{c_long, c_short, c_uint};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: c_short,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ }
+}
+
+#[cfg(target_arch = "mips")]
+mod arch {
+ use os::raw::{c_long, c_ulong};
+
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad1: [c_long; 3],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad2: [c_long; 2],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad5: [c_long; 14],
+ }
+}
+
+#[cfg(any(target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "sparc64"))]
+mod arch {
+ pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ use os::raw::{c_long, c_int};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_int; 2],
+ }
+}
+
+#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))]
+mod arch {
+ use os::raw::{c_long, c_int};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_long; 3],
+ }
+}
diff --git a/ctr-std/src/os/macos/fs.rs b/ctr-std/src/os/macos/fs.rs
new file mode 100644
index 0000000..12b4490
--- /dev/null
+++ b/ctr-std/src/os/macos/fs.rs
@@ -0,0 +1,160 @@
+// Copyright 2016 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.
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use libc;
+
+use fs::Metadata;
+use sys_common::AsInner;
+
+#[allow(deprecated)]
+use os::macos::raw;
+
+/// OS-specific extension methods for `fs::Metadata`
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[rustc_deprecated(since = "1.8.0",
+ reason = "deprecated in favor of the accessor \
+ methods of this trait")]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_lspare(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_qspare(&self) -> [u64; 2];
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe {
+ &*(self.as_inner().as_inner() as *const libc::stat
+ as *const raw::stat)
+ }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+ fn st_lspare(&self) -> u32 {
+ self.as_inner().as_inner().st_lspare as u32
+ }
+ fn st_qspare(&self) -> [u64; 2] {
+ let qspare = self.as_inner().as_inner().st_qspare;
+ [qspare[0] as u64, qspare[1] as u64]
+ }
+}
+
diff --git a/ctr-std/src/os/macos/mod.rs b/ctr-std/src/os/macos/mod.rs
new file mode 100644
index 0000000..c9406f7
--- /dev/null
+++ b/ctr-std/src/os/macos/mod.rs
@@ -0,0 +1,16 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! macOS-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/ctr-std/src/os/macos/raw.rs b/ctr-std/src/os/macos/raw.rs
new file mode 100644
index 0000000..8ffddf6
--- /dev/null
+++ b/ctr-std/src/os/macos/raw.rs
@@ -0,0 +1,83 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! macOS-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![rustc_deprecated(since = "1.8.0",
+ reason = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions")]
+#![allow(deprecated)]
+
+use os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_lspare: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_qspare: [i64; 2],
+}
diff --git a/ctr-std/src/os/mod.rs b/ctr-std/src/os/mod.rs
index bd05ac3..6d3d4c4 100644
--- a/ctr-std/src/os/mod.rs
+++ b/ctr-std/src/os/mod.rs
@@ -11,7 +11,50 @@
//! OS-specific functionality.
#![stable(feature = "os", since = "1.0.0")]
-#![allow(missing_docs, bad_style)]
+#![allow(missing_docs, bad_style, missing_debug_implementations)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use sys::ext as unix;
+cfg_if! {
+ if #[cfg(dox)] {
+
+ // When documenting libstd we want to show unix/windows/linux modules as
+ // these are the "main modules" that are used across platforms. This
+ // should help show platform-specific functionality in a hopefully
+ // cross-platform way in the documentation
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use sys::unix_ext as unix;
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use sys::windows_ext as windows;
+
+ #[doc(cfg(target_os = "linux"))]
+ pub mod linux;
+
+ } else {
+
+ // If we're not documenting libstd then we just expose everything as we
+ // otherwise would.
+
+ #[cfg(target_os = "android")] pub mod android;
+ #[cfg(target_os = "bitrig")] pub mod bitrig;
+ #[cfg(target_os = "dragonfly")] pub mod dragonfly;
+ #[cfg(target_os = "freebsd")] pub mod freebsd;
+ #[cfg(target_os = "haiku")] pub mod haiku;
+ #[cfg(target_os = "ios")] pub mod ios;
+ #[cfg(target_os = "macos")] pub mod macos;
+ #[cfg(target_os = "netbsd")] pub mod netbsd;
+ #[cfg(target_os = "openbsd")] pub mod openbsd;
+ #[cfg(target_os = "solaris")] pub mod solaris;
+ #[cfg(target_os = "emscripten")] pub mod emscripten;
+ #[cfg(target_os = "fuchsia")] pub mod fuchsia;
+
+ #[cfg(any(target_os = "redox", unix))]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use sys::ext as unix;
+
+ #[cfg(any(target_os = "linux", target_os = "l4re", target_os = "horizon"))]
+ pub mod linux;
+ }
+}
+
+pub mod raw;
diff --git a/ctr-std/src/os/raw.rs b/ctr-std/src/os/raw.rs
new file mode 100644
index 0000000..57baf0d
--- /dev/null
+++ b/ctr-std/src/os/raw.rs
@@ -0,0 +1,108 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! Raw OS-specific types for the current platform/architecture
+
+#![stable(feature = "raw_os", since = "1.1.0")]
+
+use fmt;
+
+#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x")),
+ all(target_os = "android", any(target_arch = "aarch64",
+ target_arch = "arm")),
+ all(target_os = "l4re", target_arch = "x86_64"),
+ all(target_os = "openbsd", target_arch = "aarch64"),
+ all(target_os = "fuchsia", target_arch = "aarch64"),
+ all(target_os = "horizon", target_arch = "arm")))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
+#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x")),
+ all(target_os = "android", any(target_arch = "aarch64",
+ target_arch = "arm")),
+ all(target_os = "l4re", target_arch = "x86_64"),
+ all(target_os = "openbsd", target_arch = "aarch64"),
+ all(target_os = "horizon", target_arch = "arm"))))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
+#[cfg(any(target_pointer_width = "32", windows))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
+#[cfg(any(target_pointer_width = "32", windows))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
+#[cfg(all(target_pointer_width = "64", not(windows)))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
+#[cfg(all(target_pointer_width = "64", not(windows)))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;
+
+/// Type used to construct void pointers for use with C.
+///
+/// This type is only useful as a pointer target. Do not use it as a
+/// return type for FFI functions which have the `void` return type in
+/// C. Use the unit type `()` or omit the return type instead.
+// NB: For LLVM to recognize the void pointer type and by extension
+// functions like malloc(), we need to have it represented as i8* in
+// LLVM bitcode. The enum used here ensures this and prevents misuse
+// of the "raw" type by only having private variants.. We need two
+// variants, because the compiler complains about the repr attribute
+// otherwise.
+#[repr(u8)]
+#[stable(feature = "raw_os", since = "1.1.0")]
+pub enum c_void {
+ #[unstable(feature = "c_void_variant", reason = "should not have to exist",
+ issue = "0")]
+ #[doc(hidden)] __variant1,
+ #[unstable(feature = "c_void_variant", reason = "should not have to exist",
+ issue = "0")]
+ #[doc(hidden)] __variant2,
+}
+
+#[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")
+ }
+}
+
+#[cfg(test)]
+#[allow(unused_imports)]
+mod tests {
+ use any::TypeId;
+ use libc;
+ use mem;
+
+ macro_rules! ok {
+ ($($t:ident)*) => {$(
+ assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
+ "{} is wrong", stringify!($t));
+ )*}
+ }
+
+ #[test]
+ fn same() {
+ use os::raw;
+ ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
+ c_longlong c_ulonglong c_float c_double);
+ }
+}
diff --git a/ctr-std/src/panic.rs b/ctr-std/src/panic.rs
index e73e0a6..5608760 100644
--- a/ctr-std/src/panic.rs
+++ b/ctr-std/src/panic.rs
@@ -8,17 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Panic support in the standard library
+//! Panic support in the standard library.
#![stable(feature = "std_panic", since = "1.9.0")]
-#![allow(auto_impl)]
use any::Any;
use cell::UnsafeCell;
use fmt;
use ops::{Deref, DerefMut};
use panicking;
-use ptr::{Unique, Shared};
+use ptr::{Unique, NonNull};
use rc::Rc;
use sync::{Arc, Mutex, RwLock, atomic};
use thread::Result;
@@ -38,7 +37,7 @@ pub use panicking::{take_hook, set_hook, PanicInfo, Location};
/// In Rust a function can "return" early if it either panics or calls a
/// function which transitively panics. This sort of control flow is not always
/// anticipated, and has the possibility of causing subtle bugs through a
-/// combination of two cricial components:
+/// combination of two critical components:
///
/// 1. A data structure is in a temporarily invalid state when the thread
/// panics.
@@ -102,7 +101,7 @@ pub use panicking::{take_hook, set_hook, PanicInfo, Location};
#[stable(feature = "catch_unwind", since = "1.9.0")]
#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \
across an unwind boundary"]
-pub trait UnwindSafe {}
+pub auto trait UnwindSafe {}
/// A marker trait representing types where a shared reference is considered
/// unwind safe.
@@ -116,7 +115,7 @@ pub trait UnwindSafe {}
#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \
and a reference may not be safely transferrable \
across a catch_unwind boundary"]
-pub trait RefUnwindSafe {}
+pub auto trait RefUnwindSafe {}
/// A simple wrapper around a type to assert that it is unwind safe.
///
@@ -188,8 +187,7 @@ pub struct AssertUnwindSafe<T>(
// * Unique, an owning pointer, lifts an implementation
// * Types like Mutex/RwLock which are explicilty poisoned are unwind safe
// * Our custom AssertUnwindSafe wrapper is indeed unwind safe
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl UnwindSafe for .. {}
+
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<'a, T: ?Sized> !UnwindSafe for &'a mut T {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
@@ -198,10 +196,10 @@ impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {}
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Shared<T> {}
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> UnwindSafe for Mutex<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
@@ -218,12 +216,10 @@ impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {}
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {}
// Pretty simple implementations for the `RefUnwindSafe` marker trait,
-// basically just saying that this is a marker trait and `UnsafeCell` is the
+// basically just saying that `UnsafeCell` is the
// only thing which doesn't implement it (which then transitively applies to
// everything else).
#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl RefUnwindSafe for .. {}
-#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> RefUnwindSafe for AssertUnwindSafe<T> {}
diff --git a/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs
index 082b0de..3769e0f 100644
--- a/ctr-std/src/panicking.rs
+++ b/ctr-std/src/panicking.rs
@@ -17,6 +17,8 @@
//! * Executing a panic up to doing the actual implementation
//! * Shims around "try"
+#![allow(unused_imports)]
+
use io::prelude::*;
use any::Any;
@@ -26,6 +28,7 @@ use intrinsics;
use mem;
use ptr;
use raw;
+use sys::stdio::Stderr;
use sys_common::rwlock::RWLock;
use sys_common::thread_info;
use sys_common::util;
@@ -37,6 +40,16 @@ thread_local! {
}
}
+// Binary interface to the panic runtime that the standard library depends on.
+//
+// The standard library is tagged with `#![needs_panic_runtime]` (introduced in
+// RFC 1513) to indicate that it requires some other crate tagged with
+// `#![panic_runtime]` to exist somewhere. Each panic runtime is intended to
+// implement these symbols (with the same signatures) so we can get matched up
+// to them.
+//
+// One day this may look a little less ad-hoc with the compiler helping out to
+// hook up these functions, but it is not this day!
#[allow(improper_ctypes)]
extern {
fn __rust_maybe_catch_panic(f: fn(*mut u8),
@@ -160,7 +173,7 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
-/// println!("panic occured: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
+/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
/// }));
///
/// panic!("Normal panic");
@@ -185,7 +198,7 @@ impl<'a> PanicInfo<'a> {
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
- /// println!("panic occured: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
+ /// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
/// }));
///
/// panic!("Normal panic");
@@ -210,9 +223,10 @@ impl<'a> PanicInfo<'a> {
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
- /// println!("panic occured in file '{}' at line {}", location.file(), location.line());
+ /// println!("panic occurred in file '{}' at line {}", location.file(),
+ /// location.line());
/// } else {
- /// println!("panic occured but can't get location information...");
+ /// println!("panic occurred but can't get location information...");
/// }
/// }));
///
@@ -238,9 +252,9 @@ impl<'a> PanicInfo<'a> {
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
-/// println!("panic occured in file '{}' at line {}", location.file(), location.line());
+/// println!("panic occurred in file '{}' at line {}", location.file(), location.line());
/// } else {
-/// println!("panic occured but can't get location information...");
+/// println!("panic occurred but can't get location information...");
/// }
/// }));
///
@@ -264,9 +278,9 @@ impl<'a> Location<'a> {
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
- /// println!("panic occured in file '{}'", location.file());
+ /// println!("panic occurred in file '{}'", location.file());
/// } else {
- /// println!("panic occured but can't get location information...");
+ /// println!("panic occurred but can't get location information...");
/// }
/// }));
///
@@ -286,9 +300,9 @@ impl<'a> Location<'a> {
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
- /// println!("panic occured at line {}", location.line());
+ /// println!("panic occurred at line {}", location.line());
/// } else {
- /// println!("panic occured but can't get location information...");
+ /// println!("panic occurred but can't get location information...");
/// }
/// }));
///
@@ -304,20 +318,19 @@ impl<'a> Location<'a> {
/// # Examples
///
/// ```should_panic
- /// #![feature(panic_col)]
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
- /// println!("panic occured at column {}", location.column());
+ /// println!("panic occurred at column {}", location.column());
/// } else {
- /// println!("panic occured but can't get location information...");
+ /// println!("panic occurred but can't get location information...");
/// }
/// }));
///
/// panic!("Normal panic");
/// ```
- #[unstable(feature = "panic_col", reason = "recently added", issue = "42939")]
+ #[stable(feature = "panic_col", since = "1.25")]
pub fn column(&self) -> u32 {
self.col
}
@@ -352,19 +365,13 @@ fn default_hook(info: &PanicInfo) {
None => "Box<Any>",
}
};
-
- // 3DS-specific code begins here
- use libctru::{consoleDebugInit, debugDevice};
- use sys::stdio::Stderr;
-
let mut err = Stderr::new().ok();
let thread = thread_info::current_thread();
- let name = thread.as_ref()
- .and_then(|t| t.name())
- .unwrap_or("<unnamed>");
-
+ let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
+
+ // 3DS-specific code here
unsafe {
- consoleDebugInit(debugDevice::debugDevice_CONSOLE);
+ ::libctru::consoleInit(::libctru::GFX_TOP, ptr::null_mut());
}
let write = |err: &mut ::io::Write| {
@@ -429,30 +436,32 @@ fn default_hook(info: &PanicInfo) {
}
};
-
- // 3DS-specific code begins here
- use libctru::{errorInit, errorText, errorDisp, errorConf};
- use libc;
-
let thread = thread_info::current_thread();
- let name = thread.as_ref()
- .and_then(|t| t.name())
- .unwrap_or("<unnamed>");
+ let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
+
+ // 3DS-specific code here to display panics via the Error applet
unsafe {
- // Setup error payload
+ use libc;
+
+ // Prepare error message for display
let error_text = format!("thread '{}' panicked at '{}', {}:{}:{}",
name, msg, file, line, col);
-
- let mut error_conf: errorConf = mem::uninitialized();
- errorInit(&mut error_conf,
+ let mut error_conf: ::libctru::errorConf = mem::uninitialized();
+ ::libctru::errorInit(&mut error_conf,
::libctru::ERROR_TEXT_WORD_WRAP,
::libctru::CFG_LANGUAGE_EN);
- errorText(&mut error_conf, error_text.as_ptr() as *const libc::c_char);
+ ::libctru::errorText(&mut error_conf, error_text.as_ptr() as *const libc::c_char);
- // Display error
- errorDisp(&mut error_conf);
+ // Display the error
+ ::libctru::errorDisp(&mut error_conf);
}
+
+ // TODO: Should the error applet be provided as a custom panic hook in `ctru-rs`
+ // instead of being selected via feature flag? And should it not be the default hook?
+
+ // TODO: If we ever implement backtrace functionality, determine the best way to
+ // incorporate it with the error applet
}
#[cfg(not(test))]
@@ -508,7 +517,7 @@ pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {
let mut any_data = 0;
let mut any_vtable = 0;
let mut data = Data {
- f: f,
+ f,
};
let r = __rust_maybe_catch_panic(do_call::<F, R>,
@@ -543,6 +552,7 @@ pub fn panicking() -> bool {
}
/// Entry point of panic from the libcore crate.
+#[cfg(not(test))]
#[lang = "panic_fmt"]
#[unwind]
pub extern fn rust_begin_panic(msg: fmt::Arguments,
diff --git a/ctr-std/src/path.rs b/ctr-std/src/path.rs
index 2435efd..7631a9a 100644
--- a/ctr-std/src/path.rs
+++ b/ctr-std/src/path.rs
@@ -10,20 +10,27 @@
//! Cross-platform path manipulation.
//!
-//! This module provides two types, `PathBuf` and `Path` (akin to `String` and
-//! `str`), for working with paths abstractly. These types are thin wrappers
-//! around `OsString` and `OsStr` respectively, meaning that they work directly
+//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`]
+//! and [`str`]), for working with paths abstractly. These types are thin wrappers
+//! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly
//! on strings according to the local platform's path syntax.
//!
+//! Paths can be parsed into [`Component`]s by iterating over the structure
+//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly
+//! correspond to the substrings between path separators (`/` or `\`). You can
+//! reconstruct an equivalent path from components with the [`push`] method on
+//! [`PathBuf`]; note that the paths may differ syntactically by the
+//! normalization described in the documentation for the [`components`] method.
+//!
//! ## Simple usage
//!
//! Path manipulation includes both parsing components from slices and building
//! new owned paths.
//!
-//! To parse a path, you can create a `Path` slice from a `str`
+//! To parse a path, you can create a [`Path`] slice from a [`str`]
//! slice and start asking questions:
//!
-//! ```rust
+//! ```
//! use std::path::Path;
//! use std::ffi::OsStr;
//!
@@ -39,70 +46,34 @@
//! assert_eq!(extension, Some(OsStr::new("txt")));
//! ```
//!
-//! To build or modify paths, use `PathBuf`:
+//! To build or modify paths, use [`PathBuf`]:
//!
-//! ```rust
+//! ```
//! use std::path::PathBuf;
//!
+//! // This way works...
//! let mut path = PathBuf::from("c:\\");
+//!
//! path.push("windows");
//! path.push("system32");
-//! path.set_extension("dll");
-//! ```
-//!
-//! ## Path components and normalization
-//!
-//! The path APIs are built around the notion of "components", which roughly
-//! correspond to the substrings between path separators (`/` and, on Windows,
-//! `\`). The APIs for path parsing are largely specified in terms of the path's
-//! components, so it's important to clearly understand how those are
-//! determined.
-//!
-//! A path can always be reconstructed into an *equivalent* path by
-//! putting together its components via `push`. Syntactically, the
-//! paths may differ by the normalization described below.
-//!
-//! ### Component types
-//!
-//! Components come in several types:
-//!
-//! * Normal components are the default: standard references to files or
-//! directories. The path `a/b` has two normal components, `a` and `b`.
-//!
-//! * Current directory components represent the `.` character. For example,
-//! `./a` has a current directory component and a normal component `a`.
-//!
-//! * The root directory component represents a separator that designates
-//! starting from root. For example, `/a/b` has a root directory component
-//! followed by normal components `a` and `b`.
-//!
-//! On Windows, an additional component type comes into play:
-//!
-//! * Prefix components, of which there is a large variety. For example, `C:`
-//! and `\\server\share` are prefixes. The path `C:windows` has a prefix
-//! component `C:` and a normal component `windows`; the path `C:\windows` has a
-//! prefix component `C:`, a root directory component, and a normal component
-//! `windows`.
//!
-//! ### Normalization
-//!
-//! Aside from splitting on the separator(s), there is a small amount of
-//! "normalization":
+//! path.set_extension("dll");
//!
-//! * Repeated separators are ignored: `a/b` and `a//b` both have components `a`
-//! and `b`.
+//! // ... but push is best used if you don't know everything up
+//! // front. If you do, this way is better:
+//! let path: PathBuf = ["c:\\", "windows", "system32.dll"].iter().collect();
+//! ```
//!
-//! * Occurrences of `.` are normalized away, *except* if they are at
-//! the beginning of the path (in which case they are often meaningful
-//! in terms of path searching). So, for example, `a/./b`, `a/b/`,
-//! `/a/b/.` and `a/b` all have components `a` and `b`, but `./a/b`
-//! has a leading current directory component.
+//! [`Component`]: ../../std/path/enum.Component.html
+//! [`components`]: ../../std/path/struct.Path.html#method.components
+//! [`PathBuf`]: ../../std/path/struct.PathBuf.html
+//! [`Path`]: ../../std/path/struct.Path.html
+//! [`push`]: ../../std/path/struct.PathBuf.html#method.push
+//! [`String`]: ../../std/string/struct.String.html
//!
-//! No other normalization takes place by default. In particular,
-//! `a/c` and `a/b/../c` are distinct, to account for the possibility
-//! that `b` is a symbolic link (so its parent isn't `a`). Further
-//! normalization is possible to build on top of the components APIs,
-//! and will be included in this library in the near future.
+//! [`str`]: ../../std/primitive.str.html
+//! [`OsString`]: ../../std/ffi/struct.OsString.html
+//! [`OsStr`]: ../../std/ffi/struct.OsStr.html
#![stable(feature = "rust1", since = "1.0.0")]
@@ -114,8 +85,9 @@ use fs;
use hash::{Hash, Hasher};
use io;
use iter::{self, FusedIterator};
-use mem;
use ops::{self, Deref};
+use rc::Rc;
+use sync::Arc;
use ffi::{OsStr, OsString};
@@ -135,36 +107,81 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
// Windows Prefixes
////////////////////////////////////////////////////////////////////////////////
-/// Path prefixes (Windows only).
+/// Windows path prefixes, e.g. `C:` or `\\server\share`.
+///
+/// Windows uses a variety of path prefix styles, including references to drive
+/// volumes (like `C:`), network shared folders (like `\\server\share`), and
+/// others. In addition, some path prefixes are "verbatim" (i.e. prefixed with
+/// `\\?\`), in which case `/` is *not* treated as a separator and essentially
+/// no normalization is performed.
///
-/// Windows uses a variety of path styles, including references to drive
-/// volumes (like `C:`), network shared folders (like `\\server\share`) and
-/// others. In addition, some path prefixes are "verbatim", in which case
-/// `/` is *not* treated as a separator and essentially no normalization is
-/// performed.
+/// # Examples
+///
+/// ```
+/// use std::path::{Component, Path, Prefix};
+/// use std::path::Prefix::*;
+/// use std::ffi::OsStr;
+///
+/// fn get_path_prefix(s: &str) -> Prefix {
+/// let path = Path::new(s);
+/// match path.components().next().unwrap() {
+/// Component::Prefix(prefix_component) => prefix_component.kind(),
+/// _ => panic!(),
+/// }
+/// }
+///
+/// # if cfg!(windows) {
+/// assert_eq!(Verbatim(OsStr::new("pictures")),
+/// get_path_prefix(r"\\?\pictures\kittens"));
+/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")),
+/// get_path_prefix(r"\\?\UNC\server\share"));
+/// assert_eq!(VerbatimDisk(b'C'), get_path_prefix(r"\\?\c:\"));
+/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")),
+/// get_path_prefix(r"\\.\BrainInterface"));
+/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")),
+/// get_path_prefix(r"\\server\share"));
+/// assert_eq!(Disk(b'C'), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris"));
+/// # }
+/// ```
#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Prefix<'a> {
- /// Prefix `\\?\`, together with the given component immediately following it.
+ /// Verbatim prefix, e.g. `\\?\cat_pics`.
+ ///
+ /// Verbatim prefixes consist of `\\?\` immediately followed by the given
+ /// component.
#[stable(feature = "rust1", since = "1.0.0")]
Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
- /// Prefix `\\?\UNC\`, with the "server" and "share" components following it.
+ /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_,
+ /// e.g. `\\?\UNC\server\share`.
+ ///
+ /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the
+ /// server's hostname and a share name.
#[stable(feature = "rust1", since = "1.0.0")]
VerbatimUNC(
#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
),
- /// Prefix like `\\?\C:\`, for the given drive letter
+ /// Verbatim disk prefix, e.g. `\\?\C:\`.
+ ///
+ /// Verbatim disk prefixes consist of `\\?\` immediately followed by the
+ /// drive letter and `:\`.
#[stable(feature = "rust1", since = "1.0.0")]
VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8),
- /// Prefix `\\.\`, together with the given component immediately following it.
+ /// Device namespace prefix, e.g. `\\.\COM42`.
+ ///
+ /// Device namespace prefixes consist of `\\.\` immediately followed by the
+ /// device name.
#[stable(feature = "rust1", since = "1.0.0")]
DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
- /// Prefix `\\server\share`, with the given "server" and "share" components.
+ /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g.
+ /// `\\server\share`.
+ ///
+ /// UNC prefixes consist of the server's hostname and a share name.
#[stable(feature = "rust1", since = "1.0.0")]
UNC(
#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
@@ -209,6 +226,20 @@ impl<'a> Prefix<'a> {
}
/// Determines if the prefix is verbatim, i.e. begins with `\\?\`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Prefix::*;
+ /// use std::ffi::OsStr;
+ ///
+ /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim());
+ /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim());
+ /// assert!(VerbatimDisk(b'C').is_verbatim());
+ /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim());
+ /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim());
+ /// assert!(!Disk(b'C').is_verbatim());
+ /// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_verbatim(&self) -> bool {
@@ -245,7 +276,7 @@ impl<'a> Prefix<'a> {
/// ```
/// use std::path;
///
-/// assert!(path::is_separator('/'));
+/// assert!(path::is_separator('/')); // '/' works for both Unix and Windows
/// assert!(!path::is_separator('❤'));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
@@ -286,10 +317,15 @@ fn iter_after<A, I, J>(mut iter: I, mut prefix: J) -> Option<I>
// See note at the top of this module to understand why these are used:
fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
- unsafe { mem::transmute(s) }
+ unsafe { &*(s as *const OsStr as *const [u8]) }
}
unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
- mem::transmute(s)
+ &*(s as *const [u8] as *const OsStr)
+}
+
+// Detect scheme on Redox
+fn has_redox_scheme(s: &[u8]) -> bool {
+ cfg!(target_os = "redox") && s.split(|b| *b == b'/').next().unwrap_or(b"").contains(&b':')
}
////////////////////////////////////////////////////////////////////////////////
@@ -348,9 +384,42 @@ enum State {
Done = 3,
}
-/// A Windows path prefix, e.g. `C:` or `\\server\share`.
+/// A structure wrapping a Windows path prefix as well as its unparsed string
+/// representation.
+///
+/// In addition to the parsed [`Prefix`] information returned by [`kind`],
+/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice,
+/// returned by [`as_os_str`].
+///
+/// Instances of this `struct` can be obtained by matching against the
+/// [`Prefix` variant] on [`Component`].
///
/// Does not occur on Unix.
+///
+/// # Examples
+///
+/// ```
+/// # if cfg!(windows) {
+/// use std::path::{Component, Path, Prefix};
+/// use std::ffi::OsStr;
+///
+/// let path = Path::new(r"c:\you\later\");
+/// match path.components().next().unwrap() {
+/// Component::Prefix(prefix_component) => {
+/// assert_eq!(Prefix::Disk(b'C'), prefix_component.kind());
+/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str());
+/// }
+/// _ => unreachable!(),
+/// }
+/// # }
+/// ```
+///
+/// [`as_os_str`]: #method.as_os_str
+/// [`Component`]: enum.Component.html
+/// [`kind`]: #method.kind
+/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
+/// [`Prefix` variant]: enum.Component.html#variant.Prefix
+/// [`Prefix`]: enum.Prefix.html
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Copy, Clone, Eq, Debug)]
pub struct PrefixComponent<'a> {
@@ -362,13 +431,20 @@ pub struct PrefixComponent<'a> {
}
impl<'a> PrefixComponent<'a> {
- /// The parsed prefix data.
+ /// Returns the parsed prefix data.
+ ///
+ /// See [`Prefix`]'s documentation for more information on the different
+ /// kinds of prefixes.
+ ///
+ /// [`Prefix`]: enum.Prefix.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn kind(&self) -> Prefix<'a> {
self.parsed
}
- /// The raw `OsStr` slice for this prefix.
+ /// Returns the raw [`OsStr`] slice for this prefix.
+ ///
+ /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_os_str(&self) -> &'a OsStr {
self.raw
@@ -405,11 +481,11 @@ impl<'a> Hash for PrefixComponent<'a> {
/// A single component of a path.
///
-/// See the module documentation for an in-depth explanation of components and
-/// their role in the API.
+/// A `Component` roughly corresponds to a substring between path separators
+/// (`/` or `\`).
///
-/// This `enum` is created from iterating over the [`path::Components`]
-/// `struct`.
+/// This `enum` is created by iterating over [`Components`], which in turn is
+/// created by the [`components`][`Path::components`] method on [`Path`].
///
/// # Examples
///
@@ -426,37 +502,49 @@ impl<'a> Hash for PrefixComponent<'a> {
/// ]);
/// ```
///
-/// [`path::Components`]: struct.Components.html
+/// [`Components`]: struct.Components.html
+/// [`Path`]: struct.Path.html
+/// [`Path::components`]: struct.Path.html#method.components
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Component<'a> {
/// A Windows path prefix, e.g. `C:` or `\\server\share`.
///
+ /// There is a large variety of prefix types, see [`Prefix`]'s documentation
+ /// for more.
+ ///
/// Does not occur on Unix.
+ ///
+ /// [`Prefix`]: enum.Prefix.html
#[stable(feature = "rust1", since = "1.0.0")]
Prefix(
#[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a>
),
- /// The root directory component, appears after any prefix and before anything else
+ /// The root directory component, appears after any prefix and before anything else.
+ ///
+ /// It represents a separator that designates that a path starts from root.
#[stable(feature = "rust1", since = "1.0.0")]
RootDir,
- /// A reference to the current directory, i.e. `.`
+ /// A reference to the current directory, i.e. `.`.
#[stable(feature = "rust1", since = "1.0.0")]
CurDir,
- /// A reference to the parent directory, i.e. `..`
+ /// A reference to the parent directory, i.e. `..`.
#[stable(feature = "rust1", since = "1.0.0")]
ParentDir,
- /// A normal component, i.e. `a` and `b` in `a/b`
+ /// A normal component, e.g. `a` and `b` in `a/b`.
+ ///
+ /// This variant is the most common one, it represents references to files
+ /// or directories.
#[stable(feature = "rust1", since = "1.0.0")]
Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
}
impl<'a> Component<'a> {
- /// Extracts the underlying `OsStr` slice.
+ /// Extracts the underlying [`OsStr`] slice.
///
/// # Examples
///
@@ -467,6 +555,8 @@ impl<'a> Component<'a> {
/// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect();
/// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
/// ```
+ ///
+ /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_os_str(self) -> &'a OsStr {
match self {
@@ -486,12 +576,17 @@ impl<'a> AsRef<OsStr> for Component<'a> {
}
}
-/// The core iterator giving the components of a path.
-///
-/// See the module documentation for an in-depth explanation of components and
-/// their role in the API.
+#[stable(feature = "path_component_asref", since = "1.24.0")]
+impl<'a> AsRef<Path> for Component<'a> {
+ fn as_ref(&self) -> &Path {
+ self.as_os_str().as_ref()
+ }
+}
+
+/// An iterator over the [`Component`]s of a [`Path`].
///
-/// This `struct` is created by the [`path::Path::components`] method.
+/// This `struct` is created by the [`components`] method on [`Path`].
+/// See its documentation for more.
///
/// # Examples
///
@@ -505,7 +600,9 @@ impl<'a> AsRef<OsStr> for Component<'a> {
/// }
/// ```
///
-/// [`path::Path::components`]: struct.Path.html#method.components
+/// [`Component`]: enum.Component.html
+/// [`components`]: struct.Path.html#method.components
+/// [`Path`]: struct.Path.html
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Components<'a> {
@@ -526,7 +623,15 @@ pub struct Components<'a> {
back: State,
}
-/// An iterator over the components of a path, as `OsStr` slices.
+/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices.
+///
+/// This `struct` is created by the [`iter`] method on [`Path`].
+/// See its documentation for more.
+///
+/// [`Component`]: enum.Component.html
+/// [`iter`]: struct.Path.html#method.iter
+/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
+/// [`Path`]: struct.Path.html
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a> {
@@ -752,6 +857,18 @@ impl<'a> fmt::Debug for Iter<'a> {
impl<'a> Iter<'a> {
/// Extracts a slice corresponding to the portion of the path remaining for iteration.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let mut iter = Path::new("/tmp/foo/bar.txt").iter();
+ /// iter.next();
+ /// iter.next();
+ ///
+ /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_path(&self) -> &'a Path {
self.inner.as_path()
@@ -935,18 +1052,44 @@ impl<'a> cmp::Ord for Components<'a> {
/// [`Deref`]: ../ops/trait.Deref.html
///
/// More details about the overall approach can be found in
-/// the module documentation.
+/// the [module documentation](index.html).
///
/// # Examples
///
+/// You can use [`push`] to build up a `PathBuf` from
+/// components:
+///
/// ```
/// use std::path::PathBuf;
///
-/// let mut path = PathBuf::from("c:\\");
+/// let mut path = PathBuf::new();
+///
+/// path.push(r"C:\");
/// path.push("windows");
/// path.push("system32");
+///
/// path.set_extension("dll");
/// ```
+///
+/// However, [`push`] is best used for dynamic situations. This is a better way
+/// to do this when you know all of the components ahead of time:
+///
+/// ```
+/// use std::path::PathBuf;
+///
+/// let path: PathBuf = [r"C:\", "windows", "system32.dll"].iter().collect();
+/// ```
+///
+/// We can still do better than this! Since these are all strings, we can use
+/// `From::from`:
+///
+/// ```
+/// use std::path::PathBuf;
+///
+/// let path = PathBuf::from(r"C:\windows\system32.dll");
+/// ```
+///
+/// Which method works best depends on what kind of situation you're in.
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PathBuf {
@@ -1055,13 +1198,14 @@ impl PathBuf {
self.inner.push(path);
}
- /// Truncate `self` to [`self.parent()`].
+ /// Truncates `self` to [`self.parent`].
///
- /// Returns false and does nothing if [`self.file_name()`] is `None`.
+ /// Returns `false` and does nothing if [`self.file_name`] is [`None`].
/// Otherwise, returns `true`.
///
- /// [`self.parent()`]: struct.PathBuf.html#method.parent
- /// [`self.file_name()`]: struct.PathBuf.html#method.file_name
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`self.parent`]: struct.PathBuf.html#method.parent
+ /// [`self.file_name`]: struct.PathBuf.html#method.file_name
///
/// # Examples
///
@@ -1086,12 +1230,18 @@ impl PathBuf {
}
}
- /// Updates [`self.file_name()`] to `file_name`.
+ /// Updates [`self.file_name`] to `file_name`.
///
- /// If [`self.file_name()`] was `None`, this is equivalent to pushing
+ /// If [`self.file_name`] was [`None`], this is equivalent to pushing
/// `file_name`.
///
- /// [`self.file_name()`]: struct.PathBuf.html#method.file_name
+ /// Otherwise it is equivalent to calling [`pop`] and then pushing
+ /// `file_name`. The new path will be a sibling of the original path.
+ /// (That is, it will have the same parent.)
+ ///
+ /// [`self.file_name`]: struct.PathBuf.html#method.file_name
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`pop`]: struct.PathBuf.html#method.pop
///
/// # Examples
///
@@ -1119,15 +1269,17 @@ impl PathBuf {
self.push(file_name);
}
- /// Updates [`self.extension()`] to `extension`.
+ /// Updates [`self.extension`] to `extension`.
///
- /// If [`self.file_name()`] is `None`, does nothing and returns `false`.
+ /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
+ /// returns `true` and updates the extension otherwise.
///
- /// Otherwise, returns `true`; if [`self.extension()`] is `None`, the
- /// extension is added; otherwise it is replaced.
+ /// If [`self.extension`] is [`None`], the extension is added; otherwise
+ /// it is replaced.
///
- /// [`self.file_name()`]: struct.PathBuf.html#method.file_name
- /// [`self.extension()`]: struct.PathBuf.html#method.extension
+ /// [`self.file_name`]: struct.PathBuf.html#method.file_name
+ /// [`self.extension`]: struct.PathBuf.html#method.extension
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// # Examples
///
@@ -1182,6 +1334,39 @@ impl PathBuf {
pub fn into_os_string(self) -> OsString {
self.inner
}
+
+ /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`].
+ ///
+ /// [`Box`]: ../../std/boxed/struct.Box.html
+ /// [`Path`]: struct.Path.html
+ #[stable(feature = "into_boxed_path", since = "1.20.0")]
+ pub fn into_boxed_path(self) -> Box<Path> {
+ let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path;
+ unsafe { Box::from_raw(rw) }
+ }
+}
+
+#[stable(feature = "box_from_path", since = "1.17.0")]
+impl<'a> From<&'a Path> for Box<Path> {
+ fn from(path: &'a Path) -> Box<Path> {
+ let boxed: Box<OsStr> = path.inner.into();
+ let rw = Box::into_raw(boxed) as *mut Path;
+ unsafe { Box::from_raw(rw) }
+ }
+}
+
+#[stable(feature = "path_buf_from_box", since = "1.18.0")]
+impl From<Box<Path>> for PathBuf {
+ fn from(boxed: Box<Path>) -> PathBuf {
+ boxed.into_path_buf()
+ }
+}
+
+#[stable(feature = "box_from_path_buf", since = "1.20.0")]
+impl From<PathBuf> for Box<Path> {
+ fn from(p: PathBuf) -> Box<Path> {
+ p.into_boxed_path()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1253,6 +1438,13 @@ impl Borrow<Path> for PathBuf {
}
}
+#[stable(feature = "default_for_pathbuf", since = "1.17.0")]
+impl Default for PathBuf {
+ fn default() -> Self {
+ PathBuf::new()
+ }
+}
+
#[stable(feature = "cow_from_path", since = "1.6.0")]
impl<'a> From<&'a Path> for Cow<'a, Path> {
#[inline]
@@ -1269,12 +1461,51 @@ impl<'a> From<PathBuf> for Cow<'a, Path> {
}
}
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<PathBuf> for Arc<Path> {
+ #[inline]
+ fn from(s: PathBuf) -> Arc<Path> {
+ let arc: Arc<OsStr> = Arc::from(s.into_os_string());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl<'a> From<&'a Path> for Arc<Path> {
+ #[inline]
+ fn from(s: &Path) -> Arc<Path> {
+ let arc: Arc<OsStr> = Arc::from(s.as_os_str());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<PathBuf> for Rc<Path> {
+ #[inline]
+ fn from(s: PathBuf) -> Rc<Path> {
+ let rc: Rc<OsStr> = Rc::from(s.into_os_string());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl<'a> From<&'a Path> for Rc<Path> {
+ #[inline]
+ fn from(s: &Path) -> Rc<Path> {
+ let rc: Rc<OsStr> = Rc::from(s.as_os_str());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl ToOwned for Path {
type Owned = PathBuf;
fn to_owned(&self) -> PathBuf {
self.to_path_buf()
}
+ fn clone_into(&self, target: &mut PathBuf) {
+ self.inner.clone_into(&mut target.inner);
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1318,9 +1549,9 @@ impl AsRef<OsStr> for PathBuf {
/// A slice of a path (akin to [`str`]).
///
/// This type supports a number of operations for inspecting a path, including
-/// breaking the path into its components (separated by `/` or `\`, depending on
-/// the platform), extracting the file name, determining whether the path is
-/// absolute, and so on.
+/// breaking the path into its components (separated by `/` on Unix and by either
+/// `/` or `\` on Windows), extracting the file name, determining whether the path
+/// is absolute, and so on.
///
/// This is an *unsized* type, meaning that it must always be used behind a
/// pointer like `&` or [`Box`]. For an owned version of this type,
@@ -1331,7 +1562,7 @@ impl AsRef<OsStr> for PathBuf {
/// [`PathBuf`]: struct.PathBuf.html
///
/// More details about the overall approach can be found in
-/// the module documentation.
+/// the [module documentation](index.html).
///
/// # Examples
///
@@ -1339,10 +1570,11 @@ impl AsRef<OsStr> for PathBuf {
/// use std::path::Path;
/// use std::ffi::OsStr;
///
-/// let path = Path::new("/tmp/foo/bar.txt");
+/// // Note: this example does work on Windows
+/// let path = Path::new("./foo/bar.txt");
///
/// let parent = path.parent();
-/// assert_eq!(parent, Some(Path::new("/tmp/foo")));
+/// assert_eq!(parent, Some(Path::new("./foo")));
///
/// let file_stem = path.file_stem();
/// assert_eq!(file_stem, Some(OsStr::new("bar")));
@@ -1355,8 +1587,14 @@ pub struct Path {
inner: OsStr,
}
-/// An error returned from the `Path::strip_prefix` method indicating that the
-/// prefix was not found in `self`.
+/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix
+/// was not found.
+///
+/// This `struct` is created by the [`strip_prefix`] method on [`Path`].
+/// See its documentation for more.
+///
+/// [`strip_prefix`]: struct.Path.html#method.strip_prefix
+/// [`Path`]: struct.Path.html
#[derive(Debug, Clone, PartialEq, Eq)]
#[stable(since = "1.7.0", feature = "strip_prefix")]
pub struct StripPrefixError(());
@@ -1372,7 +1610,7 @@ impl Path {
os_str_as_u8_slice(&self.inner)
}
- /// Directly wrap a string slice as a `Path` slice.
+ /// Directly wraps a string slice as a `Path` slice.
///
/// This is a cost-free conversion.
///
@@ -1396,7 +1634,7 @@ impl Path {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
- unsafe { mem::transmute(s.as_ref()) }
+ unsafe { &*(s.as_ref() as *const OsStr as *const Path) }
}
/// Yields the underlying [`OsStr`] slice.
@@ -1427,8 +1665,8 @@ impl Path {
/// ```
/// use std::path::Path;
///
- /// let path_str = Path::new("foo.txt").to_str();
- /// assert_eq!(path_str, Some("foo.txt"));
+ /// let path = Path::new("foo.txt");
+ /// assert_eq!(path.to_str(), Some("foo.txt"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_str(&self) -> Option<&str> {
@@ -1443,12 +1681,17 @@ impl Path {
///
/// # Examples
///
+ /// Calling `to_string_lossy` on a `Path` with valid unicode:
+ ///
/// ```
/// use std::path::Path;
///
- /// let path_str = Path::new("foo.txt").to_string_lossy();
- /// assert_eq!(path_str, "foo.txt");
+ /// let path = Path::new("foo.txt");
+ /// assert_eq!(path.to_string_lossy(), "foo.txt");
/// ```
+ ///
+ /// Had `path` contained invalid unicode, the `to_string_lossy` call might
+ /// have returned `"fo�.txt"`.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_string_lossy(&self) -> Cow<str> {
self.inner.to_string_lossy()
@@ -1466,15 +1709,17 @@ impl Path {
/// let path_buf = Path::new("foo.txt").to_path_buf();
/// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt"));
/// ```
+ #[rustc_conversion_suggestion]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_path_buf(&self) -> PathBuf {
PathBuf::from(self.inner.to_os_string())
}
- /// A path is *absolute* if it is independent of the current directory.
+ /// Returns `true` if the `Path` is absolute, i.e. if it is independent of
+ /// the current directory.
///
/// * On Unix, a path is absolute if it starts with the root, so
- /// `is_absolute` and `has_root` are equivalent.
+ /// `is_absolute` and [`has_root`] are equivalent.
///
/// * On Windows, a path is absolute if it has a prefix and starts with the
/// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not.
@@ -1486,13 +1731,22 @@ impl Path {
///
/// assert!(!Path::new("foo.txt").is_absolute());
/// ```
+ ///
+ /// [`has_root`]: #method.has_root
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
pub fn is_absolute(&self) -> bool {
- self.has_root() && (cfg!(unix) || self.prefix().is_some())
+ if cfg!(target_os = "redox") {
+ // FIXME: Allow Redox prefixes
+ self.has_root() || has_redox_scheme(self.as_u8_slice())
+ } else {
+ self.has_root() && (cfg!(unix) || self.prefix().is_some())
+ }
}
- /// A path is *relative* if it is not absolute.
+ /// Returns `true` if the `Path` is relative, i.e. not absolute.
+ ///
+ /// See [`is_absolute`]'s documentation for more details.
///
/// # Examples
///
@@ -1501,6 +1755,8 @@ impl Path {
///
/// assert!(Path::new("foo.txt").is_relative());
/// ```
+ ///
+ /// [`is_absolute`]: #method.is_absolute
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_relative(&self) -> bool {
!self.is_absolute()
@@ -1510,7 +1766,7 @@ impl Path {
self.components().prefix
}
- /// A path has a root if the body of the path begins with the directory separator.
+ /// Returns `true` if the `Path` has a root.
///
/// * On Unix, a path has a root if it begins with `/`.
///
@@ -1531,9 +1787,11 @@ impl Path {
self.components().has_root()
}
- /// The path without its final component, if any.
+ /// Returns the `Path` without its final component, if there is one.
+ ///
+ /// Returns [`None`] if the path terminates in a root or prefix.
///
- /// Returns `None` if the path terminates in a root or prefix.
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// # Examples
///
@@ -1562,31 +1820,27 @@ impl Path {
})
}
- /// The final component of the path, if it is a normal file.
+ /// Returns the final component of the `Path`, if there is one.
///
- /// If the path terminates in `..`, `file_name` will return `None`.
+ /// If the path is a normal file, this is the file name. If it's the path of a directory, this
+ /// is the directory name.
///
- /// # Examples
+ /// Returns [`None`] If the path terminates in `..`.
///
- /// ```
- /// use std::path::Path;
- /// use std::ffi::OsStr;
- ///
- /// let path = Path::new("foo.txt");
- /// let os_str = OsStr::new("foo.txt");
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
- /// assert_eq!(Some(os_str), path.file_name());
- /// ```
- ///
- /// # Other examples
+ /// # Examples
///
/// ```
/// use std::path::Path;
/// use std::ffi::OsStr;
///
+ /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name());
+ /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name());
/// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name());
/// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name());
/// assert_eq!(None, Path::new("foo.txt/..").file_name());
+ /// assert_eq!(None, Path::new("/").file_name());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn file_name(&self) -> Option<&OsStr> {
@@ -1602,8 +1856,11 @@ impl Path {
///
/// # Errors
///
- /// If `base` is not a prefix of `self` (i.e. `starts_with`
- /// returns `false`), returns `Err`.
+ /// If `base` is not a prefix of `self` (i.e. [`starts_with`]
+ /// returns `false`), returns [`Err`].
+ ///
+ /// [`starts_with`]: #method.starts_with
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
///
/// # Examples
///
@@ -1677,17 +1934,19 @@ impl Path {
iter_after(self.components().rev(), child.components().rev()).is_some()
}
- /// Extracts the stem (non-extension) portion of [`self.file_name()`].
+ /// Extracts the stem (non-extension) portion of [`self.file_name`].
///
- /// [`self.file_name()`]: struct.Path.html#method.file_name
+ /// [`self.file_name`]: struct.Path.html#method.file_name
///
/// The stem is:
///
- /// * None, if there is no file name;
+ /// * [`None`], if there is no file name;
/// * The entire file name if there is no embedded `.`;
/// * The entire file name if the file name begins with `.` and has no other `.`s within;
/// * Otherwise, the portion of the file name before the final `.`
///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
/// # Examples
///
/// ```
@@ -1702,17 +1961,18 @@ impl Path {
self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
}
- /// Extracts the extension of [`self.file_name()`], if possible.
- ///
- /// [`self.file_name()`]: struct.Path.html#method.file_name
+ /// Extracts the extension of [`self.file_name`], if possible.
///
/// The extension is:
///
- /// * None, if there is no file name;
- /// * None, if there is no embedded `.`;
- /// * None, if the file name begins with `.` and has no other `.`s within;
+ /// * [`None`], if there is no file name;
+ /// * [`None`], if there is no embedded `.`;
+ /// * [`None`], if the file name begins with `.` and has no other `.`s within;
/// * Otherwise, the portion of the file name after the final `.`
///
+ /// [`self.file_name`]: struct.Path.html#method.file_name
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
/// # Examples
///
/// ```
@@ -1766,6 +2026,9 @@ impl Path {
///
/// let path = Path::new("/tmp/foo.txt");
/// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
+ ///
+ /// let path = Path::new("/tmp");
+ /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
@@ -1804,7 +2067,21 @@ impl Path {
buf
}
- /// Produce an iterator over the components of the path.
+ /// Produces an iterator over the [`Component`]s of the path.
+ ///
+ /// When parsing the path, there is a small amount of normalization:
+ ///
+ /// * Repeated separators are ignored, so `a/b` and `a//b` both have
+ /// `a` and `b` as components.
+ ///
+ /// * Occurrences of `.` are normalized away, except if they are at the
+ /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and
+ /// `a/b` all have `a` and `b` as components, but `./a/b` starts with
+ /// an additional [`CurDir`] component.
+ ///
+ /// Note that no other normalization takes place; in particular, `a/c`
+ /// and `a/b/../c` are distinct, to account for the possibility that `b`
+ /// is a symbolic link (so its parent isn't `a`).
///
/// # Examples
///
@@ -1819,20 +2096,29 @@ impl Path {
/// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt"))));
/// assert_eq!(components.next(), None)
/// ```
+ ///
+ /// [`Component`]: enum.Component.html
+ /// [`CurDir`]: enum.Component.html#variant.CurDir
#[stable(feature = "rust1", since = "1.0.0")]
pub fn components(&self) -> Components {
let prefix = parse_prefix(self.as_os_str());
Components {
path: self.as_u8_slice(),
- prefix: prefix,
- has_physical_root: has_physical_root(self.as_u8_slice(), prefix),
+ prefix,
+ has_physical_root: has_physical_root(self.as_u8_slice(), prefix) ||
+ has_redox_scheme(self.as_u8_slice()),
front: State::Prefix,
back: State::Body,
}
}
- /// Produce an iterator over the path's components viewed as [`OsStr`] slices.
+ /// Produces an iterator over the path's components viewed as [`OsStr`]
+ /// slices.
///
+ /// For more information about the particulars of how the path is separated
+ /// into components, see [`components`].
+ ///
+ /// [`components`]: #method.components
/// [`OsStr`]: ../ffi/struct.OsStr.html
///
/// # Examples
@@ -1871,8 +2157,7 @@ impl Path {
Display { path: self }
}
-
- /// Query the file system to get information about a file, directory, etc.
+ /// Queries the file system to get information about a file, directory, etc.
///
/// This function will traverse symbolic links to query information about the
/// destination file.
@@ -1880,16 +2165,36 @@ impl Path {
/// This is an alias to [`fs::metadata`].
///
/// [`fs::metadata`]: ../fs/fn.metadata.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/Minas/tirith");
+ /// let metadata = path.metadata().expect("metadata call failed");
+ /// println!("{:?}", metadata.file_type());
+ /// ```
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn metadata(&self) -> io::Result<fs::Metadata> {
fs::metadata(self)
}
- /// Query the metadata about a file without following symlinks.
+ /// Queries the metadata about a file without following symlinks.
///
/// This is an alias to [`fs::symlink_metadata`].
///
/// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/Minas/tirith");
+ /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
+ /// println!("{:?}", metadata.file_type());
+ /// ```
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
fs::symlink_metadata(self)
@@ -1901,6 +2206,15 @@ impl Path {
/// This is an alias to [`fs::canonicalize`].
///
/// [`fs::canonicalize`]: ../fs/fn.canonicalize.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let path = Path::new("/foo/test/../test/bar.rs");
+ /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
+ /// ```
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn canonicalize(&self) -> io::Result<PathBuf> {
fs::canonicalize(self)
@@ -1911,6 +2225,15 @@ impl Path {
/// This is an alias to [`fs::read_link`].
///
/// [`fs::read_link`]: ../fs/fn.read_link.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/laputa/sky_castle.rs");
+ /// let path_link = path.read_link().expect("read_link call failed");
+ /// ```
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn read_link(&self) -> io::Result<PathBuf> {
fs::read_link(self)
@@ -1926,6 +2249,19 @@ impl Path {
/// [`io::Result`]: ../io/type.Result.html
/// [`DirEntry`]: ../fs/struct.DirEntry.html
/// [`fs::read_dir`]: ../fs/fn.read_dir.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/laputa");
+ /// for entry in path.read_dir().expect("read_dir call failed") {
+ /// if let Ok(entry) = entry {
+ /// println!("{:?}", entry.path());
+ /// }
+ /// }
+ /// ```
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
fs::read_dir(self)
@@ -1936,22 +2272,35 @@ impl Path {
/// This function will traverse symbolic links to query information about the
/// destination file. In case of broken symbolic links this will return `false`.
///
+ /// If you cannot access the directory containing the file, e.g. because of a
+ /// permission error, this will return `false`.
+ ///
/// # Examples
///
/// ```no_run
/// use std::path::Path;
/// assert_eq!(Path::new("does_not_exist.txt").exists(), false);
/// ```
+ ///
+ /// # See Also
+ ///
+ /// This is a convenience function that coerces errors to false. If you want to
+ /// check errors, call [fs::metadata].
+ ///
+ /// [fs::metadata]: ../../std/fs/fn.metadata.html
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn exists(&self) -> bool {
fs::metadata(self).is_ok()
}
- /// Returns whether the path is pointing at a regular file.
+ /// Returns whether the path exists on disk and is pointing at a regular file.
///
/// This function will traverse symbolic links to query information about the
/// destination file. In case of broken symbolic links this will return `false`.
///
+ /// If you cannot access the directory containing the file, e.g. because of a
+ /// permission error, this will return `false`.
+ ///
/// # Examples
///
/// ```no_run
@@ -1959,16 +2308,28 @@ impl Path {
/// assert_eq!(Path::new("./is_a_directory/").is_file(), false);
/// assert_eq!(Path::new("a_file.txt").is_file(), true);
/// ```
+ ///
+ /// # See Also
+ ///
+ /// This is a convenience function that coerces errors to false. If you want to
+ /// check errors, call [fs::metadata] and handle its Result. Then call
+ /// [fs::Metadata::is_file] if it was Ok.
+ ///
+ /// [fs::metadata]: ../../std/fs/fn.metadata.html
+ /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn is_file(&self) -> bool {
fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
}
- /// Returns whether the path is pointing at a directory.
+ /// Returns whether the path exists on disk and is pointing at a directory.
///
/// This function will traverse symbolic links to query information about the
/// destination file. In case of broken symbolic links this will return `false`.
///
+ /// If you cannot access the directory containing the file, e.g. because of a
+ /// permission error, this will return `false`.
+ ///
/// # Examples
///
/// ```no_run
@@ -1976,10 +2337,31 @@ impl Path {
/// assert_eq!(Path::new("./is_a_directory/").is_dir(), true);
/// assert_eq!(Path::new("a_file.txt").is_dir(), false);
/// ```
+ ///
+ /// # See Also
+ ///
+ /// This is a convenience function that coerces errors to false. If you want to
+ /// check errors, call [fs::metadata] and handle its Result. Then call
+ /// [fs::Metadata::is_dir] if it was Ok.
+ ///
+ /// [fs::metadata]: ../../std/fs/fn.metadata.html
+ /// [fs::Metadata::is_dir]: ../../std/fs/struct.Metadata.html#method.is_dir
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn is_dir(&self) -> bool {
fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
}
+
+ /// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or
+ /// allocating.
+ ///
+ /// [`Box`]: ../../std/boxed/struct.Box.html
+ /// [`PathBuf`]: struct.PathBuf.html
+ #[stable(feature = "into_boxed_path", since = "1.20.0")]
+ pub fn into_path_buf(self: Box<Path>) -> PathBuf {
+ let rw = Box::into_raw(self) as *mut OsStr;
+ let inner = unsafe { Box::from_raw(rw) };
+ PathBuf { inner: OsString::from(inner) }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1991,12 +2373,31 @@ impl AsRef<OsStr> for Path {
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for Path {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- self.inner.fmt(formatter)
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, formatter)
}
}
-/// Helper struct for safely printing paths with `format!()` and `{}`
+/// Helper struct for safely printing paths with [`format!`] and `{}`.
+///
+/// A [`Path`] might contain non-Unicode data. This `struct` implements the
+/// [`Display`] trait in a way that mitigates that. It is created by the
+/// [`display`][`Path::display`] method on [`Path`].
+///
+/// # Examples
+///
+/// ```
+/// use std::path::Path;
+///
+/// let path = Path::new("/tmp/foo.rs");
+///
+/// println!("{}", path.display());
+/// ```
+///
+/// [`Display`]: ../../std/fmt/trait.Display.html
+/// [`format!`]: ../../std/macro.format.html
+/// [`Path`]: struct.Path.html
+/// [`Path::display`]: struct.Path.html#method.display
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Display<'a> {
path: &'a Path,
@@ -2005,14 +2406,14 @@ pub struct Display<'a> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> fmt::Debug for Display<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&self.path.to_string_lossy(), f)
+ fmt::Debug::fmt(&self.path, f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> fmt::Display for Display<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.path.to_string_lossy(), f)
+ self.path.inner.display(f)
}
}
@@ -2213,6 +2614,9 @@ impl Error for StripPrefixError {
mod tests {
use super::*;
+ use rc::Rc;
+ use sync::Arc;
+
macro_rules! t(
($path:expr, iter: $iter:expr) => (
{
@@ -3397,7 +3801,7 @@ mod tests {
}
#[test]
- fn test_eq_recievers() {
+ fn test_eq_receivers() {
use borrow::Cow;
let borrowed: &Path = Path::new("foo/bar");
@@ -3589,4 +3993,47 @@ mod tests {
let actual = format!("{:?}", iter);
assert_eq!(expected, actual);
}
+
+ #[test]
+ fn into_boxed() {
+ let orig: &str = "some/sort/of/path";
+ let path = Path::new(orig);
+ let boxed: Box<Path> = Box::from(path);
+ let path_buf = path.to_owned().into_boxed_path().into_path_buf();
+ assert_eq!(path, &*boxed);
+ assert_eq!(&*boxed, &*path_buf);
+ assert_eq!(&*path_buf, path);
+ }
+
+ #[test]
+ fn test_clone_into() {
+ let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious");
+ let path = Path::new("short");
+ path.clone_into(&mut path_buf);
+ assert_eq!(path, path_buf);
+ assert!(path_buf.into_os_string().capacity() >= 15);
+ }
+
+ #[test]
+ fn display_format_flags() {
+ assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b");
+ assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b");
+ }
+
+ #[test]
+ fn into_rc() {
+ let orig = "hello/world";
+ let path = Path::new(orig);
+ let rc: Rc<Path> = Rc::from(path);
+ let arc: Arc<Path> = Arc::from(path);
+
+ assert_eq!(&*rc, path);
+ assert_eq!(&*arc, path);
+
+ let rc2: Rc<Path> = Rc::from(path.to_owned());
+ let arc2: Arc<Path> = Arc::from(path.to_owned());
+
+ assert_eq!(&*rc2, path);
+ assert_eq!(&*arc2, path);
+ }
}
diff --git a/ctr-std/src/prelude/mod.rs b/ctr-std/src/prelude/mod.rs
index f4cd319..919e033 100644
--- a/ctr-std/src/prelude/mod.rs
+++ b/ctr-std/src/prelude/mod.rs
@@ -22,13 +22,15 @@
//!
//! On a technical level, Rust inserts
//!
-//! ```ignore
+//! ```
+//! # #[allow(unused_extern_crates)]
//! extern crate std;
//! ```
//!
//! into the crate root of every crate, and
//!
-//! ```ignore
+//! ```
+//! # #[allow(unused_imports)]
//! use std::prelude::v1::*;
//! ```
//!
@@ -50,20 +52,20 @@
//! # Prelude contents
//!
//! The current version of the prelude (version 1) lives in
-//! [`std::prelude::v1`], and reexports the following.
+//! [`std::prelude::v1`], and re-exports the following.
//!
//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`]}. The marker
//! traits indicate fundamental properties of types.
//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various
//! operations for both destructors and overloading `()`.
-//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a
-//! value.
+//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly
+//! dropping a value.
//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines
-//! [`to_owned()`], the generic method for creating an owned type from a
+//! [`to_owned`], the generic method for creating an owned type from a
//! borrowed type.
-//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone()`],
-//! the method for producing a copy of a value.
+//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines
+//! [`clone`][`Clone::clone`], the method for producing a copy of a value.
//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The
//! comparison traits, which implement the comparison operators and are often
//! seen in trait bounds.
@@ -117,8 +119,8 @@
//! [`ToOwned`]: ../borrow/trait.ToOwned.html
//! [`ToString`]: ../string/trait.ToString.html
//! [`Vec`]: ../vec/struct.Vec.html
-//! [`clone()`]: ../clone/trait.Clone.html#tymethod.clone
-//! [`drop`]: ../mem/fn.drop.html
+//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone
+//! [`mem::drop`]: ../mem/fn.drop.html
//! [`std::borrow`]: ../borrow/index.html
//! [`std::boxed`]: ../boxed/index.html
//! [`std::clone`]: ../clone/index.html
@@ -135,11 +137,11 @@
//! [`std::slice`]: ../slice/index.html
//! [`std::string`]: ../string/index.html
//! [`std::vec`]: ../vec/index.html
-//! [`to_owned()`]: ../borrow/trait.ToOwned.html#tymethod.to_owned
-//! [book-closures]: ../../book/closures.html
-//! [book-dtor]: ../../book/drop.html
-//! [book-enums]: ../../book/enums.html
-//! [book-iter]: ../../book/iterators.html
+//! [`to_owned`]: ../borrow/trait.ToOwned.html#tymethod.to_owned
+//! [book-closures]: ../../book/first-edition/closures.html
+//! [book-dtor]: ../../book/first-edition/drop.html
+//! [book-enums]: ../../book/first-edition/enums.html
+//! [book-iter]: ../../book/first-edition/iterators.html
#![stable(feature = "rust1", since = "1.0.0")]
diff --git a/ctr-std/src/prelude/v1.rs b/ctr-std/src/prelude/v1.rs
index 9ca5b44..feedd4e 100644
--- a/ctr-std/src/prelude/v1.rs
+++ b/ctr-std/src/prelude/v1.rs
@@ -14,17 +14,17 @@
#![stable(feature = "rust1", since = "1.0.0")]
-// Reexported core operators
+// Re-exported core operators
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use marker::{Copy, Send, Sized, Sync};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use ops::{Drop, Fn, FnMut, FnOnce};
-// Reexported functions
+// Re-exported functions
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use mem::drop;
-// Reexported types and traits
+// Re-exported types and traits
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use boxed::Box;
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/ctr-std/src/primitive_docs.rs b/ctr-std/src/primitive_docs.rs
new file mode 100644
index 0000000..a2caf47
--- /dev/null
+++ b/ctr-std/src/primitive_docs.rs
@@ -0,0 +1,1086 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[doc(primitive = "bool")]
+//
+/// The boolean type.
+///
+/// The `bool` represents a value, which could only be either `true` or `false`. If you cast
+/// a `bool` into an integer, `true` will be 1 and `false` will be 0.
+///
+/// # Basic usage
+///
+/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc.,
+/// which allow us to perform boolean operations using `&`, `|` and `!`.
+///
+/// [`if`] always demands a `bool` value. [`assert!`], being an important macro in testing,
+/// checks whether an expression returns `true`.
+///
+/// ```
+/// let bool_val = true & false | false;
+/// assert!(!bool_val);
+/// ```
+///
+/// [`assert!`]: macro.assert.html
+/// [`if`]: ../book/first-edition/if.html
+/// [`BitAnd`]: ops/trait.BitAnd.html
+/// [`BitOr`]: ops/trait.BitOr.html
+/// [`Not`]: ops/trait.Not.html
+///
+/// # Examples
+///
+/// A trivial example of the usage of `bool`,
+///
+/// ```
+/// let praise_the_borrow_checker = true;
+///
+/// // using the `if` conditional
+/// if praise_the_borrow_checker {
+/// println!("oh, yeah!");
+/// } else {
+/// println!("what?!!");
+/// }
+///
+/// // ... or, a match pattern
+/// match praise_the_borrow_checker {
+/// true => println!("keep praising!"),
+/// false => println!("you should praise!"),
+/// }
+/// ```
+///
+/// Also, since `bool` implements the [`Copy`](marker/trait.Copy.html) trait, we don't
+/// have to worry about the move semantics (just like the integer and float primitives).
+///
+/// Now an example of `bool` cast to integer type:
+///
+/// ```
+/// assert_eq!(true as i32, 1);
+/// assert_eq!(false as i32, 0);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_bool { }
+
+#[doc(primitive = "never")]
+//
+/// The `!` type, also called "never".
+///
+/// `!` represents the type of computations which never resolve to any value at all. For example,
+/// the [`exit`] function `fn exit(code: i32) -> !` exits the process without ever returning, and
+/// so returns `!`.
+///
+/// `break`, `continue` and `return` expressions also have type `!`. For example we are allowed to
+/// write:
+///
+/// ```
+/// #![feature(never_type)]
+/// # fn foo() -> u32 {
+/// let x: ! = {
+/// return 123
+/// };
+/// # }
+/// ```
+///
+/// Although the `let` is pointless here, it illustrates the meaning of `!`. Since `x` is never
+/// assigned a value (because `return` returns from the entire function), `x` can be given type
+/// `!`. We could also replace `return 123` with a `panic!` or a never-ending `loop` and this code
+/// would still be valid.
+///
+/// A more realistic usage of `!` is in this code:
+///
+/// ```
+/// # fn get_a_number() -> Option<u32> { None }
+/// # loop {
+/// let num: u32 = match get_a_number() {
+/// Some(num) => num,
+/// None => break,
+/// };
+/// # }
+/// ```
+///
+/// Both match arms must produce values of type [`u32`], but since `break` never produces a value
+/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another
+/// behaviour of the `!` type - expressions with type `!` will coerce into any other type.
+///
+/// [`u32`]: primitive.str.html
+/// [`exit`]: process/fn.exit.html
+///
+/// # `!` and generics
+///
+/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`]
+/// trait:
+///
+/// ```
+/// trait FromStr: Sized {
+/// type Err;
+/// fn from_str(s: &str) -> Result<Self, Self::Err>;
+/// }
+/// ```
+///
+/// When implementing this trait for [`String`] we need to pick a type for [`Err`]. And since
+/// converting a string into a string will never result in an error, the appropriate type is `!`.
+/// (Currently the type actually used is an enum with no variants, though this is only because `!`
+/// was added to Rust at a later date and it may change in the future). With an [`Err`] type of
+/// `!`, if we have to call [`String::from_str`] for some reason the result will be a
+/// [`Result<String, !>`] which we can unpack like this:
+///
+/// ```ignore (string-from-str-error-type-is-not-never-yet)
+/// // NOTE: This does not work today!
+/// let Ok(s) = String::from_str("hello");
+/// ```
+///
+/// Since the [`Err`] variant contains a `!`, it can never occur. So we can exhaustively match on
+/// [`Result<T, !>`] by just taking the [`Ok`] variant. This illustrates another behaviour of `!` -
+/// it can be used to "delete" certain enum variants from generic types like `Result`.
+///
+/// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str
+/// [`Result<String, !>`]: result/enum.Result.html
+/// [`Result<T, !>`]: result/enum.Result.html
+/// [`Ok`]: result/enum.Result.html#variant.Ok
+/// [`String`]: string/struct.String.html
+/// [`Err`]: result/enum.Result.html#variant.Err
+/// [`FromStr`]: str/trait.FromStr.html
+///
+/// # `!` and traits
+///
+/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
+/// which doesn't `panic!`. As is turns out, most traits can have an `impl` for `!`. Take [`Debug`]
+/// for example:
+///
+/// ```
+/// # #![feature(never_type)]
+/// # use std::fmt;
+/// # trait Debug {
+/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result;
+/// # }
+/// impl Debug for ! {
+/// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+/// *self
+/// }
+/// }
+/// ```
+///
+/// Once again we're using `!`'s ability to coerce into any other type, in this case
+/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be
+/// called (because there is no value of type `!` for it to be called with). Writing `*self`
+/// essentially tells the compiler "We know that this code can never be run, so just treat the
+/// entire function body has having type [`fmt::Result`]". This pattern can be used a lot when
+/// implementing traits for `!`. Generally, any trait which only has methods which take a `self`
+/// parameter should have such as impl.
+///
+/// On the other hand, one trait which would not be appropriate to implement is [`Default`]:
+///
+/// ```
+/// trait Default {
+/// fn default() -> Self;
+/// }
+/// ```
+///
+/// Since `!` has no values, it has no default value either. It's true that we could write an
+/// `impl` for this which simply panics, but the same is true for any type (we could `impl
+/// Default` for (eg.) [`File`] by just making [`default()`] panic.)
+///
+/// [`fmt::Result`]: fmt/type.Result.html
+/// [`File`]: fs/struct.File.html
+/// [`Debug`]: fmt/trait.Debug.html
+/// [`Default`]: default/trait.Default.html
+/// [`default()`]: default/trait.Default.html#tymethod.default
+///
+#[unstable(feature = "never_type", issue = "35121")]
+mod prim_never { }
+
+#[doc(primitive = "char")]
+//
+/// A character type.
+///
+/// The `char` type represents a single character. More specifically, since
+/// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
+/// scalar value]', which is similar to, but not the same as, a '[Unicode code
+/// point]'.
+///
+/// [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
+/// [Unicode code point]: http://www.unicode.org/glossary/#code_point
+///
+/// This documentation describes a number of methods and trait implementations on the
+/// `char` type. For technical reasons, there is additional, separate
+/// documentation in [the `std::char` module](char/index.html) as well.
+///
+/// # Representation
+///
+/// `char` is always four bytes in size. This is a different representation than
+/// a given character would have as part of a [`String`]. For example:
+///
+/// ```
+/// let v = vec!['h', 'e', 'l', 'l', 'o'];
+///
+/// // five elements times four bytes for each element
+/// assert_eq!(20, v.len() * std::mem::size_of::<char>());
+///
+/// let s = String::from("hello");
+///
+/// // five elements times one byte per element
+/// assert_eq!(5, s.len() * std::mem::size_of::<u8>());
+/// ```
+///
+/// [`String`]: string/struct.String.html
+///
+/// As always, remember that a human intuition for 'character' may not map to
+/// Unicode's definitions. For example, despite looking similar, the 'é'
+/// character is one Unicode code point while 'é' is two Unicode code points:
+///
+/// ```
+/// let mut chars = "é".chars();
+/// // U+00e9: 'latin small letter e with acute'
+/// assert_eq!(Some('\u{00e9}'), chars.next());
+/// assert_eq!(None, chars.next());
+///
+/// let mut chars = "é".chars();
+/// // U+0065: 'latin small letter e'
+/// assert_eq!(Some('\u{0065}'), chars.next());
+/// // U+0301: 'combining acute accent'
+/// assert_eq!(Some('\u{0301}'), chars.next());
+/// assert_eq!(None, chars.next());
+/// ```
+///
+/// This means that the contents of the first string above _will_ fit into a
+/// `char` while the contents of the second string _will not_. Trying to create
+/// a `char` literal with the contents of the second string gives an error:
+///
+/// ```text
+/// error: character literal may only contain one codepoint: 'é'
+/// let c = 'é';
+/// ^^^^
+/// ```
+///
+/// Another implication of the 4-byte fixed size of a `char` is that
+/// per-`char` processing can end up using a lot more memory:
+///
+/// ```
+/// let s = String::from("love: ❤️");
+/// let v: Vec<char> = s.chars().collect();
+///
+/// assert_eq!(12, s.len() * std::mem::size_of::<u8>());
+/// assert_eq!(32, v.len() * std::mem::size_of::<char>());
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_char { }
+
+#[doc(primitive = "unit")]
+//
+/// The `()` type, sometimes called "unit" or "nil".
+///
+/// The `()` type has exactly one value `()`, and is used when there
+/// is no other meaningful value that could be returned. `()` is most
+/// commonly seen implicitly: functions without a `-> ...` implicitly
+/// have return type `()`, that is, these are equivalent:
+///
+/// ```rust
+/// fn long() -> () {}
+///
+/// fn short() {}
+/// ```
+///
+/// The semicolon `;` can be used to discard the result of an
+/// expression at the end of a block, making the expression (and thus
+/// the block) evaluate to `()`. For example,
+///
+/// ```rust
+/// fn returns_i64() -> i64 {
+/// 1i64
+/// }
+/// fn returns_unit() {
+/// 1i64;
+/// }
+///
+/// let is_i64 = {
+/// returns_i64()
+/// };
+/// let is_unit = {
+/// returns_i64();
+/// };
+/// ```
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_unit { }
+
+#[doc(primitive = "pointer")]
+//
+/// Raw, unsafe pointers, `*const T`, and `*mut T`.
+///
+/// Working with raw pointers in Rust is uncommon,
+/// typically limited to a few patterns.
+///
+/// Use the [`null`] and [`null_mut`] functions to create null pointers, and the
+/// [`is_null`] method of the `*const T` and `*mut T` types to check for null.
+/// The `*const T` and `*mut T` types also define the [`offset`] method, for
+/// pointer math.
+///
+/// # Common ways to create raw pointers
+///
+/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`).
+///
+/// ```
+/// let my_num: i32 = 10;
+/// let my_num_ptr: *const i32 = &my_num;
+/// let mut my_speed: i32 = 88;
+/// let my_speed_ptr: *mut i32 = &mut my_speed;
+/// ```
+///
+/// To get a pointer to a boxed value, dereference the box:
+///
+/// ```
+/// let my_num: Box<i32> = Box::new(10);
+/// let my_num_ptr: *const i32 = &*my_num;
+/// let mut my_speed: Box<i32> = Box::new(88);
+/// let my_speed_ptr: *mut i32 = &mut *my_speed;
+/// ```
+///
+/// This does not take ownership of the original allocation
+/// and requires no resource management later,
+/// but you must not use the pointer after its lifetime.
+///
+/// ## 2. Consume a box (`Box<T>`).
+///
+/// The [`into_raw`] function consumes a box and returns
+/// the raw pointer. It doesn't destroy `T` or deallocate any memory.
+///
+/// ```
+/// let my_speed: Box<i32> = Box::new(88);
+/// let my_speed: *mut i32 = Box::into_raw(my_speed);
+///
+/// // By taking ownership of the original `Box<T>` though
+/// // we are obligated to put it together later to be destroyed.
+/// unsafe {
+/// drop(Box::from_raw(my_speed));
+/// }
+/// ```
+///
+/// Note that here the call to [`drop`] is for clarity - it indicates
+/// that we are done with the given value and it should be destroyed.
+///
+/// ## 3. Get it from C.
+///
+/// ```
+/// # #![feature(libc)]
+/// extern crate libc;
+///
+/// use std::mem;
+///
+/// fn main() {
+/// unsafe {
+/// let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
+/// if my_num.is_null() {
+/// panic!("failed to allocate memory");
+/// }
+/// libc::free(my_num as *mut libc::c_void);
+/// }
+/// }
+/// ```
+///
+/// Usually you wouldn't literally use `malloc` and `free` from Rust,
+/// but C APIs hand out a lot of pointers generally, so are a common source
+/// of raw pointers in Rust.
+///
+/// *[See also the `std::ptr` module](ptr/index.html).*
+///
+/// [`null`]: ../std/ptr/fn.null.html
+/// [`null_mut`]: ../std/ptr/fn.null_mut.html
+/// [`is_null`]: ../std/primitive.pointer.html#method.is_null
+/// [`offset`]: ../std/primitive.pointer.html#method.offset
+/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw
+/// [`drop`]: ../std/mem/fn.drop.html
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_pointer { }
+
+#[doc(primitive = "array")]
+//
+/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the
+/// non-negative compile-time constant size, `N`.
+///
+/// There are two syntactic forms for creating an array:
+///
+/// * A list with each element, i.e. `[x, y, z]`.
+/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`.
+/// The type of `x` must be [`Copy`][copy].
+///
+/// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if
+/// the element type allows it:
+///
+/// - [`Debug`][debug]
+/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`)
+/// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord]
+/// - [`Hash`][hash]
+/// - [`AsRef`][asref], [`AsMut`][asmut]
+/// - [`Borrow`][borrow], [`BorrowMut`][borrowmut]
+/// - [`Default`][default]
+///
+/// This limitation on the size `N` exists because Rust does not yet support
+/// code that is generic over the size of an array type. `[Foo; 3]` and `[Bar; 3]`
+/// are instances of same generic type `[T; 3]`, but `[Foo; 3]` and `[Foo; 5]` are
+/// entirely different types. As a stopgap, trait implementations are
+/// statically generated up to size 32.
+///
+/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy]
+/// and [`Clone`][clone] if the element type is [`Clone`][clone]. This works
+/// because [`Copy`][copy] and [`Clone`][clone] traits are specially known
+/// to the compiler.
+///
+/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
+/// an array. Indeed, this provides most of the API for working with arrays.
+/// Slices have a dynamic size and do not coerce to arrays.
+///
+/// There is no way to move elements out of an array. See [`mem::replace`][replace]
+/// for an alternative.
+///
+/// # Examples
+///
+/// ```
+/// let mut array: [i32; 3] = [0; 3];
+///
+/// array[1] = 1;
+/// array[2] = 2;
+///
+/// assert_eq!([1, 2], &array[1..]);
+///
+/// // This loop prints: 0 1 2
+/// for x in &array {
+/// print!("{} ", x);
+/// }
+/// ```
+///
+/// An array itself is not iterable:
+///
+/// ```compile_fail,E0277
+/// let array: [i32; 3] = [0; 3];
+///
+/// for x in array { }
+/// // error: the trait bound `[i32; 3]: std::iter::Iterator` is not satisfied
+/// ```
+///
+/// The solution is to coerce the array to a slice by calling a slice method:
+///
+/// ```
+/// # let array: [i32; 3] = [0; 3];
+/// for x in array.iter() { }
+/// ```
+///
+/// If the array has 32 or fewer elements (see above), you can also use the
+/// array reference's [`IntoIterator`] implementation:
+///
+/// ```
+/// # let array: [i32; 3] = [0; 3];
+/// for x in &array { }
+/// ```
+///
+/// [slice]: primitive.slice.html
+/// [copy]: marker/trait.Copy.html
+/// [clone]: clone/trait.Clone.html
+/// [debug]: fmt/trait.Debug.html
+/// [intoiterator]: iter/trait.IntoIterator.html
+/// [partialeq]: cmp/trait.PartialEq.html
+/// [partialord]: cmp/trait.PartialOrd.html
+/// [eq]: cmp/trait.Eq.html
+/// [ord]: cmp/trait.Ord.html
+/// [hash]: hash/trait.Hash.html
+/// [asref]: convert/trait.AsRef.html
+/// [asmut]: convert/trait.AsMut.html
+/// [borrow]: borrow/trait.Borrow.html
+/// [borrowmut]: borrow/trait.BorrowMut.html
+/// [default]: default/trait.Default.html
+/// [replace]: mem/fn.replace.html
+/// [`IntoIterator`]: iter/trait.IntoIterator.html
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_array { }
+
+#[doc(primitive = "slice")]
+//
+/// A dynamically-sized view into a contiguous sequence, `[T]`.
+///
+/// Slices are a view into a block of memory represented as a pointer and a
+/// length.
+///
+/// ```
+/// // slicing a Vec
+/// let vec = vec![1, 2, 3];
+/// let int_slice = &vec[..];
+/// // coercing an array to a slice
+/// let str_slice: &[&str] = &["one", "two", "three"];
+/// ```
+///
+/// Slices are either mutable or shared. The shared slice type is `&[T]`,
+/// while the mutable slice type is `&mut [T]`, where `T` represents the element
+/// type. For example, you can mutate the block of memory that a mutable slice
+/// points to:
+///
+/// ```
+/// let x = &mut [1, 2, 3];
+/// x[1] = 7;
+/// assert_eq!(x, &[1, 7, 3]);
+/// ```
+///
+/// *[See also the `std::slice` module](slice/index.html).*
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_slice { }
+
+#[doc(primitive = "str")]
+//
+/// String slices.
+///
+/// The `str` type, also called a 'string slice', is the most primitive string
+/// type. It is usually seen in its borrowed form, `&str`. It is also the type
+/// of string literals, `&'static str`.
+///
+/// Strings slices are always valid UTF-8.
+///
+/// This documentation describes a number of methods and trait implementations
+/// on the `str` type. For technical reasons, there is additional, separate
+/// documentation in the [`std::str`](str/index.html) module as well.
+///
+/// # Examples
+///
+/// String literals are string slices:
+///
+/// ```
+/// let hello = "Hello, world!";
+///
+/// // with an explicit type annotation
+/// let hello: &'static str = "Hello, world!";
+/// ```
+///
+/// They are `'static` because they're stored directly in the final binary, and
+/// so will be valid for the `'static` duration.
+///
+/// # Representation
+///
+/// A `&str` is made up of two components: a pointer to some bytes, and a
+/// length. You can look at these with the [`as_ptr`] and [`len`] methods:
+///
+/// ```
+/// use std::slice;
+/// use std::str;
+///
+/// let story = "Once upon a time...";
+///
+/// let ptr = story.as_ptr();
+/// let len = story.len();
+///
+/// // story has nineteen bytes
+/// assert_eq!(19, len);
+///
+/// // We can re-build a str out of ptr and len. This is all unsafe because
+/// // we are responsible for making sure the two components are valid:
+/// let s = unsafe {
+/// // First, we build a &[u8]...
+/// let slice = slice::from_raw_parts(ptr, len);
+///
+/// // ... and then convert that slice into a string slice
+/// str::from_utf8(slice)
+/// };
+///
+/// assert_eq!(s, Ok(story));
+/// ```
+///
+/// [`as_ptr`]: #method.as_ptr
+/// [`len`]: #method.len
+///
+/// Note: This example shows the internals of `&str`. `unsafe` should not be
+/// used to get a string slice under normal circumstances. Use `as_slice`
+/// instead.
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_str { }
+
+#[doc(primitive = "tuple")]
+//
+/// A finite heterogeneous sequence, `(T, U, ..)`.
+///
+/// Let's cover each of those in turn:
+///
+/// Tuples are *finite*. In other words, a tuple has a length. Here's a tuple
+/// of length `3`:
+///
+/// ```
+/// ("hello", 5, 'c');
+/// ```
+///
+/// 'Length' is also sometimes called 'arity' here; each tuple of a different
+/// length is a different, distinct type.
+///
+/// Tuples are *heterogeneous*. This means that each element of the tuple can
+/// have a different type. In that tuple above, it has the type:
+///
+/// ```
+/// # let _:
+/// (&'static str, i32, char)
+/// # = ("hello", 5, 'c');
+/// ```
+///
+/// Tuples are a *sequence*. This means that they can be accessed by position;
+/// this is called 'tuple indexing', and it looks like this:
+///
+/// ```rust
+/// let tuple = ("hello", 5, 'c');
+///
+/// assert_eq!(tuple.0, "hello");
+/// assert_eq!(tuple.1, 5);
+/// assert_eq!(tuple.2, 'c');
+/// ```
+///
+/// For more about tuples, see [the book](../book/first-edition/primitive-types.html#tuples).
+///
+/// # Trait implementations
+///
+/// If every type inside a tuple implements one of the following traits, then a
+/// tuple itself also implements it.
+///
+/// * [`Clone`]
+/// * [`Copy`]
+/// * [`PartialEq`]
+/// * [`Eq`]
+/// * [`PartialOrd`]
+/// * [`Ord`]
+/// * [`Debug`]
+/// * [`Default`]
+/// * [`Hash`]
+///
+/// [`Clone`]: clone/trait.Clone.html
+/// [`Copy`]: marker/trait.Copy.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+/// [`Eq`]: cmp/trait.Eq.html
+/// [`PartialOrd`]: cmp/trait.PartialOrd.html
+/// [`Ord`]: cmp/trait.Ord.html
+/// [`Debug`]: fmt/trait.Debug.html
+/// [`Default`]: default/trait.Default.html
+/// [`Hash`]: hash/trait.Hash.html
+///
+/// Due to a temporary restriction in Rust's type system, these traits are only
+/// implemented on tuples of arity 12 or less. In the future, this may change.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// let tuple = ("hello", 5, 'c');
+///
+/// assert_eq!(tuple.0, "hello");
+/// ```
+///
+/// Tuples are often used as a return type when you want to return more than
+/// one value:
+///
+/// ```
+/// fn calculate_point() -> (i32, i32) {
+/// // Don't do a calculation, that's not the point of the example
+/// (4, 5)
+/// }
+///
+/// let point = calculate_point();
+///
+/// assert_eq!(point.0, 4);
+/// assert_eq!(point.1, 5);
+///
+/// // Combining this with patterns can be nicer.
+///
+/// let (x, y) = calculate_point();
+///
+/// assert_eq!(x, 4);
+/// assert_eq!(y, 5);
+/// ```
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_tuple { }
+
+#[doc(primitive = "f32")]
+/// The 32-bit floating point type.
+///
+/// *[See also the `std::f32` module](f32/index.html).*
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_f32 { }
+
+#[doc(primitive = "f64")]
+//
+/// The 64-bit floating point type.
+///
+/// *[See also the `std::f64` module](f64/index.html).*
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_f64 { }
+
+#[doc(primitive = "i8")]
+//
+/// The 8-bit signed integer type.
+///
+/// *[See also the `std::i8` module](i8/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `i64` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_i8 { }
+
+#[doc(primitive = "i16")]
+//
+/// The 16-bit signed integer type.
+///
+/// *[See also the `std::i16` module](i16/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `i32` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_i16 { }
+
+#[doc(primitive = "i32")]
+//
+/// The 32-bit signed integer type.
+///
+/// *[See also the `std::i32` module](i32/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `i16` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_i32 { }
+
+#[doc(primitive = "i64")]
+//
+/// The 64-bit signed integer type.
+///
+/// *[See also the `std::i64` module](i64/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `i8` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_i64 { }
+
+#[doc(primitive = "i128")]
+//
+/// The 128-bit signed integer type.
+///
+/// *[See also the `std::i128` module](i128/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `i8` in there.
+///
+#[unstable(feature = "i128", issue="35118")]
+mod prim_i128 { }
+
+#[doc(primitive = "u8")]
+//
+/// The 8-bit unsigned integer type.
+///
+/// *[See also the `std::u8` module](u8/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `u64` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_u8 { }
+
+#[doc(primitive = "u16")]
+//
+/// The 16-bit unsigned integer type.
+///
+/// *[See also the `std::u16` module](u16/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `u32` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_u16 { }
+
+#[doc(primitive = "u32")]
+//
+/// The 32-bit unsigned integer type.
+///
+/// *[See also the `std::u32` module](u32/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `u16` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_u32 { }
+
+#[doc(primitive = "u64")]
+//
+/// The 64-bit unsigned integer type.
+///
+/// *[See also the `std::u64` module](u64/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `u8` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_u64 { }
+
+#[doc(primitive = "u128")]
+//
+/// The 128-bit unsigned integer type.
+///
+/// *[See also the `std::u128` module](u128/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `u8` in there.
+///
+#[unstable(feature = "i128", issue="35118")]
+mod prim_u128 { }
+
+#[doc(primitive = "isize")]
+//
+/// The pointer-sized signed integer type.
+///
+/// The size of this primitive is how many bytes it takes to reference any
+/// location in memory. For example, on a 32 bit target, this is 4 bytes
+/// and on a 64 bit target, this is 8 bytes.
+///
+/// *[See also the `std::isize` module](isize/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `usize` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_isize { }
+
+#[doc(primitive = "usize")]
+//
+/// The pointer-sized unsigned integer type.
+///
+/// The size of this primitive is how many bytes it takes to reference any
+/// location in memory. For example, on a 32 bit target, this is 4 bytes
+/// and on a 64 bit target, this is 8 bytes.
+///
+/// *[See also the `std::usize` module](usize/index.html).*
+///
+/// However, please note that examples are shared between primitive integer
+/// types. So it's normal if you see usage of types like `isize` in there.
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_usize { }
+
+#[doc(primitive = "reference")]
+//
+/// References, both shared and mutable.
+///
+/// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut`
+/// operators on a value, or by using a `ref` or `ref mut` pattern.
+///
+/// For those familiar with pointers, a reference is just a pointer that is assumed to not be null.
+/// In fact, `Option<&T>` has the same memory representation as a nullable pointer, and can be
+/// passed across FFI boundaries as such.
+///
+/// In most cases, references can be used much like the original value. Field access, method
+/// calling, and indexing work the same (save for mutability rules, of course). In addition, the
+/// comparison operators transparently defer to the referent's implementation, allowing references
+/// to be compared the same as owned values.
+///
+/// References have a lifetime attached to them, which represents the scope for which the borrow is
+/// valid. A lifetime is said to "outlive" another one if its representative scope is as long or
+/// longer than the other. The `'static` lifetime is the longest lifetime, which represents the
+/// total life of the program. For example, string literals have a `'static` lifetime because the
+/// text data is embedded into the binary of the program, rather than in an allocation that needs
+/// to be dynamically managed.
+///
+/// `&mut T` references can be freely coerced into `&T` references with the same referent type, and
+/// references with longer lifetimes can be freely coerced into references with shorter ones.
+///
+/// For more information on how to use references, see [the book's section on "References and
+/// Borrowing"][book-refs].
+///
+/// [book-refs]: ../book/second-edition/ch04-02-references-and-borrowing.html
+///
+/// The following traits are implemented for all `&T`, regardless of the type of its referent:
+///
+/// * [`Copy`]
+/// * [`Clone`] \(Note that this will not defer to `T`'s `Clone` implementation if it exists!)
+/// * [`Deref`]
+/// * [`Borrow`]
+/// * [`Pointer`]
+///
+/// [`Copy`]: marker/trait.Copy.html
+/// [`Clone`]: clone/trait.Clone.html
+/// [`Deref`]: ops/trait.Deref.html
+/// [`Borrow`]: borrow/trait.Borrow.html
+/// [`Pointer`]: fmt/trait.Pointer.html
+///
+/// `&mut T` references get all of the above except `Copy` and `Clone` (to prevent creating
+/// multiple simultaneous mutable borrows), plus the following, regardless of the type of its
+/// referent:
+///
+/// * [`DerefMut`]
+/// * [`BorrowMut`]
+///
+/// [`DerefMut`]: ops/trait.DerefMut.html
+/// [`BorrowMut`]: borrow/trait.BorrowMut.html
+///
+/// The following traits are implemented on `&T` references if the underlying `T` also implements
+/// that trait:
+///
+/// * All the traits in [`std::fmt`] except [`Pointer`] and [`fmt::Write`]
+/// * [`PartialOrd`]
+/// * [`Ord`]
+/// * [`PartialEq`]
+/// * [`Eq`]
+/// * [`AsRef`]
+/// * [`Fn`] \(in addition, `&T` references get [`FnMut`] and [`FnOnce`] if `T: Fn`)
+/// * [`Hash`]
+/// * [`ToSocketAddrs`]
+///
+/// [`std::fmt`]: fmt/index.html
+/// [`fmt::Write`]: fmt/trait.Write.html
+/// [`PartialOrd`]: cmp/trait.PartialOrd.html
+/// [`Ord`]: cmp/trait.Ord.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+/// [`Eq`]: cmp/trait.Eq.html
+/// [`AsRef`]: convert/trait.AsRef.html
+/// [`Fn`]: ops/trait.Fn.html
+/// [`FnMut`]: ops/trait.FnMut.html
+/// [`FnOnce`]: ops/trait.FnOnce.html
+/// [`Hash`]: hash/trait.Hash.html
+/// [`ToSocketAddrs`]: net/trait.ToSocketAddrs.html
+///
+/// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T`
+/// implements that trait:
+///
+/// * [`AsMut`]
+/// * [`FnMut`] \(in addition, `&mut T` references get [`FnOnce`] if `T: FnMut`)
+/// * [`fmt::Write`]
+/// * [`Iterator`]
+/// * [`DoubleEndedIterator`]
+/// * [`ExactSizeIterator`]
+/// * [`FusedIterator`]
+/// * [`TrustedLen`]
+/// * [`Send`] \(note that `&T` references only get `Send` if `T: Sync`)
+/// * [`io::Write`]
+/// * [`Read`]
+/// * [`Seek`]
+/// * [`BufRead`]
+///
+/// [`AsMut`]: convert/trait.AsMut.html
+/// [`Iterator`]: iter/trait.Iterator.html
+/// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+/// [`ExactSizeIterator`]: iter/trait.ExactSizeIterator.html
+/// [`FusedIterator`]: iter/trait.FusedIterator.html
+/// [`TrustedLen`]: iter/trait.TrustedLen.html
+/// [`Send`]: marker/trait.Send.html
+/// [`io::Write`]: io/trait.Write.html
+/// [`Read`]: io/trait.Read.html
+/// [`Seek`]: io/trait.Seek.html
+/// [`BufRead`]: io/trait.BufRead.html
+///
+/// Note that due to method call deref coercion, simply calling a trait method will act like they
+/// work on references as well as they do on owned values! The implementations described here are
+/// meant for generic contexts, where the final type `T` is a type parameter or otherwise not
+/// locally known.
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_ref { }
+
+#[doc(primitive = "fn")]
+//
+/// Function pointers, like `fn(usize) -> bool`.
+///
+/// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].*
+///
+/// [`Fn`]: ops/trait.Fn.html
+/// [`FnMut`]: ops/trait.FnMut.html
+/// [`FnOnce`]: ops/trait.FnOnce.html
+///
+/// Plain function pointers are obtained by casting either plain functions, or closures that don't
+/// capture an environment:
+///
+/// ```
+/// fn add_one(x: usize) -> usize {
+/// x + 1
+/// }
+///
+/// let ptr: fn(usize) -> usize = add_one;
+/// assert_eq!(ptr(5), 6);
+///
+/// let clos: fn(usize) -> usize = |x| x + 5;
+/// assert_eq!(clos(5), 10);
+/// ```
+///
+/// In addition to varying based on their signature, function pointers come in two flavors: safe
+/// and unsafe. Plain `fn()` function pointers can only point to safe functions,
+/// while `unsafe fn()` function pointers can point to safe or unsafe functions.
+///
+/// ```
+/// fn add_one(x: usize) -> usize {
+/// x + 1
+/// }
+///
+/// unsafe fn add_one_unsafely(x: usize) -> usize {
+/// x + 1
+/// }
+///
+/// let safe_ptr: fn(usize) -> usize = add_one;
+///
+/// //ERROR: mismatched types: expected normal fn, found unsafe fn
+/// //let bad_ptr: fn(usize) -> usize = add_one_unsafely;
+///
+/// let unsafe_ptr: unsafe fn(usize) -> usize = add_one_unsafely;
+/// let really_safe_ptr: unsafe fn(usize) -> usize = add_one;
+/// ```
+///
+/// On top of that, function pointers can vary based on what ABI they use. This is achieved by
+/// adding the `extern` keyword to the type name, followed by the ABI in question. For example,
+/// `fn()` is different from `extern "C" fn()`, which itself is different from `extern "stdcall"
+/// fn()`, and so on for the various ABIs that Rust supports. Non-`extern` functions have an ABI
+/// of `"Rust"`, and `extern` functions without an explicit ABI have an ABI of `"C"`. For more
+/// information, see [the nomicon's section on foreign calling conventions][nomicon-abi].
+///
+/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions
+///
+/// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them
+/// to be called with a variable number of arguments. Normal rust functions, even those with an
+/// `extern "ABI"`, cannot be variadic. For more information, see [the nomicon's section on
+/// variadic functions][nomicon-variadic].
+///
+/// [nomicon-variadic]: ../nomicon/ffi.html#variadic-functions
+///
+/// These markers can be combined, so `unsafe extern "stdcall" fn()` is a valid type.
+///
+/// Like references in rust, function pointers are assumed to not be null, so if you want to pass a
+/// function pointer over FFI and be able to accommodate null pointers, make your type
+/// `Option<fn()>` with your required signature.
+///
+/// Function pointers implement the following traits:
+///
+/// * [`Clone`]
+/// * [`PartialEq`]
+/// * [`Eq`]
+/// * [`PartialOrd`]
+/// * [`Ord`]
+/// * [`Hash`]
+/// * [`Pointer`]
+/// * [`Debug`]
+///
+/// [`Clone`]: clone/trait.Clone.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+/// [`Eq`]: cmp/trait.Eq.html
+/// [`PartialOrd`]: cmp/trait.PartialOrd.html
+/// [`Ord`]: cmp/trait.Ord.html
+/// [`Hash`]: hash/trait.Hash.html
+/// [`Pointer`]: fmt/trait.Pointer.html
+/// [`Debug`]: fmt/trait.Debug.html
+///
+/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
+/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
+/// may change.
+///
+/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe*
+/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits
+/// are specially known to the compiler.
+///
+/// [`Copy`]: marker/trait.Copy.html
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_fn { }
diff --git a/ctr-std/src/process.rs b/ctr-std/src/process.rs
new file mode 100644
index 0000000..5c66ac6
--- /dev/null
+++ b/ctr-std/src/process.rs
@@ -0,0 +1,1846 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! A module for working with processes.
+//!
+//! This module is mostly concerned with spawning and interacting with child
+//! processes, but it also provides [`abort`] and [`exit`] for terminating the
+//! current process.
+//!
+//! # Spawning a process
+//!
+//! The [`Command`] struct is used to configure and spawn processes:
+//!
+//! ```
+//! use std::process::Command;
+//!
+//! let output = Command::new("echo")
+//! .arg("Hello world")
+//! .output()
+//! .expect("Failed to execute command");
+//!
+//! assert_eq!(b"Hello world\n", output.stdout.as_slice());
+//! ```
+//!
+//! Several methods on [`Command`], such as [`spawn`] or [`output`], can be used
+//! to spawn a process. In particular, [`output`] spawns the child process and
+//! waits until the process terminates, while [`spawn`] will return a [`Child`]
+//! that represents the spawned child process.
+//!
+//! # Handling I/O
+//!
+//! The [`stdout`], [`stdin`], and [`stderr`] of a child process can be
+//! configured by passing an [`Stdio`] to the corresponding method on
+//! [`Command`]. Once spawned, they can be accessed from the [`Child`]. For
+//! example, piping output from one command into another command can be done
+//! like so:
+//!
+//! ```no_run
+//! use std::process::{Command, Stdio};
+//!
+//! // stdout must be configured with `Stdio::piped` in order to use
+//! // `echo_child.stdout`
+//! let echo_child = Command::new("echo")
+//! .arg("Oh no, a tpyo!")
+//! .stdout(Stdio::piped())
+//! .spawn()
+//! .expect("Failed to start echo process");
+//!
+//! // Note that `echo_child` is moved here, but we won't be needing
+//! // `echo_child` anymore
+//! let echo_out = echo_child.stdout.expect("Failed to open echo stdout");
+//!
+//! let mut sed_child = Command::new("sed")
+//! .arg("s/tpyo/typo/")
+//! .stdin(Stdio::from(echo_out))
+//! .stdout(Stdio::piped())
+//! .spawn()
+//! .expect("Failed to start sed process");
+//!
+//! let output = sed_child.wait_with_output().expect("Failed to wait on sed");
+//! assert_eq!(b"Oh no, a typo!\n", output.stdout.as_slice());
+//! ```
+//!
+//! Note that [`ChildStderr`] and [`ChildStdout`] implement [`Read`] and
+//! [`ChildStdin`] implements [`Write`]:
+//!
+//! ```no_run
+//! use std::process::{Command, Stdio};
+//! use std::io::Write;
+//!
+//! let mut child = Command::new("/bin/cat")
+//! .stdin(Stdio::piped())
+//! .stdout(Stdio::piped())
+//! .spawn()
+//! .expect("failed to execute child");
+//!
+//! {
+//! // limited borrow of stdin
+//! let stdin = child.stdin.as_mut().expect("failed to get stdin");
+//! stdin.write_all(b"test").expect("failed to write to stdin");
+//! }
+//!
+//! let output = child
+//! .wait_with_output()
+//! .expect("failed to wait on child");
+//!
+//! assert_eq!(b"test", output.stdout.as_slice());
+//! ```
+//!
+//! [`abort`]: fn.abort.html
+//! [`exit`]: fn.exit.html
+//!
+//! [`Command`]: struct.Command.html
+//! [`spawn`]: struct.Command.html#method.spawn
+//! [`output`]: struct.Command.html#method.output
+//!
+//! [`Child`]: struct.Child.html
+//! [`ChildStdin`]: struct.ChildStdin.html
+//! [`ChildStdout`]: struct.ChildStdout.html
+//! [`ChildStderr`]: struct.ChildStderr.html
+//! [`Stdio`]: struct.Stdio.html
+//!
+//! [`stdout`]: struct.Command.html#method.stdout
+//! [`stdin`]: struct.Command.html#method.stdin
+//! [`stderr`]: struct.Command.html#method.stderr
+//!
+//! [`Write`]: ../io/trait.Write.html
+//! [`Read`]: ../io/trait.Read.html
+
+#![stable(feature = "process", since = "1.0.0")]
+
+use io::prelude::*;
+
+use ffi::OsStr;
+use fmt;
+use fs;
+use io::{self, Initializer};
+use path::Path;
+use str;
+use sys::pipe::{read2, AnonPipe};
+use sys::process as imp;
+use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+/// Representation of a running or exited child process.
+///
+/// This structure is used to represent and manage child processes. A child
+/// process is created via the [`Command`] struct, which configures the
+/// spawning process and can itself be constructed using a builder-style
+/// interface.
+///
+/// There is no implementation of [`Drop`] for child processes,
+/// so if you do not ensure the `Child` has exited then it will continue to
+/// run, even after the `Child` handle to the child process has gone out of
+/// scope.
+///
+/// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make
+/// the parent process wait until the child has actually exited before
+/// continuing.
+///
+/// # Examples
+///
+/// ```should_panic
+/// use std::process::Command;
+///
+/// let mut child = Command::new("/bin/cat")
+/// .arg("file.txt")
+/// .spawn()
+/// .expect("failed to execute child");
+///
+/// let ecode = child.wait()
+/// .expect("failed to wait on child");
+///
+/// assert!(ecode.success());
+/// ```
+///
+/// [`Command`]: struct.Command.html
+/// [`Drop`]: ../../core/ops/trait.Drop.html
+/// [`wait`]: #method.wait
+#[stable(feature = "process", since = "1.0.0")]
+pub struct Child {
+ handle: imp::Process,
+
+ /// The handle for writing to the child's standard input (stdin), if it has
+ /// been captured.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stdin: Option<ChildStdin>,
+
+ /// The handle for reading from the child's standard output (stdout), if it
+ /// has been captured.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stdout: Option<ChildStdout>,
+
+ /// The handle for reading from the child's standard error (stderr), if it
+ /// has been captured.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stderr: Option<ChildStderr>,
+}
+
+impl AsInner<imp::Process> for Child {
+ fn as_inner(&self) -> &imp::Process { &self.handle }
+}
+
+impl FromInner<(imp::Process, imp::StdioPipes)> for Child {
+ fn from_inner((handle, io): (imp::Process, imp::StdioPipes)) -> Child {
+ Child {
+ handle,
+ stdin: io.stdin.map(ChildStdin::from_inner),
+ stdout: io.stdout.map(ChildStdout::from_inner),
+ stderr: io.stderr.map(ChildStderr::from_inner),
+ }
+ }
+}
+
+impl IntoInner<imp::Process> for Child {
+ fn into_inner(self) -> imp::Process { self.handle }
+}
+
+#[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")
+ .field("stdin", &self.stdin)
+ .field("stdout", &self.stdout)
+ .field("stderr", &self.stderr)
+ .finish()
+ }
+}
+
+/// A handle to a child process's standard input (stdin).
+///
+/// This struct is used in the [`stdin`] field on [`Child`].
+///
+/// When an instance of `ChildStdin` is [dropped], the `ChildStdin`'s underlying
+/// file handle will be closed. If the child process was blocked on input prior
+/// to being dropped, it will become unblocked after dropping.
+///
+/// [`Child`]: struct.Child.html
+/// [`stdin`]: struct.Child.html#structfield.stdin
+/// [dropped]: ../ops/trait.Drop.html
+#[stable(feature = "process", since = "1.0.0")]
+pub struct ChildStdin {
+ inner: AnonPipe
+}
+
+#[stable(feature = "process", since = "1.0.0")]
+impl Write for ChildStdin {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl AsInner<AnonPipe> for ChildStdin {
+ fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
+impl IntoInner<AnonPipe> for ChildStdin {
+ fn into_inner(self) -> AnonPipe { self.inner }
+}
+
+impl FromInner<AnonPipe> for ChildStdin {
+ fn from_inner(pipe: AnonPipe) -> ChildStdin {
+ ChildStdin { inner: pipe }
+ }
+}
+
+#[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 { .. }")
+ }
+}
+
+/// A handle to a child process's standard output (stdout).
+///
+/// This struct is used in the [`stdout`] field on [`Child`].
+///
+/// When an instance of `ChildStdout` is [dropped], the `ChildStdout`'s
+/// underlying file handle will be closed.
+///
+/// [`Child`]: struct.Child.html
+/// [`stdout`]: struct.Child.html#structfield.stdout
+/// [dropped]: ../ops/trait.Drop.html
+#[stable(feature = "process", since = "1.0.0")]
+pub struct ChildStdout {
+ inner: AnonPipe
+}
+
+#[stable(feature = "process", since = "1.0.0")]
+impl Read for ChildStdout {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+impl AsInner<AnonPipe> for ChildStdout {
+ fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
+impl IntoInner<AnonPipe> for ChildStdout {
+ fn into_inner(self) -> AnonPipe { self.inner }
+}
+
+impl FromInner<AnonPipe> for ChildStdout {
+ fn from_inner(pipe: AnonPipe) -> ChildStdout {
+ ChildStdout { inner: pipe }
+ }
+}
+
+#[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 { .. }")
+ }
+}
+
+/// A handle to a child process's stderr.
+///
+/// This struct is used in the [`stderr`] field on [`Child`].
+///
+/// When an instance of `ChildStderr` is [dropped], the `ChildStderr`'s
+/// underlying file handle will be closed.
+///
+/// [`Child`]: struct.Child.html
+/// [`stderr`]: struct.Child.html#structfield.stderr
+/// [dropped]: ../ops/trait.Drop.html
+#[stable(feature = "process", since = "1.0.0")]
+pub struct ChildStderr {
+ inner: AnonPipe
+}
+
+#[stable(feature = "process", since = "1.0.0")]
+impl Read for ChildStderr {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+impl AsInner<AnonPipe> for ChildStderr {
+ fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
+impl IntoInner<AnonPipe> for ChildStderr {
+ fn into_inner(self) -> AnonPipe { self.inner }
+}
+
+impl FromInner<AnonPipe> for ChildStderr {
+ fn from_inner(pipe: AnonPipe) -> ChildStderr {
+ ChildStderr { inner: pipe }
+ }
+}
+
+#[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 { .. }")
+ }
+}
+
+/// A process builder, providing fine-grained control
+/// over how a new process should be spawned.
+///
+/// A default configuration can be
+/// generated using `Command::new(program)`, where `program` gives a path to the
+/// program to be executed. Additional builder methods allow the configuration
+/// to be changed (for example, by adding arguments) prior to spawning:
+///
+/// ```
+/// use std::process::Command;
+///
+/// let output = if cfg!(target_os = "windows") {
+/// Command::new("cmd")
+/// .args(&["/C", "echo hello"])
+/// .output()
+/// .expect("failed to execute process")
+/// } else {
+/// Command::new("sh")
+/// .arg("-c")
+/// .arg("echo hello")
+/// .output()
+/// .expect("failed to execute process")
+/// };
+///
+/// let hello = output.stdout;
+/// ```
+#[stable(feature = "process", since = "1.0.0")]
+pub struct Command {
+ inner: imp::Command,
+}
+
+impl Command {
+ /// Constructs a new `Command` for launching the program at
+ /// path `program`, with the following default configuration:
+ ///
+ /// * No arguments to the program
+ /// * Inherit the current process's environment
+ /// * Inherit the current process's working directory
+ /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output`
+ ///
+ /// Builder methods are provided to change these defaults and
+ /// otherwise configure the process.
+ ///
+ /// If `program` is not an absolute path, the `PATH` will be searched in
+ /// an OS-defined way.
+ ///
+ /// The search path to be used may be controlled by setting the
+ /// `PATH` environment variable on the Command,
+ /// but this has some implementation limitations on Windows
+ /// (see <https://github.com/rust-lang/rust/issues/37519>).
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("sh")
+ /// .spawn()
+ /// .expect("sh command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
+ Command { inner: imp::Command::new(program.as_ref()) }
+ }
+
+ /// Add an argument to pass to the program.
+ ///
+ /// Only one argument can be passed per use. So instead of:
+ ///
+ /// ```no_run
+ /// # std::process::Command::new("sh")
+ /// .arg("-C /path/to/repo")
+ /// # ;
+ /// ```
+ ///
+ /// usage would be:
+ ///
+ /// ```no_run
+ /// # std::process::Command::new("sh")
+ /// .arg("-C")
+ /// .arg("/path/to/repo")
+ /// # ;
+ /// ```
+ ///
+ /// To pass multiple arguments see [`args`].
+ ///
+ /// [`args`]: #method.args
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .arg("-l")
+ /// .arg("-a")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
+ self.inner.arg(arg.as_ref());
+ self
+ }
+
+ /// Add multiple arguments to pass to the program.
+ ///
+ /// To pass a single argument see [`arg`].
+ ///
+ /// [`arg`]: #method.arg
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .args(&["-l", "-a"])
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn args<I, S>(&mut self, args: I) -> &mut Command
+ where I: IntoIterator<Item=S>, S: AsRef<OsStr>
+ {
+ for arg in args {
+ self.arg(arg.as_ref());
+ }
+ self
+ }
+
+ /// Inserts or updates an environment variable mapping.
+ ///
+ /// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
+ /// and case-sensitive on all other platforms.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .env("PATH", "/bin")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
+ where K: AsRef<OsStr>, V: AsRef<OsStr>
+ {
+ self.inner.env_mut().set(key.as_ref(), val.as_ref());
+ self
+ }
+
+ /// Add or update multiple environment variable mappings.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ /// use std::env;
+ /// use std::collections::HashMap;
+ ///
+ /// let filtered_env : HashMap<String, String> =
+ /// env::vars().filter(|&(ref k, _)|
+ /// k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH"
+ /// ).collect();
+ ///
+ /// Command::new("printenv")
+ /// .stdin(Stdio::null())
+ /// .stdout(Stdio::inherit())
+ /// .env_clear()
+ /// .envs(&filtered_env)
+ /// .spawn()
+ /// .expect("printenv failed to start");
+ /// ```
+ #[stable(feature = "command_envs", since = "1.19.0")]
+ pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Command
+ where I: IntoIterator<Item=(K, V)>, K: AsRef<OsStr>, V: AsRef<OsStr>
+ {
+ for (ref key, ref val) in vars {
+ self.inner.env_mut().set(key.as_ref(), val.as_ref());
+ }
+ self
+ }
+
+ /// Removes an environment variable mapping.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .env_remove("PATH")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command {
+ self.inner.env_mut().remove(key.as_ref());
+ self
+ }
+
+ /// Clears the entire environment map for the child process.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .env_clear()
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn env_clear(&mut self) -> &mut Command {
+ self.inner.env_mut().clear();
+ self
+ }
+
+ /// Sets the working directory for the child process.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .current_dir("/bin")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command {
+ self.inner.cwd(dir.as_ref().as_ref());
+ self
+ }
+
+ /// Configuration for the child process's standard input (stdin) handle.
+ ///
+ /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+ /// defaults to [`piped`] when used with `output`.
+ ///
+ /// [`inherit`]: struct.Stdio.html#method.inherit
+ /// [`piped`]: struct.Stdio.html#method.piped
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// Command::new("ls")
+ /// .stdin(Stdio::null())
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
+ self.inner.stdin(cfg.into().0);
+ self
+ }
+
+ /// Configuration for the child process's standard output (stdout) handle.
+ ///
+ /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+ /// defaults to [`piped`] when used with `output`.
+ ///
+ /// [`inherit`]: struct.Stdio.html#method.inherit
+ /// [`piped`]: struct.Stdio.html#method.piped
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// Command::new("ls")
+ /// .stdout(Stdio::null())
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
+ self.inner.stdout(cfg.into().0);
+ self
+ }
+
+ /// Configuration for the child process's standard error (stderr) handle.
+ ///
+ /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+ /// defaults to [`piped`] when used with `output`.
+ ///
+ /// [`inherit`]: struct.Stdio.html#method.inherit
+ /// [`piped`]: struct.Stdio.html#method.piped
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// Command::new("ls")
+ /// .stderr(Stdio::null())
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
+ self.inner.stderr(cfg.into().0);
+ self
+ }
+
+ /// Executes the command as a child process, returning a handle to it.
+ ///
+ /// By default, stdin, stdout and stderr are inherited from the parent.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn spawn(&mut self) -> io::Result<Child> {
+ self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner)
+ }
+
+ /// Executes the command as a child process, waiting for it to finish and
+ /// collecting all of its output.
+ ///
+ /// By default, stdout and stderr are captured (and used to provide the
+ /// resulting output). Stdin is not inherited from the parent and any
+ /// attempt by the child process to read from the stdin stream will result
+ /// in the stream immediately closing.
+ ///
+ /// # Examples
+ ///
+ /// ```should_panic
+ /// use std::process::Command;
+ /// let output = Command::new("/bin/cat")
+ /// .arg("file.txt")
+ /// .output()
+ /// .expect("failed to execute process");
+ ///
+ /// println!("status: {}", output.status);
+ /// println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
+ /// println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+ ///
+ /// assert!(output.status.success());
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn output(&mut self) -> io::Result<Output> {
+ self.inner.spawn(imp::Stdio::MakePipe, false).map(Child::from_inner)
+ .and_then(|p| p.wait_with_output())
+ }
+
+ /// Executes a command as a child process, waiting for it to finish and
+ /// collecting its exit status.
+ ///
+ /// By default, stdin, stdout and stderr are inherited from the parent.
+ ///
+ /// # Examples
+ ///
+ /// ```should_panic
+ /// use std::process::Command;
+ ///
+ /// let status = Command::new("/bin/cat")
+ /// .arg("file.txt")
+ /// .status()
+ /// .expect("failed to execute process");
+ ///
+ /// println!("process exited with: {}", status);
+ ///
+ /// assert!(status.success());
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn status(&mut self) -> io::Result<ExitStatus> {
+ self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner)
+ .and_then(|mut p| p.wait())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Command {
+ /// Format the program and arguments of a Command for display. Any
+ /// non-utf8 data is lossily converted using the utf8 replacement
+ /// character.
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+impl AsInner<imp::Command> for Command {
+ fn as_inner(&self) -> &imp::Command { &self.inner }
+}
+
+impl AsInnerMut<imp::Command> for Command {
+ fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner }
+}
+
+/// The output of a finished process.
+///
+/// This is returned in a Result by either the [`output`] method of a
+/// [`Command`], or the [`wait_with_output`] method of a [`Child`]
+/// process.
+///
+/// [`Command`]: struct.Command.html
+/// [`Child`]: struct.Child.html
+/// [`output`]: struct.Command.html#method.output
+/// [`wait_with_output`]: struct.Child.html#method.wait_with_output
+#[derive(PartialEq, Eq, Clone)]
+#[stable(feature = "process", since = "1.0.0")]
+pub struct Output {
+ /// The status (exit code) of the process.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub status: ExitStatus,
+ /// The data that the process wrote to stdout.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stdout: Vec<u8>,
+ /// The data that the process wrote to stderr.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stderr: Vec<u8>,
+}
+
+// If either stderr or stdout are valid utf8 strings it prints the valid
+// strings, otherwise it prints the byte sequence instead
+#[stable(feature = "process_output_debug", since = "1.7.0")]
+impl fmt::Debug for Output {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+
+ let stdout_utf8 = str::from_utf8(&self.stdout);
+ let stdout_debug: &fmt::Debug = match stdout_utf8 {
+ Ok(ref str) => str,
+ Err(_) => &self.stdout
+ };
+
+ let stderr_utf8 = str::from_utf8(&self.stderr);
+ let stderr_debug: &fmt::Debug = match stderr_utf8 {
+ Ok(ref str) => str,
+ Err(_) => &self.stderr
+ };
+
+ fmt.debug_struct("Output")
+ .field("status", &self.status)
+ .field("stdout", stdout_debug)
+ .field("stderr", stderr_debug)
+ .finish()
+ }
+}
+
+/// Describes what to do with a standard I/O stream for a child process when
+/// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`].
+///
+/// [`stdin`]: struct.Command.html#method.stdin
+/// [`stdout`]: struct.Command.html#method.stdout
+/// [`stderr`]: struct.Command.html#method.stderr
+/// [`Command`]: struct.Command.html
+#[stable(feature = "process", since = "1.0.0")]
+pub struct Stdio(imp::Stdio);
+
+impl Stdio {
+ /// A new pipe should be arranged to connect the parent and child processes.
+ ///
+ /// # Examples
+ ///
+ /// With stdout:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let output = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(Stdio::piped())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n");
+ /// // Nothing echoed to console
+ /// ```
+ ///
+ /// With stdin:
+ ///
+ /// ```no_run
+ /// use std::io::Write;
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let mut child = Command::new("rev")
+ /// .stdin(Stdio::piped())
+ /// .stdout(Stdio::piped())
+ /// .spawn()
+ /// .expect("Failed to spawn child process");
+ ///
+ /// {
+ /// let mut stdin = child.stdin.as_mut().expect("Failed to open stdin");
+ /// stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin");
+ /// }
+ ///
+ /// let output = child.wait_with_output().expect("Failed to read stdout");
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) }
+
+ /// The child inherits from the corresponding parent descriptor.
+ ///
+ /// # Examples
+ ///
+ /// With stdout:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let output = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(Stdio::inherit())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+ /// // "Hello, world!" echoed to console
+ /// ```
+ ///
+ /// With stdin:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let output = Command::new("rev")
+ /// .stdin(Stdio::inherit())
+ /// .stdout(Stdio::piped())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout));
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) }
+
+ /// This stream will be ignored. This is the equivalent of attaching the
+ /// stream to `/dev/null`
+ ///
+ /// # Examples
+ ///
+ /// With stdout:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let output = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(Stdio::null())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+ /// // Nothing echoed to console
+ /// ```
+ ///
+ /// With stdin:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let output = Command::new("rev")
+ /// .stdin(Stdio::null())
+ /// .stdout(Stdio::piped())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+ /// // Ignores any piped-in input
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn null() -> Stdio { Stdio(imp::Stdio::Null) }
+}
+
+impl FromInner<imp::Stdio> for Stdio {
+ fn from_inner(inner: imp::Stdio) -> Stdio {
+ Stdio(inner)
+ }
+}
+
+#[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 { .. }")
+ }
+}
+
+#[stable(feature = "stdio_from", since = "1.20.0")]
+impl From<ChildStdin> for Stdio {
+ fn from(child: ChildStdin) -> Stdio {
+ Stdio::from_inner(child.into_inner().into())
+ }
+}
+
+#[stable(feature = "stdio_from", since = "1.20.0")]
+impl From<ChildStdout> for Stdio {
+ fn from(child: ChildStdout) -> Stdio {
+ Stdio::from_inner(child.into_inner().into())
+ }
+}
+
+#[stable(feature = "stdio_from", since = "1.20.0")]
+impl From<ChildStderr> for Stdio {
+ fn from(child: ChildStderr) -> Stdio {
+ Stdio::from_inner(child.into_inner().into())
+ }
+}
+
+#[stable(feature = "stdio_from", since = "1.20.0")]
+impl From<fs::File> for Stdio {
+ fn from(file: fs::File) -> Stdio {
+ Stdio::from_inner(file.into_inner().into())
+ }
+}
+
+/// Describes the result of a process after it has terminated.
+///
+/// This `struct` is used to represent the exit status of a child process.
+/// Child processes are created via the [`Command`] struct and their exit
+/// status is exposed through the [`status`] method.
+///
+/// [`Command`]: struct.Command.html
+/// [`status`]: struct.Command.html#method.status
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[stable(feature = "process", since = "1.0.0")]
+pub struct ExitStatus(imp::ExitStatus);
+
+impl ExitStatus {
+ /// Was termination successful? Signal termination is not considered a
+ /// success, and success is defined as a zero exit status.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,no_run
+ /// use std::process::Command;
+ ///
+ /// let status = Command::new("mkdir")
+ /// .arg("projects")
+ /// .status()
+ /// .expect("failed to execute mkdir");
+ ///
+ /// if status.success() {
+ /// println!("'projects/' directory created");
+ /// } else {
+ /// println!("failed to create 'projects/' directory");
+ /// }
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn success(&self) -> bool {
+ self.0.success()
+ }
+
+ /// Returns the exit code of the process, if any.
+ ///
+ /// On Unix, this will return `None` if the process was terminated
+ /// by a signal; `std::os::unix` provides an extension trait for
+ /// extracting the signal and other details from the `ExitStatus`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let status = Command::new("mkdir")
+ /// .arg("projects")
+ /// .status()
+ /// .expect("failed to execute mkdir");
+ ///
+ /// match status.code() {
+ /// Some(code) => println!("Exited with status code: {}", code),
+ /// None => println!("Process terminated by signal")
+ /// }
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn code(&self) -> Option<i32> {
+ self.0.code()
+ }
+}
+
+impl AsInner<imp::ExitStatus> for ExitStatus {
+ fn as_inner(&self) -> &imp::ExitStatus { &self.0 }
+}
+
+impl FromInner<imp::ExitStatus> for ExitStatus {
+ fn from_inner(s: imp::ExitStatus) -> ExitStatus {
+ ExitStatus(s)
+ }
+}
+
+#[stable(feature = "process", since = "1.0.0")]
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl Child {
+ /// Forces the child to exit. This is equivalent to sending a
+ /// SIGKILL on unix platforms.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let mut command = Command::new("yes");
+ /// if let Ok(mut child) = command.spawn() {
+ /// child.kill().expect("command wasn't running");
+ /// } else {
+ /// println!("yes command didn't start");
+ /// }
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn kill(&mut self) -> io::Result<()> {
+ self.handle.kill()
+ }
+
+ /// Returns the OS-assigned process identifier associated with this child.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let mut command = Command::new("ls");
+ /// if let Ok(child) = command.spawn() {
+ /// println!("Child's id is {}", child.id());
+ /// } else {
+ /// println!("ls command didn't start");
+ /// }
+ /// ```
+ #[stable(feature = "process_id", since = "1.3.0")]
+ pub fn id(&self) -> u32 {
+ self.handle.id()
+ }
+
+ /// Waits for the child to exit completely, returning the status that it
+ /// exited with. This function will continue to have the same return value
+ /// after it has been called at least once.
+ ///
+ /// The stdin handle to the child process, if any, will be closed
+ /// before waiting. This helps avoid deadlock: it ensures that the
+ /// child does not block waiting for input from the parent, while
+ /// the parent waits for the child to exit.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let mut command = Command::new("ls");
+ /// if let Ok(mut child) = command.spawn() {
+ /// child.wait().expect("command wasn't running");
+ /// println!("Child has finished its execution!");
+ /// } else {
+ /// println!("ls command didn't start");
+ /// }
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ drop(self.stdin.take());
+ self.handle.wait().map(ExitStatus)
+ }
+
+ /// Attempts to collect the exit status of the child if it has already
+ /// exited.
+ ///
+ /// This function will not block the calling thread and will only advisorily
+ /// check to see if the child process has exited or not. If the child has
+ /// exited then on Unix the process id is reaped. This function is
+ /// guaranteed to repeatedly return a successful exit status so long as the
+ /// child has already exited.
+ ///
+ /// If the child has exited, then `Ok(Some(status))` is returned. If the
+ /// exit status is not available at this time then `Ok(None)` is returned.
+ /// If an error occurs, then that error is returned.
+ ///
+ /// Note that unlike `wait`, this function will not attempt to drop stdin.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let mut child = Command::new("ls").spawn().unwrap();
+ ///
+ /// match child.try_wait() {
+ /// Ok(Some(status)) => println!("exited with: {}", status),
+ /// Ok(None) => {
+ /// println!("status not ready yet, let's really wait");
+ /// let res = child.wait();
+ /// println!("result: {:?}", res);
+ /// }
+ /// Err(e) => println!("error attempting to wait: {}", e),
+ /// }
+ /// ```
+ #[stable(feature = "process_try_wait", since = "1.18.0")]
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ Ok(self.handle.try_wait()?.map(ExitStatus))
+ }
+
+ /// Simultaneously waits for the child to exit and collect all remaining
+ /// output on the stdout/stderr handles, returning an `Output`
+ /// instance.
+ ///
+ /// The stdin handle to the child process, if any, will be closed
+ /// before waiting. This helps avoid deadlock: it ensures that the
+ /// child does not block waiting for input from the parent, while
+ /// the parent waits for the child to exit.
+ ///
+ /// By default, stdin, stdout and stderr are inherited from the parent.
+ /// In order to capture the output into this `Result<Output>` it is
+ /// necessary to create new pipes between parent and child. Use
+ /// `stdout(Stdio::piped())` or `stderr(Stdio::piped())`, respectively.
+ ///
+ /// # Examples
+ ///
+ /// ```should_panic
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let child = Command::new("/bin/cat")
+ /// .arg("file.txt")
+ /// .stdout(Stdio::piped())
+ /// .spawn()
+ /// .expect("failed to execute child");
+ ///
+ /// let output = child
+ /// .wait_with_output()
+ /// .expect("failed to wait on child");
+ ///
+ /// assert!(output.status.success());
+ /// ```
+ ///
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn wait_with_output(mut self) -> io::Result<Output> {
+ drop(self.stdin.take());
+
+ let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
+ match (self.stdout.take(), self.stderr.take()) {
+ (None, None) => {}
+ (Some(mut out), None) => {
+ let res = out.read_to_end(&mut stdout);
+ res.unwrap();
+ }
+ (None, Some(mut err)) => {
+ let res = err.read_to_end(&mut stderr);
+ res.unwrap();
+ }
+ (Some(out), Some(err)) => {
+ let res = read2(out.inner, &mut stdout, err.inner, &mut stderr);
+ res.unwrap();
+ }
+ }
+
+ let status = self.wait()?;
+ Ok(Output {
+ status,
+ stdout,
+ stderr,
+ })
+ }
+}
+
+/// Terminates the current process with the specified exit code.
+///
+/// This function will never return and will immediately terminate the current
+/// process. The exit code is passed through to the underlying OS and will be
+/// available for consumption by another process.
+///
+/// Note that because this function never returns, and that it terminates the
+/// process, no destructors on the current stack or any other thread's stack
+/// will be run. If a clean shutdown is needed it is recommended to only call
+/// this function at a known point where there are no more destructors left
+/// to run.
+///
+/// ## Platform-specific behavior
+///
+/// **Unix**: On Unix-like platforms, it is unlikely that all 32 bits of `exit`
+/// will be visible to a parent process inspecting the exit code. On most
+/// Unix-like platforms, only the eight least-significant bits are considered.
+///
+/// # 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:
+///
+/// ```
+/// fn run_app() -> Result<(), ()> {
+/// // Application logic here
+/// Ok(())
+/// }
+///
+/// fn main() {
+/// ::std::process::exit(match run_app() {
+/// Ok(_) => 0,
+/// Err(err) => {
+/// eprintln!("error: {:?}", err);
+/// 1
+/// }
+/// });
+/// }
+/// ```
+///
+/// Due to [platform-specific behavior], the exit code for this example will be
+/// `0` on Linux, but `256` on Windows:
+///
+/// ```no_run
+/// use std::process;
+///
+/// process::exit(0x0100);
+/// ```
+///
+/// [platform-specific behavior]: #platform-specific-behavior
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn exit(code: i32) -> ! {
+ ::sys_common::cleanup();
+ ::sys::os::exit(code)
+}
+
+/// Terminates the process in an abnormal fashion.
+///
+/// The function will never return and will immediately terminate the current
+/// process in a platform specific "abnormal" manner.
+///
+/// Note that because this function never returns, and that it terminates the
+/// process, no destructors on the current stack or any other thread's stack
+/// will be run.
+///
+/// This is in contrast to the default behaviour of [`panic!`] which unwinds
+/// the current thread's stack and calls all destructors.
+/// When `panic="abort"` is set, either as an argument to `rustc` or in a
+/// crate's Cargo.toml, [`panic!`] and `abort` are similar. However,
+/// [`panic!`] will still call the [panic hook] while `abort` will not.
+///
+/// If a clean shutdown is needed it is recommended to only call
+/// this function at a known point where there are no more destructors left
+/// to run.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::process;
+///
+/// fn main() {
+/// println!("aborting");
+///
+/// process::abort();
+///
+/// // execution never gets here
+/// }
+/// ```
+///
+/// The `abort` function terminates the process, so the destructor will not
+/// get run on the example below:
+///
+/// ```no_run
+/// use std::process;
+///
+/// struct HasDrop;
+///
+/// impl Drop for HasDrop {
+/// fn drop(&mut self) {
+/// println!("This will never be printed!");
+/// }
+/// }
+///
+/// fn main() {
+/// let _x = HasDrop;
+/// process::abort();
+/// // the destructor implemented for HasDrop will never get run
+/// }
+/// ```
+///
+/// [`panic!`]: ../../std/macro.panic.html
+/// [panic hook]: ../../std/panic/fn.set_hook.html
+#[stable(feature = "process_abort", since = "1.17.0")]
+pub fn abort() -> ! {
+ unsafe { ::sys::abort_internal() };
+}
+
+/// Returns the OS-assigned process identifier associated with this process.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```no_run
+/// #![feature(getpid)]
+/// use std::process;
+///
+/// println!("My pid is {}", process::id());
+/// ```
+///
+///
+#[unstable(feature = "getpid", issue = "44971", reason = "recently added")]
+pub fn id() -> u32 {
+ ::sys::os::getpid()
+}
+
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
+mod tests {
+ use io::prelude::*;
+
+ use io::ErrorKind;
+ use str;
+ use super::{Command, Output, Stdio};
+
+ // FIXME(#10380) these tests should not all be ignored on android.
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn smoke() {
+ let p = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 0"]).spawn()
+ } else {
+ Command::new("true").spawn()
+ };
+ assert!(p.is_ok());
+ let mut p = p.unwrap();
+ assert!(p.wait().unwrap().success());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn smoke_failure() {
+ match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
+ Ok(..) => panic!(),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn exit_reported_right() {
+ let p = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 1"]).spawn()
+ } else {
+ Command::new("false").spawn()
+ };
+ assert!(p.is_ok());
+ let mut p = p.unwrap();
+ assert!(p.wait().unwrap().code() == Some(1));
+ drop(p.wait());
+ }
+
+ #[test]
+ #[cfg(unix)]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn signal_reported_right() {
+ use os::unix::process::ExitStatusExt;
+
+ let mut p = Command::new("/bin/sh")
+ .arg("-c").arg("read a")
+ .stdin(Stdio::piped())
+ .spawn().unwrap();
+ p.kill().unwrap();
+ match p.wait().unwrap().signal() {
+ Some(9) => {},
+ result => panic!("not terminated by signal 9 (instead, {:?})",
+ result),
+ }
+ }
+
+ pub fn run_output(mut cmd: Command) -> String {
+ let p = cmd.spawn();
+ assert!(p.is_ok());
+ let mut p = p.unwrap();
+ assert!(p.stdout.is_some());
+ let mut ret = String::new();
+ p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap();
+ assert!(p.wait().unwrap().success());
+ return ret;
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn stdout_works() {
+ if cfg!(target_os = "windows") {
+ let mut cmd = Command::new("cmd");
+ cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped());
+ assert_eq!(run_output(cmd), "foobar\r\n");
+ } else {
+ let mut cmd = Command::new("echo");
+ cmd.arg("foobar").stdout(Stdio::piped());
+ assert_eq!(run_output(cmd), "foobar\n");
+ }
+ }
+
+ #[test]
+ #[cfg_attr(any(windows, target_os = "android"), ignore)]
+ fn set_current_dir_works() {
+ let mut cmd = Command::new("/bin/sh");
+ cmd.arg("-c").arg("pwd")
+ .current_dir("/")
+ .stdout(Stdio::piped());
+ assert_eq!(run_output(cmd), "/\n");
+ }
+
+ #[test]
+ #[cfg_attr(any(windows, target_os = "android"), ignore)]
+ fn stdin_works() {
+ let mut p = Command::new("/bin/sh")
+ .arg("-c").arg("read line; echo $line")
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn().unwrap();
+ p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
+ drop(p.stdin.take());
+ let mut out = String::new();
+ p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap();
+ assert!(p.wait().unwrap().success());
+ assert_eq!(out, "foobar\n");
+ }
+
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ #[cfg(unix)]
+ fn uid_works() {
+ use os::unix::prelude::*;
+ use libc;
+ let mut p = Command::new("/bin/sh")
+ .arg("-c").arg("true")
+ .uid(unsafe { libc::getuid() })
+ .gid(unsafe { libc::getgid() })
+ .spawn().unwrap();
+ assert!(p.wait().unwrap().success());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ #[cfg(unix)]
+ fn uid_to_root_fails() {
+ use os::unix::prelude::*;
+ use libc;
+
+ // if we're already root, this isn't a valid test. Most of the bots run
+ // as non-root though (android is an exception).
+ if unsafe { libc::getuid() == 0 } { return }
+ assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_process_status() {
+ let mut status = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap()
+ } else {
+ Command::new("false").status().unwrap()
+ };
+ assert!(status.code() == Some(1));
+
+ status = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap()
+ } else {
+ Command::new("true").status().unwrap()
+ };
+ assert!(status.success());
+ }
+
+ #[test]
+ fn test_process_output_fail_to_start() {
+ match Command::new("/no-binary-by-this-name-should-exist").output() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound),
+ Ok(..) => panic!()
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_process_output_output() {
+ let Output {status, stdout, stderr}
+ = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap()
+ } else {
+ Command::new("echo").arg("hello").output().unwrap()
+ };
+ let output_str = str::from_utf8(&stdout).unwrap();
+
+ assert!(status.success());
+ assert_eq!(output_str.trim().to_string(), "hello");
+ assert_eq!(stderr, Vec::new());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_process_output_error() {
+ let Output {status, stdout, stderr}
+ = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap()
+ } else {
+ Command::new("mkdir").arg("./").output().unwrap()
+ };
+
+ assert!(status.code() == Some(1));
+ assert_eq!(stdout, Vec::new());
+ assert!(!stderr.is_empty());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_finish_once() {
+ let mut prog = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
+ } else {
+ Command::new("false").spawn().unwrap()
+ };
+ assert!(prog.wait().unwrap().code() == Some(1));
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_finish_twice() {
+ let mut prog = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
+ } else {
+ Command::new("false").spawn().unwrap()
+ };
+ assert!(prog.wait().unwrap().code() == Some(1));
+ assert!(prog.wait().unwrap().code() == Some(1));
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_wait_with_output_once() {
+ let prog = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap()
+ } else {
+ Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap()
+ };
+
+ let Output {status, stdout, stderr} = prog.wait_with_output().unwrap();
+ let output_str = str::from_utf8(&stdout).unwrap();
+
+ assert!(status.success());
+ assert_eq!(output_str.trim().to_string(), "hello");
+ assert_eq!(stderr, Vec::new());
+ }
+
+ #[cfg(all(unix, not(target_os="android")))]
+ pub fn env_cmd() -> Command {
+ Command::new("env")
+ }
+ #[cfg(target_os="android")]
+ pub fn env_cmd() -> Command {
+ let mut cmd = Command::new("/system/bin/sh");
+ cmd.arg("-c").arg("set");
+ cmd
+ }
+
+ #[cfg(windows)]
+ pub fn env_cmd() -> Command {
+ let mut cmd = Command::new("cmd");
+ cmd.arg("/c").arg("set");
+ cmd
+ }
+
+ #[test]
+ fn test_inherit_env() {
+ use env;
+
+ let result = env_cmd().output().unwrap();
+ let output = String::from_utf8(result.stdout).unwrap();
+
+ for (ref k, ref v) in env::vars() {
+ // Don't check android RANDOM variable which seems to change
+ // whenever the shell runs, and our `env_cmd` is indeed running a
+ // shell which means it'll get a different RANDOM than we probably
+ // have.
+ //
+ // Also skip env vars with `-` in the name on android because, well,
+ // I'm not sure. It appears though that the `set` command above does
+ // not print env vars with `-` in the name, so we just skip them
+ // here as we won't find them in the output. Note that most env vars
+ // use `_` instead of `-`, but our build system sets a few env vars
+ // with `-` in the name.
+ if cfg!(target_os = "android") &&
+ (*k == "RANDOM" || k.contains("-")) {
+ continue
+ }
+
+ // Windows has hidden environment variables whose names start with
+ // equals signs (`=`). Those do not show up in the output of the
+ // `set` command.
+ assert!((cfg!(windows) && k.starts_with("=")) ||
+ k.starts_with("DYLD") ||
+ output.contains(&format!("{}={}", *k, *v)) ||
+ output.contains(&format!("{}='{}'", *k, *v)),
+ "output doesn't contain `{}={}`\n{}",
+ k, v, output);
+ }
+ }
+
+ #[test]
+ fn test_override_env() {
+ use env;
+
+ // In some build environments (such as chrooted Nix builds), `env` can
+ // only be found in the explicitly-provided PATH env variable, not in
+ // default places such as /bin or /usr/bin. So we need to pass through
+ // PATH to our sub-process.
+ let mut cmd = env_cmd();
+ cmd.env_clear().env("RUN_TEST_NEW_ENV", "123");
+ if let Some(p) = env::var_os("PATH") {
+ cmd.env("PATH", &p);
+ }
+ let result = cmd.output().unwrap();
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
+
+ assert!(output.contains("RUN_TEST_NEW_ENV=123"),
+ "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
+ }
+
+ #[test]
+ fn test_add_to_env() {
+ let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap();
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
+
+ assert!(output.contains("RUN_TEST_NEW_ENV=123"),
+ "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
+ }
+
+ #[test]
+ fn test_capture_env_at_spawn() {
+ use env;
+
+ let mut cmd = env_cmd();
+ cmd.env("RUN_TEST_NEW_ENV1", "123");
+
+ // This variable will not be present if the environment has already
+ // been captured above.
+ env::set_var("RUN_TEST_NEW_ENV2", "456");
+ let result = cmd.output().unwrap();
+ env::remove_var("RUN_TEST_NEW_ENV2");
+
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
+
+ assert!(output.contains("RUN_TEST_NEW_ENV1=123"),
+ "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}", output);
+ assert!(output.contains("RUN_TEST_NEW_ENV2=456"),
+ "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}", output);
+ }
+
+ // Regression tests for #30858.
+ #[test]
+ fn test_interior_nul_in_progname_is_error() {
+ match Command::new("has-some-\0\0s-inside").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ #[test]
+ fn test_interior_nul_in_arg_is_error() {
+ match Command::new("echo").arg("has-some-\0\0s-inside").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ #[test]
+ fn test_interior_nul_in_args_is_error() {
+ match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ #[test]
+ fn test_interior_nul_in_current_dir_is_error() {
+ match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ // Regression tests for #30862.
+ #[test]
+ fn test_interior_nul_in_env_key_is_error() {
+ match env_cmd().env("has-some-\0\0s-inside", "value").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ #[test]
+ fn test_interior_nul_in_env_value_is_error() {
+ match env_cmd().env("key", "has-some-\0\0s-inside").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ /// Test that process creation flags work by debugging a process.
+ /// Other creation flags make it hard or impossible to detect
+ /// behavioral changes in the process.
+ #[test]
+ #[cfg(windows)]
+ fn test_creation_flags() {
+ use os::windows::process::CommandExt;
+ use sys::c::{BOOL, DWORD, INFINITE};
+ #[repr(C, packed)]
+ struct DEBUG_EVENT {
+ pub event_code: DWORD,
+ pub process_id: DWORD,
+ pub thread_id: DWORD,
+ // This is a union in the real struct, but we don't
+ // need this data for the purposes of this test.
+ pub _junk: [u8; 164],
+ }
+
+ extern "system" {
+ fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL;
+ fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD,
+ dwContinueStatus: DWORD) -> BOOL;
+ }
+
+ const DEBUG_PROCESS: DWORD = 1;
+ const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5;
+ const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001;
+
+ let mut child = Command::new("cmd")
+ .creation_flags(DEBUG_PROCESS)
+ .stdin(Stdio::piped()).spawn().unwrap();
+ child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap();
+ let mut events = 0;
+ let mut event = DEBUG_EVENT {
+ event_code: 0,
+ process_id: 0,
+ thread_id: 0,
+ _junk: [0; 164],
+ };
+ loop {
+ if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 {
+ panic!("WaitForDebugEvent failed!");
+ }
+ events += 1;
+
+ if event.event_code == EXIT_PROCESS_DEBUG_EVENT {
+ break;
+ }
+
+ if unsafe { ContinueDebugEvent(event.process_id,
+ event.thread_id,
+ DBG_EXCEPTION_NOT_HANDLED) } == 0 {
+ panic!("ContinueDebugEvent failed!");
+ }
+ }
+ assert!(events > 0);
+ }
+}
diff --git a/ctr-std/src/rt.rs b/ctr-std/src/rt.rs
index 735509b..9dbaf78 100644
--- a/ctr-std/src/rt.rs
+++ b/ctr-std/src/rt.rs
@@ -22,31 +22,54 @@
issue = "0")]
#![doc(hidden)]
-use panic;
-use sys_common::thread_info;
-use thread::Thread;
-use mem;
-// Reexport some of our utilities which are expected by other crates.
-pub use panicking::{begin_panic, begin_panic_fmt};
+// Re-export some of our utilities which are expected by other crates.
+pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count};
-//TODO: Handle argc/argv arguments
-#[lang = "start"]
-#[allow(unused_variables)]
-fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
- let failed = unsafe {
- let thread = Thread::new(Some("main".to_owned()));
+// To reduce the generated code of the new `lang_start`, this function is doing
+// the real work.
+#[cfg(not(test))]
+fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe),
+ argc: isize, argv: *const *const u8) -> isize {
+ use panic;
+ use sys;
+ use sys_common;
+ use sys_common::thread_info;
+ use thread::Thread;
+
+ sys::init();
+
+ unsafe {
+ let main_guard = sys::thread::guard::init();
+ sys::stack_overflow::init();
- thread_info::set(None, thread);
+ // Next, set up the current Thread with the guard information we just
+ // created. Note that this isn't necessary in general for new threads,
+ // but we just do this to name the main thread and to give it correct
+ // info about the stack bounds.
+ let thread = Thread::new(Some("main".to_owned()));
+ thread_info::set(main_guard, thread);
- let res = panic::catch_unwind(mem::transmute::<_, fn()>(main));
+ // Store our args if necessary in a squirreled away location
+ sys::args::init(argc, argv);
- res.is_err()
- };
+ // Let's run some code!
+ #[cfg(feature = "backtrace")]
+ let exit_code = panic::catch_unwind(|| {
+ ::sys_common::backtrace::__rust_begin_short_backtrace(move || main())
+ });
+ #[cfg(not(feature = "backtrace"))]
+ let exit_code = panic::catch_unwind(move || main());
- if failed {
- 101
- } else {
- 0
+ sys_common::cleanup();
+ exit_code.unwrap_or(101) as isize
}
}
+
+#[cfg(not(test))]
+#[lang = "start"]
+fn lang_start<T: ::termination::Termination + 'static>
+ (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize
+{
+ lang_start_internal(&move || main().report(), argc, argv)
+}
diff --git a/ctr-std/src/sync/barrier.rs b/ctr-std/src/sync/barrier.rs
index f15e7ff..273c7c1 100644
--- a/ctr-std/src/sync/barrier.rs
+++ b/ctr-std/src/sync/barrier.rs
@@ -50,12 +50,11 @@ struct BarrierState {
generation_id: usize,
}
-/// A result returned from wait.
+/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`]
+/// have rendezvoused.
///
-/// Currently this opaque structure only has one method, [`.is_leader()`]. Only
-/// one thread will receive a result that will return `true` from this function.
-///
-/// [`.is_leader()`]: #method.is_leader
+/// [`wait`]: struct.Barrier.html#method.wait
+/// [`Barrier`]: struct.Barrier.html
///
/// # Examples
///
@@ -153,7 +152,7 @@ impl Barrier {
BarrierWaitResult(false)
} else {
lock.count = 0;
- lock.generation_id += 1;
+ lock.generation_id = lock.generation_id.wrapping_add(1);
self.cvar.notify_all();
BarrierWaitResult(true)
}
diff --git a/ctr-std/src/sync/condvar.rs b/ctr-std/src/sync/condvar.rs
index 68c7e88..5640217 100644
--- a/ctr-std/src/sync/condvar.rs
+++ b/ctr-std/src/sync/condvar.rs
@@ -150,7 +150,7 @@ impl Condvar {
///
/// This function will atomically unlock the mutex specified (represented by
/// `guard`) and block the current thread. This means that any calls
- /// to [`notify_one()`] or [`notify_all()`] which happen logically after the
+ /// to [`notify_one`] or [`notify_all`] which happen logically after the
/// mutex is unlocked are candidates to wake this thread up. When this
/// function call returns, the lock specified will have been re-acquired.
///
@@ -167,16 +167,16 @@ impl Condvar {
///
/// # Panics
///
- /// This function will [`panic!()`] if it is used with more than one mutex
+ /// This function will [`panic!`] if it is used with more than one mutex
/// over time. Each condition variable is dynamically bound to exactly one
/// mutex to ensure defined behavior across platforms. If this functionality
/// is not desired, then unsafe primitives in `sys` are provided.
///
- /// [`notify_one()`]: #method.notify_one
- /// [`notify_all()`]: #method.notify_all
+ /// [`notify_one`]: #method.notify_one
+ /// [`notify_all`]: #method.notify_all
/// [poisoning]: ../sync/struct.Mutex.html#poisoning
/// [`Mutex`]: ../sync/struct.Mutex.html
- /// [`panic!()`]: ../../std/macro.panic.html
+ /// [`panic!`]: ../../std/macro.panic.html
///
/// # Examples
///
@@ -359,11 +359,11 @@ impl Condvar {
/// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
/// `notify_one` are not buffered in any way.
///
- /// To wake up all threads, see [`notify_all()`].
+ /// To wake up all threads, see [`notify_all`].
///
/// [`wait`]: #method.wait
/// [`wait_timeout`]: #method.wait_timeout
- /// [`notify_all()`]: #method.notify_all
+ /// [`notify_all`]: #method.notify_all
///
/// # Examples
///
@@ -401,9 +401,9 @@ impl Condvar {
/// variable are awoken. Calls to `notify_all()` are not buffered in any
/// way.
///
- /// To wake up only one thread, see [`notify_one()`].
+ /// To wake up only one thread, see [`notify_one`].
///
- /// [`notify_one()`]: #method.notify_one
+ /// [`notify_one`]: #method.notify_one
///
/// # Examples
///
@@ -461,7 +461,7 @@ impl fmt::Debug for Condvar {
}
}
-#[stable(feature = "condvar_default", since = "1.9.0")]
+#[stable(feature = "condvar_default", since = "1.10.0")]
impl Default for Condvar {
/// Creates a `Condvar` which is ready to be waited on and notified.
fn default() -> Condvar {
@@ -480,9 +480,10 @@ impl Drop for Condvar {
mod tests {
use sync::mpsc::channel;
use sync::{Condvar, Mutex, Arc};
+ use sync::atomic::{AtomicBool, Ordering};
use thread;
use time::Duration;
- use u32;
+ use u64;
#[test]
fn smoke() {
@@ -547,23 +548,58 @@ mod tests {
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
- fn wait_timeout_ms() {
+ fn wait_timeout_wait() {
let m = Arc::new(Mutex::new(()));
- let m2 = m.clone();
let c = Arc::new(Condvar::new());
- let c2 = c.clone();
- let g = m.lock().unwrap();
- let (g, _no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
- // spurious wakeups mean this isn't necessarily true
- // assert!(!no_timeout);
- let _t = thread::spawn(move || {
- let _g = m2.lock().unwrap();
- c2.notify_one();
- });
- let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u32::MAX as u64)).unwrap();
- assert!(!timeout_res.timed_out());
- drop(g);
+ loop {
+ let g = m.lock().unwrap();
+ let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
+ // spurious wakeups mean this isn't necessarily true
+ // so execute test again, if not timeout
+ if !no_timeout.timed_out() {
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn wait_timeout_wake() {
+ let m = Arc::new(Mutex::new(()));
+ let c = Arc::new(Condvar::new());
+
+ loop {
+ let g = m.lock().unwrap();
+
+ let c2 = c.clone();
+ let m2 = m.clone();
+
+ let notified = Arc::new(AtomicBool::new(false));
+ let notified_copy = notified.clone();
+
+ let t = thread::spawn(move || {
+ let _g = m2.lock().unwrap();
+ thread::sleep(Duration::from_millis(1));
+ notified_copy.store(true, Ordering::SeqCst);
+ c2.notify_one();
+ });
+ let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap();
+ assert!(!timeout_res.timed_out());
+ // spurious wakeups mean this isn't necessarily true
+ // so execute test again, if not notified
+ if !notified.load(Ordering::SeqCst) {
+ t.join().unwrap();
+ continue;
+ }
+ drop(g);
+
+ t.join().unwrap();
+
+ break;
+ }
}
#[test]
diff --git a/ctr-std/src/sync/mpsc/blocking.rs b/ctr-std/src/sync/mpsc/blocking.rs
index 0f9ef6f..c08bd6d 100644
--- a/ctr-std/src/sync/mpsc/blocking.rs
+++ b/ctr-std/src/sync/mpsc/blocking.rs
@@ -46,7 +46,7 @@ pub fn tokens() -> (WaitToken, SignalToken) {
inner: inner.clone(),
};
let signal_token = SignalToken {
- inner: inner
+ inner,
};
(wait_token, signal_token)
}
diff --git a/ctr-std/src/sync/mpsc/cache_aligned.rs b/ctr-std/src/sync/mpsc/cache_aligned.rs
new file mode 100644
index 0000000..5af0126
--- /dev/null
+++ b/ctr-std/src/sync/mpsc/cache_aligned.rs
@@ -0,0 +1,37 @@
+// Copyright 2017 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 ops::{Deref, DerefMut};
+
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(align(64))]
+pub(super) struct Aligner;
+
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub(super) struct CacheAligned<T>(pub T, pub Aligner);
+
+impl<T> Deref for CacheAligned<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<T> DerefMut for CacheAligned<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+impl<T> CacheAligned<T> {
+ pub(super) fn new(t: T) -> Self {
+ CacheAligned(t, Aligner)
+ }
+}
diff --git a/ctr-std/src/sync/mpsc/mod.rs b/ctr-std/src/sync/mpsc/mod.rs
index aeeab17..2dd3aeb 100644
--- a/ctr-std/src/sync/mpsc/mod.rs
+++ b/ctr-std/src/sync/mpsc/mod.rs
@@ -13,40 +13,50 @@
//! This module provides message-based communication over channels, concretely
//! defined among three types:
//!
-//! * `Sender`
-//! * `SyncSender`
-//! * `Receiver`
+//! * [`Sender`]
+//! * [`SyncSender`]
+//! * [`Receiver`]
//!
-//! A `Sender` or `SyncSender` is used to send data to a `Receiver`. Both
+//! A [`Sender`] or [`SyncSender`] is used to send data to a [`Receiver`]. Both
//! senders are clone-able (multi-producer) such that many threads can send
//! simultaneously to one receiver (single-consumer).
//!
//! These channels come in two flavors:
//!
-//! 1. An asynchronous, infinitely buffered channel. The `channel()` function
+//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function
//! will return a `(Sender, Receiver)` tuple where all sends will be
//! **asynchronous** (they never block). The channel conceptually has an
//! infinite buffer.
//!
-//! 2. A synchronous, bounded channel. The `sync_channel()` function will return
-//! a `(SyncSender, Receiver)` tuple where the storage for pending messages
-//! is a pre-allocated buffer of a fixed size. All sends will be
+//! 2. A synchronous, bounded channel. The [`sync_channel`] function will
+//! return a `(SyncSender, Receiver)` tuple where the storage for pending
+//! messages is a pre-allocated buffer of a fixed size. All sends will be
//! **synchronous** by blocking until there is buffer space available. Note
-//! that a bound of 0 is allowed, causing the channel to become a
-//! "rendezvous" channel where each sender atomically hands off a message to
-//! a receiver.
+//! that a bound of 0 is allowed, causing the channel to become a "rendezvous"
+//! channel where each sender atomically hands off a message to a receiver.
+//!
+//! [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html
+//! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html
+//! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+//! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
+//! [`channel`]: ../../../std/sync/mpsc/fn.channel.html
+//! [`sync_channel`]: ../../../std/sync/mpsc/fn.sync_channel.html
//!
//! ## Disconnection
//!
-//! The send and receive operations on channels will all return a `Result`
+//! The send and receive operations on channels will all return a [`Result`]
//! indicating whether the operation succeeded or not. An unsuccessful operation
//! is normally indicative of the other half of a channel having "hung up" by
//! being dropped in its corresponding thread.
//!
//! Once half of a channel has been deallocated, most operations can no longer
-//! continue to make progress, so `Err` will be returned. Many applications will
-//! continue to `unwrap()` the results returned from this module, instigating a
-//! propagation of failure among threads if one unexpectedly dies.
+//! continue to make progress, so [`Err`] will be returned. Many applications
+//! will continue to [`unwrap`] the results returned from this module,
+//! instigating a propagation of failure among threads if one unexpectedly dies.
+//!
+//! [`Result`]: ../../../std/result/enum.Result.html
+//! [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+//! [`unwrap`]: ../../../std/result/enum.Result.html#method.unwrap
//!
//! # Examples
//!
@@ -287,8 +297,36 @@ mod sync;
mod mpsc_queue;
mod spsc_queue;
-/// The receiving-half of Rust's channel type. This half can only be owned by
-/// one thread
+mod cache_aligned;
+
+/// The receiving half of Rust's [`channel`][] (or [`sync_channel`]) type.
+/// This half can only be owned by one thread.
+///
+/// Messages sent to the channel can be retrieved using [`recv`].
+///
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
+/// [`recv`]: struct.Receiver.html#method.recv
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+/// send.send("Hello world!").unwrap();
+/// thread::sleep(Duration::from_secs(2)); // block for two seconds
+/// send.send("Delayed for 2 seconds").unwrap();
+/// });
+///
+/// println!("{}", recv.recv().unwrap()); // Received immediately
+/// println!("Waiting...");
+/// println!("{}", recv.recv().unwrap()); // Received after 2 seconds
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Receiver<T> {
inner: UnsafeCell<Flavor<T>>,
@@ -302,38 +340,153 @@ unsafe impl<T: Send> Send for Receiver<T> { }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> !Sync for Receiver<T> { }
-/// An iterator over messages on a receiver, this iterator will block
-/// whenever `next` is called, waiting for a new message, and `None` will be
-/// returned when the corresponding channel has hung up.
+/// An iterator over messages on a [`Receiver`], created by [`iter`].
+///
+/// This iterator will block whenever [`next`] is called,
+/// waiting for a new message, and [`None`] will be returned
+/// when the corresponding channel has hung up.
+///
+/// [`iter`]: struct.Receiver.html#method.iter
+/// [`Receiver`]: struct.Receiver.html
+/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next
+/// [`None`]: ../../../std/option/enum.Option.html#variant.None
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+/// send.send(1u8).unwrap();
+/// send.send(2u8).unwrap();
+/// send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.iter() {
+/// println!("Got: {}", x);
+/// }
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Iter<'a, T: 'a> {
rx: &'a Receiver<T>
}
-/// An iterator that attempts to yield all pending values for a receiver.
-/// `None` will be returned when there are no pending values remaining or
+/// An iterator that attempts to yield all pending values for a [`Receiver`],
+/// created by [`try_iter`].
+///
+/// [`None`] will be returned when there are no pending values remaining or
/// if the corresponding channel has hung up.
///
-/// This Iterator will never block the caller in order to wait for data to
-/// become available. Instead, it will return `None`.
+/// This iterator will never block the caller in order to wait for data to
+/// become available. Instead, it will return [`None`].
+///
+/// [`Receiver`]: struct.Receiver.html
+/// [`try_iter`]: struct.Receiver.html#method.try_iter
+/// [`None`]: ../../../std/option/enum.Option.html#variant.None
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (sender, receiver) = channel();
+///
+/// // Nothing is in the buffer yet
+/// assert!(receiver.try_iter().next().is_none());
+/// println!("Nothing in the buffer...");
+///
+/// thread::spawn(move || {
+/// sender.send(1).unwrap();
+/// sender.send(2).unwrap();
+/// sender.send(3).unwrap();
+/// });
+///
+/// println!("Going to sleep...");
+/// thread::sleep(Duration::from_secs(2)); // block for two seconds
+///
+/// for x in receiver.try_iter() {
+/// println!("Got: {}", x);
+/// }
+/// ```
#[stable(feature = "receiver_try_iter", since = "1.15.0")]
#[derive(Debug)]
pub struct TryIter<'a, T: 'a> {
rx: &'a Receiver<T>
}
-/// An owning iterator over messages on a receiver, this iterator will block
-/// whenever `next` is called, waiting for a new message, and `None` will be
-/// returned when the corresponding channel has hung up.
+/// An owning iterator over messages on a [`Receiver`],
+/// created by **Receiver::into_iter**.
+///
+/// This iterator will block whenever [`next`]
+/// is called, waiting for a new message, and [`None`] will be
+/// returned if the corresponding channel has hung up.
+///
+/// [`Receiver`]: struct.Receiver.html
+/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next
+/// [`None`]: ../../../std/option/enum.Option.html#variant.None
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+/// send.send(1u8).unwrap();
+/// send.send(2u8).unwrap();
+/// send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.into_iter() {
+/// println!("Got: {}", x);
+/// }
+/// ```
#[stable(feature = "receiver_into_iter", since = "1.1.0")]
#[derive(Debug)]
pub struct IntoIter<T> {
rx: Receiver<T>
}
-/// The sending-half of Rust's asynchronous channel type. This half can only be
+/// The sending-half of Rust's asynchronous [`channel`] type. This half can only be
/// owned by one thread, but it can be cloned to send to other threads.
+///
+/// Messages can be sent through this channel with [`send`].
+///
+/// [`channel`]: fn.channel.html
+/// [`send`]: struct.Sender.html#method.send
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+/// let sender2 = sender.clone();
+///
+/// // First thread owns sender
+/// thread::spawn(move || {
+/// sender.send(1).unwrap();
+/// });
+///
+/// // Second thread owns sender2
+/// thread::spawn(move || {
+/// sender2.send(2).unwrap();
+/// });
+///
+/// let msg = receiver.recv().unwrap();
+/// let msg2 = receiver.recv().unwrap();
+///
+/// assert_eq!(3, msg + msg2);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Sender<T> {
inner: UnsafeCell<Flavor<T>>,
@@ -347,8 +500,53 @@ unsafe impl<T: Send> Send for Sender<T> { }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> !Sync for Sender<T> { }
-/// The sending-half of Rust's synchronous channel type. This half can only be
-/// owned by one thread, but it can be cloned to send to other threads.
+/// The sending-half of Rust's synchronous [`sync_channel`] type.
+///
+/// Messages can be sent through this channel with [`send`] or [`try_send`].
+///
+/// [`send`] will block if there is no space in the internal buffer.
+///
+/// [`sync_channel`]: fn.sync_channel.html
+/// [`send`]: struct.SyncSender.html#method.send
+/// [`try_send`]: struct.SyncSender.html#method.try_send
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::sync_channel;
+/// use std::thread;
+///
+/// // Create a sync_channel with buffer size 2
+/// let (sync_sender, receiver) = sync_channel(2);
+/// let sync_sender2 = sync_sender.clone();
+///
+/// // First thread owns sync_sender
+/// thread::spawn(move || {
+/// sync_sender.send(1).unwrap();
+/// sync_sender.send(2).unwrap();
+/// });
+///
+/// // Second thread owns sync_sender2
+/// thread::spawn(move || {
+/// sync_sender2.send(3).unwrap();
+/// // thread will now block since the buffer is full
+/// println!("Thread unblocked!");
+/// });
+///
+/// let mut msg;
+///
+/// msg = receiver.recv().unwrap();
+/// println!("message {} received", msg);
+///
+/// // "Thread unblocked!" will be printed now
+///
+/// msg = receiver.recv().unwrap();
+/// println!("message {} received", msg);
+///
+/// msg = receiver.recv().unwrap();
+///
+/// println!("message {} received", msg);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SyncSender<T> {
inner: Arc<sync::Packet<T>>,
@@ -357,73 +555,97 @@ pub struct SyncSender<T> {
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Send> Send for SyncSender<T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> !Sync for SyncSender<T> {}
-
-/// An error returned from the `send` function on channels.
+/// An error returned from the [`Sender::send`] or [`SyncSender::send`]
+/// function on **channel**s.
///
-/// A `send` operation can only fail if the receiving end of a channel is
+/// A **send** operation can only fail if the receiving end of a channel is
/// disconnected, implying that the data could never be received. The error
/// contains the data being sent as a payload so it can be recovered.
+///
+/// [`Sender::send`]: struct.Sender.html#method.send
+/// [`SyncSender::send`]: struct.SyncSender.html#method.send
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
-/// An error returned from the `recv` function on a `Receiver`.
+/// An error returned from the [`recv`] function on a [`Receiver`].
///
-/// The `recv` operation can only fail if the sending half of a channel is
-/// disconnected, implying that no further messages will ever be received.
+/// The [`recv`] operation can only fail if the sending half of a
+/// [`channel`][`channel`] (or [`sync_channel`]) is disconnected, implying that no further
+/// messages will ever be received.
+///
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`Receiver`]: struct.Receiver.html
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RecvError;
-/// This enumeration is the list of the possible reasons that `try_recv` could
-/// not return data when called.
+/// This enumeration is the list of the possible reasons that [`try_recv`] could
+/// not return data when called. This can occur with both a [`channel`] and
+/// a [`sync_channel`].
+///
+/// [`try_recv`]: struct.Receiver.html#method.try_recv
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum TryRecvError {
- /// This channel is currently empty, but the sender(s) have not yet
+ /// This **channel** is currently empty, but the **Sender**(s) have not yet
/// disconnected, so data may yet become available.
#[stable(feature = "rust1", since = "1.0.0")]
Empty,
- /// This channel's sending half has become disconnected, and there will
- /// never be any more data received on this channel
+ /// The **channel**'s sending half has become disconnected, and there will
+ /// never be any more data received on it.
#[stable(feature = "rust1", since = "1.0.0")]
Disconnected,
}
-/// This enumeration is the list of possible errors that `recv_timeout` could
-/// not return data when called.
+/// This enumeration is the list of possible errors that made [`recv_timeout`]
+/// unable to return data when called. This can occur with both a [`channel`] and
+/// a [`sync_channel`].
+///
+/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
pub enum RecvTimeoutError {
- /// This channel is currently empty, but the sender(s) have not yet
+ /// This **channel** is currently empty, but the **Sender**(s) have not yet
/// disconnected, so data may yet become available.
#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
Timeout,
- /// This channel's sending half has become disconnected, and there will
- /// never be any more data received on this channel
+ /// The **channel**'s sending half has become disconnected, and there will
+ /// never be any more data received on it.
#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
Disconnected,
}
/// This enumeration is the list of the possible error outcomes for the
-/// `SyncSender::try_send` method.
+/// [`try_send`] method.
+///
+/// [`try_send`]: struct.SyncSender.html#method.try_send
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum TrySendError<T> {
- /// The data could not be sent on the channel because it would require that
+ /// The data could not be sent on the [`sync_channel`] because it would require that
/// the callee block to send the data.
///
/// If this is a buffered channel, then the buffer is full at this time. If
- /// this is not a buffered channel, then there is no receiver available to
+ /// this is not a buffered channel, then there is no [`Receiver`] available to
/// acquire the data.
+ ///
+ /// [`sync_channel`]: fn.sync_channel.html
+ /// [`Receiver`]: struct.Receiver.html
#[stable(feature = "rust1", since = "1.0.0")]
Full(#[stable(feature = "rust1", since = "1.0.0")] T),
- /// This channel's receiving half has disconnected, so the data could not be
+ /// This [`sync_channel`]'s receiving half has disconnected, so the data could not be
/// sent. The data is returned back to the callee in this case.
+ ///
+ /// [`sync_channel`]: fn.sync_channel.html
#[stable(feature = "rust1", since = "1.0.0")]
Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T),
}
@@ -457,15 +679,27 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
}
/// Creates a new asynchronous channel, returning the sender/receiver halves.
-/// All data sent on the sender will become available on the receiver, and no
-/// send will block the calling thread (this channel has an "infinite buffer").
+/// All data sent on the [`Sender`] will become available on the [`Receiver`] in
+/// the same order as it was sent, and no [`send`] will block the calling thread
+/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
+/// block after its buffer limit is reached). [`recv`] will block until a message
+/// is available.
///
-/// If the [`Receiver`] is disconnected while trying to [`send()`] with the
-/// [`Sender`], the [`send()`] method will return an error.
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but
+/// only one [`Receiver`] is supported.
///
-/// [`send()`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
-/// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html
-/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+/// If the [`Receiver`] is disconnected while trying to [`send`] with the
+/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, If the
+/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will
+/// return a [`RecvError`].
+///
+/// [`send`]: struct.Sender.html#method.send
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`Sender`]: struct.Sender.html
+/// [`Receiver`]: struct.Receiver.html
+/// [`sync_channel`]: fn.sync_channel.html
+/// [`SendError`]: struct.SendError.html
+/// [`RecvError`]: struct.RecvError.html
///
/// # Examples
///
@@ -473,20 +707,18 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
/// use std::sync::mpsc::channel;
/// use std::thread;
///
-/// // tx is the sending half (tx for transmission), and rx is the receiving
-/// // half (rx for receiving).
-/// let (tx, rx) = channel();
+/// let (sender, receiver) = channel();
///
/// // Spawn off an expensive computation
/// thread::spawn(move|| {
/// # fn expensive_computation() {}
-/// tx.send(expensive_computation()).unwrap();
+/// sender.send(expensive_computation()).unwrap();
/// });
///
/// // Do some useful work for awhile
///
/// // Let's see what that answer was
-/// println!("{:?}", rx.recv().unwrap());
+/// println!("{:?}", receiver.recv().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
@@ -495,24 +727,32 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
}
/// Creates a new synchronous, bounded channel.
-///
-/// Like asynchronous channels, the [`Receiver`] will block until a message
-/// becomes available. These channels differ greatly in the semantics of the
-/// sender from asynchronous channels, however.
+/// All data sent on the [`SyncSender`] will become available on the [`Receiver`]
+/// in the same order as it was sent. Like asynchronous [`channel`]s, the
+/// [`Receiver`] will block until a message becomes available. `sync_channel`
+/// differs greatly in the semantics of the sender, however.
///
/// This channel has an internal buffer on which messages will be queued.
/// `bound` specifies the buffer size. When the internal buffer becomes full,
/// future sends will *block* waiting for the buffer to open up. Note that a
/// buffer size of 0 is valid, in which case this becomes "rendezvous channel"
-/// where each [`send()`] will not return until a recv is paired with it.
+/// where each [`send`] will not return until a [`recv`] is paired with it.
///
-/// Like asynchronous channels, if the [`Receiver`] is disconnected while
-/// trying to [`send()`] with the [`SyncSender`], the [`send()`] method will
-/// return an error.
+/// The [`SyncSender`] can be cloned to [`send`] to the same channel multiple
+/// times, but only one [`Receiver`] is supported.
///
-/// [`send()`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send
-/// [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html
-/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying
+/// to [`send`] with the [`SyncSender`], the [`send`] method will return a
+/// [`SendError`]. Similarly, If the [`SyncSender`] is disconnected while trying
+/// to [`recv`], the [`recv`] method will return a [`RecvError`].
+///
+/// [`channel`]: fn.channel.html
+/// [`send`]: struct.SyncSender.html#method.send
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`SyncSender`]: struct.SyncSender.html
+/// [`Receiver`]: struct.Receiver.html
+/// [`SendError`]: struct.SendError.html
+/// [`RecvError`]: struct.RecvError.html
///
/// # Examples
///
@@ -520,18 +760,18 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
/// use std::sync::mpsc::sync_channel;
/// use std::thread;
///
-/// let (tx, rx) = sync_channel(1);
+/// let (sender, receiver) = sync_channel(1);
///
/// // this returns immediately
-/// tx.send(1).unwrap();
+/// sender.send(1).unwrap();
///
/// thread::spawn(move|| {
/// // this will block until the previous message has been received
-/// tx.send(2).unwrap();
+/// sender.send(2).unwrap();
/// });
///
-/// assert_eq!(rx.recv().unwrap(), 1);
-/// assert_eq!(rx.recv().unwrap(), 2);
+/// assert_eq!(receiver.recv().unwrap(), 1);
+/// assert_eq!(receiver.recv().unwrap(), 2);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
@@ -556,10 +796,13 @@ impl<T> Sender<T> {
/// A successful send occurs when it is determined that the other end of
/// the channel has not hung up already. An unsuccessful send would be one
/// where the corresponding receiver has already been deallocated. Note
- /// that a return value of `Err` means that the data will never be
- /// received, but a return value of `Ok` does *not* mean that the data
+ /// that a return value of [`Err`] means that the data will never be
+ /// received, but a return value of [`Ok`] does *not* mean that the data
/// will be received. It is possible for the corresponding receiver to
- /// hang up immediately after this function returns `Ok`.
+ /// hang up immediately after this function returns [`Ok`].
+ ///
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ /// [`Ok`]: ../../../std/result/enum.Result.html#variant.Ok
///
/// This method will never block the current thread.
///
@@ -675,10 +918,10 @@ impl<T> Drop for Sender<T> {
}
}
-#[stable(feature = "mpsc_debug", since = "1.7.0")]
+#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Sender {{ .. }}")
+ f.debug_struct("Sender").finish()
}
}
@@ -699,12 +942,37 @@ impl<T> SyncSender<T> {
/// Note that a successful send does *not* guarantee that the receiver will
/// ever see the data if there is a buffer on this channel. Items may be
/// enqueued in the internal buffer for the receiver to receive at a later
- /// time. If the buffer size is 0, however, it can be guaranteed that the
- /// receiver has indeed received the data if this function returns success.
+ /// time. If the buffer size is 0, however, the channel becomes a rendezvous
+ /// channel and it guarantees that the receiver has indeed received
+ /// the data if this function returns success.
///
- /// This function will never panic, but it may return `Err` if the
- /// `Receiver` has disconnected and is no longer able to receive
+ /// This function will never panic, but it may return [`Err`] if the
+ /// [`Receiver`] has disconnected and is no longer able to receive
/// information.
+ ///
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use std::sync::mpsc::sync_channel;
+ /// use std::thread;
+ ///
+ /// // Create a rendezvous sync_channel with buffer size 0
+ /// let (sync_sender, receiver) = sync_channel(0);
+ ///
+ /// thread::spawn(move || {
+ /// println!("sending message...");
+ /// sync_sender.send(1).unwrap();
+ /// // Thread is now blocked until the message is received
+ ///
+ /// println!("...message received!");
+ /// });
+ ///
+ /// let msg = receiver.recv().unwrap();
+ /// assert_eq!(1, msg);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn send(&self, t: T) -> Result<(), SendError<T>> {
self.inner.send(t).map_err(SendError)
@@ -712,13 +980,53 @@ impl<T> SyncSender<T> {
/// Attempts to send a value on this channel without blocking.
///
- /// This method differs from `send` by returning immediately if the
+ /// This method differs from [`send`] by returning immediately if the
/// channel's buffer is full or no receiver is waiting to acquire some
- /// data. Compared with `send`, this function has two failure cases
+ /// data. Compared with [`send`], this function has two failure cases
/// instead of one (one for disconnection, one for a full buffer).
///
- /// See `SyncSender::send` for notes about guarantees of whether the
+ /// See [`send`] for notes about guarantees of whether the
/// receiver has received the data or not if this function is successful.
+ ///
+ /// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use std::sync::mpsc::sync_channel;
+ /// use std::thread;
+ ///
+ /// // Create a sync_channel with buffer size 1
+ /// let (sync_sender, receiver) = sync_channel(1);
+ /// let sync_sender2 = sync_sender.clone();
+ ///
+ /// // First thread owns sync_sender
+ /// thread::spawn(move || {
+ /// sync_sender.send(1).unwrap();
+ /// sync_sender.send(2).unwrap();
+ /// // Thread blocked
+ /// });
+ ///
+ /// // Second thread owns sync_sender2
+ /// thread::spawn(move || {
+ /// // This will return an error and send
+ /// // no message if the buffer is full
+ /// sync_sender2.try_send(3).is_err();
+ /// });
+ ///
+ /// let mut msg;
+ /// msg = receiver.recv().unwrap();
+ /// println!("message {} received", msg);
+ ///
+ /// msg = receiver.recv().unwrap();
+ /// println!("message {} received", msg);
+ ///
+ /// // Third message may have never been sent
+ /// match receiver.try_recv() {
+ /// Ok(msg) => println!("message {} received", msg),
+ /// Err(_) => println!("the third message was never sent"),
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
self.inner.try_send(t)
@@ -740,10 +1048,10 @@ impl<T> Drop for SyncSender<T> {
}
}
-#[stable(feature = "mpsc_debug", since = "1.7.0")]
+#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for SyncSender<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "SyncSender {{ .. }}")
+ f.debug_struct("SyncSender").finish()
}
}
@@ -756,7 +1064,7 @@ impl<T> Receiver<T> {
Receiver { inner: UnsafeCell::new(inner) }
}
- /// Attempts to return a pending value on this receiver without blocking
+ /// Attempts to return a pending value on this receiver without blocking.
///
/// This method will never block the caller in order to wait for data to
/// become available. Instead, this will always return immediately with a
@@ -764,6 +1072,21 @@ impl<T> Receiver<T> {
///
/// This is useful for a flavor of "optimistic check" before deciding to
/// block on a receiver.
+ ///
+ /// Compared with [`recv`], this function has two failure cases instead of one
+ /// (one for disconnection, one for an empty buffer).
+ ///
+ /// [`recv`]: struct.Receiver.html#method.recv
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use std::sync::mpsc::{Receiver, channel};
+ ///
+ /// let (_, receiver): (_, Receiver<i32>) = channel();
+ ///
+ /// assert!(receiver.try_recv().is_err());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn try_recv(&self) -> Result<T, TryRecvError> {
loop {
@@ -819,15 +1142,19 @@ impl<T> Receiver<T> {
///
/// This function will always block the current thread if there is no data
/// available and it's possible for more data to be sent. Once a message is
- /// sent to the corresponding `Sender`, then this receiver will wake up and
- /// return that message.
+ /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this
+ /// receiver will wake up and return that message.
///
- /// If the corresponding `Sender` has disconnected, or it disconnects while
- /// this call is blocking, this call will wake up and return `Err` to
+ /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+ /// this call is blocking, this call will wake up and return [`Err`] to
/// indicate that no more messages can ever be received on this channel.
/// However, since channels are buffered, messages sent before the disconnect
/// will still be properly received.
///
+ /// [`Sender`]: struct.Sender.html
+ /// [`SyncSender`]: struct.SyncSender.html
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ ///
/// # Examples
///
/// ```
@@ -907,25 +1234,58 @@ impl<T> Receiver<T> {
///
/// This function will always block the current thread if there is no data
/// available and it's possible for more data to be sent. Once a message is
- /// sent to the corresponding `Sender`, then this receiver will wake up and
- /// return that message.
+ /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this
+ /// receiver will wake up and return that message.
///
- /// If the corresponding `Sender` has disconnected, or it disconnects while
- /// this call is blocking, this call will wake up and return `Err` to
+ /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+ /// this call is blocking, this call will wake up and return [`Err`] to
/// indicate that no more messages can ever be received on this channel.
/// However, since channels are buffered, messages sent before the disconnect
/// will still be properly received.
///
+ /// [`Sender`]: struct.Sender.html
+ /// [`SyncSender`]: struct.SyncSender.html
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ ///
/// # Examples
///
+ /// Successfully receiving value before encountering timeout:
+ ///
+ /// ```no_run
+ /// use std::thread;
+ /// use std::time::Duration;
+ /// use std::sync::mpsc;
+ ///
+ /// let (send, recv) = mpsc::channel();
+ ///
+ /// thread::spawn(move || {
+ /// send.send('a').unwrap();
+ /// });
+ ///
+ /// assert_eq!(
+ /// recv.recv_timeout(Duration::from_millis(400)),
+ /// Ok('a')
+ /// );
+ /// ```
+ ///
+ /// Receiving an error upon reaching timeout:
+ ///
/// ```no_run
- /// use std::sync::mpsc::{self, RecvTimeoutError};
+ /// use std::thread;
/// use std::time::Duration;
+ /// use std::sync::mpsc;
+ ///
+ /// let (send, recv) = mpsc::channel();
///
- /// let (send, recv) = mpsc::channel::<()>();
+ /// thread::spawn(move || {
+ /// thread::sleep(Duration::from_millis(800));
+ /// send.send('a').unwrap();
+ /// });
///
- /// let timeout = Duration::from_millis(100);
- /// assert_eq!(Err(RecvTimeoutError::Timeout), recv.recv_timeout(timeout));
+ /// assert_eq!(
+ /// recv.recv_timeout(Duration::from_millis(400)),
+ /// Err(mpsc::RecvTimeoutError::Timeout)
+ /// );
/// ```
#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
@@ -937,11 +1297,72 @@ impl<T> Receiver<T> {
Err(TryRecvError::Disconnected)
=> Err(RecvTimeoutError::Disconnected),
Err(TryRecvError::Empty)
- => self.recv_max_until(Instant::now() + timeout)
+ => self.recv_deadline(Instant::now() + timeout)
}
}
- fn recv_max_until(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
+ /// Attempts to wait for a value on this receiver, returning an error if the
+ /// corresponding channel has hung up, or if `deadline` is reached.
+ ///
+ /// This function will always block the current thread if there is no data
+ /// available and it's possible for more data to be sent. Once a message is
+ /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this
+ /// receiver will wake up and return that message.
+ ///
+ /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+ /// this call is blocking, this call will wake up and return [`Err`] to
+ /// indicate that no more messages can ever be received on this channel.
+ /// However, since channels are buffered, messages sent before the disconnect
+ /// will still be properly received.
+ ///
+ /// [`Sender`]: struct.Sender.html
+ /// [`SyncSender`]: struct.SyncSender.html
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// Successfully receiving value before reaching deadline:
+ ///
+ /// ```no_run
+ /// #![feature(deadline_api)]
+ /// use std::thread;
+ /// use std::time::{Duration, Instant};
+ /// use std::sync::mpsc;
+ ///
+ /// let (send, recv) = mpsc::channel();
+ ///
+ /// thread::spawn(move || {
+ /// send.send('a').unwrap();
+ /// });
+ ///
+ /// assert_eq!(
+ /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+ /// Ok('a')
+ /// );
+ /// ```
+ ///
+ /// Receiving an error upon reaching deadline:
+ ///
+ /// ```no_run
+ /// #![feature(deadline_api)]
+ /// use std::thread;
+ /// use std::time::{Duration, Instant};
+ /// use std::sync::mpsc;
+ ///
+ /// let (send, recv) = mpsc::channel();
+ ///
+ /// thread::spawn(move || {
+ /// thread::sleep(Duration::from_millis(800));
+ /// send.send('a').unwrap();
+ /// });
+ ///
+ /// assert_eq!(
+ /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+ /// Err(mpsc::RecvTimeoutError::Timeout)
+ /// );
+ /// ```
+ #[unstable(feature = "deadline_api", issue = "46316")]
+ pub fn recv_deadline(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
use self::RecvTimeoutError::*;
loop {
@@ -993,7 +1414,31 @@ impl<T> Receiver<T> {
}
/// Returns an iterator that will block waiting for messages, but never
- /// `panic!`. It will return `None` when the channel has hung up.
+ /// [`panic!`]. It will return [`None`] when the channel has hung up.
+ ///
+ /// [`panic!`]: ../../../std/macro.panic.html
+ /// [`None`]: ../../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use std::sync::mpsc::channel;
+ /// use std::thread;
+ ///
+ /// let (send, recv) = channel();
+ ///
+ /// thread::spawn(move || {
+ /// send.send(1).unwrap();
+ /// send.send(2).unwrap();
+ /// send.send(3).unwrap();
+ /// });
+ ///
+ /// let mut iter = recv.iter();
+ /// assert_eq!(iter.next(), Some(1));
+ /// assert_eq!(iter.next(), Some(2));
+ /// assert_eq!(iter.next(), Some(3));
+ /// assert_eq!(iter.next(), None);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<T> {
Iter { rx: self }
@@ -1001,8 +1446,42 @@ impl<T> Receiver<T> {
/// Returns an iterator that will attempt to yield all pending values.
/// It will return `None` if there are no more pending values or if the
- /// channel has hung up. The iterator will never `panic!` or block the
+ /// channel has hung up. The iterator will never [`panic!`] or block the
/// user by waiting for values.
+ ///
+ /// [`panic!`]: ../../../std/macro.panic.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::sync::mpsc::channel;
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let (sender, receiver) = channel();
+ ///
+ /// // nothing is in the buffer yet
+ /// assert!(receiver.try_iter().next().is_none());
+ ///
+ /// thread::spawn(move || {
+ /// thread::sleep(Duration::from_secs(1));
+ /// sender.send(1).unwrap();
+ /// sender.send(2).unwrap();
+ /// sender.send(3).unwrap();
+ /// });
+ ///
+ /// // nothing is in the buffer yet
+ /// assert!(receiver.try_iter().next().is_none());
+ ///
+ /// // block for two seconds
+ /// thread::sleep(Duration::from_secs(2));
+ ///
+ /// let mut iter = receiver.try_iter();
+ /// assert_eq!(iter.next(), Some(1));
+ /// assert_eq!(iter.next(), Some(2));
+ /// assert_eq!(iter.next(), Some(3));
+ /// assert_eq!(iter.next(), None);
+ /// ```
#[stable(feature = "receiver_try_iter", since = "1.15.0")]
pub fn try_iter(&self) -> TryIter<T> {
TryIter { rx: self }
@@ -1132,10 +1611,10 @@ impl<T> Drop for Receiver<T> {
}
}
-#[stable(feature = "mpsc_debug", since = "1.7.0")]
+#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for Receiver<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Receiver {{ .. }}")
+ f.debug_struct("Receiver").finish()
}
}
@@ -1207,6 +1686,15 @@ impl<T: Send> error::Error for TrySendError<T> {
}
}
+#[stable(feature = "mpsc_error_conversions", since = "1.24.0")]
+impl<T> From<SendError<T>> for TrySendError<T> {
+ fn from(err: SendError<T>) -> TrySendError<T> {
+ match err {
+ SendError(t) => TrySendError::Disconnected(t),
+ }
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for RecvError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -1259,7 +1747,16 @@ impl error::Error for TryRecvError {
}
}
-#[stable(feature = "mpsc_recv_timeout_error", since = "1.14.0")]
+#[stable(feature = "mpsc_error_conversions", since = "1.24.0")]
+impl From<RecvError> for TryRecvError {
+ fn from(err: RecvError) -> TryRecvError {
+ match err {
+ RecvError => TryRecvError::Disconnected,
+ }
+ }
+}
+
+#[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")]
impl fmt::Display for RecvTimeoutError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
@@ -1273,7 +1770,7 @@ impl fmt::Display for RecvTimeoutError {
}
}
-#[stable(feature = "mpsc_recv_timeout_error", since = "1.14.0")]
+#[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")]
impl error::Error for RecvTimeoutError {
fn description(&self) -> &str {
match *self {
@@ -1291,6 +1788,15 @@ impl error::Error for RecvTimeoutError {
}
}
+#[stable(feature = "mpsc_error_conversions", since = "1.24.0")]
+impl From<RecvError> for RecvTimeoutError {
+ fn from(err: RecvError) -> RecvTimeoutError {
+ match err {
+ RecvError => RecvTimeoutError::Disconnected,
+ }
+ }
+}
+
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use env;
@@ -1539,7 +2045,7 @@ mod tests {
fn oneshot_single_thread_send_then_recv() {
let (tx, rx) = channel::<Box<i32>>();
tx.send(box 10).unwrap();
- assert!(rx.recv().unwrap() == box 10);
+ assert!(*rx.recv().unwrap() == 10);
}
#[test]
@@ -1596,7 +2102,7 @@ mod tests {
fn oneshot_multi_task_recv_then_send() {
let (tx, rx) = channel::<Box<i32>>();
let _t = thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box 10);
+ assert!(*rx.recv().unwrap() == 10);
});
tx.send(box 10).unwrap();
@@ -1609,7 +2115,7 @@ mod tests {
drop(tx);
});
let res = thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box 10);
+ assert!(*rx.recv().unwrap() == 10);
}).join();
assert!(res.is_err());
}
@@ -1663,7 +2169,7 @@ mod tests {
let _t = thread::spawn(move|| {
tx.send(box 10).unwrap();
});
- assert!(rx.recv().unwrap() == box 10);
+ assert!(*rx.recv().unwrap() == 10);
}
}
@@ -1688,7 +2194,7 @@ mod tests {
if i == 10 { return }
thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box i);
+ assert!(*rx.recv().unwrap() == i);
recv(rx, i + 1);
});
}
@@ -2225,7 +2731,7 @@ mod sync_tests {
fn oneshot_single_thread_send_then_recv() {
let (tx, rx) = sync_channel::<Box<i32>>(1);
tx.send(box 10).unwrap();
- assert!(rx.recv().unwrap() == box 10);
+ assert!(*rx.recv().unwrap() == 10);
}
#[test]
@@ -2297,7 +2803,7 @@ mod sync_tests {
fn oneshot_multi_task_recv_then_send() {
let (tx, rx) = sync_channel::<Box<i32>>(0);
let _t = thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box 10);
+ assert!(*rx.recv().unwrap() == 10);
});
tx.send(box 10).unwrap();
@@ -2310,7 +2816,7 @@ mod sync_tests {
drop(tx);
});
let res = thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box 10);
+ assert!(*rx.recv().unwrap() == 10);
}).join();
assert!(res.is_err());
}
@@ -2364,7 +2870,7 @@ mod sync_tests {
let _t = thread::spawn(move|| {
tx.send(box 10).unwrap();
});
- assert!(rx.recv().unwrap() == box 10);
+ assert!(*rx.recv().unwrap() == 10);
}
}
@@ -2389,7 +2895,7 @@ mod sync_tests {
if i == 10 { return }
thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box i);
+ assert!(*rx.recv().unwrap() == i);
recv(rx, i + 1);
});
}
@@ -2593,22 +3099,4 @@ mod sync_tests {
repro()
}
}
-
- #[test]
- fn fmt_debug_sender() {
- let (tx, _) = channel::<i32>();
- assert_eq!(format!("{:?}", tx), "Sender { .. }");
- }
-
- #[test]
- fn fmt_debug_recv() {
- let (_, rx) = channel::<i32>();
- assert_eq!(format!("{:?}", rx), "Receiver { .. }");
- }
-
- #[test]
- fn fmt_debug_sync_sender() {
- let (tx, _) = sync_channel::<i32>(1);
- assert_eq!(format!("{:?}", tx), "SyncSender { .. }");
- }
}
diff --git a/ctr-std/src/sync/mpsc/mpsc_queue.rs b/ctr-std/src/sync/mpsc/mpsc_queue.rs
index 8d80f94..296773d 100644
--- a/ctr-std/src/sync/mpsc/mpsc_queue.rs
+++ b/ctr-std/src/sync/mpsc/mpsc_queue.rs
@@ -1,29 +1,12 @@
-/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are
- * those of the authors and should not be interpreted as representing official
- * policies, either expressed or implied, of Dmitry Vyukov.
- */
+// Copyright 2017 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.
//! A mostly lock-free multi-producer, single consumer queue.
//!
diff --git a/ctr-std/src/sync/mpsc/select.rs b/ctr-std/src/sync/mpsc/select.rs
index 8b4da53..a9f3cea 100644
--- a/ctr-std/src/sync/mpsc/select.rs
+++ b/ctr-std/src/sync/mpsc/select.rs
@@ -148,12 +148,12 @@ impl Select {
let id = self.next_id.get();
self.next_id.set(id + 1);
Handle {
- id: id,
+ id,
selector: self.inner.get(),
next: ptr::null_mut(),
prev: ptr::null_mut(),
added: false,
- rx: rx,
+ rx,
packet: rx,
}
}
@@ -354,13 +354,13 @@ impl Iterator for Packets {
impl fmt::Debug for Select {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Select {{ .. }}")
+ f.debug_struct("Select").finish()
}
}
impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Handle {{ .. }}")
+ f.debug_struct("Handle").finish()
}
}
@@ -774,18 +774,4 @@ mod tests {
}
}
}
-
- #[test]
- fn fmt_debug_select() {
- let sel = Select::new();
- assert_eq!(format!("{:?}", sel), "Select { .. }");
- }
-
- #[test]
- fn fmt_debug_handle() {
- let (_, rx) = channel::<i32>();
- let sel = Select::new();
- let handle = sel.handle(&rx);
- assert_eq!(format!("{:?}", handle), "Handle { .. }");
- }
}
diff --git a/ctr-std/src/sync/mpsc/spsc_queue.rs b/ctr-std/src/sync/mpsc/spsc_queue.rs
index 5858e4b..cc4be92 100644
--- a/ctr-std/src/sync/mpsc/spsc_queue.rs
+++ b/ctr-std/src/sync/mpsc/spsc_queue.rs
@@ -1,31 +1,12 @@
-/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are
- * those of the authors and should not be interpreted as representing official
- * policies, either expressed or implied, of Dmitry Vyukov.
- */
-
-// http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
+// Copyright 2017 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.
//! A single-producer single-consumer concurrent queue
//!
@@ -33,18 +14,23 @@
//! concurrently between two threads. This data structure is safe to use and
//! enforces the semantics that there is one pusher and one popper.
+// http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
+
use alloc::boxed::Box;
use core::ptr;
use core::cell::UnsafeCell;
use sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
+use super::cache_aligned::CacheAligned;
+
// Node within the linked list queue of messages to send
struct Node<T> {
// FIXME: this could be an uninitialized T if we're careful enough, and
// that would reduce memory usage (and be a bit faster).
// is it worth it?
value: Option<T>, // nullable for re-use of nodes
+ cached: bool, // This node goes into the node cache
next: AtomicPtr<Node<T>>, // next node in the queue
}
@@ -52,38 +38,55 @@ struct Node<T> {
/// but it can be safely shared in an Arc if it is guaranteed that there
/// is only one popper and one pusher touching the queue at any one point in
/// time.
-pub struct Queue<T> {
+pub struct Queue<T, ProducerAddition=(), ConsumerAddition=()> {
// consumer fields
+ consumer: CacheAligned<Consumer<T, ConsumerAddition>>,
+
+ // producer fields
+ producer: CacheAligned<Producer<T, ProducerAddition>>,
+}
+
+struct Consumer<T, Addition> {
tail: UnsafeCell<*mut Node<T>>, // where to pop from
tail_prev: AtomicPtr<Node<T>>, // where to pop from
+ cache_bound: usize, // maximum cache size
+ cached_nodes: AtomicUsize, // number of nodes marked as cachable
+ addition: Addition,
+}
- // producer fields
+struct Producer<T, Addition> {
head: UnsafeCell<*mut Node<T>>, // where to push to
first: UnsafeCell<*mut Node<T>>, // where to get new nodes from
tail_copy: UnsafeCell<*mut Node<T>>, // between first/tail
-
- // Cache maintenance fields. Additions and subtractions are stored
- // separately in order to allow them to use nonatomic addition/subtraction.
- cache_bound: usize,
- cache_additions: AtomicUsize,
- cache_subtractions: AtomicUsize,
+ addition: Addition,
}
-unsafe impl<T: Send> Send for Queue<T> { }
+unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Send for Queue<T, P, C> { }
-unsafe impl<T: Send> Sync for Queue<T> { }
+unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Sync for Queue<T, P, C> { }
impl<T> Node<T> {
fn new() -> *mut Node<T> {
Box::into_raw(box Node {
value: None,
+ cached: false,
next: AtomicPtr::new(ptr::null_mut::<Node<T>>()),
})
}
}
-impl<T> Queue<T> {
- /// Creates a new queue.
+impl<T, ProducerAddition, ConsumerAddition> Queue<T, ProducerAddition, ConsumerAddition> {
+
+ /// Creates a new queue. With given additional elements in the producer and
+ /// consumer portions of the queue.
+ ///
+ /// Due to the performance implications of cache-contention,
+ /// we wish to keep fields used mainly by the producer on a separate cache
+ /// line than those used by the consumer.
+ /// Since cache lines are usually 64 bytes, it is unreasonably expensive to
+ /// allocate one for small fields, so we allow users to insert additional
+ /// fields into the cache lines already allocated by this for the producer
+ /// and consumer.
///
/// This is unsafe as the type system doesn't enforce a single
/// consumer-producer relationship. It also allows the consumer to `pop`
@@ -100,19 +103,28 @@ impl<T> Queue<T> {
/// cache (if desired). If the value is 0, then the cache has
/// no bound. Otherwise, the cache will never grow larger than
/// `bound` (although the queue itself could be much larger.
- pub unsafe fn new(bound: usize) -> Queue<T> {
+ pub unsafe fn with_additions(
+ bound: usize,
+ producer_addition: ProducerAddition,
+ consumer_addition: ConsumerAddition,
+ ) -> Self {
let n1 = Node::new();
let n2 = Node::new();
(*n1).next.store(n2, Ordering::Relaxed);
Queue {
- tail: UnsafeCell::new(n2),
- tail_prev: AtomicPtr::new(n1),
- head: UnsafeCell::new(n2),
- first: UnsafeCell::new(n1),
- tail_copy: UnsafeCell::new(n1),
- cache_bound: bound,
- cache_additions: AtomicUsize::new(0),
- cache_subtractions: AtomicUsize::new(0),
+ consumer: CacheAligned::new(Consumer {
+ tail: UnsafeCell::new(n2),
+ tail_prev: AtomicPtr::new(n1),
+ cache_bound: bound,
+ cached_nodes: AtomicUsize::new(0),
+ addition: consumer_addition
+ }),
+ producer: CacheAligned::new(Producer {
+ head: UnsafeCell::new(n2),
+ first: UnsafeCell::new(n1),
+ tail_copy: UnsafeCell::new(n1),
+ addition: producer_addition
+ }),
}
}
@@ -126,35 +138,25 @@ impl<T> Queue<T> {
assert!((*n).value.is_none());
(*n).value = Some(t);
(*n).next.store(ptr::null_mut(), Ordering::Relaxed);
- (**self.head.get()).next.store(n, Ordering::Release);
- *self.head.get() = n;
+ (**self.producer.head.get()).next.store(n, Ordering::Release);
+ *(&self.producer.head).get() = n;
}
}
unsafe fn alloc(&self) -> *mut Node<T> {
// First try to see if we can consume the 'first' node for our uses.
- // We try to avoid as many atomic instructions as possible here, so
- // the addition to cache_subtractions is not atomic (plus we're the
- // only one subtracting from the cache).
- if *self.first.get() != *self.tail_copy.get() {
- if self.cache_bound > 0 {
- let b = self.cache_subtractions.load(Ordering::Relaxed);
- self.cache_subtractions.store(b + 1, Ordering::Relaxed);
- }
- let ret = *self.first.get();
- *self.first.get() = (*ret).next.load(Ordering::Relaxed);
+ if *self.producer.first.get() != *self.producer.tail_copy.get() {
+ let ret = *self.producer.first.get();
+ *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
return ret;
}
// If the above fails, then update our copy of the tail and try
// again.
- *self.tail_copy.get() = self.tail_prev.load(Ordering::Acquire);
- if *self.first.get() != *self.tail_copy.get() {
- if self.cache_bound > 0 {
- let b = self.cache_subtractions.load(Ordering::Relaxed);
- self.cache_subtractions.store(b + 1, Ordering::Relaxed);
- }
- let ret = *self.first.get();
- *self.first.get() = (*ret).next.load(Ordering::Relaxed);
+ *self.producer.0.tail_copy.get() =
+ self.consumer.tail_prev.load(Ordering::Acquire);
+ if *self.producer.first.get() != *self.producer.tail_copy.get() {
+ let ret = *self.producer.first.get();
+ *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
return ret;
}
// If all of that fails, then we have to allocate a new node
@@ -170,27 +172,27 @@ impl<T> Queue<T> {
// sentinel from where we should start popping from. Hence, look at
// tail's next field and see if we can use it. If we do a pop, then
// the current tail node is a candidate for going into the cache.
- let tail = *self.tail.get();
+ let tail = *self.consumer.tail.get();
let next = (*tail).next.load(Ordering::Acquire);
if next.is_null() { return None }
assert!((*next).value.is_some());
let ret = (*next).value.take();
- *self.tail.get() = next;
- if self.cache_bound == 0 {
- self.tail_prev.store(tail, Ordering::Release);
+ *self.consumer.0.tail.get() = next;
+ if self.consumer.cache_bound == 0 {
+ self.consumer.tail_prev.store(tail, Ordering::Release);
} else {
- // FIXME: this is dubious with overflow.
- let additions = self.cache_additions.load(Ordering::Relaxed);
- let subtractions = self.cache_subtractions.load(Ordering::Relaxed);
- let size = additions - subtractions;
-
- if size < self.cache_bound {
- self.tail_prev.store(tail, Ordering::Release);
- self.cache_additions.store(additions + 1, Ordering::Relaxed);
+ let cached_nodes = self.consumer.cached_nodes.load(Ordering::Relaxed);
+ if cached_nodes < self.consumer.cache_bound && !(*tail).cached {
+ self.consumer.cached_nodes.store(cached_nodes, Ordering::Relaxed);
+ (*tail).cached = true;
+ }
+
+ if (*tail).cached {
+ self.consumer.tail_prev.store(tail, Ordering::Release);
} else {
- (*self.tail_prev.load(Ordering::Relaxed))
- .next.store(next, Ordering::Relaxed);
+ (*self.consumer.tail_prev.load(Ordering::Relaxed))
+ .next.store(next, Ordering::Relaxed);
// We have successfully erased all references to 'tail', so
// now we can safely drop it.
let _: Box<Node<T>> = Box::from_raw(tail);
@@ -211,17 +213,25 @@ impl<T> Queue<T> {
// This is essentially the same as above with all the popping bits
// stripped out.
unsafe {
- let tail = *self.tail.get();
+ let tail = *self.consumer.tail.get();
let next = (*tail).next.load(Ordering::Acquire);
if next.is_null() { None } else { (*next).value.as_mut() }
}
}
+
+ pub fn producer_addition(&self) -> &ProducerAddition {
+ &self.producer.addition
+ }
+
+ pub fn consumer_addition(&self) -> &ConsumerAddition {
+ &self.consumer.addition
+ }
}
-impl<T> Drop for Queue<T> {
+impl<T, ProducerAddition, ConsumerAddition> Drop for Queue<T, ProducerAddition, ConsumerAddition> {
fn drop(&mut self) {
unsafe {
- let mut cur = *self.first.get();
+ let mut cur = *self.producer.first.get();
while !cur.is_null() {
let next = (*cur).next.load(Ordering::Relaxed);
let _n: Box<Node<T>> = Box::from_raw(cur);
@@ -241,7 +251,7 @@ mod tests {
#[test]
fn smoke() {
unsafe {
- let queue = Queue::new(0);
+ let queue = Queue::with_additions(0, (), ());
queue.push(1);
queue.push(2);
assert_eq!(queue.pop(), Some(1));
@@ -258,7 +268,7 @@ mod tests {
#[test]
fn peek() {
unsafe {
- let queue = Queue::new(0);
+ let queue = Queue::with_additions(0, (), ());
queue.push(vec![1]);
// Ensure the borrowchecker works
@@ -281,7 +291,7 @@ mod tests {
#[test]
fn drop_full() {
unsafe {
- let q: Queue<Box<_>> = Queue::new(0);
+ let q: Queue<Box<_>> = Queue::with_additions(0, (), ());
q.push(box 1);
q.push(box 2);
}
@@ -290,7 +300,7 @@ mod tests {
#[test]
fn smoke_bound() {
unsafe {
- let q = Queue::new(0);
+ let q = Queue::with_additions(0, (), ());
q.push(1);
q.push(2);
assert_eq!(q.pop(), Some(1));
@@ -312,7 +322,7 @@ mod tests {
}
unsafe fn stress_bound(bound: usize) {
- let q = Arc::new(Queue::new(bound));
+ let q = Arc::new(Queue::with_additions(bound, (), ()));
let (tx, rx) = channel();
let q2 = q.clone();
diff --git a/ctr-std/src/sync/mpsc/stream.rs b/ctr-std/src/sync/mpsc/stream.rs
index 47cd897..d1515eb 100644
--- a/ctr-std/src/sync/mpsc/stream.rs
+++ b/ctr-std/src/sync/mpsc/stream.rs
@@ -41,15 +41,22 @@ const MAX_STEALS: isize = 5;
const MAX_STEALS: isize = 1 << 20;
pub struct Packet<T> {
- queue: spsc::Queue<Message<T>>, // internal queue for all message
+ // internal queue for all messages
+ queue: spsc::Queue<Message<T>, ProducerAddition, ConsumerAddition>,
+}
+struct ProducerAddition {
cnt: AtomicIsize, // How many items are on this channel
- steals: UnsafeCell<isize>, // How many times has a port received without blocking?
to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up
port_dropped: AtomicBool, // flag if the channel has been destroyed.
}
+struct ConsumerAddition {
+ steals: UnsafeCell<isize>, // How many times has a port received without blocking?
+}
+
+
pub enum Failure<T> {
Empty,
Disconnected,
@@ -78,13 +85,18 @@ enum Message<T> {
impl<T> Packet<T> {
pub fn new() -> Packet<T> {
Packet {
- queue: unsafe { spsc::Queue::new(128) },
-
- cnt: AtomicIsize::new(0),
- steals: UnsafeCell::new(0),
- to_wake: AtomicUsize::new(0),
-
- port_dropped: AtomicBool::new(false),
+ queue: unsafe { spsc::Queue::with_additions(
+ 128,
+ ProducerAddition {
+ cnt: AtomicIsize::new(0),
+ to_wake: AtomicUsize::new(0),
+
+ port_dropped: AtomicBool::new(false),
+ },
+ ConsumerAddition {
+ steals: UnsafeCell::new(0),
+ }
+ )},
}
}
@@ -92,7 +104,7 @@ impl<T> Packet<T> {
// If the other port has deterministically gone away, then definitely
// must return the data back up the stack. Otherwise, the data is
// considered as being sent.
- if self.port_dropped.load(Ordering::SeqCst) { return Err(t) }
+ if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { return Err(t) }
match self.do_send(Data(t)) {
UpSuccess | UpDisconnected => {},
@@ -104,14 +116,16 @@ impl<T> Packet<T> {
pub fn upgrade(&self, up: Receiver<T>) -> UpgradeResult {
// If the port has gone away, then there's no need to proceed any
// further.
- if self.port_dropped.load(Ordering::SeqCst) { return UpDisconnected }
+ if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) {
+ return UpDisconnected
+ }
self.do_send(GoUp(up))
}
fn do_send(&self, t: Message<T>) -> UpgradeResult {
self.queue.push(t);
- match self.cnt.fetch_add(1, Ordering::SeqCst) {
+ match self.queue.producer_addition().cnt.fetch_add(1, Ordering::SeqCst) {
// As described in the mod's doc comment, -1 == wakeup
-1 => UpWoke(self.take_to_wake()),
// As as described before, SPSC queues must be >= -2
@@ -125,7 +139,7 @@ impl<T> Packet<T> {
// will never remove this data. We can only have at most one item to
// drain (the port drains the rest).
DISCONNECTED => {
- self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+ self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
let first = self.queue.pop();
let second = self.queue.pop();
assert!(second.is_none());
@@ -144,8 +158,8 @@ impl<T> Packet<T> {
// Consumes ownership of the 'to_wake' field.
fn take_to_wake(&self) -> SignalToken {
- let ptr = self.to_wake.load(Ordering::SeqCst);
- self.to_wake.store(0, Ordering::SeqCst);
+ let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst);
+ self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
assert!(ptr != 0);
unsafe { SignalToken::cast_from_usize(ptr) }
}
@@ -154,14 +168,16 @@ impl<T> Packet<T> {
// back if it shouldn't sleep. Note that this is the location where we take
// steals into account.
fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> {
- assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+ assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
let ptr = unsafe { token.cast_to_usize() };
- self.to_wake.store(ptr, Ordering::SeqCst);
+ self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst);
- let steals = unsafe { ptr::replace(self.steals.get(), 0) };
+ let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) };
- match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
- DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); }
+ match self.queue.producer_addition().cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
+ DISCONNECTED => {
+ self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
+ }
// If we factor in our steals and notice that the channel has no
// data, we successfully sleep
n => {
@@ -170,7 +186,7 @@ impl<T> Packet<T> {
}
}
- self.to_wake.store(0, Ordering::SeqCst);
+ self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
Err(unsafe { SignalToken::cast_from_usize(ptr) })
}
@@ -201,7 +217,7 @@ impl<T> Packet<T> {
// "steal" factored into the channel count above).
data @ Ok(..) |
data @ Err(Upgraded(..)) => unsafe {
- *self.steals.get() -= 1;
+ *self.queue.consumer_addition().steals.get() -= 1;
data
},
@@ -223,20 +239,21 @@ impl<T> Packet<T> {
// down as much as possible (without going negative), and then
// adding back in whatever we couldn't factor into steals.
Some(data) => unsafe {
- if *self.steals.get() > MAX_STEALS {
- match self.cnt.swap(0, Ordering::SeqCst) {
+ if *self.queue.consumer_addition().steals.get() > MAX_STEALS {
+ match self.queue.producer_addition().cnt.swap(0, Ordering::SeqCst) {
DISCONNECTED => {
- self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+ self.queue.producer_addition().cnt.store(
+ DISCONNECTED, Ordering::SeqCst);
}
n => {
- let m = cmp::min(n, *self.steals.get());
- *self.steals.get() -= m;
+ let m = cmp::min(n, *self.queue.consumer_addition().steals.get());
+ *self.queue.consumer_addition().steals.get() -= m;
self.bump(n - m);
}
}
- assert!(*self.steals.get() >= 0);
+ assert!(*self.queue.consumer_addition().steals.get() >= 0);
}
- *self.steals.get() += 1;
+ *self.queue.consumer_addition().steals.get() += 1;
match data {
Data(t) => Ok(t),
GoUp(up) => Err(Upgraded(up)),
@@ -244,7 +261,7 @@ impl<T> Packet<T> {
},
None => {
- match self.cnt.load(Ordering::SeqCst) {
+ match self.queue.producer_addition().cnt.load(Ordering::SeqCst) {
n if n != DISCONNECTED => Err(Empty),
// This is a little bit of a tricky case. We failed to pop
@@ -273,7 +290,7 @@ impl<T> Packet<T> {
pub fn drop_chan(&self) {
// Dropping a channel is pretty simple, we just flag it as disconnected
// and then wakeup a blocker if there is one.
- match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) {
+ match self.queue.producer_addition().cnt.swap(DISCONNECTED, Ordering::SeqCst) {
-1 => { self.take_to_wake().signal(); }
DISCONNECTED => {}
n => { assert!(n >= 0); }
@@ -300,7 +317,7 @@ impl<T> Packet<T> {
// sends are gated on this flag, so we're immediately guaranteed that
// there are a bounded number of active sends that we'll have to deal
// with.
- self.port_dropped.store(true, Ordering::SeqCst);
+ self.queue.producer_addition().port_dropped.store(true, Ordering::SeqCst);
// Now that we're guaranteed to deal with a bounded number of senders,
// we need to drain the queue. This draining process happens atomically
@@ -310,9 +327,9 @@ impl<T> Packet<T> {
// continue to fail while active senders send data while we're dropping
// data, but eventually we're guaranteed to break out of this loop
// (because there is a bounded number of senders).
- let mut steals = unsafe { *self.steals.get() };
+ let mut steals = unsafe { *self.queue.consumer_addition().steals.get() };
while {
- let cnt = self.cnt.compare_and_swap(
+ let cnt = self.queue.producer_addition().cnt.compare_and_swap(
steals, DISCONNECTED, Ordering::SeqCst);
cnt != DISCONNECTED && cnt != steals
} {
@@ -353,9 +370,9 @@ impl<T> Packet<T> {
// increment the count on the channel (used for selection)
fn bump(&self, amt: isize) -> isize {
- match self.cnt.fetch_add(amt, Ordering::SeqCst) {
+ match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) {
DISCONNECTED => {
- self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+ self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
DISCONNECTED
}
n => n
@@ -404,8 +421,8 @@ impl<T> Packet<T> {
// this end. This is fine because we know it's a small bounded windows
// of time until the data is actually sent.
if was_upgrade {
- assert_eq!(unsafe { *self.steals.get() }, 0);
- assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+ assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0);
+ assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
return Ok(true)
}
@@ -418,7 +435,7 @@ impl<T> Packet<T> {
// If we were previously disconnected, then we know for sure that there
// is no thread in to_wake, so just keep going
let has_data = if prev == DISCONNECTED {
- assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+ assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
true // there is data, that data is that we're disconnected
} else {
let cur = prev + steals + 1;
@@ -441,13 +458,13 @@ impl<T> Packet<T> {
if prev < 0 {
drop(self.take_to_wake());
} else {
- while self.to_wake.load(Ordering::SeqCst) != 0 {
+ while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != 0 {
thread::yield_now();
}
}
unsafe {
- assert_eq!(*self.steals.get(), 0);
- *self.steals.get() = steals;
+ assert_eq!(*self.queue.consumer_addition().steals.get(), 0);
+ *self.queue.consumer_addition().steals.get() = steals;
}
// if we were previously positive, then there's surely data to
@@ -481,7 +498,7 @@ impl<T> Drop for Packet<T> {
// disconnection, but also a proper fence before the read of
// `to_wake`, so this assert cannot be removed with also removing
// the `to_wake` assert.
- assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED);
- assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+ assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED);
+ assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
}
}
diff --git a/ctr-std/src/sync/mpsc/sync.rs b/ctr-std/src/sync/mpsc/sync.rs
index 1d16e00..90f12c8 100644
--- a/ctr-std/src/sync/mpsc/sync.rs
+++ b/ctr-std/src/sync/mpsc/sync.rs
@@ -177,7 +177,7 @@ impl<T> Packet<T> {
lock: Mutex::new(State {
disconnected: false,
blocker: NoneBlocked,
- cap: cap,
+ cap,
canceled: None,
queue: Queue {
head: ptr::null_mut(),
diff --git a/ctr-std/src/sync/mutex.rs b/ctr-std/src/sync/mutex.rs
index 97b84d5..3b4904c 100644
--- a/ctr-std/src/sync/mutex.rs
+++ b/ctr-std/src/sync/mutex.rs
@@ -10,7 +10,6 @@
use cell::UnsafeCell;
use fmt;
-use marker;
use mem;
use ops::{Deref, DerefMut};
use ptr;
@@ -20,30 +19,38 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
/// A mutual exclusion primitive useful for protecting shared data
///
/// This mutex will block threads waiting for the lock to become available. The
-/// mutex can also be statically initialized or created via a `new`
+/// mutex can also be statically initialized or created via a [`new`]
/// constructor. Each mutex has a type parameter which represents the data that
/// it is protecting. The data can only be accessed through the RAII guards
-/// returned from `lock` and `try_lock`, which guarantees that the data is only
+/// returned from [`lock`] and [`try_lock`], which guarantees that the data is only
/// ever accessed when the mutex is locked.
///
/// # Poisoning
///
/// The mutexes in this module implement a strategy called "poisoning" where a
/// mutex is considered poisoned whenever a thread panics while holding the
-/// lock. Once a mutex is poisoned, all other threads are unable to access the
+/// mutex. Once a mutex is poisoned, all other threads are unable to access the
/// data by default as it is likely tainted (some invariant is not being
/// upheld).
///
-/// For a mutex, this means that the `lock` and `try_lock` methods return a
-/// `Result` which indicates whether a mutex has been poisoned or not. Most
-/// usage of a mutex will simply `unwrap()` these results, propagating panics
+/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a
+/// [`Result`] which indicates whether a mutex has been poisoned or not. Most
+/// usage of a mutex will simply [`unwrap()`] these results, propagating panics
/// among threads to ensure that a possibly invalid invariant is not witnessed.
///
/// A poisoned mutex, however, does not prevent all access to the underlying
-/// data. The `PoisonError` type has an `into_inner` method which will return
+/// data. The [`PoisonError`] type has an [`into_inner`] method which will return
/// the guard that would have otherwise been returned on a successful lock. This
/// allows access to the data, despite the lock being poisoned.
///
+/// [`new`]: #method.new
+/// [`lock`]: #method.lock
+/// [`try_lock`]: #method.try_lock
+/// [`Result`]: ../../std/result/enum.Result.html
+/// [`unwrap()`]: ../../std/result/enum.Result.html#method.unwrap
+/// [`PoisonError`]: ../../std/sync/struct.PoisonError.html
+/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner
+///
/// # Examples
///
/// ```
@@ -61,7 +68,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
/// let data = Arc::new(Mutex::new(0));
///
/// let (tx, rx) = channel();
-/// for _ in 0..10 {
+/// for _ in 0..N {
/// let (data, tx) = (data.clone(), tx.clone());
/// thread::spawn(move || {
/// // The shared state can only be accessed once the lock is held.
@@ -115,7 +122,7 @@ pub struct Mutex<T: ?Sized> {
// Note that this mutex is in a *box*, not inlined into the struct itself.
// Once a native mutex has been used once, its address can never change (it
// can't be moved). This mutex type can be safely moved at any time, so to
- // ensure that the native mutex is used correctly we box the inner lock to
+ // ensure that the native mutex is used correctly we box the inner mutex to
// give it a constant address.
inner: Box<sys::Mutex>,
poison: poison::Flag,
@@ -132,16 +139,16 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
///
-/// The data protected by the mutex can be access through this guard via its
+/// The data protected by the mutex can be accessed through this guard via its
/// [`Deref`] and [`DerefMut`] implementations.
///
-/// This structure is created by the [`lock()`] and [`try_lock()`] methods on
+/// This structure is created by the [`lock`] and [`try_lock`] methods on
/// [`Mutex`].
///
/// [`Deref`]: ../../std/ops/trait.Deref.html
/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html
-/// [`lock()`]: struct.Mutex.html#method.lock
-/// [`try_lock()`]: struct.Mutex.html#method.try_lock
+/// [`lock`]: struct.Mutex.html#method.lock
+/// [`try_lock`]: struct.Mutex.html#method.try_lock
/// [`Mutex`]: struct.Mutex.html
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -153,7 +160,9 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {}
+impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> { }
+#[stable(feature = "mutexguard", since = "1.19.0")]
+unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> { }
impl<T> Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
@@ -183,7 +192,7 @@ impl<T: ?Sized> Mutex<T> {
/// Acquires a mutex, blocking the current thread until it is able to do so.
///
/// This function will block the local thread until it is available to acquire
- /// the mutex. Upon returning, the thread is the only thread with the mutex
+ /// the mutex. Upon returning, the thread is the only thread with the lock
/// held. An RAII guard is returned to allow scoped unlock of the lock. When
/// the guard goes out of scope, the mutex will be unlocked.
///
@@ -225,7 +234,7 @@ impl<T: ?Sized> Mutex<T> {
/// Attempts to acquire this lock.
///
- /// If the lock could not be acquired at this time, then `Err` is returned.
+ /// If the lock could not be acquired at this time, then [`Err`] is returned.
/// Otherwise, an RAII guard is returned. The lock will be unlocked when the
/// guard is dropped.
///
@@ -237,6 +246,8 @@ impl<T: ?Sized> Mutex<T> {
/// this call will return failure if the mutex would otherwise be
/// acquired.
///
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ ///
/// # Examples
///
/// ```
@@ -267,9 +278,9 @@ impl<T: ?Sized> Mutex<T> {
}
}
- /// Determines whether the lock is poisoned.
+ /// Determines whether the mutex is poisoned.
///
- /// If another thread is active, the lock can still become poisoned at any
+ /// If another thread is active, the mutex can still become poisoned at any
/// time. You should not trust a `false` value for program correctness
/// without additional synchronization.
///
@@ -312,7 +323,7 @@ impl<T: ?Sized> Mutex<T> {
#[stable(feature = "mutex_into_inner", since = "1.6.0")]
pub fn into_inner(self) -> LockResult<T> where T: Sized {
// We know statically that there are no outstanding references to
- // `self` so there's no need to lock the inner lock.
+ // `self` so there's no need to lock the inner mutex.
//
// To get the inner value, we'd like to call `data.into_inner()`,
// but because `Mutex` impl-s `Drop`, we can't move out of it, so
@@ -353,7 +364,7 @@ impl<T: ?Sized> Mutex<T> {
#[stable(feature = "mutex_get_mut", since = "1.6.0")]
pub fn get_mut(&mut self) -> LockResult<&mut T> {
// We know statically that there are no other references to `self`, so
- // there's no need to lock the inner lock.
+ // there's no need to lock the inner mutex.
let data = unsafe { &mut *self.data.get() };
poison::map_result(self.poison.borrow(), |_| data )
}
@@ -371,7 +382,18 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> {
}
}
-#[stable(feature = "mutex_default", since = "1.9.0")]
+#[stable(feature = "mutex_from", since = "1.24.0")]
+impl<T> From<T> for Mutex<T> {
+ /// Creates a new mutex in an unlocked state ready for use.
+ /// This is equivalent to [`Mutex::new`].
+ ///
+ /// [`Mutex::new`]: #method.new
+ fn from(t: T) -> Self {
+ Mutex::new(t)
+ }
+}
+
+#[stable(feature = "mutex_default", since = "1.10.0")]
impl<T: ?Sized + Default> Default for Mutex<T> {
/// Creates a `Mutex<T>`, with the `Default` value for T.
fn default() -> Mutex<T> {
@@ -383,11 +405,18 @@ impl<T: ?Sized + Default> Default for Mutex<T> {
impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_lock() {
- Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard),
+ Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
Err(TryLockError::Poisoned(err)) => {
- write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
+ f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish()
},
- Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ <locked> }}")
+ Err(TryLockError::WouldBlock) => {
+ struct LockedPlaceholder;
+ impl fmt::Debug for LockedPlaceholder {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
+ }
+
+ f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish()
+ }
}
}
}
@@ -439,6 +468,13 @@ impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> {
}
}
+#[stable(feature = "std_guard_impls", since = "1.20.0")]
+impl<'a, T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'a, T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ (**self).fmt(f)
+ }
+}
+
pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
&guard.__lock.inner
}
@@ -459,9 +495,6 @@ mod tests {
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
- unsafe impl<T: Send> Send for Packet<T> {}
- unsafe impl<T> Sync for Packet<T> {}
-
#[test]
fn smoke() {
let m = Mutex::new(());
diff --git a/ctr-std/src/sync/once.rs b/ctr-std/src/sync/once.rs
index c449315..6fd8b6a 100644
--- a/ctr-std/src/sync/once.rs
+++ b/ctr-std/src/sync/once.rs
@@ -72,9 +72,11 @@ use thread::{self, Thread};
/// A synchronization primitive which can be used to run a one-time global
/// initialization. Useful for one-time initialization for FFI or related
-/// functionality. This type can only be constructed with the `ONCE_INIT`
+/// functionality. This type can only be constructed with the [`ONCE_INIT`]
/// value.
///
+/// [`ONCE_INIT`]: constant.ONCE_INIT.html
+///
/// # Examples
///
/// ```
@@ -101,15 +103,28 @@ unsafe impl Sync for Once {}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl Send for Once {}
-/// State yielded to the `call_once_force` method which can be used to query
-/// whether the `Once` was previously poisoned or not.
+/// State yielded to [`call_once_force`]’s closure parameter. The state can be
+/// used to query the poison status of the [`Once`].
+///
+/// [`call_once_force`]: struct.Once.html#method.call_once_force
+/// [`Once`]: struct.Once.html
#[unstable(feature = "once_poison", issue = "33577")]
#[derive(Debug)]
pub struct OnceState {
poisoned: bool,
}
-/// Initialization value for static `Once` values.
+/// Initialization value for static [`Once`] values.
+///
+/// [`Once`]: struct.Once.html
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Once, ONCE_INIT};
+///
+/// static START: Once = ONCE_INIT;
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub const ONCE_INIT: Once = Once::new();
@@ -212,15 +227,52 @@ impl Once {
self.call_inner(false, &mut |_| f.take().unwrap()());
}
- /// Performs the same function as `call_once` except ignores poisoning.
+ /// Performs the same function as [`call_once`] except ignores poisoning.
+ ///
+ /// Unlike [`call_once`], if this `Once` has been poisoned (i.e. a previous
+ /// call to `call_once` or `call_once_force` caused a panic), calling
+ /// `call_once_force` will still invoke the closure `f` and will _not_
+ /// result in an immediate panic. If `f` panics, the `Once` will remain
+ /// in a poison state. If `f` does _not_ panic, the `Once` will no
+ /// longer be in a poison state and all future calls to `call_once` or
+ /// `call_one_force` will no-op.
+ ///
+ /// The closure `f` is yielded a [`OnceState`] structure which can be used
+ /// to query the poison status of the `Once`.
+ ///
+ /// [`call_once`]: struct.Once.html#method.call_once
+ /// [`OnceState`]: struct.OnceState.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(once_poison)]
+ ///
+ /// use std::sync::{Once, ONCE_INIT};
+ /// use std::thread;
+ ///
+ /// static INIT: Once = ONCE_INIT;
+ ///
+ /// // poison the once
+ /// let handle = thread::spawn(|| {
+ /// INIT.call_once(|| panic!());
+ /// });
+ /// assert!(handle.join().is_err());
///
- /// If this `Once` has been poisoned (some initialization panicked) then
- /// this function will continue to attempt to call initialization functions
- /// until one of them doesn't panic.
+ /// // poisoning propagates
+ /// let handle = thread::spawn(|| {
+ /// INIT.call_once(|| {});
+ /// });
+ /// assert!(handle.join().is_err());
///
- /// The closure `f` is yielded a structure which can be used to query the
- /// state of this `Once` (whether initialization has previously panicked or
- /// not).
+ /// // call_once_force will still run and reset the poisoned state
+ /// INIT.call_once_force(|state| {
+ /// assert!(state.poisoned());
+ /// });
+ ///
+ /// // once any success happens, we stop propagating the poison
+ /// INIT.call_once(|| {});
+ /// ```
#[unstable(feature = "once_poison", issue = "33577")]
pub fn call_once_force<F>(&'static self, f: F) where F: FnOnce(&OnceState) {
// same as above, just with a different parameter to `call_inner`.
@@ -366,10 +418,47 @@ impl Drop for Finish {
}
impl OnceState {
- /// Returns whether the associated `Once` has been poisoned.
+ /// Returns whether the associated [`Once`] was poisoned prior to the
+ /// invocation of the closure passed to [`call_once_force`].
+ ///
+ /// [`call_once_force`]: struct.Once.html#method.call_once_force
+ /// [`Once`]: struct.Once.html
+ ///
+ /// # Examples
+ ///
+ /// A poisoned `Once`:
+ ///
+ /// ```
+ /// #![feature(once_poison)]
+ ///
+ /// use std::sync::{Once, ONCE_INIT};
+ /// use std::thread;
+ ///
+ /// static INIT: Once = ONCE_INIT;
+ ///
+ /// // poison the once
+ /// let handle = thread::spawn(|| {
+ /// INIT.call_once(|| panic!());
+ /// });
+ /// assert!(handle.join().is_err());
+ ///
+ /// INIT.call_once_force(|state| {
+ /// assert!(state.poisoned());
+ /// });
+ /// ```
+ ///
+ /// An unpoisoned `Once`:
+ ///
+ /// ```
+ /// #![feature(once_poison)]
+ ///
+ /// use std::sync::{Once, ONCE_INIT};
+ ///
+ /// static INIT: Once = ONCE_INIT;
///
- /// Once an initalization routine for a `Once` has panicked it will forever
- /// indicate to future forced initialization routines that it is poisoned.
+ /// INIT.call_once_force(|state| {
+ /// assert!(!state.poisoned());
+ /// });
#[unstable(feature = "once_poison", issue = "33577")]
pub fn poisoned(&self) -> bool {
self.poisoned
diff --git a/ctr-std/src/sync/rwlock.rs b/ctr-std/src/sync/rwlock.rs
index a3db0ad..2edf02e 100644
--- a/ctr-std/src/sync/rwlock.rs
+++ b/ctr-std/src/sync/rwlock.rs
@@ -10,7 +10,6 @@
use cell::UnsafeCell;
use fmt;
-use marker;
use mem;
use ops::{Deref, DerefMut};
use ptr;
@@ -24,19 +23,24 @@ use sys_common::rwlock as sys;
/// of the underlying data (exclusive access) and the read portion of this lock
/// typically allows for read-only access (shared access).
///
+/// In comparison, a [`Mutex`] does not distinguish between readers or writers
+/// that aquire the lock, therefore blocking any threads waiting for the lock to
+/// become available. An `RwLock` will allow any number of readers to aquire the
+/// lock as long as a writer is not holding the lock.
+///
/// The priority policy of the lock is dependent on the underlying operating
/// system's implementation, and this type does not guarantee that any
/// particular policy will be used.
///
/// The type parameter `T` represents the data that this lock protects. It is
-/// required that `T` satisfies `Send` to be shared across threads and `Sync` to
-/// allow concurrent access through readers. The RAII guards returned from the
-/// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
-/// to allow access to the contained of the lock.
+/// required that `T` satisfies [`Send`] to be shared across threads and
+/// [`Sync`] to allow concurrent access through readers. The RAII guards
+/// returned from the locking methods implement [`Deref`][] (and [`DerefMut`]
+/// for the `write` methods) to allow access to the content of the lock.
///
/// # Poisoning
///
-/// An `RwLock`, like `Mutex`, will become poisoned on a panic. Note, however,
+/// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however,
/// that an `RwLock` may only be poisoned if a panic occurs while it is locked
/// exclusively (write mode). If a panic occurs in any reader, then the lock
/// will not be poisoned.
@@ -63,6 +67,12 @@ use sys_common::rwlock as sys;
/// assert_eq!(*w, 6);
/// } // write lock is dropped here
/// ```
+///
+/// [`Deref`]: ../../std/ops/trait.Deref.html
+/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html
+/// [`Send`]: ../../std/marker/trait.Send.html
+/// [`Sync`]: ../../std/marker/trait.Sync.html
+/// [`Mutex`]: struct.Mutex.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLock<T: ?Sized> {
inner: Box<sys::RWLock>,
@@ -71,18 +81,18 @@ pub struct RwLock<T: ?Sized> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: ?Sized + Send + Sync> Send for RwLock<T> {}
+unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
/// RAII structure used to release the shared read access of a lock when
/// dropped.
///
-/// This structure is created by the [`read()`] and [`try_read()`] methods on
+/// This structure is created by the [`read`] and [`try_read`] methods on
/// [`RwLock`].
///
-/// [`read()`]: struct.RwLock.html#method.read
-/// [`try_read()`]: struct.RwLock.html#method.try_read
+/// [`read`]: struct.RwLock.html#method.read
+/// [`try_read`]: struct.RwLock.html#method.try_read
/// [`RwLock`]: struct.RwLock.html
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -91,16 +101,19 @@ pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {}
+impl<'a, T: ?Sized> !Send for RwLockReadGuard<'a, T> {}
+
+#[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
+unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockReadGuard<'a, T> {}
/// RAII structure used to release the exclusive write access of a lock when
/// dropped.
///
-/// This structure is created by the [`write()`] and [`try_write()`] methods
+/// This structure is created by the [`write`] and [`try_write`] methods
/// on [`RwLock`].
///
-/// [`write()`]: struct.RwLock.html#method.write
-/// [`try_write()`]: struct.RwLock.html#method.try_write
+/// [`write`]: struct.RwLock.html#method.write
+/// [`try_write`]: struct.RwLock.html#method.try_write
/// [`RwLock`]: struct.RwLock.html
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -110,7 +123,10 @@ pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized> !marker::Send for RwLockWriteGuard<'a, T> {}
+impl<'a, T: ?Sized> !Send for RwLockWriteGuard<'a, T> {}
+
+#[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
+unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockWriteGuard<'a, T> {}
impl<T> RwLock<T> {
/// Creates a new instance of an `RwLock<T>` which is unlocked.
@@ -154,6 +170,24 @@ impl<T: ?Sized> RwLock<T> {
/// # Panics
///
/// This function might panic when called if the lock is already held by the current thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, RwLock};
+ /// use std::thread;
+ ///
+ /// let lock = Arc::new(RwLock::new(1));
+ /// let c_lock = lock.clone();
+ ///
+ /// let n = lock.read().unwrap();
+ /// assert_eq!(*n, 1);
+ ///
+ /// thread::spawn(move || {
+ /// let r = c_lock.read();
+ /// assert!(r.is_ok());
+ /// }).join().unwrap();
+ /// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn read(&self) -> LockResult<RwLockReadGuard<T>> {
@@ -180,6 +214,19 @@ impl<T: ?Sized> RwLock<T> {
/// is poisoned whenever a writer panics while holding an exclusive lock. An
/// error will only be returned if the lock would have otherwise been
/// acquired.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let lock = RwLock::new(1);
+ ///
+ /// match lock.try_read() {
+ /// Ok(n) => assert_eq!(*n, 1),
+ /// Err(_) => unreachable!(),
+ /// };
+ /// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<T>> {
@@ -210,6 +257,19 @@ impl<T: ?Sized> RwLock<T> {
/// # Panics
///
/// This function might panic when called if the lock is already held by the current thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let lock = RwLock::new(1);
+ ///
+ /// let mut n = lock.write().unwrap();
+ /// *n = 2;
+ ///
+ /// assert!(lock.try_read().is_err());
+ /// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write(&self) -> LockResult<RwLockWriteGuard<T>> {
@@ -236,6 +296,19 @@ impl<T: ?Sized> RwLock<T> {
/// is poisoned whenever a writer panics while holding an exclusive lock. An
/// error will only be returned if the lock would have otherwise been
/// acquired.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let lock = RwLock::new(1);
+ ///
+ /// let n = lock.read().unwrap();
+ /// assert_eq!(*n, 1);
+ ///
+ /// assert!(lock.try_write().is_err());
+ /// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<T>> {
@@ -253,6 +326,22 @@ impl<T: ?Sized> RwLock<T> {
/// If another thread is active, the lock can still become poisoned at any
/// time. You should not trust a `false` value for program correctness
/// without additional synchronization.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, RwLock};
+ /// use std::thread;
+ ///
+ /// let lock = Arc::new(RwLock::new(0));
+ /// let c_lock = lock.clone();
+ ///
+ /// let _ = thread::spawn(move || {
+ /// let _lock = c_lock.write().unwrap();
+ /// panic!(); // the lock gets poisoned
+ /// }).join();
+ /// assert_eq!(lock.is_poisoned(), true);
+ /// ```
#[inline]
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn is_poisoned(&self) -> bool {
@@ -267,6 +356,19 @@ impl<T: ?Sized> RwLock<T> {
/// is poisoned whenever a writer panics while holding an exclusive lock. An
/// error will only be returned if the lock would have otherwise been
/// acquired.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let lock = RwLock::new(String::new());
+ /// {
+ /// let mut s = lock.write().unwrap();
+ /// *s = "modified".to_owned();
+ /// }
+ /// assert_eq!(lock.into_inner().unwrap(), "modified");
+ /// ```
#[stable(feature = "rwlock_into_inner", since = "1.6.0")]
pub fn into_inner(self) -> LockResult<T> where T: Sized {
// We know statically that there are no outstanding references to
@@ -282,7 +384,7 @@ impl<T: ?Sized> RwLock<T> {
(ptr::read(inner), ptr::read(poison), ptr::read(data))
};
mem::forget(self);
- inner.destroy(); // Keep in sync with the `Drop` impl.
+ inner.destroy(); // Keep in sync with the `Drop` impl.
drop(inner);
poison::map_result(poison.borrow(), |_| data.into_inner())
@@ -300,6 +402,16 @@ impl<T: ?Sized> RwLock<T> {
/// is poisoned whenever a writer panics while holding an exclusive lock. An
/// error will only be returned if the lock would have otherwise been
/// acquired.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let mut lock = RwLock::new(0);
+ /// *lock.get_mut().unwrap() = 10;
+ /// assert_eq!(*lock.read().unwrap(), 10);
+ /// ```
#[stable(feature = "rwlock_get_mut", since = "1.6.0")]
pub fn get_mut(&mut self) -> LockResult<&mut T> {
// We know statically that there are no other references to `self`, so
@@ -321,16 +433,23 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> {
impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_read() {
- Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard),
+ Ok(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(),
Err(TryLockError::Poisoned(err)) => {
- write!(f, "RwLock {{ data: Poisoned({:?}) }}", &**err.get_ref())
+ f.debug_struct("RwLock").field("data", &&**err.get_ref()).finish()
},
- Err(TryLockError::WouldBlock) => write!(f, "RwLock {{ <locked> }}")
+ Err(TryLockError::WouldBlock) => {
+ struct LockedPlaceholder;
+ impl fmt::Debug for LockedPlaceholder {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
+ }
+
+ f.debug_struct("RwLock").field("data", &LockedPlaceholder).finish()
+ }
}
}
}
-#[stable(feature = "rw_lock_default", since = "1.9.0")]
+#[stable(feature = "rw_lock_default", since = "1.10.0")]
impl<T: Default> Default for RwLock<T> {
/// Creates a new `RwLock<T>`, with the `Default` value for T.
fn default() -> RwLock<T> {
@@ -338,6 +457,17 @@ impl<T: Default> Default for RwLock<T> {
}
}
+#[stable(feature = "rw_lock_from", since = "1.24.0")]
+impl<T> From<T> for RwLock<T> {
+ /// Creates a new instance of an `RwLock<T>` which is unlocked.
+ /// This is equivalent to [`RwLock::new`].
+ ///
+ /// [`RwLock::new`]: #method.new
+ fn from(t: T) -> Self {
+ RwLock::new(t)
+ }
+}
+
impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
unsafe fn new(lock: &'rwlock RwLock<T>)
-> LockResult<RwLockReadGuard<'rwlock, T>> {
@@ -370,6 +500,13 @@ impl<'a, T: fmt::Debug> fmt::Debug for RwLockReadGuard<'a, T> {
}
}
+#[stable(feature = "std_guard_impls", since = "1.20.0")]
+impl<'a, T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'a, T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ (**self).fmt(f)
+ }
+}
+
#[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 {
@@ -379,6 +516,13 @@ impl<'a, T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'a, T> {
}
}
+#[stable(feature = "std_guard_impls", since = "1.20.0")]
+impl<'a, T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'a, T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ (**self).fmt(f)
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> {
type Target = T;
@@ -421,8 +565,6 @@ impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> {
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
- #![allow(deprecated)] // rand
-
use rand::{self, Rng};
use sync::mpsc::channel;
use thread;
@@ -443,7 +585,7 @@ mod tests {
#[test]
fn frob() {
- const N: usize = 10;
+ const N: u32 = 10;
const M: usize = 1000;
let r = Arc::new(RwLock::new(()));
@@ -472,7 +614,7 @@ mod tests {
fn test_rw_arc_poison_wr() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
- let _: Result<(), _> = thread::spawn(move|| {
+ let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.write().unwrap();
panic!();
}).join();
@@ -484,7 +626,7 @@ mod tests {
let arc = Arc::new(RwLock::new(1));
assert!(!arc.is_poisoned());
let arc2 = arc.clone();
- let _: Result<(), _> = thread::spawn(move|| {
+ let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.write().unwrap();
panic!();
}).join();
@@ -496,7 +638,7 @@ mod tests {
fn test_rw_arc_no_poison_rr() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
- let _: Result<(), _> = thread::spawn(move|| {
+ let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.read().unwrap();
panic!();
}).join();
@@ -507,7 +649,7 @@ mod tests {
fn test_rw_arc_no_poison_rw() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
- let _: Result<(), _> = thread::spawn(move|| {
+ let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.read().unwrap();
panic!()
}).join();
@@ -521,7 +663,7 @@ mod tests {
let arc2 = arc.clone();
let (tx, rx) = channel();
- thread::spawn(move|| {
+ thread::spawn(move || {
let mut lock = arc2.write().unwrap();
for _ in 0..10 {
let tmp = *lock;
@@ -536,7 +678,7 @@ mod tests {
let mut children = Vec::new();
for _ in 0..5 {
let arc3 = arc.clone();
- children.push(thread::spawn(move|| {
+ children.push(thread::spawn(move || {
let lock = arc3.read().unwrap();
assert!(*lock >= 0);
}));
@@ -557,7 +699,7 @@ mod tests {
fn test_rw_arc_access_in_unwind() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
- let _ = thread::spawn(move|| -> () {
+ let _ = thread::spawn(move || -> () {
struct Unwinder {
i: Arc<RwLock<isize>>,
}
diff --git a/ctr-std/src/sys/mod.rs b/ctr-std/src/sys/mod.rs
index 175e227..569336d 100644
--- a/ctr-std/src/sys/mod.rs
+++ b/ctr-std/src/sys/mod.rs
@@ -13,25 +13,78 @@
//! The `std::sys` module is the abstracted interface through which
//! `std` talks to the underlying operating system. It has different
//! implementations for different operating system families, today
-//! just Unix and Windows.
+//! just Unix and Windows, and initial support for Redox.
//!
//! The centralization of platform-specific code in this module is
//! enforced by the "platform abstraction layer" tidy script in
-//! `tools/tidy/pal.rs`.
+//! `tools/tidy/src/pal.rs`.
//!
//! This module is closely related to the platform-independent system
//! integration code in `std::sys_common`. See that module's
//! documentation for details.
//!
-//! In the future it would be desirable for the indepedent
+//! In the future it would be desirable for the independent
//! implementations of this module to be extracted to their own crates
//! that `std` can link to, thus enabling their implementation
//! out-of-tree via crate replacement. Though due to the complex
//! inter-dependencies within `std` that will be a challenging goal to
//! achieve.
-pub use self::imp::*;
+#![allow(missing_debug_implementations)]
-#[cfg(unix)]
-#[path = "unix/mod.rs"]
-mod imp;
+cfg_if! {
+ if #[cfg(unix)] {
+ mod unix;
+ pub use self::unix::*;
+ } else {
+ compile_error!("libstd doesn't compile for this platform yet");
+ }
+}
+
+// Import essential modules from both platforms when documenting. These are
+// then later used in the `std::os` module when documenting, for example,
+// Windows when we're compiling for Linux.
+
+#[cfg(dox)]
+cfg_if! {
+ if #[cfg(any(unix, target_os = "redox"))] {
+ // On unix we'll document what's already available
+ pub use self::ext as unix_ext;
+ } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] {
+ // On CloudABI and wasm right now the module below doesn't compile
+ // (missing things in `libc` which is empty) so just omit everything
+ // with an empty module
+ #[unstable(issue = "0", feature = "std_internals")]
+ pub mod unix_ext {}
+ } else {
+ // On other platforms like Windows document the bare bones of unix
+ use os::linux as platform;
+ #[path = "unix/ext/mod.rs"]
+ pub mod unix_ext;
+ }
+}
+
+#[cfg(dox)]
+cfg_if! {
+ if #[cfg(windows)] {
+ // On windows we'll just be documenting what's already available
+ pub use self::ext as windows_ext;
+ } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] {
+ // On CloudABI and wasm right now the shim below doesn't compile, so
+ // just omit it
+ #[unstable(issue = "0", feature = "std_internals")]
+ pub mod windows_ext {}
+ } else {
+ // On all other platforms (aka linux/osx/etc) then pull in a "minimal"
+ // amount of windows goop which ends up compiling
+ #[macro_use]
+ #[path = "windows/compat.rs"]
+ mod compat;
+
+ #[path = "windows/c.rs"]
+ mod c;
+
+ #[path = "windows/ext/mod.rs"]
+ pub mod windows_ext;
+ }
+}
diff --git a/ctr-std/src/sys/unix/args.rs b/ctr-std/src/sys/unix/args.rs
new file mode 100644
index 0000000..84d0c85
--- /dev/null
+++ b/ctr-std/src/sys/unix/args.rs
@@ -0,0 +1,60 @@
+// Copyright 2017 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 ffi::OsString;
+use marker::PhantomData;
+use vec;
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+ // Currently null because we haven't implemented args yet
+}
+
+pub unsafe fn cleanup() {
+}
+
+pub fn args() -> Args {
+ return Args {
+ iter: Vec::new().into_iter(),
+ _dont_send_or_sync_me: PhantomData,
+ }
+}
+
+pub struct Args {
+ iter: vec::IntoIter<OsString>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ self.iter.as_slice()
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ self.iter.next_back()
+ }
+}
diff --git a/ctr-std/src/sys/unix/backtrace.rs b/ctr-std/src/sys/unix/backtrace.rs
new file mode 100644
index 0000000..9a8c48f
--- /dev/null
+++ b/ctr-std/src/sys/unix/backtrace.rs
@@ -0,0 +1,37 @@
+// Copyright 2017 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 io;
+use sys::unsupported;
+use sys_common::backtrace::Frame;
+
+pub struct BacktraceContext;
+
+pub fn unwind_backtrace(_frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ unsupported()
+}
+
+pub fn resolve_symname<F>(_frame: Frame,
+ _callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ unsupported()
+}
+
+pub fn foreach_symbol_fileline<F>(_: Frame,
+ _: F,
+ _: &BacktraceContext) -> io::Result<bool>
+ where F: FnMut(&[u8], u32) -> io::Result<()>
+{
+ unsupported()
+}
diff --git a/ctr-std/src/sys/unix/cmath.rs b/ctr-std/src/sys/unix/cmath.rs
new file mode 100644
index 0000000..2bc9665
--- /dev/null
+++ b/ctr-std/src/sys/unix/cmath.rs
@@ -0,0 +1,43 @@
+// Copyright 2017 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.
+
+#![cfg(not(test))]
+
+use libc::{c_float, c_double};
+
+#[link_name = "m"]
+extern {
+ pub fn acos(n: c_double) -> c_double;
+ pub fn acosf(n: c_float) -> c_float;
+ pub fn asin(n: c_double) -> c_double;
+ pub fn asinf(n: c_float) -> c_float;
+ pub fn atan(n: c_double) -> c_double;
+ pub fn atan2(a: c_double, b: c_double) -> c_double;
+ pub fn atan2f(a: c_float, b: c_float) -> c_float;
+ pub fn atanf(n: c_float) -> c_float;
+ pub fn cbrt(n: c_double) -> c_double;
+ pub fn cbrtf(n: c_float) -> c_float;
+ pub fn cosh(n: c_double) -> c_double;
+ pub fn coshf(n: c_float) -> c_float;
+ pub fn expm1(n: c_double) -> c_double;
+ pub fn expm1f(n: c_float) -> c_float;
+ pub fn fdim(a: c_double, b: c_double) -> c_double;
+ pub fn fdimf(a: c_float, b: c_float) -> c_float;
+ pub fn hypot(x: c_double, y: c_double) -> c_double;
+ pub fn hypotf(x: c_float, y: c_float) -> c_float;
+ pub fn log1p(n: c_double) -> c_double;
+ pub fn log1pf(n: c_float) -> c_float;
+ pub fn sinh(n: c_double) -> c_double;
+ pub fn sinhf(n: c_float) -> c_float;
+ pub fn tan(n: c_double) -> c_double;
+ pub fn tanf(n: c_float) -> c_float;
+ pub fn tanh(n: c_double) -> c_double;
+ pub fn tanhf(n: c_float) -> c_float;
+}
diff --git a/ctr-std/src/sys/unix/condvar.rs b/ctr-std/src/sys/unix/condvar.rs
index 938df8f..bfff16b 100644
--- a/ctr-std/src/sys/unix/condvar.rs
+++ b/ctr-std/src/sys/unix/condvar.rs
@@ -112,7 +112,9 @@ impl Condvar {
let now = Instant::now();
- let nanos = dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64;
+ let nanos = dur.as_secs()
+ .saturating_mul(1_000_000_000)
+ .saturating_add(dur.subsec_nanos() as u64);
mutex.unlock();
diff --git a/ctr-std/src/sys/unix/env.rs b/ctr-std/src/sys/unix/env.rs
new file mode 100644
index 0000000..393bdfe
--- /dev/null
+++ b/ctr-std/src/sys/unix/env.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 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.
+
+pub mod os {
+ pub const FAMILY: &'static str = "nintendo";
+ pub const OS: &'static str = "horizon";
+ pub const DLL_PREFIX: &'static str = "";
+ pub const DLL_SUFFIX: &'static str = ".cro";
+ pub const DLL_EXTENSION: &'static str = ".cro";
+ pub const EXE_SUFFIX: &'static str = ".3dsx";
+ pub const EXE_EXTENSION: &'static str = "3dsx";
+}
diff --git a/ctr-std/src/sys/unix/ext/ffi.rs b/ctr-std/src/sys/unix/ext/ffi.rs
index d59b4fc..fb9984c 100644
--- a/ctr-std/src/sys/unix/ext/ffi.rs
+++ b/ctr-std/src/sys/unix/ext/ffi.rs
@@ -20,11 +20,38 @@ use sys_common::{FromInner, IntoInner, AsInner};
/// Unix-specific extensions to `OsString`.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
- /// Creates an `OsString` from a byte vector.
+ /// Creates an [`OsString`] from a byte vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::OsStringExt;
+ ///
+ /// let bytes = b"foo".to_vec();
+ /// let os_string = OsString::from_vec(bytes);
+ /// assert_eq!(os_string.to_str(), Some("foo"));
+ /// ```
+ ///
+ /// [`OsString`]: ../../../ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
fn from_vec(vec: Vec<u8>) -> Self;
- /// Yields the underlying byte vector of this `OsString`.
+ /// Yields the underlying byte vector of this [`OsString`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::OsStringExt;
+ ///
+ /// let mut os_string = OsString::new();
+ /// os_string.push("foo");
+ /// let bytes = os_string.into_vec();
+ /// assert_eq!(bytes, b"foo");
+ /// ```
+ ///
+ /// [`OsString`]: ../../../ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
fn into_vec(self) -> Vec<u8>;
}
@@ -43,9 +70,36 @@ impl OsStringExt for OsString {
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
#[stable(feature = "rust1", since = "1.0.0")]
+ /// Creates an [`OsStr`] from a byte slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ /// use std::os::unix::ffi::OsStrExt;
+ ///
+ /// let bytes = b"foo";
+ /// let os_str = OsStr::from_bytes(bytes);
+ /// assert_eq!(os_str.to_str(), Some("foo"));
+ /// ```
+ ///
+ /// [`OsStr`]: ../../../ffi/struct.OsStr.html
fn from_bytes(slice: &[u8]) -> &Self;
- /// Gets the underlying byte view of the `OsStr` slice.
+ /// Gets the underlying byte view of the [`OsStr`] slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ /// use std::os::unix::ffi::OsStrExt;
+ ///
+ /// let mut os_str = OsStr::new("foo");
+ /// let bytes = os_str.as_bytes();
+ /// assert_eq!(bytes, b"foo");
+ /// ```
+ ///
+ /// [`OsStr`]: ../../../ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
fn as_bytes(&self) -> &[u8];
}
diff --git a/ctr-std/src/sys/unix/ext/io.rs b/ctr-std/src/sys/unix/ext/io.rs
new file mode 100644
index 0000000..c9fe359
--- /dev/null
+++ b/ctr-std/src/sys/unix/ext/io.rs
@@ -0,0 +1,108 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! Unix-specific extensions to general I/O primitives
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs;
+use os::raw;
+use sys;
+use io;
+use sys_common::{AsInner, FromInner, IntoInner};
+use libc;
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = raw::c_int;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawFd {
+ /// Constructs a new instance of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawFd {
+ /// Consumes this object, returning the raw underlying file descriptor.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for fs::File {
+ unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+ fs::File::from_inner(sys::fs::File::from_inner(fd))
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for fs::File {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdin {
+ fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdout {
+ fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stderr {
+ fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
+}
diff --git a/ctr-std/src/sys/unix/ext/mod.rs b/ctr-std/src/sys/unix/ext/mod.rs
index 04ea563..7b0d175 100644
--- a/ctr-std/src/sys/unix/ext/mod.rs
+++ b/ctr-std/src/sys/unix/ext/mod.rs
@@ -10,10 +10,16 @@
//! Experimental extensions to `std` for Unix platforms.
//!
-//! For now, this module is limited to extracting file descriptors,
-//! but its functionality will grow over time.
+//! Provides access to platform-level information on Unix platforms, and
+//! exposes Unix-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
//!
-//! # Example
+//! It exposes more ways to deal with platform-specific strings (`OsStr`,
+//! `OsString`), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! # Examples
//!
//! ```no_run
//! use std::fs::File;
@@ -28,8 +34,15 @@
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(unix))]
+pub mod io;
pub mod ffi;
+//pub mod fs;
+//pub mod process;
+pub mod raw;
+//pub mod thread;
+//pub mod net;
/// A prelude for conveniently writing platform-specific code.
///
@@ -37,5 +50,17 @@ pub mod ffi;
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::ffi::{OsStrExt, OsStringExt};
+ //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ //pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
+ //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ //pub use super::fs::DirEntryExt;
+ //#[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
+ //pub use super::fs::FileExt;
+ //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ //pub use super::thread::JoinHandleExt;
+ //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ //pub use super::process::{CommandExt, ExitStatusExt};
}
diff --git a/ctr-std/src/sys/unix/ext/raw.rs b/ctr-std/src/sys/unix/ext/raw.rs
new file mode 100644
index 0000000..7e4a439
--- /dev/null
+++ b/ctr-std/src/sys/unix/ext/raw.rs
@@ -0,0 +1,33 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! Unix-specific primitives available on all unix platforms
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![rustc_deprecated(since = "1.8.0",
+ reason = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions")]
+#![allow(deprecated, warnings)]
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32;
+
+#[doc(inline)]
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use sys::platform::raw::pthread_t;
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t};
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use sys::platform::raw::{blkcnt_t, time_t};
diff --git a/ctr-std/src/sys/unix/fd.rs b/ctr-std/src/sys/unix/fd.rs
index 91adac1..e19cbb0 100644
--- a/ctr-std/src/sys/unix/fd.rs
+++ b/ctr-std/src/sys/unix/fd.rs
@@ -14,9 +14,9 @@ use cmp;
use io::{self, Read};
use libc::{self, c_int, c_void, ssize_t};
use mem;
+use sync::atomic::{AtomicBool, Ordering};
use sys::cvt;
use sys_common::AsInner;
-use sys_common::io::read_to_end_uninitialized;
#[derive(Debug)]
pub struct FileDesc {
@@ -28,7 +28,7 @@ fn max_len() -> usize {
// with the man page quoting that if the count of bytes to read is
// greater than `SSIZE_MAX` the result is "unspecified".
//
- // On OSX, however, apparently the 64-bit libc is either buggy or
+ // On macOS, however, apparently the 64-bit libc is either buggy or
// intentionally showing odd behavior by rejecting any read with a size
// larger than or equal to INT_MAX. To handle both of these the read
// size is capped on both platforms.
@@ -110,22 +110,98 @@ impl FileDesc {
}
}
- // This is a unix-specific operation that the 3DS likely doesn't support.
- // However, there's no reason to make calling this function an error either.
+ #[cfg(not(any(target_env = "newlib",
+ target_os = "solaris",
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "l4re",
+ target_os = "haiku")))]
pub fn set_cloexec(&self) -> io::Result<()> {
- Ok(())
+ unsafe {
+ cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
+ Ok(())
+ }
+ }
+ #[cfg(any(target_env = "newlib",
+ target_os = "solaris",
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "l4re",
+ target_os = "haiku"))]
+ pub fn set_cloexec(&self) -> io::Result<()> {
+ unsafe {
+ let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
+ let new = previous | libc::FD_CLOEXEC;
+ if new != previous {
+ cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
+ }
+ Ok(())
+ }
}
- // This is a unix-specific operation that the 3DS likely doesn't support.
- // However, there's no reason to make calling this function an error either.
- pub fn set_nonblocking(&self) -> io::Result<()> {
- Ok(())
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ unsafe {
+ let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
+ let new = if nonblocking {
+ previous | libc::O_NONBLOCK
+ } else {
+ previous & !libc::O_NONBLOCK
+ };
+ if new != previous {
+ cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
+ }
+ Ok(())
+ }
}
- // The sdmc and romfs devoptabs definitely don't support this operation.
- // Not sure if it will be needed for network support or not.
pub fn duplicate(&self) -> io::Result<FileDesc> {
- unimplemented!()
+ // We want to atomically duplicate this file descriptor and set the
+ // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
+ // flag, however, isn't supported on older Linux kernels (earlier than
+ // 2.6.24).
+ //
+ // To detect this and ensure that CLOEXEC is still set, we
+ // follow a strategy similar to musl [1] where if passing
+ // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
+ // supported (the third parameter, 0, is always valid), so we stop
+ // trying that.
+ //
+ // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
+ // resolve so we at least compile this.
+ //
+ // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
+ #[cfg(any(target_os = "android", target_os = "haiku"))]
+ use libc::F_DUPFD as F_DUPFD_CLOEXEC;
+ #[cfg(not(any(target_os = "android", target_os="haiku")))]
+ use libc::F_DUPFD_CLOEXEC;
+
+ let make_filedesc = |fd| {
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ Ok(fd)
+ };
+ static TRY_CLOEXEC: AtomicBool =
+ AtomicBool::new(!cfg!(target_os = "android"));
+ let fd = self.raw();
+ if TRY_CLOEXEC.load(Ordering::Relaxed) {
+ match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
+ // We *still* call the `set_cloexec` method as apparently some
+ // linux kernel at some point stopped setting CLOEXEC even
+ // though it reported doing so on F_DUPFD_CLOEXEC.
+ Ok(fd) => {
+ return Ok(if cfg!(target_os = "linux") {
+ make_filedesc(fd)?
+ } else {
+ FileDesc::new(fd)
+ })
+ }
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
+ TRY_CLOEXEC.store(false, Ordering::Relaxed);
+ }
+ Err(e) => return Err(e),
+ }
+ }
+ cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
}
}
@@ -133,10 +209,6 @@ impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
-
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- unsafe { read_to_end_uninitialized(self, buf) }
- }
}
impl AsInner<c_int> for FileDesc {
diff --git a/ctr-std/src/sys/unix/fs.rs b/ctr-std/src/sys/unix/fs.rs
index 06413c3..f30b270 100644
--- a/ctr-std/src/sys/unix/fs.rs
+++ b/ctr-std/src/sys/unix/fs.rs
@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+
use os::unix::prelude::*;
use ffi::{CString, CStr, OsString, OsStr};
@@ -23,8 +25,8 @@ use sys::time::SystemTime;
use sys::{cvt, cvt_r};
use sys_common::{AsInner, FromInner};
-use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek as lseek64,
- dirent as dirent64, open as open64, ftruncate as ftruncate64, off_t as off64_t};
+use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
+ ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64};
use libc::{readdir_r as readdir64_r};
pub struct File(FileDesc);
@@ -47,6 +49,12 @@ unsafe impl Sync for Dir {}
pub struct DirEntry {
entry: dirent64,
root: Arc<PathBuf>,
+ // We need to store an owned copy of the directory name
+ // on Solaris and Fuchsia because a) it uses a zero-length
+ // array to store the name, b) its lifetime between readdir
+ // calls is not guaranteed.
+ #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
+ name: Box<[u8]>
}
#[derive(Clone, Debug)]
@@ -75,7 +83,7 @@ pub struct DirBuilder { mode: mode_t }
impl FileAttr {
pub fn size(&self) -> u64 { self.stat.st_size as u64 }
pub fn perm(&self) -> FilePermissions {
- FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 }
+ FilePermissions { mode: (self.stat.st_mode as mode_t) }
}
pub fn file_type(&self) -> FileType {
@@ -85,17 +93,15 @@ impl FileAttr {
impl FileAttr {
pub fn modified(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_mtime as libc::time_t,
- tv_nsec: 0,
- }))
+ Err(io::Error::new(io::ErrorKind::Other,
+ "modification time is not available on this platform \
+ currently"))
}
pub fn accessed(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_atime as libc::time_t,
- tv_nsec: 0,
- }))
+ Err(io::Error::new(io::ErrorKind::Other,
+ "access time is not available on this platform \
+ currently"))
}
pub fn created(&self) -> io::Result<SystemTime> {
@@ -110,11 +116,17 @@ impl AsInner<stat64> for FileAttr {
}
impl FilePermissions {
- pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
+ pub fn readonly(&self) -> bool {
+ // check if any class (owner, group, others) has write permission
+ self.mode & 0o222 == 0
+ }
+
pub fn set_readonly(&mut self, readonly: bool) {
if readonly {
+ // remove write permission for all classes; equivalent to `chmod a-w <file>`
self.mode &= !0o222;
} else {
+ // add write permission for all classes; equivalent to `chmod a+w <file>`
self.mode |= 0o222;
}
}
@@ -146,6 +158,42 @@ impl fmt::Debug for ReadDir {
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
+ #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ unsafe {
+ loop {
+ // Although readdir_r(3) would be a correct function to use here because
+ // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
+ // is safe to use in threaded applications and it is generally preferred
+ // over the readdir_r(3C) function.
+ super::os::set_errno(0);
+ let entry_ptr = libc::readdir(self.dirp.0);
+ if entry_ptr.is_null() {
+ // NULL can mean either the end is reached or an error occurred.
+ // So we had to clear errno beforehand to check for an error now.
+ return match super::os::errno() {
+ 0 => None,
+ e => Some(Err(Error::from_raw_os_error(e))),
+ }
+ }
+
+ let name = (*entry_ptr).d_name.as_ptr();
+ let namelen = libc::strlen(name) as usize;
+
+ let ret = DirEntry {
+ entry: *entry_ptr,
+ name: ::slice::from_raw_parts(name as *const u8,
+ namelen as usize).to_owned().into_boxed_slice(),
+ root: self.root.clone()
+ };
+ if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
+ return Some(Ok(ret))
+ }
+ }
+ }
+ }
+
+ #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
unsafe {
let mut ret = DirEntry {
@@ -188,6 +236,12 @@ impl DirEntry {
lstat(&self.path())
}
+ #[cfg(any(target_os = "solaris", target_os = "haiku"))]
+ pub fn file_type(&self) -> io::Result<FileType> {
+ lstat(&self.path()).map(|m| m.file_type())
+ }
+
+ #[cfg(not(any(target_os = "solaris", target_os = "haiku")))]
pub fn file_type(&self) -> io::Result<FileType> {
match self.entry.d_type {
libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
@@ -293,7 +347,7 @@ impl File {
// Linux kernel then the flag is just ignored by the OS, so we continue
// to explicitly ask for a CLOEXEC fd here.
//
- // The CLOEXEC flag, however, is supported on versions of OSX/BSD/etc
+ // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
// that we support, so we only do this on Linux currently.
if cfg!(target_os = "linux") {
fd.set_cloexec()?;
@@ -323,6 +377,10 @@ impl File {
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
+ #[cfg(target_os = "android")]
+ return ::sys::android::ftruncate64(self.0.raw(), size);
+
+ #[cfg(not(target_os = "android"))]
return cvt_r(|| unsafe {
ftruncate64(self.0.raw(), size as off64_t)
}).map(|_| ());
@@ -332,10 +390,6 @@ impl File {
self.0.read(buf)
}
- pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.0.read_to_end(buf)
- }
-
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.0.read_at(buf, offset)
}
@@ -358,6 +412,8 @@ impl File {
SeekFrom::End(off) => (libc::SEEK_END, off),
SeekFrom::Current(off) => (libc::SEEK_CUR, off),
};
+ #[cfg(target_os = "emscripten")]
+ let pos = pos as i32;
let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?;
Ok(n as u64)
}
@@ -404,11 +460,52 @@ impl FromInner<c_int> for File {
impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ #[cfg(target_os = "linux")]
+ fn get_path(fd: c_int) -> Option<PathBuf> {
+ let mut p = PathBuf::from("/proc/self/fd");
+ p.push(&fd.to_string());
+ readlink(&p).ok()
+ }
+
+ #[cfg(target_os = "macos")]
+ fn get_path(fd: c_int) -> Option<PathBuf> {
+ // FIXME: The use of PATH_MAX is generally not encouraged, but it
+ // is inevitable in this case because macOS defines `fcntl` with
+ // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
+ // alternatives. If a better method is invented, it should be used
+ // instead.
+ 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);
+ buf.shrink_to_fit();
+ 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(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 {
+ return None;
+ }
+ match mode & libc::O_ACCMODE {
+ libc::O_RDONLY => Some((true, false)),
+ libc::O_RDWR => Some((true, true)),
+ libc::O_WRONLY => Some((false, true)),
+ _ => None
+ }
+ }
+
+ #[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
diff --git a/ctr-std/src/sys/unix/io.rs b/ctr-std/src/sys/unix/io.rs
deleted file mode 100644
index 6d38b00..0000000
--- a/ctr-std/src/sys/unix/io.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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 io;
-use libc;
-use sys::fd::FileDesc;
-
-pub struct Stdin(());
-pub struct Stdout(());
-pub struct Stderr(());
-
-impl Stdin {
- pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
-
- pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDIN_FILENO);
- let ret = fd.read(data);
- fd.into_raw();
- ret
- }
-
- pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDIN_FILENO);
- let ret = fd.read_to_end(buf);
- fd.into_raw();
- ret
- }
-}
-
-impl Stdout {
- pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
-
- pub fn write(&self, data: &[u8]) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDOUT_FILENO);
- let ret = fd.write(data);
- fd.into_raw();
- ret
- }
-
- pub fn flush(&self) -> io::Result<()> {
- Ok(())
- }
-}
-
-impl Stderr {
- pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
-
- pub fn write(&self, data: &[u8]) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDERR_FILENO);
- let ret = fd.write(data);
- fd.into_raw();
- ret
- }
-
- pub fn flush(&self) -> io::Result<()> {
- Ok(())
- }
-}
-
-// FIXME: right now this raw stderr handle is used in a few places because
-// std::io::stderr_raw isn't exposed, but once that's exposed this impl
-// should go away
-impl io::Write for Stderr {
- fn write(&mut self, data: &[u8]) -> io::Result<usize> {
- Stderr::write(self, data)
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Stderr::flush(self)
- }
-}
-
-pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
-pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
diff --git a/ctr-std/src/sys/unix/memchr.rs b/ctr-std/src/sys/unix/memchr.rs
index ae8e3d0..71d9111 100644
--- a/ctr-std/src/sys/unix/memchr.rs
+++ b/ctr-std/src/sys/unix/memchr.rs
@@ -1,3 +1,13 @@
+// Copyright 2017 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.
+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
@@ -28,10 +38,8 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
}
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
- // turns out that newlib doesn't have memrchr(), so we
- // use the fallback version instead
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
- ::sys_common::memchr::fallback::memrchr(needle, haystack)
+ ::core::slice::memchr::memrchr(needle, haystack)
}
memrchr_specific(needle, haystack)
diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs
index c0e4eb4..11be366 100644
--- a/ctr-std/src/sys/unix/mod.rs
+++ b/ctr-std/src/sys/unix/mod.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -8,46 +8,53 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(missing_docs, bad_style)]
+//! System bindings for the Nintendo 3DS
use io::{self, ErrorKind};
use libc;
+#[cfg(any(dox, target_os = "linux", target_os = "horizon"))] pub use os::linux as platform;
+
pub use self::rand::hashmap_random_keys;
+pub use libc::strlen;
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod cmath;
pub mod condvar;
+pub mod env;
pub mod ext;
pub mod fast_thread_local;
pub mod fd;
pub mod fs;
-pub mod stdio;
pub mod memchr;
pub mod mutex;
+pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rand;
pub mod rwlock;
+pub mod stack_overflow;
pub mod thread;
-pub mod rand;
pub mod thread_local;
pub mod time;
+pub mod stdio;
#[cfg(not(test))]
pub fn init() {
- // By default, some platforms will send a *signal* when an EPIPE error
- // would otherwise be delivered. This runtime doesn't install a SIGPIPE
- // handler, causing it to kill the program, which isn't exactly what we
- // want!
- //
- // Hence, we set SIGPIPE to ignore when the program starts up in order
- // to prevent this problem.
- unsafe {
- reset_sigpipe();
- }
+}
- // I don't think we have signal handling on the 3DS, so let's leave this
- // blank for now
- unsafe fn reset_sigpipe() {}
+pub fn unsupported<T>() -> io::Result<T> {
+ Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> io::Error {
+ io::Error::new(io::ErrorKind::Other,
+ "operation not supported on 3DS yet")
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
@@ -76,6 +83,11 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
}
}
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
@@ -111,6 +123,13 @@ pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
}
}
+// On Unix-like platforms, libc::abort will unregister signal handlers
+// including the SIGABRT handler, preventing the abort from being blocked, and
+// fclose streams, with the side effect of flushing them so libc bufferred
+// output will be printed. Additionally the shell will generally print a more
+// understandable error message like "Abort trap" rather than "Illegal
+// instruction" that intrinsics::abort would cause, as intrinsics::abort is
+// implemented as an illegal instruction.
pub unsafe fn abort_internal() -> ! {
::libc::abort()
}
diff --git a/ctr-std/src/sys/unix/mutex.rs b/ctr-std/src/sys/unix/mutex.rs
index 0cfd392..51e6b47 100644
--- a/ctr-std/src/sys/unix/mutex.rs
+++ b/ctr-std/src/sys/unix/mutex.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -11,7 +11,9 @@
use cell::UnsafeCell;
use mem;
-pub struct Mutex { inner: UnsafeCell<::libctru::LightLock> }
+pub struct Mutex {
+ inner: UnsafeCell<::libctru::LightLock>,
+}
#[inline]
pub unsafe fn raw(m: &Mutex) -> *mut ::libctru::LightLock {
@@ -21,23 +23,26 @@ pub unsafe fn raw(m: &Mutex) -> *mut ::libctru::LightLock {
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
-#[allow(dead_code)] // sys isn't exported yet
impl Mutex {
pub const fn new() -> Mutex {
Mutex { inner: UnsafeCell::new(0) }
}
+
#[inline]
pub unsafe fn init(&mut self) {
::libctru::LightLock_Init(self.inner.get());
}
+
#[inline]
pub unsafe fn lock(&self) {
::libctru::LightLock_Lock(self.inner.get());
}
+
#[inline]
pub unsafe fn unlock(&self) {
::libctru::LightLock_Unlock(self.inner.get());
}
+
#[inline]
pub unsafe fn try_lock(&self) -> bool {
match ::libctru::LightLock_TryLock(self.inner.get()) {
@@ -45,8 +50,10 @@ impl Mutex {
_ => false,
}
}
+
#[inline]
- pub unsafe fn destroy(&self) {}
+ pub unsafe fn destroy(&self) {
+ }
}
pub struct ReentrantMutex { inner: UnsafeCell<::libctru::RecursiveLock> }
@@ -58,18 +65,15 @@ impl ReentrantMutex {
pub unsafe fn uninitialized() -> ReentrantMutex {
ReentrantMutex { inner: mem::uninitialized() }
}
- #[inline]
+
pub unsafe fn init(&mut self) {
::libctru::RecursiveLock_Init(self.inner.get());
}
- #[inline]
+
pub unsafe fn lock(&self) {
::libctru::RecursiveLock_Lock(self.inner.get());
}
- #[inline]
- pub unsafe fn unlock(&self) {
- ::libctru::RecursiveLock_Unlock(self.inner.get());
- }
+
#[inline]
pub unsafe fn try_lock(&self) -> bool {
match ::libctru::RecursiveLock_TryLock(self.inner.get()) {
@@ -77,6 +81,10 @@ impl ReentrantMutex {
_ => false,
}
}
- #[inline]
+
+ pub unsafe fn unlock(&self) {
+ ::libctru::RecursiveLock_Unlock(self.inner.get());
+ }
+
pub unsafe fn destroy(&self) {}
}
diff --git a/ctr-std/src/sys/unix/net.rs b/ctr-std/src/sys/unix/net.rs
new file mode 100644
index 0000000..b9b1a39
--- /dev/null
+++ b/ctr-std/src/sys/unix/net.rs
@@ -0,0 +1,418 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![allow(dead_code)]
+
+use ffi::CStr;
+use io;
+use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_NONAME as 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, sockaddr_to_addr};
+use time::{Duration, Instant};
+use cmp;
+
+pub use sys::{cvt, cvt_r};
+pub extern crate libc as netc;
+
+#[allow(non_camel_case_types)]
+pub type wrlen_t = size_t;
+
+// See below for the usage of SOCK_CLOEXEC, but this constant is only defined on
+// Linux currently (e.g. support doesn't exist on other platforms). In order to
+// get name resolution to work and things to compile we just define a dummy
+// SOCK_CLOEXEC here for other platforms. Note that the dummy constant isn't
+// actually ever used (the blocks below are wrapped in `if cfg!` as well.
+#[cfg(target_os = "linux")]
+use libc::SOCK_CLOEXEC;
+#[cfg(not(target_os = "linux"))]
+const SOCK_CLOEXEC: c_int = 0;
+
+// Another conditional contant for name resolution: Macos et iOS use
+// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
+// Other platforms do otherwise.
+#[cfg(target_vendor = "apple")]
+use libc::SO_NOSIGPIPE;
+#[cfg(not(target_vendor = "apple"))]
+const SO_NOSIGPIPE: c_int = 0;
+
+pub struct Socket(FileDesc);
+
+pub fn init() {}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+ if err == 0 {
+ return Ok(())
+ }
+ if err == EAI_SYSTEM {
+ return Err(io::Error::last_os_error())
+ }
+
+ let detail = unsafe {
+ str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap()
+ .to_owned()
+ };
+ Err(io::Error::new(io::ErrorKind::Other,
+ &format!("failed to lookup address information: {}",
+ detail)[..]))
+}
+
+impl Socket {
+ pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+ let fam = match *addr {
+ SocketAddr::V4(..) => libc::AF_INET,
+ SocketAddr::V6(..) => libc::AF_INET6,
+ };
+ Socket::new_raw(fam, ty)
+ }
+
+ pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
+ unsafe {
+ // On linux we first attempt to pass the SOCK_CLOEXEC flag to
+ // atomically create the socket and set it as CLOEXEC. Support for
+ // this option, however, was added in 2.6.27, and we still support
+ // 2.6.18 as a kernel, so if the returned error is EINVAL we
+ // fallthrough to the fallback.
+ if cfg!(target_os = "linux") {
+ match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
+ Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ let fd = cvt(libc::socket(fam, ty, 0))?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ let socket = Socket(fd);
+ if cfg!(target_vendor = "apple") {
+ setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?;
+ }
+ Ok(socket)
+ }
+ }
+
+ pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
+ unsafe {
+ let mut fds = [0, 0];
+
+ // Like above, see if we can set cloexec atomically
+ if cfg!(target_os = "linux") {
+ match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
+ Ok(_) => {
+ return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
+ }
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {},
+ Err(e) => return Err(e),
+ }
+ }
+
+ cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
+ let a = FileDesc::new(fds[0]);
+ let b = FileDesc::new(fds[1]);
+ a.set_cloexec()?;
+ b.set_cloexec()?;
+ Ok((Socket(a), Socket(b)))
+ }
+ }
+
+ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+ self.set_nonblocking(true)?;
+ let r = unsafe {
+ let (addrp, len) = addr.into_inner();
+ cvt(libc::connect(self.0.raw(), addrp, len))
+ };
+ self.set_nonblocking(false)?;
+
+ match r {
+ Ok(_) => return Ok(()),
+ // there's no ErrorKind for EINPROGRESS :(
+ Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
+ Err(e) => return Err(e),
+ }
+
+ let mut pollfd = libc::pollfd {
+ fd: self.0.raw(),
+ events: libc::POLLOUT,
+ revents: 0,
+ };
+
+ if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+
+ let start = Instant::now();
+
+ loop {
+ let elapsed = start.elapsed();
+ if elapsed >= timeout {
+ return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out"));
+ }
+
+ let timeout = timeout - elapsed;
+ let mut timeout = timeout.as_secs()
+ .saturating_mul(1_000)
+ .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
+ if timeout == 0 {
+ timeout = 1;
+ }
+
+ let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int;
+
+ match unsafe { libc::poll(&mut pollfd, 1, timeout) } {
+ -1 => {
+ let err = io::Error::last_os_error();
+ if err.kind() != io::ErrorKind::Interrupted {
+ return Err(err);
+ }
+ }
+ 0 => {}
+ _ => {
+ // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+ // for POLLHUP rather than read readiness
+ if pollfd.revents & libc::POLLHUP != 0 {
+ let e = self.take_error()?
+ .unwrap_or_else(|| {
+ io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
+ });
+ return Err(e);
+ }
+
+ return Ok(());
+ }
+ }
+ }
+ }
+
+ pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
+ -> io::Result<Socket> {
+ let fd = cvt_r(|| unsafe {
+ libc::accept(self.0.raw(), storage, len)
+ })?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ Ok(Socket(fd))
+ }
+
+ pub fn duplicate(&self) -> io::Result<Socket> {
+ self.0.duplicate().map(Socket)
+ }
+
+ fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+ 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<usize> {
+ self.recv_with_flags(buf, 0)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ 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 write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
+ let timeout = match dur {
+ Some(dur) => {
+ if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+
+ let secs = if dur.as_secs() > libc::time_t::max_value() as u64 {
+ libc::time_t::max_value()
+ } else {
+ dur.as_secs() as libc::time_t
+ };
+ let mut timeout = libc::timeval {
+ tv_sec: secs,
+ tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t,
+ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+ timeout
+ }
+ None => {
+ libc::timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ }
+ }
+ };
+ setsockopt(self, libc::SOL_SOCKET, kind, timeout)
+ }
+
+ pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
+ let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?;
+ if raw.tv_sec == 0 && raw.tv_usec == 0 {
+ Ok(None)
+ } else {
+ let sec = raw.tv_sec as u64;
+ let nsec = (raw.tv_usec as u32) * 1000;
+ Ok(Some(Duration::new(sec, nsec)))
+ }
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ let how = match how {
+ Shutdown::Write => libc::SHUT_WR,
+ Shutdown::Read => libc::SHUT_RD,
+ Shutdown::Both => libc::SHUT_RDWR,
+ };
+ cvt(unsafe { libc::shutdown(self.0.raw(), how) })?;
+ Ok(())
+ }
+
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int)
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?;
+ Ok(raw != 0)
+ }
+
+ // TODO: Fix libc::FIONBIO and remove explicit cast
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ let mut nonblocking = nonblocking as libc::c_int;
+ cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO as u32, &mut nonblocking) }).map(|_| ())
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
+ if raw == 0 {
+ Ok(None)
+ } else {
+ Ok(Some(io::Error::from_raw_os_error(raw as i32)))
+ }
+ }
+}
+
+impl AsInner<c_int> for Socket {
+ fn as_inner(&self) -> &c_int { self.0.as_inner() }
+}
+
+impl FromInner<c_int> for Socket {
+ fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) }
+}
+
+impl IntoInner<c_int> for Socket {
+ fn into_inner(self) -> c_int { self.0.into_raw() }
+}
+
+// In versions of glibc prior to 2.26, there's a bug where the DNS resolver
+// will cache the contents of /etc/resolv.conf, so changes to that file on disk
+// can be ignored by a long-running program. That can break DNS lookups on e.g.
+// laptops where the network comes and goes. See
+// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some
+// distros including Debian have patched glibc to fix this for a long time.
+//
+// A workaround for this bug is to call the res_init libc function, to clear
+// the cached configs. Unfortunately, while we believe glibc's implementation
+// of res_init is thread-safe, we know that other implementations are not
+// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could
+// try to synchronize its res_init calls with a Mutex, but that wouldn't
+// protect programs that call into libc in other ways. So instead of calling
+// res_init unconditionally, we call it only when we detect we're linking
+// against glibc version < 2.26. (That is, when we both know its needed and
+// believe it's thread-safe).
+pub fn res_init_if_glibc_before_2_26() -> io::Result<()> {
+ // If the version fails to parse, we treat it the same as "not glibc".
+ if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
+ if let Some(version) = parse_glibc_version(version_str) {
+ if version < (2, 26) {
+ let ret = unsafe { libc::res_init() };
+ if ret != 0 {
+ return Err(io::Error::last_os_error());
+ }
+ }
+ }
+ }
+ Ok(())
+}
+
+fn glibc_version_cstr() -> Option<&'static CStr> {
+ None
+}
+
+// Returns Some((major, minor)) if the string is a valid "x.y" version,
+// ignoring any extra dot-separated parts. Otherwise return None.
+fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
+ let mut parsed_ints = version.split(".").map(str::parse::<usize>).fuse();
+ match (parsed_ints.next(), parsed_ints.next()) {
+ (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)),
+ _ => None
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_res_init() {
+ // This mostly just tests that the weak linkage doesn't panic wildly...
+ res_init_if_glibc_before_2_26().unwrap();
+ }
+
+ #[test]
+ fn test_parse_glibc_version() {
+ let cases = [
+ ("0.0", Some((0, 0))),
+ ("01.+2", Some((1, 2))),
+ ("3.4.5.six", Some((3, 4))),
+ ("1", None),
+ ("1.-2", None),
+ ("1.foo", None),
+ ("foo.1", None),
+ ];
+ for &(version_str, parsed) in cases.iter() {
+ assert_eq!(parsed, parse_glibc_version(version_str));
+ }
+ }
+}
diff --git a/ctr-std/src/sys/unix/os.rs b/ctr-std/src/sys/unix/os.rs
index de087d9..5de756d 100644
--- a/ctr-std/src/sys/unix/os.rs
+++ b/ctr-std/src/sys/unix/os.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -8,26 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Implementation of `std::os` functionality for unix systems
-
-#![allow(unused_imports)] // lots of cfg code here
-
-use os::unix::prelude::*;
-
use error::Error as StdError;
use ffi::{CString, CStr, OsString, OsStr};
use fmt;
use io;
use iter;
-use libc::{self, c_int, c_char, c_void};
-use marker::PhantomData;
-use mem;
-use memchr;
+use libc::{self, c_int, c_char};
use path::{self, PathBuf};
-use ptr;
use slice;
use str;
-use vec;
+use sys::{unsupported, Void};
+use sys::unix::ext::ffi::{OsStrExt, OsStringExt};
const TMPBUF_SZ: usize = 128;
@@ -64,6 +55,42 @@ pub fn error_string(errno: i32) -> String {
}
}
+pub fn getcwd() -> io::Result<PathBuf> {
+ let mut buf = Vec::with_capacity(512);
+ loop {
+ unsafe {
+ let ptr = buf.as_mut_ptr() as *mut libc::c_char;
+ if !libc::getcwd(ptr, buf.capacity()).is_null() {
+ let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
+ buf.set_len(len);
+ buf.shrink_to_fit();
+ return Ok(PathBuf::from(OsString::from_vec(buf)));
+ } else {
+ let error = io::Error::last_os_error();
+ if error.raw_os_error() != Some(libc::ERANGE) {
+ return Err(error);
+ }
+ }
+
+ // Trigger the internal buffer resizing logic of `Vec` by requiring
+ // more space than the current capacity.
+ let cap = buf.capacity();
+ buf.set_len(cap);
+ buf.reserve(1);
+ }
+ }
+}
+
+pub fn chdir(p: &path::Path) -> io::Result<()> {
+ let p: &OsStr = p.as_ref();
+ let p = CString::new(p.as_bytes())?;
+ unsafe {
+ match libc::chdir(p.as_ptr()) == (0 as c_int) {
+ true => Ok(()),
+ false => Err(io::Error::last_os_error()),
+ }
+ }
+}
pub struct SplitPaths<'a> {
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
@@ -118,6 +145,47 @@ impl StdError for JoinPathsError {
fn description(&self) -> &str { "failed to join paths" }
}
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub struct Env(Void);
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> {
+ match self.0 {}
+ }
+}
+
+pub fn env() -> Env {
+ panic!("not supported on 3DS yet")
+}
+
+pub fn getenv(_k: &OsStr) -> io::Result<Option<OsString>> {
+ return Ok(None)
+}
+
+pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn unsetenv(_n: &OsStr) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn temp_dir() -> PathBuf {
+ PathBuf::from("/tmp")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
pub fn exit(code: i32) -> ! {
unsafe { libc::exit(code as c_int) }
}
+
+pub fn getpid() -> u32 {
+ panic!("no pids on 3DS")
+}
diff --git a/ctr-std/src/sys/unix/os_str.rs b/ctr-std/src/sys/unix/os_str.rs
index 5a733c0..543c22e 100644
--- a/ctr-std/src/sys/unix/os_str.rs
+++ b/ctr-std/src/sys/unix/os_str.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -12,10 +12,14 @@
/// a `Vec<u8>`/`[u8]`.
use borrow::Cow;
-use fmt::{self, Debug};
+use fmt;
use str;
use mem;
+use rc::Rc;
+use sync::Arc;
use sys_common::{AsInner, IntoInner};
+use sys_common::bytestring::debug_fmt_bytestring;
+use std_unicode::lossy::Utf8Lossy;
#[derive(Clone, Hash)]
pub struct Buf {
@@ -26,15 +30,27 @@ pub struct Slice {
pub inner: [u8]
}
-impl Debug for Slice {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- self.to_string_lossy().fmt(formatter)
+impl fmt::Debug for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ debug_fmt_bytestring(&self.inner, formatter)
}
}
-impl Debug for Buf {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- self.as_slice().fmt(formatter)
+impl fmt::Display for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
+ }
+}
+
+impl fmt::Debug for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self.as_slice(), formatter)
+ }
+}
+
+impl fmt::Display for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self.as_slice(), formatter)
}
}
@@ -83,6 +99,11 @@ impl Buf {
self.inner.reserve_exact(additional)
}
+ #[inline]
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
pub fn as_slice(&self) -> &Slice {
unsafe { mem::transmute(&*self.inner) }
}
@@ -94,6 +115,27 @@ impl Buf {
pub fn push_slice(&mut self, s: &Slice) {
self.inner.extend_from_slice(&s.inner)
}
+
+ #[inline]
+ pub fn into_box(self) -> Box<Slice> {
+ unsafe { mem::transmute(self.inner.into_boxed_slice()) }
+ }
+
+ #[inline]
+ pub fn from_box(boxed: Box<Slice>) -> Buf {
+ let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
+ Buf { inner: inner.into_vec() }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ self.as_slice().into_arc()
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ self.as_slice().into_rc()
+ }
}
impl Slice {
@@ -116,4 +158,27 @@ impl Slice {
pub fn to_owned(&self) -> Buf {
Buf { inner: self.inner.to_vec() }
}
+
+ #[inline]
+ pub fn into_box(&self) -> Box<Slice> {
+ let boxed: Box<[u8]> = self.inner.into();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ pub fn empty_box() -> Box<Slice> {
+ let boxed: Box<[u8]> = Default::default();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ let arc: Arc<[u8]> = Arc::from(&self.inner);
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ let rc: Rc<[u8]> = Rc::from(&self.inner);
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
+ }
}
diff --git a/ctr-std/src/sys/unix/path.rs b/ctr-std/src/sys/unix/path.rs
index bf9af7a..395b8c1 100644
--- a/ctr-std/src/sys/unix/path.rs
+++ b/ctr-std/src/sys/unix/path.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
diff --git a/ctr-std/src/sys/unix/pipe.rs b/ctr-std/src/sys/unix/pipe.rs
new file mode 100644
index 0000000..992e1ac
--- /dev/null
+++ b/ctr-std/src/sys/unix/pipe.rs
@@ -0,0 +1,35 @@
+// Copyright 2017 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 io;
+use sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+pub fn read2(p1: AnonPipe,
+ _v1: &mut Vec<u8>,
+ _p2: AnonPipe,
+ _v2: &mut Vec<u8>) -> io::Result<()> {
+ match p1.0 {}
+}
diff --git a/ctr-std/src/sys/unix/process.rs b/ctr-std/src/sys/unix/process.rs
new file mode 100644
index 0000000..f058aa9
--- /dev/null
+++ b/ctr-std/src/sys/unix/process.rs
@@ -0,0 +1,151 @@
+// Copyright 2017 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 ffi::OsStr;
+use fmt;
+use io;
+use sys::fs::File;
+use sys::pipe::AnonPipe;
+use sys::{unsupported, Void};
+use sys_common::process::{CommandEnv, DefaultEnvKey};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ env: CommandEnv<DefaultEnvKey>
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+}
+
+impl Command {
+ pub fn new(_program: &OsStr) -> Command {
+ Command {
+ env: Default::default()
+ }
+ }
+
+ pub fn arg(&mut self, _arg: &OsStr) {
+ }
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn cwd(&mut self, _dir: &OsStr) {
+ }
+
+ pub fn stdin(&mut self, _stdin: Stdio) {
+ }
+
+ pub fn stdout(&mut self, _stdout: Stdio) {
+ }
+
+ pub fn stderr(&mut self, _stderr: Stdio) {
+ }
+
+ pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ unsupported()
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ pipe.diverge()
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(_file: File) -> Stdio {
+ //file.diverge()
+ unimplemented!()
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ Ok(())
+ }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+ pub fn success(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ match self.0 {}
+ }
+}
+
+impl Clone for ExitStatus {
+ fn clone(&self) -> ExitStatus {
+ match self.0 {}
+ }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+ fn eq(&self, _other: &ExitStatus) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for ExitStatus {
+}
+
+impl fmt::Debug for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct Process(Void);
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ match self.0 {}
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ match self.0 {}
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ match self.0 {}
+ }
+}
diff --git a/ctr-std/src/sys/unix/stack_overflow.rs b/ctr-std/src/sys/unix/stack_overflow.rs
new file mode 100644
index 0000000..bed2741
--- /dev/null
+++ b/ctr-std/src/sys/unix/stack_overflow.rs
@@ -0,0 +1,23 @@
+// Copyright 2017 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.
+
+pub struct Handler;
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ Handler
+ }
+}
+
+pub unsafe fn init() {
+}
+
+pub unsafe fn cleanup() {
+}
diff --git a/ctr-std/src/sys/unix/stdio.rs b/ctr-std/src/sys/unix/stdio.rs
index 6d38b00..e9b3d4a 100644
--- a/ctr-std/src/sys/unix/stdio.rs
+++ b/ctr-std/src/sys/unix/stdio.rs
@@ -25,13 +25,6 @@ impl Stdin {
fd.into_raw();
ret
}
-
- pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDIN_FILENO);
- let ret = fd.read_to_end(buf);
- fd.into_raw();
- ret
- }
}
impl Stdout {
@@ -77,5 +70,8 @@ impl io::Write for Stderr {
}
}
-pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
+pub fn is_ebadf(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(libc::EBADF as i32)
+}
+
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
diff --git a/ctr-std/src/sys/unix/thread.rs b/ctr-std/src/sys/unix/thread.rs
index 0b21bff..21224ad 100644
--- a/ctr-std/src/sys/unix/thread.rs
+++ b/ctr-std/src/sys/unix/thread.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -18,29 +18,28 @@ use ptr;
use sys_common::thread::start_thread;
use time::Duration;
-use libctru::{svcSleepThread, svcGetThreadPriority,
- threadCreate, threadJoin, threadFree, threadDetach,
- Thread as ThreadHandle};
+use libctru::Thread as ThreadHandle;
pub struct Thread {
handle: ThreadHandle,
}
-// Some platforms may have pthread_t as a pointer in which case we still want
-// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+
impl Thread {
pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> {
let p = box p;
- let stack_size = cmp::max(stack, 0x10000);
+ let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
let mut priority = 0;
- svcGetThreadPriority(&mut priority, 0xFFFF8000);
+ ::libctru::svcGetThreadPriority(&mut priority, 0xFFFF8000);
- let handle = threadCreate(Some(thread_func), &*p as *const _ as *mut _,
- stack_size, priority, -2, false);
+ let handle = ::libctru::threadCreate(Some(thread_func), &*p as *const _ as *mut _,
+ stack_size, priority, -2, false);
return if handle == ptr::null_mut() {
Err(io::Error::from_raw_os_error(libc::EAGAIN))
@@ -50,12 +49,14 @@ impl Thread {
};
extern "C" fn thread_func(start: *mut libc::c_void) {
- unsafe { start_thread(start) }
+ unsafe { start_thread(start as *mut u8) }
}
}
-
+
pub fn yield_now() {
- unsafe { svcSleepThread(0) }
+ unsafe {
+ ::libctru::svcSleepThread(0)
+ }
}
pub fn set_name(_name: &CStr) {
@@ -64,35 +65,21 @@ impl Thread {
pub fn sleep(dur: Duration) {
unsafe {
- let nanos = dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64;
- svcSleepThread(nanos as i64)
+ let nanos = dur.as_secs()
+ .saturating_mul(1_000_000_000)
+ .saturating_add(dur.subsec_nanos() as u64);
+ ::libctru::svcSleepThread(nanos as i64)
}
}
pub fn join(self) {
unsafe {
- let ret = threadJoin(self.handle, u64::max_value());
- threadFree(self.handle);
+ let ret = ::libctru::threadJoin(self.handle, u64::max_value());
+ ::libctru::threadFree(self.handle);
mem::forget(self);
debug_assert_eq!(ret, 0);
}
}
-
- pub fn id(&self) -> ThreadHandle {
- self.handle
- }
-
- pub fn into_id(self) -> ThreadHandle {
- let handle = self.handle;
- mem::forget(self);
- handle
- }
-}
-
-impl Drop for Thread {
- fn drop(&mut self) {
- unsafe { threadDetach(self.handle) }
- }
}
pub mod guard {
diff --git a/ctr-std/src/sys/unix/thread_local.rs b/ctr-std/src/sys/unix/thread_local.rs
index abdd9ac..3cb3523 100644
--- a/ctr-std/src/sys/unix/thread_local.rs
+++ b/ctr-std/src/sys/unix/thread_local.rs
@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// Borrowed from /sys/redox/thread_local.rs
+
#![allow(dead_code)] // not used on all platforms
use collections::BTreeMap;
@@ -64,3 +66,8 @@ pub unsafe fn set(key: Key, value: *mut u8) {
pub unsafe fn destroy(key: Key) {
keys().remove(&key);
}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
diff --git a/ctr-std/src/sys/unix/time.rs b/ctr-std/src/sys/unix/time.rs
index 3bc1dca..d5dcbc4 100644
--- a/ctr-std/src/sys/unix/time.rs
+++ b/ctr-std/src/sys/unix/time.rs
@@ -11,6 +11,7 @@
use cmp::Ordering;
use libc;
use time::Duration;
+use core::hash::{Hash, Hasher};
pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
@@ -103,6 +104,13 @@ impl Ord for Timespec {
}
}
+impl Hash for Timespec {
+ fn hash<H : Hasher>(&self, state: &mut H) {
+ self.t.tv_sec.hash(state);
+ self.t.tv_nsec.hash(state);
+ }
+}
+
mod inner {
use fmt;
use libc;
@@ -116,12 +124,12 @@ mod inner {
use libctru;
- #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant {
t: u64
}
- #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SystemTime {
t: Timespec,
}
diff --git a/ctr-std/src/sys_common/backtrace.rs b/ctr-std/src/sys_common/backtrace.rs
new file mode 100644
index 0000000..36cbce2
--- /dev/null
+++ b/ctr-std/src/sys_common/backtrace.rs
@@ -0,0 +1,461 @@
+// 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.
+
+/// Common code for printing the backtrace in the same way across the different
+/// supported platforms.
+
+use env;
+use io::prelude::*;
+use io;
+use str;
+use sync::atomic::{self, Ordering};
+use path::{self, Path};
+use sys::mutex::Mutex;
+use ptr;
+
+pub use sys::backtrace::{
+ unwind_backtrace,
+ resolve_symname,
+ foreach_symbol_fileline,
+ BacktraceContext
+};
+
+#[cfg(target_pointer_width = "64")]
+pub const HEX_WIDTH: usize = 18;
+
+#[cfg(target_pointer_width = "32")]
+pub const HEX_WIDTH: usize = 10;
+
+/// Represents an item in the backtrace list. See `unwind_backtrace` for how
+/// it is created.
+#[derive(Debug, Copy, Clone)]
+pub struct Frame {
+ /// Exact address of the call that failed.
+ pub exact_position: *const u8,
+ /// Address of the enclosing function.
+ pub symbol_addr: *const u8,
+}
+
+/// Max number of frames to print.
+const MAX_NB_FRAMES: usize = 100;
+
+/// Prints the current backtrace.
+pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+ static LOCK: Mutex = Mutex::new();
+
+ // Use a lock to prevent mixed output in multithreading context.
+ // Some platforms also requires it, like `SymFromAddr` on Windows.
+ unsafe {
+ LOCK.lock();
+ let res = _print(w, format);
+ LOCK.unlock();
+ res
+ }
+}
+
+fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+ let mut frames = [Frame {
+ exact_position: ptr::null(),
+ symbol_addr: ptr::null(),
+ }; MAX_NB_FRAMES];
+ let (nb_frames, context) = unwind_backtrace(&mut frames)?;
+ let (skipped_before, skipped_after) =
+ filter_frames(&frames[..nb_frames], format, &context);
+ if skipped_before + skipped_after > 0 {
+ writeln!(w, "note: Some details are omitted, \
+ run with `RUST_BACKTRACE=full` for a verbose backtrace.")?;
+ }
+ writeln!(w, "stack backtrace:")?;
+
+ let filtered_frames = &frames[..nb_frames - skipped_after];
+ for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
+ resolve_symname(*frame, |symname| {
+ output(w, index, *frame, symname, format)
+ }, &context)?;
+ let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
+ output_fileline(w, file, line, format)
+ }, &context)?;
+ if has_more_filenames {
+ w.write_all(b" <... and possibly more>")?;
+ }
+ }
+
+ Ok(())
+}
+
+/// Returns a number of frames to remove at the beginning and at the end of the
+/// backtrace, according to the backtrace format.
+fn filter_frames(frames: &[Frame],
+ format: PrintFormat,
+ context: &BacktraceContext) -> (usize, usize)
+{
+ if format == PrintFormat::Full {
+ return (0, 0);
+ }
+
+ let skipped_before = 0;
+
+ let skipped_after = frames.len() - frames.iter().position(|frame| {
+ let mut is_marker = false;
+ let _ = resolve_symname(*frame, |symname| {
+ if let Some(mangled_symbol_name) = symname {
+ // Use grep to find the concerned functions
+ if mangled_symbol_name.contains("__rust_begin_short_backtrace") {
+ is_marker = true;
+ }
+ }
+ Ok(())
+ }, context);
+ is_marker
+ }).unwrap_or(frames.len());
+
+ if skipped_before + skipped_after >= frames.len() {
+ // Avoid showing completely empty backtraces
+ return (0, 0);
+ }
+
+ (skipped_before, skipped_after)
+}
+
+
+/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
+#[inline(never)]
+pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
+ where F: FnOnce() -> T, F: Send, T: Send
+{
+ f()
+}
+
+/// Controls how the backtrace should be formated.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum PrintFormat {
+ /// Show all the frames with absolute path for files.
+ Full = 2,
+ /// Show only relevant data from the backtrace.
+ Short = 3,
+}
+
+// For now logging is turned off by default, and this function checks to see
+// whether the magical environment variable is present to see if it's turned on.
+pub fn log_enabled() -> Option<PrintFormat> {
+ static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
+ match ENABLED.load(Ordering::SeqCst) {
+ 0 => {},
+ 1 => return None,
+ 2 => return Some(PrintFormat::Full),
+ 3 => return Some(PrintFormat::Short),
+ _ => unreachable!(),
+ }
+
+ let val = match env::var_os("RUST_BACKTRACE") {
+ Some(x) => if &x == "0" {
+ None
+ } else if &x == "full" {
+ Some(PrintFormat::Full)
+ } else {
+ Some(PrintFormat::Short)
+ },
+ None => None,
+ };
+ ENABLED.store(match val {
+ Some(v) => v as isize,
+ None => 1,
+ }, Ordering::SeqCst);
+ val
+}
+
+/// Print the symbol of the backtrace frame.
+///
+/// These output functions should now be used everywhere to ensure consistency.
+/// You may want to also use `output_fileline`.
+fn output(w: &mut Write, idx: usize, frame: Frame,
+ s: Option<&str>, format: PrintFormat) -> io::Result<()> {
+ // Remove the `17: 0x0 - <unknown>` line.
+ if format == PrintFormat::Short && frame.exact_position == ptr::null() {
+ return Ok(());
+ }
+ match format {
+ PrintFormat::Full => write!(w,
+ " {:2}: {:2$?} - ",
+ idx,
+ frame.exact_position,
+ HEX_WIDTH)?,
+ PrintFormat::Short => write!(w, " {:2}: ", idx)?,
+ }
+ match s {
+ Some(string) => demangle(w, string, format)?,
+ None => w.write_all(b"<unknown>")?,
+ }
+ w.write_all(b"\n")
+}
+
+/// Print the filename and line number of the backtrace frame.
+///
+/// See also `output`.
+#[allow(dead_code)]
+fn output_fileline(w: &mut Write,
+ file: &[u8],
+ line: u32,
+ format: PrintFormat) -> io::Result<()> {
+ // prior line: " ##: {:2$} - func"
+ w.write_all(b"")?;
+ match format {
+ PrintFormat::Full => write!(w,
+ " {:1$}",
+ "",
+ HEX_WIDTH)?,
+ PrintFormat::Short => write!(w, " ")?,
+ }
+
+ let file = str::from_utf8(file).unwrap_or("<unknown>");
+ let file_path = Path::new(file);
+ let mut already_printed = false;
+ if format == PrintFormat::Short && file_path.is_absolute() {
+ if let Ok(cwd) = env::current_dir() {
+ if let Ok(stripped) = file_path.strip_prefix(&cwd) {
+ if let Some(s) = stripped.to_str() {
+ write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?;
+ already_printed = true;
+ }
+ }
+ }
+ }
+ if !already_printed {
+ write!(w, " at {}:{}", file, line)?;
+ }
+
+ w.write_all(b"\n")
+}
+
+
+// All rust symbols are in theory lists of "::"-separated identifiers. Some
+// assemblers, however, can't handle these characters in symbol names. To get
+// around this, we use C++-style mangling. The mangling method is:
+//
+// 1. Prefix the symbol with "_ZN"
+// 2. For each element of the path, emit the length plus the element
+// 3. End the path with "E"
+//
+// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar".
+//
+// We're the ones printing our backtraces, so we can't rely on anything else to
+// demangle our symbols. It's *much* nicer to look at demangled symbols, so
+// this function is implemented to give us nice pretty output.
+//
+// Note that this demangler isn't quite as fancy as it could be. We have lots
+// of other information in our symbols like hashes, version, type information,
+// etc. Additionally, this doesn't handle glue symbols at all.
+pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Result<()> {
+ // During ThinLTO LLVM may import and rename internal symbols, so strip out
+ // those endings first as they're one of the last manglings applied to
+ // symbol names.
+ let llvm = ".llvm.";
+ if let Some(i) = s.find(llvm) {
+ let candidate = &s[i + llvm.len()..];
+ let all_hex = candidate.chars().all(|c| {
+ match c {
+ 'A' ... 'F' | '0' ... '9' => true,
+ _ => false,
+ }
+ });
+
+ if all_hex {
+ s = &s[..i];
+ }
+ }
+
+ // Validate the symbol. If it doesn't look like anything we're
+ // expecting, we just print it literally. Note that we must handle non-rust
+ // symbols because we could have any function in the backtrace.
+ let mut valid = true;
+ let mut inner = s;
+ if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
+ inner = &s[3 .. s.len() - 1];
+ // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too.
+ } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") {
+ inner = &s[2 .. s.len() - 1];
+ } else {
+ valid = false;
+ }
+
+ if valid {
+ let mut chars = inner.chars();
+ while valid {
+ let mut i = 0;
+ for c in chars.by_ref() {
+ if c.is_numeric() {
+ i = i * 10 + c as usize - '0' as usize;
+ } else {
+ break
+ }
+ }
+ if i == 0 {
+ valid = chars.next().is_none();
+ break
+ } else if chars.by_ref().take(i - 1).count() != i - 1 {
+ valid = false;
+ }
+ }
+ }
+
+ // Alright, let's do this.
+ if !valid {
+ writer.write_all(s.as_bytes())?;
+ } else {
+ // remove the `::hfc2edb670e5eda97` part at the end of the symbol.
+ if format == PrintFormat::Short {
+ // The symbol in still mangled.
+ let mut split = inner.rsplitn(2, "17h");
+ match (split.next(), split.next()) {
+ (Some(addr), rest) => {
+ if addr.len() == 16 &&
+ addr.chars().all(|c| c.is_digit(16))
+ {
+ inner = rest.unwrap_or("");
+ }
+ }
+ _ => (),
+ }
+ }
+
+ let mut first = true;
+ while !inner.is_empty() {
+ if !first {
+ writer.write_all(b"::")?;
+ } else {
+ first = false;
+ }
+ let mut rest = inner;
+ while rest.chars().next().unwrap().is_numeric() {
+ rest = &rest[1..];
+ }
+ let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap();
+ inner = &rest[i..];
+ rest = &rest[..i];
+ if rest.starts_with("_$") {
+ rest = &rest[1..];
+ }
+ while !rest.is_empty() {
+ if rest.starts_with(".") {
+ if let Some('.') = rest[1..].chars().next() {
+ writer.write_all(b"::")?;
+ rest = &rest[2..];
+ } else {
+ writer.write_all(b".")?;
+ rest = &rest[1..];
+ }
+ } else if rest.starts_with("$") {
+ macro_rules! demangle {
+ ($($pat:expr => $demangled:expr),*) => ({
+ $(if rest.starts_with($pat) {
+ writer.write_all($demangled)?;
+ rest = &rest[$pat.len()..];
+ } else)*
+ {
+ writer.write_all(rest.as_bytes())?;
+ break;
+ }
+
+ })
+ }
+
+ // see src/librustc/back/link.rs for these mappings
+ demangle! (
+ "$SP$" => b"@",
+ "$BP$" => b"*",
+ "$RF$" => b"&",
+ "$LT$" => b"<",
+ "$GT$" => b">",
+ "$LP$" => b"(",
+ "$RP$" => b")",
+ "$C$" => b",",
+
+ // in theory we can demangle any Unicode code point, but
+ // for simplicity we just catch the common ones.
+ "$u7e$" => b"~",
+ "$u20$" => b" ",
+ "$u27$" => b"'",
+ "$u5b$" => b"[",
+ "$u5d$" => b"]",
+ "$u7b$" => b"{",
+ "$u7d$" => b"}",
+ "$u3b$" => b";",
+ "$u2b$" => b"+",
+ "$u22$" => b"\""
+ )
+ } else {
+ let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') {
+ None => rest.len(),
+ Some((i, _)) => i,
+ };
+ writer.write_all(rest[..idx].as_bytes())?;
+ rest = &rest[idx..];
+ }
+ }
+ }
+ }
+
+ Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+ use sys_common;
+ macro_rules! t { ($a:expr, $b:expr) => ({
+ let mut m = Vec::new();
+ sys_common::backtrace::demangle(&mut m,
+ $a,
+ super::PrintFormat::Full).unwrap();
+ assert_eq!(String::from_utf8(m).unwrap(), $b);
+ }) }
+
+ #[test]
+ fn demangle() {
+ t!("test", "test");
+ t!("_ZN4testE", "test");
+ t!("_ZN4test", "_ZN4test");
+ t!("_ZN4test1a2bcE", "test::a::bc");
+ }
+
+ #[test]
+ fn demangle_dollars() {
+ t!("_ZN4$RP$E", ")");
+ t!("_ZN8$RF$testE", "&test");
+ t!("_ZN8$BP$test4foobE", "*test::foob");
+ t!("_ZN9$u20$test4foobE", " test::foob");
+ t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>");
+ }
+
+ #[test]
+ fn demangle_many_dollars() {
+ t!("_ZN13test$u20$test4foobE", "test test::foob");
+ t!("_ZN12test$BP$test4foobE", "test*test::foob");
+ }
+
+ #[test]
+ fn demangle_windows() {
+ t!("ZN4testE", "test");
+ t!("ZN13test$u20$test4foobE", "test test::foob");
+ t!("ZN12test$RF$test4foobE", "test&test::foob");
+ }
+
+ #[test]
+ fn demangle_elements_beginning_with_underscore() {
+ t!("_ZN13_$LT$test$GT$E", "<test>");
+ t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}");
+ t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR");
+ }
+
+ #[test]
+ fn demangle_trait_impls() {
+ t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE",
+ "<Test + 'static as foo::Bar<Test>>::bar");
+ }
+}
diff --git a/ctr-std/src/sys_common/bytestring.rs b/ctr-std/src/sys_common/bytestring.rs
new file mode 100644
index 0000000..eb9cad0
--- /dev/null
+++ b/ctr-std/src/sys_common/bytestring.rs
@@ -0,0 +1,56 @@
+// 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.
+
+#![allow(dead_code)]
+
+use fmt::{Formatter, Result, Write};
+use std_unicode::lossy::{Utf8Lossy, Utf8LossyChunk};
+
+pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result {
+ // Writes out a valid unicode string with the correct escape sequences
+ fn write_str_escaped(f: &mut Formatter, s: &str) -> Result {
+ for c in s.chars().flat_map(|c| c.escape_debug()) {
+ f.write_char(c)?
+ }
+ Ok(())
+ }
+
+ f.write_str("\"")?;
+ for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(slice).chunks() {
+ write_str_escaped(f, valid)?;
+ for b in broken {
+ write!(f, "\\x{:02X}", b)?;
+ }
+ }
+ f.write_str("\"")
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use fmt::{Formatter, Result, Debug};
+
+ #[test]
+ fn smoke() {
+ struct Helper<'a>(&'a [u8]);
+
+ impl<'a> Debug for Helper<'a> {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ debug_fmt_bytestring(self.0, f)
+ }
+ }
+
+ let input = b"\xF0hello,\tworld";
+ let expected = r#""\xF0hello,\tworld""#;
+ let output = format!("{:?}", Helper(input));
+
+ assert!(output == expected);
+ }
+}
diff --git a/ctr-std/src/sys_common/gnu/libbacktrace.rs b/ctr-std/src/sys_common/gnu/libbacktrace.rs
new file mode 100644
index 0000000..6ad3af6
--- /dev/null
+++ b/ctr-std/src/sys_common/gnu/libbacktrace.rs
@@ -0,0 +1,216 @@
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 libc;
+
+use ffi::CStr;
+use io;
+use mem;
+use ptr;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+
+pub fn foreach_symbol_fileline<F>(frame: Frame,
+ mut f: F,
+ _: &BacktraceContext) -> io::Result<bool>
+where F: FnMut(&[u8], u32) -> io::Result<()>
+{
+ // pcinfo may return an arbitrary number of file:line pairs,
+ // in the order of stack trace (i.e. inlined calls first).
+ // in order to avoid allocation, we stack-allocate a fixed size of entries.
+ const FILELINE_SIZE: usize = 32;
+ let mut fileline_buf = [(ptr::null(), !0); FILELINE_SIZE];
+ let ret;
+ let fileline_count = {
+ let state = unsafe { init_state() };
+ if state.is_null() {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "failed to allocate libbacktrace state")
+ )
+ }
+ let mut fileline_win: &mut [FileLine] = &mut fileline_buf;
+ let fileline_addr = &mut fileline_win as *mut &mut [FileLine];
+ ret = unsafe {
+ backtrace_pcinfo(state,
+ frame.exact_position as libc::uintptr_t,
+ pcinfo_cb,
+ error_cb,
+ fileline_addr as *mut libc::c_void)
+ };
+ FILELINE_SIZE - fileline_win.len()
+ };
+ if ret == 0 {
+ for &(file, line) in &fileline_buf[..fileline_count] {
+ if file.is_null() { continue; } // just to be sure
+ let file = unsafe { CStr::from_ptr(file).to_bytes() };
+ f(file, line)?;
+ }
+ Ok(fileline_count == FILELINE_SIZE)
+ } else {
+ Ok(false)
+ }
+}
+
+/// Converts a pointer to symbol to its string value.
+pub fn resolve_symname<F>(frame: Frame,
+ callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ let symname = {
+ let state = unsafe { init_state() };
+ if state.is_null() {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "failed to allocate libbacktrace state")
+ )
+ }
+ let mut data: *const libc::c_char = ptr::null();
+ let data_addr = &mut data as *mut *const libc::c_char;
+ let ret = unsafe {
+ backtrace_syminfo(state,
+ frame.symbol_addr as libc::uintptr_t,
+ syminfo_cb,
+ error_cb,
+ data_addr as *mut libc::c_void)
+ };
+ if ret == 0 || data.is_null() {
+ None
+ } else {
+ unsafe {
+ CStr::from_ptr(data).to_str().ok()
+ }
+ }
+ };
+ callback(symname)
+}
+
+////////////////////////////////////////////////////////////////////////
+// libbacktrace.h API
+////////////////////////////////////////////////////////////////////////
+type backtrace_syminfo_callback =
+extern "C" fn(data: *mut libc::c_void,
+ pc: libc::uintptr_t,
+ symname: *const libc::c_char,
+ symval: libc::uintptr_t,
+ symsize: libc::uintptr_t);
+type backtrace_full_callback =
+extern "C" fn(data: *mut libc::c_void,
+ pc: libc::uintptr_t,
+ filename: *const libc::c_char,
+ lineno: libc::c_int,
+ function: *const libc::c_char) -> libc::c_int;
+type backtrace_error_callback =
+extern "C" fn(data: *mut libc::c_void,
+ msg: *const libc::c_char,
+ errnum: libc::c_int);
+enum backtrace_state {}
+
+extern {
+ fn backtrace_create_state(filename: *const libc::c_char,
+ threaded: libc::c_int,
+ error: backtrace_error_callback,
+ data: *mut libc::c_void)
+ -> *mut backtrace_state;
+ fn backtrace_syminfo(state: *mut backtrace_state,
+ addr: libc::uintptr_t,
+ cb: backtrace_syminfo_callback,
+ error: backtrace_error_callback,
+ data: *mut libc::c_void) -> libc::c_int;
+ fn backtrace_pcinfo(state: *mut backtrace_state,
+ addr: libc::uintptr_t,
+ cb: backtrace_full_callback,
+ error: backtrace_error_callback,
+ data: *mut libc::c_void) -> libc::c_int;
+}
+
+////////////////////////////////////////////////////////////////////////
+// helper callbacks
+////////////////////////////////////////////////////////////////////////
+
+type FileLine = (*const libc::c_char, u32);
+
+extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
+ _errnum: libc::c_int) {
+ // do nothing for now
+}
+extern fn syminfo_cb(data: *mut libc::c_void,
+ _pc: libc::uintptr_t,
+ symname: *const libc::c_char,
+ _symval: libc::uintptr_t,
+ _symsize: libc::uintptr_t) {
+ let slot = data as *mut *const libc::c_char;
+ unsafe { *slot = symname; }
+}
+extern fn pcinfo_cb(data: *mut libc::c_void,
+ _pc: libc::uintptr_t,
+ filename: *const libc::c_char,
+ lineno: libc::c_int,
+ _function: *const libc::c_char) -> libc::c_int {
+ if !filename.is_null() {
+ let slot = data as *mut &mut [FileLine];
+ let buffer = unsafe {ptr::read(slot)};
+
+ // if the buffer is not full, add file:line to the buffer
+ // and adjust the buffer for next possible calls to pcinfo_cb.
+ if !buffer.is_empty() {
+ buffer[0] = (filename, lineno as u32);
+ unsafe { ptr::write(slot, &mut buffer[1..]); }
+ }
+ }
+
+ 0
+}
+
+// The libbacktrace API supports creating a state, but it does not
+// support destroying a state. I personally take this to mean that a
+// state is meant to be created and then live forever.
+//
+// I would love to register an at_exit() handler which cleans up this
+// state, but libbacktrace provides no way to do so.
+//
+// With these constraints, this function has a statically cached state
+// that is calculated the first time this is requested. Remember that
+// backtracing all happens serially (one global lock).
+//
+// Things don't work so well on not-Linux since libbacktrace can't track
+// down that executable this is. We at one point used env::current_exe but
+// it turns out that there are some serious security issues with that
+// approach.
+//
+// Specifically, on certain platforms like BSDs, a malicious actor can cause
+// an arbitrary file to be placed at the path returned by current_exe.
+// libbacktrace does not behave defensively in the presence of ill-formed
+// DWARF information, and has been demonstrated to segfault in at least one
+// case. There is no evidence at the moment to suggest that a more carefully
+// constructed file can't cause arbitrary code execution. As a result of all
+// of this, we don't hint libbacktrace with the path to the current process.
+unsafe fn init_state() -> *mut backtrace_state {
+ static mut STATE: *mut backtrace_state = ptr::null_mut();
+ if !STATE.is_null() { return STATE }
+
+ let filename = match ::sys::backtrace::gnu::get_executable_filename() {
+ Ok((filename, file)) => {
+ // filename is purposely leaked here since libbacktrace requires
+ // it to stay allocated permanently, file is also leaked so that
+ // the file stays locked
+ let filename_ptr = filename.as_ptr();
+ mem::forget(filename);
+ mem::forget(file);
+ filename_ptr
+ },
+ Err(_) => ptr::null(),
+ };
+
+ STATE = backtrace_create_state(filename, 0, error_cb,
+ ptr::null_mut());
+ STATE
+}
diff --git a/ctr-std/src/sys_common/gnu/mod.rs b/ctr-std/src/sys_common/gnu/mod.rs
new file mode 100644
index 0000000..3a8cf2d
--- /dev/null
+++ b/ctr-std/src/sys_common/gnu/mod.rs
@@ -0,0 +1,15 @@
+// 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.
+
+#![allow(missing_docs)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+pub mod libbacktrace;
diff --git a/ctr-std/src/sys_common/io.rs b/ctr-std/src/sys_common/io.rs
index 23daeeb..ab23936 100644
--- a/ctr-std/src/sys_common/io.rs
+++ b/ctr-std/src/sys_common/io.rs
@@ -7,51 +7,8 @@
// <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 io;
-use io::ErrorKind;
-use io::Read;
-use slice::from_raw_parts_mut;
-
pub const DEFAULT_BUF_SIZE: usize = 8 * 1024;
-// Provides read_to_end functionality over an uninitialized buffer.
-// This function is unsafe because it calls the underlying
-// read function with a slice into uninitialized memory. The default
-// implementation of read_to_end for readers will zero out new memory in
-// the buf before passing it to read, but avoiding this zero can often
-// lead to a fairly significant performance win.
-//
-// Implementations using this method have to adhere to two guarantees:
-// * The implementation of read never reads the buffer provided.
-// * The implementation of read correctly reports how many bytes were written.
-pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::Result<usize> {
-
- let start_len = buf.len();
- buf.reserve(16);
-
- // Always try to read into the empty space of the vector (from the length to the capacity).
- // If the vector ever fills up then we reserve an extra byte which should trigger the normal
- // reallocation routines for the vector, which will likely double the size.
- //
- // This function is similar to the read_to_end function in std::io, but the logic about
- // reservations and slicing is different enough that this is duplicated here.
- loop {
- if buf.len() == buf.capacity() {
- buf.reserve(1);
- }
-
- let buf_slice = from_raw_parts_mut(buf.as_mut_ptr().offset(buf.len() as isize),
- buf.capacity() - buf.len());
-
- match r.read(buf_slice) {
- Ok(0) => { return Ok(buf.len() - start_len); }
- Ok(n) => { let len = buf.len() + n; buf.set_len(len); },
- Err(ref e) if e.kind() == ErrorKind::Interrupted => { }
- Err(e) => { return Err(e); }
- }
- }
-}
-
#[cfg(test)]
#[allow(dead_code)] // not used on emscripten
pub mod test {
@@ -91,89 +48,3 @@ pub mod test {
TempDir(ret)
}
}
-
-#[cfg(test)]
-mod tests {
- use io::prelude::*;
- use super::*;
- use io;
- use io::{ErrorKind, Take, Repeat, repeat};
- use slice::from_raw_parts;
-
- struct ErrorRepeat {
- lr: Take<Repeat>
- }
-
- fn error_repeat(byte: u8, limit: u64) -> ErrorRepeat {
- ErrorRepeat { lr: repeat(byte).take(limit) }
- }
-
- impl Read for ErrorRepeat {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- let ret = self.lr.read(buf);
- if let Ok(0) = ret {
- return Err(io::Error::new(ErrorKind::Other, ""))
- }
- ret
- }
- }
-
- fn init_vec_data() -> Vec<u8> {
- let mut vec = vec![10u8; 200];
- unsafe { vec.set_len(0); }
- vec
- }
-
- fn assert_all_eq(buf: &[u8], value: u8) {
- for n in buf {
- assert_eq!(*n, value);
- }
- }
-
- fn validate(buf: &Vec<u8>, good_read_len: usize) {
- assert_all_eq(buf, 1u8);
- let cap = buf.capacity();
- let end_slice = unsafe { from_raw_parts(buf.as_ptr().offset(good_read_len as isize),
- cap - good_read_len) };
- assert_all_eq(end_slice, 10u8);
- }
-
- #[test]
- fn read_to_end_uninit_error() {
- let mut er = error_repeat(1,100);
- let mut vec = init_vec_data();
- if let Err(_) = unsafe { read_to_end_uninitialized(&mut er, &mut vec) } {
- validate(&vec, 100);
- } else {
- assert!(false);
- }
- }
-
- #[test]
- fn read_to_end_uninit_zero_len_vec() {
- let mut er = repeat(1).take(100);
- let mut vec = Vec::new();
- let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() };
- assert_all_eq(&vec, 1u8);
- assert_eq!(vec.len(), n);
- }
-
- #[test]
- fn read_to_end_uninit_good() {
- let mut er = repeat(1).take(100);
- let mut vec = init_vec_data();
- let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() };
- validate(&vec, 100);
- assert_eq!(vec.len(), n);
- }
-
- #[bench]
- #[cfg_attr(target_os = "emscripten", ignore)]
- fn bench_uninitialized(b: &mut ::test::Bencher) {
- b.iter(|| {
- let mut lr = repeat(1).take(10000000);
- let mut vec = Vec::with_capacity(1024);
- unsafe { read_to_end_uninitialized(&mut lr, &mut vec) }
- });
- }
-}
diff --git a/ctr-std/src/sys_common/memchr.rs b/ctr-std/src/sys_common/memchr.rs
deleted file mode 100644
index 3824a5f..0000000
--- a/ctr-std/src/sys_common/memchr.rs
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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.
-//
-// Original implementation taken from rust-memchr
-// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
-
-#[allow(dead_code)]
-pub mod fallback {
- use cmp;
- use mem;
-
- const LO_U64: u64 = 0x0101010101010101;
- const HI_U64: u64 = 0x8080808080808080;
-
- // use truncation
- const LO_USIZE: usize = LO_U64 as usize;
- const HI_USIZE: usize = HI_U64 as usize;
-
- /// Return `true` if `x` contains any zero byte.
- ///
- /// From *Matters Computational*, J. Arndt
- ///
- /// "The idea is to subtract one from each of the bytes and then look for
- /// bytes where the borrow propagated all the way to the most significant
- /// bit."
- #[inline]
- fn contains_zero_byte(x: usize) -> bool {
- x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
- }
-
- #[cfg(target_pointer_width = "32")]
- #[inline]
- fn repeat_byte(b: u8) -> usize {
- let mut rep = (b as usize) << 8 | b as usize;
- rep = rep << 16 | rep;
- rep
- }
-
- #[cfg(target_pointer_width = "64")]
- #[inline]
- fn repeat_byte(b: u8) -> usize {
- let mut rep = (b as usize) << 8 | b as usize;
- rep = rep << 16 | rep;
- rep = rep << 32 | rep;
- rep
- }
-
- /// Return the first index matching the byte `a` in `text`.
- pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
- // Scan for a single byte value by reading two `usize` words at a time.
- //
- // Split `text` in three parts
- // - unaligned initial part, before the first word aligned address in text
- // - body, scan by 2 words at a time
- // - the last remaining part, < 2 word size
- let len = text.len();
- let ptr = text.as_ptr();
- let usize_bytes = mem::size_of::<usize>();
-
- // search up to an aligned boundary
- let align = (ptr as usize) & (usize_bytes- 1);
- let mut offset;
- if align > 0 {
- offset = cmp::min(usize_bytes - align, len);
- if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
- return Some(index);
- }
- } else {
- offset = 0;
- }
-
- // search the body of the text
- let repeated_x = repeat_byte(x);
-
- if len >= 2 * usize_bytes {
- while offset <= len - 2 * usize_bytes {
- unsafe {
- let u = *(ptr.offset(offset as isize) as *const usize);
- let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
-
- // break if there is a matching byte
- let zu = contains_zero_byte(u ^ repeated_x);
- let zv = contains_zero_byte(v ^ repeated_x);
- if zu || zv {
- break;
- }
- }
- offset += usize_bytes * 2;
- }
- }
-
- // find the byte after the point the body loop stopped
- text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
- }
-
- /// Return the last index matching the byte `a` in `text`.
- pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
- // Scan for a single byte value by reading two `usize` words at a time.
- //
- // Split `text` in three parts
- // - unaligned tail, after the last word aligned address in text
- // - body, scan by 2 words at a time
- // - the first remaining bytes, < 2 word size
- let len = text.len();
- let ptr = text.as_ptr();
- let usize_bytes = mem::size_of::<usize>();
-
- // search to an aligned boundary
- let end_align = (ptr as usize + len) & (usize_bytes - 1);
- let mut offset;
- if end_align > 0 {
- offset = if end_align >= len { 0 } else { len - end_align };
- if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
- return Some(offset + index);
- }
- } else {
- offset = len;
- }
-
- // search the body of the text
- let repeated_x = repeat_byte(x);
-
- while offset >= 2 * usize_bytes {
- unsafe {
- let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
- let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
-
- // break if there is a matching byte
- let zu = contains_zero_byte(u ^ repeated_x);
- let zv = contains_zero_byte(v ^ repeated_x);
- if zu || zv {
- break;
- }
- }
- offset -= 2 * usize_bytes;
- }
-
- // find the byte before the point the body loop stopped
- text[..offset].iter().rposition(|elt| *elt == x)
- }
-
- // test fallback implementations on all platforms
- #[test]
- fn matches_one() {
- assert_eq!(Some(0), memchr(b'a', b"a"));
- }
-
- #[test]
- fn matches_begin() {
- assert_eq!(Some(0), memchr(b'a', b"aaaa"));
- }
-
- #[test]
- fn matches_end() {
- assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
- }
-
- #[test]
- fn matches_nul() {
- assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
- }
-
- #[test]
- fn matches_past_nul() {
- assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
- }
-
- #[test]
- fn no_match_empty() {
- assert_eq!(None, memchr(b'a', b""));
- }
-
- #[test]
- fn no_match() {
- assert_eq!(None, memchr(b'a', b"xyz"));
- }
-
- #[test]
- fn matches_one_reversed() {
- assert_eq!(Some(0), memrchr(b'a', b"a"));
- }
-
- #[test]
- fn matches_begin_reversed() {
- assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
- }
-
- #[test]
- fn matches_end_reversed() {
- assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
- }
-
- #[test]
- fn matches_nul_reversed() {
- assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
- }
-
- #[test]
- fn matches_past_nul_reversed() {
- assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
- }
-
- #[test]
- fn no_match_empty_reversed() {
- assert_eq!(None, memrchr(b'a', b""));
- }
-
- #[test]
- fn no_match_reversed() {
- assert_eq!(None, memrchr(b'a', b"xyz"));
- }
-
- #[test]
- fn each_alignment_reversed() {
- let mut data = [1u8; 64];
- let needle = 2;
- let pos = 40;
- data[pos] = needle;
- for start in 0..16 {
- assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
- }
- }
-}
diff --git a/ctr-std/src/sys_common/mod.rs b/ctr-std/src/sys_common/mod.rs
index 4a7d79f..27504d3 100644
--- a/ctr-std/src/sys_common/mod.rs
+++ b/ctr-std/src/sys_common/mod.rs
@@ -10,7 +10,7 @@
//! Platform-independent platform abstraction
//!
-//! This is the platform-independent portion of the standard libraries
+//! This is the platform-independent portion of the standard library's
//! platform abstraction layer, whereas `std::sys` is the
//! platform-specific portion.
//!
@@ -23,11 +23,16 @@
//! `std::sys` from the standard library.
#![allow(missing_docs)]
+#![allow(missing_debug_implementations)]
+
+use sync::Once;
+use sys;
pub mod at_exit_imp;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
pub mod condvar;
pub mod io;
-pub mod memchr;
pub mod mutex;
pub mod poison;
pub mod remutex;
@@ -36,6 +41,25 @@ pub mod thread;
pub mod thread_info;
pub mod thread_local;
pub mod util;
+pub mod wtf8;
+pub mod bytestring;
+pub mod process;
+
+cfg_if! {
+ if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox"))] {
+ pub use sys::net;
+ } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
+ pub use sys::net;
+ } else {
+ pub mod net;
+ }
+}
+
+#[cfg(feature = "backtrace")]
+#[cfg(any(all(unix, not(target_os = "emscripten")),
+ all(windows, target_env = "gnu"),
+ target_os = "redox"))]
+pub mod gnu;
// common error constructors
@@ -81,6 +105,16 @@ macro_rules! rtabort {
($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*)))
}
+/// One-time runtime cleanup.
+pub fn cleanup() {
+ static CLEANUP: Once = Once::new();
+ CLEANUP.call_once(|| unsafe {
+ sys::args::cleanup();
+ sys::stack_overflow::cleanup();
+ at_exit_imp::cleanup();
+ });
+}
+
// Computes (value*numer)/denom without overflow, as long as both
// (numer*denom) and the overall result fit into i64 (which is the case
// for our time conversions).
diff --git a/ctr-std/src/sys_common/net.rs b/ctr-std/src/sys_common/net.rs
new file mode 100644
index 0000000..6223f82
--- /dev/null
+++ b/ctr-std/src/sys_common/net.rs
@@ -0,0 +1,630 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![allow(dead_code)]
+
+use cmp;
+use ffi::CString;
+use fmt;
+use io::{self, Error, ErrorKind};
+use libc::{c_int, c_void};
+use mem;
+use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+use ptr;
+use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
+use sys::net::netc as c;
+use sys_common::{AsInner, FromInner, IntoInner};
+use time::Duration;
+
+// IPV6 stuff does not seem to be supported on 3DS. TODO: Determine if that's true
+const IPV6_ADD_MEMBERSHIP: c_int = 0x0;
+const IPV6_DROP_MEMBERSHIP: c_int = 0x0;
+const IPV6_MULTICAST_LOOP: c_int = 0x0;
+const IPV6_V6ONLY: c_int = 0x0;
+
+// Neither are signals
+const MSG_NOSIGNAL: c_int = 0x0;
+
+// These constants are also currently missing from libctru. TODO: Find them?
+const SO_SNDTIMEO: c_int = 0x0;
+const SO_RCVTIMEO: c_int = 0x0;
+const SO_BROADCAST: c_int = 0x0;
+
+////////////////////////////////////////////////////////////////////////////////
+// sockaddr and misc bindings
+////////////////////////////////////////////////////////////////////////////////
+
+pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
+ payload: T) -> io::Result<()> {
+ unsafe {
+ let payload = &payload as *const T as *const c_void;
+ cvt(c::setsockopt(*sock.as_inner(), opt, val, payload,
+ mem::size_of::<T>() as c::socklen_t))?;
+ Ok(())
+ }
+}
+
+pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
+ val: c_int) -> io::Result<T> {
+ unsafe {
+ let mut slot: T = mem::zeroed();
+ let mut len = mem::size_of::<T>() as c::socklen_t;
+ cvt(c::getsockopt(*sock.as_inner(), opt, val,
+ &mut slot as *mut _ as *mut _,
+ &mut len))?;
+ assert_eq!(len as usize, mem::size_of::<T>());
+ Ok(slot)
+ }
+}
+
+fn sockname<F>(f: F) -> io::Result<SocketAddr>
+ where F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int
+{
+ unsafe {
+ let mut storage: c::sockaddr_storage = mem::zeroed();
+ let mut len = mem::size_of_val(&storage) as c::socklen_t;
+ cvt(f(&mut storage as *mut _ as *mut _, &mut len))?;
+ sockaddr_to_addr(&storage, len as usize)
+ }
+}
+
+pub fn sockaddr_to_addr(storage: &c::sockaddr_storage,
+ len: usize) -> io::Result<SocketAddr> {
+ match storage.ss_family as c_int {
+ c::AF_INET => {
+ assert!(len as usize >= mem::size_of::<c::sockaddr_in>());
+ Ok(SocketAddr::V4(FromInner::from_inner(unsafe {
+ *(storage as *const _ as *const c::sockaddr_in)
+ })))
+ }
+ c::AF_INET6 => {
+ assert!(len as usize >= mem::size_of::<c::sockaddr_in6>());
+ Ok(SocketAddr::V6(FromInner::from_inner(unsafe {
+ *(storage as *const _ as *const c::sockaddr_in6)
+ })))
+ }
+ _ => {
+ Err(Error::new(ErrorKind::InvalidInput, "invalid argument"))
+ }
+ }
+}
+
+#[cfg(target_os = "android")]
+fn to_ipv6mr_interface(value: u32) -> c_int {
+ value as c_int
+}
+
+#[cfg(not(target_os = "android"))]
+fn to_ipv6mr_interface(value: u32) -> ::libc::c_uint {
+ value as ::libc::c_uint
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// get_host_addresses
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct LookupHost {
+ original: *mut c::addrinfo,
+ cur: *mut c::addrinfo,
+}
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ loop {
+ unsafe {
+ let cur = self.cur.as_ref()?;
+ self.cur = cur.ai_next;
+ match sockaddr_to_addr(mem::transmute(cur.ai_addr),
+ cur.ai_addrlen as usize)
+ {
+ Ok(addr) => return Some(addr),
+ Err(_) => continue,
+ }
+ }
+ }
+ }
+}
+
+unsafe impl Sync for LookupHost {}
+unsafe impl Send for LookupHost {}
+
+impl Drop for LookupHost {
+ fn drop(&mut self) {
+ unsafe { c::freeaddrinfo(self.original) }
+ }
+}
+
+pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
+ init();
+
+ let c_host = CString::new(host)?;
+ let mut hints: c::addrinfo = unsafe { mem::zeroed() };
+ hints.ai_socktype = c::SOCK_STREAM;
+ let mut res = ptr::null_mut();
+ unsafe {
+ match cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) {
+ Ok(_) => {
+ Ok(LookupHost { original: res, cur: res })
+ },
+ #[cfg(unix)]
+ Err(e) => {
+ // If we're running glibc prior to version 2.26, the lookup
+ // failure could be caused by caching a stale /etc/resolv.conf.
+ // We need to call libc::res_init() to clear the cache. But we
+ // shouldn't call it in on any other platform, because other
+ // res_init implementations aren't thread-safe. See
+ // https://github.com/rust-lang/rust/issues/41570 and
+ // https://github.com/rust-lang/rust/issues/43592.
+ use sys::net::res_init_if_glibc_before_2_26;
+ let _ = res_init_if_glibc_before_2_26();
+ Err(e)
+ },
+ // the cfg is needed here to avoid an "unreachable pattern" warning
+ #[cfg(not(unix))]
+ Err(e) => Err(e),
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpStream {
+ inner: Socket,
+}
+
+impl TcpStream {
+ pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
+ init();
+
+ let sock = Socket::new(addr, c::SOCK_STREAM)?;
+
+ let (addrp, len) = addr.into_inner();
+ cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?;
+ Ok(TcpStream { inner: sock })
+ }
+
+ pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
+ init();
+
+ let sock = Socket::new(addr, c::SOCK_STREAM)?;
+ sock.connect_timeout(addr, timeout)?;
+ Ok(TcpStream { inner: sock })
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, SO_RCVTIMEO)
+ }
+
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, SO_SNDTIMEO)
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(SO_RCVTIMEO)
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(SO_SNDTIMEO)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.peek(buf)
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+ let ret = cvt(unsafe {
+ c::send(*self.inner.as_inner(),
+ buf.as_ptr() as *const c_void,
+ len,
+ MSG_NOSIGNAL)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ sockname(|buf, len| unsafe {
+ c::getpeername(*self.inner.as_inner(), buf, len)
+ })
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ sockname(|buf, len| unsafe {
+ c::getsockname(*self.inner.as_inner(), buf, len)
+ })
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.inner.shutdown(how)
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ self.inner.duplicate().map(|s| TcpStream { inner: s })
+ }
+
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ self.inner.set_nodelay(nodelay)
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ self.inner.nodelay()
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
+ Ok(raw as u32)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.inner.set_nonblocking(nonblocking)
+ }
+}
+
+impl FromInner<Socket> for TcpStream {
+ fn from_inner(socket: Socket) -> TcpStream {
+ TcpStream { inner: socket }
+ }
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut res = f.debug_struct("TcpStream");
+
+ if let Ok(addr) = self.socket_addr() {
+ res.field("addr", &addr);
+ }
+
+ if let Ok(peer) = self.peer_addr() {
+ res.field("peer", &peer);
+ }
+
+ let name = if cfg!(windows) {"socket"} else {"fd"};
+ res.field(name, &self.inner.as_inner())
+ .finish()
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP listeners
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpListener {
+ inner: Socket,
+}
+
+impl TcpListener {
+ pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
+ init();
+
+ let sock = Socket::new(addr, c::SOCK_STREAM)?;
+
+ // On platforms with Berkeley-derived sockets, this allows
+ // to quickly rebind a socket, without needing to wait for
+ // the OS to clean up the previous one.
+ if !cfg!(windows) {
+ setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR,
+ 1 as c_int)?;
+ }
+
+ // Bind our new socket
+ let (addrp, len) = addr.into_inner();
+ cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
+
+ // Start listening
+ cvt(unsafe { c::listen(*sock.as_inner(), 128) })?;
+ Ok(TcpListener { inner: sock })
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ sockname(|buf, len| unsafe {
+ c::getsockname(*self.inner.as_inner(), buf, len)
+ })
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
+ let mut len = mem::size_of_val(&storage) as c::socklen_t;
+ let sock = self.inner.accept(&mut storage as *mut _ as *mut _,
+ &mut len)?;
+ let addr = sockaddr_to_addr(&storage, len as usize)?;
+ Ok((TcpStream { inner: sock, }, addr))
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ self.inner.duplicate().map(|s| TcpListener { inner: s })
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
+ Ok(raw as u32)
+ }
+
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_V6ONLY, only_v6 as c_int)
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_V6ONLY)?;
+ Ok(raw != 0)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.inner.set_nonblocking(nonblocking)
+ }
+}
+
+impl FromInner<Socket> for TcpListener {
+ fn from_inner(socket: Socket) -> TcpListener {
+ TcpListener { inner: socket }
+ }
+}
+
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut res = f.debug_struct("TcpListener");
+
+ if let Ok(addr) = self.socket_addr() {
+ res.field("addr", &addr);
+ }
+
+ let name = if cfg!(windows) {"socket"} else {"fd"};
+ res.field(name, &self.inner.as_inner())
+ .finish()
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// UDP
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UdpSocket {
+ inner: Socket,
+}
+
+impl UdpSocket {
+ pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
+ init();
+
+ let sock = Socket::new(addr, c::SOCK_DGRAM)?;
+ let (addrp, len) = addr.into_inner();
+ cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
+ Ok(UdpSocket { inner: sock })
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ sockname(|buf, len| unsafe {
+ c::getsockname(*self.inner.as_inner(), buf, len)
+ })
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.inner.recv_from(buf)
+ }
+
+ 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<usize> {
+ let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+ let (dstp, dstlen) = dst.into_inner();
+ let ret = cvt(unsafe {
+ c::sendto(*self.inner.as_inner(),
+ buf.as_ptr() as *const c_void, len,
+ MSG_NOSIGNAL, dstp, dstlen)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ self.inner.duplicate().map(|s| UdpSocket { inner: s })
+ }
+
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, SO_RCVTIMEO)
+ }
+
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, SO_SNDTIMEO)
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(SO_RCVTIMEO)
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(SO_SNDTIMEO)
+ }
+
+ pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
+ setsockopt(&self.inner, c::SOL_SOCKET, SO_BROADCAST, broadcast as c_int)
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, SO_BROADCAST)?;
+ Ok(raw != 0)
+ }
+
+ pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int)
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?;
+ Ok(raw != 0)
+ }
+
+ pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int)
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?;
+ Ok(raw as u32)
+ }
+
+ pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int)
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_MULTICAST_LOOP)?;
+ Ok(raw != 0)
+ }
+
+ pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
+ -> io::Result<()> {
+ let mreq = c::ip_mreq {
+ imr_multiaddr: *multiaddr.as_inner(),
+ imr_interface: *interface.as_inner(),
+ };
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq)
+ }
+
+ pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
+ -> io::Result<()> {
+ let mreq = c::ipv6_mreq {
+ ipv6mr_multiaddr: *multiaddr.as_inner(),
+ ipv6mr_interface: to_ipv6mr_interface(interface),
+ };
+ setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq)
+ }
+
+ pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
+ -> io::Result<()> {
+ let mreq = c::ip_mreq {
+ imr_multiaddr: *multiaddr.as_inner(),
+ imr_interface: *interface.as_inner(),
+ };
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq)
+ }
+
+ pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
+ -> io::Result<()> {
+ let mreq = c::ipv6_mreq {
+ ipv6mr_multiaddr: *multiaddr.as_inner(),
+ ipv6mr_interface: to_ipv6mr_interface(interface),
+ };
+ setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq)
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
+ Ok(raw as u32)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.inner.set_nonblocking(nonblocking)
+ }
+
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.peek(buf)
+ }
+
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+ let ret = cvt(unsafe {
+ c::send(*self.inner.as_inner(),
+ buf.as_ptr() as *const c_void,
+ len,
+ MSG_NOSIGNAL)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
+ let (addrp, len) = addr.into_inner();
+ cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(|_| ())
+ }
+}
+
+impl FromInner<Socket> for UdpSocket {
+ fn from_inner(socket: Socket) -> UdpSocket {
+ UdpSocket { inner: socket }
+ }
+}
+
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut res = f.debug_struct("UdpSocket");
+
+ if let Ok(addr) = self.socket_addr() {
+ res.field("addr", &addr);
+ }
+
+ let name = if cfg!(windows) {"socket"} else {"fd"};
+ res.field(name, &self.inner.as_inner())
+ .finish()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use collections::HashMap;
+
+ #[test]
+ fn no_lookup_host_duplicates() {
+ let mut addrs = HashMap::new();
+ let lh = match lookup_host("localhost") {
+ Ok(lh) => lh,
+ Err(e) => panic!("couldn't resolve `localhost': {}", e)
+ };
+ let _na = lh.map(|sa| *addrs.entry(sa).or_insert(0) += 1).count();
+ assert!(addrs.values().filter(|&&v| v > 1).count() == 0);
+ }
+}
diff --git a/ctr-std/src/sys_common/poison.rs b/ctr-std/src/sys_common/poison.rs
index bdc727f..934ac3e 100644
--- a/ctr-std/src/sys_common/poison.rs
+++ b/ctr-std/src/sys_common/poison.rs
@@ -60,17 +60,53 @@ pub struct Guard {
/// A type of error which can be returned whenever a lock is acquired.
///
-/// Both Mutexes and RwLocks are poisoned whenever a thread fails while the lock
+/// Both [`Mutex`]es and [`RwLock`]s are poisoned whenever a thread fails while the lock
/// is held. The precise semantics for when a lock is poisoned is documented on
/// each lock, but once a lock is poisoned then all future acquisitions will
/// return this error.
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Arc, Mutex};
+/// use std::thread;
+///
+/// let mutex = Arc::new(Mutex::new(1));
+///
+/// // poison the mutex
+/// let c_mutex = mutex.clone();
+/// let _ = thread::spawn(move || {
+/// let mut data = c_mutex.lock().unwrap();
+/// *data = 2;
+/// panic!();
+/// }).join();
+///
+/// match mutex.lock() {
+/// Ok(_) => unreachable!(),
+/// Err(p_err) => {
+/// let data = p_err.get_ref();
+/// println!("recovered: {}", data);
+/// }
+/// };
+/// ```
+///
+/// [`Mutex`]: ../../std/sync/struct.Mutex.html
+/// [`RwLock`]: ../../std/sync/struct.RwLock.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PoisonError<T> {
guard: T,
}
-/// An enumeration of possible errors which can occur while calling the
-/// `try_lock` method.
+/// An enumeration of possible errors associated with a [`TryLockResult`] which
+/// can occur while trying to aquire a lock, from the [`try_lock`] method on a
+/// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`].
+///
+/// [`Mutex`]: struct.Mutex.html
+/// [`RwLock`]: struct.RwLock.html
+/// [`TryLockResult`]: type.TryLockResult.html
+/// [`try_lock`]: struct.Mutex.html#method.try_lock
+/// [`try_read`]: struct.RwLock.html#method.try_read
+/// [`try_write`]: struct.RwLock.html#method.try_write
#[stable(feature = "rust1", since = "1.0.0")]
pub enum TryLockError<T> {
/// The lock could not be acquired because another thread failed while holding
@@ -85,19 +121,26 @@ pub enum TryLockError<T> {
/// A type alias for the result of a lock method which can be poisoned.
///
-/// The `Ok` variant of this result indicates that the primitive was not
-/// poisoned, and the `Guard` is contained within. The `Err` variant indicates
-/// that the primitive was poisoned. Note that the `Err` variant *also* carries
-/// the associated guard, and it can be acquired through the `into_inner`
+/// The [`Ok`] variant of this result indicates that the primitive was not
+/// poisoned, and the `Guard` is contained within. The [`Err`] variant indicates
+/// that the primitive was poisoned. Note that the [`Err`] variant *also* carries
+/// the associated guard, and it can be acquired through the [`into_inner`]
/// method.
+///
+/// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner
#[stable(feature = "rust1", since = "1.0.0")]
pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;
/// A type alias for the result of a nonblocking locking method.
///
-/// For more information, see `LockResult`. A `TryLockResult` doesn't
-/// necessarily hold the associated guard in the `Err` type as the lock may not
+/// For more information, see [`LockResult`]. A `TryLockResult` doesn't
+/// necessarily hold the associated guard in the [`Err`] type as the lock may not
/// have been acquired for other reasons.
+///
+/// [`LockResult`]: ../../std/sync/type.LockResult.html
+/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
#[stable(feature = "rust1", since = "1.0.0")]
pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
@@ -124,6 +167,11 @@ impl<T> Error for PoisonError<T> {
impl<T> PoisonError<T> {
/// Creates a `PoisonError`.
+ ///
+ /// This is generally created by methods like [`Mutex::lock`] or [`RwLock::read`].
+ ///
+ /// [`Mutex::lock`]: ../../std/sync/struct.Mutex.html#method.lock
+ /// [`RwLock::read`]: ../../std/sync/struct.RwLock.html#method.read
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn new(guard: T) -> PoisonError<T> {
PoisonError { guard: guard }
@@ -131,6 +179,28 @@ impl<T> PoisonError<T> {
/// Consumes this error indicating that a lock is poisoned, returning the
/// underlying guard to allow access regardless.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// use std::sync::{Arc, Mutex};
+ /// use std::thread;
+ ///
+ /// let mutex = Arc::new(Mutex::new(HashSet::new()));
+ ///
+ /// // poison the mutex
+ /// let c_mutex = mutex.clone();
+ /// let _ = thread::spawn(move || {
+ /// let mut data = c_mutex.lock().unwrap();
+ /// data.insert(10);
+ /// panic!();
+ /// }).join();
+ ///
+ /// let p_err = mutex.lock().unwrap_err();
+ /// let data = p_err.into_inner();
+ /// println!("recovered {} items", data.len());
+ /// ```
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn into_inner(self) -> T { self.guard }
diff --git a/ctr-std/src/sys_common/process.rs b/ctr-std/src/sys_common/process.rs
new file mode 100644
index 0000000..fd1a5fd
--- /dev/null
+++ b/ctr-std/src/sys_common/process.rs
@@ -0,0 +1,124 @@
+// 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.
+
+#![allow(dead_code)]
+#![unstable(feature = "process_internals", issue = "0")]
+
+use ffi::{OsStr, OsString};
+use env;
+use collections::BTreeMap;
+use alloc::borrow::Borrow;
+
+pub trait EnvKey:
+ From<OsString> + Into<OsString> +
+ Borrow<OsStr> + Borrow<Self> + AsRef<OsStr> +
+ Ord + Clone {}
+
+// Implement a case-sensitive environment variable key
+#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
+pub struct DefaultEnvKey(OsString);
+
+impl From<OsString> for DefaultEnvKey {
+ fn from(k: OsString) -> Self { DefaultEnvKey(k) }
+}
+
+impl From<DefaultEnvKey> for OsString {
+ fn from(k: DefaultEnvKey) -> Self { k.0 }
+}
+
+impl Borrow<OsStr> for DefaultEnvKey {
+ fn borrow(&self) -> &OsStr { &self.0 }
+}
+
+impl AsRef<OsStr> for DefaultEnvKey {
+ fn as_ref(&self) -> &OsStr { &self.0 }
+}
+
+impl EnvKey for DefaultEnvKey {}
+
+// Stores a set of changes to an environment
+#[derive(Clone, Debug)]
+pub struct CommandEnv<K> {
+ clear: bool,
+ vars: BTreeMap<K, Option<OsString>>
+}
+
+impl<K: EnvKey> Default for CommandEnv<K> {
+ fn default() -> Self {
+ CommandEnv {
+ clear: false,
+ vars: Default::default()
+ }
+ }
+}
+
+impl<K: EnvKey> CommandEnv<K> {
+ // Capture the current environment with these changes applied
+ pub fn capture(&self) -> BTreeMap<K, OsString> {
+ let mut result = BTreeMap::<K, OsString>::new();
+ if !self.clear {
+ for (k, v) in env::vars_os() {
+ result.insert(k.into(), v);
+ }
+ }
+ for (k, maybe_v) in &self.vars {
+ if let &Some(ref v) = maybe_v {
+ result.insert(k.clone(), v.clone());
+ } else {
+ result.remove(k);
+ }
+ }
+ result
+ }
+
+ // Apply these changes directly to the current environment
+ pub fn apply(&self) {
+ if self.clear {
+ for (k, _) in env::vars_os() {
+ env::remove_var(k);
+ }
+ }
+ for (key, maybe_val) in self.vars.iter() {
+ if let &Some(ref val) = maybe_val {
+ env::set_var(key, val);
+ } else {
+ env::remove_var(key);
+ }
+ }
+ }
+
+ pub fn is_unchanged(&self) -> bool {
+ !self.clear && self.vars.is_empty()
+ }
+
+ pub fn capture_if_changed(&self) -> Option<BTreeMap<K, OsString>> {
+ if self.is_unchanged() {
+ None
+ } else {
+ Some(self.capture())
+ }
+ }
+
+ // The following functions build up changes
+ pub fn set(&mut self, key: &OsStr, value: &OsStr) {
+ self.vars.insert(key.to_owned().into(), Some(value.to_owned()));
+ }
+ pub fn remove(&mut self, key: &OsStr) {
+ if self.clear {
+ self.vars.remove(key);
+ } else {
+ self.vars.insert(key.to_owned().into(), None);
+ }
+ }
+ pub fn clear(&mut self) {
+ self.clear = true;
+ self.vars.clear();
+ }
+}
diff --git a/ctr-std/src/sys_common/remutex.rs b/ctr-std/src/sys_common/remutex.rs
index 4d0407c..ce43ec6 100644
--- a/ctr-std/src/sys_common/remutex.rs
+++ b/ctr-std/src/sys_common/remutex.rs
@@ -116,11 +116,18 @@ impl<T> Drop for ReentrantMutex<T> {
impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_lock() {
- Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard),
+ Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
Err(TryLockError::Poisoned(err)) => {
- write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
+ f.debug_struct("ReentrantMutex").field("data", &**err.get_ref()).finish()
},
- Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ <locked> }}")
+ Err(TryLockError::WouldBlock) => {
+ struct LockedPlaceholder;
+ impl fmt::Debug for LockedPlaceholder {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
+ }
+
+ f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish()
+ }
}
}
}
diff --git a/ctr-std/src/sys_common/thread.rs b/ctr-std/src/sys_common/thread.rs
index bb6baae..f1379b6 100644
--- a/ctr-std/src/sys_common/thread.rs
+++ b/ctr-std/src/sys_common/thread.rs
@@ -9,14 +9,32 @@
// except according to those terms.
use alloc::boxed::FnBox;
-use libc;
-//use sys::stack_overflow;
+use env;
+use sync::atomic::{self, Ordering};
+use sys::stack_overflow;
+use sys::thread as imp;
-pub unsafe fn start_thread(main: *mut libc::c_void) {
+#[allow(dead_code)]
+pub unsafe fn start_thread(main: *mut u8) {
// Next, set up our stack overflow handler which may get triggered if we run
// out of stack.
- // let _handler = stack_overflow::Handler::new();
+ let _handler = stack_overflow::Handler::new();
// Finally, let's run some code.
Box::from_raw(main as *mut Box<FnBox()>)()
}
+
+pub fn min_stack() -> usize {
+ static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
+ match MIN.load(Ordering::SeqCst) {
+ 0 => {}
+ n => return n - 1,
+ }
+ let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
+ let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE);
+
+ // 0 is our sentinel value, so ensure that we'll never see 0 after
+ // initialization has run
+ MIN.store(amt + 1, Ordering::SeqCst);
+ amt
+}
diff --git a/ctr-std/src/sys_common/thread_info.rs b/ctr-std/src/sys_common/thread_info.rs
index 2abb8af..7970042 100644
--- a/ctr-std/src/sys_common/thread_info.rs
+++ b/ctr-std/src/sys_common/thread_info.rs
@@ -45,7 +45,7 @@ pub fn stack_guard() -> Option<usize> {
pub fn set(stack_guard: Option<usize>, thread: Thread) {
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
- stack_guard: stack_guard,
- thread: thread,
+ stack_guard,
+ thread,
}));
}
diff --git a/ctr-std/src/sys_common/thread_local.rs b/ctr-std/src/sys_common/thread_local.rs
index 25a9d57..a4aa3d9 100644
--- a/ctr-std/src/sys_common/thread_local.rs
+++ b/ctr-std/src/sys_common/thread_local.rs
@@ -33,7 +33,7 @@
//! Using a dynamically allocated TLS key. Note that this key can be shared
//! among many threads via an `Arc`.
//!
-//! ```rust,ignore
+//! ```ignore (cannot-doctest-private-modules)
//! let key = Key::new(None);
//! assert!(key.get().is_null());
//! key.set(1 as *mut u8);
@@ -45,7 +45,7 @@
//! Sometimes a statically allocated key is either required or easier to work
//! with, however.
//!
-//! ```rust,ignore
+//! ```ignore (cannot-doctest-private-modules)
//! static KEY: StaticKey = INIT;
//!
//! unsafe {
@@ -58,9 +58,10 @@
#![unstable(feature = "thread_local_internals", issue = "0")]
#![allow(dead_code)] // sys isn't exported yet
+use ptr;
use sync::atomic::{self, AtomicUsize, Ordering};
-
use sys::thread_local as imp;
+use sys_common::mutex::Mutex;
/// A type for TLS keys that are statically allocated.
///
@@ -73,7 +74,7 @@ use sys::thread_local as imp;
///
/// # Examples
///
-/// ```ignore
+/// ```ignore (cannot-doctest-private-modules)
/// use tls::os::{StaticKey, INIT};
///
/// static KEY: StaticKey = INIT;
@@ -104,7 +105,7 @@ pub struct StaticKey {
///
/// # Examples
///
-/// ```rust,ignore
+/// ```ignore (cannot-doctest-private-modules)
/// use tls::os::Key;
///
/// let key = Key::new(None);
@@ -127,7 +128,7 @@ impl StaticKey {
pub const fn new(dtor: Option<unsafe extern fn(*mut u8)>) -> StaticKey {
StaticKey {
key: atomic::AtomicUsize::new(0),
- dtor: dtor
+ dtor,
}
}
@@ -145,20 +146,6 @@ impl StaticKey {
#[inline]
pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) }
- /// Deallocates this OS TLS key.
- ///
- /// This function is unsafe as there is no guarantee that the key is not
- /// currently in use by other threads or will not ever be used again.
- ///
- /// Note that this does *not* run the user-provided destructor if one was
- /// specified at definition time. Doing so must be done manually.
- pub unsafe fn destroy(&self) {
- match self.key.swap(0, Ordering::SeqCst) {
- 0 => {}
- n => { imp::destroy(n as imp::Key) }
- }
- }
-
#[inline]
unsafe fn key(&self) -> imp::Key {
match self.key.load(Ordering::Relaxed) {
@@ -168,6 +155,24 @@ impl StaticKey {
}
unsafe fn lazy_init(&self) -> usize {
+ // Currently the Windows implementation of TLS is pretty hairy, and
+ // it greatly simplifies creation if we just synchronize everything.
+ //
+ // Additionally a 0-index of a tls key hasn't been seen on windows, so
+ // we just simplify the whole branch.
+ if imp::requires_synchronized_create() {
+ static INIT_LOCK: Mutex = Mutex::new();
+ INIT_LOCK.lock();
+ let mut key = self.key.load(Ordering::SeqCst);
+ if key == 0 {
+ key = imp::create(self.dtor) as usize;
+ self.key.store(key, Ordering::SeqCst);
+ }
+ INIT_LOCK.unlock();
+ assert!(key != 0);
+ return key
+ }
+
// POSIX allows the key created here to be 0, but the compare_and_swap
// below relies on using 0 as a sentinel value to check who won the
// race to set the shared TLS key. As far as I know, there is no
@@ -227,7 +232,42 @@ impl Key {
impl Drop for Key {
fn drop(&mut self) {
- unsafe { imp::destroy(self.key) }
+ // Right now Windows doesn't support TLS key destruction, but this also
+ // isn't used anywhere other than tests, so just leak the TLS key.
+ // unsafe { imp::destroy(self.key) }
+ }
+}
+
+pub unsafe fn register_dtor_fallback(t: *mut u8,
+ dtor: unsafe extern fn(*mut u8)) {
+ // The fallback implementation uses a vanilla OS-based TLS key to track
+ // the list of destructors that need to be run for this thread. The key
+ // then has its own destructor which runs all the other destructors.
+ //
+ // The destructor for DTORS is a little special in that it has a `while`
+ // loop to continuously drain the list of registered destructors. It
+ // *should* be the case that this loop always terminates because we
+ // provide the guarantee that a TLS key cannot be set after it is
+ // flagged for destruction.
+
+ static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
+ type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
+ if DTORS.get().is_null() {
+ let v: Box<List> = box Vec::new();
+ DTORS.set(Box::into_raw(v) as *mut u8);
+ }
+ let list: &mut List = &mut *(DTORS.get() as *mut List);
+ list.push((t, dtor));
+
+ unsafe extern fn run_dtors(mut ptr: *mut u8) {
+ while !ptr.is_null() {
+ let list: Box<List> = Box::from_raw(ptr as *mut List);
+ for (ptr, dtor) in list.into_iter() {
+ dtor(ptr);
+ }
+ ptr = DTORS.get();
+ DTORS.set(ptr::null_mut());
+ }
}
}
diff --git a/ctr-std/src/sys_common/util.rs b/ctr-std/src/sys_common/util.rs
index aad0680..a391c7c 100644
--- a/ctr-std/src/sys_common/util.rs
+++ b/ctr-std/src/sys_common/util.rs
@@ -10,29 +10,8 @@
use fmt;
use io::prelude::*;
-use sync::atomic::{self, Ordering};
use sys::stdio::Stderr;
-
-pub fn min_stack() -> usize {
- static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
- match MIN.load(Ordering::SeqCst) {
- 0 => {}
- n => return n - 1,
- }
-
- // NOTE: We don't have env variable support on the 3DS so let's just use the
- // default minimum
-
- // let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
- // let amt = amt.unwrap_or(2 * 1024 * 1024);
-
- let amt = 2 * 1024 * 1024;
-
- // 0 is our sentinel value, so ensure that we'll never see 0 after
- // initialization has run
- MIN.store(amt + 1, Ordering::SeqCst);
- amt
-}
+use thread;
pub fn dumb_print(args: fmt::Arguments) {
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
@@ -47,3 +26,9 @@ pub fn abort(args: fmt::Arguments) -> ! {
dumb_print(format_args!("fatal runtime error: {}\n", args));
unsafe { ::sys::abort_internal(); }
}
+
+#[allow(dead_code)] // stack overflow detection not enabled on all platforms
+pub unsafe fn report_overflow() {
+ dumb_print(format_args!("\nthread '{}' has overflowed its stack\n",
+ thread::current().name().unwrap_or("<unknown>")));
+}
diff --git a/ctr-std/src/sys_common/wtf8.rs b/ctr-std/src/sys_common/wtf8.rs
new file mode 100644
index 0000000..46d554d
--- /dev/null
+++ b/ctr-std/src/sys_common/wtf8.rs
@@ -0,0 +1,1284 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! Implementation of [the WTF-8 encoding](https://simonsapin.github.io/wtf-8/).
+//!
+//! This library uses Rust’s type system to maintain
+//! [well-formedness](https://simonsapin.github.io/wtf-8/#well-formed),
+//! like the `String` and `&str` types do for UTF-8.
+//!
+//! Since [WTF-8 must not be used
+//! for interchange](https://simonsapin.github.io/wtf-8/#intended-audience),
+//! this library deliberately does not provide access to the underlying bytes
+//! of WTF-8 strings,
+//! nor can it decode WTF-8 from arbitrary bytes.
+//! WTF-8 strings can be obtained from UTF-8, UTF-16, or code points.
+
+// this module is imported from @SimonSapin's repo and has tons of dead code on
+// unix (it's mostly used on windows), so don't worry about dead code here.
+#![allow(dead_code)]
+
+use core::str::next_code_point;
+
+use ascii::*;
+use borrow::Cow;
+use char;
+use fmt;
+use hash::{Hash, Hasher};
+use iter::FromIterator;
+use mem;
+use ops;
+use rc::Rc;
+use slice;
+use str;
+use sync::Arc;
+use sys_common::AsInner;
+
+const UTF8_REPLACEMENT_CHARACTER: &'static str = "\u{FFFD}";
+
+/// A Unicode code point: from U+0000 to U+10FFFF.
+///
+/// Compare with the `char` type,
+/// which represents a Unicode scalar value:
+/// a code point that is not a surrogate (U+D800 to U+DFFF).
+#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
+pub struct CodePoint {
+ value: u32
+}
+
+/// Format the code point as `U+` followed by four to six hexadecimal digits.
+/// Example: `U+1F4A9`
+impl fmt::Debug for CodePoint {
+ #[inline]
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(formatter, "U+{:04X}", self.value)
+ }
+}
+
+impl CodePoint {
+ /// Unsafely creates a new `CodePoint` without checking the value.
+ ///
+ /// Only use when `value` is known to be less than or equal to 0x10FFFF.
+ #[inline]
+ pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint {
+ CodePoint { value: value }
+ }
+
+ /// Creates a new `CodePoint` if the value is a valid code point.
+ ///
+ /// Returns `None` if `value` is above 0x10FFFF.
+ #[inline]
+ pub fn from_u32(value: u32) -> Option<CodePoint> {
+ match value {
+ 0 ... 0x10FFFF => Some(CodePoint { value: value }),
+ _ => None
+ }
+ }
+
+ /// Creates a new `CodePoint` from a `char`.
+ ///
+ /// Since all Unicode scalar values are code points, this always succeeds.
+ #[inline]
+ pub fn from_char(value: char) -> CodePoint {
+ CodePoint { value: value as u32 }
+ }
+
+ /// Returns the numeric value of the code point.
+ #[inline]
+ pub fn to_u32(&self) -> u32 {
+ self.value
+ }
+
+ /// Optionally returns a Unicode scalar value for the code point.
+ ///
+ /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF).
+ #[inline]
+ pub fn to_char(&self) -> Option<char> {
+ match self.value {
+ 0xD800 ... 0xDFFF => None,
+ _ => Some(unsafe { char::from_u32_unchecked(self.value) })
+ }
+ }
+
+ /// Returns a Unicode scalar value for the code point.
+ ///
+ /// Returns `'\u{FFFD}'` (the replacement character “�”)
+ /// if the code point is a surrogate (from U+D800 to U+DFFF).
+ #[inline]
+ pub fn to_char_lossy(&self) -> char {
+ self.to_char().unwrap_or('\u{FFFD}')
+ }
+}
+
+/// An owned, growable string of well-formed WTF-8 data.
+///
+/// Similar to `String`, but can additionally contain surrogate code points
+/// if they’re not in a surrogate pair.
+#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)]
+pub struct Wtf8Buf {
+ bytes: Vec<u8>
+}
+
+impl ops::Deref for Wtf8Buf {
+ type Target = Wtf8;
+
+ fn deref(&self) -> &Wtf8 {
+ self.as_slice()
+ }
+}
+
+impl ops::DerefMut for Wtf8Buf {
+ fn deref_mut(&mut self) -> &mut Wtf8 {
+ self.as_mut_slice()
+ }
+}
+
+/// Format the string with double quotes,
+/// and surrogates as `\u` followed by four hexadecimal digits.
+/// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800]
+impl fmt::Debug for Wtf8Buf {
+ #[inline]
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fmt::Debug::fmt(&**self, formatter)
+ }
+}
+
+impl Wtf8Buf {
+ /// Creates a new, empty WTF-8 string.
+ #[inline]
+ pub fn new() -> Wtf8Buf {
+ Wtf8Buf { bytes: Vec::new() }
+ }
+
+ /// Creates a new, empty WTF-8 string with pre-allocated capacity for `n` bytes.
+ #[inline]
+ pub fn with_capacity(n: usize) -> Wtf8Buf {
+ Wtf8Buf { bytes: Vec::with_capacity(n) }
+ }
+
+ /// Creates a WTF-8 string from a UTF-8 `String`.
+ ///
+ /// This takes ownership of the `String` and does not copy.
+ ///
+ /// Since WTF-8 is a superset of UTF-8, this always succeeds.
+ #[inline]
+ pub fn from_string(string: String) -> Wtf8Buf {
+ Wtf8Buf { bytes: string.into_bytes() }
+ }
+
+ /// Creates a WTF-8 string from a UTF-8 `&str` slice.
+ ///
+ /// This copies the content of the slice.
+ ///
+ /// Since WTF-8 is a superset of UTF-8, this always succeeds.
+ #[inline]
+ pub fn from_str(str: &str) -> Wtf8Buf {
+ Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()) }
+ }
+
+ pub fn clear(&mut self) {
+ self.bytes.clear()
+ }
+
+ /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units.
+ ///
+ /// This is lossless: calling `.encode_wide()` on the resulting string
+ /// will always return the original code units.
+ pub fn from_wide(v: &[u16]) -> Wtf8Buf {
+ let mut string = Wtf8Buf::with_capacity(v.len());
+ for item in char::decode_utf16(v.iter().cloned()) {
+ match item {
+ Ok(ch) => string.push_char(ch),
+ Err(surrogate) => {
+ let surrogate = surrogate.unpaired_surrogate();
+ // Surrogates are known to be in the code point range.
+ let code_point = unsafe {
+ CodePoint::from_u32_unchecked(surrogate as u32)
+ };
+ // Skip the WTF-8 concatenation check,
+ // surrogate pairs are already decoded by decode_utf16
+ string.push_code_point_unchecked(code_point)
+ }
+ }
+ }
+ string
+ }
+
+ /// Copied from String::push
+ /// This does **not** include the WTF-8 concatenation check.
+ fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
+ let c = unsafe {
+ char::from_u32_unchecked(code_point.value)
+ };
+ let mut bytes = [0; 4];
+ let bytes = c.encode_utf8(&mut bytes).as_bytes();
+ self.bytes.extend_from_slice(bytes)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &Wtf8 {
+ unsafe { Wtf8::from_bytes_unchecked(&self.bytes) }
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut Wtf8 {
+ unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) }
+ }
+
+ /// Reserves capacity for at least `additional` more bytes to be inserted
+ /// in the given `Wtf8Buf`.
+ /// The collection may reserve more space to avoid frequent reallocations.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the new capacity overflows `usize`.
+ #[inline]
+ pub fn reserve(&mut self, additional: usize) {
+ self.bytes.reserve(additional)
+ }
+
+ #[inline]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.bytes.reserve_exact(additional)
+ }
+
+ #[inline]
+ pub fn shrink_to_fit(&mut self) {
+ self.bytes.shrink_to_fit()
+ }
+
+ /// Returns the number of bytes that this string buffer can hold without reallocating.
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.bytes.capacity()
+ }
+
+ /// Append a UTF-8 slice at the end of the string.
+ #[inline]
+ pub fn push_str(&mut self, other: &str) {
+ self.bytes.extend_from_slice(other.as_bytes())
+ }
+
+ /// Append a WTF-8 slice at the end of the string.
+ ///
+ /// This replaces newly paired surrogates at the boundary
+ /// with a supplementary code point,
+ /// like concatenating ill-formed UTF-16 strings effectively would.
+ #[inline]
+ pub fn push_wtf8(&mut self, other: &Wtf8) {
+ match ((&*self).final_lead_surrogate(), other.initial_trail_surrogate()) {
+ // Replace newly paired surrogates by a supplementary code point.
+ (Some(lead), Some(trail)) => {
+ let len_without_lead_surrogate = self.len() - 3;
+ self.bytes.truncate(len_without_lead_surrogate);
+ let other_without_trail_surrogate = &other.bytes[3..];
+ // 4 bytes for the supplementary code point
+ self.bytes.reserve(4 + other_without_trail_surrogate.len());
+ self.push_char(decode_surrogate_pair(lead, trail));
+ self.bytes.extend_from_slice(other_without_trail_surrogate);
+ }
+ _ => self.bytes.extend_from_slice(&other.bytes)
+ }
+ }
+
+ /// Append a Unicode scalar value at the end of the string.
+ #[inline]
+ pub fn push_char(&mut self, c: char) {
+ self.push_code_point_unchecked(CodePoint::from_char(c))
+ }
+
+ /// Append a code point at the end of the string.
+ ///
+ /// This replaces newly paired surrogates at the boundary
+ /// with a supplementary code point,
+ /// like concatenating ill-formed UTF-16 strings effectively would.
+ #[inline]
+ pub fn push(&mut self, code_point: CodePoint) {
+ if let trail @ 0xDC00...0xDFFF = code_point.to_u32() {
+ if let Some(lead) = (&*self).final_lead_surrogate() {
+ let len_without_lead_surrogate = self.len() - 3;
+ self.bytes.truncate(len_without_lead_surrogate);
+ self.push_char(decode_surrogate_pair(lead, trail as u16));
+ return
+ }
+ }
+
+ // No newly paired surrogates at the boundary.
+ self.push_code_point_unchecked(code_point)
+ }
+
+ /// Shortens a string to the specified length.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `new_len` > current length,
+ /// or if `new_len` is not a code point boundary.
+ #[inline]
+ pub fn truncate(&mut self, new_len: usize) {
+ assert!(is_code_point_boundary(self, new_len));
+ self.bytes.truncate(new_len)
+ }
+
+ /// Consumes the WTF-8 string and tries to convert it to UTF-8.
+ ///
+ /// This does not copy the data.
+ ///
+ /// If the contents are not well-formed UTF-8
+ /// (that is, if the string contains surrogates),
+ /// the original WTF-8 string is returned instead.
+ pub fn into_string(self) -> Result<String, Wtf8Buf> {
+ match self.next_surrogate(0) {
+ None => Ok(unsafe { String::from_utf8_unchecked(self.bytes) }),
+ Some(_) => Err(self),
+ }
+ }
+
+ /// Consumes the WTF-8 string and converts it lossily to UTF-8.
+ ///
+ /// This does not copy the data (but may overwrite parts of it in place).
+ ///
+ /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”)
+ pub fn into_string_lossy(mut self) -> String {
+ let mut pos = 0;
+ loop {
+ match self.next_surrogate(pos) {
+ Some((surrogate_pos, _)) => {
+ pos = surrogate_pos + 3;
+ self.bytes[surrogate_pos..pos]
+ .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
+ },
+ None => return unsafe { String::from_utf8_unchecked(self.bytes) }
+ }
+ }
+ }
+
+ /// Converts this `Wtf8Buf` into a boxed `Wtf8`.
+ #[inline]
+ pub fn into_box(self) -> Box<Wtf8> {
+ unsafe { mem::transmute(self.bytes.into_boxed_slice()) }
+ }
+
+ /// Converts a `Box<Wtf8>` into a `Wtf8Buf`.
+ pub fn from_box(boxed: Box<Wtf8>) -> Wtf8Buf {
+ let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) };
+ Wtf8Buf { bytes: bytes.into_vec() }
+ }
+}
+
+/// Create a new WTF-8 string from an iterator of code points.
+///
+/// This replaces surrogate code point pairs with supplementary code points,
+/// like concatenating ill-formed UTF-16 strings effectively would.
+impl FromIterator<CodePoint> for Wtf8Buf {
+ fn from_iter<T: IntoIterator<Item=CodePoint>>(iter: T) -> Wtf8Buf {
+ let mut string = Wtf8Buf::new();
+ string.extend(iter);
+ string
+ }
+}
+
+/// Append code points from an iterator to the string.
+///
+/// This replaces surrogate code point pairs with supplementary code points,
+/// like concatenating ill-formed UTF-16 strings effectively would.
+impl Extend<CodePoint> for Wtf8Buf {
+ fn extend<T: IntoIterator<Item=CodePoint>>(&mut self, iter: T) {
+ let iterator = iter.into_iter();
+ let (low, _high) = iterator.size_hint();
+ // Lower bound of one byte per code point (ASCII only)
+ self.bytes.reserve(low);
+ for code_point in iterator {
+ self.push(code_point);
+ }
+ }
+}
+
+/// A borrowed slice of well-formed WTF-8 data.
+///
+/// Similar to `&str`, but can additionally contain surrogate code points
+/// if they’re not in a surrogate pair.
+#[derive(Eq, Ord, PartialEq, PartialOrd)]
+pub struct Wtf8 {
+ bytes: [u8]
+}
+
+impl AsInner<[u8]> for Wtf8 {
+ fn as_inner(&self) -> &[u8] { &self.bytes }
+}
+
+/// Format the slice with double quotes,
+/// and surrogates as `\u` followed by four hexadecimal digits.
+/// Example: `"a\u{D800}"` for a slice with code points [U+0061, U+D800]
+impl fmt::Debug for Wtf8 {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fn write_str_escaped(f: &mut fmt::Formatter, s: &str) -> fmt::Result {
+ use fmt::Write;
+ for c in s.chars().flat_map(|c| c.escape_debug()) {
+ f.write_char(c)?
+ }
+ Ok(())
+ }
+
+ formatter.write_str("\"")?;
+ let mut pos = 0;
+ loop {
+ match self.next_surrogate(pos) {
+ None => break,
+ Some((surrogate_pos, surrogate)) => {
+ write_str_escaped(
+ formatter,
+ unsafe { str::from_utf8_unchecked(
+ &self.bytes[pos .. surrogate_pos]
+ )},
+ )?;
+ write!(formatter, "\\u{{{:x}}}", surrogate)?;
+ pos = surrogate_pos + 3;
+ }
+ }
+ }
+ write_str_escaped(
+ formatter,
+ unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) },
+ )?;
+ formatter.write_str("\"")
+ }
+}
+
+impl fmt::Display for Wtf8 {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let wtf8_bytes = &self.bytes;
+ let mut pos = 0;
+ loop {
+ match self.next_surrogate(pos) {
+ Some((surrogate_pos, _)) => {
+ formatter.write_str(unsafe {
+ str::from_utf8_unchecked(&wtf8_bytes[pos .. surrogate_pos])
+ })?;
+ formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?;
+ pos = surrogate_pos + 3;
+ },
+ None => {
+ let s = unsafe {
+ str::from_utf8_unchecked(&wtf8_bytes[pos..])
+ };
+ if pos == 0 {
+ return s.fmt(formatter)
+ } else {
+ return formatter.write_str(s)
+ }
+ }
+ }
+ }
+ }
+}
+
+impl Wtf8 {
+ /// Creates a WTF-8 slice from a UTF-8 `&str` slice.
+ ///
+ /// Since WTF-8 is a superset of UTF-8, this always succeeds.
+ #[inline]
+ pub fn from_str(value: &str) -> &Wtf8 {
+ unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) }
+ }
+
+ /// Creates a WTF-8 slice from a WTF-8 byte slice.
+ ///
+ /// Since the byte slice is not checked for valid WTF-8, this functions is
+ /// marked unsafe.
+ #[inline]
+ unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 {
+ mem::transmute(value)
+ }
+
+ /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice.
+ ///
+ /// Since the byte slice is not checked for valid WTF-8, this functions is
+ /// marked unsafe.
+ #[inline]
+ unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 {
+ mem::transmute(value)
+ }
+
+ /// Returns the length, in WTF-8 bytes.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.bytes.len()
+ }
+
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.bytes.is_empty()
+ }
+
+ /// Returns the code point at `position` if it is in the ASCII range,
+ /// or `b'\xFF' otherwise.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `position` is beyond the end of the string.
+ #[inline]
+ pub fn ascii_byte_at(&self, position: usize) -> u8 {
+ match self.bytes[position] {
+ ascii_byte @ 0x00 ... 0x7F => ascii_byte,
+ _ => 0xFF
+ }
+ }
+
+ /// Returns an iterator for the string’s code points.
+ #[inline]
+ pub fn code_points(&self) -> Wtf8CodePoints {
+ Wtf8CodePoints { bytes: self.bytes.iter() }
+ }
+
+ /// Tries to convert the string to UTF-8 and return a `&str` slice.
+ ///
+ /// Returns `None` if the string contains surrogates.
+ ///
+ /// This does not copy the data.
+ #[inline]
+ pub fn as_str(&self) -> Option<&str> {
+ // Well-formed WTF-8 is also well-formed UTF-8
+ // if and only if it contains no surrogate.
+ match self.next_surrogate(0) {
+ None => Some(unsafe { str::from_utf8_unchecked(&self.bytes) }),
+ Some(_) => None,
+ }
+ }
+
+ /// Lossily converts the string to UTF-8.
+ /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8.
+ ///
+ /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”).
+ ///
+ /// This only copies the data if necessary (if it contains any surrogate).
+ pub fn to_string_lossy(&self) -> Cow<str> {
+ let surrogate_pos = match self.next_surrogate(0) {
+ None => return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }),
+ Some((pos, _)) => pos,
+ };
+ let wtf8_bytes = &self.bytes;
+ let mut utf8_bytes = Vec::with_capacity(self.len());
+ utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]);
+ utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
+ let mut pos = surrogate_pos + 3;
+ loop {
+ match self.next_surrogate(pos) {
+ Some((surrogate_pos, _)) => {
+ utf8_bytes.extend_from_slice(&wtf8_bytes[pos .. surrogate_pos]);
+ utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
+ pos = surrogate_pos + 3;
+ },
+ None => {
+ utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]);
+ return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) })
+ }
+ }
+ }
+ }
+
+ /// Converts the WTF-8 string to potentially ill-formed UTF-16
+ /// and return an iterator of 16-bit code units.
+ ///
+ /// This is lossless:
+ /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units
+ /// would always return the original WTF-8 string.
+ #[inline]
+ pub fn encode_wide(&self) -> EncodeWide {
+ EncodeWide { code_points: self.code_points(), extra: 0 }
+ }
+
+ #[inline]
+ fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> {
+ let mut iter = self.bytes[pos..].iter();
+ loop {
+ let b = *iter.next()?;
+ if b < 0x80 {
+ pos += 1;
+ } else if b < 0xE0 {
+ iter.next();
+ pos += 2;
+ } else if b == 0xED {
+ match (iter.next(), iter.next()) {
+ (Some(&b2), Some(&b3)) if b2 >= 0xA0 => {
+ return Some((pos, decode_surrogate(b2, b3)))
+ }
+ _ => pos += 3
+ }
+ } else if b < 0xF0 {
+ iter.next();
+ iter.next();
+ pos += 3;
+ } else {
+ iter.next();
+ iter.next();
+ iter.next();
+ pos += 4;
+ }
+ }
+ }
+
+ #[inline]
+ fn final_lead_surrogate(&self) -> Option<u16> {
+ let len = self.len();
+ if len < 3 {
+ return None
+ }
+ match &self.bytes[(len - 3)..] {
+ &[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)),
+ _ => None
+ }
+ }
+
+ #[inline]
+ fn initial_trail_surrogate(&self) -> Option<u16> {
+ let len = self.len();
+ if len < 3 {
+ return None
+ }
+ match &self.bytes[..3] {
+ &[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)),
+ _ => None
+ }
+ }
+
+ /// Boxes this `Wtf8`.
+ #[inline]
+ pub fn into_box(&self) -> Box<Wtf8> {
+ let boxed: Box<[u8]> = self.bytes.into();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ /// Creates a boxed, empty `Wtf8`.
+ pub fn empty_box() -> Box<Wtf8> {
+ let boxed: Box<[u8]> = Default::default();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Wtf8> {
+ let arc: Arc<[u8]> = Arc::from(&self.bytes);
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) }
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Wtf8> {
+ let rc: Rc<[u8]> = Rc::from(&self.bytes);
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) }
+ }
+}
+
+
+/// Return a slice of the given string for the byte range [`begin`..`end`).
+///
+/// # Panics
+///
+/// Panics when `begin` and `end` do not point to code point boundaries,
+/// or point beyond the end of the string.
+impl ops::Index<ops::Range<usize>> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, range: ops::Range<usize>) -> &Wtf8 {
+ // is_code_point_boundary checks that the index is in [0, .len()]
+ if range.start <= range.end &&
+ is_code_point_boundary(self, range.start) &&
+ is_code_point_boundary(self, range.end) {
+ unsafe { slice_unchecked(self, range.start, range.end) }
+ } else {
+ slice_error_fail(self, range.start, range.end)
+ }
+ }
+}
+
+/// Return a slice of the given string from byte `begin` to its end.
+///
+/// # Panics
+///
+/// Panics when `begin` is not at a code point boundary,
+/// or is beyond the end of the string.
+impl ops::Index<ops::RangeFrom<usize>> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, range: ops::RangeFrom<usize>) -> &Wtf8 {
+ // is_code_point_boundary checks that the index is in [0, .len()]
+ if is_code_point_boundary(self, range.start) {
+ unsafe { slice_unchecked(self, range.start, self.len()) }
+ } else {
+ slice_error_fail(self, range.start, self.len())
+ }
+ }
+}
+
+/// Return a slice of the given string from its beginning to byte `end`.
+///
+/// # Panics
+///
+/// Panics when `end` is not at a code point boundary,
+/// or is beyond the end of the string.
+impl ops::Index<ops::RangeTo<usize>> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, range: ops::RangeTo<usize>) -> &Wtf8 {
+ // is_code_point_boundary checks that the index is in [0, .len()]
+ if is_code_point_boundary(self, range.end) {
+ unsafe { slice_unchecked(self, 0, range.end) }
+ } else {
+ slice_error_fail(self, 0, range.end)
+ }
+ }
+}
+
+impl ops::Index<ops::RangeFull> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, _range: ops::RangeFull) -> &Wtf8 {
+ self
+ }
+}
+
+#[inline]
+fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 {
+ // The first byte is assumed to be 0xED
+ 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F
+}
+
+#[inline]
+fn decode_surrogate_pair(lead: u16, trail: u16) -> char {
+ let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32);
+ unsafe { char::from_u32_unchecked(code_point) }
+}
+
+/// Copied from core::str::StrPrelude::is_char_boundary
+#[inline]
+pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool {
+ if index == slice.len() { return true; }
+ match slice.bytes.get(index) {
+ None => false,
+ Some(&b) => b < 128 || b >= 192,
+ }
+}
+
+/// Copied from core::str::raw::slice_unchecked
+#[inline]
+pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 {
+ // memory layout of an &[u8] and &Wtf8 are the same
+ Wtf8::from_bytes_unchecked(slice::from_raw_parts(
+ s.bytes.as_ptr().offset(begin as isize),
+ end - begin
+ ))
+}
+
+/// Copied from core::str::raw::slice_error_fail
+#[inline(never)]
+pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! {
+ assert!(begin <= end);
+ panic!("index {} and/or {} in `{:?}` do not lie on character boundary",
+ begin, end, s);
+}
+
+/// Iterator for the code points of a WTF-8 string.
+///
+/// Created with the method `.code_points()`.
+#[derive(Clone)]
+pub struct Wtf8CodePoints<'a> {
+ bytes: slice::Iter<'a, u8>
+}
+
+impl<'a> Iterator for Wtf8CodePoints<'a> {
+ type Item = CodePoint;
+
+ #[inline]
+ fn next(&mut self) -> Option<CodePoint> {
+ next_code_point(&mut self.bytes).map(|c| CodePoint { value: c })
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.bytes.len();
+ (len.saturating_add(3) / 4, Some(len))
+ }
+}
+
+/// Generates a wide character sequence for potentially ill-formed UTF-16.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct EncodeWide<'a> {
+ code_points: Wtf8CodePoints<'a>,
+ extra: u16
+}
+
+// Copied from libunicode/u_str.rs
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for EncodeWide<'a> {
+ type Item = u16;
+
+ #[inline]
+ fn next(&mut self) -> Option<u16> {
+ if self.extra != 0 {
+ let tmp = self.extra;
+ self.extra = 0;
+ return Some(tmp);
+ }
+
+ let mut buf = [0; 2];
+ self.code_points.next().map(|code_point| {
+ let c = unsafe {
+ char::from_u32_unchecked(code_point.value)
+ };
+ let n = c.encode_utf16(&mut buf).len();
+ if n == 2 {
+ self.extra = buf[1];
+ }
+ buf[0]
+ })
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (low, high) = self.code_points.size_hint();
+ // every code point gets either one u16 or two u16,
+ // so this iterator is between 1 or 2 times as
+ // long as the underlying iterator.
+ (low, high.and_then(|n| n.checked_mul(2)))
+ }
+}
+
+impl Hash for CodePoint {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.value.hash(state)
+ }
+}
+
+impl Hash for Wtf8Buf {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ state.write(&self.bytes);
+ 0xfeu8.hash(state)
+ }
+}
+
+impl Hash for Wtf8 {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ state.write(&self.bytes);
+ 0xfeu8.hash(state)
+ }
+}
+
+impl AsciiExt for Wtf8 {
+ type Owned = Wtf8Buf;
+
+ fn is_ascii(&self) -> bool {
+ self.bytes.is_ascii()
+ }
+ fn to_ascii_uppercase(&self) -> Wtf8Buf {
+ Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() }
+ }
+ fn to_ascii_lowercase(&self) -> Wtf8Buf {
+ Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() }
+ }
+ fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool {
+ self.bytes.eq_ignore_ascii_case(&other.bytes)
+ }
+
+ fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() }
+ fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() }
+}
+
+#[cfg(test)]
+mod tests {
+ use borrow::Cow;
+ use super::*;
+
+ #[test]
+ fn code_point_from_u32() {
+ assert!(CodePoint::from_u32(0).is_some());
+ assert!(CodePoint::from_u32(0xD800).is_some());
+ assert!(CodePoint::from_u32(0x10FFFF).is_some());
+ assert!(CodePoint::from_u32(0x110000).is_none());
+ }
+
+ #[test]
+ fn code_point_to_u32() {
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+ assert_eq!(c(0).to_u32(), 0);
+ assert_eq!(c(0xD800).to_u32(), 0xD800);
+ assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF);
+ }
+
+ #[test]
+ fn code_point_from_char() {
+ assert_eq!(CodePoint::from_char('a').to_u32(), 0x61);
+ assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9);
+ }
+
+ #[test]
+ fn code_point_to_string() {
+ assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061");
+ assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9");
+ }
+
+ #[test]
+ fn code_point_to_char() {
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+ assert_eq!(c(0x61).to_char(), Some('a'));
+ assert_eq!(c(0x1F4A9).to_char(), Some('💩'));
+ assert_eq!(c(0xD800).to_char(), None);
+ }
+
+ #[test]
+ fn code_point_to_char_lossy() {
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+ assert_eq!(c(0x61).to_char_lossy(), 'a');
+ assert_eq!(c(0x1F4A9).to_char_lossy(), '💩');
+ assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}');
+ }
+
+ #[test]
+ fn wtf8buf_new() {
+ assert_eq!(Wtf8Buf::new().bytes, b"");
+ }
+
+ #[test]
+ fn wtf8buf_from_str() {
+ assert_eq!(Wtf8Buf::from_str("").bytes, b"");
+ assert_eq!(Wtf8Buf::from_str("aé 💩").bytes,
+ b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_from_string() {
+ assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b"");
+ assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes,
+ b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_from_wide() {
+ assert_eq!(Wtf8Buf::from_wide(&[]).bytes, b"");
+ assert_eq!(Wtf8Buf::from_wide(
+ &[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]).bytes,
+ b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_push_str() {
+ let mut string = Wtf8Buf::new();
+ assert_eq!(string.bytes, b"");
+ string.push_str("aé 💩");
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_push_char() {
+ let mut string = Wtf8Buf::from_str("aé ");
+ assert_eq!(string.bytes, b"a\xC3\xA9 ");
+ string.push_char('💩');
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_push() {
+ let mut string = Wtf8Buf::from_str("aé ");
+ assert_eq!(string.bytes, b"a\xC3\xA9 ");
+ string.push(CodePoint::from_char('💩'));
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD83D)); // lead
+ string.push(c(0xDCA9)); // trail
+ assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD83D)); // lead
+ string.push(c(0x20)); // not surrogate
+ string.push(c(0xDCA9)); // trail
+ assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD800)); // lead
+ string.push(c(0xDBFF)); // lead
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD800)); // lead
+ string.push(c(0xE000)); // not surrogate
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD7FF)); // not surrogate
+ string.push(c(0xDC00)); // trail
+ assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0x61)); // not surrogate, < 3 bytes
+ string.push(c(0xDC00)); // trail
+ assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xDC00)); // trail
+ assert_eq!(string.bytes, b"\xED\xB0\x80");
+ }
+
+ #[test]
+ fn wtf8buf_push_wtf8() {
+ let mut string = Wtf8Buf::from_str("aé");
+ assert_eq!(string.bytes, b"a\xC3\xA9");
+ string.push_wtf8(Wtf8::from_str(" 💩"));
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ fn w(v: &[u8]) -> &Wtf8 { unsafe { Wtf8::from_bytes_unchecked(v) } }
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
+ string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
+ assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
+ string.push_wtf8(w(b" ")); // not surrogate
+ string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
+ assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\x80")); // lead
+ string.push_wtf8(w(b"\xED\xAF\xBF")); // lead
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\x80")); // lead
+ string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate
+ string.push_wtf8(w(b"\xED\xB0\x80")); // trail
+ assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes
+ string.push_wtf8(w(b"\xED\xB0\x80")); // trail
+ assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xB0\x80")); // trail
+ assert_eq!(string.bytes, b"\xED\xB0\x80");
+ }
+
+ #[test]
+ fn wtf8buf_truncate() {
+ let mut string = Wtf8Buf::from_str("aé");
+ string.truncate(1);
+ assert_eq!(string.bytes, b"a");
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8buf_truncate_fail_code_point_boundary() {
+ let mut string = Wtf8Buf::from_str("aé");
+ string.truncate(2);
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8buf_truncate_fail_longer() {
+ let mut string = Wtf8Buf::from_str("aé");
+ string.truncate(4);
+ }
+
+ #[test]
+ fn wtf8buf_into_string() {
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩")));
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(string.clone().into_string(), Err(string));
+ }
+
+ #[test]
+ fn wtf8buf_into_string_lossy() {
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩"));
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�"));
+ }
+
+ #[test]
+ fn wtf8buf_from_iterator() {
+ fn f(values: &[u32]) -> Wtf8Buf {
+ values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::<Wtf8Buf>()
+ }
+ assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+ assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+ assert_eq!(f(&[0xD800, 0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+ assert_eq!(f(&[0xD800, 0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
+ assert_eq!(f(&[0xD7FF, 0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+ assert_eq!(f(&[0x61, 0xDC00]).bytes, b"\x61\xED\xB0\x80");
+ assert_eq!(f(&[0xDC00]).bytes, b"\xED\xB0\x80");
+ }
+
+ #[test]
+ fn wtf8buf_extend() {
+ fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf {
+ fn c(value: &u32) -> CodePoint { CodePoint::from_u32(*value).unwrap() }
+ let mut string = initial.iter().map(c).collect::<Wtf8Buf>();
+ string.extend(extended.iter().map(c));
+ string
+ }
+
+ assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes,
+ b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+ assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+ assert_eq!(e(&[0xD800], &[0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+ assert_eq!(e(&[0xD800], &[0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
+ assert_eq!(e(&[0xD7FF], &[0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+ assert_eq!(e(&[0x61], &[0xDC00]).bytes, b"\x61\xED\xB0\x80");
+ assert_eq!(e(&[], &[0xDC00]).bytes, b"\xED\xB0\x80");
+ }
+
+ #[test]
+ fn wtf8buf_show() {
+ let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r");
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
+ }
+
+ #[test]
+ fn wtf8buf_as_slice() {
+ assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé"));
+ }
+
+ #[test]
+ fn wtf8buf_show_str() {
+ let text = "a\té 💩\r";
+ let string = Wtf8Buf::from_str(text);
+ assert_eq!(format!("{:?}", text), format!("{:?}", string));
+ }
+
+ #[test]
+ fn wtf8_from_str() {
+ assert_eq!(&Wtf8::from_str("").bytes, b"");
+ assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8_len() {
+ assert_eq!(Wtf8::from_str("").len(), 0);
+ assert_eq!(Wtf8::from_str("aé 💩").len(), 8);
+ }
+
+ #[test]
+ fn wtf8_slice() {
+ assert_eq!(&Wtf8::from_str("aé 💩")[1.. 4].bytes, b"\xC3\xA9 ");
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8_slice_not_code_point_boundary() {
+ &Wtf8::from_str("aé 💩")[2.. 4];
+ }
+
+ #[test]
+ fn wtf8_slice_from() {
+ assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8_slice_from_not_code_point_boundary() {
+ &Wtf8::from_str("aé 💩")[2..];
+ }
+
+ #[test]
+ fn wtf8_slice_to() {
+ assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 ");
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8_slice_to_not_code_point_boundary() {
+ &Wtf8::from_str("aé 💩")[5..];
+ }
+
+ #[test]
+ fn wtf8_ascii_byte_at() {
+ let slice = Wtf8::from_str("aé 💩");
+ assert_eq!(slice.ascii_byte_at(0), b'a');
+ assert_eq!(slice.ascii_byte_at(1), b'\xFF');
+ assert_eq!(slice.ascii_byte_at(2), b'\xFF');
+ assert_eq!(slice.ascii_byte_at(3), b' ');
+ assert_eq!(slice.ascii_byte_at(4), b'\xFF');
+ }
+
+ #[test]
+ fn wtf8_code_points() {
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+ fn cp(string: &Wtf8Buf) -> Vec<Option<char>> {
+ string.code_points().map(|c| c.to_char()).collect::<Vec<_>>()
+ }
+ let mut string = Wtf8Buf::from_str("é ");
+ assert_eq!(cp(&string), [Some('é'), Some(' ')]);
+ string.push(c(0xD83D));
+ assert_eq!(cp(&string), [Some('é'), Some(' '), None]);
+ string.push(c(0xDCA9));
+ assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]);
+ }
+
+ #[test]
+ fn wtf8_as_str() {
+ assert_eq!(Wtf8::from_str("").as_str(), Some(""));
+ assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩"));
+ let mut string = Wtf8Buf::new();
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(string.as_str(), None);
+ }
+
+ #[test]
+ fn wtf8_to_string_lossy() {
+ assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed(""));
+ assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩"));
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ let expected: Cow<str> = Cow::Owned(String::from("aé 💩�"));
+ assert_eq!(string.to_string_lossy(), expected);
+ }
+
+ #[test]
+ fn wtf8_display() {
+ fn d(b: &[u8]) -> String {
+ format!("{}", &unsafe { Wtf8::from_bytes_unchecked(b) })
+ }
+
+ assert_eq!("", d("".as_bytes()));
+ assert_eq!("aé 💩", d("aé 💩".as_bytes()));
+
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!("aé 💩�", d(string.as_inner()));
+ }
+
+ #[test]
+ fn wtf8_encode_wide() {
+ let mut string = Wtf8Buf::from_str("aé ");
+ string.push(CodePoint::from_u32(0xD83D).unwrap());
+ string.push_char('💩');
+ assert_eq!(string.encode_wide().collect::<Vec<_>>(),
+ vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]);
+ }
+}
diff --git a/ctr-std/src/termination.rs b/ctr-std/src/termination.rs
new file mode 100644
index 0000000..e4a577e
--- /dev/null
+++ b/ctr-std/src/termination.rs
@@ -0,0 +1,80 @@
+// Copyright 2017 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 error::Error;
+// TODO: Add these consts to the libc crate for newlib
+mod exit {
+ pub const SUCCESS: i32 = 0;
+ pub const FAILURE: i32 = 1;
+}
+
+/// A trait for implementing arbitrary return types in the `main` function.
+///
+/// The c-main function only supports to return integers as return type.
+/// So, every type implementing the `Termination` trait has to be converted
+/// to an integer.
+///
+/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate
+/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
+#[cfg_attr(not(test), lang = "termination")]
+#[unstable(feature = "termination_trait", issue = "43301")]
+#[rustc_on_unimplemented =
+ "`main` can only return types that implement {Termination}, not `{Self}`"]
+pub trait Termination {
+ /// Is called to get the representation of the value as status code.
+ /// This status code is returned to the operating system.
+ fn report(self) -> i32;
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+impl Termination for () {
+ fn report(self) -> i32 { exit::SUCCESS }
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+impl<T: Termination, E: Error> Termination for Result<T, E> {
+ fn report(self) -> i32 {
+ match self {
+ Ok(val) => val.report(),
+ Err(err) => {
+ print_error(err);
+ exit::FAILURE
+ }
+ }
+ }
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+fn print_error<E: Error>(err: E) {
+ eprintln!("Error: {}", err.description());
+
+ if let Some(ref err) = err.cause() {
+ eprintln!("Caused by: {}", err.description());
+ }
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+impl Termination for ! {
+ fn report(self) -> i32 { unreachable!(); }
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+impl Termination for bool {
+ fn report(self) -> i32 {
+ if self { exit::SUCCESS } else { exit::FAILURE }
+ }
+}
+
+#[unstable(feature = "termination_trait", issue = "43301")]
+impl Termination for i32 {
+ fn report(self) -> i32 {
+ self
+ }
+}
diff --git a/ctr-std/src/thread/local.rs b/ctr-std/src/thread/local.rs
index 0172f89..fcbca38 100644
--- a/ctr-std/src/thread/local.rs
+++ b/ctr-std/src/thread/local.rs
@@ -31,6 +31,10 @@ use mem;
/// within a thread, and values that implement [`Drop`] get destructed when a
/// thread exits. Some caveats apply, which are explained below.
///
+/// A `LocalKey`'s initializer cannot recursively depend on itself, and using
+/// a `LocalKey` in this way will cause the initializer to infinitely recurse
+/// on the first call to `with`.
+///
/// # Examples
///
/// ```
@@ -91,13 +95,13 @@ pub struct LocalKey<T: 'static> {
//
// Note that the thunk is itself unsafe because the returned lifetime of the
// slot where data lives, `'static`, is not actually valid. The lifetime
- // here is actually `'thread`!
+ // here is actually slightly shorter than the currently running thread!
//
// Although this is an extra layer of indirection, it should in theory be
// trivially devirtualizable by LLVM because the value of `inner` never
// changes and the constant should be readonly within a crate. This mainly
// only runs into problems when TLS statics are exported across crates.
- inner: fn() -> Option<&'static UnsafeCell<Option<T>>>,
+ inner: unsafe fn() -> Option<&'static UnsafeCell<Option<T>>>,
// initialization routine to invoke to create a value
init: fn() -> T,
@@ -157,12 +161,14 @@ macro_rules! thread_local {
issue = "0")]
#[macro_export]
#[allow_internal_unstable]
+#[allow_internal_unsafe]
macro_rules! __thread_local_inner {
- ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
- $(#[$attr])* $vis static $name: $crate::thread::LocalKey<$t> = {
+ (@key $(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
+ {
+ #[inline]
fn __init() -> $t { $init }
- fn __getit() -> $crate::option::Option<
+ unsafe fn __getit() -> $crate::option::Option<
&'static $crate::cell::UnsafeCell<
$crate::option::Option<$t>>>
{
@@ -178,8 +184,14 @@ macro_rules! __thread_local_inner {
__KEY.get()
}
- $crate::thread::LocalKey::new(__getit, __init)
- };
+ unsafe {
+ $crate::thread::LocalKey::new(__getit, __init)
+ }
+ }
+ };
+ ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
+ $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
+ __thread_local_inner!(@key $(#[$attr])* $vis $name, $t, $init);
}
}
@@ -252,11 +264,11 @@ impl<T: 'static> LocalKey<T> {
#[unstable(feature = "thread_local_internals",
reason = "recently added to create a key",
issue = "0")]
- pub const fn new(inner: fn() -> Option<&'static UnsafeCell<Option<T>>>,
- init: fn() -> T) -> LocalKey<T> {
+ pub const unsafe fn new(inner: unsafe fn() -> Option<&'static UnsafeCell<Option<T>>>,
+ init: fn() -> T) -> LocalKey<T> {
LocalKey {
- inner: inner,
- init: init,
+ inner,
+ init,
}
}
@@ -308,7 +320,10 @@ impl<T: 'static> LocalKey<T> {
///
/// Once the initialization expression succeeds, the key transitions to the
/// `Valid` state which will guarantee that future calls to [`with`] will
- /// succeed within the thread.
+ /// succeed within the thread. Some keys might skip the `Uninitialized`
+ /// state altogether and start in the `Valid` state as an optimization
+ /// (e.g. keys initialized with a constant expression), but no guarantees
+ /// are made.
///
/// When a thread exits, each key will be destroyed in turn, and as keys are
/// destroyed they will enter the `Destroyed` state just before the
@@ -391,8 +406,6 @@ pub mod fast {
}
}
- unsafe impl<T> ::marker::Sync for Key<T> { }
-
impl<T> Key<T> {
pub const fn new() -> Key<T> {
Key {
@@ -402,14 +415,12 @@ pub mod fast {
}
}
- pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
- unsafe {
- if mem::needs_drop::<T>() && self.dtor_running.get() {
- return None
- }
- self.register_dtor();
+ pub unsafe fn get(&self) -> Option<&'static UnsafeCell<Option<T>>> {
+ if mem::needs_drop::<T>() && self.dtor_running.get() {
+ return None
}
- Some(&self.inner)
+ self.register_dtor();
+ Some(&*(&self.inner as *const _))
}
unsafe fn register_dtor(&self) {
@@ -478,26 +489,24 @@ pub mod os {
}
}
- pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
- unsafe {
- let ptr = self.os.get() as *mut Value<T>;
- if !ptr.is_null() {
- if ptr as usize == 1 {
- return None
- }
- return Some(&(*ptr).value);
+ pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
+ let ptr = self.os.get() as *mut Value<T>;
+ if !ptr.is_null() {
+ if ptr as usize == 1 {
+ return None
}
-
- // If the lookup returned null, we haven't initialized our own
- // local copy, so do that now.
- let ptr: Box<Value<T>> = box Value {
- key: self,
- value: UnsafeCell::new(None),
- };
- let ptr = Box::into_raw(ptr);
- self.os.set(ptr as *mut u8);
- Some(&(*ptr).value)
+ return Some(&(*ptr).value);
}
+
+ // If the lookup returned null, we haven't initialized our own
+ // local copy, so do that now.
+ let ptr: Box<Value<T>> = box Value {
+ key: self,
+ value: UnsafeCell::new(None),
+ };
+ let ptr = Box::into_raw(ptr);
+ self.os.set(ptr as *mut u8);
+ Some(&(*ptr).value)
}
}
diff --git a/ctr-std/src/thread/mod.rs b/ctr-std/src/thread/mod.rs
index c35676f..ee49bf7 100644
--- a/ctr-std/src/thread/mod.rs
+++ b/ctr-std/src/thread/mod.rs
@@ -25,11 +25,15 @@
//!
//! Fatal logic errors in Rust cause *thread panic*, during which
//! a thread will unwind the stack, running destructors and freeing
-//! owned resources. Thread panic is unrecoverable from within
-//! the panicking thread (i.e. there is no 'try/catch' in Rust), but
-//! the panic may optionally be detected from a different thread. If
-//! the main thread panics, the application will exit with a non-zero
-//! exit code.
+//! owned resources. While not meant as a 'try/catch' mechanism, panics
+//! in Rust can nonetheless be caught (unless compiling with `panic=abort`) with
+//! [`catch_unwind`](../../std/panic/fn.catch_unwind.html) and recovered
+//! from, or alternatively be resumed with
+//! [`resume_unwind`](../../std/panic/fn.resume_unwind.html). If the panic
+//! is not caught the thread will exit, but the panic may optionally be
+//! detected from a different thread with [`join`]. If the main thread panics
+//! without the panic being caught, the application will exit with a
+//! non-zero exit code.
//!
//! When the main thread of a Rust program terminates, the entire program shuts
//! down, even if other threads are still running. However, this module provides
@@ -112,6 +116,29 @@
//! will want to make use of some form of **interior mutability** through the
//! [`Cell`] or [`RefCell`] types.
//!
+//! ## Naming threads
+//!
+//! Threads are able to have associated names for identification purposes. By default, spawned
+//! threads are unnamed. To specify a name for a thread, build the thread with [`Builder`] and pass
+//! the desired thread name to [`Builder::name`]. To retrieve the thread name from within the
+//! thread, use [`Thread::name`]. A couple examples of where the name of a thread gets used:
+//!
+//! * If a panic occurs in a named thread, the thread name will be printed in the panic message.
+//! * The thread name is provided to the OS where applicable (e.g. `pthread_setname_np` in
+//! unix-like platforms).
+//!
+//! ## Stack size
+//!
+//! The default stack size for spawned threads is 2 MiB, though this particular stack size is
+//! subject to change in the future. There are two ways to manually specify the stack size for
+//! spawned threads:
+//!
+//! * Build the thread with [`Builder`] and pass the desired stack size to [`Builder::stack_size`].
+//! * Set the `RUST_MIN_STACK` environment variable to an integer representing the desired stack
+//! size (in bytes). Note that setting [`Builder::stack_size`] will override this.
+//!
+//! Note that the stack size of the main thread is *not* determined by Rust.
+//!
//! [channels]: ../../std/sync/mpsc/index.html
//! [`Arc`]: ../../std/sync/struct.Arc.html
//! [`spawn`]: ../../std/thread/fn.spawn.html
@@ -123,11 +150,14 @@
//! [`Err`]: ../../std/result/enum.Result.html#variant.Err
//! [`panic!`]: ../../std/macro.panic.html
//! [`Builder`]: ../../std/thread/struct.Builder.html
+//! [`Builder::stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size
+//! [`Builder::name`]: ../../std/thread/struct.Builder.html#method.name
//! [`thread::current`]: ../../std/thread/fn.current.html
//! [`thread::Result`]: ../../std/thread/type.Result.html
//! [`Thread`]: ../../std/thread/struct.Thread.html
//! [`park`]: ../../std/thread/fn.park.html
//! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark
+//! [`Thread::name`]: ../../std/thread/struct.Thread.html#method.name
//! [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html
//! [`Cell`]: ../cell/struct.Cell.html
//! [`RefCell`]: ../cell/struct.RefCell.html
@@ -145,10 +175,12 @@ use panic;
use panicking;
use str;
use sync::{Mutex, Condvar, Arc};
+use sync::atomic::AtomicUsize;
+use sync::atomic::Ordering::SeqCst;
use sys::thread as imp;
use sys_common::mutex;
use sys_common::thread_info;
-use sys_common::util;
+use sys_common::thread;
use sys_common::{AsInner, IntoInner};
use time::Duration;
@@ -187,16 +219,8 @@ pub use self::local::{LocalKey, LocalKeyState, AccessError};
///
/// The two configurations available are:
///
-/// - [`name`]: allows to give a name to the thread which is currently
-/// only used in `panic` messages.
-/// - [`stack_size`]: specifies the desired stack size. Note that this can
-/// be overridden by the OS.
-///
-/// If the [`stack_size`] field is not specified, the stack size
-/// will be the `RUST_MIN_STACK` environment variable. If it is
-/// not specified either, a sensible default will be set.
-///
-/// If the [`name`] field is not specified, the thread will not be named.
+/// - [`name`]: specifies an [associated name for the thread][naming-threads]
+/// - [`stack_size`]: specifies the [desired stack size for the thread][stack-size]
///
/// The [`spawn`] method will take ownership of the builder and create an
/// [`io::Result`] to the thread handle with the given configuration.
@@ -228,6 +252,8 @@ pub use self::local::{LocalKey, LocalKeyState, AccessError};
/// [`spawn`]: ../../std/thread/struct.Builder.html#method.spawn
/// [`io::Result`]: ../../std/io/type.Result.html
/// [`unwrap`]: ../../std/result/enum.Result.html#method.unwrap
+/// [naming-threads]: ./index.html#naming-threads
+/// [stack-size]: ./index.html#stack-size
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Builder {
@@ -267,6 +293,11 @@ impl Builder {
/// Names the thread-to-be. Currently the name is used for identification
/// only in panic messages.
///
+ /// The name must not contain null bytes (`\0`).
+ ///
+ /// For more information about named threads, see
+ /// [this module-level documentation][naming-threads].
+ ///
/// # Examples
///
/// ```
@@ -281,6 +312,8 @@ impl Builder {
///
/// handler.join().unwrap();
/// ```
+ ///
+ /// [naming-threads]: ./index.html#naming-threads
#[stable(feature = "rust1", since = "1.0.0")]
pub fn name(mut self, name: String) -> Builder {
self.name = Some(name);
@@ -292,6 +325,9 @@ impl Builder {
/// The actual stack size may be greater than this value if
/// the platform specifies minimal stack size.
///
+ /// For more information about the stack size for threads, see
+ /// [this module-level documentation][stack-size].
+ ///
/// # Examples
///
/// ```
@@ -299,6 +335,8 @@ impl Builder {
///
/// let builder = thread::Builder::new().stack_size(32 * 1024);
/// ```
+ ///
+ /// [stack-size]: ./index.html#stack-size
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stack_size(mut self, size: usize) -> Builder {
self.stack_size = Some(size);
@@ -325,6 +363,10 @@ impl Builder {
/// [`io::Result`]: ../../std/io/type.Result.html
/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
///
+ /// # Panics
+ ///
+ /// Panics if a thread name was set and it contained null bytes.
+ ///
/// # Examples
///
/// ```
@@ -344,7 +386,7 @@ impl Builder {
{
let Builder { name, stack_size } = self;
- let stack_size = stack_size.unwrap_or(util::min_stack());
+ let stack_size = stack_size.unwrap_or_else(thread::min_stack);
let my_thread = Thread::new(name);
let their_thread = my_thread.clone();
@@ -413,7 +455,7 @@ impl Builder {
/// *by value* from the thread where it is spawned to the new thread. Its
/// return value will need to be passed from the new thread to the thread
/// where it is `join`ed.
-/// As a reminder, the [`Send`] marker trait, expresses that it is safe to be
+/// As a reminder, the [`Send`] marker trait expresses that it is safe to be
/// passed from thread to thread. [`Sync`] expresses that it is safe to have a
/// reference be passed from thread to thread.
///
@@ -449,15 +491,17 @@ impl Builder {
/// let (tx, rx) = channel();
///
/// let sender = thread::spawn(move || {
-/// let _ = tx.send("Hello, thread".to_owned());
+/// tx.send("Hello, thread".to_owned())
+/// .expect("Unable to send on channel");
/// });
///
/// let receiver = thread::spawn(move || {
-/// println!("{}", rx.recv().unwrap());
+/// let value = rx.recv().expect("Unable to receive from channel");
+/// println!("{}", value);
/// });
///
-/// let _ = sender.join();
-/// let _ = receiver.join();
+/// sender.join().expect("The sender thread has panicked");
+/// receiver.join().expect("The receiver thread has panicked");
/// ```
///
/// A thread can also return a value through its [`JoinHandle`], you can use
@@ -530,8 +574,8 @@ pub fn current() -> Thread {
/// implementing low-level shared resources or synchronization primitives.
///
/// However programmers will usually prefer to use, [`channel`]s, [`Condvar`]s,
-/// [`Mutex`]es or [`join`] for their synchronisation routines, as they avoid
-/// thinking about thread schedulling.
+/// [`Mutex`]es or [`join`] for their synchronization routines, as they avoid
+/// thinking about thread scheduling.
///
/// Note that [`channel`]s for example are implemented using this primitive.
/// Indeed when you call `send` or `recv`, which are blocking, they will yield
@@ -656,6 +700,11 @@ pub fn sleep(dur: Duration) {
imp::Thread::sleep(dur)
}
+// constants for park/unpark
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
/// Blocks unless or until the current thread's token is made available.
///
/// A call to `park` does not guarantee that the thread will remain parked
@@ -733,11 +782,27 @@ pub fn sleep(dur: Duration) {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn park() {
let thread = current();
- let mut guard = thread.inner.lock.lock().unwrap();
- while !*guard {
- guard = thread.inner.cvar.wait(guard).unwrap();
+
+ // If we were previously notified then we consume this notification and
+ // return quickly.
+ if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+ return
+ }
+
+ // Otherwise we need to coordinate going to sleep
+ let mut m = thread.inner.lock.lock().unwrap();
+ match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+ Ok(_) => {}
+ Err(NOTIFIED) => return, // notified after we locked
+ Err(_) => panic!("inconsistent park state"),
+ }
+ loop {
+ m = thread.inner.cvar.wait(m).unwrap();
+ match thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+ Ok(_) => return, // got a notification
+ Err(_) => {} // spurious wakeup, go back to sleep
+ }
}
- *guard = false;
}
/// Use [`park_timeout`].
@@ -777,7 +842,7 @@ pub fn park_timeout_ms(ms: u32) {
/// Platforms which do not support nanosecond precision for sleeping will have
/// `dur` rounded up to the nearest granularity of time they can sleep for.
///
-/// # Example
+/// # Examples
///
/// Waiting for the complete expiration of the timeout:
///
@@ -804,12 +869,30 @@ pub fn park_timeout_ms(ms: u32) {
#[stable(feature = "park_timeout", since = "1.4.0")]
pub fn park_timeout(dur: Duration) {
let thread = current();
- let mut guard = thread.inner.lock.lock().unwrap();
- if !*guard {
- let (g, _) = thread.inner.cvar.wait_timeout(guard, dur).unwrap();
- guard = g;
+
+ // Like `park` above we have a fast path for an already-notified thread, and
+ // afterwards we start coordinating for a sleep.
+ // return quickly.
+ if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+ return
+ }
+ let m = thread.inner.lock.lock().unwrap();
+ match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+ Ok(_) => {}
+ Err(NOTIFIED) => return, // notified after we locked
+ Err(_) => panic!("inconsistent park_timeout state"),
+ }
+
+ // Wait with a timeout, and if we spuriously wake up or otherwise wake up
+ // from a notification we just want to unconditionally set the state back to
+ // empty, either consuming a notification or un-flagging ourselves as
+ // parked.
+ let (_m, _result) = thread.inner.cvar.wait_timeout(m, dur).unwrap();
+ match thread.inner.state.swap(EMPTY, SeqCst) {
+ NOTIFIED => {} // got a notification, hurray!
+ PARKED => {} // no notification, alas
+ n => panic!("inconsistent park_timeout state: {}", n),
}
- *guard = false;
}
////////////////////////////////////////////////////////////////////////////////
@@ -820,7 +903,8 @@ pub fn park_timeout(dur: Duration) {
///
/// A `ThreadId` is an opaque object that has a unique value for each thread
/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's
-/// system-designated identifier.
+/// system-designated identifier. A `ThreadId` can be retrieved from the [`id`]
+/// method on a [`Thread`].
///
/// # Examples
///
@@ -834,6 +918,9 @@ pub fn park_timeout(dur: Duration) {
/// let other_thread_id = other_thread.join().unwrap();
/// assert!(thread::current().id() != other_thread_id);
/// ```
+///
+/// [`id`]: ../../std/thread/struct.Thread.html#method.id
+/// [`Thread`]: ../../std/thread/struct.Thread.html
#[stable(feature = "thread_id", since = "1.19.0")]
#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
pub struct ThreadId(u64);
@@ -872,7 +959,10 @@ impl ThreadId {
struct Inner {
name: Option<CString>, // Guaranteed to be UTF-8
id: ThreadId,
- lock: Mutex<bool>, // true when there is a buffered unpark
+
+ // state for thread park/unpark
+ state: AtomicUsize,
+ lock: Mutex<()>,
cvar: Condvar,
}
@@ -896,6 +986,9 @@ struct Inner {
/// docs of [`Builder`] and [`spawn`] for more details.
///
/// [`Builder`]: ../../std/thread/struct.Builder.html
+/// [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread
+/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+/// [`thread::current`]: ../../std/thread/fn.current.html
/// [`spawn`]: ../../std/thread/fn.spawn.html
pub struct Thread {
@@ -904,6 +997,7 @@ pub struct Thread {
impl Thread {
// Used only internally to construct a thread object without spawning
+ // Panics if the name contains nuls.
pub(crate) fn new(name: Option<String>) -> Thread {
let cname = name.map(|n| {
CString::new(n).expect("thread name may not contain interior null bytes")
@@ -912,7 +1006,8 @@ impl Thread {
inner: Arc::new(Inner {
name: cname,
id: ThreadId::new(),
- lock: Mutex::new(false),
+ state: AtomicUsize::new(EMPTY),
+ lock: Mutex::new(()),
cvar: Condvar::new(),
})
}
@@ -952,10 +1047,22 @@ impl Thread {
/// [park]: fn.park.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unpark(&self) {
- let mut guard = self.inner.lock.lock().unwrap();
- if !*guard {
- *guard = true;
- self.inner.cvar.notify_one();
+ loop {
+ match self.inner.state.compare_exchange(EMPTY, NOTIFIED, SeqCst, SeqCst) {
+ Ok(_) => return, // no one was waiting
+ Err(NOTIFIED) => return, // already unparked
+ Err(PARKED) => {} // gotta go wake someone up
+ _ => panic!("inconsistent state in unpark"),
+ }
+
+ // Coordinate wakeup through the mutex and a condvar notification
+ let _lock = self.inner.lock.lock().unwrap();
+ match self.inner.state.compare_exchange(PARKED, NOTIFIED, SeqCst, SeqCst) {
+ Ok(_) => return self.inner.cvar.notify_one(),
+ Err(NOTIFIED) => return, // a different thread unparked
+ Err(EMPTY) => {} // parked thread went away, try again
+ _ => panic!("inconsistent state in unpark"),
+ }
}
}
@@ -980,6 +1087,9 @@ impl Thread {
/// Gets the thread's name.
///
+ /// For more information about named threads, see
+ /// [this module-level documentation][naming-threads].
+ ///
/// # Examples
///
/// Threads by default have no name specified:
@@ -1010,6 +1120,8 @@ impl Thread {
///
/// handler.join().unwrap();
/// ```
+ ///
+ /// [naming-threads]: ./index.html#naming-threads
#[stable(feature = "rust1", since = "1.0.0")]
pub fn name(&self) -> Option<&str> {
self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) } )
@@ -1143,7 +1255,7 @@ impl<T> JoinInner<T> {
/// });
/// });
///
-/// let _ = original_thread.join();
+/// original_thread.join().expect("The thread being joined has panicked");
/// println!("Original thread is joined.");
///
/// // We make sure that the new thread has time to run, before the main
@@ -1188,6 +1300,11 @@ impl<T> JoinHandle<T> {
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
/// [`panic`]: ../../std/macro.panic.html
///
+ /// # Panics
+ ///
+ /// This function may panic on some platforms if a thread attempts to join
+ /// itself or otherwise may create a deadlock with joining threads.
+ ///
/// # Examples
///
/// ```
diff --git a/ctr-std/src/time/duration.rs b/ctr-std/src/time/duration.rs
index 41d675b..cb5bfb9 100644
--- a/ctr-std/src/time/duration.rs
+++ b/ctr-std/src/time/duration.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -8,22 +8,29 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use iter::Sum;
use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
const NANOS_PER_SEC: u32 = 1_000_000_000;
const NANOS_PER_MILLI: u32 = 1_000_000;
+const NANOS_PER_MICRO: u32 = 1_000;
const MILLIS_PER_SEC: u64 = 1_000;
+const MICROS_PER_SEC: u64 = 1_000_000;
-/// A duration type to represent a span of time, typically used for system
+/// A `Duration` type to represent a span of time, typically used for system
/// timeouts.
///
-/// Each duration is composed of a number of seconds and nanosecond precision.
-/// APIs binding a system timeout will typically round up the nanosecond
-/// precision if the underlying system does not support that level of precision.
+/// Each `Duration` is composed of a whole number of seconds and a fractional part
+/// represented in nanoseconds. If the underlying system does not support
+/// nanosecond-level precision, APIs binding a system timeout will typically round up
+/// the number of nanoseconds.
///
-/// Durations implement many common traits, including `Add`, `Sub`, and other
-/// ops traits. Currently a duration may only be inspected for its number of
-/// seconds and its nanosecond precision.
+/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
+/// [`ops`] traits.
+///
+/// [`Add`]: ../../std/ops/trait.Add.html
+/// [`Sub`]: ../../std/ops/trait.Sub.html
+/// [`ops`]: ../../std/ops/index.html
///
/// # Examples
///
@@ -46,16 +53,24 @@ pub struct Duration {
}
impl Duration {
- /// Creates a new `Duration` from the specified number of seconds and
- /// additional nanosecond precision.
+ /// Creates a new `Duration` from the specified number of whole seconds and
+ /// additional nanoseconds.
///
- /// If the nanoseconds is greater than 1 billion (the number of nanoseconds
- /// in a second), then it will carry over into the seconds provided.
+ /// If the number of nanoseconds is greater than 1 billion (the number of
+ /// nanoseconds in a second), then it will carry over into the seconds provided.
///
/// # Panics
///
/// This constructor will panic if the carry from the nanoseconds overflows
/// the seconds counter.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let five_seconds = Duration::new(5, 0);
+ /// ```
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
pub fn new(secs: u64, nanos: u32) -> Duration {
@@ -65,7 +80,18 @@ impl Duration {
Duration { secs: secs, nanos: nanos }
}
- /// Creates a new `Duration` from the specified number of seconds.
+ /// Creates a new `Duration` from the specified number of whole seconds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_secs(5);
+ ///
+ /// assert_eq!(5, duration.as_secs());
+ /// assert_eq!(0, duration.subsec_nanos());
+ /// ```
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
pub fn from_secs(secs: u64) -> Duration {
@@ -73,6 +99,17 @@ impl Duration {
}
/// Creates a new `Duration` from the specified number of milliseconds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_millis(2569);
+ ///
+ /// assert_eq!(2, duration.as_secs());
+ /// assert_eq!(569_000_000, duration.subsec_nanos());
+ /// ```
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
pub fn from_millis(millis: u64) -> Duration {
@@ -81,39 +118,155 @@ impl Duration {
Duration { secs: secs, nanos: nanos }
}
- /// Returns the number of whole seconds represented by this duration.
+ /// Creates a new `Duration` from the specified number of microseconds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_from_micros)]
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_micros(1_000_002);
+ ///
+ /// assert_eq!(1, duration.as_secs());
+ /// assert_eq!(2000, duration.subsec_nanos());
+ /// ```
+ #[unstable(feature = "duration_from_micros", issue = "44400")]
+ #[inline]
+ pub fn from_micros(micros: u64) -> Duration {
+ let secs = micros / MICROS_PER_SEC;
+ let nanos = ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO;
+ Duration { secs: secs, nanos: nanos }
+ }
+
+ /// Creates a new `Duration` from the specified number of nanoseconds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_extras)]
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_nanos(1_000_000_123);
+ ///
+ /// assert_eq!(1, duration.as_secs());
+ /// assert_eq!(123, duration.subsec_nanos());
+ /// ```
+ #[unstable(feature = "duration_extras", issue = "46507")]
+ #[inline]
+ pub fn from_nanos(nanos: u64) -> Duration {
+ let secs = nanos / (NANOS_PER_SEC as u64);
+ let nanos = (nanos % (NANOS_PER_SEC as u64)) as u32;
+ Duration { secs: secs, nanos: nanos }
+ }
+
+ /// Returns the number of _whole_ seconds contained by this `Duration`.
+ ///
+ /// The returned value does not include the fractional (nanosecond) part of the
+ /// duration, which can be obtained using [`subsec_nanos`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::new(5, 730023852);
+ /// assert_eq!(duration.as_secs(), 5);
+ /// ```
+ ///
+ /// To determine the total number of seconds represented by the `Duration`,
+ /// use `as_secs` in combination with [`subsec_nanos`]:
+ ///
+ /// ```
+ /// use std::time::Duration;
///
- /// The extra precision represented by this duration is ignored (i.e. extra
- /// nanoseconds are not represented in the returned value).
+ /// let duration = Duration::new(5, 730023852);
+ ///
+ /// assert_eq!(5.730023852,
+ /// duration.as_secs() as f64
+ /// + duration.subsec_nanos() as f64 * 1e-9);
+ /// ```
+ ///
+ /// [`subsec_nanos`]: #method.subsec_nanos
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
pub fn as_secs(&self) -> u64 { self.secs }
- /// Returns the nanosecond precision represented by this duration.
+ /// Returns the fractional part of this `Duration`, in milliseconds.
+ ///
+ /// This method does **not** return the length of the duration when
+ /// represented by milliseconds. The returned number always represents a
+ /// fractional portion of a second (i.e. it is less than one thousand).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_extras)]
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_millis(5432);
+ /// assert_eq!(duration.as_secs(), 5);
+ /// assert_eq!(duration.subsec_millis(), 432);
+ /// ```
+ #[unstable(feature = "duration_extras", issue = "46507")]
+ #[inline]
+ pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
+
+ /// Returns the fractional part of this `Duration`, in microseconds.
+ ///
+ /// This method does **not** return the length of the duration when
+ /// represented by microseconds. The returned number always represents a
+ /// fractional portion of a second (i.e. it is less than one million).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_extras, duration_from_micros)]
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_micros(1_234_567);
+ /// assert_eq!(duration.as_secs(), 1);
+ /// assert_eq!(duration.subsec_micros(), 234_567);
+ /// ```
+ #[unstable(feature = "duration_extras", issue = "46507")]
+ #[inline]
+ pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
+
+ /// Returns the fractional part of this `Duration`, in nanoseconds.
///
/// This method does **not** return the length of the duration when
/// represented by nanoseconds. The returned number always represents a
/// fractional portion of a second (i.e. it is less than one billion).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_millis(5010);
+ /// assert_eq!(duration.as_secs(), 5);
+ /// assert_eq!(duration.subsec_nanos(), 10_000_000);
+ /// ```
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
pub fn subsec_nanos(&self) -> u32 { self.nanos }
- /// Checked duration addition. Computes `self + other`, returning `None`
+ /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
/// if overflow occurred.
///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
/// # Examples
///
/// Basic usage:
///
/// ```
- /// #![feature(duration_checked_ops)]
- ///
/// use std::time::Duration;
///
/// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
/// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None);
/// ```
- #[unstable(feature = "duration_checked_ops", issue = "35774")]
+ #[stable(feature = "duration_checked_ops", since = "1.16.0")]
#[inline]
pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
@@ -128,30 +281,30 @@ impl Duration {
}
debug_assert!(nanos < NANOS_PER_SEC);
Some(Duration {
- secs: secs,
- nanos: nanos,
+ secs,
+ nanos,
})
} else {
None
}
}
- /// Checked duration subtraction. Computes `self + other`, returning `None`
- /// if the result would be negative or if underflow occurred.
+ /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
+ /// if the result would be negative or if overflow occurred.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// Basic usage:
///
/// ```
- /// #![feature(duration_checked_ops)]
- ///
/// use std::time::Duration;
///
/// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1)));
/// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None);
/// ```
- #[unstable(feature = "duration_checked_ops", issue = "35774")]
+ #[stable(feature = "duration_checked_ops", since = "1.16.0")]
#[inline]
pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
@@ -172,22 +325,22 @@ impl Duration {
}
}
- /// Checked duration multiplication. Computes `self * other`, returning
- /// `None` if underflow or overflow occurred.
+ /// Checked `Duration` multiplication. Computes `self * other`, returning
+ /// [`None`] if overflow occurred.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// Basic usage:
///
/// ```
- /// #![feature(duration_checked_ops)]
- ///
/// use std::time::Duration;
///
/// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
/// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None);
/// ```
- #[unstable(feature = "duration_checked_ops", issue = "35774")]
+ #[stable(feature = "duration_checked_ops", since = "1.16.0")]
#[inline]
pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
// Multiply nanoseconds as u64, because it cannot overflow that way.
@@ -199,31 +352,31 @@ impl Duration {
.and_then(|s| s.checked_add(extra_secs)) {
debug_assert!(nanos < NANOS_PER_SEC);
Some(Duration {
- secs: secs,
- nanos: nanos,
+ secs,
+ nanos,
})
} else {
None
}
}
- /// Checked duration division. Computes `self / other`, returning `None`
- /// if `other == 0` or the operation results in underflow or overflow.
+ /// Checked `Duration` division. Computes `self / other`, returning [`None`]
+ /// if `other == 0`.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// Basic usage:
///
/// ```
- /// #![feature(duration_checked_ops)]
- ///
/// use std::time::Duration;
///
/// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
/// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
/// assert_eq!(Duration::new(2, 0).checked_div(0), None);
/// ```
- #[unstable(feature = "duration_checked_ops", issue = "35774")]
+ #[stable(feature = "duration_checked_ops", since = "1.16.0")]
#[inline]
pub fn checked_div(self, rhs: u32) -> Option<Duration> {
if rhs != 0 {
@@ -303,6 +456,20 @@ impl DivAssign<u32> for Duration {
}
}
+#[stable(feature = "duration_sum", since = "1.16.0")]
+impl Sum for Duration {
+ fn sum<I: Iterator<Item=Duration>>(iter: I) -> Duration {
+ iter.fold(Duration::new(0, 0), |a, b| a + b)
+ }
+}
+
+#[stable(feature = "duration_sum", since = "1.16.0")]
+impl<'a> Sum<&'a Duration> for Duration {
+ fn sum<I: Iterator<Item=&'a Duration>>(iter: I) -> Duration {
+ iter.fold(Duration::new(0, 0), |a, b| a + *b)
+ }
+}
+
#[cfg(test)]
mod tests {
use super::Duration;
diff --git a/ctr-std/src/time/mod.rs b/ctr-std/src/time/mod.rs
index 6854f1e..6ce3b3e 100644
--- a/ctr-std/src/time/mod.rs
+++ b/ctr-std/src/time/mod.rs
@@ -33,10 +33,10 @@ pub use self::duration::Duration;
mod duration;
-/// A measurement of a monotonically increasing clock.
-/// Opaque and useful only with `Duration`.
+/// A measurement of a monotonically nondecreasing clock.
+/// Opaque and useful only with `Duration`.
///
-/// Instants are always guaranteed to be greater than any previously measured
+/// Instants are always guaranteed to be no less than any previously measured
/// instant when created, and are often useful for tasks such as measuring
/// benchmarks or timing how long an operation takes.
///
@@ -66,14 +66,14 @@ mod duration;
/// println!("{}", now.elapsed().as_secs());
/// }
/// ```
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct Instant(time::Instant);
/// A measurement of the system clock, useful for talking to
/// external entities like the file system or other processes.
///
-/// Distinct from the `Instant` type, this time measurement **is not
+/// Distinct from the [`Instant`] type, this time measurement **is not
/// monotonic**. This means that you can save a file to the file system, then
/// save another file to the file system, **and the second file has a
/// `SystemTime` measurement earlier than the first**. In other words, an
@@ -81,15 +81,20 @@ pub struct Instant(time::Instant);
/// earlier `SystemTime`!
///
/// Consequently, comparing two `SystemTime` instances to learn about the
-/// duration between them returns a `Result` instead of an infallible `Duration`
+/// duration between them returns a [`Result`] instead of an infallible [`Duration`]
/// to indicate that this sort of time drift may happen and needs to be handled.
///
-/// Although a `SystemTime` cannot be directly inspected, the `UNIX_EPOCH`
+/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`]
/// constant is provided in this module as an anchor in time to learn
/// information about a `SystemTime`. By calculating the duration from this
/// fixed point in time, a `SystemTime` can be converted to a human-readable time,
/// or perhaps some other string representation.
///
+/// [`Instant`]: ../../std/time/struct.Instant.html
+/// [`Result`]: ../../std/result/enum.Result.html
+/// [`Duration`]: ../../std/time/struct.Duration.html
+/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html
+///
/// Example:
///
/// ```no_run
@@ -107,24 +112,48 @@ pub struct Instant(time::Instant);
/// println!("{}", elapsed.as_secs());
/// }
/// Err(e) => {
-/// // an error occured!
+/// // an error occurred!
/// println!("Error: {:?}", e);
/// }
/// }
/// }
/// ```
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct SystemTime(time::SystemTime);
-/// An error returned from the `duration_since` method on `SystemTime`,
-/// used to learn how far in the opposite direction a system time lies.
+/// An error returned from the `duration_since` and `elapsed` methods on
+/// `SystemTime`, used to learn how far in the opposite direction a system time
+/// lies.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread::sleep;
+/// use std::time::{Duration, SystemTime};
+///
+/// let sys_time = SystemTime::now();
+/// sleep(Duration::from_secs(1));
+/// let new_sys_time = SystemTime::now();
+/// match sys_time.duration_since(new_sys_time) {
+/// Ok(_) => {}
+/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
+/// }
+/// ```
#[derive(Clone, Debug)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct SystemTimeError(Duration);
impl Instant {
/// Returns an instant corresponding to "now".
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Instant;
+ ///
+ /// let now = Instant::now();
+ /// ```
#[stable(feature = "time2", since = "1.8.0")]
pub fn now() -> Instant {
Instant(time::Instant::now())
@@ -134,10 +163,19 @@ impl Instant {
///
/// # Panics
///
- /// This function will panic if `earlier` is later than `self`, which should
- /// only be possible if `earlier` was created after `self`. Because
- /// `Instant` is monotonic, the only time that this should happen should be
- /// a bug.
+ /// This function will panic if `earlier` is later than `self`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::time::{Duration, Instant};
+ /// use std::thread::sleep;
+ ///
+ /// let now = Instant::now();
+ /// sleep(Duration::new(1, 0));
+ /// let new_now = Instant::now();
+ /// println!("{:?}", new_now.duration_since(now));
+ /// ```
#[stable(feature = "time2", since = "1.8.0")]
pub fn duration_since(&self, earlier: Instant) -> Duration {
self.0.sub_instant(&earlier.0)
@@ -218,6 +256,14 @@ impl fmt::Debug for Instant {
impl SystemTime {
/// Returns the system time corresponding to "now".
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::SystemTime;
+ ///
+ /// let sys_time = SystemTime::now();
+ /// ```
#[stable(feature = "time2", since = "1.8.0")]
pub fn now() -> SystemTime {
SystemTime(time::SystemTime::now())
@@ -229,11 +275,26 @@ impl SystemTime {
/// guaranteed to always be before later measurements (due to anomalies such
/// as the system clock being adjusted either forwards or backwards).
///
- /// If successful, `Ok(Duration)` is returned where the duration represents
+ /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents
/// the amount of time elapsed from the specified measurement to this one.
///
- /// Returns an `Err` if `earlier` is later than `self`, and the error
+ /// Returns an [`Err`] if `earlier` is later than `self`, and the error
/// contains how far from `self` the time is.
+ ///
+ /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::SystemTime;
+ ///
+ /// let sys_time = SystemTime::now();
+ /// let difference = sys_time.duration_since(sys_time)
+ /// .expect("SystemTime::duration_since failed");
+ /// println!("{:?}", difference);
+ /// ```
#[stable(feature = "time2", since = "1.8.0")]
pub fn duration_since(&self, earlier: SystemTime)
-> Result<Duration, SystemTimeError> {
@@ -244,12 +305,28 @@ impl SystemTime {
///
/// This function may fail as the underlying system clock is susceptible to
/// drift and updates (e.g. the system clock could go backwards), so this
- /// function may not always succeed. If successful, `Ok(duration)` is
+ /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is
/// returned where the duration represents the amount of time elapsed from
/// this time measurement to the current time.
///
- /// Returns an `Err` if `self` is later than the current system time, and
+ /// Returns an [`Err`] if `self` is later than the current system time, and
/// the error contains how far from the current system time `self` is.
+ ///
+ /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread::sleep;
+ /// use std::time::{Duration, SystemTime};
+ ///
+ /// let sys_time = SystemTime::now();
+ /// let one_sec = Duration::from_secs(1);
+ /// sleep(one_sec);
+ /// assert!(sys_time.elapsed().unwrap() >= one_sec);
+ /// ```
#[stable(feature = "time2", since = "1.8.0")]
pub fn elapsed(&self) -> Result<Duration, SystemTimeError> {
SystemTime::now().duration_since(*self)
@@ -300,9 +377,22 @@ impl fmt::Debug for SystemTime {
///
/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
/// respect to the system clock. Using `duration_since` on an existing
-/// `SystemTime` instance can tell how far away from this point in time a
+/// [`SystemTime`] instance can tell how far away from this point in time a
/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
-/// `SystemTime` instance to represent another fixed point in time.
+/// [`SystemTime`] instance to represent another fixed point in time.
+///
+/// [`SystemTime`]: ../../std/time/struct.SystemTime.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::time::{SystemTime, UNIX_EPOCH};
+///
+/// match SystemTime::now().duration_since(UNIX_EPOCH) {
+/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
+/// Err(_) => panic!("SystemTime before UNIX EPOCH!"),
+/// }
+/// ```
#[stable(feature = "time2", since = "1.8.0")]
pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH);
@@ -310,9 +400,28 @@ impl SystemTimeError {
/// Returns the positive duration which represents how far forward the
/// second system time was from the first.
///
- /// A `SystemTimeError` is returned from the `duration_since`
- /// operation whenever the second system time represents a point later
+ /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`]
+ /// methods of [`SystemTime`] whenever the second system time represents a point later
/// in time than the `self` of the method call.
+ ///
+ /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since
+ /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed
+ /// [`SystemTime`]: ../../std/time/struct.SystemTime.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread::sleep;
+ /// use std::time::{Duration, SystemTime};
+ ///
+ /// let sys_time = SystemTime::now();
+ /// sleep(Duration::from_secs(1));
+ /// let new_sys_time = SystemTime::now();
+ /// match sys_time.duration_since(new_sys_time) {
+ /// Ok(_) => {}
+ /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
+ /// }
+ /// ```
#[stable(feature = "time2", since = "1.8.0")]
pub fn duration(&self) -> Duration {
self.0
@@ -400,7 +509,7 @@ mod tests {
let dur = dur.duration();
assert!(a > b);
assert_almost_eq!(b + dur, a);
- assert_almost_eq!(b - dur, a);
+ assert_almost_eq!(a - dur, b);
}
}
@@ -411,9 +520,12 @@ mod tests {
assert_almost_eq!(a - second + second, a);
- let eighty_years = second * 60 * 60 * 24 * 365 * 80;
- assert_almost_eq!(a - eighty_years + eighty_years, a);
- assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a);
+ // A difference of 80 and 800 years cannot fit inside a 32-bit time_t
+ if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) {
+ let eighty_years = second * 60 * 60 * 24 * 365 * 80;
+ assert_almost_eq!(a - eighty_years + eighty_years, a);
+ assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a);
+ }
let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000)
@@ -435,9 +547,17 @@ mod tests {
assert!(b > a);
assert_eq!(b - a, Duration::new(1, 0));
- // let's assume that we're all running computers later than 2000
let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30;
- assert!(a > thirty_years);
+
+ // Right now for CI this test is run in an emulator, and apparently the
+ // aarch64 emulator's sense of time is that we're still living in the
+ // 70s.
+ //
+ // Otherwise let's assume that we're all running computers later than
+ // 2000.
+ if !cfg!(target_arch = "aarch64") {
+ assert!(a > thirty_years);
+ }
// let's assume that we're all running computers earlier than 2090.
// Should give us ~70 years to fix this!