new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"d56246d6c8796c638b5012c2d7a91d9b6ec101b6a47128e2d4bfa957c1c784e8","CHANGELOG.md":"4f602de0b17e0d0121371482dfcf3caf2265b70bf92e8b5db1cba5dd8f391469","Cargo.toml":"8e4d1f0b25be862107a6938190c9817cd7ea516db50e688de1d0fe87519105ee","README.md":"6771ca940645b2f7e7a018c8cd25b25f8bf35786e229b54fa2fded1f2d0ae411","examples/all.rs":"6f073ea0e3db541a4eefb41436fc03a121a1f932fd6a2798b485a72d64bd1a3c","examples/doc.rs":"574948eb776c3d363f5cff9a48015bab6c17828c7306dc3eb8818afa90a31a83","examples/quickstart.rs":"c3142d5139d89c3861b119507a372fba47ac3d7df61aa90b068d518dea8fd6f6","examples/size.rs":"7922acd891dfd06f1d36308a3ccdf03def2646b2f39bfd1b15cf2896247bad8f","src/error_chain.rs":"d0cb3e4a93f9c358e4bd18ab8443573e57ace15442f4697ad95963d10408f882","src/example_generated.rs":"7d5220020aada7def70d3b3e396dadb0b139ed104b1253d06ac53f48517ec668","src/lib.rs":"0d1c972252dd1df3117ddf0a71a4734cdb350b41376e09cbe4b868afb0e2762b","src/quick_error.rs":"1889b9ca1f7a5e9124275fd5da81e709d0d6bd3b06915bf320c23d4c4f083301","src/quick_main.rs":"106a0cf44a6a2fbb9fb1d8932d234f43cd7af230fc6685b28f6b9dfaca2a3210","tests/quick_main.rs":"1d6a726856b954d4cffddab00602583921972ceeeb2bf7ba9ebbac6a51584b53","tests/tests.rs":"67b6acf87f4986fa013f018195e3becd6dd63d8101a7af07a417e8e526cf50ad"},"package":"d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/.travis.yml
@@ -0,0 +1,45 @@
+language: rust
+rust:
+- stable
+- beta
+- nightly
+# Oldest supported version for all features.
+# Use of https://github.com/rust-lang/rfcs/pull/16
+- 1.13.0
+# Oldest supported version as dependency, with no features, tests, or examples.
+- 1.10.0
+
+sudo: false
+cache: cargo
+addons:
+ apt:
+ packages:
+ - libcurl4-openssl-dev
+ - libelf-dev
+ - libdw-dev
+
+before_script:
+- |
+ pip install 'travis-cargo<0.2' --user &&
+ export PATH=$HOME/.local/bin:$PATH
+
+script:
+- travis-cargo build -- $FEATURES
+- travis-cargo --skip 1.10.0 test -- $FEATURES
+
+after_success:
+- travis-cargo --only stable doc
+- travis-cargo --only stable doc-upload
+
+env:
+ global:
+ - secure: ncxJbvJM1vCZfcEftjsFKJMxxhKLgWKaR8Go9AMo0VB5fB2XVW/6NYO5bQEEYpOf1Nc/+2FbI2+Dkz0S/mJpUcNSfBgablCHgwU2sHse7KsoaqfHj2mf1E3exjzSHoP96hPGicC5zAjSXFjCgJPOUSGqqRaJ7z5AsJLhJT6LuK7QpvwPBZzklUN8T+n1sVmws8TNmRIbaniq/q6wYHANHcy6Dl59dx4sKwniUGiZdUhCiddVpoxbECSxc0A8mN2pk7/aW+WGxK3goBs5ZF7+JXF318F62pDcXQmR5CX6WdpenIcJ25g1Vg1WhQ4Ifpe17CN0bfxV8ShuzrQUThCDMffZCo9XySBtODdEowwK1UIpjnFLfIxjOs45Cd8o3tM2j0CfvtnjOz6BCdUU0qiwNPPNx0wFkx3ZiOfSh+FhBhvyPM12HN2tdN0esgVBItFmEci+sSIIXqjVL6DNiu5zTjbu0bs6COwlUWdmL6vmsZtq5tl7Cno9+C3szxRVAkShGydd04l9NYjqNEzTa1EPG50OsnVRKGdRiFzSxhc3BWExNKvcQ4v867t6/PpPkW6s4oXmYI3+De+8O7ExWc6a4alcrDXKlMs5fCb5Pcd4Ju9kowcjkoJo5yf2wW3Ox5R8SJpaEEpvyhx5O/qtIxjhHNzeo8Wsr/6gdNDv20r91TI=
+ - TRAVIS_CARGO_NIGHTLY_FEATURE=""
+ matrix:
+ - FEATURES=--features=backtrace
+ - FEATURES=--no-default-features
+
+matrix:
+ exclude:
+ - env: FEATURES=--features=backtrace
+ rust: 1.10.0
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/CHANGELOG.md
@@ -0,0 +1,100 @@
+# Unreleased
+
+# 0.10.0
+
+- [Add a new constructor for `Error`: `with_chain`.](https://github.com/brson/error-chain/pull/126)
+- [Add the `ensure!` macro.](https://github.com/brson/error-chain/pull/135)
+
+# 0.9.0
+
+- Revert [Add a `Sync` bound to errors](https://github.com/brson/error-chain/pull/110)
+
+# 0.8.1
+
+- Add crates.io categorie.
+
+# 0.8.0
+
+- [Add a `Sync` bound to errors](https://github.com/brson/error-chain/pull/110)
+- [Add `ChainedError::display` to format error chains](https://github.com/brson/error-chain/pull/113)
+
+# 0.7.2
+
+- Add `quick_main!` (#88).
+- `allow(unused)` for the `Result` wrapper.
+- Minimum rust version supported is now 1.10 on some conditions (#103).
+
+# 0.7.1
+
+- [Add the `bail!` macro](https://github.com/brson/error-chain/pull/76)
+
+# 0.7.0
+
+- [Rollback several design changes to fix regressions](https://github.com/brson/error-chain/pull/75)
+- New `Variant(Error) #[attrs]` for `links` and `foreign_links`.
+- Hide implementation details from the doc.
+- Always generate `Error::backtrace`.
+
+# 0.6.2
+
+- Allow dead code.
+
+# 0.6.1
+
+- Fix wrong trait constraint in ResultExt implementation (#66).
+
+# 0.6.0
+
+- Conditional compilation for error variants.
+- Backtrace generation is now a feature.
+- More standard trait implementations for extra convenience.
+- Remove ChainErr.
+- Remove need to specify `ErrorKind` in `links {}`.
+- Add ResultExt trait.
+- Error.1 is a struct instead of a tuple.
+- Error is now a struct.
+- The declarations order is more flexible.
+- Way better error reporting when there is a syntax error in the macro call.
+- `Result` generation can be disabled.
+- At most one declaration of each type can be present.
+
+# 0.5.0
+
+- [Only generate backtraces with RUST_BACKTRACE set](https://github.com/brson/error-chain/pull/27)
+- [Fixup matching, disallow repeating "types" section](https://github.com/brson/error-chain/pull/26)
+- [Fix tests on stable/beta](https://github.com/brson/error-chain/pull/28)
+- [Only deploy docs when tagged](https://github.com/brson/error-chain/pull/30)
+
+Contributors: benaryorg, Brian Anderson, Georg Brandl
+
+# 0.4.2
+
+- [Fix the resolution of the ErrorKind description method](https://github.com/brson/error-chain/pull/24)
+
+Contributors: Brian Anderson
+
+# 0.4.1 (yanked)
+
+- [Fix a problem with resolving methods of the standard Error type](https://github.com/brson/error-chain/pull/22)
+
+Contributors: Brian Anderson
+
+# 0.4.0 (yanked)
+
+- [Remove the foreign link description and forward to the foreign error](https://github.com/brson/error-chain/pull/19)
+- [Allow missing sections](https://github.com/brson/error-chain/pull/17)
+
+Contributors: Brian Anderson, Taylor Cramer
+
+# 0.3.0
+
+- [Forward Display implementation for foreign errors](https://github.com/brson/error-chain/pull/13)
+
+Contributors: Brian Anderson, Taylor Cramer
+
+# 0.2.2
+
+- [Don't require `types` section in macro invocation](https://github.com/brson/error-chain/pull/8)
+- [Add "quick start" to README](https://github.com/brson/error-chain/pull/9)
+
+Contributors: Brian Anderson, Jake Shadle, Nate Mara
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+
+name = "error-chain"
+version = "0.10.0"
+authors = [ "Brian Anderson <banderson@mozilla.com>",
+ "Paul Colomiets <paul@colomiets.name>",
+ "Colin Kiegel <kiegel@gmx.de>",
+ "Yamakaky <yamakaky@yamaworld.fr>"]
+description = "Yet another error boilerplate library."
+categories = ["rust-patterns"]
+
+documentation = "https://docs.rs/error-chain"
+homepage = "https://github.com/brson/error-chain"
+repository = "https://github.com/brson/error-chain"
+
+license = "MIT/Apache-2.0"
+
+[badges]
+travis-ci = { repository = "brson/error-chain" }
+
+[features]
+default = ["backtrace", "example_generated"]
+example_generated = []
+
+[dependencies]
+backtrace = { version = "0.3", optional = true }
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/README.md
@@ -0,0 +1,36 @@
+# error-chain - Consistent error handling for Rust
+
+[![Build Status](https://api.travis-ci.org/brson/error-chain.svg?branch=master)](https://travis-ci.org/brson/error-chain)
+[![Latest Version](https://img.shields.io/crates/v/error-chain.svg)](https://crates.io/crates/error-chain)
+[![License](https://img.shields.io/github/license/brson/error-chain.svg)](https://github.com/brson/error-chain)
+
+`error-chain` makes it easy to take full advantage of Rust's error
+handling features without the overhead of maintaining boilerplate
+error types and conversions. It implements an opinionated strategy for
+defining your own error types, as well as conversions from others'
+error types.
+
+[Documentation (crates.io)](https://docs.rs/error-chain).
+
+[Documentation (master)](https://brson.github.io/error-chain).
+
+## Quick start
+
+If you just want to set up your new project with error-chain,
+follow the [quickstart.rs] template, and read this [intro]
+to error-chain.
+
+[quickstart.rs]: https://github.com/brson/error-chain/blob/master/examples/quickstart.rs
+[intro]: http://brson.github.io/2016/11/30/starting-with-error-chain
+
+## Supported Rust version
+
+Please view the beginning of the [Travis configuration file](.travis.yml)
+to see the oldest supported Rust version.
+
+Note that `error-chain` supports older versions of Rust when built with
+`default-features = false`.
+
+## License
+
+MIT/Apache-2.0
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/examples/all.rs
@@ -0,0 +1,36 @@
+#[macro_use]
+extern crate error_chain;
+
+pub mod inner {
+ error_chain! {}
+}
+
+#[cfg(feature = "a_feature")]
+pub mod feature {
+ error_chain! {}
+}
+
+error_chain! {
+ // Types generated by the macro. If empty or absent, it defaults to
+ // Error, ErrorKind, Result;
+ types {
+ // With custom names:
+ MyError, MyErrorKind, MyResult;
+ // Without the `Result` wrapper:
+ // Error, ErrorKind;
+ }
+
+ // Automatic bindings to other error types generated by `error_chain!`.
+ links {
+ Inner(inner::Error, inner::ErrorKind);
+ // Attributes can be added at the end of the declaration.
+ Feature(feature::Error, feature::ErrorKind) #[cfg(feature = "a_feature")];
+ }
+
+ // Bindings to types implementing std::error::Error.
+ foreign_links {
+ Io(::std::io::Error);
+ }
+}
+
+fn main() {}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/examples/doc.rs
@@ -0,0 +1,29 @@
+#![deny(missing_docs)]
+
+//! This module is used to check that all generated items are documented.
+
+#[macro_use]
+extern crate error_chain;
+
+/// Inner module.
+pub mod inner {
+ error_chain! {
+ }
+}
+
+error_chain! {
+ links {
+ Inner(inner::Error, inner::ErrorKind) #[doc = "Doc"];
+ }
+ foreign_links {
+ Io(::std::io::Error) #[doc = "Io"];
+ }
+ errors {
+ /// Doc
+ Test2 {
+
+ }
+ }
+}
+
+fn main() {}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/examples/quickstart.rs
@@ -0,0 +1,77 @@
+// Simple and robust error handling with error-chain!
+// Use this as a template for new projects.
+
+// `error_chain!` can recurse deeply
+#![recursion_limit = "1024"]
+
+// Import the macro. Don't forget to add `error-chain` in your
+// `Cargo.toml`!
+#[macro_use]
+extern crate error_chain;
+
+// We'll put our errors in an `errors` module, and other modules in
+// this crate will `use errors::*;` to get access to everything
+// `error_chain!` creates.
+mod errors {
+ // Create the Error, ErrorKind, ResultExt, and Result types
+ error_chain! { }
+}
+
+use errors::*;
+
+fn main() {
+ if let Err(ref e) = run() {
+ use ::std::io::Write;
+ let stderr = &mut ::std::io::stderr();
+ let errmsg = "Error writing to stderr";
+
+ writeln!(stderr, "error: {}", e).expect(errmsg);
+
+ for e in e.iter().skip(1) {
+ writeln!(stderr, "caused by: {}", e).expect(errmsg);
+ }
+
+ // The backtrace is not always generated. Try to run this example
+ // with `RUST_BACKTRACE=1`.
+ if let Some(backtrace) = e.backtrace() {
+ writeln!(stderr, "backtrace: {:?}", backtrace).expect(errmsg);
+ }
+
+ ::std::process::exit(1);
+ }
+}
+
+// The above main gives you maximum control over how the error is
+// formatted. If you don't care (i.e. you want to display the full
+// error during an assert) you can just call the `display` method
+// on the error object
+#[allow(dead_code)]
+fn alternative_main() {
+ if let Err(ref e) = run() {
+ use std::io::Write;
+ use error_chain::ChainedError; // trait which holds `display`
+ let stderr = &mut ::std::io::stderr();
+ let errmsg = "Error writing to stderr";
+
+ writeln!(stderr, "{}", e.display()).expect(errmsg);
+ ::std::process::exit(1);
+ }
+}
+
+// Use this macro to auto-generate the main above. You may want to
+// set the `RUST_BACKTRACE` env variable to see a backtrace.
+//quick_main!(run);
+
+
+// Most functions will return the `Result` type, imported from the
+// `errors` module. It is a typedef of the standard `Result` type
+// for which the error type is always our own `Error`.
+fn run() -> Result<()> {
+ use std::fs::File;
+
+ // This operation will fail
+ File::open("tretrete")
+ .chain_err(|| "unable to open tretrete file")?;
+
+ Ok(())
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/examples/size.rs
@@ -0,0 +1,40 @@
+#[macro_use]
+extern crate error_chain;
+
+use std::mem::{size_of, size_of_val};
+
+error_chain! {
+ errors {
+ AVariant
+ Another
+ }
+}
+
+fn main() {
+ println!("Memory usage in bytes");
+ println!("---------------------");
+ println!("Result<()>: {}", size_of::<Result<()>>());
+ println!(" (): {}", size_of::<()>());
+ println!(" Error: {}", size_of::<Error>());
+ println!(" ErrorKind: {}", size_of::<ErrorKind>());
+ let msg = ErrorKind::Msg("test".into());
+ println!(" ErrorKind::Msg: {}", size_of_val(&msg));
+ println!(" String: {}", size_of::<String>());
+ println!(" State: {}", size_of::<error_chain::State>());
+ #[cfg(feature = "backtrace")]
+ {
+ let state = error_chain::State {
+ next_error: None,
+ backtrace: None,
+ };
+ println!(" State.next_error: {}", size_of_val(&state.next_error));
+ println!(" State.backtrace: {}", size_of_val(&state.backtrace));
+ }
+ #[cfg(not(feature = "backtrace"))]
+ {
+ let state = error_chain::State {
+ next_error: None,
+ };
+ println!(" State.next_error: {}", size_of_val(&state.next_error));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/src/error_chain.rs
@@ -0,0 +1,426 @@
+/// Prefer to use `error_chain` instead of this macro.
+#[macro_export]
+macro_rules! error_chain_processed {
+ // Default values for `types`.
+ (
+ types {}
+ $( $rest: tt )*
+ ) => {
+ error_chain_processed! {
+ types {
+ Error, ErrorKind, ResultExt, Result;
+ }
+ $( $rest )*
+ }
+ };
+ // With `Result` wrapper.
+ (
+ types {
+ $error_name:ident, $error_kind_name:ident,
+ $result_ext_name:ident, $result_name:ident;
+ }
+ $( $rest: tt )*
+ ) => {
+ error_chain_processed! {
+ types {
+ $error_name, $error_kind_name,
+ $result_ext_name;
+ }
+ $( $rest )*
+ }
+ /// Convenient wrapper around `std::Result`.
+ #[allow(unused)]
+ pub type $result_name<T> = ::std::result::Result<T, $error_name>;
+ };
+ // Without `Result` wrapper.
+ (
+ types {
+ $error_name:ident, $error_kind_name:ident,
+ $result_ext_name:ident;
+ }
+
+ links {
+ $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path )
+ $( #[$meta_links:meta] )*; ) *
+ }
+
+ foreign_links {
+ $( $foreign_link_variant:ident ( $foreign_link_error_path:path )
+ $( #[$meta_foreign_links:meta] )*; )*
+ }
+
+ errors {
+ $( $error_chunks:tt ) *
+ }
+
+ ) => {
+ /// The Error type.
+ ///
+ /// This tuple struct is made of two elements:
+ ///
+ /// - an `ErrorKind` which is used to determine the type of the error.
+ /// - An internal `State`, not meant for direct use outside of `error_chain`
+ /// internals, containing:
+ /// - a backtrace, generated when the error is created.
+ /// - an error chain, used for the implementation of `Error::cause()`.
+ #[derive(Debug)]
+ pub struct $error_name(
+ // The members must be `pub` for `links`.
+ /// The kind of the error.
+ pub $error_kind_name,
+ /// Contains the error chain and the backtrace.
+ #[doc(hidden)]
+ pub $crate::State,
+ );
+
+ impl $crate::ChainedError for $error_name {
+ type ErrorKind = $error_kind_name;
+
+ fn new(kind: $error_kind_name, state: $crate::State) -> $error_name {
+ $error_name(kind, state)
+ }
+
+ fn from_kind(kind: Self::ErrorKind) -> Self {
+ Self::from_kind(kind)
+ }
+
+ fn with_chain<E, K>(error: E, kind: K)
+ -> Self
+ where E: ::std::error::Error + Send + 'static,
+ K: Into<Self::ErrorKind>
+ {
+ Self::with_chain(error, kind)
+ }
+
+ fn kind(&self) -> &Self::ErrorKind {
+ self.kind()
+ }
+
+ fn iter(&self) -> $crate::ErrorChainIter {
+ $crate::ErrorChainIter(Some(self))
+ }
+
+ fn backtrace(&self) -> Option<&$crate::Backtrace> {
+ self.backtrace()
+ }
+
+ impl_extract_backtrace!($error_name
+ $error_kind_name
+ $([$link_error_path, $(#[$meta_links])*])*);
+ }
+
+ #[allow(dead_code)]
+ impl $error_name {
+ /// Constructs an error from a kind, and generates a backtrace.
+ pub fn from_kind(kind: $error_kind_name) -> $error_name {
+ $error_name(
+ kind,
+ $crate::State::default(),
+ )
+ }
+
+ /// Constructs a chained error from another error and a kind, and generates a backtrace.
+ pub fn with_chain<E, K>(error: E, kind: K)
+ -> $error_name
+ where E: ::std::error::Error + Send + 'static,
+ K: Into<$error_kind_name>
+ {
+ $error_name(
+ kind.into(),
+ $crate::State::new::<$error_name>(Box::new(error), ),
+ )
+ }
+
+ /// Returns the kind of the error.
+ pub fn kind(&self) -> &$error_kind_name {
+ &self.0
+ }
+
+ /// Iterates over the error chain.
+ pub fn iter(&self) -> $crate::ErrorChainIter {
+ $crate::ChainedError::iter(self)
+ }
+
+ /// Returns the backtrace associated with this error.
+ pub fn backtrace(&self) -> Option<&$crate::Backtrace> {
+ self.1.backtrace()
+ }
+ }
+
+ impl ::std::error::Error for $error_name {
+ fn description(&self) -> &str {
+ self.0.description()
+ }
+
+ fn cause(&self) -> Option<&::std::error::Error> {
+ match self.1.next_error {
+ Some(ref c) => Some(&**c),
+ None => {
+ match self.0 {
+ $(
+ $(#[$meta_foreign_links])*
+ $error_kind_name::$foreign_link_variant(ref foreign_err) => {
+ foreign_err.cause()
+ }
+ ) *
+ _ => None
+ }
+ }
+ }
+ }
+ }
+
+ impl ::std::fmt::Display for $error_name {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ ::std::fmt::Display::fmt(&self.0, f)
+ }
+ }
+
+ $(
+ $(#[$meta_links])*
+ impl From<$link_error_path> for $error_name {
+ fn from(e: $link_error_path) -> Self {
+ $error_name(
+ $error_kind_name::$link_variant(e.0),
+ e.1,
+ )
+ }
+ }
+ ) *
+
+ $(
+ $(#[$meta_foreign_links])*
+ impl From<$foreign_link_error_path> for $error_name {
+ fn from(e: $foreign_link_error_path) -> Self {
+ $error_name::from_kind(
+ $error_kind_name::$foreign_link_variant(e)
+ )
+ }
+ }
+ ) *
+
+ impl From<$error_kind_name> for $error_name {
+ fn from(e: $error_kind_name) -> Self {
+ $error_name::from_kind(e)
+ }
+ }
+
+ impl<'a> From<&'a str> for $error_name {
+ fn from(s: &'a str) -> Self {
+ $error_name::from_kind(s.into())
+ }
+ }
+
+ impl From<String> for $error_name {
+ fn from(s: String) -> Self {
+ $error_name::from_kind(s.into())
+ }
+ }
+
+ impl ::std::ops::Deref for $error_name {
+ type Target = $error_kind_name;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+
+
+ // The ErrorKind type
+ // --------------
+
+ quick_error! {
+ /// The kind of an error.
+ #[derive(Debug)]
+ pub enum $error_kind_name {
+
+ /// A convenient variant for String.
+ Msg(s: String) {
+ description(&s)
+ display("{}", s)
+ }
+
+ $(
+ $(#[$meta_links])*
+ $link_variant(e: $link_kind_path) {
+ description(e.description())
+ display("{}", e)
+ }
+ ) *
+
+ $(
+ $(#[$meta_foreign_links])*
+ $foreign_link_variant(err: $foreign_link_error_path) {
+ description(::std::error::Error::description(err))
+ display("{}", err)
+ }
+ ) *
+
+ $($error_chunks)*
+ }
+ }
+
+ $(
+ $(#[$meta_links])*
+ impl From<$link_kind_path> for $error_kind_name {
+ fn from(e: $link_kind_path) -> Self {
+ $error_kind_name::$link_variant(e)
+ }
+ }
+ ) *
+
+ impl<'a> From<&'a str> for $error_kind_name {
+ fn from(s: &'a str) -> Self {
+ $error_kind_name::Msg(s.to_string())
+ }
+ }
+
+ impl From<String> for $error_kind_name {
+ fn from(s: String) -> Self {
+ $error_kind_name::Msg(s)
+ }
+ }
+
+ impl From<$error_name> for $error_kind_name {
+ fn from(e: $error_name) -> Self {
+ e.0
+ }
+ }
+
+ // The ResultExt trait defines the `chain_err` method.
+
+ /// Additional methods for `Result`, for easy interaction with this crate.
+ pub trait $result_ext_name<T, E> {
+ /// If the `Result` is an `Err` then `chain_err` evaluates the closure,
+ /// which returns *some type that can be converted to `ErrorKind`*, boxes
+ /// the original error to store as the cause, then returns a new error
+ /// containing the original error.
+ fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name>
+ where F: FnOnce() -> EK,
+ EK: Into<$error_kind_name>;
+ }
+
+ impl<T, E> $result_ext_name<T, E> for ::std::result::Result<T, E> where E: ::std::error::Error + Send + 'static {
+ fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name>
+ where F: FnOnce() -> EK,
+ EK: Into<$error_kind_name> {
+ self.map_err(move |e| {
+ let state = $crate::State::new::<$error_name>(Box::new(e), );
+ $crate::ChainedError::new(callback().into(), state)
+ })
+ }
+ }
+
+
+ };
+}
+
+/// Internal macro used for reordering of the fields.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! error_chain_processing {
+ (
+ ({}, $b:tt, $c:tt, $d:tt)
+ types $content:tt
+ $( $tail:tt )*
+ ) => {
+ error_chain_processing! {
+ ($content, $b, $c, $d)
+ $($tail)*
+ }
+ };
+ (
+ ($a:tt, {}, $c:tt, $d:tt)
+ links $content:tt
+ $( $tail:tt )*
+ ) => {
+ error_chain_processing! {
+ ($a, $content, $c, $d)
+ $($tail)*
+ }
+ };
+ (
+ ($a:tt, $b:tt, {}, $d:tt)
+ foreign_links $content:tt
+ $( $tail:tt )*
+ ) => {
+ error_chain_processing! {
+ ($a, $b, $content, $d)
+ $($tail)*
+ }
+ };
+ (
+ ($a:tt, $b:tt, $c:tt, {})
+ errors $content:tt
+ $( $tail:tt )*
+ ) => {
+ error_chain_processing! {
+ ($a, $b, $c, $content)
+ $($tail)*
+ }
+ };
+ ( ($a:tt, $b:tt, $c:tt, $d:tt) ) => {
+ error_chain_processed! {
+ types $a
+ links $b
+ foreign_links $c
+ errors $d
+ }
+ };
+}
+
+/// This macro is used for handling of duplicated and out-of-order fields. For
+/// the exact rules, see `error_chain_processed`.
+#[macro_export]
+macro_rules! error_chain {
+ ( $( $block_name:ident { $( $block_content:tt )* } )* ) => {
+ error_chain_processing! {
+ ({}, {}, {}, {})
+ $($block_name { $( $block_content )* })*
+ }
+ };
+}
+
+/// Macro used to manage the `backtrace` feature.
+///
+/// See
+/// https://www.reddit.com/r/rust/comments/57virt/hey_rustaceans_got_an_easy_question_ask_here/da5r4ti/?context=3
+/// for more details.
+#[macro_export]
+#[doc(hidden)]
+#[cfg(feature = "backtrace")]
+macro_rules! impl_extract_backtrace {
+ ($error_name: ident
+ $error_kind_name: ident
+ $([$link_error_path: path, $(#[$meta_links: meta])*])*) => {
+ fn extract_backtrace(e: &(::std::error::Error + Send + 'static))
+ -> Option<::std::sync::Arc<$crate::Backtrace>> {
+ if let Some(e) = e.downcast_ref::<$error_name>() {
+ return e.1.backtrace.clone();
+ }
+ $(
+ $( #[$meta_links] )*
+ {
+ if let Some(e) = e.downcast_ref::<$link_error_path>() {
+ return e.1.backtrace.clone();
+ }
+ }
+ ) *
+ None
+ }
+ }
+}
+
+/// Macro used to manage the `backtrace` feature.
+///
+/// See
+/// https://www.reddit.com/r/rust/comments/57virt/hey_rustaceans_got_an_easy_question_ask_here/da5r4ti/?context=3
+/// for more details.
+#[macro_export]
+#[doc(hidden)]
+#[cfg(not(feature = "backtrace"))]
+macro_rules! impl_extract_backtrace {
+ ($error_name: ident
+ $error_kind_name: ident
+ $([$link_error_path: path, $(#[$meta_links: meta])*])*) => {}
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/src/example_generated.rs
@@ -0,0 +1,38 @@
+//! These modules show an example of code generated by the macro. **IT MUST NOT BE
+//! USED OUTSIDE THIS CRATE**.
+//!
+//! This is the basic error structure. You can see that `ErrorKind`
+//! has been populated in a variety of ways. All `ErrorKind`s get a
+//! `Msg` variant for basic errors. When strings are converted to
+//! `ErrorKind`s they become `ErrorKind::Msg`. The "links" defined in
+//! the macro are expanded to the `Inner` variant, and the
+//! "foreign links" to the `Io` variant.
+//!
+//! Both types come with a variety of `From` conversions as well:
+//! `Error` can be created from `ErrorKind`, `&str` and `String`,
+//! and the `links` and `foreign_links` error types. `ErrorKind`
+//! can be created from the corresponding `ErrorKind`s of the link
+//! types, as well as from `&str` and `String`.
+//!
+//! `into()` and `From::from` are used heavily to massage types into
+//! the right shape. Which one to use in any specific case depends on
+//! the influence of type inference, but there are some patterns that
+//! arise frequently.
+
+/// Another code generated by the macro.
+pub mod inner {
+ error_chain! {}
+}
+
+error_chain! {
+ links {
+ Inner(inner::Error, inner::ErrorKind) #[doc = "Link to another `ErrorChain`."];
+ }
+ foreign_links {
+ Io(::std::io::Error) #[doc = "Link to a `std::error::Error` type."];
+ }
+ errors {
+ #[doc = "A custom error kind."]
+ Custom
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/src/lib.rs
@@ -0,0 +1,659 @@
+#![deny(missing_docs)]
+
+//! A library for consistent and reliable error handling
+//!
+//! error-chain makes it easy to take full advantage of Rust's
+//! powerful error handling features without the overhead of
+//! maintaining boilerplate error types and conversions. It implements
+//! an opinionated strategy for defining your own error types, as well
+//! as conversions from others' error types.
+//!
+//! ## Quick start
+//!
+//! If you just want to set up your new project with error-chain,
+//! follow the [quickstart.rs] template, and read this [intro]
+//! to error-chain.
+//!
+//! [quickstart.rs]: https://github.com/brson/error-chain/blob/master/examples/quickstart.rs
+//! [intro]: http://brson.github.io/2016/11/30/starting-with-error-chain
+//!
+//! ## Why error chain?
+//!
+//! * error-chain is easy to configure. Handle errors robustly with minimal
+//! effort.
+//! * Basic error handling requires no maintenance of custom error types
+//! nor the `From` conversions that make `?` work.
+//! * error-chain scales from simple error handling strategies to more
+//! rigorous. Return formatted strings for simple errors, only
+//! introducing error variants and their strong typing as needed for
+//! advanced error recovery.
+//! * error-chain makes it trivial to correctly manage the [cause] of
+//! the errors generated by your own code. This is the "chaining"
+//! in "error-chain".
+//!
+//! [cause]: https://doc.rust-lang.org/std/error/trait.Error.html#method.cause
+//!
+//! ## Principles of error-chain
+//!
+//! error-chain is based on the following principles:
+//!
+//! * No error should ever be discarded. This library primarily
+//! makes it easy to "chain" errors with the `chain_err` method.
+//! * Introducing new errors is trivial. Simple errors can be introduced
+//! at the error site with just a string.
+//! * Handling errors is possible with pattern matching.
+//! * Conversions between error types are done in an automatic and
+//! consistent way - `From` conversion behavior is never specified
+//! explicitly.
+//! * Errors implement Send.
+//! * Errors can carry backtraces.
+//!
+//! Similar to other libraries like [error-type] and [quick-error],
+//! this library introduces the error chaining mechanism originally
+//! employed by Cargo. The `error_chain!` macro declares the types
+//! and implementation boilerplate necessary for fulfilling a
+//! particular error-handling strategy. Most importantly it defines a
+//! custom error type (called `Error` by convention) and the `From`
+//! conversions that let the `try!` macro and `?` operator work.
+//!
+//! This library differs in a few ways from previous error libs:
+//!
+//! * Instead of defining the custom `Error` type as an enum, it is a
+//! struct containing an `ErrorKind` (which defines the
+//! `description` and `display` methods for the error), an opaque,
+//! optional, boxed `std::error::Error + Send + 'static` object
+//! (which defines the `cause`, and establishes the links in the
+//! error chain), and a `Backtrace`.
+//! * The macro also defines a `ResultExt` trait that defines a
+//! `chain_err` method. This method on all `std::error::Error + Send + 'static`
+//! types extends the error chain by boxing the current
+//! error into an opaque object and putting it inside a new concrete
+//! error.
+//! * It provides automatic `From` conversions between other error types
+//! defined by the `error_chain!` that preserve type information,
+//! and facilitate seamless error composition and matching of composed
+//! errors.
+//! * It provides automatic `From` conversions between any other error
+//! type that hides the type of the other error in the `cause` box.
+//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at
+//! the earliest opportunity and propagates it down the stack through
+//! `From` and `ResultExt` conversions.
+//!
+//! To accomplish its goals it makes some tradeoffs:
+//!
+//! * The split between the `Error` and `ErrorKind` types can make it
+//! slightly more cumbersome to instantiate new (unchained) errors,
+//! requiring an `Into` or `From` conversion; as well as slightly
+//! more cumbersome to match on errors with another layer of types
+//! to match.
+//! * Because the error type contains `std::error::Error + Send + 'static` objects,
+//! it can't implement `PartialEq` for easy comparisons.
+//!
+//! ## Declaring error types
+//!
+//! Generally, you define one family of error types per crate, though
+//! it's also perfectly fine to define error types on a finer-grained
+//! basis, such as per module.
+//!
+//! Assuming you are using crate-level error types, typically you will
+//! define an `errors` module and inside it call `error_chain!`:
+//!
+//! ```
+//! # #[macro_use] extern crate error_chain;
+//! mod other_error {
+//! error_chain! {}
+//! }
+//!
+//! error_chain! {
+//! // The type defined for this error. These are the conventional
+//! // and recommended names, but they can be arbitrarily chosen.
+//! //
+//! // It is also possible to leave this section out entirely, or
+//! // leave it empty, and these names will be used automatically.
+//! types {
+//! Error, ErrorKind, ResultExt, Result;
+//! }
+//!
+//! // Without the `Result` wrapper:
+//! //
+//! // types {
+//! // Error, ErrorKind, ResultExt;
+//! // }
+//!
+//! // Automatic conversions between this error chain and other
+//! // error chains. In this case, it will e.g. generate an
+//! // `ErrorKind` variant called `Another` which in turn contains
+//! // the `other_error::ErrorKind`, with conversions from
+//! // `other_error::Error`.
+//! //
+//! // Optionally, some attributes can be added to a variant.
+//! //
+//! // This section can be empty.
+//! links {
+//! Another(other_error::Error, other_error::ErrorKind) #[cfg(unix)];
+//! }
+//!
+//! // Automatic conversions between this error chain and other
+//! // error types not defined by the `error_chain!`. These will be
+//! // wrapped in a new error with, in the first case, the
+//! // `ErrorKind::Fmt` variant. The description and cause will
+//! // forward to the description and cause of the original error.
+//! //
+//! // Optionally, some attributes can be added to a variant.
+//! //
+//! // This section can be empty.
+//! foreign_links {
+//! Fmt(::std::fmt::Error);
+//! Io(::std::io::Error) #[cfg(unix)];
+//! }
+//!
+//! // Define additional `ErrorKind` variants. The syntax here is
+//! // the same as `quick_error!`, but the `from()` and `cause()`
+//! // syntax is not supported.
+//! errors {
+//! InvalidToolchainName(t: String) {
+//! description("invalid toolchain name")
+//! display("invalid toolchain name: '{}'", t)
+//! }
+//! }
+//! }
+//!
+//! # fn main() {}
+//! ```
+//!
+//! Each section, `types`, `links`, `foreign_links`, and `errors` may
+//! be omitted if it is empty.
+//!
+//! This populates the module with a number of definitions,
+//! the most important of which are the `Error` type
+//! and the `ErrorKind` type. An example of generated code can be found in the
+//! [example_generated](example_generated) module.
+//!
+//! ## Returning new errors
+//!
+//! Introducing new error chains, with a string message:
+//!
+//! ```
+//! # #[macro_use] extern crate error_chain;
+//! # fn main() {}
+//! # error_chain! {}
+//! fn foo() -> Result<()> {
+//! Err("foo error!".into())
+//! }
+//! ```
+//!
+//! Introducing new error chains, with an `ErrorKind`:
+//!
+//! ```
+//! # #[macro_use] extern crate error_chain;
+//! # fn main() {}
+//! error_chain! {
+//! errors { FooError }
+//! }
+//!
+//! fn foo() -> Result<()> {
+//! Err(ErrorKind::FooError.into())
+//! }
+//! ```
+//!
+//! Note that the return type is the typedef `Result`, which is
+//! defined by the macro as `pub type Result<T> =
+//! ::std::result::Result<T, Error>`. Note that in both cases
+//! `.into()` is called to convert a type into the `Error` type; both
+//! strings and `ErrorKind` have `From` conversions to turn them into
+//! `Error`.
+//!
+//! When the error is emitted inside a `try!` macro or behind the
+//! `?` operator, the explicit conversion isn't needed; `try!` will
+//! automatically convert `Err(ErrorKind)` to `Err(Error)`. So the
+//! below is equivalent to the previous:
+//!
+//! ```
+//! # #[macro_use] extern crate error_chain;
+//! # fn main() {}
+//! # error_chain! { errors { FooError } }
+//! fn foo() -> Result<()> {
+//! Ok(try!(Err(ErrorKind::FooError)))
+//! }
+//!
+//! fn bar() -> Result<()> {
+//! Ok(try!(Err("bogus!")))
+//! }
+//! ```
+//!
+//! ## The `bail!` macro
+//!
+//! The above method of introducing new errors works but is a little
+//! verbose. Instead we can use the `bail!` macro, which, much like `try!`
+//! and `?`, performs an early return with conversions. With `bail!` the
+//! previous examples look like:
+//!
+//! ```
+//! # #[macro_use] extern crate error_chain;
+//! # fn main() {}
+//! # error_chain! { errors { FooError } }
+//! fn foo() -> Result<()> {
+//! if true {
+//! bail!(ErrorKind::FooError);
+//! } else {
+//! Ok(())
+//! }
+//! }
+//!
+//! fn bar() -> Result<()> {
+//! if true {
+//! bail!("bogus!");
+//! } else {
+//! Ok(())
+//! }
+//! }
+//! ```
+//!
+//! ## Chaining errors
+//!
+//! To extend the error chain:
+//!
+//! ```
+//! # #[macro_use] extern crate error_chain;
+//! # fn main() {}
+//! # error_chain! {}
+//! # fn do_something() -> Result<()> { unimplemented!() }
+//! # fn test() -> Result<()> {
+//! let res: Result<()> = do_something().chain_err(|| "something went wrong");
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! `chain_err` can be called on any `Result` type where the contained
+//! error type implements `std::error::Error + Send + 'static`. If
+//! the `Result` is an `Err` then `chain_err` evaluates the closure,
+//! which returns *some type that can be converted to `ErrorKind`*,
+//! boxes the original error to store as the cause, then returns a new
+//! error containing the original error.
+//!
+//! ## Matching errors
+//!
+//! error-chain error variants are matched with simple patterns.
+//! `Error` is a tuple struct and its first field is the `ErrorKind`,
+//! making dispatching on error kinds relatively compact:
+//!
+//! ```
+//! # #[macro_use] extern crate error_chain;
+//! # fn main() {
+//! error_chain! {
+//! errors {
+//! InvalidToolchainName(t: String) {
+//! description("invalid toolchain name")
+//! display("invalid toolchain name: '{}'", t)
+//! }
+//! }
+//! }
+//!
+//! match Error::from("error!") {
+//! Error(ErrorKind::InvalidToolchainName(_), _) => { }
+//! Error(ErrorKind::Msg(_), _) => { }
+//! }
+//! # }
+//! ```
+//!
+//! Chained errors are also matched with (relatively) compact syntax
+//!
+//! ```
+//! # #[macro_use] extern crate error_chain;
+//! mod utils {
+//! error_chain! {
+//! errors {
+//! BadStuff {
+//! description("bad stuff")
+//! }
+//! }
+//! }
+//! }
+//!
+//! mod app {
+//! error_chain! {
+//! links {
+//! Utils(::utils::Error, ::utils::ErrorKind);
+//! }
+//! }
+//! }
+//!
+//!
+//! # fn main() {
+//! match app::Error::from("error!") {
+//! app::Error(app::ErrorKind::Utils(utils::ErrorKind::BadStuff), _) => { }
+//! _ => { }
+//! }
+//! # }
+//! ```
+//!
+//! ## Foreign links
+//!
+//! Errors that do not conform to the same conventions as this library
+//! can still be included in the error chain. They are considered "foreign
+//! errors", and are declared using the `foreign_links` block of the
+//! `error_chain!` macro. `Error`s are automatically created from
+//! foreign errors by the `try!` macro.
+//!
+//! Foreign links and regular links have one crucial difference:
+//! `From` conversions for regular links *do not introduce a new error
+//! into the error chain*, while conversions for foreign links *always
+//! introduce a new error into the error chain*. So for the example
+//! above all errors deriving from the `temp::Error` type will be
+//! presented to the user as a new `ErrorKind::Temp` variant, and the
+//! cause will be the original `temp::Error` error. In contrast, when
+//! `rustup_utils::Error` is converted to `Error` the two `ErrorKind`s
+//! are converted between each other to create a new `Error` but the
+//! old error is discarded; there is no "cause" created from the
+//! original error.
+//!
+//! ## Backtraces
+//!
+//! If the `RUST_BACKTRACE` environment variable is set to anything
+//! but ``0``, the earliest non-foreign error to be generated creates
+//! a single backtrace, which is passed through all `From` conversions
+//! and `chain_err` invocations of compatible types. To read the
+//! backtrace just call the `backtrace()` method.
+//!
+//! Backtrace generation can be disabled by turning off the `backtrace` feature.
+//!
+//! ## Iteration
+//!
+//! The `iter` method returns an iterator over the chain of error boxes.
+//!
+//! [error-type]: https://github.com/DanielKeep/rust-error-type
+//! [quick-error]: https://github.com/tailhook/quick-error
+
+
+#[cfg(feature = "backtrace")]
+extern crate backtrace;
+
+use std::error;
+use std::iter::Iterator;
+#[cfg(feature = "backtrace")]
+use std::sync::Arc;
+use std::fmt;
+
+#[cfg(feature = "backtrace")]
+pub use backtrace::Backtrace;
+#[cfg(not(feature = "backtrace"))]
+/// Dummy type used when the `backtrace` feature is disabled.
+pub type Backtrace = ();
+
+#[macro_use]
+mod quick_error;
+#[macro_use]
+mod error_chain;
+#[macro_use]
+mod quick_main;
+pub use quick_main::ExitCode;
+#[cfg(feature = "example_generated")]
+pub mod example_generated;
+
+/// Iterator over the error chain using the `Error::cause()` method.
+pub struct ErrorChainIter<'a>(pub Option<&'a error::Error>);
+
+impl<'a> Iterator for ErrorChainIter<'a> {
+ type Item = &'a error::Error;
+
+ fn next<'b>(&'b mut self) -> Option<&'a error::Error> {
+ match self.0.take() {
+ Some(e) => {
+ self.0 = e.cause();
+ Some(e)
+ }
+ None => None,
+ }
+ }
+}
+
+/// Returns a backtrace of the current call stack if `RUST_BACKTRACE`
+/// is set to anything but ``0``, and `None` otherwise. This is used
+/// in the generated error implementations.
+#[cfg(feature = "backtrace")]
+#[doc(hidden)]
+pub fn make_backtrace() -> Option<Arc<Backtrace>> {
+ match std::env::var_os("RUST_BACKTRACE") {
+ Some(ref val) if val != "0" => Some(Arc::new(Backtrace::new())),
+ _ => None,
+ }
+}
+
+/// This trait is implemented on all the errors generated by the `error_chain`
+/// macro.
+pub trait ChainedError: error::Error + Send + 'static {
+ /// Associated kind type.
+ type ErrorKind;
+
+ /// Constructs an error from a kind, and generates a backtrace.
+ fn from_kind(kind: Self::ErrorKind) -> Self where Self: Sized;
+
+ /// Constructs a chained error from another error and a kind, and generates a backtrace.
+ fn with_chain<E, K>(error: E, kind: K) -> Self
+ where Self: Sized,
+ E: ::std::error::Error + Send + 'static,
+ K: Into<Self::ErrorKind>;
+
+ /// Returns the kind of the error.
+ fn kind(&self) -> &Self::ErrorKind;
+
+ /// Iterates over the error chain.
+ fn iter(&self) -> ErrorChainIter;
+
+ /// Returns the backtrace associated with this error.
+ fn backtrace(&self) -> Option<&Backtrace>;
+
+ /// Returns an object which implements `Display` for printing the full
+ /// context of this error.
+ ///
+ /// The full cause chain and backtrace, if present, will be printed.
+ fn display<'a>(&'a self) -> Display<'a, Self> {
+ Display(self)
+ }
+
+ /// Creates an error from its parts.
+ #[doc(hidden)]
+ fn new(kind: Self::ErrorKind, state: State) -> Self where Self: Sized;
+
+ /// Returns the first known backtrace, either from its State or from one
+ /// of the errors from `foreign_links`.
+ #[cfg(feature = "backtrace")]
+ #[doc(hidden)]
+ fn extract_backtrace(e: &(error::Error + Send + 'static)) -> Option<Arc<Backtrace>>
+ where Self: Sized;
+}
+
+/// A struct which formats an error for output.
+#[derive(Debug)]
+pub struct Display<'a, T: 'a + ?Sized>(&'a T);
+
+impl<'a, T> fmt::Display for Display<'a, T>
+ where T: ChainedError
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ try!(writeln!(fmt, "Error: {}", self.0));
+
+ for e in self.0.iter().skip(1) {
+ try!(writeln!(fmt, "Caused by: {}", e));
+ }
+
+ if let Some(backtrace) = self.0.backtrace() {
+ try!(writeln!(fmt, "{:?}", backtrace));
+ }
+
+ Ok(())
+ }
+}
+
+/// Common state between errors.
+#[derive(Debug)]
+#[doc(hidden)]
+pub struct State {
+ /// Next error in the error chain.
+ pub next_error: Option<Box<error::Error + Send>>,
+ /// Backtrace for the current error.
+ #[cfg(feature = "backtrace")]
+ pub backtrace: Option<Arc<Backtrace>>,
+}
+
+impl Default for State {
+ #[cfg(feature = "backtrace")]
+ fn default() -> State {
+ State {
+ next_error: None,
+ backtrace: make_backtrace(),
+ }
+ }
+
+ #[cfg(not(feature = "backtrace"))]
+ fn default() -> State {
+ State { next_error: None }
+ }
+}
+
+impl State {
+ /// Creates a new State type
+ #[cfg(feature = "backtrace")]
+ pub fn new<CE: ChainedError>(e: Box<error::Error + Send>) -> State {
+ let backtrace = CE::extract_backtrace(&*e).or_else(make_backtrace);
+ State {
+ next_error: Some(e),
+ backtrace: backtrace,
+ }
+ }
+
+ /// Creates a new State type
+ #[cfg(not(feature = "backtrace"))]
+ pub fn new<CE: ChainedError>(e: Box<error::Error + Send>) -> State {
+ State { next_error: Some(e) }
+ }
+
+ /// Returns the inner backtrace if present.
+ #[cfg(feature = "backtrace")]
+ pub fn backtrace(&self) -> Option<&Backtrace> {
+ self.backtrace.as_ref().map(|v| &**v)
+ }
+
+ /// Returns the inner backtrace if present.
+ #[cfg(not(feature = "backtrace"))]
+ pub fn backtrace(&self) -> Option<&Backtrace> {
+ None
+ }
+}
+
+/// Exits a function early with an error
+///
+/// The `bail!` macro provides an easy way to exit a function.
+/// `bail!(expr)` is equivalent to writing.
+///
+/// ```
+/// # #[macro_use] extern crate error_chain;
+/// # error_chain! { }
+/// # fn main() { }
+/// # fn foo() -> Result<()> {
+/// # let expr = "";
+/// return Err(expr.into());
+/// # }
+/// ```
+///
+/// And as shorthand it takes a formatting string a la `println!`:
+///
+/// ```
+/// # #[macro_use] extern crate error_chain;
+/// # error_chain! { }
+/// # fn main() { }
+/// # fn foo() -> Result<()> {
+/// # let n = 0;
+/// bail!("bad number: {}", n);
+/// # }
+/// ```
+///
+/// # Examples
+///
+/// Bailing on a custom error:
+///
+/// ```
+/// # #[macro_use] extern crate error_chain;
+/// # fn main() {}
+/// error_chain! {
+/// errors { FooError }
+/// }
+///
+/// fn foo() -> Result<()> {
+/// if bad_condition() {
+/// bail!(ErrorKind::FooError);
+/// }
+///
+/// Ok(())
+/// }
+///
+/// # fn bad_condition() -> bool { true }
+/// ```
+///
+/// Bailing on a formatted string:
+///
+/// ```
+/// # #[macro_use] extern crate error_chain;
+/// # fn main() {}
+/// error_chain! { }
+///
+/// fn foo() -> Result<()> {
+/// if let Some(bad_num) = bad_condition() {
+/// bail!("so bad: {}", bad_num);
+/// }
+///
+/// Ok(())
+/// }
+///
+/// # fn bad_condition() -> Option<i8> { None }
+/// ```
+#[macro_export]
+macro_rules! bail {
+ ($e:expr) => {
+ return Err($e.into());
+ };
+ ($fmt:expr, $($arg:tt)+) => {
+ return Err(format!($fmt, $($arg)+).into());
+ };
+}
+
+/// Exits a function early with an error if the condition is not satisfied
+///
+/// The `ensure!` macro is a convenience helper that provides a way to exit
+/// a function with an error if the given condition fails.
+///
+/// As an example, `ensure!(condition, "error code: {}", errcode)` is equivalent to
+///
+/// ```
+/// # #[macro_use] extern crate error_chain;
+/// # error_chain! { }
+/// # fn main() { }
+/// # fn foo() -> Result<()> {
+/// # let errcode = 0u8;
+/// # let condition = true;
+/// if !condition {
+/// bail!("error code: {}", errcode);
+/// }
+/// # Ok(())
+/// # }
+/// ```
+///
+/// See documentation for `bail!` macro for further details.
+#[macro_export]
+macro_rules! ensure {
+ ($cond:expr, $e:expr) => {
+ if !($cond) {
+ bail!($e);
+ }
+ };
+ ($cond:expr, $fmt:expr, $($arg:tt)+) => {
+ if !($cond) {
+ bail!($fmt, $($arg)+);
+ }
+ };
+}
+
+#[doc(hidden)]
+pub mod mock {
+ error_chain!{}
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/src/quick_error.rs
@@ -0,0 +1,529 @@
+// From https://github.com/tailhook/quick-error
+// Changes:
+// - replace `impl Error` by `impl Item::description`
+// - $imeta
+
+#[macro_export]
+macro_rules! quick_error {
+ ( $(#[$meta:meta])*
+ pub enum $name:ident { $($chunks:tt)* }
+ ) => {
+ quick_error!(SORT [pub enum $name $(#[$meta])* ]
+ items [] buf []
+ queue [ $($chunks)* ]);
+ };
+ ( $(#[$meta:meta])*
+ enum $name:ident { $($chunks:tt)* }
+ ) => {
+ quick_error!(SORT [enum $name $(#[$meta])* ]
+ items [] buf []
+ queue [ $($chunks)* ]);
+ };
+ // Queue is empty, can do the work
+ (SORT [enum $name:ident $( #[$meta:meta] )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [ ]
+ queue [ ]
+ ) => {
+ quick_error!(ENUM_DEFINITION [enum $name $( #[$meta] )*]
+ body []
+ queue [$($( #[$imeta] )*
+ => $iitem: $imode [$( $ivar: $ityp ),*] )*]
+ );
+ quick_error!(IMPLEMENTATIONS $name {$(
+ $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
+ )*});
+ $(
+ quick_error!(ERROR_CHECK $imode $($ifuncs)*);
+ )*
+ };
+ (SORT [pub enum $name:ident $( #[$meta:meta] )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [ ]
+ queue [ ]
+ ) => {
+ quick_error!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*]
+ body []
+ queue [$($( #[$imeta] )*
+ => $iitem: $imode [$( $ivar: $ityp ),*] )*]
+ );
+ quick_error!(IMPLEMENTATIONS $name {$(
+ $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
+ )*});
+ $(
+ quick_error!(ERROR_CHECK $imode $($ifuncs)*);
+ )*
+ };
+ // Add meta to buffer
+ (SORT [$( $def:tt )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [$( #[$bmeta:meta] )*]
+ queue [ #[$qmeta:meta] $( $tail:tt )*]
+ ) => {
+ quick_error!(SORT [$( $def )*]
+ items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
+ buf [$( #[$bmeta] )* #[$qmeta] ]
+ queue [$( $tail )*]);
+ };
+ // Add ident to buffer
+ (SORT [$( $def:tt )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [$( #[$bmeta:meta] )*]
+ queue [ $qitem:ident $( $tail:tt )*]
+ ) => {
+ quick_error!(SORT [$( $def )*]
+ items [$( $(#[$imeta])*
+ => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
+ buf [$(#[$bmeta])* => $qitem : UNIT [ ] ]
+ queue [$( $tail )*]);
+ };
+ // Flush buffer on meta after ident
+ (SORT [$( $def:tt )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [$( #[$bmeta:meta] )*
+ => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
+ queue [ #[$qmeta:meta] $( $tail:tt )*]
+ ) => {
+ quick_error!(SORT [$( $def )*]
+ enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )*
+ $(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
+ $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
+ buf [ #[$qmeta] ]
+ queue [$( $tail )*]);
+ };
+ // Add tuple enum-variant
+ (SORT [$( $def:tt )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
+ queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*]
+ ) => {
+ quick_error!(SORT [$( $def )*]
+ items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
+ buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),*] ]
+ queue [$( $tail )*]
+ );
+ };
+ // Add struct enum-variant - e.g. { descr: &'static str }
+ (SORT [$( $def:tt )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
+ queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*]
+ ) => {
+ quick_error!(SORT [$( $def )*]
+ items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
+ buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ]
+ queue [$( $tail )*]);
+ };
+ // Add struct enum-variant, with excess comma - e.g. { descr: &'static str, }
+ (SORT [$( $def:tt )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
+ queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*]
+ ) => {
+ quick_error!(SORT [$( $def )*]
+ items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
+ buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ]
+ queue [$( $tail )*]);
+ };
+ // Add braces and flush always on braces
+ (SORT [$( $def:tt )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [$( #[$bmeta:meta] )*
+ => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
+ queue [ {$( $qfuncs:tt )*} $( $tail:tt )*]
+ ) => {
+ quick_error!(SORT [$( $def )*]
+ items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
+ $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ]
+ buf [ ]
+ queue [$( $tail )*]);
+ };
+ // Flush buffer on double ident
+ (SORT [$( $def:tt )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [$( #[$bmeta:meta] )*
+ => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
+ queue [ $qitem:ident $( $tail:tt )*]
+ ) => {
+ quick_error!(SORT [$( $def )*]
+ items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
+ $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
+ buf [ => $qitem : UNIT [ ] ]
+ queue [$( $tail )*]);
+ };
+ // Flush buffer on end
+ (SORT [$( $def:tt )*]
+ items [$($( #[$imeta:meta] )*
+ => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+ {$( $ifuncs:tt )*} )* ]
+ buf [$( #[$bmeta:meta] )*
+ => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
+ queue [ ]
+ ) => {
+ quick_error!(SORT [$( $def )*]
+ items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
+ $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
+ buf [ ]
+ queue [ ]);
+ };
+ // Public enum (Queue Empty)
+ (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*]
+ body [$($( #[$imeta:meta] )*
+ => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
+ queue [ ]
+ ) => {
+ $(#[$meta])*
+ pub enum $name {
+ $(
+ $(#[$imeta])*
+ $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*,
+ )*
+ }
+ };
+ // Private enum (Queue Empty)
+ (ENUM_DEFINITION [enum $name:ident $( #[$meta:meta] )*]
+ body [$($( #[$imeta:meta] )*
+ => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
+ queue [ ]
+ ) => {
+ $(#[$meta])*
+ enum $name {
+ $(
+ $(#[$imeta])*
+ $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*,
+ )*
+ }
+ };
+ // Unit variant
+ (ENUM_DEFINITION [$( $def:tt )*]
+ body [$($( #[$imeta:meta] )*
+ => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
+ queue [$( #[$qmeta:meta] )*
+ => $qitem:ident: UNIT [ ] $( $queue:tt )*]
+ ) => {
+ quick_error!(ENUM_DEFINITION [ $($def)* ]
+ body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
+ $( #[$qmeta] )* => $qitem () {} ]
+ queue [ $($queue)* ]
+ );
+ };
+ // Tuple variant
+ (ENUM_DEFINITION [$( $def:tt )*]
+ body [$($( #[$imeta:meta] )*
+ => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
+ queue [$( #[$qmeta:meta] )*
+ => $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*]
+ ) => {
+ quick_error!(ENUM_DEFINITION [ $($def)* ]
+ body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
+ $( #[$qmeta] )* => $qitem (($( $qtyp ),*)) {} ]
+ queue [ $($queue)* ]
+ );
+ };
+ // Struct variant
+ (ENUM_DEFINITION [$( $def:tt )*]
+ body [$($( #[$imeta:meta] )*
+ => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
+ queue [$( #[$qmeta:meta] )*
+ => $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*]
+ ) => {
+ quick_error!(ENUM_DEFINITION [ $($def)* ]
+ body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
+ $( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ]
+ queue [ $($queue)* ]
+ );
+ };
+ (IMPLEMENTATIONS
+ $name:ident {$(
+ $item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*}
+ )*}
+ ) => {
+ #[allow(unused)]
+ impl ::std::fmt::Display for $name {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
+ -> ::std::fmt::Result
+ {
+ match *self {
+ $(
+ $(#[$imeta])*
+ quick_error!(ITEM_PATTERN
+ $name $item: $imode [$( ref $var ),*]
+ ) => {
+ let display_fn = quick_error!(FIND_DISPLAY_IMPL
+ $name $item: $imode
+ {$( $funcs )*});
+
+ display_fn(self, fmt)
+ }
+ )*
+ }
+ }
+ }
+ /*#[allow(unused)]
+ impl ::std::error::Error for $name {
+ fn description(&self) -> &str {
+ match *self {
+ $(
+ quick_error!(ITEM_PATTERN
+ $name $item: $imode [$( ref $var ),*]
+ ) => {
+ quick_error!(FIND_DESCRIPTION_IMPL
+ $item: $imode self fmt [$( $var ),*]
+ {$( $funcs )*})
+ }
+ )*
+ }
+ }
+ fn cause(&self) -> Option<&::std::error::Error> {
+ match *self {
+ $(
+ quick_error!(ITEM_PATTERN
+ $name $item: $imode [$( ref $var ),*]
+ ) => {
+ quick_error!(FIND_CAUSE_IMPL
+ $item: $imode [$( $var ),*]
+ {$( $funcs )*})
+ }
+ )*
+ }
+ }
+ }*/
+ #[allow(unused)]
+ impl $name {
+ /// A string describing the error kind.
+ pub fn description(&self) -> &str {
+ match *self {
+ $(
+ $(#[$imeta])*
+ quick_error!(ITEM_PATTERN
+ $name $item: $imode [$( ref $var ),*]
+ ) => {
+ quick_error!(FIND_DESCRIPTION_IMPL
+ $item: $imode self fmt [$( $var ),*]
+ {$( $funcs )*})
+ }
+ )*
+ }
+ }
+ }
+ $(
+ quick_error!(FIND_FROM_IMPL
+ $name $item: $imode [$( $var:$typ ),*]
+ {$( $funcs )*});
+ )*
+ };
+ (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
+ { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*}
+ ) => {
+ |quick_error!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| {
+ write!(f, $( $exprs )*)
+ }
+ };
+ (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
+ { display($pattern:expr) $( $tail:tt )*}
+ ) => {
+ |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern) }
+ };
+ (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
+ { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*}
+ ) => {
+ |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern, $( $exprs )*) }
+ };
+ (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
+ { $t:tt $( $tail:tt )*}
+ ) => {
+ quick_error!(FIND_DISPLAY_IMPL
+ $name $item: $imode
+ {$( $tail )*})
+ };
+ (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
+ { }
+ ) => {
+ |self_: &$name, f: &mut ::std::fmt::Formatter| {
+ write!(f, "{}", self_.description())
+ }
+ };
+ (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
+ [$( $var:ident ),*]
+ { description($expr:expr) $( $tail:tt )*}
+ ) => {
+ $expr
+ };
+ (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
+ [$( $var:ident ),*]
+ { $t:tt $( $tail:tt )*}
+ ) => {
+ quick_error!(FIND_DESCRIPTION_IMPL
+ $item: $imode $me $fmt [$( $var ),*]
+ {$( $tail )*})
+ };
+ (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
+ [$( $var:ident ),*]
+ { }
+ ) => {
+ stringify!($item)
+ };
+ (FIND_CAUSE_IMPL $item:ident: $imode:tt
+ [$( $var:ident ),*]
+ { cause($expr:expr) $( $tail:tt )*}
+ ) => {
+ Some($expr)
+ };
+ (FIND_CAUSE_IMPL $item:ident: $imode:tt
+ [$( $var:ident ),*]
+ { $t:tt $( $tail:tt )*}
+ ) => {
+ quick_error!(FIND_CAUSE_IMPL
+ $item: $imode [$( $var ),*]
+ { $($tail)* })
+ };
+ (FIND_CAUSE_IMPL $item:ident: $imode:tt
+ [$( $var:ident ),*]
+ { }
+ ) => {
+ None
+ };
+ (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
+ [$( $var:ident: $typ:ty ),*]
+ { from() $( $tail:tt )*}
+ ) => {
+ $(
+ impl From<$typ> for $name {
+ fn from($var: $typ) -> $name {
+ $name::$item($var)
+ }
+ }
+ )*
+ quick_error!(FIND_FROM_IMPL
+ $name $item: $imode [$( $var:$typ ),*]
+ {$( $tail )*});
+ };
+ (FIND_FROM_IMPL $name:ident $item:ident: UNIT
+ [ ]
+ { from($ftyp:ty) $( $tail:tt )*}
+ ) => {
+ impl From<$ftyp> for $name {
+ fn from(_discarded_error: $ftyp) -> $name {
+ $name::$item
+ }
+ }
+ quick_error!(FIND_FROM_IMPL
+ $name $item: UNIT [ ]
+ {$( $tail )*});
+ };
+ (FIND_FROM_IMPL $name:ident $item:ident: TUPLE
+ [$( $var:ident: $typ:ty ),*]
+ { from($fvar:ident: $ftyp:ty) -> ($( $texpr:expr ),*) $( $tail:tt )*}
+ ) => {
+ impl From<$ftyp> for $name {
+ fn from($fvar: $ftyp) -> $name {
+ $name::$item($( $texpr ),*)
+ }
+ }
+ quick_error!(FIND_FROM_IMPL
+ $name $item: TUPLE [$( $var:$typ ),*]
+ { $($tail)* });
+ };
+ (FIND_FROM_IMPL $name:ident $item:ident: STRUCT
+ [$( $var:ident: $typ:ty ),*]
+ { from($fvar:ident: $ftyp:ty) -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )*}
+ ) => {
+ impl From<$ftyp> for $name {
+ fn from($fvar: $ftyp) -> $name {
+ $name::$item {
+ $( $tvar: $texpr ),*
+ }
+ }
+ }
+ quick_error!(FIND_FROM_IMPL
+ $name $item: STRUCT [$( $var:$typ ),*]
+ { $($tail)* });
+ };
+ (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
+ [$( $var:ident: $typ:ty ),*]
+ { $t:tt $( $tail:tt )*}
+ ) => {
+ quick_error!(FIND_FROM_IMPL
+ $name $item: $imode [$( $var:$typ ),*]
+ {$( $tail )*}
+ );
+ };
+ (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
+ [$( $var:ident: $typ:ty ),*]
+ { }
+ ) => {
+ };
+ (ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT
+ ) => { };
+ (ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE
+ [$( $typ:ty ),*]
+ ) => {
+ ($( $typ ),*)
+ };
+ (ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT
+ [$( $var:ident: $typ:ty ),*]
+ ) => {
+ {$( $var:$typ ),*}
+ };
+ (ITEM_PATTERN $name:ident $item:ident: UNIT []
+ ) => {
+ $name::$item
+ };
+ (ITEM_PATTERN $name:ident $item:ident: TUPLE
+ [$( ref $var:ident ),*]
+ ) => {
+ $name::$item ($( ref $var ),*)
+ };
+ (ITEM_PATTERN $name:ident $item:ident: STRUCT
+ [$( ref $var:ident ),*]
+ ) => {
+ $name::$item {$( ref $var ),*}
+ };
+ // This one should match all allowed sequences in "funcs" but not match
+ // anything else.
+ // This is to contrast FIND_* clauses which just find stuff they need and
+ // skip everything else completely
+ (ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*)
+ => { quick_error!(ERROR_CHECK $imode $($tail)*); };
+ (ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*)
+ => { quick_error!(ERROR_CHECK $imode $($tail)*); };
+ (ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*)
+ => { quick_error!(ERROR_CHECK $imode $($tail)*); };
+ (ERROR_CHECK $imode:tt description($expr:expr) $( $tail:tt )*)
+ => { quick_error!(ERROR_CHECK $imode $($tail)*); };
+ (ERROR_CHECK $imode:tt cause($expr:expr) $($tail:tt)*)
+ => { quick_error!(ERROR_CHECK $imode $($tail)*); };
+ (ERROR_CHECK $imode:tt from() $($tail:tt)*)
+ => { quick_error!(ERROR_CHECK $imode $($tail)*); };
+ (ERROR_CHECK $imode:tt from($ftyp:ty) $($tail:tt)*)
+ => { quick_error!(ERROR_CHECK $imode $($tail)*); };
+ (ERROR_CHECK TUPLE from($fvar:ident: $ftyp:ty) -> ($( $e:expr ),*) $( $tail:tt )*)
+ => { quick_error!(ERROR_CHECK TUPLE $($tail)*); };
+ (ERROR_CHECK STRUCT from($fvar:ident: $ftyp:ty) -> {$( $v:ident: $e:expr ),*} $( $tail:tt )*)
+ => { quick_error!(ERROR_CHECK STRUCT $($tail)*); };
+ (ERROR_CHECK $imode:tt ) => {};
+ // Utility functions
+ (IDENT $ident:ident) => { $ident }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/src/quick_main.rs
@@ -0,0 +1,73 @@
+/// Convenient wrapper to be able to use `try!` and such in the main. You can
+/// use it with a separated function:
+///
+/// ```
+/// # #[macro_use] extern crate error_chain;
+/// # error_chain! {}
+/// # fn main() {
+/// quick_main!(run);
+/// # }
+///
+/// fn run() -> Result<()> {
+/// Err("error".into())
+/// }
+/// ```
+///
+/// or with a closure:
+///
+/// ```
+/// # #[macro_use] extern crate error_chain;
+/// # error_chain! {}
+/// # fn main() {
+/// quick_main!(|| -> Result<()> {
+/// Err("error".into())
+/// });
+/// # }
+/// ```
+///
+/// You can also set the exit value of the process by returning a type that implements [`ExitCode`](trait.ExitCode.html):
+///
+/// ```
+/// # #[macro_use] extern crate error_chain;
+/// # error_chain! {}
+/// # fn main() {
+/// quick_main!(run);
+/// # }
+///
+/// fn run() -> Result<i32> {
+/// Err("error".into())
+/// }
+/// ```
+#[macro_export]
+macro_rules! quick_main {
+ ($main:expr) => {
+ fn main() {
+ use ::std::io::Write;
+
+ ::std::process::exit(match $main() {
+ Ok(ret) => $crate::ExitCode::code(ret),
+ Err(ref e) => {
+ write!(&mut ::std::io::stderr(), "{}", $crate::ChainedError::display(e))
+ .expect("Error writing to stderr");
+
+ 1
+ }
+ });
+ }
+ };
+}
+
+/// Represents a value that can be used as the exit status of the process.
+/// See [`quick_main!`](macro.quick_main.html).
+pub trait ExitCode {
+ /// Returns the value to use as the exit status.
+ fn code(self) -> i32;
+}
+
+impl ExitCode for i32 {
+ fn code(self) -> i32 { self }
+}
+
+impl ExitCode for () {
+ fn code(self) -> i32 { 0 }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/tests/quick_main.rs
@@ -0,0 +1,30 @@
+#![allow(dead_code)]
+#[macro_use]
+extern crate error_chain;
+
+error_chain!();
+
+mod unit {
+ use super::*;
+ quick_main!(run);
+
+ fn run() -> Result<()> {
+ Ok(())
+ }
+}
+
+mod i32 {
+ use super::*;
+ quick_main!(run);
+
+ fn run() -> Result<i32> {
+ Ok(1)
+ }
+}
+
+mod closure {
+ use super::*;
+ quick_main!(|| -> Result<()> {
+ Ok(())
+ });
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/error-chain/tests/tests.rs
@@ -0,0 +1,595 @@
+#![allow(dead_code)]
+//#![feature(trace_macros)]
+//
+//trace_macros!(true);
+
+#[macro_use]
+extern crate error_chain;
+
+#[test]
+fn smoke_test_1() {
+ error_chain! {
+ types {
+ Error, ErrorKind, ResultExt, Result;
+ }
+
+ links { }
+
+ foreign_links { }
+
+ errors { }
+ };
+}
+
+#[test]
+fn smoke_test_2() {
+ error_chain! {
+ types { }
+
+ links { }
+
+ foreign_links { }
+
+ errors { }
+ };
+}
+
+#[test]
+fn smoke_test_3() {
+ error_chain! {
+ links { }
+
+ foreign_links { }
+
+ errors { }
+ };
+}
+
+#[test]
+fn smoke_test_4() {
+ error_chain! {
+ links { }
+
+ foreign_links { }
+
+ errors {
+ HttpStatus(e: u32) {
+ description("http request returned an unsuccessful status code")
+ display("http request returned an unsuccessful status code: {}", e)
+ }
+ }
+ };
+}
+
+#[test]
+fn smoke_test_5() {
+ error_chain! {
+ types { }
+
+ links { }
+
+ foreign_links { }
+
+ errors {
+ HttpStatus(e: u32) {
+ description("http request returned an unsuccessful status code")
+ display("http request returned an unsuccessful status code: {}", e)
+ }
+ }
+ };
+}
+
+#[test]
+fn smoke_test_6() {
+ error_chain! {
+ errors {
+ HttpStatus(e: u32) {
+ description("http request returned an unsuccessful status code")
+ display("http request returned an unsuccessful status code: {}", e)
+ }
+ }
+ };
+}
+
+#[test]
+fn smoke_test_7() {
+ error_chain! {
+ types { }
+
+ foreign_links { }
+
+ errors {
+ HttpStatus(e: u32) {
+ description("http request returned an unsuccessful status code")
+ display("http request returned an unsuccessful status code: {}", e)
+ }
+ }
+ };
+}
+
+#[test]
+fn smoke_test_8() {
+ error_chain! {
+ types { }
+
+ links { }
+ links { }
+
+ foreign_links { }
+ foreign_links { }
+
+ errors {
+ FileNotFound
+ AccessDenied
+ }
+ };
+}
+
+#[test]
+fn order_test_1() {
+ error_chain! { types { } links { } foreign_links { } errors { } };
+}
+
+#[test]
+fn order_test_2() {
+ error_chain! { links { } types { } foreign_links { } errors { } };
+}
+
+#[test]
+fn order_test_3() {
+ error_chain! { foreign_links { } links { } errors { } types { } };
+}
+
+#[test]
+fn order_test_4() {
+ error_chain! { errors { } types { } foreign_links { } };
+}
+
+#[test]
+fn order_test_5() {
+ error_chain! { foreign_links { } types { } };
+}
+
+#[test]
+fn order_test_6() {
+ error_chain! {
+ links { }
+
+ errors {
+ HttpStatus(e: u32) {
+ description("http request returned an unsuccessful status code")
+ display("http request returned an unsuccessful status code: {}", e)
+ }
+ }
+
+
+ foreign_links { }
+ };
+}
+
+#[test]
+fn order_test_7() {
+ error_chain! {
+ links { }
+
+ foreign_links { }
+
+ types {
+ Error, ErrorKind, ResultExt, Result;
+ }
+ };
+}
+
+
+#[test]
+fn order_test_8() {
+ error_chain! {
+ links { }
+
+ foreign_links { }
+ foreign_links { }
+
+ types {
+ Error, ErrorKind, ResultExt, Result;
+ }
+ };
+}
+
+#[test]
+fn empty() {
+ error_chain! { };
+}
+
+#[test]
+#[cfg(feature = "backtrace")]
+fn has_backtrace_depending_on_env() {
+ use std::env;
+
+ error_chain! {
+ types {}
+ links {}
+ foreign_links {}
+ errors {
+ MyError
+ }
+ }
+
+ let original_value = env::var_os("RUST_BACKTRACE");
+
+ // missing RUST_BACKTRACE and RUST_BACKTRACE=0
+ env::remove_var("RUST_BACKTRACE");
+ let err = Error::from(ErrorKind::MyError);
+ assert!(err.backtrace().is_none());
+ env::set_var("RUST_BACKTRACE", "0");
+ let err = Error::from(ErrorKind::MyError);
+ assert!(err.backtrace().is_none());
+
+ // RUST_BACKTRACE set to anything but 0
+ env::set_var("RUST_BACKTRACE", "yes");
+ let err = Error::from(ErrorKind::MyError);
+ assert!(err.backtrace().is_some());
+
+ if let Some(var) = original_value {
+ env::set_var("RUST_BACKTRACE", var);
+ }
+}
+
+#[test]
+fn chain_err() {
+ use std::fmt;
+
+ error_chain! {
+ foreign_links {
+ Fmt(fmt::Error);
+ }
+ errors {
+ Test
+ }
+ }
+
+ let _: Result<()> = Err(fmt::Error).chain_err(|| "");
+ let _: Result<()> = Err(Error::from_kind(ErrorKind::Test)).chain_err(|| "");
+}
+
+#[test]
+fn links() {
+ mod test {
+ error_chain! {}
+ }
+
+ error_chain! {
+ links {
+ Test(test::Error, test::ErrorKind);
+ }
+ }
+}
+
+#[cfg(test)]
+mod foreign_link_test {
+
+ use std::fmt;
+
+ // Note: foreign errors must be `pub` because they appear in the
+ // signature of the public foreign_link_error_path
+ #[derive(Debug)]
+ pub struct ForeignError {
+ cause: ForeignErrorCause
+ }
+
+ impl ::std::error::Error for ForeignError {
+ fn description(&self) -> &'static str {
+ "Foreign error description"
+ }
+
+ fn cause(&self) -> Option<&::std::error::Error> { Some(&self.cause) }
+ }
+
+ impl fmt::Display for ForeignError {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "Foreign error display")
+ }
+ }
+
+ #[derive(Debug)]
+ pub struct ForeignErrorCause {}
+
+ impl ::std::error::Error for ForeignErrorCause {
+ fn description(&self) -> &'static str {
+ "Foreign error cause description"
+ }
+
+ fn cause(&self) -> Option<&::std::error::Error> { None }
+ }
+
+ impl fmt::Display for ForeignErrorCause {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "Foreign error cause display")
+ }
+ }
+
+ error_chain! {
+ types{
+ Error, ErrorKind, ResultExt, Result;
+ }
+ links {}
+ foreign_links {
+ Foreign(ForeignError);
+ Io(::std::io::Error);
+ }
+ errors {}
+ }
+
+ #[test]
+ fn display_underlying_error() {
+ let chained_error = try_foreign_error().err().unwrap();
+ assert_eq!(
+ format!("{}", ForeignError{ cause: ForeignErrorCause{} }),
+ format!("{}", chained_error)
+ );
+ }
+
+ #[test]
+ fn finds_cause() {
+ let chained_error = try_foreign_error().err().unwrap();
+ assert_eq!(
+ format!("{}", ForeignErrorCause{}),
+ format!("{}", ::std::error::Error::cause(&chained_error).unwrap())
+ );
+ }
+
+ #[test]
+ fn iterates() {
+ let chained_error = try_foreign_error().err().unwrap();
+ let mut error_iter = chained_error.iter();
+ assert_eq!(
+ format!("{}", ForeignError{ cause: ForeignErrorCause{} }),
+ format!("{}", error_iter.next().unwrap())
+ );
+ assert_eq!(
+ format!("{}", ForeignErrorCause{}),
+ format!("{}", error_iter.next().unwrap())
+ );
+ assert_eq!(
+ format!("{:?}", None as Option<&::std::error::Error>),
+ format!("{:?}", error_iter.next())
+ );
+ }
+
+ fn try_foreign_error() -> Result<()> {
+ try!(Err(ForeignError{
+ cause: ForeignErrorCause{}
+ }));
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod attributes_test {
+ #[allow(unused_imports)]
+ use std::io;
+
+ #[cfg(not(test))]
+ mod inner {
+ error_chain! {
+
+ }
+ }
+
+ error_chain! {
+ types {
+ Error, ErrorKind, ResultExt, Result;
+ }
+
+ links {
+ Inner(inner::Error, inner::ErrorKind) #[cfg(not(test))];
+ }
+
+ foreign_links {
+ Io(io::Error) #[cfg(not(test))];
+ }
+
+ errors {
+ #[cfg(not(test))]
+ AnError {
+
+ }
+ }
+ }
+}
+
+#[test]
+fn with_result() {
+ error_chain! {
+ types {
+ Error, ErrorKind, ResultExt, Result;
+ }
+ }
+ let _: Result<()> = Ok(());
+}
+
+#[test]
+fn without_result() {
+ error_chain! {
+ types {
+ Error, ErrorKind, ResultExt;
+ }
+ }
+ let _: Result<(), ()> = Ok(());
+}
+
+#[test]
+fn documentation() {
+ mod inner {
+ error_chain! {}
+ }
+
+ error_chain! {
+ links {
+ Inner(inner::Error, inner::ErrorKind) #[doc = "Doc"];
+ }
+ foreign_links {
+ Io(::std::io::Error) #[doc = "Doc"];
+ }
+ errors {
+ /// Doc
+ Variant
+ }
+ }
+}
+
+#[cfg(test)]
+mod multiple_error_same_mod {
+ error_chain! {
+ types {
+ MyError, MyErrorKind, MyResultExt, MyResult;
+ }
+ }
+ error_chain! {}
+}
+
+#[doc(test)]
+#[deny(dead_code)]
+mod allow_dead_code {
+ error_chain! {}
+}
+
+// Make sure links actually work!
+#[test]
+fn rustup_regression() {
+ error_chain! {
+ links {
+ Download(error_chain::mock::Error, error_chain::mock::ErrorKind);
+ }
+
+ foreign_links { }
+
+ errors {
+ LocatingWorkingDir {
+ description("could not locate working directory")
+ }
+ }
+ }
+}
+
+#[test]
+fn error_patterns() {
+ error_chain! {
+ links { }
+
+ foreign_links { }
+
+ errors { }
+ }
+
+ // Tuples look nice when matching errors
+ match Error::from("Test") {
+ Error(ErrorKind::Msg(_), _) => {
+ }
+ }
+}
+
+#[test]
+fn error_first() {
+ error_chain! {
+ errors {
+ LocatingWorkingDir {
+ description("could not locate working directory")
+ }
+ }
+
+ links {
+ Download(error_chain::mock::Error, error_chain::mock::ErrorKind);
+ }
+
+ foreign_links { }
+ }
+}
+
+#[test]
+fn bail() {
+ error_chain! {
+ errors { Foo }
+ }
+
+ fn foo() -> Result<()> {
+ bail!(ErrorKind::Foo)
+ }
+
+ fn bar() -> Result<()> {
+ bail!("bar")
+ }
+
+ fn baz() -> Result<()> {
+ bail!("{}", "baz")
+ }
+}
+
+#[test]
+fn ensure() {
+ error_chain! {
+ errors { Bar }
+ }
+
+ fn foo(x: u8) -> Result<()> {
+ ensure!(x == 42, ErrorKind::Bar);
+ Ok(())
+ }
+
+ assert!(foo(42).is_ok());
+ assert!(foo(0).is_err());
+}
+
+/// Since the `types` declaration is a list of symbols, check if we
+/// don't change their meaning or order.
+#[test]
+fn types_declarations() {
+ error_chain! {
+ types {
+ MyError, MyErrorKind, MyResultExt, MyResult;
+ }
+ }
+
+ MyError::from_kind(MyErrorKind::Msg("".into()));
+
+ let err: Result<(), ::std::io::Error> = Ok(());
+ MyResultExt::chain_err(err, || "").unwrap();
+
+ let _: MyResult<()> = Ok(());
+}
+
+#[test]
+/// Calling chain_err over a `Result` containing an error to get a chained error
+//// and constructing a MyError directly, passing it an error should be equivalent.
+fn rewrapping() {
+
+ use std::env::VarError::{self, NotPresent, NotUnicode};
+
+ error_chain! {
+ foreign_links {
+ VarErr(VarError);
+ }
+
+ types {
+ MyError, MyErrorKind, MyResultExt, MyResult;
+ }
+ }
+
+ let result_a_from_func: Result<String, _> = Err(VarError::NotPresent);
+ let result_b_from_func: Result<String, _> = Err(VarError::NotPresent);
+
+ let our_error_a = result_a_from_func.map_err(|e| match e {
+ NotPresent => MyError::with_chain(e, "env var wasn't provided"),
+ NotUnicode(_) => MyError::with_chain(e, "env var was borkæ–‡å—化ã"),
+ });
+
+ let our_error_b = result_b_from_func.or_else(|e| match e {
+ NotPresent => Err(e).chain_err(|| "env var wasn't provided"),
+ NotUnicode(_) => Err(e).chain_err(|| "env var was borkæ–‡å—化ã"),
+ });
+
+ assert_eq!(
+ format!("{}", our_error_a.unwrap_err()),
+ format!("{}", our_error_b.unwrap_err())
+ );
+
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/.appveyor.yml
@@ -0,0 +1,18 @@
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+ - TARGET: i686-pc-windows-msvc
+ - TARGET: x86_64-pc-windows-gnu
+ - TARGET: i686-pc-windows-gnu
+
+install:
+ - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" -FileName "rust-nightly.exe"
+ - ps: .\rust-nightly.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null
+ - ps: $env:PATH="$env:PATH;C:\rust\bin"
+
+build_script:
+ - cargo build -v
+
+test_script:
+ - SET RUST_BACKTRACE=1
+ - cargo test -v
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".appveyor.yml":"15c5548159ad6ebcc02960bb6a3269e729e772df2733b7d4c7cc1583c413ae45",".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"5733d01f7cd27cbdd17a46399103e83eca528727e6cad7f355f6748e772ef916","Cargo.toml":"c257476252f17472f1a78c9fa92b137dc435873797ec1a137aa73043b3ad06a7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"7667acd3dfd050dadccf8b7815435b9108c24c5704944085281beed6a181e220","src/lib.rs":"106e402d1c5ae68558f4e8a3971b646c12f19762363d2cf15c13a1c2aeb1d1e7","src/unix.rs":"67f0244c118cff918f01b6c164dfe604039ce9160a099ba6e4ff86dcf8ec0097","src/windows.rs":"5767d923280998e341504f8d2a015b8b0c3f8b2b1188610aa4c1b6a343da5682"},"package":"9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/.travis.yml
@@ -0,0 +1,21 @@
+language: rust
+
+rust:
+- 1.8.0
+- stable
+- nightly
+
+os:
+ - linux
+ - osx
+
+env:
+ matrix:
+ - ARCH=x86_64
+ - ARCH=i686
+
+script:
+ - cargo build --verbose
+ - if [[ $TRAVIS_RUST_VERSION = nightly* ]]; then
+ env RUST_BACKTRACE=1 cargo test -v;
+ fi
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/Cargo.toml
@@ -0,0 +1,30 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "fs2"
+version = "0.4.2"
+authors = ["Dan Burkert <dan@danburkert.com>"]
+description = "Cross-platform file locks and file duplication."
+documentation = "https://docs.rs/fs2"
+keywords = ["file", "file-system", "lock", "duplicate", "flock"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/danburkert/fs2-rs"
+[dev-dependencies.tempdir]
+version = "0.3"
+[target."cfg(windows)".dependencies.winapi]
+version = "0.2"
+
+[target."cfg(windows)".dependencies.kernel32-sys]
+version = "0.2"
+[target."cfg(unix)".dependencies.libc]
+version = "0.2.2"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2015 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/README.md
@@ -0,0 +1,50 @@
+# fs2
+
+Extended utilities for working with files and filesystems in Rust. `fs2`
+requires Rust stable 1.8 or greater.
+
+[Documentation](https://docs.rs/fs2)
+
+[![Linux Status](https://travis-ci.org/danburkert/fs2-rs.svg?branch=master)](https://travis-ci.org/danburkert/fs2-rs)
+[![Windows Status](https://ci.appveyor.com/api/projects/status/iuvjv1aaaml0rntt/branch/master?svg=true)](https://ci.appveyor.com/project/danburkert/fs2-rs)
+
+## Features
+
+- [x] file descriptor duplication.
+- [x] file locks.
+- [x] file (pre)allocation.
+- [x] file allocation information.
+- [x] filesystem space usage information.
+
+## Platforms
+
+`fs2` should work on any platform supported by
+[`libc`](https://github.com/rust-lang-nursery/libc#platforms-and-documentation).
+
+`fs2` is continuously tested on:
+ * `x86_64-unknown-linux-gnu` (Linux)
+ * `i686-unknown-linux-gnu`
+ * `x86_64-apple-darwin` (OSX)
+ * `i686-apple-darwin`
+ * `x86_64-pc-windows-msvc` (Windows)
+ * `i686-pc-windows-msvc`
+ * `x86_64-pc-windows-gnu`
+ * `i686-pc-windows-gnu`
+
+## Benchmarks
+
+Simple benchmarks are provided for the methods provided. Many of these
+benchmarks use files in a temporary directory. On many modern Linux distros the
+default temporary directory, `/tmp`, is mounted on a tempfs filesystem, which
+will have different performance characteristics than a disk-backed filesystem.
+The temporary directory is configurable at runtime through the environment (see
+[`env::temp_dir`](https://doc.rust-lang.org/stable/std/env/fn.temp_dir.html)).
+
+## License
+
+`fs2` is primarily distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details.
+
+Copyright (c) 2015 Dan Burkert.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/src/lib.rs
@@ -0,0 +1,452 @@
+#![cfg_attr(test, feature(test))]
+#![deny(warnings)]
+
+#[cfg(unix)]
+mod unix;
+#[cfg(unix)]
+use unix as sys;
+
+#[cfg(windows)]
+mod windows;
+#[cfg(windows)]
+use windows as sys;
+
+use std::fs::File;
+use std::io::{Error, Result};
+use std::path::Path;
+
+/// Extension trait for `std::fs::File` which provides allocation, duplication and locking methods.
+///
+/// ## Notes on File Locks
+///
+/// This library provides whole-file locks in both shared (read) and exclusive
+/// (read-write) varieties.
+///
+/// File locks are a cross-platform hazard since the file lock APIs exposed by
+/// operating system kernels vary in subtle and not-so-subtle ways.
+///
+/// The API exposed by this library can be safely used across platforms as long
+/// as the following rules are followed:
+///
+/// * Multiple locks should not be created on an individual `File` instance
+/// concurrently.
+/// * Duplicated files should not be locked without great care.
+/// * Files to be locked should be opened with at least read or write
+/// permissions.
+/// * File locks may only be relied upon to be advisory.
+///
+/// See the tests in `lib.rs` for cross-platform lock behavior that may be
+/// relied upon; see the tests in `unix.rs` and `windows.rs` for examples of
+/// platform-specific behavior. File locks are implemented with
+/// [`flock(2)`](http://man7.org/linux/man-pages/man2/flock.2.html) on Unix and
+/// [`LockFile`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365202(v=vs.85).aspx)
+/// on Windows.
+pub trait FileExt {
+
+ /// Returns a duplicate instance of the file.
+ ///
+ /// The returned file will share the same file position as the original
+ /// file.
+ ///
+ /// If using rustc version 1.9 or later, prefer using `File::try_clone` to this.
+ ///
+ /// # Notes
+ ///
+ /// This is implemented with
+ /// [`dup(2)`](http://man7.org/linux/man-pages/man2/dup.2.html) on Unix and
+ /// [`DuplicateHandle`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724251(v=vs.85).aspx)
+ /// on Windows.
+ fn duplicate(&self) -> Result<File>;
+
+ /// Returns the amount of physical space allocated for a file.
+ fn allocated_size(&self) -> Result<u64>;
+
+ /// Ensures that at least `len` bytes of disk space are allocated for the
+ /// file, and the file size is at least `len` bytes. After a successful call
+ /// to `allocate`, subsequent writes to the file within the specified length
+ /// are guaranteed not to fail because of lack of disk space.
+ fn allocate(&self, len: u64) -> Result<()>;
+
+ /// Locks the file for shared usage, blocking if the file is currently
+ /// locked exclusively.
+ fn lock_shared(&self) -> Result<()>;
+
+ /// Locks the file for exclusive usage, blocking if the file is currently
+ /// locked.
+ fn lock_exclusive(&self) -> Result<()>;
+
+ /// Locks the file for shared usage, or returns a an error if the file is
+ /// currently locked (see `lock_contended_error`).
+ fn try_lock_shared(&self) -> Result<()>;
+
+ /// Locks the file for shared usage, or returns a an error if the file is
+ /// currently locked (see `lock_contended_error`).
+ fn try_lock_exclusive(&self) -> Result<()>;
+
+ /// Unlocks the file.
+ fn unlock(&self) -> Result<()>;
+}
+
+impl FileExt for File {
+ fn duplicate(&self) -> Result<File> {
+ sys::duplicate(self)
+ }
+ fn allocated_size(&self) -> Result<u64> {
+ sys::allocated_size(self)
+ }
+ fn allocate(&self, len: u64) -> Result<()> {
+ sys::allocate(self, len)
+ }
+ fn lock_shared(&self) -> Result<()> {
+ sys::lock_shared(self)
+ }
+ fn lock_exclusive(&self) -> Result<()> {
+ sys::lock_exclusive(self)
+ }
+ fn try_lock_shared(&self) -> Result<()> {
+ sys::try_lock_shared(self)
+ }
+ fn try_lock_exclusive(&self) -> Result<()> {
+ sys::try_lock_exclusive(self)
+ }
+ fn unlock(&self) -> Result<()> {
+ sys::unlock(self)
+ }
+}
+
+/// Returns the error that a call to a try lock method on a contended file will
+/// return.
+pub fn lock_contended_error() -> Error {
+ sys::lock_error()
+}
+
+/// `FsStats` contains some common stats about a file system.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct FsStats {
+ free_space: u64,
+ available_space: u64,
+ total_space: u64,
+ allocation_granularity: u64,
+}
+
+impl FsStats {
+ /// Returns the number of free bytes in the file system containing the provided
+ /// path.
+ pub fn free_space(&self) -> u64 {
+ self.free_space
+ }
+
+ /// Returns the available space in bytes to non-priveleged users in the file
+ /// system containing the provided path.
+ pub fn available_space(&self) -> u64 {
+ self.available_space
+ }
+
+ /// Returns the total space in bytes in the file system containing the provided
+ /// path.
+ pub fn total_space(&self) -> u64 {
+ self.total_space
+ }
+
+ /// Returns the filesystem's disk space allocation granularity in bytes.
+ /// The provided path may be for any file in the filesystem.
+ ///
+ /// On Posix, this is equivalent to the filesystem's block size.
+ /// On Windows, this is equivalent to the filesystem's cluster size.
+ pub fn allocation_granularity(&self) -> u64 {
+ self.allocation_granularity
+ }
+}
+
+/// Get the stats of the file system containing the provided path.
+pub fn statvfs<P>(path: P) -> Result<FsStats> where P: AsRef<Path> {
+ sys::statvfs(path.as_ref())
+}
+
+/// Returns the number of free bytes in the file system containing the provided
+/// path.
+pub fn free_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
+ statvfs(path).map(|stat| stat.free_space)
+}
+
+/// Returns the available space in bytes to non-priveleged users in the file
+/// system containing the provided path.
+pub fn available_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
+ statvfs(path).map(|stat| stat.available_space)
+}
+
+/// Returns the total space in bytes in the file system containing the provided
+/// path.
+pub fn total_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
+ statvfs(path).map(|stat| stat.total_space)
+}
+
+/// Returns the filesystem's disk space allocation granularity in bytes.
+/// The provided path may be for any file in the filesystem.
+///
+/// On Posix, this is equivalent to the filesystem's block size.
+/// On Windows, this is equivalent to the filesystem's cluster size.
+pub fn allocation_granularity<P>(path: P) -> Result<u64> where P: AsRef<Path> {
+ statvfs(path).map(|stat| stat.allocation_granularity)
+}
+
+#[cfg(test)]
+mod test {
+
+ extern crate tempdir;
+ extern crate test;
+
+ use std::fs;
+ use super::*;
+ use std::io::{Read, Seek, SeekFrom, Write};
+
+ /// Tests file duplication.
+ #[test]
+ fn duplicate() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let mut file1 =
+ fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+ let mut file2 = file1.duplicate().unwrap();
+
+ // Write into the first file and then drop it.
+ file1.write_all(b"foo").unwrap();
+ drop(file1);
+
+ let mut buf = vec![];
+
+ // Read from the second file; since the position is shared it will already be at EOF.
+ file2.read_to_end(&mut buf).unwrap();
+ assert_eq!(0, buf.len());
+
+ // Rewind and read.
+ file2.seek(SeekFrom::Start(0)).unwrap();
+ file2.read_to_end(&mut buf).unwrap();
+ assert_eq!(&buf, &b"foo");
+ }
+
+ /// Tests shared file lock operations.
+ #[test]
+ fn lock_shared() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+ let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+ let file3 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+
+ // Concurrent shared access is OK, but not shared and exclusive.
+ file1.lock_shared().unwrap();
+ file2.lock_shared().unwrap();
+ assert_eq!(file3.try_lock_exclusive().unwrap_err().kind(),
+ lock_contended_error().kind());
+ file1.unlock().unwrap();
+ assert_eq!(file3.try_lock_exclusive().unwrap_err().kind(),
+ lock_contended_error().kind());
+
+ // Once all shared file locks are dropped, an exclusive lock may be created;
+ file2.unlock().unwrap();
+ file3.lock_exclusive().unwrap();
+ }
+
+ /// Tests exclusive file lock operations.
+ #[test]
+ fn lock_exclusive() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+ let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+
+ // No other access is possible once an exclusive lock is created.
+ file1.lock_exclusive().unwrap();
+ assert_eq!(file2.try_lock_exclusive().unwrap_err().kind(),
+ lock_contended_error().kind());
+ assert_eq!(file2.try_lock_shared().unwrap_err().kind(),
+ lock_contended_error().kind());
+
+ // Once the exclusive lock is dropped, the second file is able to create a lock.
+ file1.unlock().unwrap();
+ file2.lock_exclusive().unwrap();
+ }
+
+ /// Tests that a lock is released after the file that owns it is dropped.
+ #[test]
+ fn lock_cleanup() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+ let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+
+ file1.lock_exclusive().unwrap();
+ assert_eq!(file2.try_lock_shared().unwrap_err().kind(),
+ lock_contended_error().kind());
+
+ // Drop file1; the lock should be released.
+ drop(file1);
+ file2.lock_shared().unwrap();
+ }
+
+ /// Tests file allocation.
+ #[test]
+ fn allocate() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
+ let blksize = allocation_granularity(&path).unwrap();
+
+ // New files are created with no allocated size.
+ assert_eq!(0, file.allocated_size().unwrap());
+ assert_eq!(0, file.metadata().unwrap().len());
+
+ // Allocate space for the file, checking that the allocated size steps
+ // up by block size, and the file length matches the allocated size.
+
+ file.allocate(2 * blksize - 1).unwrap();
+ assert_eq!(2 * blksize, file.allocated_size().unwrap());
+ assert_eq!(2 * blksize - 1, file.metadata().unwrap().len());
+
+ // Truncate the file, checking that the allocated size steps down by
+ // block size.
+
+ file.set_len(blksize + 1).unwrap();
+ assert_eq!(2 * blksize, file.allocated_size().unwrap());
+ assert_eq!(blksize + 1, file.metadata().unwrap().len());
+ }
+
+ /// Checks filesystem space methods.
+ #[test]
+ fn filesystem_space() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let total_space = total_space(&tempdir.path()).unwrap();
+ let free_space = free_space(&tempdir.path()).unwrap();
+ let available_space = available_space(&tempdir.path()).unwrap();
+
+ assert!(total_space > free_space);
+ assert!(total_space > available_space);
+ assert!(available_space <= free_space);
+ }
+
+ /// Benchmarks creating and removing a file. This is a baseline benchmark
+ /// for comparing against the truncate and allocate benchmarks.
+ #[bench]
+ fn bench_file_create(b: &mut test::Bencher) {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("file");
+
+ b.iter(|| {
+ fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+ fs::remove_file(&path).unwrap();
+ });
+ }
+
+ /// Benchmarks creating a file, truncating it to 32MiB, and deleting it.
+ #[bench]
+ fn bench_file_truncate(b: &mut test::Bencher) {
+ let size = 32 * 1024 * 1024;
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("file");
+
+ b.iter(|| {
+ let file = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+ file.set_len(size).unwrap();
+ fs::remove_file(&path).unwrap();
+ });
+ }
+
+ /// Benchmarks creating a file, allocating 32MiB for it, and deleting it.
+ #[bench]
+ fn bench_file_allocate(b: &mut test::Bencher) {
+ let size = 32 * 1024 * 1024;
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("file");
+
+ b.iter(|| {
+ let file = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+ file.allocate(size).unwrap();
+ fs::remove_file(&path).unwrap();
+ });
+ }
+
+ /// Benchmarks creating a file, allocating 32MiB for it, and deleting it.
+ #[bench]
+ fn bench_allocated_size(b: &mut test::Bencher) {
+ let size = 32 * 1024 * 1024;
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("file");
+ let file = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+ file.allocate(size).unwrap();
+
+ b.iter(|| {
+ file.allocated_size().unwrap();
+ });
+ }
+
+ /// Benchmarks duplicating a file descriptor or handle.
+ #[bench]
+ fn bench_duplicate(b: &mut test::Bencher) {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+
+ b.iter(|| test::black_box(file.duplicate().unwrap()));
+ }
+
+ /// Benchmarks locking and unlocking a file lock.
+ #[bench]
+ fn bench_lock_unlock(b: &mut test::Bencher) {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+
+ b.iter(|| {
+ file.lock_exclusive().unwrap();
+ file.unlock().unwrap();
+ });
+ }
+
+ /// Benchmarks the free space method.
+ #[bench]
+ fn bench_free_space(b: &mut test::Bencher) {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ b.iter(|| {
+ test::black_box(free_space(&tempdir.path()).unwrap());
+ });
+ }
+
+ /// Benchmarks the available space method.
+ #[bench]
+ fn bench_available_space(b: &mut test::Bencher) {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ b.iter(|| {
+ test::black_box(available_space(&tempdir.path()).unwrap());
+ });
+ }
+
+ /// Benchmarks the total space method.
+ #[bench]
+ fn bench_total_space(b: &mut test::Bencher) {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ b.iter(|| {
+ test::black_box(total_space(&tempdir.path()).unwrap());
+ });
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/src/unix.rs
@@ -0,0 +1,250 @@
+extern crate libc;
+
+use std::ffi::CString;
+use std::fs::File;
+use std::io::{Error, ErrorKind, Result};
+use std::mem;
+use std::os::unix::ffi::OsStrExt;
+use std::os::unix::fs::MetadataExt;
+use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::path::Path;
+
+use FsStats;
+
+pub fn duplicate(file: &File) -> Result<File> {
+ unsafe {
+ let fd = libc::dup(file.as_raw_fd());
+
+ if fd < 0 {
+ Err(Error::last_os_error())
+ } else {
+ Ok(File::from_raw_fd(fd))
+ }
+ }
+}
+
+pub fn lock_shared(file: &File) -> Result<()> {
+ flock(file, libc::LOCK_SH)
+}
+
+pub fn lock_exclusive(file: &File) -> Result<()> {
+ flock(file, libc::LOCK_EX)
+}
+
+pub fn try_lock_shared(file: &File) -> Result<()> {
+ flock(file, libc::LOCK_SH | libc::LOCK_NB)
+}
+
+pub fn try_lock_exclusive(file: &File) -> Result<()> {
+ flock(file, libc::LOCK_EX | libc::LOCK_NB)
+}
+
+pub fn unlock(file: &File) -> Result<()> {
+ flock(file, libc::LOCK_UN)
+}
+
+pub fn lock_error() -> Error {
+ Error::from_raw_os_error(libc::EWOULDBLOCK)
+}
+
+#[cfg(not(target_os = "solaris"))]
+fn flock(file: &File, flag: libc::c_int) -> Result<()> {
+ let ret = unsafe { libc::flock(file.as_raw_fd(), flag) };
+ if ret < 0 { Err(Error::last_os_error()) } else { Ok(()) }
+}
+
+/// Simulate flock() using fcntl(); primarily for Oracle Solaris.
+#[cfg(target_os = "solaris")]
+fn flock(file: &File, flag: libc::c_int) -> Result<()> {
+ let mut fl = libc::flock {
+ l_whence: 0,
+ l_start: 0,
+ l_len: 0,
+ l_type: 0,
+ l_pad: [0; 4],
+ l_pid: 0,
+ l_sysid: 0,
+ };
+
+ // In non-blocking mode, use F_SETLK for cmd, F_SETLKW otherwise, and don't forget to clear
+ // LOCK_NB.
+ let (cmd, operation) = match flag & libc::LOCK_NB {
+ 0 => (libc::F_SETLKW, flag),
+ _ => (libc::F_SETLK, flag & !libc::LOCK_NB),
+ };
+
+ match operation {
+ libc::LOCK_SH => fl.l_type |= libc::F_RDLCK,
+ libc::LOCK_EX => fl.l_type |= libc::F_WRLCK,
+ libc::LOCK_UN => fl.l_type |= libc::F_UNLCK,
+ _ => return Err(Error::from_raw_os_error(libc::EINVAL)),
+ }
+
+ let ret = unsafe { libc::fcntl(file.as_raw_fd(), cmd, &fl) };
+ match ret {
+ // Translate EACCES to EWOULDBLOCK
+ -1 => match Error::last_os_error().raw_os_error() {
+ Some(libc::EACCES) => return Err(lock_error()),
+ _ => return Err(Error::last_os_error())
+ },
+ _ => Ok(())
+ }
+}
+
+pub fn allocated_size(file: &File) -> Result<u64> {
+ file.metadata().map(|m| m.blocks() as u64 * 512)
+}
+
+#[cfg(any(target_os = "linux",
+ target_os = "freebsd",
+ target_os = "android",
+ target_os = "nacl"))]
+pub fn allocate(file: &File, len: u64) -> Result<()> {
+ let ret = unsafe { libc::posix_fallocate(file.as_raw_fd(), 0, len as libc::off_t) };
+ if ret == 0 { Ok(()) } else { Err(Error::last_os_error()) }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub fn allocate(file: &File, len: u64) -> Result<()> {
+ let stat = try!(file.metadata());
+
+ if len > stat.blocks() as u64 * 512 {
+ let mut fstore = libc::fstore_t {
+ fst_flags: libc::F_ALLOCATECONTIG,
+ fst_posmode: libc::F_PEOFPOSMODE,
+ fst_offset: 0,
+ fst_length: len as libc::off_t,
+ fst_bytesalloc: 0,
+ };
+
+ let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) };
+ if ret == -1 {
+ // Unable to allocate contiguous disk space; attempt to allocate non-contiguously.
+ fstore.fst_flags = libc::F_ALLOCATEALL;
+ let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) };
+ if ret == -1 {
+ return Err(Error::last_os_error());
+ }
+ }
+ }
+
+ if len > stat.size() as u64 {
+ file.set_len(len)
+ } else {
+ Ok(())
+ }
+}
+
+#[cfg(any(target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "solaris",
+ target_os = "haiku"))]
+pub fn allocate(file: &File, len: u64) -> Result<()> {
+ // No file allocation API available, just set the length if necessary.
+ if len > try!(file.metadata()).len() as u64 {
+ file.set_len(len)
+ } else {
+ Ok(())
+ }
+}
+
+pub fn statvfs(path: &Path) -> Result<FsStats> {
+ let cstr = match CString::new(path.as_os_str().as_bytes()) {
+ Ok(cstr) => cstr,
+ Err(..) => return Err(Error::new(ErrorKind::InvalidInput, "path contained a null")),
+ };
+
+ unsafe {
+ let mut stat: libc::statvfs = mem::zeroed();
+ // danburkert/fs2-rs#1: cast is necessary for platforms where c_char != u8.
+ if libc::statvfs(cstr.as_ptr() as *const _, &mut stat) != 0 {
+ Err(Error::last_os_error())
+ } else {
+ Ok(FsStats {
+ free_space: stat.f_frsize as u64 * stat.f_bfree as u64,
+ available_space: stat.f_frsize as u64 * stat.f_bavail as u64,
+ total_space: stat.f_frsize as u64 * stat.f_blocks as u64,
+ allocation_granularity: stat.f_frsize as u64,
+ })
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ extern crate tempdir;
+ extern crate libc;
+
+ use std::fs::{self, File};
+ use std::os::unix::io::AsRawFd;
+
+ use {FileExt, lock_contended_error};
+
+ /// The duplicate method returns a file with a new file descriptor.
+ #[test]
+ fn duplicate_new_fd() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
+ let file2 = file1.duplicate().unwrap();
+ assert!(file1.as_raw_fd() != file2.as_raw_fd());
+ }
+
+ /// The duplicate method should preservesthe close on exec flag.
+ #[test]
+ fn duplicate_cloexec() {
+
+ fn flags(file: &File) -> libc::c_int {
+ unsafe { libc::fcntl(file.as_raw_fd(), libc::F_GETFL, 0) }
+ }
+
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
+ let file2 = file1.duplicate().unwrap();
+
+ assert_eq!(flags(&file1), flags(&file2));
+ }
+
+ /// Tests that locking a file descriptor will replace any existing locks
+ /// held on the file descriptor.
+ #[test]
+ fn lock_replace() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
+ let file2 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
+
+ // Creating a shared lock will drop an exclusive lock.
+ file1.lock_exclusive().unwrap();
+ file1.lock_shared().unwrap();
+ file2.lock_shared().unwrap();
+
+ // Attempting to replace a shared lock with an exclusive lock will fail
+ // with multiple lock holders, and remove the original shared lock.
+ assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+ file1.lock_shared().unwrap();
+ }
+
+ /// Tests that locks are shared among duplicated file descriptors.
+ #[test]
+ fn lock_duplicate() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
+ let file2 = file1.duplicate().unwrap();
+ let file3 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
+
+ // Create a lock through fd1, then replace it through fd2.
+ file1.lock_shared().unwrap();
+ file2.lock_exclusive().unwrap();
+ assert_eq!(file3.try_lock_shared().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+
+ // Either of the file descriptors should be able to unlock.
+ file1.unlock().unwrap();
+ file3.lock_shared().unwrap();
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/fs2/src/windows.rs
@@ -0,0 +1,271 @@
+extern crate kernel32;
+extern crate winapi;
+
+use std::fs::File;
+use std::io::{Error, Result};
+use std::mem;
+use std::os::windows::ffi::OsStrExt;
+use std::os::windows::io::{AsRawHandle, FromRawHandle};
+use std::path::Path;
+use std::ptr;
+
+use FsStats;
+
+pub fn duplicate(file: &File) -> Result<File> {
+ unsafe {
+ let mut handle = ptr::null_mut();
+ let current_process = kernel32::GetCurrentProcess();
+ let ret = kernel32::DuplicateHandle(current_process,
+ file.as_raw_handle(),
+ current_process,
+ &mut handle,
+ 0,
+ true as winapi::BOOL,
+ winapi::DUPLICATE_SAME_ACCESS);
+ if ret == 0 {
+ Err(Error::last_os_error())
+ } else {
+ Ok(File::from_raw_handle(handle))
+ }
+ }
+}
+
+pub fn allocated_size(file: &File) -> Result<u64> {
+ unsafe {
+ let mut info: winapi::FILE_STANDARD_INFO = mem::zeroed();
+
+ let ret = kernel32::GetFileInformationByHandleEx(
+ file.as_raw_handle(),
+ winapi::FileStandardInfo,
+ &mut info as *mut _ as *mut _,
+ mem::size_of::<winapi::FILE_STANDARD_INFO>() as winapi::DWORD);
+
+ if ret == 0 {
+ Err(Error::last_os_error())
+ } else {
+ Ok(info.AllocationSize as u64)
+ }
+ }
+}
+
+pub fn allocate(file: &File, len: u64) -> Result<()> {
+ if try!(allocated_size(file)) < len {
+ unsafe {
+ let mut info: winapi::FILE_ALLOCATION_INFO = mem::zeroed();
+ info.AllocationSize = len as i64;
+ let ret = kernel32::SetFileInformationByHandle(
+ file.as_raw_handle(),
+ winapi::FileAllocationInfo,
+ &mut info as *mut _ as *mut _,
+ mem::size_of::<winapi::FILE_ALLOCATION_INFO>() as winapi::DWORD);
+ if ret == 0 {
+ return Err(Error::last_os_error());
+ }
+ }
+ }
+ if try!(file.metadata()).len() < len {
+ file.set_len(len)
+ } else {
+ Ok(())
+ }
+}
+
+pub fn lock_shared(file: &File) -> Result<()> {
+ lock_file(file, 0)
+}
+
+pub fn lock_exclusive(file: &File) -> Result<()> {
+ lock_file(file, winapi::LOCKFILE_EXCLUSIVE_LOCK)
+}
+
+pub fn try_lock_shared(file: &File) -> Result<()> {
+ lock_file(file, winapi::LOCKFILE_FAIL_IMMEDIATELY)
+}
+
+pub fn try_lock_exclusive(file: &File) -> Result<()> {
+ lock_file(file, winapi::LOCKFILE_EXCLUSIVE_LOCK | winapi::LOCKFILE_FAIL_IMMEDIATELY)
+}
+
+pub fn unlock(file: &File) -> Result<()> {
+ unsafe {
+ let ret = kernel32::UnlockFile(file.as_raw_handle(), 0, 0, !0, !0);
+ if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) }
+ }
+}
+
+pub fn lock_error() -> Error {
+ Error::from_raw_os_error(winapi::ERROR_LOCK_VIOLATION as i32)
+}
+
+fn lock_file(file: &File, flags: winapi::DWORD) -> Result<()> {
+ unsafe {
+ let mut overlapped = mem::zeroed();
+ let ret = kernel32::LockFileEx(file.as_raw_handle(), flags, 0, !0, !0, &mut overlapped);
+ if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) }
+ }
+}
+
+fn volume_path(path: &Path, volume_path: &mut [u16]) -> Result<()> {
+ let path_utf8: Vec<u16> = path.as_os_str().encode_wide().chain(Some(0)).collect();
+ unsafe {
+ let ret = kernel32::GetVolumePathNameW(path_utf8.as_ptr(),
+ volume_path.as_mut_ptr(),
+ volume_path.len() as winapi::DWORD);
+ if ret == 0 { Err(Error::last_os_error()) } else { Ok(())
+ }
+ }
+}
+
+pub fn statvfs(path: &Path) -> Result<FsStats> {
+ let root_path: &mut [u16] = &mut [0; 261];
+ try!(volume_path(path, root_path));
+ unsafe {
+
+ let mut sectors_per_cluster = 0;
+ let mut bytes_per_sector = 0;
+ let mut number_of_free_clusters = 0;
+ let mut total_number_of_clusters = 0;
+ let ret = kernel32::GetDiskFreeSpaceW(root_path.as_ptr(),
+ &mut sectors_per_cluster,
+ &mut bytes_per_sector,
+ &mut number_of_free_clusters,
+ &mut total_number_of_clusters);
+ if ret == 0 {
+ Err(Error::last_os_error())
+ } else {
+ let bytes_per_cluster = sectors_per_cluster as u64 * bytes_per_sector as u64;
+ let free_space = bytes_per_cluster * number_of_free_clusters as u64;
+ let total_space = bytes_per_cluster * total_number_of_clusters as u64;
+ Ok(FsStats {
+ free_space: free_space,
+ available_space: free_space,
+ total_space: total_space,
+ allocation_granularity: bytes_per_cluster,
+ })
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ extern crate tempdir;
+
+ use std::fs;
+ use std::os::windows::io::AsRawHandle;
+
+ use {FileExt, lock_contended_error};
+
+ /// The duplicate method returns a file with a new file handle.
+ #[test]
+ fn duplicate_new_handle() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
+ let file2 = file1.duplicate().unwrap();
+ assert!(file1.as_raw_handle() != file2.as_raw_handle());
+ }
+
+ /// A duplicated file handle does not have access to the original handle's locks.
+ #[test]
+ fn lock_duplicate_handle_independence() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+ let file2 = file1.duplicate().unwrap();
+
+ // Locking the original file handle will block the duplicate file handle from opening a lock.
+ file1.lock_shared().unwrap();
+ assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+
+ // Once the original file handle is unlocked, the duplicate handle can proceed with a lock.
+ file1.unlock().unwrap();
+ file2.lock_exclusive().unwrap();
+ }
+
+ /// A file handle may not be exclusively locked multiple times, or exclusively locked and then
+ /// shared locked.
+ #[test]
+ fn lock_non_reentrant() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+
+ // Multiple exclusive locks fails.
+ file.lock_exclusive().unwrap();
+ assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+ file.unlock().unwrap();
+
+ // Shared then Exclusive locks fails.
+ file.lock_shared().unwrap();
+ assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+ }
+
+ /// A file handle can hold an exclusive lock and any number of shared locks, all of which must
+ /// be unlocked independently.
+ #[test]
+ fn lock_layering() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+
+ // Open two shared locks on the file, and then try and fail to open an exclusive lock.
+ file.lock_exclusive().unwrap();
+ file.lock_shared().unwrap();
+ file.lock_shared().unwrap();
+ assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+
+ // Pop one of the shared locks and try again.
+ file.unlock().unwrap();
+ assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+
+ // Pop the second shared lock and try again.
+ file.unlock().unwrap();
+ assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+
+ // Pop the exclusive lock and finally succeed.
+ file.unlock().unwrap();
+ file.lock_exclusive().unwrap();
+ }
+
+ /// A file handle with multiple open locks will have all locks closed on drop.
+ #[test]
+ fn lock_layering_cleanup() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+ let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+
+ // Open two shared locks on the file, and then try and fail to open an exclusive lock.
+ file1.lock_shared().unwrap();
+ assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+
+ drop(file1);
+ file2.lock_exclusive().unwrap();
+ }
+
+ /// A file handle's locks will not be released until the original handle and all of its
+ /// duplicates have been closed. This on really smells like a bug in Windows.
+ #[test]
+ fn lock_duplicate_cleanup() {
+ let tempdir = tempdir::TempDir::new("fs2").unwrap();
+ let path = tempdir.path().join("fs2");
+ let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
+ let file2 = file1.duplicate().unwrap();
+
+ // Open a lock on the original handle, then close it.
+ file1.lock_shared().unwrap();
+ drop(file1);
+
+ // Attempting to create a lock on the file with the duplicate handle will fail.
+ assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
+ lock_contended_error().raw_os_error());
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"647d4a5498a3bef693b45603933e604b6ccf7aba8823a33b764ca1833797768b","Cargo.toml":"1c82b292358c72b779205f71efaef3fa343b42143e2cd1845fc44ffd95527a77","LICENSE-APACHE":"01b5abb4a95cc87b220efbd67a1e99c74bef3d744806dd44b4d57e81db814962","LICENSE-MIT":"d4784f55731ba75b77ad73a52808914b26b2f93b69dd4c03249528a75afbd946","README.md":"247302d4c1dc621f150bc06fc0d37f7ad5a4f2dcf1aafe25f8dfe8eb4fe35921","appveyor.yml":"8c309c2779904317005c7f7404470daf2aad344571168a37da214e37833be2a9","src/lib.rs":"aab60277edb10e3b93a5f1a307054fd78c263f3a597b5088e5d7280378c7b028","src/sys/mod.rs":"4c3765602032675d6d236a25b99c00f20515f7e86b7f8afa3148aeaaef58def1","src/sys/unix.rs":"bbf6c36a4a4d48342581ae6c17f8d7ef95d22f4958cf71193429ce53ec4555c2","src/sys/windows.rs":"f0690442f4842b0f0e8fc34739397f0dca8912fde424563d8540d954868f64c7","src/unix.rs":"76e76333e31dd53d1ea6704a880f4188014af09fe8be3cecd5239003b2a1fe7c","src/windows.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},"package":"29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/.travis.yml
@@ -0,0 +1,24 @@
+---
+language: rust
+sudo: false
+
+rust:
+ - stable
+
+os:
+ - linux
+ - osx
+
+matrix:
+ include:
+ - os: linux
+ # Oldest supported Rust (this should track Mio)
+ rust: 1.9.0
+
+script:
+ - cargo build
+ - cargo test
+
+notifications:
+ email:
+ on_success: never
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "iovec"
+version = "0.1.0"
+authors = ["Carl Lerche <me@carllerche.com>"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+keywords = ["scatter", "gather", "vectored", "io", "networking"]
+repository = "https://github.com/carllerche/iovec"
+homepage = "https://github.com/carllerche/iovec"
+documentation = "https://docs.rs/iovec"
+description = """
+Portable buffer type for scatter/gather I/O operations
+"""
+categories = ["network-programming", "api-bindings"]
+
+[target.'cfg(unix)'.dependencies]
+libc = "0.2"
+
+[target.'cfg(windows)'.dependencies]
+winapi = "0.2"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright 2017 Carl Lerche
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2017 Carl Lerche
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/README.md
@@ -0,0 +1,35 @@
+# IoVec
+
+A specialized byte slice type for performing vectored I/O operations.
+
+[![Crates.io](https://img.shields.io/crates/v/iovec.svg?maxAge=2592000)](https://crates.io/crates/iovec)
+[![Build Status](https://travis-ci.org/carllerche/iovec.svg?branch=master)](https://travis-ci.org/carllerche/iovec)
+
+[Documentation](https://docs.rs/iovec)
+
+## Usage
+
+To use `iovec`, first add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+iovec = "0.1"
+```
+
+Next, add this to your crate:
+
+```rust
+extern crate iovec;
+
+use iovec::IoVec;
+```
+
+For more detail, see [documentation](https://docs.rs/iovec).
+
+# License
+
+`iovec` is primarily distributed under the terms of both the MIT license and the
+Apache License (Version 2.0), with portions covered by various BSD-like
+licenses.
+
+See LICENSE-APACHE, and LICENSE-MIT for details.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/appveyor.yml
@@ -0,0 +1,16 @@
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+
+install:
+ - curl -sSf -o rustup-init.exe https://win.rustup.rs/
+ - rustup-init.exe -y --default-host %TARGET%
+ - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
+ - rustc -V
+ - cargo -V
+
+build: false
+
+test_script:
+ - cargo build
+ - cargo test
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/src/lib.rs
@@ -0,0 +1,134 @@
+//! A specialized byte slice type for performing vectored I/O operations.
+//!
+//! For more detail, see [`IoVec`] documentation.
+//!
+//! [`IoVec`]: struct.IoVec.html
+
+#[cfg(unix)]
+extern crate libc;
+
+#[cfg(windows)]
+extern crate winapi;
+
+mod sys;
+
+use std::{ops, mem};
+
+#[cfg(unix)]
+pub mod unix;
+
+/// Max length of an `IoVec` slice.
+///
+/// Attempts to convert slices longer than this value will result in a panic.
+pub const MAX_LENGTH: usize = sys::MAX_LENGTH;
+
+/// A specialized byte slice type for performing vectored I/O operations.
+///
+/// On all systems, the types needed to peform vectored I/O systems have the
+/// same size as Rust's [slice]. However, the layout is not necessarily the
+/// same. `IoVec` provides a portable compatibility layer.
+///
+/// The `IoVec` behaves like like a Rust [slice], providing the same functions.
+/// It also provides conversion functions to and from the OS specific vectored
+/// types.
+///
+/// # Examples
+///
+/// ```
+/// use iovec::IoVec;
+///
+/// let mut data = vec![];
+/// data.extend_from_slice(b"hello");
+///
+/// let iovec: &IoVec = data.as_slice().into();
+///
+/// assert_eq!(&iovec[..], &b"hello"[..]);
+/// ```
+///
+/// # Panics
+///
+/// Attempting to convert a slice longer than [`MAX_LENGTH`] to an `IoVec` will
+/// result in a panic.
+///
+/// [`MAX_LENGTH`]: constant.MAX_LENGTH.html
+pub struct IoVec {
+ sys: sys::IoVec,
+}
+
+impl IoVec {
+ #[deprecated(since = "0.1.0", note = "deref instead")]
+ #[doc(hidden)]
+ pub fn as_bytes(&self) -> &[u8] {
+ &**self
+ }
+
+ #[deprecated(since = "0.1.0", note = "deref instead")]
+ #[doc(hidden)]
+ pub fn as_mut_bytes(&mut self) -> &mut [u8] {
+ &mut **self
+ }
+}
+
+impl ops::Deref for IoVec {
+ type Target = [u8];
+
+ fn deref(&self) -> &[u8] {
+ &self.sys.as_ref()
+ }
+}
+
+impl ops::DerefMut for IoVec {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ self.sys.as_mut()
+ }
+}
+
+impl<'a> From<&'a [u8]> for &'a IoVec {
+ fn from(bytes: &'a [u8]) -> &'a IoVec {
+ unsafe {
+ let iovec: &sys::IoVec = bytes.into();
+ mem::transmute(iovec)
+ }
+ }
+}
+
+impl<'a> From<&'a mut [u8]> for &'a mut IoVec {
+ fn from(bytes: &'a mut [u8]) -> &'a mut IoVec {
+ unsafe {
+ let iovec: &mut sys::IoVec = bytes.into();
+ mem::transmute(iovec)
+ }
+ }
+}
+
+impl<'a> Default for &'a IoVec {
+ fn default() -> Self {
+ let b: &[u8] = Default::default();
+ b.into()
+ }
+}
+
+impl<'a> Default for &'a mut IoVec {
+ fn default() -> Self {
+ let b: &mut [u8] = Default::default();
+ b.into()
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::IoVec;
+
+ #[test]
+ fn convert_ref() {
+ let buf: &IoVec = (&b"hello world"[..]).into();
+ assert_eq!(buf[..], b"hello world"[..]);
+ }
+
+ #[test]
+ fn convert_mut() {
+ let mut buf: Vec<u8> = b"hello world".to_vec();
+ let buf: &mut IoVec = (&mut buf[..]).into();
+ assert_eq!(buf[..], b"hello world"[..]);
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/src/sys/mod.rs
@@ -0,0 +1,17 @@
+#[cfg(unix)]
+mod unix;
+
+#[cfg(unix)]
+pub use self::unix::{
+ IoVec,
+ MAX_LENGTH,
+};
+
+#[cfg(windows)]
+mod windows;
+
+#[cfg(windows)]
+pub use self::windows::{
+ IoVec,
+ MAX_LENGTH,
+};
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/src/sys/unix.rs
@@ -0,0 +1,50 @@
+use libc;
+use std::{mem, slice, usize};
+
+pub struct IoVec {
+ inner: [u8],
+}
+
+pub const MAX_LENGTH: usize = usize::MAX;
+
+impl IoVec {
+ pub fn as_ref(&self) -> &[u8] {
+ unsafe {
+ let vec = self.iovec();
+ slice::from_raw_parts(vec.iov_base as *const u8, vec.iov_len)
+ }
+ }
+
+ pub fn as_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ let vec = self.iovec();
+ slice::from_raw_parts_mut(vec.iov_base as *mut u8, vec.iov_len)
+ }
+ }
+
+ unsafe fn iovec(&self) -> libc::iovec {
+ mem::transmute(&self.inner)
+ }
+}
+
+impl<'a> From<&'a [u8]> for &'a IoVec {
+ fn from(src: &'a [u8]) -> Self {
+ unsafe {
+ mem::transmute(libc::iovec {
+ iov_base: src.as_ptr() as *mut _,
+ iov_len: src.len(),
+ })
+ }
+ }
+}
+
+impl<'a> From<&'a mut [u8]> for &'a mut IoVec {
+ fn from(src: &'a mut [u8]) -> Self {
+ unsafe {
+ mem::transmute(libc::iovec {
+ iov_base: src.as_ptr() as *mut _,
+ iov_len: src.len(),
+ })
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/src/sys/windows.rs
@@ -0,0 +1,54 @@
+use winapi::{WSABUF, DWORD};
+use std::{mem, slice, u32};
+
+pub struct IoVec {
+ inner: [u8],
+}
+
+pub const MAX_LENGTH: usize = u32::MAX as usize;
+
+impl IoVec {
+ pub fn as_ref(&self) -> &[u8] {
+ unsafe {
+ let vec = self.wsabuf();
+ slice::from_raw_parts(vec.buf as *const u8, vec.len as usize)
+ }
+ }
+
+ pub fn as_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ let vec = self.wsabuf();
+ slice::from_raw_parts_mut(vec.buf as *mut u8, vec.len as usize)
+ }
+ }
+
+ unsafe fn wsabuf(&self) -> WSABUF {
+ mem::transmute(&self.inner)
+ }
+}
+
+impl<'a> From<&'a [u8]> for &'a IoVec {
+ fn from(src: &'a [u8]) -> Self {
+ assert!(src.len() <= MAX_LENGTH);
+
+ unsafe {
+ mem::transmute(WSABUF {
+ buf: src.as_ptr() as *mut _,
+ len: src.len() as DWORD,
+ })
+ }
+ }
+}
+
+impl<'a> From<&'a mut [u8]> for &'a mut IoVec {
+ fn from(src: &'a mut [u8]) -> Self {
+ assert!(src.len() <= MAX_LENGTH);
+
+ unsafe {
+ mem::transmute(WSABUF {
+ buf: src.as_ptr() as *mut _,
+ len: src.len() as DWORD,
+ })
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/iovec/src/unix.rs
@@ -0,0 +1,68 @@
+//! IoVec extensions for Unix platforms.
+//!
+//! These functions provide conversions to unix specific representations of the
+//! vectored data.
+//!
+//! # Examples
+//!
+//! ```
+//! use iovec::IoVec;
+//! use iovec::unix;
+//!
+//! let a = b"hello".to_vec();
+//! let b = b"world".to_vec();
+//!
+//! let bufs: &[&IoVec] = &[(&a[..]).into(), (&b[..]).into()];
+//! let os_bufs = unix::as_os_slice(&bufs[..]);
+//!
+//! // Use the `os_bufs` slice with `writev`.
+//! ```
+
+use IoVec;
+use libc;
+
+use std::mem;
+
+/// Convert a slice of `IoVec` refs to a slice of `libc::iovec`.
+///
+/// The return value can be passed to `writev` bindings.
+///
+/// # Examples
+///
+/// ```
+/// use iovec::IoVec;
+/// use iovec::unix;
+///
+/// let a = b"hello".to_vec();
+/// let b = b"world".to_vec();
+///
+/// let bufs: &[&IoVec] = &[a[..].into(), b[..].into()];
+/// let os_bufs = unix::as_os_slice(bufs);
+///
+/// // Use the `os_bufs` slice with `writev`.
+/// ```
+pub fn as_os_slice<'a>(iov: &'a [&IoVec]) -> &'a [libc::iovec] {
+ unsafe { mem::transmute(iov) }
+}
+
+/// Convert a mutable slice of `IoVec` refs to a mutable slice of `libc::iovec`.
+///
+/// The return value can be passed to `readv` bindings.
+///
+/// # Examples
+///
+/// ```
+/// use iovec::IoVec;
+/// use iovec::unix;
+///
+/// let mut a = [0; 10];
+/// let mut b = [0; 10];
+///
+/// let bufs: &mut [&mut IoVec] = &mut [(&mut a[..]).into(), (&mut b[..]).into()];
+/// let os_bufs = unix::as_os_slice_mut(bufs);
+///
+/// // Use the `os_bufs` slice with `readv`.
+/// ```
+pub fn as_os_slice_mut<'a>(iov: &'a mut [&mut IoVec]) -> &'a mut [libc::iovec] {
+ unsafe { mem::transmute(iov) }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/lazycell/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","CHANGELOG.md":"a8defced70d220e04f77271ccced7e207d4e1417ed5e512b3dd4c8f9979e6a52","Cargo.toml":"46631e96c028ae56b797ec10524d6d9912fdd9857c3bea82957b1c394050b224","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6fc4fe1f402475d5c3f6e1b5c35407c5f489daa58bf8bb085d231909b5fac666","README.md":"fb8373bbd59d2885e119bdacf25898e0e3b98d4a97ea840c62cf967db28c61a2","src/lib.rs":"efcff18d06fdcc4bca2ead19e41b33dbc83f9c7d1591cd98206f657dad704580"},"package":"ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/lazycell/CHANGELOG.md
@@ -0,0 +1,80 @@
+<a name="v0.4.0"></a>
+## (2016-08-17)
+
+
+#### Breaking Changes
+
+* **LazyCell:** return Err(value) on full cell ([68f3415d](https://github.com/indiv0/lazycell/commit/68f3415dd5d6a66ba047a133b7028ebe4f1c5070), breaks [#](https://github.com/indiv0/lazycell/issues/))
+
+#### Improvements
+
+* **LazyCell:** return Err(value) on full cell ([68f3415d](https://github.com/indiv0/lazycell/commit/68f3415dd5d6a66ba047a133b7028ebe4f1c5070), breaks [#](https://github.com/indiv0/lazycell/issues/))
+
+
+
+<a name="v0.3.0"></a>
+## (2016-08-16)
+
+
+#### Features
+
+* add AtomicLazyCell which is thread-safe ([85afbd36](https://github.com/indiv0/lazycell/commit/85afbd36d8a148e14cc53654b39ddb523980124d))
+
+#### Improvements
+
+* Use UnsafeCell instead of RefCell ([3347a8e9](https://github.com/indiv0/lazycell/commit/3347a8e97d2215a47e25c1e2fc953e8052ad8eb6))
+
+
+
+<a name="v0.2.1"></a>
+## (2016-04-18)
+
+
+#### Documentation
+
+* put types in between backticks ([607cf939](https://github.com/indiv0/lazycell/commit/607cf939b05e35001ba3070ec7a0b17b064e7be1))
+
+
+
+<a name="v0.2.0"></a>
+## v0.2.0 (2016-03-28)
+
+
+#### Features
+
+* **lazycell:**
+ * add tests for `LazyCell` struct ([38f1313d](https://github.com/indiv0/lazycell/commit/38f1313d98542ca8c98b424edfa9ba9c3975f99e), closes [#30](https://github.com/indiv0/lazycell/issues/30))
+ * remove unnecessary `Default` impl ([68c16d2d](https://github.com/indiv0/lazycell/commit/68c16d2df4e9d13d5298162c06edf918246fd758))
+
+#### Documentation
+
+* **CHANGELOG:** removed unnecessary sections ([1cc0555d](https://github.com/indiv0/lazycell/commit/1cc0555d875898a01b0832ff967aed6b40e720eb))
+* **README:** add link to documentation ([c8dc33f0](https://github.com/indiv0/lazycell/commit/c8dc33f01f2c0dc187f59ee53a2b73081053012b), closes [#13](https://github.com/indiv0/lazycell/issues/13))
+
+
+
+<a name="v0.1.0"></a>
+## v0.1.0 (2016-03-16)
+
+
+#### Features
+
+* **lib.rs:** implement Default trait for LazyCell ([150a6304](https://github.com/indiv0/LazyCell/commit/150a6304a230ee1de8424e49c447ec1b2d6578ce))
+
+
+
+<a name="v0.0.1"></a>
+## v0.0.1 (2016-03-16)
+
+
+#### Bug Fixes
+
+* **Cargo.toml:** loosen restrictions on Clippy version ([84dd8f96](https://github.com/indiv0/LazyCell/commit/84dd8f960000294f9dad47d776a41b98ed812981))
+
+#### Features
+
+* add initial implementation ([4b39764a](https://github.com/indiv0/LazyCell/commit/4b39764a575bcb701dbd8047b966f72720fd18a4))
+* add initial commit ([a80407a9](https://github.com/indiv0/LazyCell/commit/a80407a907ef7c9401f120104663172f6965521a))
+
+
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/lazycell/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "lazycell"
+version = "0.4.0"
+authors = ["Alex Crichton <alex@alexcrichton.com>",
+ "Nikita Pekin <contact@nikitapek.in>"]
+description = "A library providing a lazily filled Cell struct"
+repository = "https://github.com/indiv0/lazycell"
+documentation = "http://indiv0.github.io/lazycell/lazycell/"
+readme = "README.md"
+keywords = ["lazycell", "lazy", "cell", "library"]
+license = "MIT/Apache-2.0"
+include = [
+ "CHANGELOG.md",
+ "Cargo.toml",
+ "LICENSE-MIT",
+ "LICENSE-APACHE",
+ "README.md",
+ "src/**/*.rs",
+]
+
+[dependencies]
+clippy = { version = "0.0", optional = true }
+
+[features]
+nightly = []
+nightly-testing = ["clippy", "nightly"]
new file mode 100644
--- /dev/null
+++ b/third_party/rust/lazycell/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/lazycell/LICENSE-MIT
@@ -0,0 +1,26 @@
+Original work Copyright (c) 2014 The Rust Project Developers
+Modified work Copyright (c) 2016 Nikita Pekin and lazycell contributors
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/lazycell/README.md
@@ -0,0 +1,76 @@
+# lazycell
+
+<table>
+ <tr>
+ <td><strong>Linux / OS X</strong></td>
+ <td><a href="https://travis-ci.org/indiv0/lazycell" title="Travis Build Status"><img src="https://travis-ci.org/indiv0/lazycell.svg?branch=master" alt="travis-badge"></img></a></td>
+ </tr>
+ <tr>
+ <td><strong>Windows</strong></td>
+ <td><a href="https://ci.appveyor.com/project/indiv0/lazycell" title="Appveyor Build Status"><img src="https://ci.appveyor.com/api/projects/status/8sql0kict385l3cy?svg=true" alt="appveyor-badge"></img></a></td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <a href="https://indiv0.github.io/lazycell/lazycell" title="API Docs"><img src="https://img.shields.io/badge/API-docs-blue.svg" alt="api-docs-badge"></img></a>
+ <a href="https://crates.io/crates/lazycell" title="Crates.io"><img src="https://img.shields.io/crates/v/lazycell.svg" alt="crates-io"></img></a>
+ <a href="#license" title="License: MIT/Apache-2.0"><img src="https://img.shields.io/crates/l/lazycell.svg" alt="license-badge"></img></a>
+ <a href="https://coveralls.io/github/indiv0/lazycell?branch=master" title="Coverage Status"><img src="https://coveralls.io/repos/github/indiv0/lazycell/badge.svg?branch=master" alt="coveralls-badge"></img></a>
+ </td>
+ </tr>
+</table>
+
+Rust library providing a lazily filled Cell.
+
+# Table of Contents
+
+* [Usage](#usage)
+* [Contributing](#contributing)
+* [Credits](#credits)
+* [License](#license)
+
+## Usage
+
+Add the following to your `Cargo.toml`:
+
+```toml
+[dependencies]
+lazycell = "0.4"
+```
+
+And in your `lib.rs` or `main.rs`:
+
+```rust
+extern crate lazycell;
+```
+
+See the [API docs][api-docs] for information on using the crate in your library.
+
+## Contributing
+
+Contributions are always welcome!
+If you have an idea for something to add (code, documentation, tests, examples,
+etc.) feel free to give it a shot.
+
+Please read [CONTRIBUTING.md][contributing] before you start contributing.
+
+## Credits
+
+The LazyCell library is based originally on work by The Rust Project Developers
+for the project [crates.io][crates-io-repo].
+
+The list of contributors to this project can be found at
+[CONTRIBUTORS.md][contributors].
+
+## License
+
+LazyCell is distributed under the terms of both the MIT license and the Apache
+License (Version 2.0).
+
+See [LICENSE-APACHE][license-apache], and [LICENSE-MIT][license-mit] for details.
+
+[api-docs]: https://indiv0.github.io/lazycell/lazycell
+[contributing]: https://github.com/indiv0/lazycell/blob/master/CONTRIBUTING.md "Contribution Guide"
+[contributors]: https://github.com/indiv0/lazycell/blob/master/CONTRIBUTORS.md "List of Contributors"
+[crates-io-repo]: https://github.com/rust-lang/crates.io "rust-lang/crates.io: Source code for crates.io"
+[license-apache]: https://github.com/indiv0/lazycell/blob/master/LICENSE-APACHE "Apache-2.0 License"
+[license-mit]: https://github.com/indiv0/lazycell/blob/master/LICENSE-MIT "MIT License"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/lazycell/src/lib.rs
@@ -0,0 +1,234 @@
+// Original work Copyright (c) 2014 The Rust Project Developers
+// Modified work Copyright (c) 2016 Nikita Pekin and the lazycell contributors
+// See the README.md file at the top-level directory of this distribution.
+//
+// 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.
+
+#![deny(missing_docs)]
+#![cfg_attr(feature = "nightly", feature(plugin))]
+#![cfg_attr(feature = "clippy", plugin(clippy))]
+
+//! This crate provides a `LazyCell` struct which acts as a lazily filled
+//! `Cell`, but with frozen contents.
+//!
+//! With a `RefCell`, the inner contents cannot be borrowed for the lifetime of
+//! the entire object, but only of the borrows returned. A `LazyCell` is a
+//! variation on `RefCell` which allows borrows to be tied to the lifetime of
+//! the outer object.
+//!
+//! The limitation of a `LazyCell` is that after it is initialized, it can never
+//! be modified.
+//!
+//! # Example
+//!
+//! The following example shows a quick example of the basic functionality of
+//! `LazyCell`.
+//!
+//! ```
+//! use lazycell::LazyCell;
+//!
+//! let lazycell = LazyCell::new();
+//!
+//! assert_eq!(lazycell.borrow(), None);
+//! assert!(!lazycell.filled());
+//! lazycell.fill(1).ok();
+//! assert!(lazycell.filled());
+//! assert_eq!(lazycell.borrow(), Some(&1));
+//! assert_eq!(lazycell.into_inner(), Some(1));
+//! ```
+//!
+//! `AtomicLazyCell` is a variant that uses an atomic variable to manage
+//! coordination in a thread-safe fashion.
+
+use std::cell::UnsafeCell;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+/// A lazily filled `Cell`, with frozen contents.
+pub struct LazyCell<T> {
+ inner: UnsafeCell<Option<T>>,
+}
+
+impl<T> LazyCell<T> {
+ /// Creates a new, empty, `LazyCell`.
+ pub fn new() -> LazyCell<T> {
+ LazyCell { inner: UnsafeCell::new(None) }
+ }
+
+ /// Put a value into this cell.
+ ///
+ /// This function will return Err(value) is the cell is already full.
+ pub fn fill(&self, t: T) -> Result<(), T> {
+ let mut slot = unsafe { &mut *self.inner.get() };
+ if slot.is_some() {
+ return Err(t);
+ }
+ *slot = Some(t);
+
+ Ok(())
+ }
+
+ /// Test whether this cell has been previously filled.
+ pub fn filled(&self) -> bool {
+ self.borrow().is_some()
+ }
+
+ /// Borrows the contents of this lazy cell for the duration of the cell
+ /// itself.
+ ///
+ /// This function will return `Some` if the cell has been previously
+ /// initialized, and `None` if it has not yet been initialized.
+ pub fn borrow(&self) -> Option<&T> {
+ unsafe { &*self.inner.get() }.as_ref()
+ }
+
+ /// Consumes this `LazyCell`, returning the underlying value.
+ pub fn into_inner(self) -> Option<T> {
+ unsafe { self.inner.into_inner() }
+ }
+}
+
+// Tracks the AtomicLazyCell inner state
+const NONE: usize = 0;
+const LOCK: usize = 1;
+const SOME: usize = 2;
+
+/// A lazily filled `Cell`, with frozen contents.
+pub struct AtomicLazyCell<T> {
+ inner: UnsafeCell<Option<T>>,
+ state: AtomicUsize,
+}
+
+impl<T> AtomicLazyCell<T> {
+ /// Creates a new, empty, `AtomicLazyCell`.
+ pub fn new() -> AtomicLazyCell<T> {
+ AtomicLazyCell {
+ inner: UnsafeCell::new(None),
+ state: AtomicUsize::new(NONE),
+ }
+ }
+
+ /// Put a value into this cell.
+ ///
+ /// This function will return Err(value) is the cell is already full.
+ pub fn fill(&self, t: T) -> Result<(), T> {
+ if NONE != self.state.compare_and_swap(NONE, LOCK, Ordering::Acquire) {
+ return Err(t);
+ }
+
+ unsafe { *self.inner.get() = Some(t) };
+
+ if LOCK != self.state.compare_and_swap(LOCK, SOME, Ordering::Release) {
+ panic!("unable to release lock");
+ }
+
+ Ok(())
+ }
+
+ /// Test whether this cell has been previously filled.
+ pub fn filled(&self) -> bool {
+ self.state.load(Ordering::Acquire) == SOME
+ }
+
+ /// Borrows the contents of this lazy cell for the duration of the cell
+ /// itself.
+ ///
+ /// This function will return `Some` if the cell has been previously
+ /// initialized, and `None` if it has not yet been initialized.
+ pub fn borrow(&self) -> Option<&T> {
+ match self.state.load(Ordering::Acquire) {
+ SOME => unsafe { &*self.inner.get() }.as_ref(),
+ _ => None,
+ }
+ }
+
+ /// Consumes this `LazyCell`, returning the underlying value.
+ pub fn into_inner(self) -> Option<T> {
+ unsafe { self.inner.into_inner() }
+ }
+}
+
+unsafe impl<T: Sync> Sync for AtomicLazyCell<T> { }
+unsafe impl<T: Send> Send for AtomicLazyCell<T> { }
+
+#[cfg(test)]
+mod tests {
+ use super::{LazyCell, AtomicLazyCell};
+
+ #[test]
+ fn test_borrow_from_empty() {
+ let lazycell: LazyCell<usize> = LazyCell::new();
+
+ let value = lazycell.borrow();
+ assert_eq!(value, None);
+ }
+
+ #[test]
+ fn test_fill_and_borrow() {
+ let lazycell = LazyCell::new();
+
+ assert!(!lazycell.filled());
+ lazycell.fill(1).unwrap();
+ assert!(lazycell.filled());
+
+ let value = lazycell.borrow();
+ assert_eq!(value, Some(&1));
+ }
+
+ #[test]
+ fn test_already_filled_error() {
+ let lazycell = LazyCell::new();
+
+ lazycell.fill(1).unwrap();
+ assert_eq!(lazycell.fill(1), Err(1));
+ }
+
+ #[test]
+ fn test_into_inner() {
+ let lazycell = LazyCell::new();
+
+ lazycell.fill(1).unwrap();
+ let value = lazycell.into_inner();
+ assert_eq!(value, Some(1));
+ }
+
+ #[test]
+ fn test_atomic_borrow_from_empty() {
+ let lazycell: AtomicLazyCell<usize> = AtomicLazyCell::new();
+
+ let value = lazycell.borrow();
+ assert_eq!(value, None);
+ }
+
+ #[test]
+ fn test_atomic_fill_and_borrow() {
+ let lazycell = AtomicLazyCell::new();
+
+ assert!(!lazycell.filled());
+ lazycell.fill(1).unwrap();
+ assert!(lazycell.filled());
+
+ let value = lazycell.borrow();
+ assert_eq!(value, Some(&1));
+ }
+
+ #[test]
+ fn test_atomic_already_filled_panic() {
+ let lazycell = AtomicLazyCell::new();
+
+ lazycell.fill(1).unwrap();
+ assert_eq!(1, lazycell.fill(1).unwrap_err());
+ }
+
+ #[test]
+ fn test_atomic_into_inner() {
+ let lazycell = AtomicLazyCell::new();
+
+ lazycell.fill(1).unwrap();
+ let value = lazycell.into_inner();
+ assert_eq!(value, Some(1));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/.appveyor.yml
@@ -0,0 +1,59 @@
+# Based on the "trust" template v0.1.1
+# https://github.com/japaric/trust/tree/v0.1.1
+
+environment:
+ global:
+ # TODO This is the Rust channel that build jobs will use by default but can be
+ # overridden on a case by case basis down below
+ RUST_VERSION: stable
+
+ # TODO These are all the build jobs. Adjust as necessary. Comment out what you
+ # don't need
+ matrix:
+ # MinGW
+ - TARGET: i686-pc-windows-gnu
+ - TARGET: x86_64-pc-windows-gnu
+
+ # MSVC
+ - TARGET: i686-pc-windows-msvc
+ - TARGET: x86_64-pc-windows-msvc
+
+ # Testing other channels
+ - TARGET: x86_64-pc-windows-gnu
+ RUST_VERSION: nightly
+ - TARGET: x86_64-pc-windows-msvc
+ RUST_VERSION: nightly
+
+install:
+ - ps: >-
+ If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') {
+ $Env:PATH += ';C:\msys64\mingw64\bin'
+ } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') {
+ $Env:PATH += ';C:\msys64\mingw32\bin'
+ }
+ - curl -sSf -o rustup-init.exe https://win.rustup.rs/
+ - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION%
+ - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
+ - rustc -Vv
+ - cargo -V
+
+# TODO This is the "test phase", tweak it as you see fit
+test_script:
+ # we don't run the "test phase" when doing deploys
+ - if [%APPVEYOR_REPO_TAG%]==[false] (
+ cargo build --target %TARGET% &&
+ cargo build --target %TARGET% --release &&
+ cargo test --target %TARGET% &&
+ cargo test --target %TARGET% --release
+ )
+
+cache:
+ - C:\Users\appveyor\.cargo\registry
+ - target
+
+notifications:
+ - provider: Email
+ on_build_success: false
+
+# disable automatic builds
+build: false
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".appveyor.yml":"715ca44917107f2a6a79163b7ea2a1faa5f06d6f6ec01d18e0279cca0b2c9da3",".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"888f10c4e7364e7a299a4d3460410a8271b02c425e78c320528e1ecdea872b72","Cargo.toml":"0471662940a928f6b0304f44c0a9fded42f53d99f0a5392e6908745d216e61c3","LICENSE-APACHE":"04ea4849dba9dcae07113850c6f1b1a69052c625210639914eee352023f750ad","LICENSE-MIT":"bd1d8f06a6ce1f7645991e347b95864b970eed43624305eb4bb78c09aef8692d","README.md":"f60620f4edcbdfc29d752fe08c1bea6867daeefcf256e9e5db085cd6be72d89e","ci/install.sh":"8b165fc99df296261fcc9cdcbc8b8a177c11c505cdc9255cc19efb66cb0055db","ci/script.sh":"ad444efa1c26fbe8133c5c67448224569bf25fc64c2b8d6c301ab0ca23b8fc38","examples/cat.rs":"ee76408175b7a96776da063e975bdae217656392b59f84ba06e6775f1b561e93","src/lib.rs":"6e57576f52492cfb874063e07dcd34dc862b7e4ba1daeea02222e3b79260965c","src/unix.rs":"93547aa35e051f08d3f14ad985f5845b86a51ccdc0dbda6964c167d5c60d75ae","src/windows.rs":"645eb0f85fa26cc5d6af7095e303dd8d777b7df928cbdeccaeb9f424659ea091"},"package":"46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/.travis.yml
@@ -0,0 +1,69 @@
+# Based on the "trust" template v0.1.1
+# https://github.com/japaric/trust/tree/v0.1.1
+
+dist: trusty
+language: rust
+services: docker
+sudo: required
+
+rust: nightly
+env: TARGET=x86_64-unknown-linux-gnu
+
+matrix:
+ # TODO These are all the build jobs. Adjust as necessary. Comment out what you
+ # don't need
+ include:
+ # Linux
+ - env: TARGET=i686-unknown-linux-gnu
+ - env: TARGET=i686-unknown-linux-musl
+ # - env: TARGET=x86_64-unknown-linux-gnu # this is the default job
+ - env: TARGET=x86_64-unknown-linux-musl
+
+ # OSX
+ - env: TARGET=i686-apple-darwin
+ os: osx
+ - env: TARGET=x86_64-apple-darwin
+ os: osx
+
+ # *BSD
+ - env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1
+ - env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1
+ - env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1
+
+ # Other architectures
+ - env: TARGET=aarch64-unknown-linux-gnu
+ - env: TARGET=armv7-unknown-linux-gnueabihf
+ - env: TARGET=mips-unknown-linux-gnu
+ - env: TARGET=mips64-unknown-linux-gnuabi64
+ - env: TARGET=mips64el-unknown-linux-gnuabi64
+ - env: TARGET=mipsel-unknown-linux-gnu
+ - env: TARGET=powerpc-unknown-linux-gnu
+ - env: TARGET=powerpc64-unknown-linux-gnu
+ - env: TARGET=powerpc64le-unknown-linux-gnu
+ - env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1
+
+ # Testing other channels
+ - env: TARGET=x86_64-unknown-linux-gnu
+ rust: 1.8.0
+ - env: TARGET=x86_64-unknown-linux-gnu
+ rust: stable
+
+before_install: set -e
+
+install:
+ - sh ci/install.sh
+ - source ~/.cargo/env || true
+
+script:
+ - bash ci/script.sh
+
+after_script: set +e
+
+cache: cargo
+before_cache:
+ # Travis can't cache files that are not readable by "others"
+ - chmod -R a+r $HOME/.cargo
+
+notifications:
+ email:
+ on_success: never
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "memmap"
+version = "0.5.2"
+authors = ["Dan Burkert <dan@danburkert.com>"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/danburkert/memmap-rs"
+documentation = "https://docs.rs/memmap"
+description = "Cross-platform Rust API for memory-mapped file IO"
+keywords = ["mmap", "memory-map", "io", "file"]
+
+[target.'cfg(unix)'.dependencies]
+libc = "0.2"
+
+[target.'cfg(windows)'.dependencies]
+winapi = "0.2"
+fs2 = "0.4"
+kernel32-sys = "0.2"
+
+[dev-dependencies]
+tempdir = "0.3"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [2015] [Dan Burkert]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2015 Dan Burkert
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/README.md
@@ -0,0 +1,53 @@
+# memmap
+
+A Rust library for cross-platform memory-mapped file IO. `memmap` requires Rust
+stable 1.8 or greater.
+
+[Documentation](https://docs.rs/memmap)
+
+[![Linux Status](https://travis-ci.org/danburkert/memmap-rs.svg?branch=master)](https://travis-ci.org/danburkert/memmap-rs)
+[![Build status](https://ci.appveyor.com/api/projects/status/ubka00959pstatkg/branch/master?svg=true)](https://ci.appveyor.com/project/danburkert/mmap)
+
+## Features
+
+- [x] file-backed memory maps
+- [x] anonymous memory maps
+- [x] synchronous and asynchronous flushing
+- [x] copy-on-write memory maps
+- [x] read-only memory maps
+- [x] stack support (`MAP_STACK` on unix)
+- [x] executable memory maps
+- [ ] huge page support
+
+## Platforms
+
+`memmap` should work on any platform supported by
+[`libc`](https://github.com/rust-lang-nursery/libc#platforms-and-documentation).
+
+`memmap` is continuously tested on:
+ * `x86_64-unknown-linux-gnu` (Linux)
+ * `i686-unknown-linux-gnu`
+ * `x86_64-unknown-linux-musl` (Linux MUSL)
+ * `x86_64-apple-darwin` (OSX)
+ * `i686-apple-darwin`
+ * `x86_64-pc-windows-msvc` (Windows)
+ * `i686-pc-windows-msvc`
+ * `x86_64-pc-windows-gnu`
+ * `i686-pc-windows-gnu`
+
+`memmap` is continuously cross-compile against:
+ * `arm-linux-androideabi` (Android)
+ * `aarch64-unknown-linux-gnu` (ARM)
+ * `arm-unknown-linux-gnueabihf`
+ * `mips-unknown-linux-gnu` (MIPS)
+ * `x86_64-apple-ios` (iOS)
+ * `i686-apple-ios`
+
+## License
+
+`memmap` is primarily distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details.
+
+Copyright (c) 2015 Dan Burkert.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/ci/install.sh
@@ -0,0 +1,31 @@
+set -ex
+
+main() {
+ curl https://sh.rustup.rs -sSf | \
+ sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
+
+ local target=
+ if [ $TRAVIS_OS_NAME = linux ]; then
+ target=x86_64-unknown-linux-gnu
+ sort=sort
+ else
+ target=x86_64-apple-darwin
+ sort=gsort # for `sort --sort-version`, from brew's coreutils.
+ fi
+
+ # This fetches latest stable release
+ local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
+ | cut -d/ -f3 \
+ | grep -E '^v[0-9.]+$' \
+ | $sort --version-sort \
+ | tail -n1)
+ echo cross version: $tag
+ curl -LSfs https://japaric.github.io/trust/install.sh | \
+ sh -s -- \
+ --force \
+ --git japaric/cross \
+ --tag $tag \
+ --target $target
+}
+
+main
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/ci/script.sh
@@ -0,0 +1,21 @@
+# This script takes care of testing your crate
+
+set -ex
+
+# TODO This is the "test phase", tweak it as you see fit
+main() {
+ cross build --target $TARGET
+ cross build --target $TARGET --release
+
+ if [ ! -z $DISABLE_TESTS ]; then
+ return
+ fi
+
+ cross test --target $TARGET
+ cross test --target $TARGET --release
+}
+
+# we don't run the "test phase" when doing deploys
+if [ -z $TRAVIS_TAG ]; then
+ main
+fi
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/examples/cat.rs
@@ -0,0 +1,16 @@
+extern crate memmap;
+
+use std::env;
+use std::io::{self, Write};
+
+use memmap::{Mmap, Protection};
+
+/// Output a file's contents to stdout. The file path must be provided as the first process
+/// argument.
+fn main() {
+ let path = env::args().nth(1).expect("supply a single path as the program argument");
+
+ let mmap = Mmap::open_path(path, Protection::Read).unwrap();
+
+ io::stdout().write_all(unsafe { mmap.as_slice() }).unwrap();
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/src/lib.rs
@@ -0,0 +1,933 @@
+//! A cross-platform Rust API for memory maps.
+
+#![deny(warnings)]
+
+#[cfg(windows)]
+mod windows;
+#[cfg(windows)]
+use windows::MmapInner;
+
+#[cfg(unix)]
+mod unix;
+#[cfg(unix)]
+use unix::MmapInner;
+
+use std::cell::UnsafeCell;
+use std::fmt;
+use std::fs::{self, File};
+use std::io::{Error, ErrorKind, Result};
+use std::path::Path;
+use std::rc::Rc;
+use std::slice;
+use std::sync::Arc;
+use std::usize;
+
+/// Memory map protection.
+///
+/// Determines how a memory map may be used. If the memory map is backed by a
+/// file, then the file must have permissions corresponding to the operations
+/// the protection level allows.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum Protection {
+
+ /// A read-only memory map. Writes to the memory map will result in a panic.
+ Read,
+
+ /// A read-write memory map. Writes to the memory map will be reflected in
+ /// the file after a call to `Mmap::flush` or after the `Mmap` is dropped.
+ ReadWrite,
+
+ /// A read, copy-on-write memory map. Writes to the memory map will not be
+ /// carried through to the underlying file. It is unspecified whether
+ /// changes made to the file after the memory map is created will be
+ /// visible.
+ ReadCopy,
+
+ /// A readable and executable mapping.
+ ReadExecute,
+}
+
+impl Protection {
+
+ fn as_open_options(self) -> fs::OpenOptions {
+ let mut options = fs::OpenOptions::new();
+ options.read(true)
+ .write(self.write());
+
+ options
+ }
+
+ /// Returns `true` if the `Protection` is writable.
+ pub fn write(self) -> bool {
+ match self {
+ Protection::ReadWrite | Protection::ReadCopy => true,
+ _ => false,
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
+pub struct MmapOptions {
+ /// Indicates that the memory map should be suitable for a stack.
+ ///
+ /// This option should only be used with anonymous memory maps.
+ pub stack: bool,
+}
+
+/// A memory-mapped buffer.
+///
+/// A file-backed `Mmap` buffer may be used to read or write data to a file. Use
+/// `Mmap::open(..)` to create a file-backed memory map. An anonymous `Mmap`
+/// buffer may be used any place that an in-memory byte buffer is needed, and
+/// gives the added features of a memory map. Use `Mmap::anonymous(..)` to
+/// create an anonymous memory map.
+///
+/// Changes written to a memory-mapped file are not guaranteed to be durable
+/// until the memory map is flushed, or it is dropped.
+///
+/// ```
+/// use std::io::Write;
+/// use memmap::{Mmap, Protection};
+///
+/// let file_mmap = Mmap::open_path("README.md", Protection::Read).unwrap();
+/// let bytes: &[u8] = unsafe { file_mmap.as_slice() };
+/// assert_eq!(b"# memmap", &bytes[0..8]);
+///
+/// let mut anon_mmap = Mmap::anonymous(4096, Protection::ReadWrite).unwrap();
+/// unsafe { anon_mmap.as_mut_slice() }.write(b"foo").unwrap();
+/// assert_eq!(b"foo\0\0", unsafe { &anon_mmap.as_slice()[0..5] });
+/// ```
+pub struct Mmap {
+ inner: MmapInner
+}
+
+impl Mmap {
+
+ /// Opens a file-backed memory map.
+ ///
+ /// The file must be opened with read permissions, and write permissions if
+ /// the supplied protection is `ReadWrite`. The file must not be empty.
+ pub fn open(file: &File, prot: Protection) -> Result<Mmap> {
+ let len = try!(file.metadata()).len();
+ if len > usize::MAX as u64 {
+ return Err(Error::new(ErrorKind::InvalidData,
+ "file length overflows usize"));
+ }
+ MmapInner::open(file, prot, 0, len as usize).map(|inner| Mmap { inner: inner })
+ }
+
+ /// Opens a file-backed memory map.
+ ///
+ /// The file must not be empty.
+ pub fn open_path<P>(path: P, prot: Protection) -> Result<Mmap>
+ where P: AsRef<Path> {
+ let file = try!(prot.as_open_options().open(path));
+ let len = try!(file.metadata()).len();
+ if len > usize::MAX as u64 {
+ return Err(Error::new(ErrorKind::InvalidData,
+ "file length overflows usize"));
+ }
+ MmapInner::open(&file, prot, 0, len as usize).map(|inner| Mmap { inner: inner })
+ }
+
+ /// Opens a file-backed memory map with the specified offset and length.
+ ///
+ /// The file must be opened with read permissions, and write permissions if
+ /// the supplied protection is `ReadWrite`. The file must not be empty. The
+ /// length must be greater than zero.
+ pub fn open_with_offset(file: &File,
+ prot: Protection,
+ offset: usize,
+ len: usize) -> Result<Mmap> {
+ MmapInner::open(file, prot, offset, len).map(|inner| Mmap { inner: inner })
+ }
+
+ /// Opens an anonymous memory map.
+ ///
+ /// The length must be greater than zero.
+ pub fn anonymous(len: usize, prot: Protection) -> Result<Mmap> {
+ Mmap::anonymous_with_options(len, prot, Default::default())
+ }
+
+ /// Opens an anonymous memory map with the provided options.
+ ///
+ /// The length must be greater than zero.
+ pub fn anonymous_with_options(len: usize,
+ prot: Protection,
+ options: MmapOptions) -> Result<Mmap> {
+ MmapInner::anonymous(len, prot, options).map(|inner| Mmap { inner: inner })
+ }
+
+ /// Flushes outstanding memory map modifications to disk.
+ ///
+ /// When this returns with a non-error result, all outstanding changes to a
+ /// file-backed memory map are guaranteed to be durably stored. The file's
+ /// metadata (including last modification timestamp) may not be updated.
+ pub fn flush(&self) -> Result<()> {
+ let len = self.len();
+ self.inner.flush(0, len)
+ }
+
+ /// Asynchronously flushes outstanding memory map modifications to disk.
+ ///
+ /// This method initiates flushing modified pages to durable storage, but it
+ /// will not wait for the operation to complete before returning. The file's
+ /// metadata (including last modification timestamp) may not be updated.
+ pub fn flush_async(&self) -> Result<()> {
+ let len = self.len();
+ self.inner.flush_async(0, len)
+ }
+
+ /// Flushes outstanding memory map modifications in the range to disk.
+ ///
+ /// The offset and length must be in the bounds of the mmap.
+ ///
+ /// When this returns with a non-error result, all outstanding changes to a
+ /// file-backed memory in the range are guaranteed to be durable stored. The
+ /// file's metadata (including last modification timestamp) may not be
+ /// updated. It is not guaranteed the only the changes in the specified
+ /// range are flushed; other outstanding changes to the mmap may be flushed
+ /// as well.
+ pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> {
+ self.inner.flush(offset, len)
+ }
+
+ /// Asynchronously flushes outstanding memory map modifications in the range
+ /// to disk.
+ ///
+ /// The offset and length must be in the bounds of the mmap.
+ ///
+ /// This method initiates flushing modified pages to durable storage, but it
+ /// will not wait for the operation to complete before returning. The file's
+ /// metadata (including last modification timestamp) may not be updated. It
+ /// is not guaranteed that the only changes flushed are those in the
+ /// specified range; other outstanding changes to the mmap may be flushed as
+ /// well.
+ pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> {
+ self.inner.flush_async(offset, len)
+ }
+
+ /// Change the `Protection` this mapping was created with.
+ ///
+ /// If you create a read-only file-backed mapping, you can **not** use this method to make the
+ /// mapping writeable. Remap the file instead.
+ pub fn set_protection(&mut self, prot: Protection) -> Result<()> {
+ self.inner.set_protection(prot)
+ }
+
+ /// Returns the length of the memory map.
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ /// Returns a pointer to the mapped memory.
+ ///
+ /// See `Mmap::as_slice` for invariants that must hold when dereferencing
+ /// the pointer.
+ pub fn ptr(&self) -> *const u8 {
+ self.inner.ptr()
+ }
+
+ /// Returns a pointer to the mapped memory.
+ ///
+ /// See `Mmap::as_mut_slice` for invariants that must hold when
+ /// dereferencing the pointer.
+ pub fn mut_ptr(&mut self) -> *mut u8 {
+ self.inner.mut_ptr()
+ }
+
+ /// Returns the memory mapped file as an immutable slice.
+ ///
+ /// ## Unsafety
+ ///
+ /// The caller must ensure that the file is not concurrently modified.
+ pub unsafe fn as_slice(&self) -> &[u8] {
+ slice::from_raw_parts(self.ptr(), self.len())
+ }
+
+ /// Returns the memory mapped file as a mutable slice.
+ ///
+ /// ## Unsafety
+ ///
+ /// The caller must ensure that the file is not concurrently accessed.
+ pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
+ slice::from_raw_parts_mut(self.mut_ptr(), self.len())
+ }
+
+ /// Creates a splittable mmap view from the mmap.
+ pub fn into_view(self) -> MmapView {
+ let len = self.len();
+ MmapView { inner: Rc::new(UnsafeCell::new(self)),
+ offset: 0,
+ len: len }
+ }
+
+ /// Creates a thread-safe splittable mmap view from the mmap.
+ pub fn into_view_sync(self) -> MmapViewSync {
+ let len = self.len();
+ MmapViewSync { inner: Arc::new(UnsafeCell::new(self)),
+ offset: 0,
+ len: len }
+ }
+}
+
+impl fmt::Debug for Mmap {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Mmap {{ ptr: {:?}, len: {} }}", self.ptr(), self.len())
+ }
+}
+
+/// A view of a memory map.
+///
+/// The view may be split into disjoint ranges, each of which will share the
+/// underlying memory map.
+pub struct MmapView {
+ inner: Rc<UnsafeCell<Mmap>>,
+ offset: usize,
+ len: usize,
+}
+
+impl MmapView {
+
+ /// Split the view into disjoint pieces at the specified offset.
+ ///
+ /// The provided offset must be less than the view's length.
+ pub fn split_at(self, offset: usize) -> Result<(MmapView, MmapView)> {
+ if self.len < offset {
+ return Err(Error::new(ErrorKind::InvalidInput,
+ "mmap view split offset must be less than the view length"));
+ }
+ let MmapView { inner, offset: self_offset, len: self_len } = self;
+ Ok((MmapView { inner: inner.clone(),
+ offset: self_offset,
+ len: offset },
+ MmapView { inner: inner,
+ offset: self_offset + offset,
+ len: self_len - offset }))
+ }
+
+ /// Restricts the range of the view to the provided offset and length.
+ ///
+ /// The provided range must be a subset of the current range
+ /// (`offset + len < view.len()`).
+ pub fn restrict(&mut self, offset: usize, len: usize) -> Result<()> {
+ if offset + len > self.len {
+ return Err(Error::new(ErrorKind::InvalidInput,
+ "mmap view may only be restricted to a subrange \
+ of the current view"));
+ }
+ self.offset = self.offset + offset;
+ self.len = len;
+ Ok(())
+ }
+
+ /// Get a reference to the inner mmap.
+ ///
+ /// The caller must ensure that memory outside the `offset`/`len` range is
+ /// not accessed.
+ fn inner(&self) -> &Mmap {
+ unsafe {
+ &*self.inner.get()
+ }
+ }
+
+ /// Get a mutable reference to the inner mmap.
+ ///
+ /// The caller must ensure that memory outside the `offset`/`len` range is
+ /// not accessed.
+ fn inner_mut(&self) -> &mut Mmap {
+ unsafe {
+ &mut *self.inner.get()
+ }
+ }
+
+ /// Flushes outstanding view modifications to disk.
+ ///
+ /// When this returns with a non-error result, all outstanding changes to a
+ /// file-backed memory map view are guaranteed to be durably stored. The
+ /// file's metadata (including last modification timestamp) may not be
+ /// updated.
+ pub fn flush(&self) -> Result<()> {
+ self.inner_mut().flush_range(self.offset, self.len)
+ }
+
+ /// Asynchronously flushes outstanding memory map view modifications to
+ /// disk.
+ ///
+ /// This method initiates flushing modified pages to durable storage, but it
+ /// will not wait for the operation to complete before returning. The file's
+ /// metadata (including last modification timestamp) may not be updated.
+ pub fn flush_async(&self) -> Result<()> {
+ self.inner_mut().flush_async_range(self.offset, self.len)
+ }
+
+ /// Returns the length of the memory map view.
+ pub fn len(&self) -> usize {
+ self.len
+ }
+
+ /// Returns a shared pointer to the mapped memory.
+ ///
+ /// See `Mmap::as_slice` for invariants that must hold when dereferencing
+ /// the pointer.
+ pub fn ptr(&self) -> *const u8 {
+ unsafe { self.inner().ptr().offset(self.offset as isize) }
+ }
+
+ /// Returns a mutable pointer to the mapped memory.
+ ///
+ /// See `Mmap::as_mut_slice` for invariants that must hold when
+ /// dereferencing the pointer.
+ pub fn mut_ptr(&mut self) -> *mut u8 {
+ unsafe { self.inner_mut().mut_ptr().offset(self.offset as isize) }
+ }
+
+ /// Returns the memory mapped file as an immutable slice.
+ ///
+ /// ## Unsafety
+ ///
+ /// The caller must ensure that the file is not concurrently modified.
+ pub unsafe fn as_slice(&self) -> &[u8] {
+ &self.inner().as_slice()[self.offset..self.offset + self.len]
+ }
+
+ /// Returns the memory mapped file as a mutable slice.
+ ///
+ /// ## Unsafety
+ ///
+ /// The caller must ensure that the file is not concurrently accessed.
+ pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
+ &mut self.inner_mut().as_mut_slice()[self.offset..self.offset + self.len]
+ }
+
+ /// Clones the view of the memory map.
+ ///
+ /// The underlying memory map is shared, and thus the caller must ensure that the memory
+ /// underlying the view is not illegally aliased.
+ pub unsafe fn clone(&self) -> MmapView {
+ MmapView {
+ inner: self.inner.clone(),
+ offset: self.offset,
+ len: self.len,
+ }
+ }
+}
+
+impl fmt::Debug for MmapView {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "MmapView {{ ptr: {:?}, offset: {}, len: {} }}",
+ self.inner().ptr(), self.offset, self.len)
+ }
+}
+
+/// A thread-safe view of a memory map.
+///
+/// The view may be split into disjoint ranges, each of which will share the
+/// underlying memory map.
+pub struct MmapViewSync {
+ inner: Arc<UnsafeCell<Mmap>>,
+ offset: usize,
+ len: usize,
+}
+
+impl MmapViewSync {
+
+ /// Split the view into disjoint pieces at the specified offset.
+ ///
+ /// The provided offset must be less than the view's length.
+ pub fn split_at(self, offset: usize) -> Result<(MmapViewSync, MmapViewSync)> {
+ if self.len < offset {
+ return Err(Error::new(ErrorKind::InvalidInput,
+ "mmap view split offset must be less than the view length"));
+ }
+ let MmapViewSync { inner, offset: self_offset, len: self_len } = self;
+ Ok((MmapViewSync { inner: inner.clone(),
+ offset: self_offset,
+ len: offset },
+ MmapViewSync { inner: inner,
+ offset: self_offset + offset,
+ len: self_len - offset }))
+ }
+
+ /// Restricts the range of this view to the provided offset and length.
+ ///
+ /// The provided range must be a subset of the current range (`offset + len < view.len()`).
+ pub fn restrict(&mut self, offset: usize, len: usize) -> Result<()> {
+ if offset + len > self.len {
+ return Err(Error::new(ErrorKind::InvalidInput,
+ "mmap view may only be restricted to a subrange \
+ of the current view"));
+ }
+ self.offset = self.offset + offset;
+ self.len = len;
+ Ok(())
+ }
+
+ /// Get a reference to the inner mmap.
+ ///
+ /// The caller must ensure that memory outside the `offset`/`len` range is not accessed.
+ fn inner(&self) -> &Mmap {
+ unsafe {
+ &*self.inner.get()
+ }
+ }
+
+ /// Get a mutable reference to the inner mmap.
+ ///
+ /// The caller must ensure that memory outside the `offset`/`len` range is not accessed.
+ fn inner_mut(&self) -> &mut Mmap {
+ unsafe {
+ &mut *self.inner.get()
+ }
+ }
+
+ /// Flushes outstanding view modifications to disk.
+ ///
+ /// When this returns with a non-error result, all outstanding changes to a file-backed memory
+ /// map view are guaranteed to be durably stored. The file's metadata (including last
+ /// modification timestamp) may not be updated.
+ pub fn flush(&self) -> Result<()> {
+ self.inner_mut().flush_range(self.offset, self.len)
+ }
+
+ /// Asynchronously flushes outstanding memory map view modifications to disk.
+ ///
+ /// This method initiates flushing modified pages to durable storage, but it will not wait
+ /// for the operation to complete before returning. The file's metadata (including last
+ /// modification timestamp) may not be updated.
+ pub fn flush_async(&self) -> Result<()> {
+ self.inner_mut().flush_async_range(self.offset, self.len)
+ }
+
+ /// Returns the length of the memory map view.
+ pub fn len(&self) -> usize {
+ self.len
+ }
+
+ /// Returns a shared pointer to the mapped memory.
+ ///
+ /// See `Mmap::as_slice` for invariants that must hold when dereferencing the pointer.
+ pub fn ptr(&self) -> *const u8 {
+ unsafe { self.inner().ptr().offset(self.offset as isize) }
+ }
+
+ /// Returns a mutable pointer to the mapped memory.
+ ///
+ /// See `Mmap::as_mut_slice` for invariants that must hold when dereferencing the pointer.
+ pub fn mut_ptr(&mut self) -> *mut u8 {
+ unsafe { self.inner_mut().mut_ptr().offset(self.offset as isize) }
+ }
+
+ /// Returns the memory mapped file as an immutable slice.
+ ///
+ /// ## Unsafety
+ ///
+ /// The caller must ensure that the file is not concurrently modified.
+ pub unsafe fn as_slice(&self) -> &[u8] {
+ &self.inner().as_slice()[self.offset..self.offset + self.len]
+ }
+
+ /// Returns the memory mapped file as a mutable slice.
+ ///
+ /// ## Unsafety
+ ///
+ /// The caller must ensure that the file is not concurrently accessed.
+ pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
+ &mut self.inner_mut().as_mut_slice()[self.offset..self.offset + self.len]
+ }
+
+ /// Clones the view of the memory map.
+ ///
+ /// The underlying memory map is shared, and thus the caller must ensure that the memory
+ /// underlying the view is not illegally aliased.
+ pub unsafe fn clone(&self) -> MmapViewSync {
+ MmapViewSync {
+ inner: self.inner.clone(),
+ offset: self.offset,
+ len: self.len,
+ }
+ }
+}
+
+impl fmt::Debug for MmapViewSync {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "MmapViewSync {{ ptr: {:?}, offset: {}, len: {} }}",
+ self.inner().ptr(), self.offset, self.len)
+ }
+}
+
+unsafe impl Sync for MmapViewSync {}
+unsafe impl Send for MmapViewSync {}
+
+#[cfg(test)]
+mod test {
+ extern crate tempdir;
+
+ use std::{fs, iter};
+ use std::io::{Read, Write};
+ use std::thread;
+ use std::sync::Arc;
+ use std::ptr;
+
+ use super::*;
+
+ #[test]
+ fn map_file() {
+ let expected_len = 128;
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ fs::OpenOptions::new()
+ .write(true)
+ .create(true)
+ .open(&path).unwrap()
+ .set_len(expected_len as u64).unwrap();
+
+ let mut mmap = Mmap::open_path(path, Protection::ReadWrite).unwrap();
+ let len = mmap.len();
+ assert_eq!(expected_len, len);
+
+ let zeros = iter::repeat(0).take(len).collect::<Vec<_>>();
+ let incr = (0..len).map(|n| n as u8).collect::<Vec<_>>();
+
+ // check that the mmap is empty
+ assert_eq!(&zeros[..], unsafe { mmap.as_slice() });
+
+ // write values into the mmap
+ unsafe { mmap.as_mut_slice() }.write_all(&incr[..]).unwrap();
+
+ // read values back
+ assert_eq!(&incr[..], unsafe { mmap.as_slice() });
+ }
+
+ /// Checks that a 0-length file will not be mapped.
+ #[test]
+ fn map_empty_file() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ fs::OpenOptions::new()
+ .write(true)
+ .create(true)
+ .open(&path).unwrap();
+
+ assert!(Mmap::open_path(path, Protection::ReadWrite).is_err());
+ }
+
+ #[test]
+ fn map_anon() {
+ let expected_len = 128;
+ let mut mmap = Mmap::anonymous(expected_len, Protection::ReadWrite).unwrap();
+ let len = mmap.len();
+ assert_eq!(expected_len, len);
+
+ let zeros = iter::repeat(0).take(len).collect::<Vec<_>>();
+ let incr = (0..len).map(|n| n as u8).collect::<Vec<_>>();
+
+ // check that the mmap is empty
+ assert_eq!(&zeros[..], unsafe { mmap.as_slice() });
+
+ // write values into the mmap
+ unsafe { mmap.as_mut_slice() }.write_all(&incr[..]).unwrap();
+
+ // read values back
+ assert_eq!(&incr[..], unsafe { mmap.as_slice() });
+ }
+
+ #[test]
+ fn file_write() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let mut file = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path).unwrap();
+ file.set_len(128).unwrap();
+
+ let write = b"abc123";
+ let mut read = [0u8; 6];
+
+ let mut mmap = Mmap::open_path(&path, Protection::ReadWrite).unwrap();
+ unsafe { mmap.as_mut_slice() }.write_all(write).unwrap();
+ mmap.flush().unwrap();
+
+ file.read(&mut read).unwrap();
+ assert_eq!(write, &read);
+ }
+
+ #[test]
+ fn flush_range() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let file = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path).unwrap();
+ file.set_len(128).unwrap();
+ let write = b"abc123";
+
+ let mut mmap = Mmap::open_with_offset(&file, Protection::ReadWrite, 2, write.len()).unwrap();
+ unsafe { mmap.as_mut_slice() }.write_all(write).unwrap();
+ mmap.flush_range(0, write.len()).unwrap();
+ }
+
+ #[test]
+ fn map_copy() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let mut file = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path).unwrap();
+ file.set_len(128).unwrap();
+
+ let nulls = b"\0\0\0\0\0\0";
+ let write = b"abc123";
+ let mut read = [0u8; 6];
+
+ let mut mmap = Mmap::open_path(&path, Protection::ReadCopy).unwrap();
+ unsafe { mmap.as_mut_slice() }.write(write).unwrap();
+ mmap.flush().unwrap();
+
+ // The mmap contains the write
+ unsafe { mmap.as_slice() }.read(&mut read).unwrap();
+ assert_eq!(write, &read);
+
+ // The file does not contain the write
+ file.read(&mut read).unwrap();
+ assert_eq!(nulls, &read);
+
+ // another mmap does not contain the write
+ let mmap2 = Mmap::open_path(&path, Protection::Read).unwrap();
+ unsafe { mmap2.as_slice() }.read(&mut read).unwrap();
+ assert_eq!(nulls, &read);
+ }
+
+ #[test]
+ fn map_offset() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let file = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+
+ file.set_len(500000 as u64).unwrap();
+
+ let offset = 5099;
+ let len = 50050;
+
+ let mut mmap = Mmap::open_with_offset(&file,
+ Protection::ReadWrite,
+ offset,
+ len).unwrap();
+ assert_eq!(len, mmap.len());
+
+ let zeros = iter::repeat(0).take(len).collect::<Vec<_>>();
+ let incr = (0..len).map(|n| n as u8).collect::<Vec<_>>();
+
+ // check that the mmap is empty
+ assert_eq!(&zeros[..], unsafe { mmap.as_slice() });
+
+ // write values into the mmap
+ unsafe { mmap.as_mut_slice() }.write_all(&incr[..]).unwrap();
+
+ // read values back
+ assert_eq!(&incr[..], unsafe { mmap.as_slice() });
+ }
+
+ #[test]
+ fn index() {
+ let mut mmap = Mmap::anonymous(128, Protection::ReadWrite).unwrap();
+ unsafe { mmap.as_mut_slice()[0] = 42 };
+ assert_eq!(42, unsafe { mmap.as_slice()[0] });
+ }
+
+ #[test]
+ fn sync_send() {
+ let mmap = Arc::new(Mmap::anonymous(128, Protection::ReadWrite).unwrap());
+ thread::spawn(move || {
+ unsafe {
+ mmap.as_slice();
+ }
+ });
+ }
+
+ #[test]
+ fn view() {
+ let len = 128;
+ let split = 32;
+ let mut view = Mmap::anonymous(len, Protection::ReadWrite).unwrap().into_view();
+ let incr = (0..len).map(|n| n as u8).collect::<Vec<_>>();
+ // write values into the view
+ unsafe { view.as_mut_slice() }.write_all(&incr[..]).unwrap();
+
+ let (mut view1, view2) = view.split_at(32).unwrap();
+ assert_eq!(view1.len(), split);
+ assert_eq!(view2.len(), len - split);
+
+ assert_eq!(&incr[0..split], unsafe { view1.as_slice() });
+ assert_eq!(&incr[split..], unsafe { view2.as_slice() });
+
+ view1.restrict(10, 10).unwrap();
+ assert_eq!(&incr[10..20], unsafe { view1.as_slice() })
+ }
+
+ #[test]
+ fn view_sync() {
+ let len = 128;
+ let split = 32;
+ let mut view = Mmap::anonymous(len, Protection::ReadWrite).unwrap().into_view_sync();
+ let incr = (0..len).map(|n| n as u8).collect::<Vec<_>>();
+ // write values into the view
+ unsafe { view.as_mut_slice() }.write_all(&incr[..]).unwrap();
+
+ let (mut view1, view2) = view.split_at(32).unwrap();
+ assert_eq!(view1.len(), split);
+ assert_eq!(view2.len(), len - split);
+
+ assert_eq!(&incr[0..split], unsafe { view1.as_slice() });
+ assert_eq!(&incr[split..], unsafe { view2.as_slice() });
+
+ view1.restrict(10, 10).unwrap();
+ assert_eq!(&incr[10..20], unsafe { view1.as_slice() })
+ }
+
+ #[test]
+ fn view_write() {
+ let len = 131072; // 256KiB
+ let split = 66560; // 65KiB + 10B
+
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let mut file = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path).unwrap();
+ file.set_len(len).unwrap();
+
+ let incr = (0..len).map(|n| n as u8).collect::<Vec<_>>();
+ let incr1 = incr[0..split].to_owned();
+ let incr2 = incr[split..].to_owned();
+
+ let (mut view1, mut view2) = Mmap::open_path(&path, Protection::ReadWrite)
+ .unwrap()
+ .into_view_sync()
+ .split_at(split)
+ .unwrap();
+
+
+ let join1 = thread::spawn(move || {
+ unsafe { view1.as_mut_slice() }.write(&incr1).unwrap();
+ view1.flush().unwrap();
+ });
+
+ let join2 = thread::spawn(move || {
+ unsafe { view2.as_mut_slice() }.write(&incr2).unwrap();
+ view2.flush().unwrap();
+ });
+
+ join1.join().unwrap();
+ join2.join().unwrap();
+
+ let mut buf = Vec::new();
+ file.read_to_end(&mut buf).unwrap();
+ assert_eq!(incr, &buf[..]);
+ }
+
+ #[test]
+ fn view_sync_send() {
+ let view = Arc::new(Mmap::anonymous(128, Protection::ReadWrite).unwrap().into_view_sync());
+ thread::spawn(move || {
+ unsafe {
+ view.as_slice();
+ }
+ });
+ }
+
+ #[test]
+ fn set_prot() {
+ let mut map = Mmap::anonymous(1, Protection::Read).unwrap();
+ map.set_protection(Protection::ReadWrite).unwrap();
+
+ // We should now be able to write to the memory. If not this will cause a SIGSEGV.
+ unsafe { ptr::write(map.mut_ptr(), 0xf1); }
+
+ map.set_protection(Protection::Read).unwrap();
+
+ assert_eq!(unsafe { ptr::read(map.mut_ptr()) }, 0xf1);
+ }
+
+ #[test]
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ fn jit_x86() {
+ use std::mem;
+
+ let mut map = Mmap::anonymous(4096, Protection::ReadWrite).unwrap();
+
+ {
+ let mut jitmem = unsafe { map.as_mut_slice() };
+ jitmem[0] = 0xB8; // mov eax, 0xAB
+ jitmem[1] = 0xAB;
+ jitmem[2] = 0x00;
+ jitmem[3] = 0x00;
+ jitmem[4] = 0x00;
+ jitmem[5] = 0xC3; // ret
+ }
+
+ map.set_protection(Protection::ReadExecute).unwrap();
+
+ let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(map.mut_ptr()) };
+ assert_eq!(jitfn(), 0xab);
+ }
+
+ #[test]
+ fn offset_set_protection() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let file = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+
+ file.set_len(500000 as u64).unwrap();
+
+ let offset = 5099;
+ let len = 50050;
+
+ let mut mmap = Mmap::open_with_offset(&file,
+ Protection::ReadWrite,
+ offset,
+ len).unwrap();
+ assert_eq!(len, mmap.len());
+
+ let zeros = iter::repeat(0).take(len).collect::<Vec<_>>();
+ let incr = (0..len).map(|n| n as u8).collect::<Vec<_>>();
+
+ // check that the mmap is empty
+ assert_eq!(&zeros[..], unsafe { mmap.as_slice() });
+
+ // write values into the mmap
+ unsafe { mmap.as_mut_slice() }.write_all(&incr[..]).unwrap();
+
+ // change to read-only protection
+ mmap.set_protection(Protection::Read).unwrap();
+
+ // read values back
+ assert_eq!(&incr[..], unsafe { mmap.as_slice() });
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/src/unix.rs
@@ -0,0 +1,182 @@
+extern crate libc;
+
+use std::{io, ptr};
+use std::fs::File;
+use std::os::unix::io::AsRawFd;
+
+use ::Protection;
+use ::MmapOptions;
+
+impl Protection {
+
+ /// Returns the `Protection` value as a POSIX protection flag.
+ fn as_prot(self) -> libc::c_int {
+ match self {
+ Protection::Read => libc::PROT_READ,
+ Protection::ReadWrite => libc::PROT_READ | libc::PROT_WRITE,
+ Protection::ReadCopy => libc::PROT_READ | libc::PROT_WRITE,
+ Protection::ReadExecute => libc::PROT_READ | libc::PROT_EXEC,
+ }
+ }
+
+ fn as_flag(self) -> libc::c_int {
+ match self {
+ Protection::Read => libc::MAP_SHARED,
+ Protection::ReadWrite => libc::MAP_SHARED,
+ Protection::ReadCopy => libc::MAP_PRIVATE,
+ Protection::ReadExecute => libc::MAP_SHARED,
+ }
+ }
+}
+
+#[cfg(any(all(target_os = "linux", not(target_arch="mips")),
+ target_os = "freebsd",
+ target_os = "android"))]
+const MAP_STACK: libc::c_int = libc::MAP_STACK;
+
+#[cfg(not(any(all(target_os = "linux", not(target_arch="mips")),
+ target_os = "freebsd",
+ target_os = "android")))]
+const MAP_STACK: libc::c_int = 0;
+
+impl MmapOptions {
+ fn as_flag(self) -> libc::c_int {
+ let mut flag = 0;
+ if self.stack { flag |= MAP_STACK }
+ flag
+ }
+}
+
+pub struct MmapInner {
+ ptr: *mut libc::c_void,
+ len: usize,
+}
+
+impl MmapInner {
+
+ pub fn open(file: &File, prot: Protection, offset: usize, len: usize) -> io::Result<MmapInner> {
+ let alignment = offset % page_size();
+ let aligned_offset = offset - alignment;
+ let aligned_len = len + alignment;
+ if aligned_len == 0 {
+ // Normally the OS would catch this, but it segfaults under QEMU.
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "memory map must have a non-zero length"));
+ }
+
+ unsafe {
+ let ptr = libc::mmap(ptr::null_mut(),
+ aligned_len as libc::size_t,
+ prot.as_prot(),
+ prot.as_flag(),
+ file.as_raw_fd(),
+ aligned_offset as libc::off_t);
+
+ if ptr == libc::MAP_FAILED {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(MmapInner {
+ ptr: ptr.offset(alignment as isize),
+ len: len,
+ })
+ }
+ }
+ }
+
+ /// Open an anonymous memory map.
+ pub fn anonymous(len: usize, prot: Protection, options: MmapOptions) -> io::Result<MmapInner> {
+ let ptr = unsafe {
+ libc::mmap(ptr::null_mut(),
+ len as libc::size_t,
+ prot.as_prot(),
+ options.as_flag() | prot.as_flag() | libc::MAP_ANON,
+ -1,
+ 0)
+ };
+
+ if ptr == libc::MAP_FAILED {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(MmapInner {
+ ptr: ptr,
+ len: len as usize,
+ })
+ }
+ }
+
+ pub fn flush(&self, offset: usize, len: usize) -> io::Result<()> {
+ let alignment = (self.ptr as usize + offset) % page_size();
+ let offset = offset as isize - alignment as isize;
+ let len = len + alignment;
+ let result = unsafe { libc::msync(self.ptr.offset(offset),
+ len as libc::size_t,
+ libc::MS_SYNC) };
+ if result == 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ pub fn flush_async(&self, offset: usize, len: usize) -> io::Result<()> {
+ let alignment = offset % page_size();
+ let aligned_offset = offset - alignment;
+ let aligned_len = len + alignment;
+ let result = unsafe { libc::msync(self.ptr.offset(aligned_offset as isize),
+ aligned_len as libc::size_t,
+ libc::MS_ASYNC) };
+ if result == 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ pub fn set_protection(&mut self, prot: Protection) -> io::Result<()> {
+ unsafe {
+ let alignment = self.ptr as usize % page_size();
+ let ptr = self.ptr.offset(- (alignment as isize));
+ let len = self.len + alignment;
+ let result = libc::mprotect(ptr,
+ len,
+ prot.as_prot());
+ if result == 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+
+ pub fn ptr(&self) -> *const u8 {
+ self.ptr as *const u8
+ }
+
+ pub fn mut_ptr(&mut self) -> *mut u8 {
+ self.ptr as *mut u8
+ }
+
+ pub fn len(&self) -> usize {
+ self.len
+ }
+}
+
+impl Drop for MmapInner {
+ fn drop(&mut self) {
+ let alignment = self.ptr as usize % page_size();
+ unsafe {
+ assert!(libc::munmap(self.ptr.offset(- (alignment as isize)),
+ (self.len + alignment) as libc::size_t) == 0,
+ "unable to unmap mmap: {}", io::Error::last_os_error());
+ }
+ }
+}
+
+unsafe impl Sync for MmapInner { }
+unsafe impl Send for MmapInner { }
+
+fn page_size() -> usize {
+ unsafe {
+ libc::sysconf(libc::_SC_PAGESIZE) as usize
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/memmap/src/windows.rs
@@ -0,0 +1,194 @@
+extern crate fs2;
+extern crate kernel32;
+extern crate winapi;
+
+use std::{io, mem, ptr};
+use std::fs::File;
+use std::os::raw::c_void;
+use std::os::windows::io::AsRawHandle;
+
+use self::fs2::FileExt;
+
+use ::Protection;
+use ::MmapOptions;
+
+impl Protection {
+
+ /// Returns the `Protection` as a flag appropriate for a call to `CreateFileMapping`.
+ fn as_mapping_flag(self) -> winapi::DWORD {
+ match self {
+ Protection::Read => winapi::PAGE_READONLY,
+ Protection::ReadWrite => winapi::PAGE_READWRITE,
+ Protection::ReadCopy => winapi::PAGE_READONLY,
+ Protection::ReadExecute => winapi::PAGE_EXECUTE_READ,
+ }
+ }
+
+ /// Returns the `Protection` as a flag appropriate for a call to `MapViewOfFile`.
+ fn as_view_flag(self) -> winapi::DWORD {
+ match self {
+ Protection::Read => winapi::FILE_MAP_READ,
+ Protection::ReadWrite => winapi::FILE_MAP_ALL_ACCESS,
+ Protection::ReadCopy => winapi::FILE_MAP_COPY,
+ Protection::ReadExecute => winapi::FILE_MAP_READ | winapi::FILE_MAP_EXECUTE,
+ }
+ }
+}
+
+pub struct MmapInner {
+ file: Option<File>,
+ ptr: *mut c_void,
+ len: usize,
+}
+
+impl MmapInner {
+
+ pub fn open(file: &File, prot: Protection, offset: usize, len: usize) -> io::Result<MmapInner> {
+ let alignment = offset % allocation_granularity();
+ let aligned_offset = offset - alignment;
+ let aligned_len = len + alignment;
+
+ unsafe {
+ let handle = kernel32::CreateFileMappingW(file.as_raw_handle(),
+ ptr::null_mut(),
+ prot.as_mapping_flag(),
+ 0,
+ 0,
+ ptr::null());
+ if handle == ptr::null_mut() {
+ return Err(io::Error::last_os_error());
+ }
+
+ let ptr = kernel32::MapViewOfFile(handle,
+ prot.as_view_flag(),
+ (aligned_offset >> 16 >> 16) as winapi::DWORD,
+ (aligned_offset & 0xffffffff) as winapi::DWORD,
+ aligned_len as winapi::SIZE_T);
+ kernel32::CloseHandle(handle);
+
+ if ptr == ptr::null_mut() {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(MmapInner {
+ file: Some(try!(file.duplicate())),
+ ptr: ptr.offset(alignment as isize),
+ len: len as usize,
+ })
+ }
+ }
+ }
+
+ pub fn anonymous(len: usize, prot: Protection, _options: MmapOptions) -> io::Result<MmapInner> {
+ unsafe {
+ // Create a mapping and view with maximum access permissions, then use `VirtualProtect`
+ // to set the actual `Protection`. This way, we can set more permissive protection later
+ // on.
+ // Also see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366537.aspx
+
+ let handle = kernel32::CreateFileMappingW(winapi::INVALID_HANDLE_VALUE,
+ ptr::null_mut(),
+ winapi::PAGE_EXECUTE_READWRITE,
+ (len >> 16 >> 16) as winapi::DWORD,
+ (len & 0xffffffff) as winapi::DWORD,
+ ptr::null());
+ if handle == ptr::null_mut() {
+ return Err(io::Error::last_os_error());
+ }
+ let access = winapi::FILE_MAP_ALL_ACCESS | winapi::FILE_MAP_EXECUTE;
+ let ptr = kernel32::MapViewOfFile(handle,
+ access,
+ 0,
+ 0,
+ len as winapi::SIZE_T);
+ kernel32::CloseHandle(handle);
+
+ if ptr == ptr::null_mut() {
+ return Err(io::Error::last_os_error());
+ }
+
+ let mut old = 0;
+ let result = kernel32::VirtualProtect(ptr,
+ len as winapi::SIZE_T,
+ prot.as_mapping_flag(),
+ &mut old);
+ if result != 0 {
+ Ok(MmapInner {
+ file: None,
+ ptr: ptr,
+ len: len as usize,
+ })
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+
+ pub fn flush(&self, offset: usize, len: usize) -> io::Result<()> {
+ try!(self.flush_async(offset, len));
+ if let Some(ref file) = self.file { file.sync_data() } else { Ok(()) }
+ }
+
+ pub fn flush_async(&self, offset: usize, len: usize) -> io::Result<()> {
+ let result = unsafe { kernel32::FlushViewOfFile(self.ptr.offset(offset as isize),
+ len as winapi::SIZE_T) };
+ if result != 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ pub fn set_protection(&mut self, prot: Protection) -> io::Result<()> {
+ unsafe {
+ let alignment = self.ptr as usize % allocation_granularity();
+ let ptr = self.ptr.offset(- (alignment as isize));
+ let aligned_len = self.len as winapi::SIZE_T + alignment as winapi::SIZE_T;
+
+ let mut old = 0;
+ let result = kernel32::VirtualProtect(ptr,
+ aligned_len,
+ prot.as_mapping_flag(),
+ &mut old);
+
+ if result != 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+
+ pub fn ptr(&self) -> *const u8 {
+ self.ptr as *const u8
+ }
+
+ pub fn mut_ptr(&mut self) -> *mut u8 {
+ self.ptr as *mut u8
+ }
+
+ pub fn len(&self) -> usize {
+ self.len
+ }
+}
+
+impl Drop for MmapInner {
+ fn drop(&mut self) {
+ let alignment = self.ptr as usize % allocation_granularity();
+ unsafe {
+ let ptr = self.ptr.offset(- (alignment as isize));
+ assert!(kernel32::UnmapViewOfFile(ptr) != 0,
+ "unable to unmap mmap: {}", io::Error::last_os_error());
+ }
+ }
+}
+
+unsafe impl Sync for MmapInner { }
+unsafe impl Send for MmapInner { }
+
+fn allocation_granularity() -> usize {
+ unsafe {
+ let mut info = mem::zeroed();
+ kernel32::GetSystemInfo(&mut info);
+ return info.dwAllocationGranularity as usize;
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"0602d18a229e5bd001e2aaf8ff26c1bdb3dba926f911aec8901c0ee7bed27ca9","Cargo.toml":"e503ea1d349539b2c75e3659660bc6232a447719ce2c7f7b7bec38fbbab6f640","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"322030d7ae24aec8fb2d2c32a7245c7a6dab5b885b439d599d3acd2ddca9bd80","src/datagram.rs":"b4311804bd4e330905fbf3e47e8c738759bbc039bf6ad2045490080a958d48c2","src/lib.rs":"381e167fff02b16d5234fe8bfa3f85684fee4796f83356c2dfdcbfe09fa9a1fe","src/listener.rs":"1cf1d1ca896f4718df27d1affbbc9125d86484c60f3dc479741f50ecb484a290","src/socket.rs":"6f14598a19d66cf76e50fe6a72c17dc840bf46216597a2e055a3bb5efff267e4","src/stream.rs":"7353ebe4a104ed0226c849e638cf9f6922083488b81b2e862c17b59d404ac15f","tests/echo.rs":"3056f97689f0696e970cc401bf0b1f5c0cd4f9952b6fe2dda60831c870f6171c","tests/smoke.rs":"2a6ee54b3f9d58a63cb3beecda8646f17ebdb3d20aa59c740f8c972cc06063e9"},"package":"1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/.travis.yml
@@ -0,0 +1,23 @@
+language: rust
+rust:
+ - stable
+ - beta
+ - nightly
+sudo: false
+before_script:
+ - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
+script:
+ - cargo test
+ - cargo doc
+after_success:
+ - travis-cargo --only nightly doc-upload
+env:
+ global:
+ secure: "V+dRcbwjNbHJxvoEcASMMdXY74YSmQqZXA9P2oa4gzP7lI0fXqM47pBIVfA4Mj4dhZywByywc/EBDc51JOjdORZognENxLUymTlTcTu7zcq+r7woXYPQHmm7BEvrEKBbQTaV/sO+200CN4d5mT1sPNJoFMp8lUL7/QtoczH+vGWSzWBb8F59oxRpNqD1MhaTpo0oWVMp8yskLvylgIjEoCY8E1uKp7rkqgAxUj8RmZt3hnFAr1SIu32tYUhj7STw8Ad++pI+kdx6SH0bslBy7TQcEhsTPQ4Q66u1z5pkVhv/Q0u3QLiJcI8WWEukTa3lwRUusXwZXfuME2Lz6PiKWa7jSGDc0UBc83oy7FOxyY+tutk74MQU0861dh2UlJgzzw+A7NnZHXueNQyT3RaD3K1ce3aPdCMBPM6GcRFkMcm+6llz5weGBhWHo5Uyeuy+Y88OF/ZZS7a5PdmvPfapB3Ir6MRZaDse/bDEWaBd5wO7ZMk8YyFumxJWuksHWxnIYTEjkn+4zHH1doCSr5axjryv9oDa8Agjcd1ePRNUAlgszslUeyU5ACfX2rJi2VlEL+DC01WfUQC0z0M8ISOOaQdoVRnwYOYpw6qQHZDU2Es7f1TihIzAOmzkgnz9wpInzs73EDjHqyROVRnHQO8P/epapbisWlakWWmUn7GJA3Y="
+
+notifications:
+ email:
+ on_success: never
+os:
+ - linux
+ - osx
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "mio-uds"
+version = "0.6.4"
+authors = ["Alex Crichton <alex@alexcrichton.com>"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/alexcrichton/mio-uds"
+homepage = "https://github.com/alexcrichton/mio-uds"
+documentation = "https://docs.rs/mio-uds"
+description = """
+Unix domain socket bindings for mio
+"""
+categories = ["asynchronous"]
+
+[badges]
+travis-ci = { repository = "alexcrichton/mio-uds" }
+
+[target."cfg(unix)".dependencies]
+libc = "0.2"
+mio = "0.6.5"
+
+[dev-dependencies]
+tempdir = "0.3"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 Alex Crichton
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/README.md
@@ -0,0 +1,35 @@
+# mio-uds
+
+[![Build Status](https://travis-ci.org/alexcrichton/mio-uds.svg?branch=master)](https://travis-ci.org/alexcrichton/mio-uds)
+
+[Documentation](https://docs.rs/mio-uds)
+
+A library for integrating Unix Domain Sockets with [mio]. Based on the standard
+library's [support for Unix sockets][std], except all of the abstractions and
+types are nonblocking to conform with the expectations of mio.
+
+[mio]: https://github.com/carllerche/mio
+[std]: https://doc.rust-lang.org/std/os/unix/net/
+
+```toml
+# Cargo.toml
+[dependencies]
+mio-uds = "0.6"
+mio = "0.6"
+```
+
+## Usage
+
+The three exported types at the top level, `UnixStream`, `UnixListener`, and
+`UnixDatagram`, are thin wrappers around the libstd counterparts. They can be
+used in similar fashions to mio's TCP and UDP types in terms of registration and
+API.
+
+# License
+
+`mio-uds` is primarily distributed under the terms of both the MIT license and
+the Apache License (Version 2.0), with portions covered by various BSD-like
+licenses.
+
+See LICENSE-APACHE, and LICENSE-MIT for details.
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/src/datagram.rs
@@ -0,0 +1,183 @@
+use std::io;
+use std::net::Shutdown;
+use std::os::unix::net;
+use std::os::unix::prelude::*;
+use std::path::Path;
+
+use libc;
+use mio::event::Evented;
+use mio::unix::EventedFd;
+use mio::{Poll, Token, Ready, PollOpt};
+
+use cvt;
+use socket::{sockaddr_un, Socket};
+
+/// A Unix datagram socket.
+#[derive(Debug)]
+pub struct UnixDatagram {
+ inner: net::UnixDatagram,
+}
+
+impl UnixDatagram {
+ /// Creates a Unix datagram socket bound to the given path.
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
+ UnixDatagram::_bind(path.as_ref())
+ }
+
+ fn _bind(path: &Path) -> io::Result<UnixDatagram> {
+ unsafe {
+ let (addr, len) = try!(sockaddr_un(path));
+ let fd = try!(Socket::new(libc::SOCK_DGRAM));
+
+ let addr = &addr as *const _ as *const _;
+ try!(cvt(libc::bind(fd.fd(), addr, len)));
+
+ Ok(UnixDatagram::from_raw_fd(fd.into_fd()))
+ }
+ }
+
+ /// Consumes a standard library `UnixDatagram` and returns a wrapped
+ /// `UnixDatagram` compatible with mio.
+ ///
+ /// The returned stream is moved into nonblocking mode and is otherwise
+ /// ready to get associated with an event loop.
+ pub fn from_datagram(stream: net::UnixDatagram) -> io::Result<UnixDatagram> {
+ try!(stream.set_nonblocking(true));
+ Ok(UnixDatagram { inner: stream })
+ }
+
+ /// Create an unnamed pair of connected sockets.
+ ///
+ /// Returns two `UnixDatagrams`s which are connected to each other.
+ pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
+ unsafe {
+ let (a, b) = try!(Socket::pair(libc::SOCK_DGRAM));
+ Ok((UnixDatagram::from_raw_fd(a.into_fd()),
+ UnixDatagram::from_raw_fd(b.into_fd())))
+ }
+ }
+
+ /// Creates a Unix Datagram socket which is not bound to any address.
+ pub fn unbound() -> io::Result<UnixDatagram> {
+ let stream = try!(net::UnixDatagram::unbound());
+ try!(stream.set_nonblocking(true));
+ Ok(UnixDatagram { inner: stream })
+ }
+
+ /// Connects the socket to the specified address.
+ ///
+ /// The `send` method may be used to send data to the specified address.
+ /// `recv` and `recv_from` will only receive data from that address.
+ pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ self.inner.connect(path)
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixListener` is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one listener will affect the other.
+ pub fn try_clone(&self) -> io::Result<UnixDatagram> {
+ self.inner.try_clone().map(|i| {
+ UnixDatagram { inner: i }
+ })
+ }
+
+ /// Returns the address of this socket.
+ pub fn local_addr(&self) -> io::Result<net::SocketAddr> {
+ self.inner.local_addr()
+ }
+
+ /// Returns the address of this socket's peer.
+ ///
+ /// The `connect` method will connect the socket to a peer.
+ pub fn peer_addr(&self) -> io::Result<net::SocketAddr> {
+ self.inner.peer_addr()
+ }
+
+ /// Receives data from the socket.
+ ///
+ /// On success, returns the number of bytes read and the address from
+ /// whence the data came.
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, net::SocketAddr)> {
+ self.inner.recv_from(buf)
+ }
+
+ /// Receives data from the socket.
+ ///
+ /// On success, returns the number of bytes read.
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.recv(buf)
+ }
+
+ /// Sends data on the socket to the specified address.
+ ///
+ /// On success, returns the number of bytes written.
+ pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
+ self.inner.send_to(buf, path)
+ }
+
+ /// Sends data on the socket to the socket's peer.
+ ///
+ /// The peer address may be set by the `connect` method, and this method
+ /// will return an error if the socket has not already been connected.
+ ///
+ /// On success, returns the number of bytes written.
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.send(buf)
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ /// Shut down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O calls on the
+ /// specified portions to immediately return with an appropriate value
+ /// (see the documentation of `Shutdown`).
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.inner.shutdown(how)
+ }
+}
+
+impl Evented for UnixDatagram {
+ fn register(&self,
+ poll: &Poll,
+ token: Token,
+ events: Ready,
+ opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).register(poll, token, events, opts)
+ }
+
+ fn reregister(&self,
+ poll: &Poll,
+ token: Token,
+ events: Ready,
+ opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).reregister(poll, token, events, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).deregister(poll)
+ }
+}
+
+impl AsRawFd for UnixDatagram {
+ fn as_raw_fd(&self) -> i32 {
+ self.inner.as_raw_fd()
+ }
+}
+
+impl IntoRawFd for UnixDatagram {
+ fn into_raw_fd(self) -> i32 {
+ self.inner.into_raw_fd()
+ }
+}
+
+impl FromRawFd for UnixDatagram {
+ unsafe fn from_raw_fd(fd: i32) -> UnixDatagram {
+ UnixDatagram { inner: net::UnixDatagram::from_raw_fd(fd) }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/src/lib.rs
@@ -0,0 +1,27 @@
+//! MIO bindings for Unix Domain Sockets
+
+#![cfg(unix)]
+#![deny(missing_docs)]
+#![doc(html_root_url = "https://docs.rs/mio-uds/0.6")]
+
+extern crate libc;
+extern crate mio;
+
+use std::io;
+
+mod datagram;
+mod listener;
+mod socket;
+mod stream;
+
+pub use stream::UnixStream;
+pub use listener::UnixListener;
+pub use datagram::UnixDatagram;
+
+fn cvt(i: libc::c_int) -> io::Result<libc::c_int> {
+ if i == -1 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(i)
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/src/listener.rs
@@ -0,0 +1,134 @@
+use std::io;
+use std::os::unix::net;
+use std::os::unix::prelude::*;
+use std::path::Path;
+
+use libc;
+use mio::event::Evented;
+use mio::unix::EventedFd;
+use mio::{Poll, Token, Ready, PollOpt};
+
+use UnixStream;
+use cvt;
+use socket::{sockaddr_un, Socket};
+
+/// A structure representing a Unix domain socket server.
+///
+/// This listener can be used to accept new streams connected to a remote
+/// endpoint, through which the `read` and `write` methods can be used to
+/// communicate.
+#[derive(Debug)]
+pub struct UnixListener {
+ inner: net::UnixListener,
+}
+
+impl UnixListener {
+ /// Creates a new `UnixListener` bound to the specified socket.
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
+ UnixListener::_bind(path.as_ref())
+ }
+
+ fn _bind(path: &Path) -> io::Result<UnixListener> {
+ unsafe {
+ let (addr, len) = try!(sockaddr_un(path));
+ let fd = try!(Socket::new(libc::SOCK_STREAM));
+
+ let addr = &addr as *const _ as *const _;
+ try!(cvt(libc::bind(fd.fd(), addr, len)));
+ try!(cvt(libc::listen(fd.fd(), 128)));
+
+ Ok(UnixListener::from_raw_fd(fd.into_fd()))
+ }
+ }
+
+ /// Consumes a standard library `UnixListener` and returns a wrapped
+ /// `UnixListener` compatible with mio.
+ ///
+ /// The returned stream is moved into nonblocking mode and is otherwise
+ /// ready to get associated with an event loop.
+ pub fn from_listener(stream: net::UnixListener) -> io::Result<UnixListener> {
+ try!(stream.set_nonblocking(true));
+ Ok(UnixListener { inner: stream })
+ }
+
+ /// Accepts a new incoming connection to this listener.
+ ///
+ /// When established, the corresponding `UnixStream` and the remote peer's
+ /// address will be returned as `Ok(Some(...))`. If there is no connection
+ /// waiting to be accepted, then `Ok(None)` is returned.
+ ///
+ /// If an error happens while accepting, `Err` is returned.
+ pub fn accept(&self) -> io::Result<Option<(UnixStream, net::SocketAddr)>> {
+ match self.inner.accept() {
+ Ok((socket, addr)) => {
+ try!(socket.set_nonblocking(true));
+ Ok(Some(unsafe {
+ (UnixStream::from_raw_fd(socket.into_raw_fd()), addr)
+ }))
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
+ Err(e) => Err(e),
+ }
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixListener` is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one listener will affect the other.
+ pub fn try_clone(&self) -> io::Result<UnixListener> {
+ self.inner.try_clone().map(|l| {
+ UnixListener { inner: l }
+ })
+ }
+
+ /// Returns the local socket address of this listener.
+ pub fn local_addr(&self) -> io::Result<net::SocketAddr> {
+ self.inner.local_addr()
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+}
+
+impl Evented for UnixListener {
+ fn register(&self,
+ poll: &Poll,
+ token: Token,
+ events: Ready,
+ opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).register(poll, token, events, opts)
+ }
+
+ fn reregister(&self,
+ poll: &Poll,
+ token: Token,
+ events: Ready,
+ opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).reregister(poll, token, events, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).deregister(poll)
+ }
+}
+
+impl AsRawFd for UnixListener {
+ fn as_raw_fd(&self) -> i32 {
+ self.inner.as_raw_fd()
+ }
+}
+
+impl IntoRawFd for UnixListener {
+ fn into_raw_fd(self) -> i32 {
+ self.inner.into_raw_fd()
+ }
+}
+
+impl FromRawFd for UnixListener {
+ unsafe fn from_raw_fd(fd: i32) -> UnixListener {
+ UnixListener { inner: net::UnixListener::from_raw_fd(fd) }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/src/socket.rs
@@ -0,0 +1,141 @@
+use std::cmp::Ordering;
+use std::io;
+use std::mem;
+use std::os::unix::prelude::*;
+use std::path::Path;
+
+use libc::{self, c_int, c_ulong};
+
+use cvt;
+
+// 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, SOCK_NONBLOCK};
+#[cfg(not(target_os = "linux"))]
+const SOCK_CLOEXEC: c_int = 0;
+#[cfg(not(target_os = "linux"))]
+const SOCK_NONBLOCK: c_int = 0;
+
+pub struct Socket {
+ fd: c_int,
+}
+
+impl Socket {
+ pub fn new(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") {
+ let flags = ty | SOCK_CLOEXEC | SOCK_NONBLOCK;
+ match cvt(libc::socket(libc::AF_UNIX, flags, 0)) {
+ Ok(fd) => return Ok(Socket { fd: fd }),
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ let fd = Socket { fd: try!(cvt(libc::socket(libc::AF_UNIX, ty, 0))) };
+ try!(cvt(libc::ioctl(fd.fd, libc::FIOCLEX)));
+ let mut nonblocking = 1 as c_ulong;
+ try!(cvt(libc::ioctl(fd.fd, libc::FIONBIO, &mut nonblocking)));
+ Ok(fd)
+ }
+ }
+
+ pub fn pair(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") {
+ let flags = ty | SOCK_CLOEXEC | SOCK_NONBLOCK;
+ match cvt(libc::socketpair(libc::AF_UNIX, flags, 0, fds.as_mut_ptr())) {
+ Ok(_) => {
+ return Ok((Socket { fd: fds[0] }, Socket { fd: fds[1] }))
+ }
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {},
+ Err(e) => return Err(e),
+ }
+ }
+
+ try!(cvt(libc::socketpair(libc::AF_UNIX, ty, 0, fds.as_mut_ptr())));
+ let a = Socket { fd: fds[0] };
+ let b = Socket { fd: fds[1] };
+ try!(cvt(libc::ioctl(a.fd, libc::FIOCLEX)));
+ try!(cvt(libc::ioctl(b.fd, libc::FIOCLEX)));
+ let mut nonblocking = 1 as c_ulong;
+ try!(cvt(libc::ioctl(a.fd, libc::FIONBIO, &mut nonblocking)));
+ try!(cvt(libc::ioctl(b.fd, libc::FIONBIO, &mut nonblocking)));
+ Ok((a, b))
+ }
+ }
+
+ pub fn fd(&self) -> c_int {
+ self.fd
+ }
+
+ pub fn into_fd(self) -> c_int {
+ let ret = self.fd;
+ mem::forget(self);
+ ret
+ }
+}
+
+impl Drop for Socket {
+ fn drop(&mut self) {
+ unsafe {
+ let _ = libc::close(self.fd);
+ }
+ }
+}
+
+pub unsafe fn sockaddr_un(path: &Path)
+ -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+ let mut addr: libc::sockaddr_un = mem::zeroed();
+ addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+ let bytes = path.as_os_str().as_bytes();
+
+ match (bytes.get(0), bytes.len().cmp(&addr.sun_path.len())) {
+ // Abstract paths don't need a null terminator
+ (Some(&0), Ordering::Greater) => {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "path must be no longer than SUN_LEN"));
+ }
+ (_, Ordering::Greater) | (_, Ordering::Equal) => {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "path must be shorter than SUN_LEN"));
+ }
+ _ => {}
+ }
+ for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
+ *dst = *src as libc::c_char;
+ }
+ // null byte for pathname addresses is already there because we zeroed the
+ // struct
+
+ let mut len = sun_path_offset() + bytes.len();
+ match bytes.get(0) {
+ Some(&0) | None => {}
+ Some(_) => len += 1,
+ }
+ Ok((addr, len as libc::socklen_t))
+}
+
+fn sun_path_offset() -> usize {
+ unsafe {
+ // Work with an actual instance of the type since using a null pointer is UB
+ let addr: libc::sockaddr_un = mem::uninitialized();
+ let base = &addr as *const _ as usize;
+ let path = &addr.sun_path as *const _ as usize;
+ path - base
+ }
+}
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/src/stream.rs
@@ -0,0 +1,189 @@
+use std::io::prelude::*;
+use std::io;
+use std::os::unix::net;
+use std::os::unix::prelude::*;
+use std::path::Path;
+use std::net::Shutdown;
+
+use libc;
+use mio::event::Evented;
+use mio::unix::EventedFd;
+use mio::{Poll, Token, Ready, PollOpt};
+
+use cvt;
+use socket::{sockaddr_un, Socket};
+
+/// A Unix stream socket.
+///
+/// This type represents a `SOCK_STREAM` connection of the `AF_UNIX` family,
+/// otherwise known as Unix domain sockets or Unix sockets. This stream is
+/// readable/writable and acts similarly to a TCP stream where reads/writes are
+/// all in order with respect to the other connected end.
+///
+/// Streams can either be connected to paths locally or another ephemeral socket
+/// created by the `pair` function.
+///
+/// A `UnixStream` implements the `Read`, `Write`, `Evented`, `AsRawFd`,
+/// `IntoRawFd`, and `FromRawFd` traits for interoperating with other I/O code.
+///
+/// Note that all values of this type are typically in nonblocking mode, so the
+/// `read` and `write` methods may return an error with the kind of
+/// `WouldBlock`, indicating that it's not ready to read/write just yet.
+#[derive(Debug)]
+pub struct UnixStream {
+ inner: net::UnixStream,
+}
+
+impl UnixStream {
+ /// Connects to the socket named by `path`.
+ ///
+ /// The socket returned may not be readable and/or writable yet, as the
+ /// connection may be in progress. The socket should be registered with an
+ /// event loop to wait on both of these properties being available.
+ pub fn connect<P: AsRef<Path>>(p: P) -> io::Result<UnixStream> {
+ UnixStream::_connect(p.as_ref())
+ }
+
+ fn _connect(path: &Path) -> io::Result<UnixStream> {
+ unsafe {
+ let (addr, len) = try!(sockaddr_un(path));
+ let socket = try!(Socket::new(libc::SOCK_STREAM));
+ let addr = &addr as *const _ as *const _;
+ match cvt(libc::connect(socket.fd(), addr, len)) {
+ Ok(_) => {}
+ Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
+ Err(e) => return Err(e),
+ }
+
+ Ok(UnixStream::from_raw_fd(socket.into_fd()))
+ }
+ }
+
+ /// Consumes a standard library `UnixStream` and returns a wrapped
+ /// `UnixStream` compatible with mio.
+ ///
+ /// The returned stream is moved into nonblocking mode and is otherwise
+ /// ready to get associated with an event loop.
+ pub fn from_stream(stream: net::UnixStream) -> io::Result<UnixStream> {
+ try!(stream.set_nonblocking(true));
+ Ok(UnixStream { inner: stream })
+ }
+
+ /// Creates an unnamed pair of connected sockets.
+ ///
+ /// Returns two `UnixStream`s which are connected to each other.
+ pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
+ Socket::pair(libc::SOCK_STREAM).map(|(a, b)| unsafe {
+ (UnixStream::from_raw_fd(a.into_fd()),
+ UnixStream::from_raw_fd(b.into_fd()))
+ })
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixStream` 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 propogated to the other
+ /// stream.
+ pub fn try_clone(&self) -> io::Result<UnixStream> {
+ self.inner.try_clone().map(|s| {
+ UnixStream { inner: s }
+ })
+ }
+
+ /// Returns the socket address of the local half of this connection.
+ pub fn local_addr(&self) -> io::Result<net::SocketAddr> {
+ self.inner.local_addr()
+ }
+
+ /// Returns the socket address of the remote half of this connection.
+ pub fn peer_addr(&self) -> io::Result<net::SocketAddr> {
+ self.inner.peer_addr()
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ /// Shuts down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O calls on the
+ /// specified portions to immediately return with an appropriate value
+ /// (see the documentation of `Shutdown`).
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.inner.shutdown(how)
+ }
+}
+
+impl Evented for UnixStream {
+ fn register(&self,
+ poll: &Poll,
+ token: Token,
+ events: Ready,
+ opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).register(poll, token, events, opts)
+ }
+
+ fn reregister(&self,
+ poll: &Poll,
+ token: Token,
+ events: Ready,
+ opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).reregister(poll, token, events, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).deregister(poll)
+ }
+}
+
+impl Read for UnixStream {
+ fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(bytes)
+ }
+}
+
+impl<'a> Read for &'a UnixStream {
+ fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
+ (&self.inner).read(bytes)
+ }
+}
+
+impl Write for UnixStream {
+ fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
+ self.inner.write(bytes)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.flush()
+ }
+}
+
+impl<'a> Write for &'a UnixStream {
+ fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
+ (&self.inner).write(bytes)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ (&self.inner).flush()
+ }
+}
+
+impl AsRawFd for UnixStream {
+ fn as_raw_fd(&self) -> i32 {
+ self.inner.as_raw_fd()
+ }
+}
+
+impl IntoRawFd for UnixStream {
+ fn into_raw_fd(self) -> i32 {
+ self.inner.into_raw_fd()
+ }
+}
+
+impl FromRawFd for UnixStream {
+ unsafe fn from_raw_fd(fd: i32) -> UnixStream {
+ UnixStream { inner: net::UnixStream::from_raw_fd(fd) }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/tests/echo.rs
@@ -0,0 +1,276 @@
+extern crate mio;
+extern crate tempdir;
+extern crate mio_uds;
+
+use std::io::{self, Write, Read};
+use std::io::ErrorKind::WouldBlock;
+
+use tempdir::TempDir;
+
+use mio::*;
+use mio_uds::*;
+
+macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{} failed with {}", stringify!($e), e),
+ })
+}
+
+const SERVER: Token = Token(0);
+const CLIENT: Token = Token(1);
+
+struct EchoConn {
+ sock: UnixStream,
+ buf: Vec<u8>,
+ token: Option<Token>,
+ interest: Ready,
+}
+
+impl EchoConn {
+ fn new(sock: UnixStream) -> EchoConn {
+ EchoConn {
+ sock: sock,
+ buf: Vec::new(),
+ token: None,
+ interest: Ready::readable(),
+ }
+ }
+
+ fn writable(&mut self, poll: &Poll) -> io::Result<()> {
+ match self.sock.write(&self.buf) {
+ Ok(n) => {
+ assert_eq!(n, self.buf.len());
+ self.interest.insert(Ready::readable());
+ self.interest.remove(Ready::writable());
+ }
+ Err(ref e) if e.kind() == WouldBlock => {
+ self.interest.insert(Ready::writable());
+ }
+ Err(e) => panic!("not implemented; client err={:?}", e),
+ }
+
+ assert!(self.interest.is_readable() || self.interest.is_writable(),
+ "actual={:?}", self.interest);
+ poll.reregister(&self.sock, self.token.unwrap(), self.interest,
+ PollOpt::edge() | PollOpt::oneshot())
+ }
+
+ fn readable(&mut self, poll: &Poll) -> io::Result<()> {
+ let mut buf = [0; 1024];
+
+ match self.sock.read(&mut buf) {
+ Ok(r) => {
+ self.buf = buf[..r].to_vec();
+
+ self.interest.remove(Ready::readable());
+ self.interest.insert(Ready::writable());
+ }
+ Err(ref e) if e.kind() == WouldBlock => {}
+ Err(_e) => {
+ self.interest.remove(Ready::readable());
+ }
+ }
+
+ assert!(self.interest.is_readable() || self.interest.is_writable(),
+ "actual={:?}", self.interest);
+ poll.reregister(&self.sock, self.token.unwrap(), self.interest,
+ PollOpt::edge() | PollOpt::oneshot())
+ }
+}
+
+struct EchoServer {
+ sock: UnixListener,
+ conns: Vec<Option<EchoConn>>,
+}
+
+impl EchoServer {
+ fn accept(&mut self, poll: &Poll) -> io::Result<()> {
+ let sock = t!(self.sock.accept()).unwrap().0;
+ let conn = EchoConn::new(sock);
+ let tok = Token(self.conns.len() + 2);
+ self.conns.push(Some(conn));
+
+ // Register the connection
+ self.conn(tok).token = Some(tok);
+ t!(poll.register(&self.conn(tok).sock, tok,
+ Ready::readable(),
+ PollOpt::edge() | PollOpt::oneshot()));
+
+ Ok(())
+ }
+
+ fn conn_readable(&mut self, poll: &Poll, tok: Token) -> io::Result<()> {
+ self.conn(tok).readable(poll)
+ }
+
+ fn conn_writable(&mut self, poll: &Poll, tok: Token) -> io::Result<()> {
+ self.conn(tok).writable(poll)
+ }
+
+ fn conn<'a>(&'a mut self, tok: Token) -> &'a mut EchoConn {
+ self.conns[usize::from(tok) - 2].as_mut().unwrap()
+ }
+}
+
+struct EchoClient {
+ sock: UnixStream,
+ msgs: Vec<&'static str>,
+ tx: &'static [u8],
+ rx: &'static [u8],
+ token: Token,
+ interest: Ready,
+ active: bool,
+}
+
+
+// Sends a message and expects to receive the same exact message, one at a time
+impl EchoClient {
+ fn new(sock: UnixStream, tok: Token, mut msgs: Vec<&'static str>) -> EchoClient {
+ let curr = msgs.remove(0);
+
+ EchoClient {
+ sock: sock,
+ msgs: msgs,
+ tx: curr.as_bytes(),
+ rx: curr.as_bytes(),
+ token: tok,
+ interest: Ready::empty(),
+ active: true,
+ }
+ }
+
+ fn readable(&mut self, poll: &Poll) -> io::Result<()> {
+ let mut buf = [0; 1024];
+ match self.sock.read(&mut buf) {
+ Ok(n) => {
+ assert_eq!(&self.rx[..n], &buf[..n]);
+ self.rx = &self.rx[n..];
+
+ self.interest.remove(Ready::readable());
+
+ if self.rx.len() == 0 {
+ self.next_msg(poll).unwrap();
+ }
+ }
+ Err(ref e) if e.kind() == WouldBlock => {}
+ Err(e) => panic!("error {}", e),
+ }
+
+ if !self.interest.is_empty() {
+ assert!(self.interest.is_readable() || self.interest.is_writable(),
+ "actual={:?}", self.interest);
+ try!(poll.reregister(&self.sock, self.token, self.interest,
+ PollOpt::edge() | PollOpt::oneshot()));
+ }
+
+ Ok(())
+ }
+
+ fn writable(&mut self, poll: &Poll) -> io::Result<()> {
+ match self.sock.write(self.tx) {
+ Ok(r) => {
+ self.tx = &self.tx[r..];
+ self.interest.insert(Ready::readable());
+ self.interest.remove(Ready::writable());
+ }
+ Err(ref e) if e.kind() == WouldBlock => {
+ self.interest.insert(Ready::writable());
+ }
+ Err(e) => panic!("not implemented; client err={:?}", e)
+ }
+
+ assert!(self.interest.is_readable() || self.interest.is_writable(),
+ "actual={:?}", self.interest);
+ poll.reregister(&self.sock, self.token, self.interest,
+ PollOpt::edge() | PollOpt::oneshot())
+ }
+
+ fn next_msg(&mut self, poll: &Poll) -> io::Result<()> {
+ if self.msgs.is_empty() {
+ self.active = false;
+ return Ok(());
+ }
+
+ let curr = self.msgs.remove(0);
+
+ self.tx = curr.as_bytes();
+ self.rx = curr.as_bytes();
+
+ self.interest.insert(Ready::writable());
+ assert!(self.interest.is_readable() || self.interest.is_writable(),
+ "actual={:?}", self.interest);
+ poll.reregister(&self.sock, self.token, self.interest,
+ PollOpt::edge() | PollOpt::oneshot())
+ }
+}
+
+struct Echo {
+ server: EchoServer,
+ client: EchoClient,
+}
+
+impl Echo {
+ fn new(srv: UnixListener, client: UnixStream, msgs: Vec<&'static str>) -> Echo {
+ Echo {
+ server: EchoServer {
+ sock: srv,
+ conns: Vec::new(),
+ },
+ client: EchoClient::new(client, CLIENT, msgs)
+ }
+ }
+
+ fn ready(&mut self,
+ poll: &Poll,
+ token: Token,
+ events: Ready) {
+ println!("ready {:?} {:?}", token, events);
+ if events.is_readable() {
+ match token {
+ SERVER => self.server.accept(poll).unwrap(),
+ CLIENT => self.client.readable(poll).unwrap(),
+ i => self.server.conn_readable(poll, i).unwrap()
+ }
+ }
+
+ if events.is_writable() {
+ match token {
+ SERVER => panic!("received writable for token 0"),
+ CLIENT => self.client.writable(poll).unwrap(),
+ _ => self.server.conn_writable(poll, token).unwrap()
+ }
+ }
+ }
+}
+
+#[test]
+fn echo_server() {
+ let tmp_dir = t!(TempDir::new("mio-uds"));
+ let addr = tmp_dir.path().join("sock");
+
+ let poll = t!(Poll::new());
+ let mut events = Events::with_capacity(1024);
+
+ let srv = t!(UnixListener::bind(&addr));
+ t!(poll.register(&srv,
+ SERVER,
+ Ready::readable(),
+ PollOpt::edge() | PollOpt::oneshot()));
+
+ let sock = t!(UnixStream::connect(&addr));
+ t!(poll.register(&sock,
+ CLIENT,
+ Ready::writable(),
+ PollOpt::edge() | PollOpt::oneshot()));
+
+ let mut echo = Echo::new(srv, sock, vec!["foo", "bar"]);
+ while echo.client.active {
+ t!(poll.poll(&mut events, None));
+
+ for i in 0..events.len() {
+ let event = events.get(i).unwrap();
+ echo.ready(&poll, event.token(), event.readiness());
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio-uds/tests/smoke.rs
@@ -0,0 +1,66 @@
+extern crate mio;
+extern crate tempdir;
+extern crate mio_uds;
+
+use std::io::prelude::*;
+use std::time::Duration;
+
+use mio::*;
+use mio_uds::*;
+use tempdir::TempDir;
+
+macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{} failed with {}", stringify!($e), e),
+ })
+}
+
+#[test]
+fn listener() {
+ let td = t!(TempDir::new("uds"));
+ let a = t!(UnixListener::bind(td.path().join("foo")));
+ assert!(t!(a.accept()).is_none());
+ t!(a.local_addr());
+ assert!(t!(a.take_error()).is_none());
+ let b = t!(a.try_clone());
+ assert!(t!(b.accept()).is_none());
+
+ let poll = t!(Poll::new());
+ let mut events = Events::with_capacity(1024);
+
+ t!(poll.register(&a, Token(1), Ready::readable(), PollOpt::edge()));
+
+ let s = t!(UnixStream::connect(td.path().join("foo")));
+
+ assert_eq!(t!(poll.poll(&mut events, None)), 1);
+
+ let (s2, addr) = t!(a.accept()).unwrap();
+
+ assert_eq!(t!(s.peer_addr()).as_pathname(), t!(s2.local_addr()).as_pathname());
+ assert_eq!(t!(s.local_addr()).as_pathname(), t!(s2.peer_addr()).as_pathname());
+ assert_eq!(addr.as_pathname(), t!(s.local_addr()).as_pathname());
+}
+
+#[test]
+fn stream() {
+ let poll = t!(Poll::new());
+ let mut events = Events::with_capacity(1024);
+ let (mut a, mut b) = t!(UnixStream::pair());
+
+ let both = Ready::readable() | Ready::writable();
+ t!(poll.register(&a, Token(1), both, PollOpt::edge()));
+ t!(poll.register(&b, Token(2), both, PollOpt::edge()));
+
+ assert_eq!(t!(poll.poll(&mut events, Some(Duration::new(0, 0)))), 2);
+ assert_eq!(events.get(0).unwrap().readiness(), Ready::writable());
+ assert_eq!(events.get(1).unwrap().readiness(), Ready::writable());
+
+ assert_eq!(t!(a.write(&[3])), 1);
+
+ assert_eq!(t!(poll.poll(&mut events, Some(Duration::new(0, 0)))), 1);
+ assert!(events.get(0).unwrap().readiness().is_readable());
+ assert_eq!(events.get(0).unwrap().token(), Token(2));
+
+ assert_eq!(t!(b.read(&mut [0; 1024])), 1);
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","CHANGELOG.md":"859b996b1d16ad6025c86d6d723f9db687dbe69fc15f85bf5a5dbeb1cdf89145","Cargo.toml":"1e24366fa1469647457574af270b42bfc3eccf92f92c04c81f8cf54682fceadf","LICENSE":"07919255c7e04793d8ea760d6c2ce32d19f9ff02bdbdde3ce90b1e1880929a9b","README.md":"18c1685d784a5ce3a02f9019b1e9f85035e8061bd78fdbeded57f53cc5860171","appveyor.yml":"d270d3d60d368e4dc62bb87c17fc407b524d441fdf69eff27090a6043e50d342","benches/bench_poll.rs":"ab1e38ad309d58f4c1924fdef1868fd6b899536959f08d2f33247f057c8962d0","ci/docker/aarch64-linux-android/Dockerfile":"350e18f37e45f8332e802d32e7c05c824fdaf441174c8bc5fb5602865f85b516","ci/docker/aarch64-linux-android/accept-licenses.sh":"b425a5561694c3bf065ef10a00f904c2536e63d6b11782e35a567f2808118ef2","ci/docker/aarch64-linux-android/cargo_config":"ef57da8986b41bbca9ca77d2dbceb857185d341dbb3d97a3f95cc680467e4985","ci/docker/aarch64-linux-android/install-ndk.sh":"e9e58a151ba4f71e7c23fca256bebd9b8a5ed1b3161c6154a634870174f33484","ci/docker/aarch64-linux-android/install-sdk.sh":"e068d8f16bc6297613f3de7bfab72c803594f44edaab7e546d6d8f393389b72b","ci/docker/arm-linux-androideabi/Dockerfile":"c6f153172df91bc5c7d3a859f8970ce54e1cc5c92ab295c1c9cf91c81a49fd51","ci/docker/arm-linux-androideabi/accept-licenses.sh":"84ad00815f628005ed22c5d6cd14990ebc97812a7163bd275b2877904eddab53","ci/docker/arm-linux-androideabi/cargo_config":"ec54caa043c093c699cfb3a1cc3dc35651039b50e29fb416b43f3f4dbd778397","ci/docker/arm-linux-androideabi/install-ndk.sh":"eef063bb01a16c0f90471dbce1b5a395b53141d7704e15a3c9a1c4fc5e06d4b1","ci/docker/arm-linux-androideabi/install-sdk.sh":"42c04b17c4a35bef58757332e960a6e4aba1b5e41f8fc0182265163ff93f6182","ci/ios/deploy_and_run_on_ios_simulator.rs":"977ed5ee02864e85b5583d61549865c72e70c16e62d5b4d3ea1fe486609c193e","ci/run-docker.sh":"7f6c68dbca93788111170ac4678608957a179e76cfe8c5a51d11dfea1742d7f2","ci/run-ios.sh":"2a3069d5378a8e1fdae3aeb79fda490da5b0e5c0e6c775edf37d93986305463a","ci/run.sh":"f496e9d3506aee0c26e00407a2658ada83b736ca50f4b159af219e53c3fe3acf","ci/trust/install.sh":"8b165fc99df296261fcc9cdcbc8b8a177c11c505cdc9255cc19efb66cb0055db","ci/trust/script.sh":"d5d581703524b4b770ad99d5beed4d68733e16497a50b4d0f416115526dae319","src/channel.rs":"e76baed95be4ab4af050ba731916d2a3a03057d145e68f053571e7b8ae277c28","src/deprecated/event_loop.rs":"8432e097e29a0237e6187dfaff2782f077d8c44da4fffcdb83c7991958fbd920","src/deprecated/handler.rs":"13cbc0c193f43a331e125e05d5eddf3712fe86e41a8721186d3672518ef8a9cc","src/deprecated/io.rs":"4948217ffeeba4f508cc89744da5d6af858b4ad7b4be23f927a00df93bdf2984","src/deprecated/mod.rs":"504d718e7c786c69619d27d5b6302ffca3f174b7ffba1bcd72b58e7bac8d83c6","src/deprecated/notify.rs":"8cb108387ebcfb75764e4dd2868d80eb00d793c4b7c867c08cd86ef10b91b023","src/deprecated/unix.rs":"771cf2f475f7655b8b0918d907f78acce6f729f4eb608f657f1af0e5d50ab641","src/event_imp.rs":"374ddc5ccf439bf3c8c02b3796af5bc39bbb4ee8156534752cbe63743d659802","src/io.rs":"26d42aee058dc7a94e1b6fc6f29b34d6f70029fcbf6809574b5758b0c1afd905","src/lib.rs":"979fc24e9013a2672d75b097781ac699f5f88e06455cbec65f8ef1d088e358fa","src/net/mod.rs":"340c63a8efe9ee774b7bf8ed8c0f72fc7563e5c4b35f6a8b243f92d366e145a2","src/net/tcp.rs":"73b8e98f9e474fadf8193a2b3b9cb50743d97d8e27749c063918908d28012d54","src/net/udp.rs":"2d9e4a7eb3c30e36c3ca0b38d572c0eb9006c7602a339e72c19de823f5452a95","src/poll.rs":"08129340bd814e1d2b7fad64641d0dd2a2b6862640309ae68f489a4471b046ec","src/sys/mod.rs":"e6d068be2ed80e56d768aac8ae59886db0f2c8e53f1319b03b02ff35aa031ba7","src/sys/unix/awakener.rs":"7efbec6de6562cc3dcd641f224d466403e1435334e5ad2a82c967ed5a9c30345","src/sys/unix/dlsym.rs":"559337d1f6c10e6c1172bd3908a9dcfa5a0828b53b04f7ca3a0d926afa85cd63","src/sys/unix/epoll.rs":"558cd0dd23afd43a655a778b8b7e876a2372d05a9a132b8a6547c3091c7c00c6","src/sys/unix/eventedfd.rs":"c12f916ed98930ccacb1c15d0d3ea49eb85f872e4127e1bddabb3875ac16ab38","src/sys/unix/io.rs":"5e3c48ef5cd8e3aa2bd6831eea5f9578e82a84c092add7b042675c1c0f01cad1","src/sys/unix/kqueue.rs":"567399be003ac7007e0f068856ebb402382f52c7ffef5b5044edd0290f890a80","src/sys/unix/mod.rs":"dc8bece30046f5cdb25ace072a836b6b3a085eb91c64017b3242c368aa221ef1","src/sys/unix/ready.rs":"152561f335330c8cdce65f9bcc1018e76def6180e45b26e76fa71c41625067bf","src/sys/unix/tcp.rs":"08d2617e3bb172b258d9ee56f46304fa5abd6937f9fa29289a0d9af809a25750","src/sys/unix/udp.rs":"3bedb61c9ee9966f64a6a1ba715bf64e906fc5b118bf1903d7f8aeb2931cfccd","src/sys/unix/uds.rs":"5126490860d2c980e94abc9326dd67473411b20b380aadaeeabc450571e21427","src/sys/windows/awakener.rs":"ea7dcd0370a673421f58a2d804c8da9a7f159dca1a0af87e006ac0df3d3ffa74","src/sys/windows/buffer_pool.rs":"636f4b7510a507f9985987699ce8ec140b2ed852abb231443ee1486c80759eed","src/sys/windows/from_raw_arc.rs":"c2cee14a0355256beb55a1feb54ccdcc50c8ab2d9abb3b7f114be00ed8a5583f","src/sys/windows/mod.rs":"d3b2bf7dd9011e3930d2712aa990b9599bf4060572dc4296f123eb3908ad58ab","src/sys/windows/selector.rs":"b13c9bcba172887f6fef1dffd6e5511489329f7640dd0c9a4e34bb2973bda883","src/sys/windows/tcp.rs":"b0591fc3c89d163129e9c6dbfb1b04a19edc759036e1e66bac54416944ede785","src/sys/windows/udp.rs":"d4cfefee1091d5712cc133eec9c21aafdea9f9959f1384453d1b61c6ea5e8fb5","src/timer.rs":"13c386666720e3e85cfdd5807e098396958e94980e22a21a1b706e69093fab76","src/token.rs":"9fea166777a6fd70b902ee96e395da71f41156f82f923087e61a56b3d1af641e","src/udp.rs":"a02e64c8bb585e6b8637666260809bd9ed708bef0f84bab2d46ca8655e76a03b"},"package":"9e965267d4d58496fc4f740e9861118367f13570cadf66316ed2c3f2f14d87c7"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/CHANGELOG.md
@@ -0,0 +1,128 @@
+# 0.6.9 (June 7, 2017)
+
+* More socket options are exposed through the TCP types, brought in through the
+ `net2` crate.
+
+# 0.6.8 (May 26, 2017)
+
+* Support Fuchia
+* POSIX AIO support
+* Fix memory leak caused by Register::new2
+* Windows: fix handling failed TCP connections
+* Fix build on aarch64-linux-android
+* Fix usage of `O_CLOEXEC` with `SETFL`
+
+# 0.6.7 (April 27, 2017)
+
+* Ignore EPIPE coming out of `kevent`
+* Timer thread should exit when timer is dropped.
+
+# 0.6.6 (March 22, 2017)
+
+* Add send(), recv() and connect() to UDPSocket.
+* Fix bug in custom readiness queue
+* Move net types into `net` module
+
+# 0.6.5 (March 14, 2017)
+
+* Misc improvements to kqueue bindings
+* Add official support for iOS, Android, BSD
+* Reimplement custom readiness queue
+* `Poll` is now `Sync`
+* Officially deprecate non-core functionality (timers, channel, etc...)
+* `Registration` now implements `Evented`
+* Fix bug around error conditions with `connect` on windows.
+* Use iovec crate for scatter / gather operations
+* Only support readable and writable readiness on all platforms
+* Expose additional readiness in a platform specific capacity
+
+# 0.6.4 (January 24, 2017)
+
+* Fix compilation on musl
+* Add `TcpStream::from_stream` which conversts a std TCP stream to Mio.
+
+# 0.6.3 (January 22, 2017)
+
+* Implement readv/writev for `TcpStream`, allowing vectored reads/writes to
+ work across platforms
+* Remove `nix` dependency
+* Implement `Display` and `Error` for some channel error types.
+* Optimize TCP on Windows through `SetFileCompletionNotificationModes`
+
+# 0.6.2 (December 18, 2016)
+
+* Allow registration of custom handles on Windows (like `EventedFd` on Unix)
+* Send only one byte for the awakener on Unix instead of four
+* Fix a bug in the timer implementation which caused an infinite loop
+
+# 0.6.1 (October 30, 2016)
+
+* Update dependency of `libc` to 0.2.16
+* Fix channel `dec` logic
+* Fix a timer bug around timeout cancellation
+* Don't allocate buffers for TCP reads on Windows
+* Touched up documentation in a few places
+* Fix an infinite looping timer thread on OSX
+* Fix compile on 32-bit OSX
+* Fix compile on FreeBSD
+
+# 0.6.0 (September 2, 2016)
+
+* Shift primary API towards `Poll`
+* `EventLoop` and types to `deprecated` mod. All contents of the
+ `deprecated` mod will be removed by Mio 1.0.
+* Increase minimum supported Rust version to 1.9.0
+* Deprecate unix domain socket implementation in favor of using a
+ version external to Mio. For example: https://github.com/alexcrichton/mio-uds.
+* Remove various types now included in `std`
+* Updated TCP & UDP APIs to match the versions in `std`
+* Enable implementing `Evented` for any type via `Registration`
+* Rename `IoEvent` -> `Event`
+* Access `Event` data via functions vs. public fields.
+* Expose `Events` as a public type that is passed into `Poll`
+* Use `std::time::Duration` for all APIs that require a time duration.
+* Polled events are now retrieved via `Events` type.
+* Implement `std::error::Error` for `TimerError`
+* Relax `Send` bound on notify messages.
+* Remove `Clone` impl for `Timeout` (future proof)
+* Remove `mio::prelude`
+* Remove `mio::util`
+* Remove dependency on bytes
+
+# 0.5.0 (December 3, 2015)
+
+* Windows support (#239)
+* NetBSD support (#306)
+* Android support (#295)
+* Don't re-export bytes types
+* Renamed `EventLoop::register_opt` to `EventLoop::register` (#257)
+* `EventLoopConfig` is now a builder instead of having public struct fields. It
+ is also no longer `Copy`. (#259)
+* `TcpSocket` is no longer exported in the public API (#262)
+* Integrate with net2. (#262)
+* `TcpListener` now returns the remote peer address from `accept` as well (#275)
+* The `UdpSocket::{send_to, recv_from}` methods are no longer generic over `Buf`
+ or `MutBuf` but instead take slices directly. The return types have also been
+ updated to return the number of bytes transferred. (#260)
+* Fix bug with kqueue where an error on registration prevented the
+ changelist from getting flushed (#276)
+* Support sending/receiving FDs over UNIX sockets (#291)
+* Mio's socket types are permanently associated with an EventLoop (#308)
+* Reduce unnecessary poll wakeups (#314)
+
+
+# 0.4.1 (July 21, 2015)
+
+* [BUGFIX] Fix notify channel concurrency bug (#216)
+
+# 0.4.0 (July 16, 2015)
+
+* [BUGFIX] EventLoop::register requests all events, not just readable.
+* [BUGFIX] Attempting to send a message to a shutdown event loop fails correctly.
+* [FEATURE] Expose TCP shutdown
+* [IMPROVEMENT] Coalesce readable & writable into `ready` event (#184)
+* [IMPROVEMENT] Rename TryRead & TryWrite function names to avoid conflict with std.
+* [IMPROVEMENT] Provide TCP and UDP types in mio (path to windows #155)
+* [IMPROVEMENT] Use clock_ticks crate instead of time (path to windows #155)
+* [IMPROVEMENT] Move unix specific features into mio::unix module
+* [IMPROVEMENT] TcpListener sets SO_REUSEADDR by default
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/Cargo.toml
@@ -0,0 +1,47 @@
+[package]
+
+name = "mio"
+version = "0.6.9"
+license = "MIT"
+authors = ["Carl Lerche <me@carllerche.com>"]
+description = "Lightweight non-blocking IO"
+documentation = "https://docs.rs/mio"
+homepage = "https://github.com/carllerche/mio"
+repository = "https://github.com/carllerche/mio"
+readme = "README.md"
+keywords = ["io", "async", "non-blocking"]
+categories = ["asynchronous"]
+exclude = [
+ ".gitignore",
+ ".travis.yml",
+ "deploy.sh",
+ "test/**/*",
+]
+
+[features]
+with-deprecated = []
+default = ["with-deprecated"]
+
+[dependencies]
+lazycell = "0.4.0"
+log = "0.3.1"
+slab = "0.3.0"
+net2 = "0.2.29"
+iovec = "0.1.0"
+
+[target.'cfg(unix)'.dependencies]
+libc = "0.2.19"
+
+[target.'cfg(windows)'.dependencies]
+winapi = "0.2.1"
+miow = "0.2.1"
+kernel32-sys = "0.2"
+
+[dev-dependencies]
+env_logger = { version = "0.3.0", default-features = false }
+tempdir = "0.3.4"
+bytes = "0.3.0"
+
+[[test]]
+name = "test"
+path = "test/mod.rs"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Carl Lerche and other MIO contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/README.md
@@ -0,0 +1,89 @@
+# Mio - Metal IO
+
+Mio is a lightweight I/O library for Rust with a focus on adding as little
+overhead as possible over the OS abstractions.
+
+[![crates.io](http://meritbadge.herokuapp.com/mio)](https://crates.io/crates/mio)
+[![Build Status](https://travis-ci.org/carllerche/mio.svg?branch=master)](https://travis-ci.org/carllerche/mio)
+[![Build status](https://ci.appveyor.com/api/projects/status/ok90r1tcgkyndnvw/branch/master?svg=true)](https://ci.appveyor.com/project/carllerche/mio/branch/master)
+
+**API documentation**
+
+* [master](http://carllerche.github.io/mio)
+* [v0.6](https://docs.rs/mio/^0.6)
+* [v0.5](https://docs.rs/mio/^0.5)
+
+This is a low level library, if you are looking for something easier to get
+started with, see [Tokio](https://tokio.rs).
+
+## Usage
+
+To use `mio`, first add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+mio = "0.6"
+```
+
+Then, add this to your crate root:
+
+```rust
+extern crate mio;
+```
+
+## Features
+
+* Event loop backed by epoll, kqueue.
+* Zero allocations at runtime
+* Non-blocking TCP, UDP and Unix domain sockets
+* High performance timer system
+* Thread safe message channel for cross thread communication
+
+## Non goals
+
+The following are specifically omitted from MIO and are left to the user
+or higher level libraries.
+
+* File operations
+* Thread pools / multi-threaded event loop
+
+## Platforms
+
+Currently supported platforms:
+
+* Linux
+* OS X
+* Windows
+* NetBSD
+* Android
+* iOS
+
+There are potentially others. If you find that Mio works on another
+platform, submit a PR to update the list!
+
+### Libraries
+
+* [tokio-core](//github.com/tokio-rs/tokio-core) - Underlying event loop
+ for the [Tokio project](//github.com/tokio-rs/tokio).
+* [mioco](//github.com/dpc/mioco) - Mio COroutines
+* [simplesched](//github.com/zonyitoo/simplesched) - Coroutine I/O with a simple scheduler
+* [coio-rs](//github.com/zonyitoo/coio-rs) - Coroutine I/O with work-stealing scheduler
+* [rotor](//github.com/tailhook/rotor) - A wrapper that allows to create composable I/O libraries on top of mio
+* [ws-rs](//github.com/housleyjk/ws-rs) - WebSockets based on Mio
+
+## Community
+
+A group of mio users hang out in the #mio channel on the Mozilla IRC
+server (irc.mozilla.org). This can be a good place to go for questions.
+
+## Contributing
+
+Interested in getting involved? We would love to help you! For simple
+bug fixes, just submit a PR with the fix and we can discuss the fix
+directly in the PR. If the fix is more complex, start with an issue.
+
+If you want to propose an API change, create an issue to start a
+discussion with the community. Also, feel free to talk with us in the
+IRC channel.
+
+Finally, be kind. We support the [Rust Code of Conduct](https://www.rust-lang.org/conduct.html).
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/appveyor.yml
@@ -0,0 +1,20 @@
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+ - TARGET: i686-pc-windows-msvc
+ - TARGET: i686-pc-windows-gnu
+
+install:
+ - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
+ - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
+ - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
+ - SET PATH=%PATH%;C:\MinGW\bin
+ - rustc -V
+ - cargo -V
+
+build: false
+
+test_script:
+ # Ensure that the build works without default features
+ - cargo build --no-default-features
+ - cargo test
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/benches/bench_poll.rs
@@ -0,0 +1,52 @@
+#![feature(test)]
+
+extern crate mio;
+extern crate test;
+
+use mio::*;
+use test::Bencher;
+use std::sync::Arc;
+use std::thread;
+
+#[bench]
+fn bench_poll(bench: &mut Bencher) {
+ const NUM: usize = 10_000;
+ const THREADS: usize = 4;
+
+ let poll = Poll::new().unwrap();
+ let mut events = Events::with_capacity(1024);
+
+ let mut registrations = vec![];
+ let mut set_readiness = vec![];
+
+ for i in 0..NUM {
+ let (r, s) = Registration::new(
+ &poll,
+ Token(i),
+ Ready::readable(),
+ PollOpt::edge());
+
+ registrations.push(r);
+ set_readiness.push(s);
+ }
+
+ let set_readiness = Arc::new(set_readiness);
+
+ bench.iter(move || {
+ for mut i in 0..THREADS {
+ let set_readiness = set_readiness.clone();
+ thread::spawn(move || {
+ while i < NUM {
+ set_readiness[i].set_readiness(Ready::readable()).unwrap();
+ i += THREADS;
+ }
+ });
+ }
+
+ let mut n = 0;
+
+ while n < NUM {
+ n += poll.poll(&mut events, None).unwrap();
+ }
+ })
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/aarch64-linux-android/Dockerfile
@@ -0,0 +1,48 @@
+FROM ubuntu:16.04
+
+
+
+
+
+RUN dpkg --add-architecture i386 && \
+ dpkg --add-architecture amd64 && \
+ apt-get update && \
+ apt-get install -y --no-install-recommends \
+ file \
+ curl \
+ ca-certificates \
+ python \
+ unzip \
+ expect \
+ openjdk-9-jre \
+ libstdc++6:i386 \
+ gcc \
+ libc6-dev \
+ qt5-default zlib1g:i386 libx11-6:i386 \
+ libpulse0:amd64 libpulse0:i386
+
+
+
+
+
+
+COPY cargo_config /etc/cargo_config
+
+WORKDIR /android/
+
+COPY install-ndk.sh /android/
+RUN sh /android/install-ndk.sh
+
+ENV PATH=$PATH:/android/ndk-arm64/bin:/android/sdk/tools:/android/sdk/tools/bin:/android/sdk/platform-tools:/android/sdk/emulator/qemu/linux-x86_64
+
+COPY install-sdk.sh /android/
+RUN sh /android/install-sdk.sh
+
+ENV PATH=$PATH:/rust/bin \
+ CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=aarch64-linux-android-gcc \
+ ANDROID_EMULATOR_FORCE_32BIT=0 \
+ HOME=/tmp
+RUN chmod 755 /android/sdk/tools/* /android/sdk/emulator/qemu/linux-x86_64/*
+
+RUN cp -r /root/.android /tmp
+RUN chmod 777 -R /tmp/.android
new file mode 100755
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/aarch64-linux-android/accept-licenses.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/expect -f
+# ignore-license
+
+set timeout 1800
+set cmd [lindex $argv 0]
+set licenses [lindex $argv 1]
+
+spawn {*}$cmd
+expect {
+ "Accept? (y/N):*" {
+ exp_send "y\r"
+ exp_continue
+ }
+ eof
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/aarch64-linux-android/cargo_config
@@ -0,0 +1,16 @@
+
+[target.aarch64-linux-android]
+ar = "/android/ndk-arm64/bin/aarch64-linux-android-ar"
+linker = "/android/ndk-arm64/bin/aarch64-linux-android-gcc"
+
+[target.arm-linux-androideabi]
+ar = "/android/ndk-arm64/bin/arm-linux-androideabi-ar"
+linker = "/android/ndk-arm64/bin/arm-linux-androideabi-gcc"
+
+[target.armv7-linux-androideabi]
+ar = "/android/ndk-arm64/bin/arm-linux-androideabi-ar"
+linker = "/android/ndk-arm64/bin/arm-linux-androideabi-gcc"
+
+[target.i686-linux-android]
+ar = "/android/ndk-arm64/bin/i686-linux-android-ar"
+linker = "/android/ndk-arm64/bin/i686-linux-android-gcc"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/aarch64-linux-android/install-ndk.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# 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.
+
+set -ex
+
+curl -O https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip
+unzip -q android-ndk-r14b-linux-x86_64.zip
+android-ndk-r14b/build/tools/make_standalone_toolchain.py \
+ --install-dir /android/ndk-arm64 \
+ --arch arm64 \
+ --api 24
+
+rm -rf ./android-ndk-r14b-linux-x86_64.zip ./android-ndk-r14b
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/aarch64-linux-android/install-sdk.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# 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.
+
+set -ex
+
+# Prep the SDK and emulator
+#
+# Note that the update process requires that we accept a bunch of licenses, and
+# we can't just pipe `yes` into it for some reason, so we take the same strategy
+# located in https://github.com/appunite/docker by just wrapping it in a script
+# which apparently magically accepts the licenses.
+
+mkdir sdk
+
+curl -o sdk-tools-linux-3859397.zip https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip && \
+ unzip sdk-tools-linux-3859397.zip && \
+ mv tools sdk/
+
+
+
+yes | sdkmanager --licenses
+sdkmanager tools platform-tools "build-tools;25.0.2" "platforms;android-24" "system-images;android-24;default;arm64-v8a"
+
+echo "no" | avdmanager create avd \
+ --force \
+ --name arm64-24 \
+ --package "system-images;android-24;default;arm64-v8a" \
+ --abi arm64-v8a \
+ --sdcard 256M
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/arm-linux-androideabi/Dockerfile
@@ -0,0 +1,37 @@
+FROM ubuntu:16.04
+
+RUN dpkg --add-architecture i386 && \
+ apt-get update && \
+ apt-get install -y --no-install-recommends \
+ file \
+ curl \
+ ca-certificates \
+ python \
+ unzip \
+ expect \
+ openjdk-9-jre \
+ libstdc++6:i386 \
+ gcc \
+ libc6-dev
+
+
+COPY cargo_config /etc/cargo_config
+
+WORKDIR /android/
+
+COPY install-ndk.sh /android/
+RUN sh /android/install-ndk.sh
+
+ENV PATH=$PATH:/android/ndk-arm/bin:/android/sdk/tools:/android/sdk/platform-tools
+
+COPY install-sdk.sh accept-licenses.sh /android/
+RUN sh /android/install-sdk.sh
+
+ENV PATH=$PATH:/rust/bin \
+ CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \
+ ANDROID_EMULATOR_FORCE_32BIT=1 \
+ HOME=/tmp
+RUN chmod 755 /android/sdk/tools/* /android/sdk/tools/qemu/linux-x86_64/* /android/sdk/tools/qemu/linux-x86/*
+
+RUN cp -r /root/.android /tmp
+RUN chmod 777 -R /tmp/.android
new file mode 100755
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/arm-linux-androideabi/accept-licenses.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/expect -f
+# ignore-license
+
+set timeout 1800
+set cmd [lindex $argv 0]
+set licenses [lindex $argv 1]
+
+spawn {*}$cmd
+expect {
+ "Do you accept the license '*'*" {
+ exp_send "y\r"
+ exp_continue
+ }
+ eof
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/arm-linux-androideabi/cargo_config
@@ -0,0 +1,16 @@
+
+[target.aarch64-linux-android]
+ar = "/android/ndk-arm/bin/aarch64-linux-android-ar"
+linker = "/android/ndk-arm/bin/aarch64-linux-android-gcc"
+
+[target.arm-linux-androideabi]
+ar = "/android/ndk-arm/bin/arm-linux-androideabi-ar"
+linker = "/android/ndk-arm/bin/arm-linux-androideabi-gcc"
+
+[target.armv7-linux-androideabi]
+ar = "/android/ndk-arm/bin/arm-linux-androideabi-ar"
+linker = "/android/ndk-arm/bin/arm-linux-androideabi-gcc"
+
+[target.i686-linux-android]
+ar = "/android/ndk-arm/bin/i686-linux-android-ar"
+linker = "/android/ndk-arm/bin/i686-linux-android-gcc"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/arm-linux-androideabi/install-ndk.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# 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.
+
+set -ex
+
+curl -O https://dl.google.com/android/repository/android-ndk-r13b-linux-x86_64.zip
+unzip -q android-ndk-r13b-linux-x86_64.zip
+android-ndk-r13b/build/tools/make_standalone_toolchain.py \
+ --install-dir /android/ndk-arm \
+ --arch arm \
+ --api 24
+
+rm -rf ./android-ndk-r13b-linux-x86_64.zip ./android-ndk-r13b
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/docker/arm-linux-androideabi/install-sdk.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# 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.
+
+set -ex
+
+# Prep the SDK and emulator
+#
+# Note that the update process requires that we accept a bunch of licenses, and
+# we can't just pipe `yes` into it for some reason, so we take the same strategy
+# located in https://github.com/appunite/docker by just wrapping it in a script
+# which apparently magically accepts the licenses.
+
+mkdir sdk
+curl https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz | \
+ tar xzf - -C sdk --strip-components=1
+
+filter="platform-tools,android-21"
+filter="$filter,sys-img-armeabi-v7a-android-21"
+
+./accept-licenses.sh "android - update sdk -a --no-ui --filter $filter"
+
+echo "no" | android create avd \
+ --name arm-21 \
+ --target android-21 \
+ --abi armeabi-v7a
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/ios/deploy_and_run_on_ios_simulator.rs
@@ -0,0 +1,202 @@
+// 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.
+
+// This is a script to deploy and execute a binary on an iOS simulator.
+// The primary use of this is to be able to run unit tests on the simulator and
+// retrieve the results.
+//
+// To do this through Cargo instead, use Dinghy
+// (https://github.com/snipsco/dinghy): cargo dinghy install, then cargo dinghy
+// test.
+
+use std::env;
+use std::fs::{self, File};
+use std::io::Write;
+use std::path::Path;
+use std::thread;
+use std::process::{self, Command, Stdio};
+
+macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+ })
+}
+
+// Step one: Wrap as an app
+fn package_as_simulator_app(crate_name: &str, test_binary_path: &Path) {
+ println!("Packaging simulator app");
+ drop(fs::remove_dir_all("ios_simulator_app"));
+ t!(fs::create_dir("ios_simulator_app"));
+ t!(fs::copy(test_binary_path,
+ Path::new("ios_simulator_app").join(crate_name)));
+
+ let mut f = t!(File::create("ios_simulator_app/Info.plist"));
+ t!(f.write_all(format!(r#"
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE plist PUBLIC
+ "-//Apple//DTD PLIST 1.0//EN"
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ <plist version="1.0">
+ <dict>
+ <key>CFBundleExecutable</key>
+ <string>{}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.rust.unittests</string>
+ </dict>
+ </plist>
+ "#, crate_name).as_bytes()));
+}
+
+// Step two: Start the iOS simulator
+fn start_simulator() {
+ println!("Looking for iOS simulator");
+ let output = t!(Command::new("xcrun").arg("simctl").arg("list").output());
+ assert!(output.status.success());
+ let mut simulator_exists = false;
+ let mut simulator_booted = false;
+ let mut found_rust_sim = false;
+ let stdout = t!(String::from_utf8(output.stdout));
+ for line in stdout.lines() {
+ if line.contains("rust_ios") {
+ if found_rust_sim {
+ panic!("Duplicate rust_ios simulators found. Please \
+ double-check xcrun simctl list.");
+ }
+ simulator_exists = true;
+ simulator_booted = line.contains("(Booted)");
+ found_rust_sim = true;
+ }
+ }
+
+ if simulator_exists == false {
+ println!("Creating iOS simulator");
+ Command::new("xcrun")
+ .arg("simctl")
+ .arg("create")
+ .arg("rust_ios")
+ .arg("com.apple.CoreSimulator.SimDeviceType.iPhone-SE")
+ .arg("com.apple.CoreSimulator.SimRuntime.iOS-10-2")
+ .check_status();
+ } else if simulator_booted == true {
+ println!("Shutting down already-booted simulator");
+ Command::new("xcrun")
+ .arg("simctl")
+ .arg("shutdown")
+ .arg("rust_ios")
+ .check_status();
+ }
+
+ println!("Starting iOS simulator");
+ // We can't uninstall the app (if present) as that will hang if the
+ // simulator isn't completely booted; just erase the simulator instead.
+ Command::new("xcrun").arg("simctl").arg("erase").arg("rust_ios").check_status();
+ Command::new("xcrun").arg("simctl").arg("boot").arg("rust_ios").check_status();
+}
+
+// Step three: Install the app
+fn install_app_to_simulator() {
+ println!("Installing app to simulator");
+ Command::new("xcrun")
+ .arg("simctl")
+ .arg("install")
+ .arg("booted")
+ .arg("ios_simulator_app/")
+ .check_status();
+}
+
+// Step four: Run the app
+fn run_app_on_simulator() {
+ use std::io::{self, Read, Write};
+
+ println!("Running app");
+ let mut child = t!(Command::new("xcrun")
+ .arg("simctl")
+ .arg("launch")
+ .arg("--console")
+ .arg("booted")
+ .arg("com.rust.unittests")
+ .arg("--color")
+ .arg("never")
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
+ .spawn());
+
+ let stdout = child.stdout.take().unwrap();
+ let stderr = child.stderr.take().unwrap();
+
+ let th = thread::spawn(move || {
+ let mut out = vec![];
+
+ for b in stdout.bytes() {
+ let b = b.unwrap();
+ out.push(b);
+ let out = [b];
+ io::stdout().write(&out[..]).unwrap();
+ }
+
+ out
+ });
+
+ thread::spawn(move || {
+ for b in stderr.bytes() {
+ let out = [b.unwrap()];
+ io::stderr().write(&out[..]).unwrap();
+ }
+ });
+
+ println!("Waiting for cmd to finish");
+ child.wait().unwrap();
+
+ println!("Waiting for stdout");
+ let stdout = th.join().unwrap();
+ let stdout = String::from_utf8_lossy(&stdout);
+ let passed = stdout.lines()
+ .find(|l| l.contains("test result"))
+ .map(|l| l.contains(" 0 failed"))
+ .unwrap_or(false);
+
+ println!("Shutting down simulator");
+ Command::new("xcrun")
+ .arg("simctl")
+ .arg("shutdown")
+ .arg("rust_ios")
+ .check_status();
+ if !passed {
+ panic!("tests didn't pass");
+ }
+}
+
+trait CheckStatus {
+ fn check_status(&mut self);
+}
+
+impl CheckStatus for Command {
+ fn check_status(&mut self) {
+ println!("\trunning: {:?}", self);
+ assert!(t!(self.status()).success());
+ }
+}
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ if args.len() != 2 {
+ println!("Usage: {} <executable>", args[0]);
+ process::exit(-1);
+ }
+
+ let test_binary_path = Path::new(&args[1]);
+ let crate_name = test_binary_path.file_name().unwrap();
+
+ package_as_simulator_app(crate_name.to_str().unwrap(), test_binary_path);
+ start_simulator();
+ install_app_to_simulator();
+ run_app_on_simulator();
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/run-docker.sh
@@ -0,0 +1,33 @@
+# Small script to run tests for a target (or all targets) inside all the
+# respective docker images.
+
+set -ex
+
+run() {
+ echo $1
+ docker build -t libc ci/docker/$1
+ mkdir -p target
+ docker run \
+ --user `id -u`:`id -g` \
+ --rm \
+ --volume $HOME/.cargo:/cargo \
+ --env CARGO_HOME=/cargo \
+ --volume `rustc --print sysroot`:/rust:ro \
+ --volume `pwd`:/checkout:ro \
+ --volume `pwd`/target:/checkout/target \
+ --env CARGO_TARGET_DIR=/checkout/target \
+ --workdir /checkout \
+ --privileged \
+ --interactive \
+ --tty \
+ libc \
+ ci/run.sh $1
+}
+
+if [ -z "$1" ]; then
+ for d in `ls ci/docker/`; do
+ run $d
+ done
+else
+ run $1
+fi
new file mode 100755
--- /dev/null
+++ b/third_party/rust/mio/ci/run-ios.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# Builds and runs tests for a particular target passed as an argument to this
+# script.
+
+set -ex
+
+TARGET=$1
+
+
+case "$TARGET" in
+ *-apple-ios)
+ # Download the iOS test harness
+ curl -vv -L https://github.com/carllerche/ios-test-harness/releases/download/v0.1.0/libiosharness-$TARGET.a > libiosharness.a;
+
+ # Build the test
+ cargo rustc --test test --target $TARGET -- \
+ -L . \
+ -C link-args="-mios-simulator-version-min=7.0 -e _ios_main -liosharness";
+
+
+ # Find the file to run
+ TEST_FILE="$(find target/$TARGET/debug -maxdepth 1 -type f -name test-* | head -1)";
+
+ rustc -O ./ci/ios/deploy_and_run_on_ios_simulator.rs;
+ ./deploy_and_run_on_ios_simulator $TEST_FILE;
+
+ ;;
+
+ *)
+ echo "unsupported target $TARGET";
+ exit 1;
+ ;;
+esac
new file mode 100755
--- /dev/null
+++ b/third_party/rust/mio/ci/run.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# Builds and runs tests for a particular target passed as an argument to this
+# script.
+
+set -ex
+
+TARGET=$1
+
+if [ -f /etc/cargo_config ] && [ -d /cargo ]; then cp -f /etc/cargo_config /cargo/config; fi
+cargo build --target=$TARGET --test test --verbose
+
+# Find the file to run
+TEST_FILE=$(find target/$TARGET/debug -maxdepth 1 -type f -perm -111 -name "test-*" | head -1)
+
+case "$TARGET" in
+ arm-linux-androideabi)
+ # Use the 64bit emulator
+ emulator64-arm @arm-21 -no-window &
+ adb wait-for-device
+ adb push $TEST_FILE /data/mio-test
+ adb shell /data/mio-test 2>&1 | tee /tmp/out
+ grep "^test result.* 0 failed" /tmp/out
+ ;;
+
+ aarch64-linux-android)
+ # Use the 64bit emulator
+ export LD_LIBRARY_PATH="/android/sdk/emulator/lib64/qt/lib:/usr/lib/x86_64-linux-gnu"
+ qemu-system-aarch64 @arm64-24 -memory 768 -accel off -gpu off -no-skin -no-window -no-audio -no-snapshot-load -no-snapshot-save &
+ adb wait-for-device
+ adb root
+ adb push $TEST_FILE /data/mio-test
+ #adb unroot
+ adb shell chmod 755 /data/mio-test
+ adb shell /data/mio-test 2>&1 | tee /tmp/out
+ grep "^test result.* 0 failed" /tmp/out
+ ;;
+
+ *)
+ exit 1;
+ ;;
+esac
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/trust/install.sh
@@ -0,0 +1,31 @@
+set -ex
+
+main() {
+ curl https://sh.rustup.rs -sSf | \
+ sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
+
+ local target=
+ if [ $TRAVIS_OS_NAME = linux ]; then
+ target=x86_64-unknown-linux-gnu
+ sort=sort
+ else
+ target=x86_64-apple-darwin
+ sort=gsort # for `sort --sort-version`, from brew's coreutils.
+ fi
+
+ # This fetches latest stable release
+ local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
+ | cut -d/ -f3 \
+ | grep -E '^v[0-9.]+$' \
+ | $sort --version-sort \
+ | tail -n1)
+ echo cross version: $tag
+ curl -LSfs https://japaric.github.io/trust/install.sh | \
+ sh -s -- \
+ --force \
+ --git japaric/cross \
+ --tag $tag \
+ --target $target
+}
+
+main
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/ci/trust/script.sh
@@ -0,0 +1,19 @@
+# This script takes care of testing your crate
+
+set -ex
+
+# TODO This is the "test phase", tweak it as you see fit
+main() {
+ cross build --target $TARGET
+
+ if [ ! -z $DISABLE_TESTS ]; then
+ return
+ fi
+
+ cross test --target $TARGET
+}
+
+# we don't run the "test phase" when doing deploys
+if [ -z $TRAVIS_TAG ]; then
+ main
+fi
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/channel.rs
@@ -0,0 +1,389 @@
+//! Thread safe communication channel implementing `Evented`
+
+#![allow(unused_imports, deprecated, missing_debug_implementations)]
+
+use {io, Evented, Ready, Poll, PollOpt, Registration, SetReadiness, Token};
+use lazycell::{LazyCell, AtomicLazyCell};
+use std::any::Any;
+use std::fmt;
+use std::error;
+use std::sync::{mpsc, Arc};
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+/// Creates a new asynchronous channel, where the `Receiver` can be registered
+/// with `Poll`.
+pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
+ let (tx_ctl, rx_ctl) = ctl_pair();
+ let (tx, rx) = mpsc::channel();
+
+ let tx = Sender {
+ tx: tx,
+ ctl: tx_ctl,
+ };
+
+ let rx = Receiver {
+ rx: rx,
+ ctl: rx_ctl,
+ };
+
+ (tx, rx)
+}
+
+/// Creates a new synchronous, bounded channel where the `Receiver` can be
+/// registered with `Poll`.
+pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
+ let (tx_ctl, rx_ctl) = ctl_pair();
+ let (tx, rx) = mpsc::sync_channel(bound);
+
+ let tx = SyncSender {
+ tx: tx,
+ ctl: tx_ctl,
+ };
+
+ let rx = Receiver {
+ rx: rx,
+ ctl: rx_ctl,
+ };
+
+ (tx, rx)
+}
+
+pub fn ctl_pair() -> (SenderCtl, ReceiverCtl) {
+ let inner = Arc::new(Inner {
+ pending: AtomicUsize::new(0),
+ senders: AtomicUsize::new(1),
+ set_readiness: AtomicLazyCell::new(),
+ });
+
+ let tx = SenderCtl {
+ inner: inner.clone(),
+ };
+
+ let rx = ReceiverCtl {
+ registration: LazyCell::new(),
+ inner: inner,
+ };
+
+ (tx, rx)
+}
+
+/// Tracks messages sent on a channel in order to update readiness.
+pub struct SenderCtl {
+ inner: Arc<Inner>,
+}
+
+/// Tracks messages received on a channel in order to track readiness.
+pub struct ReceiverCtl {
+ registration: LazyCell<Registration>,
+ inner: Arc<Inner>,
+}
+
+pub struct Sender<T> {
+ tx: mpsc::Sender<T>,
+ ctl: SenderCtl,
+}
+
+pub struct SyncSender<T> {
+ tx: mpsc::SyncSender<T>,
+ ctl: SenderCtl,
+}
+
+pub struct Receiver<T> {
+ rx: mpsc::Receiver<T>,
+ ctl: ReceiverCtl,
+}
+
+pub enum SendError<T> {
+ Io(io::Error),
+ Disconnected(T),
+}
+
+pub enum TrySendError<T> {
+ Io(io::Error),
+ Full(T),
+ Disconnected(T),
+}
+
+struct Inner {
+ // The number of outstanding messages for the receiver to read
+ pending: AtomicUsize,
+ // The number of sender handles
+ senders: AtomicUsize,
+ // The set readiness handle
+ set_readiness: AtomicLazyCell<SetReadiness>,
+}
+
+impl<T> Sender<T> {
+ pub fn send(&self, t: T) -> Result<(), SendError<T>> {
+ self.tx.send(t)
+ .map_err(SendError::from)
+ .and_then(|_| {
+ try!(self.ctl.inc());
+ Ok(())
+ })
+ }
+}
+
+impl<T> Clone for Sender<T> {
+ fn clone(&self) -> Sender<T> {
+ Sender {
+ tx: self.tx.clone(),
+ ctl: self.ctl.clone(),
+ }
+ }
+}
+
+impl<T> SyncSender<T> {
+ pub fn send(&self, t: T) -> Result<(), SendError<T>> {
+ self.tx.send(t)
+ .map_err(From::from)
+ .and_then(|_| {
+ try!(self.ctl.inc());
+ Ok(())
+ })
+ }
+
+ pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
+ self.tx.try_send(t)
+ .map_err(From::from)
+ .and_then(|_| {
+ try!(self.ctl.inc());
+ Ok(())
+ })
+ }
+}
+
+impl<T> Clone for SyncSender<T> {
+ fn clone(&self) -> SyncSender<T> {
+ SyncSender {
+ tx: self.tx.clone(),
+ ctl: self.ctl.clone(),
+ }
+ }
+}
+
+impl<T> Receiver<T> {
+ pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
+ self.rx.try_recv().and_then(|res| {
+ let _ = self.ctl.dec();
+ Ok(res)
+ })
+ }
+}
+
+impl<T> Evented for Receiver<T> {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.ctl.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.ctl.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.ctl.deregister(poll)
+ }
+}
+
+/*
+ *
+ * ===== SenderCtl / ReceiverCtl =====
+ *
+ */
+
+impl SenderCtl {
+ /// Call to track that a message has been sent
+ pub fn inc(&self) -> io::Result<()> {
+ let cnt = self.inner.pending.fetch_add(1, Ordering::Acquire);
+
+ if 0 == cnt {
+ // Toggle readiness to readable
+ if let Some(set_readiness) = self.inner.set_readiness.borrow() {
+ try!(set_readiness.set_readiness(Ready::readable()));
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl Clone for SenderCtl {
+ fn clone(&self) -> SenderCtl {
+ self.inner.senders.fetch_add(1, Ordering::Relaxed);
+ SenderCtl { inner: self.inner.clone() }
+ }
+}
+
+impl Drop for SenderCtl {
+ fn drop(&mut self) {
+ if self.inner.senders.fetch_sub(1, Ordering::Release) == 1 {
+ let _ = self.inc();
+ }
+ }
+}
+
+impl ReceiverCtl {
+ pub fn dec(&self) -> io::Result<()> {
+ let first = self.inner.pending.load(Ordering::Acquire);
+
+ if first == 1 {
+ // Unset readiness
+ if let Some(set_readiness) = self.inner.set_readiness.borrow() {
+ try!(set_readiness.set_readiness(Ready::empty()));
+ }
+ }
+
+ // Decrement
+ let second = self.inner.pending.fetch_sub(1, Ordering::AcqRel);
+
+ if first == 1 && second > 1 {
+ // There are still pending messages. Since readiness was
+ // previously unset, it must be reset here
+ if let Some(set_readiness) = self.inner.set_readiness.borrow() {
+ try!(set_readiness.set_readiness(Ready::readable()));
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl Evented for ReceiverCtl {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ if self.registration.borrow().is_some() {
+ return Err(io::Error::new(io::ErrorKind::Other, "receiver already registered"));
+ }
+
+ let (registration, set_readiness) = Registration::new(poll, token, interest, opts);
+
+
+ if self.inner.pending.load(Ordering::Relaxed) > 0 {
+ // TODO: Don't drop readiness
+ let _ = set_readiness.set_readiness(Ready::readable());
+ }
+
+ self.registration.fill(registration).ok().expect("unexpected state encountered");
+ self.inner.set_readiness.fill(set_readiness).ok().expect("unexpected state encountered");
+
+ Ok(())
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ match self.registration.borrow() {
+ Some(registration) => registration.update(poll, token, interest, opts),
+ None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
+ }
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ match self.registration.borrow() {
+ Some(registration) => registration.deregister(poll),
+ None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
+ }
+ }
+}
+
+/*
+ *
+ * ===== Error conversions =====
+ *
+ */
+
+impl<T> From<mpsc::SendError<T>> for SendError<T> {
+ fn from(src: mpsc::SendError<T>) -> SendError<T> {
+ SendError::Disconnected(src.0)
+ }
+}
+
+impl<T> From<io::Error> for SendError<T> {
+ fn from(src: io::Error) -> SendError<T> {
+ SendError::Io(src)
+ }
+}
+
+impl<T> From<mpsc::TrySendError<T>> for TrySendError<T> {
+ fn from(src: mpsc::TrySendError<T>) -> TrySendError<T> {
+ match src {
+ mpsc::TrySendError::Full(v) => TrySendError::Full(v),
+ mpsc::TrySendError::Disconnected(v) => TrySendError::Disconnected(v),
+ }
+ }
+}
+
+impl<T> From<mpsc::SendError<T>> for TrySendError<T> {
+ fn from(src: mpsc::SendError<T>) -> TrySendError<T> {
+ TrySendError::Disconnected(src.0)
+ }
+}
+
+impl<T> From<io::Error> for TrySendError<T> {
+ fn from(src: io::Error) -> TrySendError<T> {
+ TrySendError::Io(src)
+ }
+}
+
+/*
+ *
+ * ===== Implement Error, Debug and Display for Errors =====
+ *
+ */
+
+impl<T: Any> error::Error for SendError<T> {
+ fn description(&self) -> &str {
+ match self {
+ &SendError::Io(ref io_err) => io_err.description(),
+ &SendError::Disconnected(..) => "Disconnected",
+ }
+ }
+}
+
+impl<T: Any> error::Error for TrySendError<T> {
+ fn description(&self) -> &str {
+ match self {
+ &TrySendError::Io(ref io_err) => io_err.description(),
+ &TrySendError::Full(..) => "Full",
+ &TrySendError::Disconnected(..) => "Disconnected",
+ }
+ }
+}
+
+impl<T> fmt::Debug for SendError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ format_send_error(self, f)
+ }
+}
+
+impl<T> fmt::Display for SendError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ format_send_error(self, f)
+ }
+}
+
+impl<T> fmt::Debug for TrySendError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ format_try_send_error(self, f)
+ }
+}
+
+impl<T> fmt::Display for TrySendError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ format_try_send_error(self, f)
+ }
+}
+
+#[inline]
+fn format_send_error<T>(e: &SendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
+ match e {
+ &SendError::Io(ref io_err) => write!(f, "{}", io_err),
+ &SendError::Disconnected(..) => write!(f, "Disconnected"),
+ }
+}
+
+#[inline]
+fn format_try_send_error<T>(e: &TrySendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
+ match e {
+ &TrySendError::Io(ref io_err) => write!(f, "{}", io_err),
+ &TrySendError::Full(..) => write!(f, "Full"),
+ &TrySendError::Disconnected(..) => write!(f, "Disconnected"),
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/deprecated/event_loop.rs
@@ -0,0 +1,396 @@
+use {channel, Evented, Poll, Events, Token};
+use deprecated::{Handler, NotifyError};
+use event_imp::{Event, Ready, PollOpt};
+use timer::{self, Timer, Timeout};
+use std::{io, fmt, usize};
+use std::default::Default;
+use std::time::Duration;
+
+#[derive(Debug, Default, Clone)]
+pub struct EventLoopBuilder {
+ config: Config,
+}
+
+/// `EventLoop` configuration details
+#[derive(Clone, Debug)]
+struct Config {
+ // == Notifications ==
+ notify_capacity: usize,
+ messages_per_tick: usize,
+
+ // == Timer ==
+ timer_tick: Duration,
+ timer_wheel_size: usize,
+ timer_capacity: usize,
+}
+
+impl Default for Config {
+ fn default() -> Config {
+ // Default EventLoop configuration values
+ Config {
+ notify_capacity: 4_096,
+ messages_per_tick: 256,
+ timer_tick: Duration::from_millis(100),
+ timer_wheel_size: 1_024,
+ timer_capacity: 65_536,
+ }
+ }
+}
+
+impl EventLoopBuilder {
+ /// Construct a new `EventLoopBuilder` with the default configuration
+ /// values.
+ pub fn new() -> EventLoopBuilder {
+ EventLoopBuilder::default()
+ }
+
+ /// Sets the maximum number of messages that can be buffered on the event
+ /// loop's notification channel before a send will fail.
+ ///
+ /// The default value for this is 4096.
+ pub fn notify_capacity(&mut self, capacity: usize) -> &mut Self {
+ self.config.notify_capacity = capacity;
+ self
+ }
+
+ /// Sets the maximum number of messages that can be processed on any tick of
+ /// the event loop.
+ ///
+ /// The default value for this is 256.
+ pub fn messages_per_tick(&mut self, messages: usize) -> &mut Self {
+ self.config.messages_per_tick = messages;
+ self
+ }
+
+ pub fn timer_tick(&mut self, val: Duration) -> &mut Self {
+ self.config.timer_tick = val;
+ self
+ }
+
+ pub fn timer_wheel_size(&mut self, size: usize) -> &mut Self {
+ self.config.timer_wheel_size = size;
+ self
+ }
+
+ pub fn timer_capacity(&mut self, cap: usize) -> &mut Self {
+ self.config.timer_capacity = cap;
+ self
+ }
+
+ /// Constructs a new `EventLoop` using the configured values. The
+ /// `EventLoop` will not be running.
+ pub fn build<H: Handler>(self) -> io::Result<EventLoop<H>> {
+ EventLoop::configured(self.config)
+ }
+}
+
+/// Single threaded IO event loop.
+pub struct EventLoop<H: Handler> {
+ run: bool,
+ poll: Poll,
+ events: Events,
+ timer: Timer<H::Timeout>,
+ notify_tx: channel::SyncSender<H::Message>,
+ notify_rx: channel::Receiver<H::Message>,
+ config: Config,
+}
+
+// Token used to represent notifications
+const NOTIFY: Token = Token(usize::MAX - 1);
+const TIMER: Token = Token(usize::MAX - 2);
+
+impl<H: Handler> EventLoop<H> {
+
+ /// Constructs a new `EventLoop` using the default configuration values.
+ /// The `EventLoop` will not be running.
+ pub fn new() -> io::Result<EventLoop<H>> {
+ EventLoop::configured(Config::default())
+ }
+
+ fn configured(config: Config) -> io::Result<EventLoop<H>> {
+ // Create the IO poller
+ let poll = try!(Poll::new());
+
+ let timer = timer::Builder::default()
+ .tick_duration(config.timer_tick)
+ .num_slots(config.timer_wheel_size)
+ .capacity(config.timer_capacity)
+ .build();
+
+ // Create cross thread notification queue
+ let (tx, rx) = channel::sync_channel(config.notify_capacity);
+
+ // Register the notification wakeup FD with the IO poller
+ try!(poll.register(&rx, NOTIFY, Ready::readable(), PollOpt::edge() | PollOpt::oneshot()));
+ try!(poll.register(&timer, TIMER, Ready::readable(), PollOpt::edge()));
+
+ Ok(EventLoop {
+ run: true,
+ poll: poll,
+ timer: timer,
+ notify_tx: tx,
+ notify_rx: rx,
+ config: config,
+ events: Events::with_capacity(1024),
+ })
+ }
+
+ /// Returns a sender that allows sending messages to the event loop in a
+ /// thread-safe way, waking up the event loop if needed.
+ ///
+ /// # Example
+ /// ```
+ /// use std::thread;
+ /// use mio::deprecated::{EventLoop, Handler};
+ ///
+ /// struct MyHandler;
+ ///
+ /// impl Handler for MyHandler {
+ /// type Timeout = ();
+ /// type Message = u32;
+ ///
+ /// fn notify(&mut self, event_loop: &mut EventLoop<MyHandler>, msg: u32) {
+ /// assert_eq!(msg, 123);
+ /// event_loop.shutdown();
+ /// }
+ /// }
+ ///
+ /// let mut event_loop = EventLoop::new().unwrap();
+ /// let sender = event_loop.channel();
+ ///
+ /// // Send the notification from another thread
+ /// thread::spawn(move || {
+ /// let _ = sender.send(123);
+ /// });
+ ///
+ /// let _ = event_loop.run(&mut MyHandler);
+ /// ```
+ ///
+ /// # Implementation Details
+ ///
+ /// Each [EventLoop](#) contains a lock-free queue with a pre-allocated
+ /// buffer size. The size can be changed by modifying
+ /// [EventLoopConfig.notify_capacity](struct.EventLoopConfig.html#method.notify_capacity).
+ /// When a message is sent to the EventLoop, it is first pushed on to the
+ /// queue. Then, if the EventLoop is currently running, an atomic flag is
+ /// set to indicate that the next loop iteration should be started without
+ /// waiting.
+ ///
+ /// If the loop is blocked waiting for IO events, then it is woken up. The
+ /// strategy for waking up the event loop is platform dependent. For
+ /// example, on a modern Linux OS, eventfd is used. On older OSes, a pipe
+ /// is used.
+ ///
+ /// The strategy of setting an atomic flag if the event loop is not already
+ /// sleeping allows avoiding an expensive wakeup operation if at all possible.
+ pub fn channel(&self) -> Sender<H::Message> {
+ Sender::new(self.notify_tx.clone())
+ }
+
+ /// Schedules a timeout after the requested time interval. When the
+ /// duration has been reached,
+ /// [Handler::timeout](trait.Handler.html#method.timeout) will be invoked
+ /// passing in the supplied token.
+ ///
+ /// Returns a handle to the timeout that can be used to cancel the timeout
+ /// using [#clear_timeout](#method.clear_timeout).
+ ///
+ /// # Example
+ /// ```
+ /// use mio::deprecated::{EventLoop, Handler};
+ /// use std::time::Duration;
+ ///
+ /// struct MyHandler;
+ ///
+ /// impl Handler for MyHandler {
+ /// type Timeout = u32;
+ /// type Message = ();
+ ///
+ /// fn timeout(&mut self, event_loop: &mut EventLoop<MyHandler>, timeout: u32) {
+ /// assert_eq!(timeout, 123);
+ /// event_loop.shutdown();
+ /// }
+ /// }
+ ///
+ ///
+ /// let mut event_loop = EventLoop::new().unwrap();
+ /// let timeout = event_loop.timeout(123, Duration::from_millis(300)).unwrap();
+ /// let _ = event_loop.run(&mut MyHandler);
+ /// ```
+ pub fn timeout(&mut self, token: H::Timeout, delay: Duration) -> timer::Result<Timeout> {
+ self.timer.set_timeout(delay, token)
+ }
+
+ /// If the supplied timeout has not been triggered, cancel it such that it
+ /// will not be triggered in the future.
+ pub fn clear_timeout(&mut self, timeout: &Timeout) -> bool {
+ self.timer.cancel_timeout(&timeout).is_some()
+ }
+
+ /// Tells the event loop to exit after it is done handling all events in the
+ /// current iteration.
+ pub fn shutdown(&mut self) {
+ self.run = false;
+ }
+
+ /// Indicates whether the event loop is currently running. If it's not it has either
+ /// stopped or is scheduled to stop on the next tick.
+ pub fn is_running(&self) -> bool {
+ self.run
+ }
+
+ /// Registers an IO handle with the event loop.
+ pub fn register<E: ?Sized>(&mut self, io: &E, token: Token, interest: Ready, opt: PollOpt) -> io::Result<()>
+ where E: Evented
+ {
+ self.poll.register(io, token, interest, opt)
+ }
+
+ /// Re-Registers an IO handle with the event loop.
+ pub fn reregister<E: ?Sized>(&mut self, io: &E, token: Token, interest: Ready, opt: PollOpt) -> io::Result<()>
+ where E: Evented
+ {
+ self.poll.reregister(io, token, interest, opt)
+ }
+
+ /// Keep spinning the event loop indefinitely, and notify the handler whenever
+ /// any of the registered handles are ready.
+ pub fn run(&mut self, handler: &mut H) -> io::Result<()> {
+ self.run = true;
+
+ while self.run {
+ // Execute ticks as long as the event loop is running
+ try!(self.run_once(handler, None));
+ }
+
+ Ok(())
+ }
+
+ /// Deregisters an IO handle with the event loop.
+ ///
+ /// Both kqueue and epoll will automatically clear any pending events when closing a
+ /// file descriptor (socket). In that case, this method does not need to be called
+ /// prior to dropping a connection from the slab.
+ ///
+ /// Warning: kqueue effectively builds in deregister when using edge-triggered mode with
+ /// oneshot. Calling `deregister()` on the socket will cause a TcpStream error.
+ pub fn deregister<E: ?Sized>(&mut self, io: &E) -> io::Result<()> where E: Evented {
+ self.poll.deregister(io)
+ }
+
+ /// Spin the event loop once, with a given timeout (forever if `None`),
+ /// and notify the handler if any of the registered handles become ready
+ /// during that time.
+ pub fn run_once(&mut self, handler: &mut H, timeout: Option<Duration>) -> io::Result<()> {
+ trace!("event loop tick");
+
+ // Check the registered IO handles for any new events. Each poll
+ // is for one second, so a shutdown request can last as long as
+ // one second before it takes effect.
+ let events = match self.io_poll(timeout) {
+ Ok(e) => e,
+ Err(err) => {
+ if err.kind() == io::ErrorKind::Interrupted {
+ handler.interrupted(self);
+ 0
+ } else {
+ return Err(err);
+ }
+ }
+ };
+
+ self.io_process(handler, events);
+ handler.tick(self);
+ Ok(())
+ }
+
+ #[inline]
+ fn io_poll(&mut self, timeout: Option<Duration>) -> io::Result<usize> {
+ self.poll.poll(&mut self.events, timeout)
+ }
+
+ // Process IO events that have been previously polled
+ fn io_process(&mut self, handler: &mut H, cnt: usize) {
+ let mut i = 0;
+
+ trace!("io_process(..); cnt={}; len={}", cnt, self.events.len());
+
+ // Iterate over the notifications. Each event provides the token
+ // it was registered with (which usually represents, at least, the
+ // handle that the event is about) as well as information about
+ // what kind of event occurred (readable, writable, signal, etc.)
+ while i < cnt {
+ let evt = self.events.get(i).unwrap();
+
+ trace!("event={:?}; idx={:?}", evt, i);
+
+ match evt.token() {
+ NOTIFY => self.notify(handler),
+ TIMER => self.timer_process(handler),
+ _ => self.io_event(handler, evt)
+ }
+
+ i += 1;
+ }
+ }
+
+ fn io_event(&mut self, handler: &mut H, evt: Event) {
+ handler.ready(self, evt.token(), evt.kind());
+ }
+
+ fn notify(&mut self, handler: &mut H) {
+ for _ in 0..self.config.messages_per_tick {
+ match self.notify_rx.try_recv() {
+ Ok(msg) => handler.notify(self, msg),
+ _ => break,
+ }
+ }
+
+ // Re-register
+ let _ = self.poll.reregister(&self.notify_rx, NOTIFY, Ready::readable(), PollOpt::edge() | PollOpt::oneshot());
+ }
+
+ fn timer_process(&mut self, handler: &mut H) {
+ while let Some(t) = self.timer.poll() {
+ handler.timeout(self, t);
+ }
+ }
+}
+
+impl<H: Handler> fmt::Debug for EventLoop<H> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("EventLoop")
+ .field("run", &self.run)
+ .field("poll", &self.poll)
+ .field("config", &self.config)
+ .finish()
+ }
+}
+
+/// Sends messages to the EventLoop from other threads.
+pub struct Sender<M> {
+ tx: channel::SyncSender<M>
+}
+
+impl<M> fmt::Debug for Sender<M> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "Sender<?> {{ ... }}")
+ }
+}
+
+impl<M> Clone for Sender <M> {
+ fn clone(&self) -> Sender<M> {
+ Sender { tx: self.tx.clone() }
+ }
+}
+
+impl<M> Sender<M> {
+ fn new(tx: channel::SyncSender<M>) -> Sender<M> {
+ Sender { tx: tx }
+ }
+
+ pub fn send(&self, msg: M) -> Result<(), NotifyError<M>> {
+ try!(self.tx.try_send(msg));
+ Ok(())
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/deprecated/handler.rs
@@ -0,0 +1,37 @@
+use {Ready, Token};
+use deprecated::{EventLoop};
+
+#[allow(unused_variables)]
+pub trait Handler: Sized {
+ type Timeout;
+ type Message;
+
+ /// Invoked when the socket represented by `token` is ready to be operated
+ /// on. `events` indicates the specific operations that are
+ /// ready to be performed.
+ ///
+ /// For example, when a TCP socket is ready to be read from, `events` will
+ /// have `readable` set. When the socket is ready to be written to,
+ /// `events` will have `writable` set.
+ ///
+ /// This function will only be invoked a single time per socket per event
+ /// loop tick.
+ fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: Ready) {
+ }
+
+ /// Invoked when a message has been received via the event loop's channel.
+ fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Self::Message) {
+ }
+
+ /// Invoked when a timeout has completed.
+ fn timeout(&mut self, event_loop: &mut EventLoop<Self>, timeout: Self::Timeout) {
+ }
+
+ /// Invoked when `EventLoop` has been interrupted by a signal interrupt.
+ fn interrupted(&mut self, event_loop: &mut EventLoop<Self>) {
+ }
+
+ /// Invoked at the end of an event loop tick.
+ fn tick(&mut self, event_loop: &mut EventLoop<Self>) {
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/deprecated/io.rs
@@ -0,0 +1,28 @@
+use ::io::MapNonBlock;
+use std::io::{self, Read, Write};
+
+pub trait TryRead {
+ fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>>;
+}
+
+pub trait TryWrite {
+ fn try_write(&mut self, buf: &[u8]) -> io::Result<Option<usize>>;
+}
+
+impl<T: Read> TryRead for T {
+ fn try_read(&mut self, dst: &mut [u8]) -> io::Result<Option<usize>> {
+ self.read(dst).map_non_block()
+ }
+}
+
+impl<T: Write> TryWrite for T {
+ fn try_write(&mut self, src: &[u8]) -> io::Result<Option<usize>> {
+ self.write(src).map_non_block()
+ }
+}
+
+pub trait TryAccept {
+ type Output;
+
+ fn accept(&self) -> io::Result<Option<Self::Output>>;
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/deprecated/mod.rs
@@ -0,0 +1,36 @@
+#![allow(deprecated)]
+
+mod event_loop;
+mod io;
+mod handler;
+mod notify;
+
+#[cfg(unix)]
+pub mod unix;
+
+pub use self::event_loop::{
+ EventLoop,
+ EventLoopBuilder,
+ Sender,
+};
+pub use self::io::{
+ TryAccept,
+ TryRead,
+ TryWrite,
+};
+pub use self::handler::{
+ Handler,
+};
+pub use self::notify::{
+ NotifyError,
+};
+#[cfg(unix)]
+pub use self::unix::{
+ pipe,
+ PipeReader,
+ PipeWriter,
+ UnixListener,
+ UnixSocket,
+ UnixStream,
+ Shutdown,
+};
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/deprecated/notify.rs
@@ -0,0 +1,63 @@
+use {channel};
+use std::{fmt, io, error, any};
+
+pub enum NotifyError<T> {
+ Io(io::Error),
+ Full(T),
+ Closed(Option<T>),
+}
+
+impl<M> fmt::Debug for NotifyError<M> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ NotifyError::Io(ref e) => {
+ write!(fmt, "NotifyError::Io({:?})", e)
+ }
+ NotifyError::Full(..) => {
+ write!(fmt, "NotifyError::Full(..)")
+ }
+ NotifyError::Closed(..) => {
+ write!(fmt, "NotifyError::Closed(..)")
+ }
+ }
+ }
+}
+
+impl<M> fmt::Display for NotifyError<M> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ NotifyError::Io(ref e) => {
+ write!(fmt, "IO error: {}", e)
+ }
+ NotifyError::Full(..) => write!(fmt, "Full"),
+ NotifyError::Closed(..) => write!(fmt, "Closed")
+ }
+ }
+}
+
+impl<M: any::Any> error::Error for NotifyError<M> {
+ fn description(&self) -> &str {
+ match *self {
+ NotifyError::Io(ref err) => err.description(),
+ NotifyError::Closed(..) => "The receiving end has hung up",
+ NotifyError::Full(..) => "Queue is full"
+ }
+ }
+
+ fn cause(&self) -> Option<&error::Error> {
+ match *self {
+ NotifyError::Io(ref err) => Some(err),
+ _ => None
+ }
+ }
+}
+
+impl<M> From<channel::TrySendError<M>> for NotifyError<M> {
+ fn from(src: channel::TrySendError<M>) -> NotifyError<M> {
+ match src {
+ channel::TrySendError::Io(e) => NotifyError::Io(e),
+ channel::TrySendError::Full(v) => NotifyError::Full(v),
+ channel::TrySendError::Disconnected(v) => NotifyError::Closed(Some(v)),
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/deprecated/unix.rs
@@ -0,0 +1,422 @@
+use {io, sys, Evented, Ready, Poll, PollOpt, Token};
+use deprecated::TryAccept;
+use io::MapNonBlock;
+use std::io::{Read, Write};
+use std::path::Path;
+pub use std::net::Shutdown;
+use std::process;
+
+pub use sys::Io;
+
+#[derive(Debug)]
+pub struct UnixSocket {
+ sys: sys::UnixSocket,
+}
+
+impl UnixSocket {
+ /// Returns a new, unbound, non-blocking Unix domain socket
+ pub fn stream() -> io::Result<UnixSocket> {
+ sys::UnixSocket::stream()
+ .map(From::from)
+ }
+
+ /// Connect the socket to the specified address
+ pub fn connect<P: AsRef<Path> + ?Sized>(self, addr: &P) -> io::Result<(UnixStream, bool)> {
+ let complete = match self.sys.connect(addr) {
+ Ok(()) => true,
+ Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => false,
+ Err(e) => return Err(e),
+ };
+ Ok((From::from(self.sys), complete))
+ }
+
+ /// Bind the socket to the specified address
+ pub fn bind<P: AsRef<Path> + ?Sized>(&self, addr: &P) -> io::Result<()> {
+ self.sys.bind(addr)
+ }
+
+ /// Listen for incoming requests
+ pub fn listen(self, backlog: usize) -> io::Result<UnixListener> {
+ try!(self.sys.listen(backlog));
+ Ok(From::from(self.sys))
+ }
+
+ pub fn try_clone(&self) -> io::Result<UnixSocket> {
+ self.sys.try_clone()
+ .map(From::from)
+ }
+}
+
+impl Evented for UnixSocket {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.sys.deregister(poll)
+ }
+}
+
+impl From<sys::UnixSocket> for UnixSocket {
+ fn from(sys: sys::UnixSocket) -> UnixSocket {
+ UnixSocket { sys: sys }
+ }
+}
+
+/*
+ *
+ * ===== UnixStream =====
+ *
+ */
+
+#[derive(Debug)]
+pub struct UnixStream {
+ sys: sys::UnixSocket,
+}
+
+impl UnixStream {
+ pub fn connect<P: AsRef<Path> + ?Sized>(path: &P) -> io::Result<UnixStream> {
+ UnixSocket::stream()
+ .and_then(|sock| sock.connect(path))
+ .map(|(sock, _)| sock)
+ }
+
+ pub fn try_clone(&self) -> io::Result<UnixStream> {
+ self.sys.try_clone()
+ .map(From::from)
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<usize> {
+ self.sys.shutdown(how).map(|_| 0)
+ }
+
+ pub fn read_recv_fd(&mut self, buf: &mut [u8]) -> io::Result<(usize, Option<RawFd>)> {
+ self.sys.read_recv_fd(buf)
+ }
+
+ pub fn try_read_recv_fd(&mut self, buf: &mut [u8]) -> io::Result<Option<(usize, Option<RawFd>)>> {
+ self.read_recv_fd(buf).map_non_block()
+ }
+
+ pub fn write_send_fd(&mut self, buf: &[u8], fd: RawFd) -> io::Result<usize> {
+ self.sys.write_send_fd(buf, fd)
+ }
+
+ pub fn try_write_send_fd(&mut self, buf: &[u8], fd: RawFd) -> io::Result<Option<usize>> {
+ self.write_send_fd(buf, fd).map_non_block()
+ }
+}
+
+impl Read for UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.sys.read(buf)
+ }
+}
+
+impl Write for UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.sys.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.sys.flush()
+ }
+}
+
+impl Evented for UnixStream {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.sys.deregister(poll)
+ }
+}
+
+impl From<sys::UnixSocket> for UnixStream {
+ fn from(sys: sys::UnixSocket) -> UnixStream {
+ UnixStream { sys: sys }
+ }
+}
+
+/*
+ *
+ * ===== UnixListener =====
+ *
+ */
+
+#[derive(Debug)]
+pub struct UnixListener {
+ sys: sys::UnixSocket,
+}
+
+impl UnixListener {
+ pub fn bind<P: AsRef<Path> + ?Sized>(addr: &P) -> io::Result<UnixListener> {
+ UnixSocket::stream().and_then(|sock| {
+ try!(sock.bind(addr));
+ sock.listen(256)
+ })
+ }
+
+ pub fn accept(&self) -> io::Result<UnixStream> {
+ self.sys.accept().map(From::from)
+ }
+
+ pub fn try_clone(&self) -> io::Result<UnixListener> {
+ self.sys.try_clone().map(From::from)
+ }
+}
+
+impl Evented for UnixListener {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.sys.deregister(poll)
+ }
+}
+
+impl TryAccept for UnixListener {
+ type Output = UnixStream;
+
+ fn accept(&self) -> io::Result<Option<UnixStream>> {
+ UnixListener::accept(self).map_non_block()
+ }
+}
+
+impl From<sys::UnixSocket> for UnixListener {
+ fn from(sys: sys::UnixSocket) -> UnixListener {
+ UnixListener { sys: sys }
+ }
+}
+
+/*
+ *
+ * ===== Pipe =====
+ *
+ */
+
+pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
+ let (rd, wr) = try!(sys::pipe());
+ Ok((From::from(rd), From::from(wr)))
+}
+
+#[derive(Debug)]
+pub struct PipeReader {
+ io: Io,
+}
+
+impl PipeReader {
+ pub fn from_stdout(stdout: process::ChildStdout) -> io::Result<Self> {
+ match sys::set_nonblock(stdout.as_raw_fd()) {
+ Err(e) => return Err(e),
+ _ => {},
+ }
+ return Ok(PipeReader::from(unsafe { Io::from_raw_fd(stdout.into_raw_fd()) }));
+ }
+ pub fn from_stderr(stderr: process::ChildStderr) -> io::Result<Self> {
+ match sys::set_nonblock(stderr.as_raw_fd()) {
+ Err(e) => return Err(e),
+ _ => {},
+ }
+ return Ok(PipeReader::from(unsafe { Io::from_raw_fd(stderr.into_raw_fd()) }));
+ }
+}
+
+impl Read for PipeReader {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.io.read(buf)
+ }
+}
+
+impl<'a> Read for &'a PipeReader {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (&self.io).read(buf)
+ }
+}
+
+impl Evented for PipeReader {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.io.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.io.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.io.deregister(poll)
+ }
+}
+
+impl From<Io> for PipeReader {
+ fn from(io: Io) -> PipeReader {
+ PipeReader { io: io }
+ }
+}
+
+#[derive(Debug)]
+pub struct PipeWriter {
+ io: Io,
+}
+
+impl PipeWriter {
+ pub fn from_stdin(stdin: process::ChildStdin) -> io::Result<Self> {
+ match sys::set_nonblock(stdin.as_raw_fd()) {
+ Err(e) => return Err(e),
+ _ => {},
+ }
+ return Ok(PipeWriter::from(unsafe { Io::from_raw_fd(stdin.into_raw_fd()) }));
+ }
+}
+
+impl Write for PipeWriter {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.io.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.io.flush()
+ }
+}
+
+impl<'a> Write for &'a PipeWriter {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ (&self.io).write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ (&self.io).flush()
+ }
+}
+
+impl Evented for PipeWriter {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.io.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.io.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.io.deregister(poll)
+ }
+}
+
+impl From<Io> for PipeWriter {
+ fn from(io: Io) -> PipeWriter {
+ PipeWriter { io: io }
+ }
+}
+
+/*
+ *
+ * ===== Conversions =====
+ *
+ */
+
+use std::os::unix::io::{RawFd, IntoRawFd, AsRawFd, FromRawFd};
+
+impl IntoRawFd for UnixSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.sys.into_raw_fd()
+ }
+}
+
+impl AsRawFd for UnixSocket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.sys.as_raw_fd()
+ }
+}
+
+impl FromRawFd for UnixSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixSocket {
+ UnixSocket { sys: FromRawFd::from_raw_fd(fd) }
+ }
+}
+
+impl IntoRawFd for UnixStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.sys.into_raw_fd()
+ }
+}
+
+impl AsRawFd for UnixStream {
+ fn as_raw_fd(&self) -> RawFd {
+ self.sys.as_raw_fd()
+ }
+}
+
+impl FromRawFd for UnixStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+ UnixStream { sys: FromRawFd::from_raw_fd(fd) }
+ }
+}
+
+impl IntoRawFd for UnixListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.sys.into_raw_fd()
+ }
+}
+
+impl AsRawFd for UnixListener {
+ fn as_raw_fd(&self) -> RawFd {
+ self.sys.as_raw_fd()
+ }
+}
+
+impl FromRawFd for UnixListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+ UnixListener { sys: FromRawFd::from_raw_fd(fd) }
+ }
+}
+
+impl IntoRawFd for PipeReader {
+ fn into_raw_fd(self) -> RawFd {
+ self.io.into_raw_fd()
+ }
+}
+
+impl AsRawFd for PipeReader {
+ fn as_raw_fd(&self) -> RawFd {
+ self.io.as_raw_fd()
+ }
+}
+
+impl FromRawFd for PipeReader {
+ unsafe fn from_raw_fd(fd: RawFd) -> PipeReader {
+ PipeReader { io: FromRawFd::from_raw_fd(fd) }
+ }
+}
+
+impl IntoRawFd for PipeWriter {
+ fn into_raw_fd(self) -> RawFd {
+ self.io.into_raw_fd()
+ }
+}
+
+impl AsRawFd for PipeWriter {
+ fn as_raw_fd(&self) -> RawFd {
+ self.io.as_raw_fd()
+ }
+}
+
+impl FromRawFd for PipeWriter {
+ unsafe fn from_raw_fd(fd: RawFd) -> PipeWriter {
+ PipeWriter { io: FromRawFd::from_raw_fd(fd) }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/event_imp.rs
@@ -0,0 +1,1003 @@
+use {Poll, Token};
+use std::{fmt, io, ops};
+
+/// A value that may be registered with `Poll`
+///
+/// Values that implement `Evented` can be registered with `Poll`. Users of Mio
+/// should not use the `Evented` trait functions directly. Instead, the
+/// equivalent functions on `Poll` should be used.
+///
+/// See [`Poll`] for more details.
+///
+/// # Implementing `Evented`
+///
+/// There are two types of `Evented` values.
+///
+/// * **System** handles, which are backed by sockets or other system handles.
+/// These `Evented` handles will be monitored by the system selector. In this
+/// case, an implementation of `Evented` delegates to a lower level handle.
+///
+/// * **User** handles, which are driven entirely in user space using
+/// [`Registration`] and [`SetReadiness`]. In this case, the implementer takes
+/// responsibility for driving the readiness state changes.
+///
+/// [`Poll`]: struct.Poll.html
+/// [`Registration`]: struct.Registration.html
+/// [`SetReadiness`]: struct.SetReadiness.html
+///
+/// # Examples
+///
+/// Implementing `Evented` on a struct containing a socket:
+///
+/// ```
+/// use mio::{Ready, Poll, PollOpt, Token};
+/// use mio::event::Evented;
+/// use mio::tcp::TcpStream;
+///
+/// use std::io;
+///
+/// pub struct MyEvented {
+/// socket: TcpStream,
+/// }
+///
+/// impl Evented for MyEvented {
+/// fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
+/// -> io::Result<()>
+/// {
+/// // Delegate the `register` call to `socket`
+/// self.socket.register(poll, token, interest, opts)
+/// }
+///
+/// fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
+/// -> io::Result<()>
+/// {
+/// // Delegate the `reregister` call to `socket`
+/// self.socket.reregister(poll, token, interest, opts)
+/// }
+///
+/// fn deregister(&self, poll: &Poll) -> io::Result<()> {
+/// // Delegate the `deregister` call to `socket`
+/// self.socket.deregister(poll)
+/// }
+/// }
+/// ```
+///
+/// Implement `Evented` using [`Registration`] and [`SetReadiness`].
+///
+/// ```
+/// use mio::{Ready, Registration, Poll, PollOpt, Token};
+/// use mio::event::Evented;
+///
+/// use std::io;
+/// use std::time::Instant;
+/// use std::thread;
+///
+/// pub struct Deadline {
+/// when: Instant,
+/// registration: Registration,
+/// }
+///
+/// impl Deadline {
+/// pub fn new(when: Instant) -> Deadline {
+/// let (registration, set_readiness) = Registration::new2();
+///
+/// thread::spawn(move || {
+/// let now = Instant::now();
+///
+/// if now < when {
+/// thread::sleep(when - now);
+/// }
+///
+/// set_readiness.set_readiness(Ready::readable());
+/// });
+///
+/// Deadline {
+/// when: when,
+/// registration: registration,
+/// }
+/// }
+///
+/// pub fn is_elapsed(&self) -> bool {
+/// Instant::now() >= self.when
+/// }
+/// }
+///
+/// impl Evented for Deadline {
+/// fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
+/// -> io::Result<()>
+/// {
+/// self.registration.register(poll, token, interest, opts)
+/// }
+///
+/// fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
+/// -> io::Result<()>
+/// {
+/// self.registration.reregister(poll, token, interest, opts)
+/// }
+///
+/// fn deregister(&self, poll: &Poll) -> io::Result<()> {
+/// self.registration.deregister(poll)
+/// }
+/// }
+/// ```
+pub trait Evented {
+ /// Register `self` with the given `Poll` instance.
+ ///
+ /// This function should not be called directly. Use [`Poll::register`]
+ /// instead. Implementors should handle registration by either delegating
+ /// the call to another `Evented` type or creating a [`Registration`].
+ ///
+ /// See [struct] documentation for more details.
+ ///
+ /// [`Poll::register`]: struct.Poll.html#method.register
+ /// [`Registration`]: struct.Registration.html
+ /// [struct]: #
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()>;
+
+ /// Re-register `self` with the given `Poll` instance.
+ ///
+ /// This function should not be called directly. Use [`Poll::reregister`]
+ /// instead. Implementors should handle re-registration by either delegating
+ /// the call to another `Evented` type or calling [`Registration::update`].
+ ///
+ /// See [struct] documentation for more details.
+ ///
+ /// [`Poll::reregister`]: struct.Poll.html#method.register
+ /// [`Registration::update`]: struct.Registration.html#method.update
+ /// [struct]: #
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()>;
+
+ /// Deregister `self` from the given `Poll` instance
+ ///
+ /// This function should not be called directly. Use [`Poll::deregister`]
+ /// instead. Implementors shuld handle deregistration by either delegating
+ /// the call to another `Evented` type or by dropping the [`Registration`]
+ /// associated with `self`.
+ ///
+ /// See [struct] documentation for more details.
+ ///
+ /// [`Poll::deregister`]: struct.Poll.html#method.deregister
+ /// [`Registration`]: struct.Registration.html
+ /// [struct]: #
+ fn deregister(&self, poll: &Poll) -> io::Result<()>;
+}
+
+/// Options supplied when registering an `Evented` handle with `Poll`
+///
+/// `PollOpt` values can be combined together using the various bitwise
+/// operators.
+///
+/// For high level documentation on polling and poll options, see [`Poll`].
+///
+/// # Examples
+///
+/// ```
+/// use mio::PollOpt;
+///
+/// let opts = PollOpt::edge() | PollOpt::oneshot();
+///
+/// assert!(opts.is_edge());
+/// assert!(opts.is_oneshot());
+/// assert!(!opts.is_level());
+/// ```
+///
+/// [`Poll`]: struct.Poll.html
+#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord)]
+pub struct PollOpt(usize);
+
+impl PollOpt {
+ /// Return a `PollOpt` representing no set options.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::empty();
+ ///
+ /// assert!(!opt.is_level());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn empty() -> PollOpt {
+ PollOpt(0)
+ }
+
+ /// Return a `PollOpt` representing edge-triggered notifications.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::edge();
+ ///
+ /// assert!(opt.is_edge());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn edge() -> PollOpt {
+ PollOpt(0b0001)
+ }
+
+ /// Return a `PollOpt` representing level-triggered notifications.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::level();
+ ///
+ /// assert!(opt.is_level());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn level() -> PollOpt {
+ PollOpt(0b0010)
+ }
+
+ /// Return a `PollOpt` representing oneshot notifications.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::oneshot();
+ ///
+ /// assert!(opt.is_oneshot());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn oneshot() -> PollOpt {
+ PollOpt(0b0100)
+ }
+
+ #[deprecated(since = "0.6.5", note = "removed")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn urgent() -> PollOpt {
+ PollOpt(0b1000)
+ }
+
+ #[deprecated(since = "0.6.5", note = "removed")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn all() -> PollOpt {
+ PollOpt::edge() | PollOpt::level() | PollOpt::oneshot()
+ }
+
+ /// Returns true if the options include edge-triggered notifications.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::edge();
+ ///
+ /// assert!(opt.is_edge());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn is_edge(&self) -> bool {
+ self.contains(PollOpt::edge())
+ }
+
+ /// Returns true if the options include level-triggered notifications.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::level();
+ ///
+ /// assert!(opt.is_level());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn is_level(&self) -> bool {
+ self.contains(PollOpt::level())
+ }
+
+ /// Returns true if the options includes oneshot.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::oneshot();
+ ///
+ /// assert!(opt.is_oneshot());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn is_oneshot(&self) -> bool {
+ self.contains(PollOpt::oneshot())
+ }
+
+ #[deprecated(since = "0.6.5", note = "removed")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[allow(deprecated)]
+ #[inline]
+ pub fn is_urgent(&self) -> bool {
+ self.contains(PollOpt::urgent())
+ }
+
+ #[deprecated(since = "0.6.5", note = "removed")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn bits(&self) -> usize {
+ self.0
+ }
+
+ /// Returns true if `self` is a superset of `other`.
+ ///
+ /// `other` may represent more than one option, in which case the function
+ /// only returns true if `self` contains all of the options specified in
+ /// `other`.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::oneshot();
+ ///
+ /// assert!(opt.contains(PollOpt::oneshot()));
+ /// assert!(!opt.contains(PollOpt::edge()));
+ /// ```
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::oneshot() | PollOpt::edge();
+ ///
+ /// assert!(opt.contains(PollOpt::oneshot()));
+ /// assert!(opt.contains(PollOpt::edge()));
+ /// ```
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let opt = PollOpt::oneshot() | PollOpt::edge();
+ ///
+ /// assert!(!PollOpt::oneshot().contains(opt));
+ /// assert!(opt.contains(opt));
+ /// assert!((opt | PollOpt::level()).contains(opt));
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn contains(&self, other: PollOpt) -> bool {
+ (*self & other) == other
+ }
+
+ /// Adds all options represented by `other` into `self`.
+ ///
+ /// This is equivalent to `*self = *self | other`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let mut opt = PollOpt::empty();
+ /// opt.insert(PollOpt::oneshot());
+ ///
+ /// assert!(opt.is_oneshot());
+ /// ```
+ #[inline]
+ pub fn insert(&mut self, other: PollOpt) {
+ self.0 |= other.0;
+ }
+
+ /// Removes all options represented by `other` from `self`.
+ ///
+ /// This is equivalent to `*self = *self & !other`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::PollOpt;
+ ///
+ /// let mut opt = PollOpt::oneshot();
+ /// opt.remove(PollOpt::oneshot());
+ ///
+ /// assert!(!opt.is_oneshot());
+ /// ```
+ #[inline]
+ pub fn remove(&mut self, other: PollOpt) {
+ self.0 &= !other.0;
+ }
+}
+
+impl ops::BitOr for PollOpt {
+ type Output = PollOpt;
+
+ #[inline]
+ fn bitor(self, other: PollOpt) -> PollOpt {
+ PollOpt(self.0 | other.0)
+ }
+}
+
+impl ops::BitXor for PollOpt {
+ type Output = PollOpt;
+
+ #[inline]
+ fn bitxor(self, other: PollOpt) -> PollOpt {
+ PollOpt(self.0 ^ other.0)
+ }
+}
+
+impl ops::BitAnd for PollOpt {
+ type Output = PollOpt;
+
+ #[inline]
+ fn bitand(self, other: PollOpt) -> PollOpt {
+ PollOpt(self.0 & other.0)
+ }
+}
+
+impl ops::Sub for PollOpt {
+ type Output = PollOpt;
+
+ #[inline]
+ fn sub(self, other: PollOpt) -> PollOpt {
+ PollOpt(self.0 & !other.0)
+ }
+}
+
+impl ops::Not for PollOpt {
+ type Output = PollOpt;
+
+ #[inline]
+ fn not(self) -> PollOpt {
+ PollOpt(!self.0)
+ }
+}
+
+impl fmt::Debug for PollOpt {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut one = false;
+ let flags = [
+ (PollOpt::edge(), "Edge-Triggered"),
+ (PollOpt::level(), "Level-Triggered"),
+ (PollOpt::oneshot(), "OneShot")];
+
+ for &(flag, msg) in &flags {
+ if self.contains(flag) {
+ if one { try!(write!(fmt, " | ")) }
+ try!(write!(fmt, "{}", msg));
+
+ one = true
+ }
+ }
+
+ Ok(())
+ }
+}
+
+/// A set of readiness event kinds
+///
+/// `Ready` is a set of operation descriptors indicating which kind of an
+/// operation is ready to be performed. For example, `Ready::readable()`
+/// indicates that the associated `Evented` handle is ready to perform a
+/// `read` operation.
+///
+/// This struct only represents portable event kinds. Since only readable and
+/// writable events are guaranteed to be raised on all systems, those are the
+/// only ones available via the `Ready` struct. There are also platform specific
+/// extensions to `Ready`, i.e. `UnixReady`, which provide additional readiness
+/// event kinds only available on unix platforms.
+///
+/// `Ready` values can be combined together using the various bitwise operators.
+///
+/// For high level documentation on polling and readiness, see [`Poll`].
+///
+/// # Examples
+///
+/// ```
+/// use mio::Ready;
+///
+/// let ready = Ready::readable() | Ready::writable();
+///
+/// assert!(ready.is_readable());
+/// assert!(ready.is_writable());
+/// ```
+///
+/// [`Poll`]: struct.Poll.html
+/// [`readable`]: #method.readable
+/// [`writable`]: #method.writable
+/// [readiness]: struct.Poll.html#readiness-operations
+#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord)]
+pub struct Ready(usize);
+
+const READABLE: usize = 0b00001;
+const WRITABLE: usize = 0b00010;
+const ERROR: usize = 0b00100;
+const HUP: usize = 0b01000;
+
+impl Ready {
+ /// Returns the empty `Ready` set.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::empty();
+ ///
+ /// assert!(!ready.is_readable());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ pub fn empty() -> Ready {
+ Ready(0)
+ }
+
+ #[deprecated(since = "0.6.5", note = "use Ready::empty instead")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ pub fn none() -> Ready {
+ Ready::empty()
+ }
+
+ /// Returns a `Ready` representing readable readiness.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::readable();
+ ///
+ /// assert!(ready.is_readable());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn readable() -> Ready {
+ Ready(READABLE)
+ }
+
+ /// Returns a `Ready` representing writable readiness.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::writable();
+ ///
+ /// assert!(ready.is_writable());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn writable() -> Ready {
+ Ready(WRITABLE)
+ }
+
+ #[deprecated(since = "0.6.5", note = "use UnixReady instead")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn error() -> Ready {
+ Ready(ERROR)
+ }
+
+ #[deprecated(since = "0.6.5", note = "use UnixReady instead")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn hup() -> Ready {
+ Ready(HUP)
+ }
+
+ #[deprecated(since = "0.6.5", note = "removed")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn all() -> Ready {
+ Ready::readable() |
+ Ready::writable()
+ }
+
+ /// Returns true if `Ready` is the empty set
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::empty();
+ /// assert!(ready.is_empty());
+ /// ```
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ *self == Ready::empty()
+ }
+
+ #[deprecated(since = "0.6.5", note = "use Ready::is_empty instead")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn is_none(&self) -> bool {
+ self.is_empty()
+ }
+
+ /// Returns true if the value includes readable readiness
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::readable();
+ ///
+ /// assert!(ready.is_readable());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn is_readable(&self) -> bool {
+ self.contains(Ready::readable())
+ }
+
+ /// Returns true if the value includes writable readiness
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::writable();
+ ///
+ /// assert!(ready.is_writable());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn is_writable(&self) -> bool {
+ self.contains(Ready::writable())
+ }
+
+ #[deprecated(since = "0.6.5", note = "use UnixReady instead")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn is_error(&self) -> bool {
+ self.contains(Ready(ERROR))
+ }
+
+ #[deprecated(since = "0.6.5", note = "use UnixReady instead")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn is_hup(&self) -> bool {
+ self.contains(Ready(HUP))
+ }
+
+ /// Adds all readiness represented by `other` into `self`.
+ ///
+ /// This is equivalent to `*self = *self | other`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let mut readiness = Ready::empty();
+ /// readiness.insert(Ready::readable());
+ ///
+ /// assert!(readiness.is_readable());
+ /// ```
+ #[inline]
+ pub fn insert<T: Into<Self>>(&mut self, other: T) {
+ let other = other.into();
+ self.0 |= other.0;
+ }
+
+ /// Removes all options represented by `other` from `self`.
+ ///
+ /// This is equivalent to `*self = *self & !other`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let mut readiness = Ready::readable();
+ /// readiness.remove(Ready::readable());
+ ///
+ /// assert!(!readiness.is_readable());
+ /// ```
+ #[inline]
+ pub fn remove<T: Into<Self>>(&mut self, other: T) {
+ let other = other.into();
+ self.0 &= !other.0;
+ }
+
+ #[deprecated(since = "0.6.5", note = "removed")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ #[inline]
+ pub fn bits(&self) -> usize {
+ self.0
+ }
+
+ /// Returns true if `self` is a superset of `other`.
+ ///
+ /// `other` may represent more than one readiness operations, in which case
+ /// the function only returns true if `self` contains all readiness
+ /// specified in `other`.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let readiness = Ready::readable();
+ ///
+ /// assert!(readiness.contains(Ready::readable()));
+ /// assert!(!readiness.contains(Ready::writable()));
+ /// ```
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let readiness = Ready::readable() | Ready::writable();
+ ///
+ /// assert!(readiness.contains(Ready::readable()));
+ /// assert!(readiness.contains(Ready::writable()));
+ /// ```
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let readiness = Ready::readable() | Ready::writable();
+ ///
+ /// assert!(!Ready::readable().contains(readiness));
+ /// assert!(readiness.contains(readiness));
+ /// assert!((readiness | Ready::hup()).contains(readiness));
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn contains<T: Into<Self>>(&self, other: T) -> bool {
+ let other = other.into();
+ (*self & other) == other
+ }
+}
+
+impl<T: Into<Ready>> ops::BitOr<T> for Ready {
+ type Output = Ready;
+
+ #[inline]
+ fn bitor(self, other: T) -> Ready {
+ Ready(self.0 | other.into().0)
+ }
+}
+
+impl<T: Into<Ready>> ops::BitXor<T> for Ready {
+ type Output = Ready;
+
+ #[inline]
+ fn bitxor(self, other: T) -> Ready {
+ Ready(self.0 ^ other.into().0)
+ }
+}
+
+impl<T: Into<Ready>> ops::BitAnd<T> for Ready {
+ type Output = Ready;
+
+ #[inline]
+ fn bitand(self, other: T) -> Ready {
+ Ready(self.0 & other.into().0)
+ }
+}
+
+impl<T: Into<Ready>> ops::Sub<T> for Ready {
+ type Output = Ready;
+
+ #[inline]
+ fn sub(self, other: T) -> Ready {
+ Ready(self.0 & !other.into().0)
+ }
+}
+
+impl ops::Not for Ready {
+ type Output = Ready;
+
+ #[inline]
+ fn not(self) -> Ready {
+ Ready(!self.0)
+ }
+}
+
+// TODO: impl Debug for UnixReady
+impl fmt::Debug for Ready {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut one = false;
+ let flags = [
+ (Ready::readable(), "Readable"),
+ (Ready::writable(), "Writable"),
+ (Ready(ERROR), "Error"),
+ (Ready(HUP), "Hup")];
+
+ try!(write!(fmt, "Ready {{"));
+
+ for &(flag, msg) in &flags {
+ if self.contains(flag) {
+ if one { try!(write!(fmt, " | ")) }
+ try!(write!(fmt, "{}", msg));
+
+ one = true
+ }
+ }
+
+ try!(write!(fmt, "}}"));
+
+ Ok(())
+ }
+}
+
+/// An readiness event returned by [`Poll::poll`].
+///
+/// `Event` is a [readiness state] paired with a [`Token`]. It is returned by
+/// [`Poll::poll`].
+///
+/// For more documentation on polling and events, see [`Poll`].
+///
+/// # Examples
+///
+/// ```
+/// use mio::{Event, Ready, Token};
+///
+/// let event = Event::new(Ready::all(), Token(0));
+///
+/// assert_eq!(event.readiness(), Ready::all());
+/// assert_eq!(event.token(), Token(0));
+/// ```
+///
+/// [`Poll::poll`]: struct.Poll.html#method.poll
+/// [`Poll`]: struct.Poll.html
+/// [readiness state ]: struct.Ready.html
+/// [`Token`]: struct.Token.html
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+pub struct Event {
+ kind: Ready,
+ token: Token
+}
+
+impl Event {
+ /// Creates a new `Event` containing `readiness` and `token`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Event, Ready, Token};
+ ///
+ /// let event = Event::new(Ready::all(), Token(0));
+ ///
+ /// assert_eq!(event.readiness(), Ready::all());
+ /// assert_eq!(event.token(), Token(0));
+ /// ```
+ pub fn new(readiness: Ready, token: Token) -> Event {
+ Event {
+ kind: readiness,
+ token: token,
+ }
+ }
+
+ /// Returns the event's readiness.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Event, Ready, Token};
+ ///
+ /// let event = Event::new(Ready::all(), Token(0));
+ ///
+ /// assert_eq!(event.readiness(), Ready::all());
+ /// ```
+ pub fn readiness(&self) -> Ready {
+ self.kind
+ }
+
+ #[deprecated(since = "0.6.5", note = "use Event::readiness()")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ pub fn kind(&self) -> Ready {
+ self.kind
+ }
+
+ /// Returns the event's token.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Event, Ready, Token};
+ ///
+ /// let event = Event::new(Ready::all(), Token(0));
+ ///
+ /// assert_eq!(event.token(), Token(0));
+ /// ```
+ pub fn token(&self) -> Token {
+ self.token
+ }
+}
+
+/*
+ *
+ * ===== Mio internal helpers =====
+ *
+ */
+
+pub fn ready_as_usize(events: Ready) -> usize {
+ events.0
+}
+
+pub fn opt_as_usize(opt: PollOpt) -> usize {
+ opt.0
+}
+
+pub fn ready_from_usize(events: usize) -> Ready {
+ Ready(events)
+}
+
+pub fn opt_from_usize(opt: usize) -> PollOpt {
+ PollOpt(opt)
+}
+
+// Used internally to mutate an `Event` in place
+// Not used on all platforms
+#[allow(dead_code)]
+pub fn kind_mut(event: &mut Event) -> &mut Ready {
+ &mut event.kind
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/io.rs
@@ -0,0 +1,41 @@
+// Re-export the io::Result / Error types for convenience
+pub use std::io::{Read, Write, Result, Error, ErrorKind};
+
+// TODO: Delete this
+/// A helper trait to provide the map_non_block function on Results.
+pub trait MapNonBlock<T> {
+ /// Maps a `Result<T>` to a `Result<Option<T>>` by converting
+ /// operation-would-block errors into `Ok(None)`.
+ fn map_non_block(self) -> Result<Option<T>>;
+}
+
+impl<T> MapNonBlock<T> for Result<T> {
+ fn map_non_block(self) -> Result<Option<T>> {
+ use std::io::ErrorKind::WouldBlock;
+
+ match self {
+ Ok(value) => Ok(Some(value)),
+ Err(err) => {
+ if let WouldBlock = err.kind() {
+ Ok(None)
+ } else {
+ Err(err)
+ }
+ }
+ }
+ }
+}
+
+#[cfg(feature = "with-deprecated")]
+pub mod deprecated {
+ #[cfg(unix)]
+ const WOULDBLOCK: i32 = ::libc::EAGAIN;
+
+ #[cfg(windows)]
+ const WOULDBLOCK: i32 = ::winapi::winerror::WSAEWOULDBLOCK as i32;
+
+ /// Returns a std `WouldBlock` error without allocating
+ pub fn would_block() -> ::std::io::Error {
+ ::std::io::Error::from_raw_os_error(WOULDBLOCK)
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/lib.rs
@@ -0,0 +1,266 @@
+//! A fast, low-level IO library for Rust focusing on non-blocking APIs, event
+//! notification, and other useful utilities for building high performance IO
+//! apps.
+//!
+//! # Goals
+//!
+//! * Fast - minimal overhead over the equivalent OS facilities (epoll, kqueue, etc...)
+//! * Zero allocations
+//! * A scalable readiness-based API, similar to epoll on Linux
+//! * Design to allow for stack allocated buffers when possible (avoid double buffering).
+//! * Provide utilities such as a timers, a notification channel, buffer abstractions, and a slab.
+//!
+//! # Usage
+//!
+//! Using mio starts by creating a [`Poll`], which reads events from the OS and
+//! put them into [`Events`]. You can handle IO events from the OS with it.
+//!
+//! For more detail, see [`Poll`].
+//!
+//! [`Poll`]: struct.Poll.html
+//! [`Events`]: struct.Events.html
+//!
+//! # Example
+//!
+//! ```
+//! use mio::*;
+//! use mio::tcp::{TcpListener, TcpStream};
+//!
+//! // Setup some tokens to allow us to identify which event is
+//! // for which socket.
+//! const SERVER: Token = Token(0);
+//! const CLIENT: Token = Token(1);
+//!
+//! let addr = "127.0.0.1:13265".parse().unwrap();
+//!
+//! // Setup the server socket
+//! let server = TcpListener::bind(&addr).unwrap();
+//!
+//! // Create a poll instance
+//! let poll = Poll::new().unwrap();
+//!
+//! // Start listening for incoming connections
+//! poll.register(&server, SERVER, Ready::readable(),
+//! PollOpt::edge()).unwrap();
+//!
+//! // Setup the client socket
+//! let sock = TcpStream::connect(&addr).unwrap();
+//!
+//! // Register the socket
+//! poll.register(&sock, CLIENT, Ready::readable(),
+//! PollOpt::edge()).unwrap();
+//!
+//! // Create storage for events
+//! let mut events = Events::with_capacity(1024);
+//!
+//! loop {
+//! poll.poll(&mut events, None).unwrap();
+//!
+//! for event in events.iter() {
+//! match event.token() {
+//! SERVER => {
+//! // Accept and drop the socket immediately, this will close
+//! // the socket and notify the client of the EOF.
+//! let _ = server.accept();
+//! }
+//! CLIENT => {
+//! // The server just shuts down the socket, let's just exit
+//! // from our event loop.
+//! return;
+//! }
+//! _ => unreachable!(),
+//! }
+//! }
+//! }
+//!
+//! ```
+
+#![doc(html_root_url = "https://docs.rs/mio/0.6.1")]
+#![crate_name = "mio"]
+
+#![deny(warnings, missing_docs, missing_debug_implementations)]
+
+extern crate lazycell;
+extern crate net2;
+extern crate slab;
+extern crate iovec;
+
+#[cfg(unix)]
+extern crate libc;
+
+#[cfg(windows)]
+extern crate miow;
+
+#[cfg(windows)]
+extern crate winapi;
+
+#[cfg(windows)]
+extern crate kernel32;
+
+#[macro_use]
+extern crate log;
+
+#[cfg(test)]
+extern crate env_logger;
+
+mod event_imp;
+mod io;
+mod poll;
+mod sys;
+mod token;
+
+pub mod net;
+
+#[deprecated(since = "0.6.5", note = "use mio-more instead")]
+#[cfg(feature = "with-deprecated")]
+#[doc(hidden)]
+pub mod channel;
+
+#[deprecated(since = "0.6.5", note = "use mio-more instead")]
+#[cfg(feature = "with-deprecated")]
+#[doc(hidden)]
+pub mod timer;
+
+#[deprecated(since = "0.6.5", note = "update to use `Poll`")]
+#[cfg(feature = "with-deprecated")]
+#[doc(hidden)]
+pub mod deprecated;
+
+#[deprecated(since = "0.6.5", note = "use iovec crate directly")]
+#[cfg(feature = "with-deprecated")]
+#[doc(hidden)]
+pub use iovec::IoVec;
+
+#[deprecated(since = "0.6.6", note = "use net module instead")]
+#[cfg(feature = "with-deprecated")]
+#[doc(hidden)]
+pub mod tcp {
+ pub use net::{TcpListener, TcpStream};
+ pub use std::net::Shutdown;
+}
+
+#[deprecated(since = "0.6.6", note = "use net module instead")]
+#[cfg(feature = "with-deprecated")]
+#[doc(hidden)]
+pub mod udp;
+
+pub use poll::{
+ Poll,
+ Registration,
+ SetReadiness,
+};
+pub use event_imp::{
+ PollOpt,
+ Ready,
+};
+pub use token::Token;
+
+pub mod event {
+ //! Readiness event types and utilities.
+
+ pub use super::poll::{Events, Iter};
+ pub use super::event_imp::{Event, Evented};
+}
+
+pub use event::{
+ Events,
+};
+
+#[deprecated(since = "0.6.5", note = "use events:: instead")]
+#[cfg(feature = "with-deprecated")]
+#[doc(hidden)]
+pub use event::{Event, Evented};
+
+#[deprecated(since = "0.6.5", note = "use events::Iter instead")]
+#[cfg(feature = "with-deprecated")]
+#[doc(hidden)]
+pub use poll::Iter as EventsIter;
+
+#[deprecated(since = "0.6.5", note = "std::io::Error can avoid the allocation now")]
+#[cfg(feature = "with-deprecated")]
+#[doc(hidden)]
+pub use io::deprecated::would_block;
+
+#[cfg(unix)]
+pub mod unix {
+ //! Unix only extensions
+ pub use sys::{
+ EventedFd,
+ };
+ pub use sys::unix::UnixReady;
+}
+
+/// Windows-only extensions to the mio crate.
+///
+/// Mio on windows is currently implemented with IOCP for a high-performance
+/// implementation of asynchronous I/O. Mio then provides TCP and UDP as sample
+/// bindings for the system to connect networking types to asynchronous I/O. On
+/// Unix this scheme is then also extensible to all other file descriptors with
+/// the `EventedFd` type, but on Windows no such analog is available. The
+/// purpose of this module, however, is to similarly provide a mechanism for
+/// foreign I/O types to get hooked up into the IOCP event loop.
+///
+/// This module provides two types for interfacing with a custom IOCP handle:
+///
+/// * `Binding` - this type is intended to govern binding with mio's `Poll`
+/// type. Each I/O object should contain an instance of `Binding` that's
+/// interfaced with for the implementation of the `Evented` trait. The
+/// `register`, `reregister`, and `deregister` methods for the `Evented` trait
+/// all have rough analogs with `Binding`.
+///
+/// Note that this type **does not handle readiness**. That is, this type does
+/// not handle whether sockets are readable/writable/etc. It's intended that
+/// IOCP types will internally manage this state with a `SetReadiness` type
+/// from the `poll` module. The `SetReadiness` is typically lazily created on
+/// the first time that `Evented::register` is called and then stored in the
+/// I/O object.
+///
+/// Also note that for types which represent streams of bytes the mio
+/// interface of *readiness* doesn't map directly to the Windows model of
+/// *completion*. This means that types will have to perform internal
+/// buffering to ensure that a readiness interface can be provided. For a
+/// sample implementation see the TCP/UDP modules in mio itself.
+///
+/// * `Overlapped` - this type is intended to be used as the concreate instances
+/// of the `OVERLAPPED` type that most win32 methods expect. It's crucial, for
+/// safety, that all asynchronous operations are initiated with an instance of
+/// `Overlapped` and not another instantiation of `OVERLAPPED`.
+///
+/// Mio's `Overlapped` type is created with a function pointer that receives
+/// a `OVERLAPPED_ENTRY` type when called. This `OVERLAPPED_ENTRY` type is
+/// defined in the `winapi` crate. Whenever a completion is posted to an IOCP
+/// object the `OVERLAPPED` that was signaled will be interpreted as
+/// `Overlapped` in the mio crate and this function pointer will be invoked.
+/// Through this function pointer, and through the `OVERLAPPED` pointer,
+/// implementations can handle management of I/O events.
+///
+/// When put together these two types enable custom Windows handles to be
+/// registered with mio's event loops. The `Binding` type is used to associate
+/// handles and the `Overlapped` type is used to execute I/O operations. When
+/// the I/O operations are completed a custom function pointer is called which
+/// typically modifies a `SetReadiness` set by `Evented` methods which will get
+/// later hooked into the mio event loop.
+#[cfg(windows)]
+pub mod windows {
+
+ pub use sys::{Overlapped, Binding};
+}
+
+#[cfg(feature = "with-deprecated")]
+mod convert {
+ use std::time::Duration;
+
+ const NANOS_PER_MILLI: u32 = 1_000_000;
+ const MILLIS_PER_SEC: u64 = 1_000;
+
+ /// Convert a `Duration` to milliseconds, rounding up and saturating at
+ /// `u64::MAX`.
+ ///
+ /// The saturating is fine because `u64::MAX` milliseconds are still many
+ /// million years.
+ pub fn millis(duration: Duration) -> u64 {
+ // Round up.
+ let millis = (duration.subsec_nanos() + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
+ duration.as_secs().saturating_mul(MILLIS_PER_SEC).saturating_add(millis as u64)
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/net/mod.rs
@@ -0,0 +1,14 @@
+//! Networking primitives
+//!
+//! The types provided in this module are non-blocking by default and are
+//! designed to be portable across all supported Mio platforms. As long as the
+//! [portability guidelines] are followed, the behavior should be identical no
+//! matter the target platform.
+//!
+//! [portability guidelines]: ../struct.Poll.html#portability
+
+mod tcp;
+mod udp;
+
+pub use self::tcp::{TcpListener, TcpStream};
+pub use self::udp::UdpSocket;
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/net/tcp.rs
@@ -0,0 +1,670 @@
+//! Primitives for working with TCP
+//!
+//! The types provided in this module are non-blocking by default and are
+//! designed to be portable across all supported Mio platforms. As long as the
+//! [portability guidelines] are followed, the behavior should be identical no
+//! matter the target platform.
+//!
+/// [portability guidelines]: ../struct.Poll.html#portability
+
+
+use std::io::{Read, Write};
+use std::net::{self, SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
+use std::time::Duration;
+
+use net2::TcpBuilder;
+use iovec::IoVec;
+
+use {io, sys, Ready, Poll, PollOpt, Token};
+use event::Evented;
+use poll::SelectorId;
+
+/*
+ *
+ * ===== TcpStream =====
+ *
+ */
+
+/// A non-blocking TCP stream between a local socket and a remote socket.
+///
+/// The socket will be closed when the value is dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use std::net::TcpListener;
+/// # let _listener = TcpListener::bind("127.0.0.1:3454").unwrap();
+/// use mio::{Events, Ready, Poll, PollOpt, Token};
+/// use mio::tcp::TcpStream;
+/// use std::time::Duration;
+///
+/// let stream = TcpStream::connect(&"127.0.0.1:34254".parse().unwrap()).unwrap();
+///
+/// let poll = Poll::new().unwrap();
+/// let mut events = Events::with_capacity(128);
+///
+/// // Register the socket with `Poll`
+/// poll.register(&stream, Token(0), Ready::writable(),
+/// PollOpt::edge()).unwrap();
+///
+/// poll.poll(&mut events, Some(Duration::from_millis(100))).unwrap();
+///
+/// // The socket might be ready at this point
+/// ```
+#[derive(Debug)]
+pub struct TcpStream {
+ sys: sys::TcpStream,
+ selector_id: SelectorId,
+}
+
+use std::net::Shutdown;
+
+impl TcpStream {
+ /// Create a new TCP stream and issue a non-blocking connect to the
+ /// specified address.
+ ///
+ /// This convenience method is available and uses the system's default
+ /// options when creating a socket which is then connected. If fine-grained
+ /// control over the creation of the socket is desired, you can use
+ /// `net2::TcpBuilder` to configure a socket and then pass its socket to
+ /// `TcpStream::connect_stream` to transfer ownership into mio and schedule
+ /// the connect operation.
+ pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
+ let sock = try!(match *addr {
+ SocketAddr::V4(..) => TcpBuilder::new_v4(),
+ SocketAddr::V6(..) => TcpBuilder::new_v6(),
+ });
+ // Required on Windows for a future `connect_overlapped` operation to be
+ // executed successfully.
+ if cfg!(windows) {
+ try!(sock.bind(&inaddr_any(addr)));
+ }
+ TcpStream::connect_stream(try!(sock.to_tcp_stream()), addr)
+ }
+
+ /// Creates a new `TcpStream` from the pending socket inside the given
+ /// `std::net::TcpBuilder`, connecting it to the address specified.
+ ///
+ /// This constructor allows configuring the socket before it's actually
+ /// connected, and this function will transfer ownership to the returned
+ /// `TcpStream` if successful. An unconnected `TcpStream` can be created
+ /// with the `net2::TcpBuilder` type (and also configured via that route).
+ ///
+ /// The platform specific behavior of this function looks like:
+ ///
+ /// * On Unix, the socket is placed into nonblocking mode and then a
+ /// `connect` call is issued.
+ ///
+ /// * On Windows, the address is stored internally and the connect operation
+ /// is issued when the returned `TcpStream` is registered with an event
+ /// loop. Note that on Windows you must `bind` a socket before it can be
+ /// connected, so if a custom `TcpBuilder` is used it should be bound
+ /// (perhaps to `INADDR_ANY`) before this method is called.
+ pub fn connect_stream(stream: net::TcpStream,
+ addr: &SocketAddr) -> io::Result<TcpStream> {
+ Ok(TcpStream {
+ sys: try!(sys::TcpStream::connect(stream, addr)),
+ selector_id: SelectorId::new(),
+ })
+ }
+
+ /// Creates a new `TcpStream` from a standard `net::TcpStream`.
+ ///
+ /// This function is intended to be used to wrap a TCP stream from the
+ /// standard library in the mio equivalent. The conversion here will
+ /// automatically set `stream` to nonblocking and the returned object should
+ /// be ready to get associated with an event loop.
+ ///
+ /// Note that the TCP stream here will not have `connect` called on it, so
+ /// it should already be connected via some other means (be it manually, the
+ /// net2 crate, or the standard library).
+ pub fn from_stream(stream: net::TcpStream) -> io::Result<TcpStream> {
+ try!(stream.set_nonblocking(true));
+ Ok(TcpStream {
+ sys: sys::TcpStream::from_stream(stream),
+ selector_id: SelectorId::new(),
+ })
+ }
+
+ /// Returns the socket address of the remote peer of this TCP connection.
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ self.sys.peer_addr()
+ }
+
+ /// Returns the socket address of the local half of this TCP connection.
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.sys.local_addr()
+ }
+
+ /// 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.
+ pub fn try_clone(&self) -> io::Result<TcpStream> {
+ self.sys.try_clone().map(|s| {
+ TcpStream {
+ sys: s,
+ selector_id: self.selector_id.clone(),
+ }
+ })
+ }
+
+ /// 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`).
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.sys.shutdown(how)
+ }
+
+ /// 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.
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ self.sys.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
+ pub fn nodelay(&self) -> io::Result<bool> {
+ self.sys.nodelay()
+ }
+
+ /// Sets the value of the `SO_RCVBUF` option on this socket.
+ ///
+ /// Changes the size of the operating system's receive buffer associated
+ /// with the socket.
+ pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
+ self.sys.set_recv_buffer_size(size)
+ }
+
+ /// Gets the value of the `SO_RCVBUF` option on this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_recv_buffer_size`][link].
+ ///
+ /// [link]: #tymethod.set_recv_buffer_size
+ pub fn recv_buffer_size(&self) -> io::Result<usize> {
+ self.sys.recv_buffer_size()
+ }
+
+ /// Sets the value of the `SO_SNDBUF` option on this socket.
+ ///
+ /// Changes the size of the operating system's send buffer associated with
+ /// the socket.
+ pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
+ self.sys.set_send_buffer_size(size)
+ }
+
+ /// Gets the value of the `SO_SNDBUF` option on this socket.
+ ///
+ /// For more information about this option, see [`set_send_buffer`][link].
+ ///
+ /// [link]: #tymethod.set_send_buffer
+ pub fn send_buffer_size(&self) -> io::Result<usize> {
+ self.sys.send_buffer_size()
+ }
+
+ /// Sets whether keepalive messages are enabled to be sent on this socket.
+ ///
+ /// On Unix, this option will set the `SO_KEEPALIVE` as well as the
+ /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform).
+ /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option.
+ ///
+ /// If `None` is specified then keepalive messages are disabled, otherwise
+ /// the duration specified will be the time to remain idle before sending a
+ /// TCP keepalive probe.
+ ///
+ /// Some platforms specify this value in seconds, so sub-second
+ /// specifications may be omitted.
+ pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
+ self.sys.set_keepalive(keepalive)
+ }
+
+ /// Returns whether keepalive messages are enabled on this socket, and if so
+ /// the duration of time between them.
+ ///
+ /// For more information about this option, see [`set_keepalive`][link].
+ ///
+ /// [link]: #tymethod.set_keepalive
+ pub fn keepalive(&self) -> io::Result<Option<Duration>> {
+ self.sys.keepalive()
+ }
+
+ /// 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.
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.sys.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]: #tymethod.set_ttl
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.sys.ttl()
+ }
+
+ /// Sets the value for the `IPV6_V6ONLY` option on this socket.
+ ///
+ /// If this is set to `true` then the socket is restricted to sending and
+ /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
+ /// can bind the same port at the same time.
+ ///
+ /// If this is set to `false` then the socket can be used to send and
+ /// receive packets from an IPv4-mapped IPv6 address.
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ self.sys.set_only_v6(only_v6)
+ }
+
+ /// Gets the value of the `IPV6_V6ONLY` option for this socket.
+ ///
+ /// For more information about this option, see [`set_only_v6`][link].
+ ///
+ /// [link]: #tymethod.set_only_v6
+ pub fn only_v6(&self) -> io::Result<bool> {
+ self.sys.only_v6()
+ }
+
+ /// Sets the linger duration of this socket by setting the SO_LINGER option
+ pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.sys.set_linger(dur)
+ }
+
+ /// reads the linger duration for this socket by getting the SO_LINGER option
+ pub fn linger(&self) -> io::Result<Option<Duration>> {
+ self.sys.linger()
+ }
+
+ #[deprecated(since = "0.6.9", note = "use set_keepalive")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ pub fn set_keepalive_ms(&self, keepalive: Option<u32>) -> io::Result<()> {
+ self.set_keepalive(keepalive.map(|v| Duration::from_millis(v as u64)))
+ }
+
+ #[deprecated(since = "0.6.9", note = "use keepalive")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ pub fn keepalive_ms(&self) -> io::Result<Option<u32>> {
+ self.keepalive().map(|v| {
+ v.map(|v| {
+ ::convert::millis(v) as u32
+ })
+ })
+ }
+
+ /// 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.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.sys.take_error()
+ }
+
+ /// Read in a list of buffers all at once.
+ ///
+ /// This operation will attempt to read bytes from this socket and place
+ /// them into the list of buffers provided. Note that each buffer is an
+ /// `IoVec` which can be created from a byte slice.
+ ///
+ /// The buffers provided will be filled in sequentially. A buffer will be
+ /// entirely filled up before the next is written to.
+ ///
+ /// The number of bytes read is returned, if successful, or an error is
+ /// returned otherwise. If no bytes are available to be read yet then
+ /// a "would block" error is returned. This operation does not block.
+ ///
+ /// On Unix this corresponds to the `readv` syscall.
+ pub fn read_bufs(&self, bufs: &mut [&mut IoVec]) -> io::Result<usize> {
+ self.sys.readv(bufs)
+ }
+
+ /// Write a list of buffers all at once.
+ ///
+ /// This operation will attempt to write a list of byte buffers to this
+ /// socket. Note that each buffer is an `IoVec` which can be created from a
+ /// byte slice.
+ ///
+ /// The buffers provided will be written sequentially. A buffer will be
+ /// entirely written before the next is written.
+ ///
+ /// The number of bytes written is returned, if successful, or an error is
+ /// returned otherwise. If the socket is not currently writable then a
+ /// "would block" error is returned. This operation does not block.
+ ///
+ /// On Unix this corresponds to the `writev` syscall.
+ pub fn write_bufs(&self, bufs: &[&IoVec]) -> io::Result<usize> {
+ self.sys.writev(bufs)
+ }
+}
+
+fn inaddr_any(other: &SocketAddr) -> SocketAddr {
+ match *other {
+ SocketAddr::V4(..) => {
+ let any = Ipv4Addr::new(0, 0, 0, 0);
+ let addr = SocketAddrV4::new(any, 0);
+ SocketAddr::V4(addr)
+ }
+ SocketAddr::V6(..) => {
+ let any = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+ let addr = SocketAddrV6::new(any, 0, 0, 0);
+ SocketAddr::V6(addr)
+ }
+ }
+}
+
+impl Read for TcpStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (&self.sys).read(buf)
+ }
+}
+
+impl<'a> Read for &'a TcpStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (&self.sys).read(buf)
+ }
+}
+
+impl Write for TcpStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ (&self.sys).write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ (&self.sys).flush()
+ }
+}
+
+impl<'a> Write for &'a TcpStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ (&self.sys).write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ (&self.sys).flush()
+ }
+}
+
+impl Evented for TcpStream {
+ fn register(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ try!(self.selector_id.associate_selector(poll));
+ self.sys.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.sys.deregister(poll)
+ }
+}
+
+/*
+ *
+ * ===== TcpListener =====
+ *
+ */
+
+/// A structure representing a socket server
+///
+/// # Examples
+///
+/// ```
+/// use mio::{Events, Ready, Poll, PollOpt, Token};
+/// use mio::tcp::TcpListener;
+/// use std::time::Duration;
+///
+/// let listener = TcpListener::bind(&"127.0.0.1:34254".parse().unwrap()).unwrap();
+///
+/// let poll = Poll::new().unwrap();
+/// let mut events = Events::with_capacity(128);
+///
+/// // Register the socket with `Poll`
+/// poll.register(&listener, Token(0), Ready::writable(),
+/// PollOpt::edge()).unwrap();
+///
+/// poll.poll(&mut events, Some(Duration::from_millis(100))).unwrap();
+///
+/// // There may be a socket ready to be accepted
+/// ```
+#[derive(Debug)]
+pub struct TcpListener {
+ sys: sys::TcpListener,
+ selector_id: SelectorId,
+}
+
+impl TcpListener {
+ /// Convenience method to bind a new TCP listener to the specified address
+ /// to receive new connections.
+ ///
+ /// This function will take the following steps:
+ ///
+ /// 1. Create a new TCP socket.
+ /// 2. Set the `SO_REUSEADDR` option on the socket.
+ /// 3. Bind the socket to the specified address.
+ /// 4. Call `listen` on the socket to prepare it to receive new connections.
+ ///
+ /// If fine-grained control over the binding and listening process for a
+ /// socket is desired then the `net2::TcpBuilder` methods can be used in
+ /// combination with the `TcpListener::from_listener` method to transfer
+ /// ownership into mio.
+ pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
+ // Create the socket
+ let sock = try!(match *addr {
+ SocketAddr::V4(..) => TcpBuilder::new_v4(),
+ SocketAddr::V6(..) => TcpBuilder::new_v6(),
+ });
+
+ // Set SO_REUSEADDR, but only on Unix (mirrors what libstd does)
+ if cfg!(unix) {
+ try!(sock.reuse_address(true));
+ }
+
+ // Bind the socket
+ try!(sock.bind(addr));
+
+ // listen
+ let listener = try!(sock.listen(1024));
+ Ok(TcpListener {
+ sys: try!(sys::TcpListener::new(listener, addr)),
+ selector_id: SelectorId::new(),
+ })
+ }
+
+ /// Creates a new `TcpListener` from an instance of a
+ /// `std::net::TcpListener` type.
+ ///
+ /// This function will set the `listener` provided into nonblocking mode on
+ /// Unix, and otherwise the stream will just be wrapped up in an mio stream
+ /// ready to accept new connections and become associated with an event
+ /// loop.
+ ///
+ /// The address provided must be the address that the listener is bound to.
+ pub fn from_listener(listener: net::TcpListener, addr: &SocketAddr)
+ -> io::Result<TcpListener> {
+ sys::TcpListener::new(listener, addr).map(|s| {
+ TcpListener {
+ sys: s,
+ selector_id: SelectorId::new(),
+ }
+ })
+ }
+
+ /// Accepts a new `TcpStream`.
+ ///
+ /// This may return an `Err(e)` where `e.kind()` is
+ /// `io::ErrorKind::WouldBlock`. This means a stream may be ready at a later
+ /// point and one should wait for a notification before calling `accept`
+ /// again.
+ ///
+ /// If an accepted stream is returned, the remote address of the peer is
+ /// returned along with it.
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ self.sys.accept().map(|(s, a)| {
+ let stream = TcpStream {
+ sys: s,
+ selector_id: SelectorId::new(),
+ };
+
+ (stream, a)
+ })
+ }
+
+ /// Returns the local socket address of this listener.
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.sys.local_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.
+ pub fn try_clone(&self) -> io::Result<TcpListener> {
+ self.sys.try_clone().map(|s| {
+ TcpListener {
+ sys: s,
+ selector_id: self.selector_id.clone(),
+ }
+ })
+ }
+
+ /// 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.
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.sys.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
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.sys.ttl()
+ }
+
+ /// Sets the value for the `IPV6_V6ONLY` option on this socket.
+ ///
+ /// If this is set to `true` then the socket is restricted to sending and
+ /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
+ /// can bind the same port at the same time.
+ ///
+ /// If this is set to `false` then the socket can be used to send and
+ /// receive packets from an IPv4-mapped IPv6 address.
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ self.sys.set_only_v6(only_v6)
+ }
+
+ /// Gets the value of the `IPV6_V6ONLY` option for this socket.
+ ///
+ /// For more information about this option, see [`set_only_v6`][link].
+ ///
+ /// [link]: #method.set_only_v6
+ pub fn only_v6(&self) -> io::Result<bool> {
+ self.sys.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.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.sys.take_error()
+ }
+}
+
+impl Evented for TcpListener {
+ fn register(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ try!(self.selector_id.associate_selector(poll));
+ self.sys.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.sys.deregister(poll)
+ }
+}
+
+/*
+ *
+ * ===== UNIX ext =====
+ *
+ */
+
+#[cfg(unix)]
+use std::os::unix::io::{IntoRawFd, AsRawFd, FromRawFd, RawFd};
+
+#[cfg(unix)]
+impl IntoRawFd for TcpStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.sys.into_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl AsRawFd for TcpStream {
+ fn as_raw_fd(&self) -> RawFd {
+ self.sys.as_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl FromRawFd for TcpStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> TcpStream {
+ TcpStream {
+ sys: FromRawFd::from_raw_fd(fd),
+ selector_id: SelectorId::new(),
+ }
+ }
+}
+
+#[cfg(unix)]
+impl IntoRawFd for TcpListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.sys.into_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl AsRawFd for TcpListener {
+ fn as_raw_fd(&self) -> RawFd {
+ self.sys.as_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl FromRawFd for TcpListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
+ TcpListener {
+ sys: FromRawFd::from_raw_fd(fd),
+ selector_id: SelectorId::new(),
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/net/udp.rs
@@ -0,0 +1,304 @@
+//! Primitives for working with UDP
+//!
+//! The types provided in this module are non-blocking by default and are
+//! designed to be portable across all supported Mio platforms. As long as the
+//! [portability guidelines] are followed, the behavior should be identical no
+//! matter the target platform.
+//!
+/// [portability guidelines]: ../struct.Poll.html#portability
+
+use {io, sys, Ready, Poll, PollOpt, Token};
+use event::Evented;
+use poll::SelectorId;
+use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr};
+
+/// A User Datagram Protocol socket.
+///
+/// This is an implementation of a bound UDP socket. This supports both IPv4 and
+/// IPv6 addresses, and there is no corresponding notion of a server because UDP
+/// is a datagram protocol.
+#[derive(Debug)]
+pub struct UdpSocket {
+ sys: sys::UdpSocket,
+ selector_id: SelectorId,
+}
+
+impl UdpSocket {
+ /// Creates a UDP socket from the given address.
+ pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
+ let socket = try!(net::UdpSocket::bind(addr));
+ UdpSocket::from_socket(socket)
+ }
+
+ /// Creates a new mio-wrapped socket from an underlying and bound std
+ /// socket.
+ ///
+ /// This function requires that `socket` has previously been bound to an
+ /// address to work correctly, and returns an I/O object which can be used
+ /// with mio to send/receive UDP messages.
+ ///
+ /// This can be used in conjunction with net2's `UdpBuilder` interface to
+ /// configure a socket before it's handed off to mio, such as setting
+ /// options like `reuse_address` or binding to multiple addresses.
+ pub fn from_socket(socket: net::UdpSocket) -> io::Result<UdpSocket> {
+ Ok(UdpSocket {
+ sys: try!(sys::UdpSocket::new(socket)),
+ selector_id: SelectorId::new(),
+ })
+ }
+
+ /// Returns the socket address that this socket was created from.
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.sys.local_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.
+ pub fn try_clone(&self) -> io::Result<UdpSocket> {
+ self.sys.try_clone()
+ .map(|s| {
+ UdpSocket {
+ sys: s,
+ selector_id: self.selector_id.clone(),
+ }
+ })
+ }
+
+ /// 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.
+ pub fn send_to(&self, buf: &[u8], target: &SocketAddr) -> io::Result<usize> {
+ self.sys.send_to(buf, target)
+ }
+
+ /// Receives data from the socket. On success, returns the number of bytes
+ /// read and the address from whence the data came.
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.sys.recv_from(buf)
+ }
+
+ /// Sends data on the socket to the address previously bound via connect(). On success,
+ /// returns the number of bytes written.
+ ///
+ /// Address type can be any implementor of `ToSocketAddrs` trait. See its
+ /// documentation for concrete examples.
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ self.sys.send(buf)
+ }
+
+ /// Receives data from the socket previously bound with connect(). On success, returns
+ /// the number of bytes read and the address from whence the data came.
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.sys.recv(buf)
+ }
+
+ /// Connects the UDP socket setting the default destination for `send()`
+ /// and limiting packets that are read via `recv` from the address specified
+ /// in `addr`.
+ pub fn connect(&self, addr: SocketAddr) -> io::Result<()> {
+ self.sys.connect(addr)
+ }
+
+ /// 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
+ pub fn broadcast(&self) -> io::Result<bool> {
+ self.sys.broadcast()
+ }
+
+ /// Sets the value of the `SO_BROADCAST` option for this socket.
+ ///
+ /// When enabled, this socket is allowed to send packets to a broadcast
+ /// address.
+ pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
+ self.sys.set_broadcast(on)
+ }
+
+ /// 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
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ self.sys.multicast_loop_v4()
+ }
+
+ /// 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.
+ pub fn set_multicast_loop_v4(&self, on: bool) -> io::Result<()> {
+ self.sys.set_multicast_loop_v4(on)
+ }
+
+ /// 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
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ self.sys.multicast_ttl_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.
+ pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
+ self.sys.set_multicast_ttl_v4(ttl)
+ }
+
+ /// 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
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ self.sys.multicast_loop_v6()
+ }
+
+ /// 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.
+ pub fn set_multicast_loop_v6(&self, on: bool) -> io::Result<()> {
+ self.sys.set_multicast_loop_v6(on)
+ }
+
+ /// 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
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.sys.ttl()
+ }
+
+ /// 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.
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.sys.set_ttl(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.
+ pub fn join_multicast_v4(&self,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr) -> io::Result<()> {
+ self.sys.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).
+ pub fn join_multicast_v6(&self,
+ multiaddr: &Ipv6Addr,
+ interface: u32) -> io::Result<()> {
+ self.sys.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
+ pub fn leave_multicast_v4(&self,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr) -> io::Result<()> {
+ self.sys.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
+ pub fn leave_multicast_v6(&self,
+ multiaddr: &Ipv6Addr,
+ interface: u32) -> io::Result<()> {
+ self.sys.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.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.sys.take_error()
+ }
+}
+
+impl Evented for UdpSocket {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ try!(self.selector_id.associate_selector(poll));
+ self.sys.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.sys.deregister(poll)
+ }
+}
+
+/*
+ *
+ * ===== UNIX ext =====
+ *
+ */
+
+#[cfg(unix)]
+use std::os::unix::io::{IntoRawFd, AsRawFd, FromRawFd, RawFd};
+
+#[cfg(unix)]
+impl IntoRawFd for UdpSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.sys.into_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl AsRawFd for UdpSocket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.sys.as_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl FromRawFd for UdpSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> UdpSocket {
+ UdpSocket {
+ sys: FromRawFd::from_raw_fd(fd),
+ selector_id: SelectorId::new(),
+ }
+ }
+}
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/poll.rs
@@ -0,0 +1,2526 @@
+use {sys, Token};
+use event_imp::{self as event, Ready, Event, Evented, PollOpt};
+use std::{fmt, io, ptr, usize};
+use std::cell::UnsafeCell;
+use std::{mem, ops, isize};
+#[cfg(unix)]
+use std::os::unix::io::AsRawFd;
+#[cfg(unix)]
+use std::os::unix::io::RawFd;
+use std::sync::{Arc, Mutex, Condvar};
+use std::sync::atomic::{AtomicUsize, AtomicPtr, AtomicBool};
+use std::sync::atomic::Ordering::{self, Acquire, Release, AcqRel, Relaxed, SeqCst};
+use std::time::{Duration, Instant};
+#[cfg(unix)]
+use sys::unix::UnixReady;
+
+// Poll is backed by two readiness queues. The first is a system readiness queue
+// represented by `sys::Selector`. The system readiness queue handles events
+// provided by the system, such as TCP and UDP. The second readiness queue is
+// implemented in user space by `ReadinessQueue`. It provides a way to implement
+// purely user space `Evented` types.
+//
+// `ReadinessQueue` is is backed by a MPSC queue that supports reuse of linked
+// list nodes. This significantly reduces the number of required allocations.
+// Each `Registration` / `SetReadiness` pair allocates a single readiness node
+// that is used for the lifetime of the registration.
+//
+// The readiness node also includes a single atomic variable, `state` that
+// tracks most of the state associated with the registration. This includes the
+// current readiness, interest, poll options, and internal state. When the node
+// state is mutated, it is queued in the MPSC channel. A call to
+// `ReadinessQueue::poll` will dequeue and process nodes. The node state can
+// still be mutated while it is queued in the channel for processing.
+// Intermediate state values do not matter as long as the final state is
+// included in the call to `poll`. This is the eventually consistent nature of
+// the readiness queue.
+//
+// The readiness node is ref counted using the `ref_count` field. On creation,
+// the ref_count is initialized to 3: one `Registration` handle, one
+// `SetReadiness` handle, and one for the readiness queue. Since the readiness queue
+// doesn't *always* hold a handle to the node, we don't use the Arc type for
+// managing ref counts (this is to avoid constantly incrementing and
+// decrementing the ref count when pushing & popping from the queue). When the
+// `Registration` handle is dropped, the `dropped` flag is set on the node, then
+// the node is pushed into the registration queue. When Poll::poll pops the
+// node, it sees the drop flag is set, and decrements it's ref count.
+//
+// The MPSC queue is a modified version of the intrusive MPSC node based queue
+// described by 1024cores [1].
+//
+// The first modification is that two markers are used instead of a single
+// `stub`. The second marker is a `sleep_marker` which is used to signal to
+// producers that the consumer is going to sleep. This sleep_marker is only used
+// when the queue is empty, implying that the only node in the queue is
+// `end_marker`.
+//
+// The second modification is an `until` argument passed to the dequeue
+// function. When `poll` encounters a level-triggered node, the node will be
+// immediately pushed back into the queue. In order to avoid an infinite loop,
+// `poll` before pushing the node, the pointer is saved off and then passed
+// again as the `until` argument. If the next node to pop is `until`, then
+// `Dequeue::Empty` is returned.
+//
+// [1] http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
+
+
+/// Polls for readiness events on all registered values.
+///
+/// `Poll` allows a program to monitor a large number of `Evented` types,
+/// waiting until one or more become "ready" for some class of operations; e.g.
+/// reading and writing. An `Evented` type is considered ready if it is possible
+/// to immediately perform a corresponding operation; e.g. [`read`] or
+/// [`write`].
+///
+/// To use `Poll`, an `Evented` type must first be registered with the `Poll`
+/// instance using the [`register`] method, supplying readiness interest. The
+/// readiness interest tells `Poll` which specific operations on the handle to
+/// monitor for readiness. A `Token` is also passed to the [`register`]
+/// function. When `Poll` returns a readiness event, it will include this token.
+/// This associates the event with the `Evented` handle that generated the
+/// event.
+///
+/// [`read`]: tcp/struct.TcpStream.html#method.read
+/// [`write`]: tcp/struct.TcpStream.html#method.write
+/// [`register`]: #method.register
+///
+/// # Examples
+///
+/// A basic example -- establishing a `TcpStream` connection.
+///
+/// ```
+/// use mio::{Events, Poll, Ready, PollOpt, Token};
+/// use mio::tcp::TcpStream;
+///
+/// use std::net::{TcpListener, SocketAddr};
+///
+/// // Bind a server socket to connect to.
+/// let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
+/// let server = TcpListener::bind(&addr).unwrap();
+///
+/// // Construct a new `Poll` handle as well as the `Events` we'll store into
+/// let poll = Poll::new().unwrap();
+/// let mut events = Events::with_capacity(1024);
+///
+/// // Connect the stream
+/// let stream = TcpStream::connect(&server.local_addr().unwrap()).unwrap();
+///
+/// // Register the stream with `Poll`
+/// poll.register(&stream, Token(0), Ready::all(), PollOpt::edge()).unwrap();
+///
+/// // Wait for the socket to become ready. This has to happens in a loop to
+/// // handle spurious wakeups.
+/// loop {
+/// poll.poll(&mut events, None).unwrap();
+///
+/// for event in &events {
+/// if event.token() == Token(0) && event.readiness().is_writable() {
+/// // The socket connected (probably, it could still be a spurious
+/// // wakeup)
+/// return;
+/// }
+/// }
+/// }
+/// ```
+///
+/// # Edge-triggered and level-triggered
+///
+/// An [`Evented`] registration may request edge-triggered events or
+/// level-triggered events. This is done by setting `register`'s
+/// [`PollOpt`] argument to either [`edge`] or [`level`].
+///
+/// The difference between the two can be described as follows. Supposed that
+/// this scenario happens:
+///
+/// 1. A [`TcpStream`] is registered with `Poll`.
+/// 2. The socket receives 2kb of data.
+/// 3. A call to [`Poll::poll`] returns the token associated with the socket
+/// indicating readable readiness.
+/// 4. 1kb is read from the socket.
+/// 5. Another call to [`Poll::poll`] is made.
+///
+/// If when the socket was registered with `Poll`, edge triggered events were
+/// requested, then the call to [`Poll::poll`] done in step **5** will
+/// (probably) hang despite there being another 1kb still present in the socket
+/// read buffer. The reason for this is that edge-triggered mode delivers events
+/// only when changes occur on the monitored [`Evented`]. So, in step *5* the
+/// caller might end up waiting for some data that is already present inside the
+/// socket buffer.
+///
+/// With edge-triggered events, operations **must** be performed on the
+/// `Evented` type until [`WouldBlock`] is returned. In other words, after
+/// receiving an event indicating readiness for a certain operation, one should
+/// assume that [`Poll::poll`] may never return another event for the same token
+/// and readiness until the operation returns [`WouldBlock`].
+///
+/// By contrast, when level-triggered notfications was requested, each call to
+/// [`Poll::poll`] will return an event for the socket as long as data remains
+/// in the socket buffer. Generally, level-triggered events should be avoided if
+/// high performance is a concern.
+///
+/// Since even with edge-triggered events, multiple events can be generated upon
+/// receipt of multiple chunks of data, the caller has the option to set the
+/// [`oneshot`] flag. This tells `Poll` to disable the associated [`Evented`]
+/// after the event is returned from [`Poll::poll`]. The subsequent calls to
+/// [`Poll::poll`] will no longer include events for [`Evented`] handles that
+/// are disabled even if the readiness state changes. The handle can be
+/// re-enabled by calling [`reregister`]. When handles are disabled, internal
+/// resources used to monitor the handle are maintained until the handle is
+/// dropped or deregistered. This makes re-registering the handle a fast
+/// operation.
+///
+/// For example, in the following scenario:
+///
+/// 1. A [`TcpStream`] is registered with `Poll`.
+/// 2. The socket receives 2kb of data.
+/// 3. A call to [`Poll::poll`] returns the token associated with the socket
+/// indicating readable readiness.
+/// 4. 2kb is read from the socket.
+/// 5. Another call to read is issued and [`WouldBlock`] is returned
+/// 6. The socket receives another 2kb of data.
+/// 7. Another call to [`Poll::poll`] is made.
+///
+/// Assuming the socket was registered with `Poll` with the [`edge`] and
+/// [`oneshot`] options, then the call to [`Poll::poll`] in step 7 would block. This
+/// is because, [`oneshot`] tells `Poll` to disable events for the socket after
+/// returning an event.
+///
+/// In order to receive the event for the data received in step 6, the socket
+/// would need to be reregistered using [`reregister`].
+///
+/// [`PollOpt`]: struct.PollOpt.html
+/// [`edge`]: struct.PollOpt.html#method.edge
+/// [`level`]: struct.PollOpt.html#method.level
+/// [`Poll::poll`]: struct.Poll.html#method.poll
+/// [`WouldBlock`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.WouldBlock
+/// [`Evented`]: event/trait.Evented.html
+/// [`TcpStream`]: tcp/struct.TcpStream.html
+/// [`reregister`]: #method.reregister
+/// [`oneshot`]: struct.PollOpt.html#method.oneshot
+///
+/// # Portability
+///
+/// Using `Poll` provides a portable interface across supported platforms as
+/// long as the caller takes the following into consideration:
+///
+/// ### Spurious events
+///
+/// [`Poll::poll`] may return readiness events even if the associated
+/// [`Evented`] handle is not actually ready. Given the same code, this may
+/// happen more on some platforms than others. It is important to never assume
+/// that, just because a readiness notification was received, that the
+/// associated operation will as well.
+///
+/// If operation fails with [`WouldBlock`], then the caller should not treat
+/// this as an error and wait until another readiness event is received.
+///
+/// ### Draining readiness
+///
+/// When using edge-triggered mode, once a readiness event is received, the
+/// corresponding operation must be performed repeatedly until it returns
+/// [`WouldBlock`]. Unless this is done, there is no guarantee that another
+/// readiness event will be delivered, even if further data is received for the
+/// [`Evented`] handle.
+///
+/// For example, in the first scenario described above, after step 5, even if
+/// the socket receives more data there is no guarantee that another readiness
+/// event will be delivered.
+///
+/// ### Readiness operations
+///
+/// The only readiness operations that are guaranteed to be present on all
+/// supported platforms are [`readable`] and [`writable`]. All other readiness
+/// operations may have false negatives and as such should be considered
+/// **hints**. This means that if a socket is registered with [`readable`],
+/// [`error`], and [`hup`] interest, and either an error or hup is received, a
+/// readiness event will be generated for the socket, but it **may** only
+/// include `readable` readiness. Also note that, given the potential for
+/// spurious events, receiving a readiness event with `hup` or `error` doesn't
+/// actually mean that a `read` on the socket will return a result matching the
+/// readiness event.
+///
+/// In other words, portable programs that explicitly check for [`hup`] or
+/// [`error`] readiness should be doing so as an **optimization** and always be
+/// able to handle an error or HUP situation when performing the actual read
+/// operation.
+///
+/// [`readable`]: struct.Ready.html#method.readable
+/// [`writable`]: struct.Ready.html#method.writable
+/// [`error`]: struct.Ready.html#method.error
+/// [`hup`]: struct.Ready.html#method.hup
+///
+/// ### Registering handles
+///
+/// Unless otherwise noted, it should be assumed that types implementing
+/// [`Evented`] will never be become ready unless they are registered with `Poll`.
+///
+/// For example:
+///
+/// ```
+/// use mio::{Poll, Ready, PollOpt, Token};
+/// use mio::tcp::TcpStream;
+/// use std::time::Duration;
+/// use std::thread;
+///
+/// let sock = TcpStream::connect(&"216.58.193.100:80".parse().unwrap()).unwrap();
+///
+/// thread::sleep(Duration::from_secs(1));
+///
+/// let poll = Poll::new().unwrap();
+///
+/// // The connect is not guaranteed to have started until it is registered at
+/// // this point
+/// poll.register(&sock, Token(0), Ready::all(), PollOpt::edge()).unwrap();
+/// ```
+///
+/// # Implementation notes
+///
+/// `Poll` is backed by the selector provided by the operating system.
+///
+/// | OS | Selector |
+/// |------------|-----------|
+/// | Linux | [epoll] |
+/// | OS X, iOS | [kqueue] |
+/// | Windows | [IOCP] |
+/// | FreeBSD | [kqueue] |
+/// | Android | [epoll] |
+///
+/// On all supported platforms, socket operations are handled by using the
+/// system selector. Platform specific extensions (e.g. [`EventedFd`]) allow
+/// accessing other features provided by individual system selectors. For
+/// example, Linux's [`signalfd`] feature can be used by registering the FD with
+/// `Poll` via [`EventedFd`].
+///
+/// On all platforms except windows, a call to [`Poll::poll`] is mostly just a
+/// direct call to the system selector. However, [IOCP] uses a completion model
+/// instead of a readiness model. In this case, `Poll` must adapt the completion
+/// model Mio's API. While non-trivial, the bridge layer is still quite
+/// efficient. The most expensive part being calls to `read` and `write` require
+/// data to be copied into an intermediate buffer before it is passed to the
+/// kernel.
+///
+/// Notifications generated by [`SetReadiness`] are handled by an internal
+/// readiness queue. A single call to [`Poll::poll`] will collect events from
+/// both from the system selector and the internal readiness queue.
+///
+/// [epoll]: http://man7.org/linux/man-pages/man7/epoll.7.html
+/// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
+/// [IOCP]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365198(v=vs.85).aspx
+/// [`signalfd`]: http://man7.org/linux/man-pages/man2/signalfd.2.html
+/// [`EventedFd`]: unix/struct.EventedFd.html
+/// [`SetReadiness`]: struct.SetReadiness.html
+/// [`Poll::poll`]: struct.Poll.html#method.poll
+pub struct Poll {
+ // Platform specific IO selector
+ selector: sys::Selector,
+
+ // Custom readiness queue
+ readiness_queue: ReadinessQueue,
+
+ // Use an atomic to first check if a full lock will be required. This is a
+ // fast-path check for single threaded cases avoiding the extra syscall
+ lock_state: AtomicUsize,
+
+ // Sequences concurrent calls to `Poll::poll`
+ lock: Mutex<()>,
+
+ // Wakeup the next waiter
+ condvar: Condvar,
+}
+
+/// Handle to a user space `Poll` registration.
+///
+/// `Registration` allows implementing [`Evented`] for types that cannot work
+/// with the [system selector]. A `Registration` is always paired with a
+/// `SetReadiness`, which allows updating the registration's readiness state.
+/// When [`set_readiness`] is called and the `Registration` is associated with a
+/// [`Poll`] instance, a readiness event will be created and eventually returned
+/// by [`poll`].
+///
+/// A `Registration` / `SetReadiness` pair is created by calling
+/// [`Registration::new2`]. At this point, the registration is not being
+/// monitored by a [`Poll`] instance, so calls to `set_readiness` will not
+/// result in any readiness notifications.
+///
+/// `Registration` implements [`Evented`], so it can be used with [`Poll`] using
+/// the same [`register`], [`reregister`], and [`deregister`] functions used
+/// with TCP, UDP, etc... types. Once registered with [`Poll`], readiness state
+/// changes result in readiness events being dispatched to the [`Poll`] instance
+/// with which `Registration` is registered.
+///
+/// **Note**, before using `Registration` be sure to read the
+/// [`set_readiness`] documentation and the [portability] notes. The
+/// guarantees offered by `Registration` may be weaker than expected.
+///
+/// For high level documentation, see [`Poll`].
+///
+/// # Examples
+///
+/// ```
+/// use mio::{Ready, Registration, Poll, PollOpt, Token};
+/// use mio::event::Evented;
+///
+/// use std::io;
+/// use std::time::Instant;
+/// use std::thread;
+///
+/// pub struct Deadline {
+/// when: Instant,
+/// registration: Registration,
+/// }
+///
+/// impl Deadline {
+/// pub fn new(when: Instant) -> Deadline {
+/// let (registration, set_readiness) = Registration::new2();
+///
+/// thread::spawn(move || {
+/// let now = Instant::now();
+///
+/// if now < when {
+/// thread::sleep(when - now);
+/// }
+///
+/// set_readiness.set_readiness(Ready::readable());
+/// });
+///
+/// Deadline {
+/// when: when,
+/// registration: registration,
+/// }
+/// }
+///
+/// pub fn is_elapsed(&self) -> bool {
+/// Instant::now() >= self.when
+/// }
+/// }
+///
+/// impl Evented for Deadline {
+/// fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
+/// -> io::Result<()>
+/// {
+/// self.registration.register(poll, token, interest, opts)
+/// }
+///
+/// fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
+/// -> io::Result<()>
+/// {
+/// self.registration.reregister(poll, token, interest, opts)
+/// }
+///
+/// fn deregister(&self, poll: &Poll) -> io::Result<()> {
+/// self.registration.deregister(poll)
+/// }
+/// }
+/// ```
+///
+/// [system selector]: struct.Poll.html#implementation-notes
+/// [`Poll`]: struct.Poll.html
+/// [`Registration::new2`]: struct.Registration.html#method.new2
+/// [`Evented`]: event/trait.Evented.html
+pub struct Registration {
+ inner: RegistrationInner,
+}
+
+unsafe impl Send for Registration {}
+unsafe impl Sync for Registration {}
+
+/// Updates the readiness state of the associated [`Registration`].
+///
+/// See [`Registration`] for more documentation on using `SetReadiness` and
+/// [`Poll`] for high level polling documentation.
+///
+/// [`Registration`]
+#[derive(Clone)]
+pub struct SetReadiness {
+ inner: RegistrationInner,
+}
+
+unsafe impl Send for SetReadiness {}
+unsafe impl Sync for SetReadiness {}
+
+/// Used to associate an IO type with a Selector
+#[derive(Debug)]
+pub struct SelectorId {
+ id: AtomicUsize,
+}
+
+struct RegistrationInner {
+ // Unsafe pointer to the registration's node. The node is ref counted. This
+ // cannot "simply" be tracked by an Arc because `Poll::poll` has an implicit
+ // handle though it isn't stored anywhere. In other words, `Poll::poll`
+ // needs to decrement the ref count before the node is freed.
+ node: *mut ReadinessNode,
+}
+
+#[derive(Clone)]
+struct ReadinessQueue {
+ inner: Arc<ReadinessQueueInner>,
+}
+
+unsafe impl Send for ReadinessQueue {}
+unsafe impl Sync for ReadinessQueue {}
+
+struct ReadinessQueueInner {
+ // Used to wake up `Poll` when readiness is set in another thread.
+ awakener: sys::Awakener,
+
+ // Head of the MPSC queue used to signal readiness to `Poll::poll`.
+ head_readiness: AtomicPtr<ReadinessNode>,
+
+ // Tail of the readiness queue.
+ //
+ // Only accessed by Poll::poll. Coordination will be handled by the poll fn
+ tail_readiness: UnsafeCell<*mut ReadinessNode>,
+
+ // Fake readiness node used to punctuate the end of the readiness queue.
+ // Before attempting to read from the queue, this node is inserted in order
+ // to partition the queue between nodes that are "owned" by the dequeue end
+ // and nodes that will be pushed on by producers.
+ end_marker: Box<ReadinessNode>,
+
+ // Similar to `end_marker`, but this node signals to producers that `Poll`
+ // has gone to sleep and must be woken up.
+ sleep_marker: Box<ReadinessNode>,
+
+ // Similar to `end_marker`, but the node signals that the queue is closed.
+ // This happens when `ReadyQueue` is dropped and signals to producers that
+ // the nodes should no longer be pushed into the queue.
+ closed_marker: Box<ReadinessNode>,
+}
+
+/// Node shared by a `Registration` / `SetReadiness` pair as well as the node
+/// queued into the MPSC channel.
+struct ReadinessNode {
+ // Node state, see struct docs for `ReadinessState`
+ //
+ // This variable is the primary point of coordination between all the
+ // various threads concurrently accessing the node.
+ state: AtomicState,
+
+ // The registration token cannot fit into the `state` variable, so it is
+ // broken out here. In order to atomically update both the state and token
+ // we have to jump through a few hoops.
+ //
+ // First, `state` includes `token_read_pos` and `token_write_pos`. These can
+ // either be 0, 1, or 2 which represent a token slot. `token_write_pos` is
+ // the token slot that contains the most up to date registration token.
+ // `token_read_pos` is the token slot that `poll` is currently reading from.
+ //
+ // When a call to `update` includes a different token than the one currently
+ // associated with the registration (token_write_pos), first an unused token
+ // slot is found. The unused slot is the one not represented by
+ // `token_read_pos` OR `token_write_pos`. The new token is written to this
+ // slot, then `state` is updated with the new `token_write_pos` value. This
+ // requires that there is only a *single* concurrent call to `update`.
+ //
+ // When `poll` reads a node state, it checks that `token_read_pos` matches
+ // `token_write_pos`. If they do not match, then it atomically updates
+ // `state` such that `token_read_pos` is set to `token_write_pos`. It will
+ // then read the token at the newly updated `token_read_pos`.
+ token_0: UnsafeCell<Token>,
+ token_1: UnsafeCell<Token>,
+ token_2: UnsafeCell<Token>,
+
+ // Used when the node is queued in the readiness linked list. Accessing
+ // this field requires winning the "queue" lock
+ next_readiness: AtomicPtr<ReadinessNode>,
+
+ // Ensures that there is only one concurrent call to `update`.
+ //
+ // Each call to `update` will attempt to swap `update_lock` from `false` to
+ // `true`. If the CAS succeeds, the thread has obtained the update lock. If
+ // the CAS fails, then the `update` call returns immediately and the update
+ // is discarded.
+ update_lock: AtomicBool,
+
+ // Pointer to Arc<ReadinessQueueInner>
+ readiness_queue: AtomicPtr<()>,
+
+ // Tracks the number of `ReadyRef` pointers
+ ref_count: AtomicUsize,
+}
+
+/// Stores the ReadinessNode state in an AtomicUsize. This wrapper around the
+/// atomic variable handles encoding / decoding `ReadinessState` values.
+struct AtomicState {
+ inner: AtomicUsize,
+}
+
+const MASK_2: usize = 4 - 1;
+const MASK_4: usize = 16 - 1;
+const QUEUED_MASK: usize = 1 << QUEUED_SHIFT;
+const DROPPED_MASK: usize = 1 << DROPPED_SHIFT;
+
+const READINESS_SHIFT: usize = 0;
+const INTEREST_SHIFT: usize = 4;
+const POLL_OPT_SHIFT: usize = 8;
+const TOKEN_RD_SHIFT: usize = 12;
+const TOKEN_WR_SHIFT: usize = 14;
+const QUEUED_SHIFT: usize = 16;
+const DROPPED_SHIFT: usize = 17;
+
+/// Tracks all state for a single `ReadinessNode`. The state is packed into a
+/// `usize` variable from low to high bit as follows:
+///
+/// 4 bits: Registration current readiness
+/// 4 bits: Registration interest
+/// 4 bits: Poll options
+/// 2 bits: Token position currently being read from by `poll`
+/// 2 bits: Token position last written to by `update`
+/// 1 bit: Queued flag, set when node is being pushed into MPSC queue.
+/// 1 bit: Dropped flag, set when all `Registration` handles have been dropped.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+struct ReadinessState(usize);
+
+/// Returned by `dequeue_node`. Represents the different states as described by
+/// the queue documentation on 1024cores.net.
+enum Dequeue {
+ Data(*mut ReadinessNode),
+ Empty,
+ Inconsistent,
+}
+
+const AWAKEN: Token = Token(usize::MAX);
+const MAX_REFCOUNT: usize = (isize::MAX) as usize;
+
+/*
+ *
+ * ===== Poll =====
+ *
+ */
+
+impl Poll {
+ /// Return a new `Poll` handle.
+ ///
+ /// This function will make a syscall to the operating system to create the
+ /// system selector. If this syscall fails, `Poll::new` will return with the
+ /// error.
+ ///
+ /// See [struct] level docs for more details.
+ ///
+ /// [struct]: struct.Poll.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Poll, Events};
+ /// use std::time::Duration;
+ ///
+ /// let poll = match Poll::new() {
+ /// Ok(poll) => poll,
+ /// Err(e) => panic!("failed to create Poll instance; err={:?}", e),
+ /// };
+ ///
+ /// // Create a structure to receive polled events
+ /// let mut events = Events::with_capacity(1024);
+ ///
+ /// // Wait for events, but none will be received because no `Evented`
+ /// // handles have been registered with this `Poll` instance.
+ /// let n = poll.poll(&mut events, Some(Duration::from_millis(500))).unwrap();
+ /// assert_eq!(n, 0);
+ /// ```
+ pub fn new() -> io::Result<Poll> {
+ is_send::<Poll>();
+ is_sync::<Poll>();
+
+ let poll = Poll {
+ selector: try!(sys::Selector::new()),
+ readiness_queue: try!(ReadinessQueue::new()),
+ lock_state: AtomicUsize::new(0),
+ lock: Mutex::new(()),
+ condvar: Condvar::new(),
+ };
+
+ // Register the notification wakeup FD with the IO poller
+ try!(poll.readiness_queue.inner.awakener.register(&poll, AWAKEN, Ready::readable(), PollOpt::edge()));
+
+ Ok(poll)
+ }
+
+ /// Register an `Evented` handle with the `Poll` instance.
+ ///
+ /// Once registerd, the `Poll` instance will monitor the `Evented` handle
+ /// for readiness state changes. When it notices a state change, it will
+ /// return a readiness event for the handle the next time [`poll`] is
+ /// called.
+ ///
+ /// See the [`struct`] docs for a high level overview.
+ ///
+ /// # Arguments
+ ///
+ /// `handle: &E: Evented`: This is the handle that the `Poll` instance
+ /// should monitor for readiness state changes.
+ ///
+ /// `token: Token`: The caller picks a token to associate with the socket.
+ /// When [`poll`] returns an event for the handle, this token is included.
+ /// This allows the caller to map the event to its handle. The token
+ /// associated with the `Evented` handle can be changed at any time by
+ /// calling [`reregister`].
+ ///
+ /// `token` cannot be `Token(usize::MAX)` as it is reserved for internal
+ /// usage.
+ ///
+ /// See documentation on [`Token`] for an example showing how to pick
+ /// [`Token`] values.
+ ///
+ /// `interest: Ready`: Specifies which operations `Poll` should monitor for
+ /// readiness. `Poll` will only return readiness events for operations
+ /// specified by this argument.
+ ///
+ /// If a socket is registered with [`readable`] interest and the socket
+ /// becomes writable, no event will be returned from [`poll`].
+ ///
+ /// The readiness interest for an `Evented` handle can be changed at any
+ /// time by calling [`reregister`].
+ ///
+ /// `opts: PollOpt`: Specifies the registration options. The most common
+ /// options being [`level`] for level-triggered events, [`edge`] for
+ /// edge-triggered events, and [`oneshot`].
+ ///
+ /// The registration options for an `Evented` handle can be changed at any
+ /// time by calling [`reregister`].
+ ///
+ /// # Notes
+ ///
+ /// Unless otherwise specified, the caller should assume that once an
+ /// `Evented` handle is registered with a `Poll` instance, it is bound to
+ /// that `Poll` instance for the lifetime of the `Evented` handle. This
+ /// remains true even if the `Evented` handle is deregistered from the poll
+ /// instance using [`deregister`].
+ ///
+ /// This function is **thread safe**. It can be called concurrently from
+ /// multiple threads.
+ ///
+ /// [`struct`]: #
+ /// [`reregister`]: #method.reregister
+ /// [`deregister`]: #method.deregister
+ /// [`poll`]: #method.poll
+ /// [`level`]: struct.PollOpt.html#method.level
+ /// [`edge`]: struct.PollOpt.html#method.edge
+ /// [`oneshot`]: struct.PollOpt.html#method.oneshot
+ /// [`Token`]: struct.Token.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Events, Poll, Ready, PollOpt, Token};
+ /// use mio::tcp::TcpStream;
+ /// use std::time::{Duration, Instant};
+ ///
+ /// let poll = Poll::new().unwrap();
+ /// let socket = TcpStream::connect(&"216.58.193.100:80".parse().unwrap()).unwrap();
+ ///
+ /// // Register the socket with `poll`
+ /// poll.register(&socket, Token(0), Ready::all(), PollOpt::edge()).unwrap();
+ ///
+ /// let mut events = Events::with_capacity(1024);
+ /// let start = Instant::now();
+ /// let timeout = Duration::from_millis(500);
+ ///
+ /// loop {
+ /// let elapsed = start.elapsed();
+ ///
+ /// if elapsed >= timeout {
+ /// // Connection timed out
+ /// return;
+ /// }
+ ///
+ /// let remaining = timeout - elapsed;
+ /// poll.poll(&mut events, Some(remaining)).unwrap();
+ ///
+ /// for event in &events {
+ /// if event.token() == Token(0) {
+ /// // Something (probably) happened on the socket.
+ /// return;
+ /// }
+ /// }
+ /// }
+ /// ```
+ pub fn register<E: ?Sized>(&self, handle: &E, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()>
+ where E: Evented
+ {
+ try!(validate_args(token, interest));
+
+ /*
+ * Undefined behavior:
+ * - Reusing a token with a different `Evented` without deregistering
+ * (or closing) the original `Evented`.
+ */
+ trace!("registering with poller");
+
+ // Register interests for this socket
+ try!(handle.register(self, token, interest, opts));
+
+ Ok(())
+ }
+
+ /// Re-register an `Evented` handle with the `Poll` instance.
+ ///
+ /// Re-registering an `Evented` handle allows changing the details of the
+ /// registration. Specifically, it allows updating the associated `token`,
+ /// `interest`, and `opts` specified in previous `register` and `reregister`
+ /// calls.
+ ///
+ /// The `reregister` arguments fully override the previous values. In other
+ /// words, if a socket is registered with [`readable`] interest and the call
+ /// to `reregister` specifies [`writable`], then read interest is no longer
+ /// requested for the handle.
+ ///
+ /// The `Evented` handle must have previously been registered with this
+ /// instance of `Poll` otherwise the call to `reregister` will return with
+ /// an error.
+ ///
+ /// `token` cannot be `Token(usize::MAX)` as it is reserved for internal
+ /// usage.
+ ///
+ /// See the [`register`] documentation for details about the function
+ /// arguments and see the [`struct`] docs for a high level overview of
+ /// polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Poll, Ready, PollOpt, Token};
+ /// use mio::tcp::TcpStream;
+ ///
+ /// let poll = Poll::new().unwrap();
+ /// let socket = TcpStream::connect(&"216.58.193.100:80".parse().unwrap()).unwrap();
+ ///
+ /// // Register the socket with `poll`, requesting readable
+ /// poll.register(&socket, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
+ ///
+ /// // Reregister the socket specifying a different token and write interest
+ /// // instead. `PollOpt::edge()` must be specified even though that value
+ /// // is not being changed.
+ /// poll.reregister(&socket, Token(2), Ready::writable(), PollOpt::edge()).unwrap();
+ /// ```
+ ///
+ /// [`struct`]: #
+ /// [`register`]: #method.register
+ /// [`readable`]: struct.Ready.html#method.readable
+ /// [`writable`]: struct.Ready.html#method.writable
+ pub fn reregister<E: ?Sized>(&self, handle: &E, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()>
+ where E: Evented
+ {
+ try!(validate_args(token, interest));
+
+ trace!("registering with poller");
+
+ // Register interests for this socket
+ try!(handle.reregister(self, token, interest, opts));
+
+ Ok(())
+ }
+
+ /// Deregister an `Evented` handle with the `Poll` instance.
+ ///
+ /// When an `Evented` handle is deregistered, the `Poll` instance will
+ /// no longer monitor it for readiness state changes. Unlike disabling
+ /// handles with [`oneshot`], deregistering clears up any internal resources
+ /// needed to track the handle.
+ ///
+ /// A handle can be passed back to `register` after it has been
+ /// deregistered; however, it must be passed back to the **same** `Poll`
+ /// instance.
+ ///
+ /// `Evented` handles are automatically deregistered when they are dropped.
+ /// It is common to never need to explicitly call `deregister`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Events, Poll, Ready, PollOpt, Token};
+ /// use mio::tcp::TcpStream;
+ /// use std::time::Duration;
+ ///
+ /// let poll = Poll::new().unwrap();
+ /// let socket = TcpStream::connect(&"216.58.193.100:80".parse().unwrap()).unwrap();
+ ///
+ /// // Register the socket with `poll`
+ /// poll.register(&socket, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
+ ///
+ /// poll.deregister(&socket).unwrap();
+ ///
+ /// let mut events = Events::with_capacity(1024);
+ ///
+ /// // Set a timeout because this poll should never receive any events.
+ /// let n = poll.poll(&mut events, Some(Duration::from_secs(1))).unwrap();
+ /// assert_eq!(0, n);
+ /// ```
+ pub fn deregister<E: ?Sized>(&self, handle: &E) -> io::Result<()>
+ where E: Evented
+ {
+ trace!("deregistering handle with poller");
+
+ // Deregister interests for this socket
+ try!(handle.deregister(self));
+
+ Ok(())
+ }
+
+ /// Wait for readiness events
+ ///
+ /// Blocks the current thread and waits for readiness events for any of the
+ /// `Evented` handles that have been registered with this `Poll` instance.
+ /// The function will block until either at least one readiness event has
+ /// been received or `timeout` has elapsed. A `timeout` of `None` means that
+ /// `poll` will block until a readiness event has been received.
+ ///
+ /// The supplied `events` will be cleared and newly received readinss events
+ /// will be pushed onto the end. At most `events.capacity()` events will be
+ /// returned. If there are further pending readiness events, they will be
+ /// returned on the next call to `poll`.
+ ///
+ /// A single call to `poll` may result in multiple readiness events being
+ /// returned for a single `Evented` handle. For example, if a TCP socket
+ /// becomes both readable and writable, it may be possible for a single
+ /// readiness event to be returned with both [`readable`] and [`writable`]
+ /// readiness **OR** two separate events may be returned, one with
+ /// [`readable`] set and one with [`writable`] set.
+ ///
+ /// Note that the `timeout` will be rounded up to the system clock
+ /// granularity (usually 1ms), and kernel scheduling delays mean that
+ /// the blocking interval may be overrun by a small amount.
+ ///
+ /// `poll` returns the number of readiness events that have been pushed into
+ /// `events` or `Err` when an error has been encountered with the system
+ /// selector.
+ ///
+ /// See the [struct] level documentation for a higher level discussion of
+ /// polling.
+ ///
+ /// [`readable`]: struct.Ready.html#method.readable
+ /// [`writable`]: struct.Ready.html#method.writable
+ /// [struct]: #
+ ///
+ /// # Examples
+ ///
+ /// A basic example -- establishing a `TcpStream` connection.
+ ///
+ /// ```
+ /// use mio::{Events, Poll, Ready, PollOpt, Token};
+ /// use mio::tcp::TcpStream;
+ ///
+ /// use std::net::{TcpListener, SocketAddr};
+ /// use std::thread;
+ ///
+ /// // Bind a server socket to connect to.
+ /// let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
+ /// let server = TcpListener::bind(&addr).unwrap();
+ /// let addr = server.local_addr().unwrap().clone();
+ ///
+ /// // Spawn a thread to accept the socket
+ /// thread::spawn(move || {
+ /// let _ = server.accept();
+ /// });
+ ///
+ /// // Construct a new `Poll` handle as well as the `Events` we'll store into
+ /// let poll = Poll::new().unwrap();
+ /// let mut events = Events::with_capacity(1024);
+ ///
+ /// // Connect the stream
+ /// let stream = TcpStream::connect(&addr).unwrap();
+ ///
+ /// // Register the stream with `Poll`
+ /// poll.register(&stream, Token(0), Ready::all(), PollOpt::edge()).unwrap();
+ ///
+ /// // Wait for the socket to become ready. This has to happens in a loop to
+ /// // handle spurious wakeups.
+ /// loop {
+ /// poll.poll(&mut events, None).unwrap();
+ ///
+ /// for event in &events {
+ /// if event.token() == Token(0) && event.readiness().is_writable() {
+ /// // The socket connected (probably, it could still be a spurious
+ /// // wakeup)
+ /// return;
+ /// }
+ /// }
+ /// }
+ /// ```
+ ///
+ /// [struct]: #
+ pub fn poll(&self, events: &mut Events, mut timeout: Option<Duration>) -> io::Result<usize> {
+ let zero = Some(Duration::from_millis(0));
+
+ // At a high level, the synchronization strategy is to acquire access to
+ // the critical section by transitioning the atomic from unlocked ->
+ // locked. If the attempt fails, the thread will wait on the condition
+ // variable.
+ //
+ // # Some more detail
+ //
+ // The `lock_state` atomic usize combines:
+ //
+ // - locked flag, stored in the least significant bit
+ // - number of waiting threads, stored in the rest of the bits.
+ //
+ // When a thread transitions the locked flag from 0 -> 1, it has
+ // obtained access to the critical section.
+ //
+ // When entering `poll`, a compare-and-swap from 0 -> 1 is attempted.
+ // This is a fast path for the case when there are no concurrent calls
+ // to poll, which is very common.
+ //
+ // On failure, the mutex is locked, and the thread attempts to increment
+ // the number of waiting threads component of `lock_state`. If this is
+ // successfully done while the locked flag is set, then the thread can
+ // wait on the condition variable.
+ //
+ // When a thread exits the critical section, it unsets the locked flag.
+ // If there are any waiters, which is atomically determined while
+ // unsetting the locked flag, then the condvar is notified.
+
+ let mut curr = self.lock_state.compare_and_swap(0, 1, SeqCst);
+
+ if 0 != curr {
+ // Enter slower path
+ let mut lock = self.lock.lock().unwrap();
+ let mut inc = false;
+
+ loop {
+ if curr & 1 == 0 {
+ // The lock is currently free, attempt to grab it
+ let mut next = curr | 1;
+
+ if inc {
+ // The waiter count has previously been incremented, so
+ // decrement it here
+ next -= 2;
+ }
+
+ let actual = self.lock_state.compare_and_swap(curr, next, SeqCst);
+
+ if actual != curr {
+ curr = actual;
+ continue;
+ }
+
+ // Lock acquired, break from the loop
+ break;
+ }
+
+ if timeout == zero {
+ if inc {
+ self.lock_state.fetch_sub(2, SeqCst);
+ }
+
+ return Ok(0);
+ }
+
+ // The lock is currently held, so wait for it to become
+ // free. If the waiter count hasn't been incremented yet, do
+ // so now
+ if !inc {
+ let next = curr.checked_add(2).expect("overflow");
+ let actual = self.lock_state.compare_and_swap(curr, next, SeqCst);
+
+ if actual != curr {
+ curr = actual;
+ continue;
+ }
+
+ // Track that the waiter count has been incremented for
+ // this thread and fall through to the condvar waiting
+ inc = true;
+ }
+
+ lock = match timeout {
+ Some(to) => {
+ let now = Instant::now();
+
+ // Wait to be notified
+ let (l, _) = self.condvar.wait_timeout(lock, to).unwrap();
+
+ // See how much time was elapsed in the wait
+ let elapsed = now.elapsed();
+
+ // Update `timeout` to reflect how much time is left to
+ // wait.
+ if elapsed >= to {
+ timeout = zero;
+ } else {
+ // Update the timeout
+ timeout = Some(to - elapsed);
+ }
+
+ l
+ }
+ None => {
+ self.condvar.wait(lock).unwrap()
+ }
+ };
+
+ // Reload the state
+ curr = self.lock_state.load(SeqCst);
+
+ // Try to lock again...
+ }
+ }
+
+ let ret = self.poll2(events, timeout);
+
+ // Release the lock
+ if 1 != self.lock_state.fetch_and(!1, Release) {
+ // Acquire the mutex
+ let _lock = self.lock.lock().unwrap();
+
+ // There is at least one waiting thread, so notify one
+ self.condvar.notify_one();
+ }
+
+ ret
+ }
+
+ #[inline]
+ fn poll2(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
+ // Compute the timeout value passed to the system selector. If the
+ // readiness queue has pending nodes, we still want to poll the system
+ // selector for new events, but we don't want to block the thread to
+ // wait for new events.
+ let timeout = if timeout == Some(Duration::from_millis(0)) {
+ // If blocking is not requested, then there is no need to prepare
+ // the queue for sleep
+ timeout
+ } else if self.readiness_queue.prepare_for_sleep() {
+ // The readiness queue is empty. The call to `prepare_for_sleep`
+ // inserts `sleep_marker` into the queue. This signals to any
+ // threads setting readiness that the `Poll::poll` is going to
+ // sleep, so the awakener should be used.
+ timeout
+ } else {
+ // The readiness queue is not empty, so do not block the thread.
+ Some(Duration::from_millis(0))
+ };
+
+ // First get selector events
+ let res = self.selector.select(&mut events.inner, AWAKEN, timeout);
+
+ if try!(res) {
+ // Some awakeners require reading from a FD.
+ self.readiness_queue.inner.awakener.cleanup();
+ }
+
+ // Poll custom event queue
+ self.readiness_queue.poll(&mut events.inner);
+
+ // Return number of polled events
+ Ok(events.len())
+ }
+}
+
+#[cfg(unix)]
+fn registerable(interest: Ready) -> bool {
+ let unixinterest = UnixReady::from(interest);
+ unixinterest.is_readable() || unixinterest.is_writable() || unixinterest.is_aio()
+}
+
+#[cfg(not(unix))]
+fn registerable(interest: Ready) -> bool {
+ interest.is_readable() || interest.is_writable()
+}
+
+fn validate_args(token: Token, interest: Ready) -> io::Result<()> {
+ if token == AWAKEN {
+ return Err(io::Error::new(io::ErrorKind::Other, "invalid token"));
+ }
+
+ if !registerable(interest) {
+ return Err(io::Error::new(io::ErrorKind::Other, "interest must include readable or writable or aio"));
+ }
+
+ Ok(())
+}
+
+impl fmt::Debug for Poll {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "Poll")
+ }
+}
+
+#[cfg(unix)]
+impl AsRawFd for Poll {
+ fn as_raw_fd(&self) -> RawFd {
+ self.selector.as_raw_fd()
+ }
+}
+
+/// A collection of readiness events.
+///
+/// `Events` is passed as an argument to [`Poll::poll`] and will be used to
+/// receive any new readiness events received since the last call to [`poll`].
+/// Usually, a single `Events` instance is created at the same time as the
+/// [`Poll`] and the single instance is reused for each call to [`poll`].
+///
+/// See [`Poll`] for more documentation on polling.
+///
+/// # Examples
+///
+/// ```
+/// use mio::{Events, Poll};
+/// use std::time::Duration;
+///
+/// let mut events = Events::with_capacity(1024);
+/// let poll = Poll::new().unwrap();
+///
+/// assert_eq!(0, events.len());
+///
+/// // Register `Evented` handles with `poll`
+///
+/// poll.poll(&mut events, Some(Duration::from_millis(100))).unwrap();
+///
+/// for event in &events {
+/// println!("event={:?}", event);
+/// }
+/// ```
+///
+/// [`Poll::poll`]: struct.Poll.html#method.poll
+/// [`poll`]: struct.Poll.html#method.poll
+/// [`Poll`]: struct.Poll.html
+pub struct Events {
+ inner: sys::Events,
+}
+
+/// [`Events`] iterator.
+///
+/// This struct is created by the [`iter`] method on [`Events`].
+///
+/// # Examples
+///
+/// ```
+/// use mio::{Events, Poll};
+/// use std::time::Duration;
+///
+/// let mut events = Events::with_capacity(1024);
+/// let poll = Poll::new().unwrap();
+///
+/// // Register handles with `poll`
+///
+/// poll.poll(&mut events, Some(Duration::from_millis(100))).unwrap();
+///
+/// for event in events.iter() {
+/// println!("event={:?}", event);
+/// }
+/// ```
+///
+/// [`Events`]: struct.Events.html
+/// [`iter`]: struct.Events.html#method.iter
+#[derive(Debug)]
+pub struct Iter<'a> {
+ inner: &'a Events,
+ pos: usize,
+}
+
+impl Events {
+ /// Return a new `Events` capable of holding up to `capacity` events.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Events;
+ ///
+ /// let events = Events::with_capacity(1024);
+ ///
+ /// assert_eq!(1024, events.capacity());
+ /// ```
+ pub fn with_capacity(capacity: usize) -> Events {
+ Events {
+ inner: sys::Events::with_capacity(capacity),
+ }
+ }
+
+ /// Returns the `Event` at the given index, or `None` if the index is out of
+ /// bounds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Events, Poll};
+ /// use std::time::Duration;
+ ///
+ /// let mut events = Events::with_capacity(1024);
+ /// let poll = Poll::new().unwrap();
+ ///
+ /// // Register handles with `poll`
+ ///
+ /// let n = poll.poll(&mut events, Some(Duration::from_millis(100))).unwrap();
+ ///
+ /// for i in 0..n {
+ /// println!("event={:?}", events.get(i).unwrap());
+ /// }
+ /// ```
+ pub fn get(&self, idx: usize) -> Option<Event> {
+ self.inner.get(idx)
+ }
+
+ /// Returns the number of `Event` values currently in `self`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Events;
+ ///
+ /// let events = Events::with_capacity(1024);
+ ///
+ /// assert_eq!(0, events.len());
+ /// ```
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ /// Returns the number of `Event` values that `self` can hold.
+ ///
+ /// ```
+ /// use mio::Events;
+ ///
+ /// let events = Events::with_capacity(1024);
+ ///
+ /// assert_eq!(1024, events.capacity());
+ /// ```
+ pub fn capacity(&self) -> usize {
+ self.inner.capacity()
+ }
+
+ /// Returns `true` if `self` contains no `Event` values.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Events;
+ ///
+ /// let events = Events::with_capacity(1024);
+ ///
+ /// assert!(events.is_empty());
+ /// ```
+ pub fn is_empty(&self) -> bool {
+ self.inner.is_empty()
+ }
+
+ /// Returns an iterator over the `Event` values.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Events, Poll};
+ /// use std::time::Duration;
+ ///
+ /// let mut events = Events::with_capacity(1024);
+ /// let poll = Poll::new().unwrap();
+ ///
+ /// // Register handles with `poll`
+ ///
+ /// poll.poll(&mut events, Some(Duration::from_millis(100))).unwrap();
+ ///
+ /// for event in events.iter() {
+ /// println!("event={:?}", event);
+ /// }
+ /// ```
+ pub fn iter(&self) -> Iter {
+ Iter {
+ inner: self,
+ pos: 0
+ }
+ }
+}
+
+impl<'a> IntoIterator for &'a Events {
+ type Item = Event;
+ type IntoIter = Iter<'a>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a> Iterator for Iter<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ let ret = self.inner.get(self.pos);
+ self.pos += 1;
+ ret
+ }
+}
+
+impl fmt::Debug for Events {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Events")
+ .field("len", &self.len())
+ .field("capacity", &self.capacity())
+ .finish()
+ }
+}
+
+// ===== Accessors for internal usage =====
+
+pub fn selector(poll: &Poll) -> &sys::Selector {
+ &poll.selector
+}
+
+/*
+ *
+ * ===== Registration =====
+ *
+ */
+
+// TODO: get rid of this, windows depends on it for now
+#[allow(dead_code)]
+pub fn new_registration(poll: &Poll, token: Token, ready: Ready, opt: PollOpt)
+ -> (Registration, SetReadiness)
+{
+ Registration::new_priv(poll, token, ready, opt)
+}
+
+impl Registration {
+ /// Create and return a new `Registration` and the associated
+ /// `SetReadiness`.
+ ///
+ /// See [struct] documentation for more detail and [`Poll`]
+ /// for high level documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Events, Ready, Registration, Poll, PollOpt, Token};
+ /// use std::thread;
+ ///
+ /// let (registration, set_readiness) = Registration::new2();
+ ///
+ /// thread::spawn(move || {
+ /// use std::time::Duration;
+ /// thread::sleep(Duration::from_millis(500));
+ ///
+ /// set_readiness.set_readiness(Ready::readable());
+ /// });
+ ///
+ /// let poll = Poll::new().unwrap();
+ /// poll.register(®istration, Token(0), Ready::all(), PollOpt::edge()).unwrap();
+ ///
+ /// let mut events = Events::with_capacity(256);
+ ///
+ /// loop {
+ /// poll.poll(&mut events, None);
+ ///
+ /// for event in &events {
+ /// if event.token() == Token(0) && event.readiness().is_readable() {
+ /// return;
+ /// }
+ /// }
+ /// }
+ ///
+ /// ```
+ /// [struct]: #
+ /// [`Poll`]: struct.Poll.html
+ pub fn new2() -> (Registration, SetReadiness) {
+ // Allocate the registration node. The new node will have `ref_count`
+ // set to 2: one SetReadiness, one Registration.
+ let node = Box::into_raw(Box::new(ReadinessNode::new(
+ ptr::null_mut(), Token(0), Ready::empty(), PollOpt::empty(), 2)));
+
+ let registration = Registration {
+ inner: RegistrationInner {
+ node: node,
+ },
+ };
+
+ let set_readiness = SetReadiness {
+ inner: RegistrationInner {
+ node: node,
+ },
+ };
+
+ (registration, set_readiness)
+ }
+
+ #[deprecated(since = "0.6.5", note = "use `new2` instead")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ pub fn new(poll: &Poll, token: Token, interest: Ready, opt: PollOpt)
+ -> (Registration, SetReadiness)
+ {
+ Registration::new_priv(poll, token, interest, opt)
+ }
+
+ // TODO: Get rid of this (windows depends on it for now)
+ fn new_priv(poll: &Poll, token: Token, interest: Ready, opt: PollOpt)
+ -> (Registration, SetReadiness)
+ {
+ is_send::<Registration>();
+ is_sync::<Registration>();
+ is_send::<SetReadiness>();
+ is_sync::<SetReadiness>();
+
+ // Clone handle to the readiness queue, this bumps the ref count
+ let queue = poll.readiness_queue.inner.clone();
+
+ // Convert to a *mut () pointer
+ let queue: *mut () = unsafe { mem::transmute(queue) };
+
+ // Allocate the registration node. The new node will have `ref_count`
+ // set to 3: one SetReadiness, one Registration, and one Poll handle.
+ let node = Box::into_raw(Box::new(ReadinessNode::new(
+ queue, token, interest, opt, 3)));
+
+ let registration = Registration {
+ inner: RegistrationInner {
+ node: node,
+ },
+ };
+
+ let set_readiness = SetReadiness {
+ inner: RegistrationInner {
+ node: node,
+ },
+ };
+
+ (registration, set_readiness)
+ }
+
+ #[deprecated(since = "0.6.5", note = "use `Evented` impl")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ pub fn update(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.inner.update(poll, token, interest, opts)
+ }
+
+ #[deprecated(since = "0.6.5", note = "use `Evented` impl")]
+ #[cfg(feature = "with-deprecated")]
+ #[doc(hidden)]
+ pub fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.inner.update(poll, Token(0), Ready::empty(), PollOpt::empty())
+ }
+}
+
+impl Evented for Registration {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.inner.update(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.inner.update(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.inner.update(poll, Token(0), Ready::empty(), PollOpt::empty())
+ }
+}
+
+impl Drop for Registration {
+ fn drop(&mut self) {
+ // `flag_as_dropped` toggles the `dropped` flag and notifies
+ // `Poll::poll` to release its handle (which is just decrementing
+ // the ref count).
+ if self.inner.state.flag_as_dropped() {
+ // Can't do anything if the queuing fails
+ let _ = self.inner.enqueue_with_wakeup();
+ }
+ }
+}
+
+impl fmt::Debug for Registration {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("Registration")
+ .finish()
+ }
+}
+
+impl SetReadiness {
+ /// Returns the registration's current readiness.
+ ///
+ /// # Note
+ ///
+ /// There is no guarantee that `readiness` establishes any sort of memory
+ /// ordering. Any concurrent data access must be synchronized using another
+ /// strategy.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::{Registration, Ready};
+ ///
+ /// let (registration, set_readiness) = Registration::new2();
+ ///
+ /// assert!(set_readiness.readiness().is_empty());
+ ///
+ /// set_readiness.set_readiness(Ready::readable()).unwrap();
+ /// assert!(set_readiness.readiness().is_readable());
+ /// ```
+ pub fn readiness(&self) -> Ready {
+ self.inner.readiness()
+ }
+
+ /// Set the registration's readiness
+ ///
+ /// If the associated `Registration` is registered with a [`Poll`] instance
+ /// and has requested readiness events that include `ready`, then a call
+ /// [`poll`] will receive a readiness event representing the readiness
+ /// state change.
+ ///
+ /// # Note
+ ///
+ /// There is no guarantee that `readiness` establishes any sort of memory
+ /// ordering. Any concurrent data access must be synchronized using another
+ /// strategy.
+ ///
+ /// There is also no guarantee as to when the readiness event will be
+ /// delivered to poll. A best attempt will be made to make the delivery in a
+ /// "timely" fashion. For example, the following is **not** guaranteed to
+ /// work:
+ ///
+ /// ```
+ /// use mio::{Events, Registration, Ready, Poll, PollOpt, Token};
+ ///
+ /// let poll = Poll::new().unwrap();
+ /// let (registration, set_readiness) = Registration::new2();
+ ///
+ /// poll.register(®istration,
+ /// Token(0),
+ /// Ready::readable(),
+ /// PollOpt::edge()).unwrap();
+ ///
+ /// // Set the readiness, then immediately poll to try to get the readiness
+ /// // event
+ /// set_readiness.set_readiness(Ready::readable()).unwrap();
+ ///
+ /// let mut events = Events::with_capacity(1024);
+ /// poll.poll(&mut events, None).unwrap();
+ ///
+ /// // There is NO guarantee that the following will work. It is possible
+ /// // that the readiness event will be delivered at a later time.
+ /// let event = events.get(0).unwrap();
+ /// assert_eq!(event.token(), Token(0));
+ /// assert!(event.readiness().is_readable());
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// A simple example, for a more elaborate example, see the [`Evented`]
+ /// documentation.
+ ///
+ /// ```
+ /// use mio::{Registration, Ready};
+ ///
+ /// let (registration, set_readiness) = Registration::new2();
+ ///
+ /// assert!(set_readiness.readiness().is_empty());
+ ///
+ /// set_readiness.set_readiness(Ready::readable()).unwrap();
+ /// assert!(set_readiness.readiness().is_readable());
+ /// ```
+ ///
+ /// [`Registration`]: struct.Registration.html
+ /// [`Poll`]: struct.Poll.html
+ /// [`poll`]: struct.Poll.html#method.poll
+ pub fn set_readiness(&self, ready: Ready) -> io::Result<()> {
+ self.inner.set_readiness(ready)
+ }
+}
+
+impl fmt::Debug for SetReadiness {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "SetReadiness")
+ }
+}
+
+impl RegistrationInner {
+ /// Get the registration's readiness.
+ fn readiness(&self) -> Ready {
+ self.state.load(Relaxed).readiness()
+ }
+
+ /// Set the registration's readiness.
+ ///
+ /// This function can be called concurrently by an arbitrary number of
+ /// SetReadiness handles.
+ fn set_readiness(&self, ready: Ready) -> io::Result<()> {
+ // Load the current atomic state.
+ let mut state = self.state.load(Acquire);
+ let mut next;
+
+ loop {
+ next = state;
+
+ if state.is_dropped() {
+ // Node is dropped, no more notifications
+ return Ok(());
+ }
+
+ // Update the readiness
+ next.set_readiness(ready);
+
+ // If the readiness is not blank, try to obtain permission to
+ // push the node into the readiness queue.
+ if !next.effective_readiness().is_empty() {
+ next.set_queued();
+ }
+
+ let actual = self.state.compare_and_swap(state, next, AcqRel);
+
+ if state == actual {
+ break;
+ }
+
+ state = actual;
+ }
+
+ if !state.is_queued() && next.is_queued() {
+ // We toggled the queued flag, making us responsible for queuing the
+ // node in the MPSC readiness queue.
+ try!(self.enqueue_with_wakeup());
+ }
+
+ Ok(())
+ }
+
+ /// Update the registration details associated with the node
+ fn update(&self, poll: &Poll, token: Token, interest: Ready, opt: PollOpt) -> io::Result<()> {
+ // First, ensure poll instances match
+ //
+ // Load the queue pointer, `Relaxed` is sufficient here as only the
+ // pointer is being operated on. The actual memory is guaranteed to be
+ // visible the `poll: &Poll` ref passed as an argument to the function.
+ let mut queue = self.readiness_queue.load(Relaxed);
+ let other: &*mut () = unsafe { mem::transmute(&poll.readiness_queue.inner) };
+ let other = *other;
+
+ debug_assert!(mem::size_of::<Arc<ReadinessQueueInner>>() == mem::size_of::<*mut ()>());
+
+ if queue.is_null() {
+ // Attempt to set the queue pointer. `Release` ordering synchronizes
+ // with `Acquire` in `ensure_with_wakeup`.
+ let actual = self.readiness_queue.compare_and_swap(
+ queue, other, Release);
+
+ if actual.is_null() {
+ // The CAS succeeded, this means that the node's ref count
+ // should be incremented to reflect that the `poll` function
+ // effectively owns the node as well.
+ //
+ // `Relaxed` ordering used for the same reason as in
+ // RegistrationInner::clone
+ self.ref_count.fetch_add(1, Relaxed);
+
+ // Note that the `queue` reference stored in our
+ // `readiness_queue` field is intended to be a strong reference,
+ // so now that we've successfully claimed the reference we bump
+ // the refcount here.
+ //
+ // Down below in `release_node` when we deallocate this
+ // `RegistrationInner` is where we'll transmute this back to an
+ // arc and decrement the reference count.
+ mem::forget(poll.readiness_queue.clone());
+ } else {
+ // The CAS failed, another thread set the queue pointer, so ensure
+ // that the pointer and `other` match
+ if actual != other {
+ return Err(io::Error::new(io::ErrorKind::Other, "registration handle associated with another `Poll` instance"));
+ }
+ }
+
+ queue = other;
+ } else if queue != other {
+ return Err(io::Error::new(io::ErrorKind::Other, "registration handle associated with another `Poll` instance"));
+ }
+
+ unsafe {
+ let actual = &poll.readiness_queue.inner as *const _ as *const usize;
+ debug_assert_eq!(queue as usize, *actual);
+ }
+
+ // The `update_lock` atomic is used as a flag ensuring only a single
+ // thread concurrently enters the `update` critical section. Any
+ // concurrent calls to update are discarded. If coordinated updates are
+ // required, the Mio user is responsible for handling that.
+ //
+ // Acquire / Release ordering is used on `update_lock` to ensure that
+ // data access to the `token_*` variables are scoped to the critical
+ // section.
+
+ // Acquire the update lock.
+ if self.update_lock.compare_and_swap(false, true, Acquire) {
+ // The lock is already held. Discard the update
+ return Ok(());
+ }
+
+ // Relaxed ordering is acceptable here as the only memory that needs to
+ // be visible as part of the update are the `token_*` variables, and
+ // ordering has already been handled by the `update_lock` access.
+ let mut state = self.state.load(Relaxed);
+ let mut next;
+
+ // Read the current token, again this memory has been ordered by the
+ // acquire on `update_lock`.
+ let curr_token_pos = state.token_write_pos();
+ let curr_token = unsafe { self::token(self, curr_token_pos) };
+
+ let mut next_token_pos = curr_token_pos;
+
+ // If the `update` call is changing the token, then compute the next
+ // available token slot and write the token there.
+ //
+ // Note that this computation is happening *outside* of the
+ // compare-and-swap loop. The update lock ensures that only a single
+ // thread could be mutating the write_token_position, so the
+ // `next_token_pos` will never need to be recomputed even if
+ // `token_read_pos` concurrently changes. This is because
+ // `token_read_pos` can ONLY concurrently change to the current value of
+ // `token_write_pos`, so `next_token_pos` will always remain valid.
+ if token != curr_token {
+ next_token_pos = state.next_token_pos();
+
+ // Update the token
+ match next_token_pos {
+ 0 => unsafe { *self.token_0.get() = token },
+ 1 => unsafe { *self.token_1.get() = token },
+ 2 => unsafe { *self.token_2.get() = token },
+ _ => unreachable!(),
+ }
+ }
+
+ // Now enter the compare-and-swap loop
+ loop {
+ next = state;
+
+ // The node is only dropped once all `Registration` handles are
+ // dropped. Only `Registration` can call `update`.
+ debug_assert!(!state.is_dropped());
+
+ // Update the write token position, this will also release the token
+ // to Poll::poll.
+ next.set_token_write_pos(next_token_pos);
+
+ // Update readiness and poll opts
+ next.set_interest(interest);
+ next.set_poll_opt(opt);
+
+ // If there is effective readiness, the node will need to be queued
+ // for processing. This exact behavior is still TBD, so we are
+ // conservative for now and always fire.
+ //
+ // See https://github.com/carllerche/mio/issues/535.
+ if !next.effective_readiness().is_empty() {
+ next.set_queued();
+ }
+
+ // compare-and-swap the state values. Only `Release` is needed here.
+ // The `Release` ensures that `Poll::poll` will see the token
+ // update and the update function doesn't care about any other
+ // memory visibility.
+ let actual = self.state.compare_and_swap(state, next, Release);
+
+ if actual == state {
+ break;
+ }
+
+ // CAS failed, but `curr_token_pos` should not have changed given
+ // that we still hold the update lock.
+ debug_assert_eq!(curr_token_pos, actual.token_write_pos());
+
+ state = actual;
+ }
+
+ // Release the lock
+ self.update_lock.store(false, Release);
+
+ if !state.is_queued() && next.is_queued() {
+ // We are responsible for enqueing the node.
+ try!(enqueue_with_wakeup(queue, self));
+ }
+
+ Ok(())
+ }
+}
+
+impl ops::Deref for RegistrationInner {
+ type Target = ReadinessNode;
+
+ fn deref(&self) -> &ReadinessNode {
+ unsafe { &*self.node }
+ }
+}
+
+impl Clone for RegistrationInner {
+ fn clone(&self) -> RegistrationInner {
+ // Using a relaxed ordering is alright here, as knowledge of the
+ // original reference prevents other threads from erroneously deleting
+ // the object.
+ //
+ // As explained in the [Boost documentation][1], Increasing the
+ // reference counter can always be done with memory_order_relaxed: New
+ // references to an object can only be formed from an existing
+ // reference, and passing an existing reference from one thread to
+ // another must already provide any required synchronization.
+ //
+ // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
+ let old_size = self.ref_count.fetch_add(1, Relaxed);
+
+ // However we need to guard against massive refcounts in case someone
+ // is `mem::forget`ing Arcs. If we don't do this the count can overflow
+ // and users will use-after free. We racily saturate to `isize::MAX` on
+ // the assumption that there aren't ~2 billion threads incrementing
+ // the reference count at once. This branch will never be taken in
+ // any realistic program.
+ //
+ // We abort because such a program is incredibly degenerate, and we
+ // don't care to support it.
+ if old_size & !MAX_REFCOUNT != 0 {
+ // TODO: This should really abort the process
+ panic!();
+ }
+
+ RegistrationInner {
+ node: self.node.clone(),
+ }
+ }
+}
+
+impl Drop for RegistrationInner {
+ fn drop(&mut self) {
+ // Only handles releasing from `Registration` and `SetReadiness`
+ // handles. Poll has to call this itself.
+ release_node(self.node);
+ }
+}
+
+/*
+ *
+ * ===== ReadinessQueue =====
+ *
+ */
+
+impl ReadinessQueue {
+ /// Create a new `ReadinessQueue`.
+ fn new() -> io::Result<ReadinessQueue> {
+ is_send::<Self>();
+ is_sync::<Self>();
+
+ let end_marker = Box::new(ReadinessNode::marker());
+ let sleep_marker = Box::new(ReadinessNode::marker());
+ let closed_marker = Box::new(ReadinessNode::marker());
+
+ let ptr = &*end_marker as *const _ as *mut _;
+
+ Ok(ReadinessQueue {
+ inner: Arc::new(ReadinessQueueInner {
+ awakener: try!(sys::Awakener::new()),
+ head_readiness: AtomicPtr::new(ptr),
+ tail_readiness: UnsafeCell::new(ptr),
+ end_marker: end_marker,
+ sleep_marker: sleep_marker,
+ closed_marker: closed_marker,
+ })
+ })
+ }
+
+ /// Poll the queue for new events
+ fn poll(&self, dst: &mut sys::Events) {
+ // `until` is set with the first node that gets re-enqueued due to being
+ // set to have level-triggered notifications. This prevents an infinite
+ // loop where `Poll::poll` will keep dequeuing nodes it enqueues.
+ let mut until = ptr::null_mut();
+
+ 'outer:
+ while dst.len() < dst.capacity() {
+ // Dequeue a node. If the queue is in an inconsistent state, then
+ // stop polling. `Poll::poll` will be called again shortly and enter
+ // a syscall, which should be enough to enable the other thread to
+ // finish the queuing process.
+ let ptr = match unsafe { self.inner.dequeue_node(until) } {
+ Dequeue::Empty | Dequeue::Inconsistent => break,
+ Dequeue::Data(ptr) => ptr,
+ };
+
+ let node = unsafe { &*ptr };
+
+ // Read the node state with Acquire ordering. This allows reading
+ // the token variables.
+ let mut state = node.state.load(Acquire);
+ let mut next;
+ let mut readiness;
+ let mut opt;
+
+ loop {
+ // Build up any changes to the readiness node's state and
+ // attempt the CAS at the end
+ next = state;
+
+ // Given that the node was just read from the queue, the
+ // `queued` flag should still be set.
+ debug_assert!(state.is_queued());
+
+ // The dropped flag means we need to release the node and
+ // perform no further processing on it.
+ if state.is_dropped() {
+ // Release the node and continue
+ release_node(ptr);
+ continue 'outer;
+ }
+
+ // Process the node
+ readiness = state.effective_readiness();
+ opt = state.poll_opt();
+
+ if opt.is_edge() {
+ // Mark the node as dequeued
+ next.set_dequeued();
+
+ if opt.is_oneshot() && !readiness.is_empty() {
+ next.disarm();
+ }
+ } else if readiness.is_empty() {
+ next.set_dequeued();
+ }
+
+ // Ensure `token_read_pos` is set to `token_write_pos` so that
+ // we read the most up to date token value.
+ next.update_token_read_pos();
+
+ if state == next {
+ break;
+ }
+
+ let actual = node.state.compare_and_swap(state, next, AcqRel);
+
+ if actual == state {
+ break;
+ }
+
+ state = actual;
+ }
+
+ // If the queued flag is still set, then the node must be requeued.
+ // This typically happens when using level-triggered notifications.
+ if next.is_queued() {
+ if until.is_null() {
+ // We never want to see the node again
+ until = ptr;
+ }
+
+ // Requeue the node
+ self.inner.enqueue_node(node);
+ }
+
+ if !readiness.is_empty() {
+ // Get the token
+ let token = unsafe { token(node, next.token_read_pos()) };
+
+ // Push the event
+ dst.push_event(Event::new(readiness, token));
+ }
+ }
+ }
+
+ /// Prepare the queue for the `Poll::poll` thread to block in the system
+ /// selector. This involves changing `head_readiness` to `sleep_marker`.
+ /// Returns true if successfull and `poll` can block.
+ fn prepare_for_sleep(&self) -> bool {
+ let end_marker = self.inner.end_marker();
+ let sleep_marker = self.inner.sleep_marker();
+
+ let tail = unsafe { *self.inner.tail_readiness.get() };
+
+ // If the tail is currently set to the sleep_marker, then check if the
+ // head is as well. If it is, then the queue is currently ready to
+ // sleep. If it is not, then the queue is not empty and there should be
+ // no sleeping.
+ if tail == sleep_marker {
+ return self.inner.head_readiness.load(Acquire) == sleep_marker;
+ }
+
+ // If the tail is not currently set to `end_marker`, then the queue is
+ // not empty.
+ if tail != end_marker {
+ return false;
+ }
+
+ self.inner.sleep_marker.next_readiness.store(ptr::null_mut(), Relaxed);
+
+ let actual = self.inner.head_readiness.compare_and_swap(
+ end_marker, sleep_marker, AcqRel);
+
+ debug_assert!(actual != sleep_marker);
+
+ if actual != end_marker {
+ // The readiness queue is not empty
+ return false;
+ }
+
+ // The current tail should be pointing to `end_marker`
+ debug_assert!(unsafe { *self.inner.tail_readiness.get() == end_marker });
+ // The `end_marker` next pointer should be null
+ debug_assert!(self.inner.end_marker.next_readiness.load(Relaxed).is_null());
+
+ // Update tail pointer.
+ unsafe { *self.inner.tail_readiness.get() = sleep_marker; }
+ true
+ }
+}
+
+impl Drop for ReadinessQueue {
+ fn drop(&mut self) {
+ // Close the queue by enqueuing the closed node
+ self.inner.enqueue_node(&*self.inner.closed_marker);
+
+ loop {
+ // Free any nodes that happen to be left in the readiness queue
+ let ptr = match unsafe { self.inner.dequeue_node(ptr::null_mut()) } {
+ Dequeue::Empty => break,
+ Dequeue::Inconsistent => {
+ // This really shouldn't be possible as all other handles to
+ // `ReadinessQueueInner` are dropped, but handle this by
+ // spinning I guess?
+ continue;
+ }
+ Dequeue::Data(ptr) => ptr,
+ };
+
+ let node = unsafe { &*ptr };
+
+ let state = node.state.load(Acquire);
+
+ debug_assert!(state.is_queued());
+
+ release_node(ptr);
+ }
+ }
+}
+
+impl ReadinessQueueInner {
+ fn wakeup(&self) -> io::Result<()> {
+ self.awakener.wakeup()
+ }
+
+ /// Prepend the given node to the head of the readiness queue. This is done
+ /// with relaxed ordering. Returns true if `Poll` needs to be woken up.
+ fn enqueue_node_with_wakeup(&self, node: &ReadinessNode) -> io::Result<()> {
+ if self.enqueue_node(node) {
+ try!(self.wakeup());
+ }
+
+ Ok(())
+ }
+
+ /// Push the node into the readiness queue
+ fn enqueue_node(&self, node: &ReadinessNode) -> bool {
+ // This is the 1024cores.net intrusive MPSC queue [1] "push" function.
+ let node_ptr = node as *const _ as *mut _;
+
+ // Relaxed used as the ordering is "released" when swapping
+ // `head_readiness`
+ node.next_readiness.store(ptr::null_mut(), Relaxed);
+
+ unsafe {
+ let mut prev = self.head_readiness.load(Acquire);
+
+ loop {
+ if prev == self.closed_marker() {
+ debug_assert!(node_ptr != self.closed_marker());
+ // debug_assert!(node_ptr != self.end_marker());
+ debug_assert!(node_ptr != self.sleep_marker());
+
+ if node_ptr != self.end_marker() {
+ // The readiness queue is shutdown, but the enqueue flag was
+ // set. This means that we are responsible for decrementing
+ // the ready queue's ref count
+ debug_assert!(node.ref_count.load(Relaxed) >= 2);
+ release_node(node_ptr);
+ }
+
+ return false;
+ }
+
+ let act = self.head_readiness.compare_and_swap(prev, node_ptr, AcqRel);
+
+ if prev == act {
+ break;
+ }
+
+ prev = act;
+ }
+
+ debug_assert!((*prev).next_readiness.load(Relaxed).is_null());
+
+ (*prev).next_readiness.store(node_ptr, Release);
+
+ prev == self.sleep_marker()
+ }
+ }
+
+ /// Must only be called in `poll` or `drop`
+ unsafe fn dequeue_node(&self, until: *mut ReadinessNode) -> Dequeue {
+ // This is the 1024cores.net intrusive MPSC queue [1] "pop" function
+ // with the modifications mentioned at the top of the file.
+ let mut tail = *self.tail_readiness.get();
+ let mut next = (*tail).next_readiness.load(Acquire);
+
+ if tail == self.end_marker() || tail == self.sleep_marker() || tail == self.closed_marker() {
+ if next.is_null() {
+ return Dequeue::Empty;
+ }
+
+ *self.tail_readiness.get() = next;
+ tail = next;
+ next = (*next).next_readiness.load(Acquire);
+ }
+
+ // Only need to check `until` at this point. `until` is either null,
+ // which will never match tail OR it is a node that was pushed by
+ // the current thread. This means that either:
+ //
+ // 1) The queue is inconsistent, which is handled explicitly
+ // 2) We encounter `until` at this point in dequeue
+ // 3) we will pop a different node
+ if tail == until {
+ return Dequeue::Empty;
+ }
+
+ if !next.is_null() {
+ *self.tail_readiness.get() = next;
+ return Dequeue::Data(tail);
+ }
+
+ if self.head_readiness.load(Acquire) != tail {
+ return Dequeue::Inconsistent;
+ }
+
+ // Push the stub node
+ self.enqueue_node(&*self.end_marker);
+
+ next = (*tail).next_readiness.load(Acquire);
+
+ if !next.is_null() {
+ *self.tail_readiness.get() = next;
+ return Dequeue::Data(tail);
+ }
+
+ Dequeue::Inconsistent
+ }
+
+ fn end_marker(&self) -> *mut ReadinessNode {
+ &*self.end_marker as *const ReadinessNode as *mut ReadinessNode
+ }
+
+ fn sleep_marker(&self) -> *mut ReadinessNode {
+ &*self.sleep_marker as *const ReadinessNode as *mut ReadinessNode
+ }
+
+ fn closed_marker(&self) -> *mut ReadinessNode {
+ &*self.closed_marker as *const ReadinessNode as *mut ReadinessNode
+ }
+}
+
+impl ReadinessNode {
+ /// Return a new `ReadinessNode`, initialized with a ref_count of 3.
+ fn new(queue: *mut (),
+ token: Token,
+ interest: Ready,
+ opt: PollOpt,
+ ref_count: usize) -> ReadinessNode
+ {
+ ReadinessNode {
+ state: AtomicState::new(interest, opt),
+ // Only the first token is set, the others are initialized to 0
+ token_0: UnsafeCell::new(token),
+ token_1: UnsafeCell::new(Token(0)),
+ token_2: UnsafeCell::new(Token(0)),
+ next_readiness: AtomicPtr::new(ptr::null_mut()),
+ update_lock: AtomicBool::new(false),
+ readiness_queue: AtomicPtr::new(queue),
+ ref_count: AtomicUsize::new(ref_count),
+ }
+ }
+
+ fn marker() -> ReadinessNode {
+ ReadinessNode {
+ state: AtomicState::new(Ready::empty(), PollOpt::empty()),
+ token_0: UnsafeCell::new(Token(0)),
+ token_1: UnsafeCell::new(Token(0)),
+ token_2: UnsafeCell::new(Token(0)),
+ next_readiness: AtomicPtr::new(ptr::null_mut()),
+ update_lock: AtomicBool::new(false),
+ readiness_queue: AtomicPtr::new(ptr::null_mut()),
+ ref_count: AtomicUsize::new(0),
+ }
+ }
+
+ fn enqueue_with_wakeup(&self) -> io::Result<()> {
+ let queue = self.readiness_queue.load(Acquire);
+
+ if queue.is_null() {
+ // Not associated with a queue, nothing to do
+ return Ok(());
+ }
+
+ enqueue_with_wakeup(queue, self)
+ }
+}
+
+fn enqueue_with_wakeup(queue: *mut (), node: &ReadinessNode) -> io::Result<()> {
+ debug_assert!(!queue.is_null());
+ // This is ugly... but we don't want to bump the ref count.
+ let queue: &Arc<ReadinessQueueInner> = unsafe { mem::transmute(&queue) };
+ queue.enqueue_node_with_wakeup(node)
+}
+
+unsafe fn token(node: &ReadinessNode, pos: usize) -> Token {
+ match pos {
+ 0 => *node.token_0.get(),
+ 1 => *node.token_1.get(),
+ 2 => *node.token_2.get(),
+ _ => unreachable!(),
+ }
+}
+
+fn release_node(ptr: *mut ReadinessNode) {
+ unsafe {
+ // `AcqRel` synchronizes with other `release_node` functions and ensures
+ // that the drop happens after any reads / writes on other threads.
+ if (*ptr).ref_count.fetch_sub(1, AcqRel) != 1 {
+ return;
+ }
+
+ let node = Box::from_raw(ptr);
+
+ // Decrement the readiness_queue Arc
+ let queue = node.readiness_queue.load(Acquire);
+
+ if queue.is_null() {
+ return;
+ }
+
+ let _: Arc<ReadinessQueueInner> = mem::transmute(queue);
+ }
+}
+
+impl AtomicState {
+ fn new(interest: Ready, opt: PollOpt) -> AtomicState {
+ let state = ReadinessState::new(interest, opt);
+
+ AtomicState {
+ inner: AtomicUsize::new(state.into()),
+ }
+ }
+
+ /// Loads the current `ReadinessState`
+ fn load(&self, order: Ordering) -> ReadinessState {
+ self.inner.load(order).into()
+ }
+
+ /// Stores a state if the current state is the same as `current`.
+ fn compare_and_swap(&self, current: ReadinessState, new: ReadinessState, order: Ordering) -> ReadinessState {
+ self.inner.compare_and_swap(current.into(), new.into(), order).into()
+ }
+
+ // Returns `true` if the node should be queued
+ fn flag_as_dropped(&self) -> bool {
+ let prev: ReadinessState = self.inner.fetch_or(DROPPED_MASK | QUEUED_MASK, Release).into();
+ // The flag should not have been previously set
+ debug_assert!(!prev.is_dropped());
+
+ !prev.is_queued()
+ }
+}
+
+impl ReadinessState {
+ // Create a `ReadinessState` initialized with the provided arguments
+ #[inline]
+ fn new(interest: Ready, opt: PollOpt) -> ReadinessState {
+ let interest = event::ready_as_usize(interest);
+ let opt = event::opt_as_usize(opt);
+
+ debug_assert!(interest <= MASK_4);
+ debug_assert!(opt <= MASK_4);
+
+ let mut val = interest << INTEREST_SHIFT;
+ val |= opt << POLL_OPT_SHIFT;
+
+ ReadinessState(val)
+ }
+
+ #[inline]
+ fn get(&self, mask: usize, shift: usize) -> usize{
+ (self.0 >> shift) & mask
+ }
+
+ #[inline]
+ fn set(&mut self, val: usize, mask: usize, shift: usize) {
+ self.0 = (self.0 & !(mask << shift)) | (val << shift)
+ }
+
+ /// Get the readiness
+ #[inline]
+ fn readiness(&self) -> Ready {
+ let v = self.get(MASK_4, READINESS_SHIFT);
+ event::ready_from_usize(v)
+ }
+
+ #[inline]
+ fn effective_readiness(&self) -> Ready {
+ self.readiness() & self.interest()
+ }
+
+ /// Set the readiness
+ #[inline]
+ fn set_readiness(&mut self, v: Ready) {
+ self.set(event::ready_as_usize(v), MASK_4, READINESS_SHIFT);
+ }
+
+ /// Get the interest
+ #[inline]
+ fn interest(&self) -> Ready {
+ let v = self.get(MASK_4, INTEREST_SHIFT);
+ event::ready_from_usize(v)
+ }
+
+ /// Set the interest
+ #[inline]
+ fn set_interest(&mut self, v: Ready) {
+ self.set(event::ready_as_usize(v), MASK_4, INTEREST_SHIFT);
+ }
+
+ #[inline]
+ fn disarm(&mut self) {
+ self.set_interest(Ready::empty());
+ }
+
+ /// Get the poll options
+ #[inline]
+ fn poll_opt(&self) -> PollOpt {
+ let v = self.get(MASK_4, POLL_OPT_SHIFT);
+ event::opt_from_usize(v)
+ }
+
+ /// Set the poll options
+ #[inline]
+ fn set_poll_opt(&mut self, v: PollOpt) {
+ self.set(event::opt_as_usize(v), MASK_4, POLL_OPT_SHIFT);
+ }
+
+ #[inline]
+ fn is_queued(&self) -> bool {
+ self.0 & QUEUED_MASK == QUEUED_MASK
+ }
+
+ /// Set the queued flag
+ #[inline]
+ fn set_queued(&mut self) {
+ // Dropped nodes should never be queued
+ debug_assert!(!self.is_dropped());
+ self.0 |= QUEUED_MASK;
+ }
+
+ #[inline]
+ fn set_dequeued(&mut self) {
+ debug_assert!(self.is_queued());
+ self.0 &= !QUEUED_MASK
+ }
+
+ #[inline]
+ fn is_dropped(&self) -> bool {
+ self.0 & DROPPED_MASK == DROPPED_MASK
+ }
+
+ #[inline]
+ fn token_read_pos(&self) -> usize {
+ self.get(MASK_2, TOKEN_RD_SHIFT)
+ }
+
+ #[inline]
+ fn token_write_pos(&self) -> usize {
+ self.get(MASK_2, TOKEN_WR_SHIFT)
+ }
+
+ #[inline]
+ fn next_token_pos(&self) -> usize {
+ let rd = self.token_read_pos();
+ let wr = self.token_write_pos();
+
+ match wr {
+ 0 => {
+ match rd {
+ 1 => 2,
+ 2 => 1,
+ 0 => 1,
+ _ => unreachable!(),
+ }
+ }
+ 1 => {
+ match rd {
+ 0 => 2,
+ 2 => 0,
+ 1 => 2,
+ _ => unreachable!(),
+ }
+ }
+ 2 => {
+ match rd {
+ 0 => 1,
+ 1 => 0,
+ 2 => 0,
+ _ => unreachable!(),
+ }
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ #[inline]
+ fn set_token_write_pos(&mut self, val: usize) {
+ self.set(val, MASK_2, TOKEN_WR_SHIFT);
+ }
+
+ #[inline]
+ fn update_token_read_pos(&mut self) {
+ let val = self.token_write_pos();
+ self.set(val, MASK_2, TOKEN_RD_SHIFT);
+ }
+}
+
+impl From<ReadinessState> for usize {
+ fn from(src: ReadinessState) -> usize {
+ src.0
+ }
+}
+
+impl From<usize> for ReadinessState {
+ fn from(src: usize) -> ReadinessState {
+ ReadinessState(src)
+ }
+}
+
+fn is_send<T: Send>() {}
+fn is_sync<T: Sync>() {}
+
+impl SelectorId {
+ pub fn new() -> SelectorId {
+ SelectorId {
+ id: AtomicUsize::new(0),
+ }
+ }
+
+ pub fn associate_selector(&self, poll: &Poll) -> io::Result<()> {
+ let selector_id = self.id.load(Ordering::SeqCst);
+
+ if selector_id != 0 && selector_id != poll.selector.id() {
+ Err(io::Error::new(io::ErrorKind::Other, "socket already registered"))
+ } else {
+ self.id.store(poll.selector.id(), Ordering::SeqCst);
+ Ok(())
+ }
+ }
+}
+
+impl Clone for SelectorId {
+ fn clone(&self) -> SelectorId {
+ SelectorId {
+ id: AtomicUsize::new(self.id.load(Ordering::SeqCst)),
+ }
+ }
+}
+
+#[test]
+#[cfg(unix)]
+pub fn as_raw_fd() {
+ let poll = Poll::new().unwrap();
+ assert!(poll.as_raw_fd() > 0);
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/mod.rs
@@ -0,0 +1,35 @@
+#[cfg(unix)]
+pub use self::unix::{
+ Awakener,
+ EventedFd,
+ Events,
+ Io,
+ Selector,
+ TcpStream,
+ TcpListener,
+ UdpSocket,
+ pipe,
+ set_nonblock,
+};
+
+#[cfg(unix)]
+#[cfg(feature = "with-deprecated")]
+pub use self::unix::UnixSocket;
+
+#[cfg(unix)]
+pub mod unix;
+
+#[cfg(windows)]
+pub use self::windows::{
+ Awakener,
+ Events,
+ Selector,
+ TcpStream,
+ TcpListener,
+ UdpSocket,
+ Overlapped,
+ Binding,
+};
+
+#[cfg(windows)]
+mod windows;
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/awakener.rs
@@ -0,0 +1,74 @@
+pub use self::pipe::Awakener;
+
+/// Default awakener backed by a pipe
+mod pipe {
+ use sys::unix;
+ use {io, Ready, Poll, PollOpt, Token};
+ use event::Evented;
+ use std::io::{Read, Write};
+
+ /*
+ *
+ * ===== Awakener =====
+ *
+ */
+
+ pub struct Awakener {
+ reader: unix::Io,
+ writer: unix::Io,
+ }
+
+ impl Awakener {
+ pub fn new() -> io::Result<Awakener> {
+ let (rd, wr) = try!(unix::pipe());
+
+ Ok(Awakener {
+ reader: rd,
+ writer: wr,
+ })
+ }
+
+ pub fn wakeup(&self) -> io::Result<()> {
+ match (&self.writer).write(&[1]) {
+ Ok(_) => Ok(()),
+ Err(e) => {
+ if e.kind() == io::ErrorKind::WouldBlock {
+ Ok(())
+ } else {
+ Err(e)
+ }
+ }
+ }
+ }
+
+ pub fn cleanup(&self) {
+ let mut buf = [0; 128];
+
+ loop {
+ // Consume data until all bytes are purged
+ match (&self.reader).read(&mut buf) {
+ Ok(i) if i > 0 => {},
+ _ => return,
+ }
+ }
+ }
+
+ fn reader(&self) -> &unix::Io {
+ &self.reader
+ }
+ }
+
+ impl Evented for Awakener {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.reader().register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.reader().reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.reader().deregister(poll)
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/dlsym.rs
@@ -0,0 +1,47 @@
+use std::marker;
+use std::mem;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+use libc;
+
+macro_rules! dlsym {
+ (fn $name:ident($($t:ty),*) -> $ret:ty) => (
+ #[allow(bad_style)]
+ static $name: ::sys::unix::dlsym::DlSym<unsafe extern fn($($t),*) -> $ret> =
+ ::sys::unix::dlsym::DlSym {
+ name: concat!(stringify!($name), "\0"),
+ addr: ::std::sync::atomic::ATOMIC_USIZE_INIT,
+ _marker: ::std::marker::PhantomData,
+ };
+ )
+}
+
+pub struct DlSym<F> {
+ pub name: &'static str,
+ pub addr: AtomicUsize,
+ pub _marker: marker::PhantomData<F>,
+}
+
+impl<F> DlSym<F> {
+ pub fn get(&self) -> Option<&F> {
+ assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+ unsafe {
+ if self.addr.load(Ordering::SeqCst) == 0 {
+ self.addr.store(fetch(self.name), Ordering::SeqCst);
+ }
+ if self.addr.load(Ordering::SeqCst) == 1 {
+ None
+ } else {
+ mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
+ }
+ }
+ }
+}
+
+unsafe fn fetch(name: &str) -> usize {
+ assert_eq!(name.as_bytes()[name.len() - 1], 0);
+ match libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize {
+ 0 => 1,
+ n => n,
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/epoll.rs
@@ -0,0 +1,277 @@
+#![allow(deprecated)]
+use std::os::unix::io::AsRawFd;
+use std::os::unix::io::RawFd;
+use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+use std::time::Duration;
+use std::{cmp, i32};
+
+use libc::c_int;
+use libc;
+use libc::{EPOLLERR, EPOLLHUP};
+use libc::{EPOLLET, EPOLLOUT, EPOLLIN, EPOLLPRI};
+
+#[cfg(not(target_os = "android"))]
+use libc::{EPOLLRDHUP, EPOLLONESHOT};
+
+// libc doesn't define these constants on android, but they are supported.
+#[cfg(target_os = "android")]
+const EPOLLRDHUP: libc::c_int = 0x00002000;
+#[cfg(target_os = "android")]
+const EPOLLONESHOT: libc::c_int = 0x40000000;
+
+use {io, Ready, PollOpt, Token};
+use event_imp::Event;
+use sys::unix::{cvt, UnixReady};
+use sys::unix::io::set_cloexec;
+
+/// Each Selector has a globally unique(ish) ID associated with it. This ID
+/// gets tracked by `TcpStream`, `TcpListener`, etc... when they are first
+/// registered with the `Selector`. If a type that is previously associated with
+/// a `Selector` attempts to register itself with a different `Selector`, the
+/// operation will return with an error. This matches windows behavior.
+static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+
+#[derive(Debug)]
+pub struct Selector {
+ id: usize,
+ epfd: RawFd,
+}
+
+impl Selector {
+ pub fn new() -> io::Result<Selector> {
+ let epfd = unsafe {
+ // Emulate `epoll_create` by using `epoll_create1` if it's available
+ // and otherwise falling back to `epoll_create` followed by a call to
+ // set the CLOEXEC flag.
+ dlsym!(fn epoll_create1(c_int) -> c_int);
+
+ match epoll_create1.get() {
+ Some(epoll_create1_fn) => {
+ try!(cvt(epoll_create1_fn(libc::EPOLL_CLOEXEC)))
+ }
+ None => {
+ let fd = try!(cvt(libc::epoll_create(1024)));
+ drop(set_cloexec(fd));
+ fd
+ }
+ }
+ };
+
+ // offset by 1 to avoid choosing 0 as the id of a selector
+ let id = NEXT_ID.fetch_add(1, Ordering::Relaxed) + 1;
+
+ Ok(Selector {
+ id: id,
+ epfd: epfd,
+ })
+ }
+
+ pub fn id(&self) -> usize {
+ self.id
+ }
+
+ /// Wait for events from the OS
+ pub fn select(&self, evts: &mut Events, awakener: Token, timeout: Option<Duration>) -> io::Result<bool> {
+ let timeout_ms = timeout
+ .map(|to| cmp::min(millis(to), i32::MAX as u64) as i32)
+ .unwrap_or(-1);
+
+ // Wait for epoll events for at most timeout_ms milliseconds
+ unsafe {
+ evts.events.set_len(0);
+ let cnt = try!(cvt(libc::epoll_wait(self.epfd,
+ evts.events.as_mut_ptr(),
+ evts.events.capacity() as i32,
+ timeout_ms)));
+ let cnt = cnt as usize;
+ evts.events.set_len(cnt);
+
+ for i in 0..cnt {
+ if evts.events[i].u64 as usize == awakener.into() {
+ evts.events.remove(i);
+ return Ok(true);
+ }
+ }
+ }
+
+ Ok(false)
+ }
+
+ /// Register event interests for the given IO handle with the OS
+ pub fn register(&self, fd: RawFd, token: Token, interests: Ready, opts: PollOpt) -> io::Result<()> {
+ let mut info = libc::epoll_event {
+ events: ioevent_to_epoll(interests, opts),
+ u64: usize::from(token) as u64
+ };
+
+ unsafe {
+ try!(cvt(libc::epoll_ctl(self.epfd, libc::EPOLL_CTL_ADD, fd, &mut info)));
+ Ok(())
+ }
+ }
+
+ /// Register event interests for the given IO handle with the OS
+ pub fn reregister(&self, fd: RawFd, token: Token, interests: Ready, opts: PollOpt) -> io::Result<()> {
+ let mut info = libc::epoll_event {
+ events: ioevent_to_epoll(interests, opts),
+ u64: usize::from(token) as u64
+ };
+
+ unsafe {
+ try!(cvt(libc::epoll_ctl(self.epfd, libc::EPOLL_CTL_MOD, fd, &mut info)));
+ Ok(())
+ }
+ }
+
+ /// Deregister event interests for the given IO handle with the OS
+ pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
+ // The &info argument should be ignored by the system,
+ // but linux < 2.6.9 required it to be not null.
+ // For compatibility, we provide a dummy EpollEvent.
+ let mut info = libc::epoll_event {
+ events: 0,
+ u64: 0,
+ };
+
+ unsafe {
+ try!(cvt(libc::epoll_ctl(self.epfd, libc::EPOLL_CTL_DEL, fd, &mut info)));
+ Ok(())
+ }
+ }
+}
+
+#[cfg(feature = "with-deprecated")]
+#[allow(deprecated)]
+fn is_urgent(opts: PollOpt) -> bool {
+ opts.is_urgent()
+}
+
+#[cfg(not(feature = "with-deprecated"))]
+fn is_urgent(_: PollOpt) -> bool {
+ false
+}
+
+fn ioevent_to_epoll(interest: Ready, opts: PollOpt) -> u32 {
+ let mut kind = 0;
+
+ if interest.is_readable() {
+ if is_urgent(opts) {
+ kind |= EPOLLPRI;
+ } else {
+ kind |= EPOLLIN;
+ }
+ }
+
+ if interest.is_writable() {
+ kind |= EPOLLOUT;
+ }
+
+ if UnixReady::from(interest).is_hup() {
+ kind |= EPOLLRDHUP;
+ }
+
+ if opts.is_edge() {
+ kind |= EPOLLET;
+ }
+
+ if opts.is_oneshot() {
+ kind |= EPOLLONESHOT;
+ }
+
+ if opts.is_level() {
+ kind &= !EPOLLET;
+ }
+
+ kind as u32
+}
+
+impl AsRawFd for Selector {
+ fn as_raw_fd(&self) -> RawFd {
+ self.epfd
+ }
+}
+
+impl Drop for Selector {
+ fn drop(&mut self) {
+ unsafe {
+ let _ = libc::close(self.epfd);
+ }
+ }
+}
+
+pub struct Events {
+ events: Vec<libc::epoll_event>,
+}
+
+impl Events {
+ pub fn with_capacity(u: usize) -> Events {
+ Events {
+ events: Vec::with_capacity(u)
+ }
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.events.len()
+ }
+
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.events.capacity()
+ }
+
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.events.is_empty()
+ }
+
+ #[inline]
+ pub fn get(&self, idx: usize) -> Option<Event> {
+ self.events.get(idx).map(|event| {
+ let epoll = event.events as c_int;
+ let mut kind = Ready::empty();
+
+ if (epoll & EPOLLIN) != 0 || (epoll & EPOLLPRI) != 0 {
+ kind = kind | Ready::readable();
+ }
+
+ if (epoll & EPOLLOUT) != 0 {
+ kind = kind | Ready::writable();
+ }
+
+ // EPOLLHUP - Usually means a socket error happened
+ if (epoll & EPOLLERR) != 0 {
+ kind = kind | UnixReady::error();
+ }
+
+ if (epoll & EPOLLRDHUP) != 0 || (epoll & EPOLLHUP) != 0 {
+ kind = kind | UnixReady::hup();
+ }
+
+ let token = self.events[idx].u64;
+
+ Event::new(kind, Token(token as usize))
+ })
+ }
+
+ pub fn push_event(&mut self, event: Event) {
+ self.events.push(libc::epoll_event {
+ events: ioevent_to_epoll(event.readiness(), PollOpt::empty()),
+ u64: usize::from(event.token()) as u64
+ });
+ }
+}
+
+const NANOS_PER_MILLI: u32 = 1_000_000;
+const MILLIS_PER_SEC: u64 = 1_000;
+
+/// Convert a `Duration` to milliseconds, rounding up and saturating at
+/// `u64::MAX`.
+///
+/// The saturating is fine because `u64::MAX` milliseconds are still many
+/// million years.
+pub fn millis(duration: Duration) -> u64 {
+ // Round up.
+ let millis = (duration.subsec_nanos() + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
+ duration.as_secs().saturating_mul(MILLIS_PER_SEC).saturating_add(millis as u64)
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/eventedfd.rs
@@ -0,0 +1,98 @@
+use {io, poll, Ready, Poll, PollOpt, Token};
+use event::Evented;
+use std::os::unix::io::RawFd;
+
+/*
+ *
+ * ===== EventedFd =====
+ *
+ */
+
+#[derive(Debug)]
+
+/// Adapter for [`RawFd`] providing an [`Evented`] implementation.
+///
+/// `EventedFd` enables registering any type with an FD with [`Poll`].
+///
+/// While only implementations for TCP and UDP are provided, Mio supports
+/// registering any FD that can be registered with the underlying OS selector.
+/// `EventedFd` provides the necessary bridge.
+///
+/// Note that `EventedFd` takes a `&RawFd`. This is because `EventedFd` **does
+/// not** take ownership of the FD. Specifically, it will not manage any
+/// lifecycle related operations, such as closing the FD on drop. It is expected
+/// that the `EventedFd` is constructed right before a call to
+/// [`Poll::register`]. See the examples for more detail.
+///
+/// # Examples
+///
+/// Basic usage
+///
+/// ```
+/// use mio::{Ready, Poll, PollOpt, Token};
+/// use mio::unix::EventedFd;
+///
+/// use std::os::unix::io::AsRawFd;
+/// use std::net::TcpListener;
+///
+/// // Bind a std listener
+/// let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+///
+/// let poll = Poll::new().unwrap();
+///
+/// // Register the listener
+/// poll.register(&EventedFd(&listener.as_raw_fd()),
+/// Token(0), Ready::readable(), PollOpt::edge()).unwrap();
+/// ```
+///
+/// Implementing `Evented` for a custom type backed by a `RawFd`.
+///
+/// ```
+/// use mio::{Ready, Poll, PollOpt, Token};
+/// use mio::event::Evented;
+/// use mio::unix::EventedFd;
+///
+/// use std::os::unix::io::RawFd;
+/// use std::io;
+///
+/// pub struct MyIo {
+/// fd: RawFd,
+/// }
+///
+/// impl Evented for MyIo {
+/// fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
+/// -> io::Result<()>
+/// {
+/// EventedFd(&self.fd).register(poll, token, interest, opts)
+/// }
+///
+/// fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
+/// -> io::Result<()>
+/// {
+/// EventedFd(&self.fd).reregister(poll, token, interest, opts)
+/// }
+///
+/// fn deregister(&self, poll: &Poll) -> io::Result<()> {
+/// EventedFd(&self.fd).deregister(poll)
+/// }
+/// }
+/// ```
+///
+/// [`RawFd`]: #
+/// [`Evented`]: #
+/// [`Poll`]: #
+pub struct EventedFd<'a>(pub &'a RawFd);
+
+impl<'a> Evented for EventedFd<'a> {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ poll::selector(poll).register(*self.0, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ poll::selector(poll).reregister(*self.0, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ poll::selector(poll).deregister(*self.0)
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/io.rs
@@ -0,0 +1,107 @@
+use std::fs::File;
+use std::io::{Read, Write};
+use std::os::unix::io::{IntoRawFd, AsRawFd, FromRawFd, RawFd};
+
+use libc;
+
+use {io, Ready, Poll, PollOpt, Token};
+use event::Evented;
+use unix::EventedFd;
+use sys::unix::cvt;
+
+pub fn set_nonblock(fd: libc::c_int) -> io::Result<()> {
+ unsafe {
+ let flags = libc::fcntl(fd, libc::F_GETFL);
+ cvt(libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK)).map(|_|())
+ }
+}
+
+pub fn set_cloexec(fd: libc::c_int) -> io::Result<()> {
+ unsafe {
+ let flags = libc::fcntl(fd, libc::F_GETFD);
+ cvt(libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC)).map(|_| ())
+ }
+}
+
+/*
+ *
+ * ===== Basic IO type =====
+ *
+ */
+
+/// Manages a FD
+#[derive(Debug)]
+pub struct Io {
+ fd: File,
+}
+
+impl Io {
+ /// Try to clone the FD
+ pub fn try_clone(&self) -> io::Result<Io> {
+ Ok(Io { fd: try!(self.fd.try_clone()) })
+ }
+}
+
+impl FromRawFd for Io {
+ unsafe fn from_raw_fd(fd: RawFd) -> Io {
+ Io { fd: File::from_raw_fd(fd) }
+ }
+}
+
+impl IntoRawFd for Io {
+ fn into_raw_fd(self) -> RawFd {
+ self.fd.into_raw_fd()
+ }
+}
+
+impl AsRawFd for Io {
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd.as_raw_fd()
+ }
+}
+
+impl Evented for Io {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).deregister(poll)
+ }
+}
+
+impl Read for Io {
+ fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
+ (&self.fd).read(dst)
+ }
+}
+
+impl<'a> Read for &'a Io {
+ fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
+ (&self.fd).read(dst)
+ }
+}
+
+impl Write for Io {
+ fn write(&mut self, src: &[u8]) -> io::Result<usize> {
+ (&self.fd).write(src)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ (&self.fd).flush()
+ }
+}
+
+impl<'a> Write for &'a Io {
+ fn write(&mut self, src: &[u8]) -> io::Result<usize> {
+ (&self.fd).write(src)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ (&self.fd).flush()
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/kqueue.rs
@@ -0,0 +1,326 @@
+use std::{cmp, fmt, ptr};
+use std::os::raw::c_int;
+use std::os::unix::io::AsRawFd;
+use std::os::unix::io::RawFd;
+use std::collections::HashMap;
+use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+use std::time::Duration;
+
+use libc::{self, time_t};
+
+use {io, Ready, PollOpt, Token};
+use event_imp::{self as event, Event};
+use sys::unix::{cvt, UnixReady};
+use sys::unix::io::set_cloexec;
+
+/// Each Selector has a globally unique(ish) ID associated with it. This ID
+/// gets tracked by `TcpStream`, `TcpListener`, etc... when they are first
+/// registered with the `Selector`. If a type that is previously associated with
+/// a `Selector` attempts to register itself with a different `Selector`, the
+/// operation will return with an error. This matches windows behavior.
+static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+
+macro_rules! kevent {
+ ($id: expr, $filter: expr, $flags: expr, $data: expr) => {
+ libc::kevent {
+ ident: $id as ::libc::uintptr_t,
+ filter: $filter,
+ flags: $flags,
+ fflags: 0,
+ data: 0,
+ udata: $data as *mut _,
+ }
+ }
+}
+
+pub struct Selector {
+ id: usize,
+ kq: RawFd,
+}
+
+impl Selector {
+ pub fn new() -> io::Result<Selector> {
+ // offset by 1 to avoid choosing 0 as the id of a selector
+ let id = NEXT_ID.fetch_add(1, Ordering::Relaxed) + 1;
+ let kq = unsafe { try!(cvt(libc::kqueue())) };
+ drop(set_cloexec(kq));
+
+ Ok(Selector {
+ id: id,
+ kq: kq,
+ })
+ }
+
+ pub fn id(&self) -> usize {
+ self.id
+ }
+
+ pub fn select(&self, evts: &mut Events, awakener: Token, timeout: Option<Duration>) -> io::Result<bool> {
+ let timeout = timeout.map(|to| {
+ libc::timespec {
+ tv_sec: cmp::min(to.as_secs(), time_t::max_value() as u64) as time_t,
+ tv_nsec: to.subsec_nanos() as libc::c_long,
+ }
+ });
+ let timeout = timeout.as_ref().map(|s| s as *const _).unwrap_or(ptr::null_mut());
+
+ unsafe {
+ let cnt = try!(cvt(libc::kevent(self.kq,
+ ptr::null(),
+ 0,
+ evts.sys_events.0.as_mut_ptr(),
+ // FIXME: needs a saturating cast here.
+ evts.sys_events.0.capacity() as c_int,
+ timeout)));
+ evts.sys_events.0.set_len(cnt as usize);
+ Ok(evts.coalesce(awakener))
+ }
+ }
+
+ pub fn register(&self, fd: RawFd, token: Token, interests: Ready, opts: PollOpt) -> io::Result<()> {
+ trace!("registering; token={:?}; interests={:?}", token, interests);
+
+ let flags = if opts.contains(PollOpt::edge()) { libc::EV_CLEAR } else { 0 } |
+ if opts.contains(PollOpt::oneshot()) { libc::EV_ONESHOT } else { 0 } |
+ libc::EV_RECEIPT;
+
+ unsafe {
+ let r = if interests.contains(Ready::readable()) { libc::EV_ADD } else { libc::EV_DELETE };
+ let w = if interests.contains(Ready::writable()) { libc::EV_ADD } else { libc::EV_DELETE };
+ let mut changes = [
+ kevent!(fd, libc::EVFILT_READ, flags | r, usize::from(token)),
+ kevent!(fd, libc::EVFILT_WRITE, flags | w, usize::from(token)),
+ ];
+ try!(cvt(libc::kevent(self.kq, changes.as_ptr(), changes.len() as c_int,
+ changes.as_mut_ptr(), changes.len() as c_int,
+ ::std::ptr::null())));
+ for change in changes.iter() {
+ debug_assert_eq!(change.flags & libc::EV_ERROR, libc::EV_ERROR);
+
+ // Test to see if an error happened
+ if change.data == 0 {
+ continue
+ }
+
+ // Older versions of OSX (10.11 and 10.10 have been witnessed)
+ // can return EPIPE when registering a pipe file descriptor
+ // where the other end has already disappeared. For example code
+ // that creates a pipe, closes a file descriptor, and then
+ // registers the other end will see an EPIPE returned from
+ // `register`.
+ //
+ // It also turns out that kevent will still report events on the
+ // file descriptor, telling us that it's readable/hup at least
+ // after we've done this registration. As a result we just
+ // ignore `EPIPE` here instead of propagating it.
+ //
+ // More info can be found at carllerche/mio#582
+ if change.data as i32 == libc::EPIPE &&
+ change.filter == libc::EVFILT_WRITE {
+ continue
+ }
+
+ // ignore ENOENT error for EV_DELETE
+ let orig_flags = if change.filter == libc::EVFILT_READ { r } else { w };
+ if change.data as i32 == libc::ENOENT && orig_flags & libc::EV_DELETE != 0 {
+ continue
+ }
+
+ return Err(::std::io::Error::from_raw_os_error(change.data as i32));
+ }
+ Ok(())
+ }
+ }
+
+ pub fn reregister(&self, fd: RawFd, token: Token, interests: Ready, opts: PollOpt) -> io::Result<()> {
+ // Just need to call register here since EV_ADD is a mod if already
+ // registered
+ self.register(fd, token, interests, opts)
+ }
+
+ pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
+ unsafe {
+ // EV_RECEIPT is a nice way to apply changes and get back per-event results while not
+ // draining the actual changes.
+ let filter = libc::EV_DELETE | libc::EV_RECEIPT;
+ let mut changes = [
+ kevent!(fd, libc::EVFILT_READ, filter, ptr::null_mut()),
+ kevent!(fd, libc::EVFILT_WRITE, filter, ptr::null_mut()),
+ ];
+ try!(cvt(libc::kevent(self.kq, changes.as_ptr(), changes.len() as c_int,
+ changes.as_mut_ptr(), changes.len() as c_int,
+ ::std::ptr::null())).map(|_| ()));
+ if changes[0].data as i32 == libc::ENOENT && changes[1].data as i32 == libc::ENOENT {
+ return Err(::std::io::Error::from_raw_os_error(changes[0].data as i32));
+ }
+ for change in changes.iter() {
+ debug_assert_eq!(libc::EV_ERROR & change.flags, libc::EV_ERROR);
+ if change.data != 0 && change.data as i32 != libc::ENOENT {
+ return Err(::std::io::Error::from_raw_os_error(changes[0].data as i32));
+ }
+ }
+ Ok(())
+ }
+ }
+}
+
+impl fmt::Debug for Selector {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("Selector")
+ .field("id", &self.id)
+ .field("kq", &self.kq)
+ .finish()
+ }
+}
+
+impl AsRawFd for Selector {
+ fn as_raw_fd(&self) -> RawFd {
+ self.kq
+ }
+}
+
+impl Drop for Selector {
+ fn drop(&mut self) {
+ unsafe {
+ let _ = libc::close(self.kq);
+ }
+ }
+}
+
+pub struct Events {
+ sys_events: KeventList,
+ events: Vec<Event>,
+ event_map: HashMap<Token, usize>,
+}
+
+struct KeventList(Vec<libc::kevent>);
+
+unsafe impl Send for KeventList {}
+unsafe impl Sync for KeventList {}
+
+impl Events {
+ pub fn with_capacity(cap: usize) -> Events {
+ Events {
+ sys_events: KeventList(Vec::with_capacity(cap)),
+ events: Vec::with_capacity(cap),
+ event_map: HashMap::with_capacity(cap)
+ }
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.events.len()
+ }
+
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.events.capacity()
+ }
+
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.events.is_empty()
+ }
+
+ pub fn get(&self, idx: usize) -> Option<Event> {
+ self.events.get(idx).map(|e| *e)
+ }
+
+ fn coalesce(&mut self, awakener: Token) -> bool {
+ let mut ret = false;
+ self.events.clear();
+ self.event_map.clear();
+
+ for e in self.sys_events.0.iter() {
+ let token = Token(e.udata as usize);
+ let len = self.events.len();
+
+ if token == awakener {
+ // TODO: Should this return an error if event is an error. It
+ // is not critical as spurious wakeups are permitted.
+ ret = true;
+ continue;
+ }
+
+ let idx = *self.event_map.entry(token)
+ .or_insert(len);
+
+ if idx == len {
+ // New entry, insert the default
+ self.events.push(Event::new(Ready::empty(), token));
+
+ }
+
+ if e.flags & libc::EV_ERROR != 0 {
+ event::kind_mut(&mut self.events[idx]).insert(*UnixReady::error());
+ }
+
+ if e.filter == libc::EVFILT_READ {
+ event::kind_mut(&mut self.events[idx]).insert(Ready::readable());
+ } else if e.filter == libc::EVFILT_WRITE {
+ event::kind_mut(&mut self.events[idx]).insert(Ready::writable());
+ }
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd", target_os = "ios", target_os = "macos"))]
+ {
+ if e.filter == libc::EVFILT_AIO {
+ event::kind_mut(&mut self.events[idx]).insert(UnixReady::aio());
+ }
+ }
+
+ if e.flags & libc::EV_EOF != 0 {
+ event::kind_mut(&mut self.events[idx]).insert(UnixReady::hup());
+
+ // When the read end of the socket is closed, EV_EOF is set on
+ // flags, and fflags contains the error if there is one.
+ if e.fflags != 0 {
+ event::kind_mut(&mut self.events[idx]).insert(UnixReady::error());
+ }
+ }
+ }
+
+ ret
+ }
+
+ pub fn push_event(&mut self, event: Event) {
+ self.events.push(event);
+ }
+}
+
+impl fmt::Debug for Events {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "Events {{ len: {} }}", self.sys_events.0.len())
+ }
+}
+
+#[test]
+fn does_not_register_rw() {
+ #![allow(deprecated)]
+
+ use ::deprecated::{EventLoopBuilder, Handler};
+ use ::unix::EventedFd;
+ struct Nop;
+ impl Handler for Nop {
+ type Timeout = ();
+ type Message = ();
+ }
+
+ // registering kqueue fd will fail if write is requested (On anything but some versions of OS
+ // X)
+ let kq = unsafe { libc::kqueue() };
+ let kqf = EventedFd(&kq);
+ let mut evtloop = EventLoopBuilder::new().build::<Nop>().expect("evt loop builds");
+ evtloop.register(&kqf, Token(1234), Ready::readable(),
+ PollOpt::edge() | PollOpt::oneshot()).unwrap();
+}
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd", target_os = "ios", target_os = "macos"))]
+#[test]
+fn test_coalesce_aio() {
+ let mut events = Events::with_capacity(1);
+ events.sys_events.0.push(kevent!(0x1234, libc::EVFILT_AIO, 0, 42));
+ events.coalesce(Token(0));
+ assert!(events.events[0].readiness() == UnixReady::aio().into());
+ assert!(events.events[0].token() == Token(42));
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/mod.rs
@@ -0,0 +1,90 @@
+use libc::{self, c_int};
+
+#[macro_use]
+pub mod dlsym;
+
+#[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
+mod epoll;
+
+#[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
+pub use self::epoll::{Events, Selector};
+
+#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
+ target_os = "freebsd", target_os = "ios", target_os = "macos",
+ target_os = "netbsd", target_os = "openbsd"))]
+mod kqueue;
+
+#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
+ target_os = "freebsd", target_os = "ios", target_os = "macos",
+ target_os = "netbsd", target_os = "openbsd"))]
+pub use self::kqueue::{Events, Selector};
+
+mod awakener;
+mod eventedfd;
+mod io;
+mod ready;
+mod tcp;
+mod udp;
+
+#[cfg(feature = "with-deprecated")]
+mod uds;
+
+pub use self::awakener::Awakener;
+pub use self::eventedfd::EventedFd;
+pub use self::io::{Io, set_nonblock};
+pub use self::ready::UnixReady;
+pub use self::tcp::{TcpStream, TcpListener};
+pub use self::udp::UdpSocket;
+
+#[cfg(feature = "with-deprecated")]
+pub use self::uds::UnixSocket;
+
+pub use iovec::IoVec;
+
+use std::os::unix::io::FromRawFd;
+
+pub fn pipe() -> ::io::Result<(Io, Io)> {
+ // Use pipe2 for atomically setting O_CLOEXEC if we can, but otherwise
+ // just fall back to using `pipe`.
+ dlsym!(fn pipe2(*mut c_int, c_int) -> c_int);
+
+ let mut pipes = [0; 2];
+ let flags = libc::O_NONBLOCK | libc::O_CLOEXEC;
+ unsafe {
+ match pipe2.get() {
+ Some(pipe2_fn) => {
+ try!(cvt(pipe2_fn(pipes.as_mut_ptr(), flags)));
+ }
+ None => {
+ try!(cvt(libc::pipe(pipes.as_mut_ptr())));
+ libc::fcntl(pipes[0], libc::F_SETFL, flags);
+ libc::fcntl(pipes[1], libc::F_SETFL, flags);
+ }
+ }
+ }
+
+ unsafe {
+ Ok((Io::from_raw_fd(pipes[0]), Io::from_raw_fd(pipes[1])))
+ }
+}
+
+trait IsMinusOne {
+ fn is_minus_one(&self) -> bool;
+}
+
+impl IsMinusOne for i32 {
+ fn is_minus_one(&self) -> bool { *self == -1 }
+}
+impl IsMinusOne for isize {
+ fn is_minus_one(&self) -> bool { *self == -1 }
+}
+
+fn cvt<T: IsMinusOne>(t: T) -> ::io::Result<T> {
+ use std::io;
+
+ if t.is_minus_one() {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(t)
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/ready.rs
@@ -0,0 +1,308 @@
+use event_imp::{Ready, ready_from_usize};
+
+use std::ops;
+
+/// Unix specific extensions to `Ready`
+///
+/// Provides additional readiness event kinds that are available on unix
+/// platforms. Unix platforms are able to provide readiness events for
+/// additional socket events, such as HUP and error.
+///
+/// HUP events occur when the remote end of a socket hangs up. In the TCP case,
+/// this occurs when the remote end of a TCP socket shuts down writes.
+///
+/// Error events occur when the socket enters an error state. In this case, the
+/// socket will also receive a readable or writable event. Reading or writing to
+/// the socket will result in an error.
+///
+/// Conversion traits are implemented between `Ready` and `UnixReady`. See the
+/// examples.
+///
+/// For high level documentation on polling and readiness, see [`Poll`].
+///
+/// # Examples
+///
+/// Most of the time, all that is needed is using bit operations
+///
+/// ```
+/// use mio::Ready;
+/// use mio::unix::UnixReady;
+///
+/// let ready = Ready::readable() | UnixReady::hup();
+///
+/// assert!(ready.is_readable());
+/// assert!(UnixReady::from(ready).is_hup());
+/// ```
+///
+/// Basic conversion between ready types.
+///
+/// ```
+/// use mio::Ready;
+/// use mio::unix::UnixReady;
+///
+/// // Start with a portable ready
+/// let ready = Ready::readable();
+///
+/// // Convert to a unix ready, adding HUP
+/// let mut unix_ready = UnixReady::from(ready) | UnixReady::hup();
+///
+/// unix_ready.insert(UnixReady::error());
+///
+/// // `unix_ready` maintains readable interest
+/// assert!(unix_ready.is_readable());
+/// assert!(unix_ready.is_hup());
+/// assert!(unix_ready.is_error());
+///
+/// // Convert back to `Ready`
+/// let ready = Ready::from(unix_ready);
+///
+/// // Readable is maintained
+/// assert!(ready.is_readable());
+/// ```
+///
+/// Registering readable and error interest on a socket
+///
+/// ```
+/// use mio::{Ready, Poll, PollOpt, Token};
+/// use mio::tcp::TcpStream;
+/// use mio::unix::UnixReady;
+///
+/// let addr = "216.58.193.68:80".parse().unwrap();
+/// let socket = TcpStream::connect(&addr).unwrap();
+///
+/// let poll = Poll::new().unwrap();
+///
+/// poll.register(&socket,
+/// Token(0),
+/// Ready::readable() | UnixReady::error(),
+/// PollOpt::edge()).unwrap();
+///
+/// ```
+///
+/// [`Poll`]: struct.Poll.html
+/// [readiness]: struct.Poll.html#readiness-operations
+#[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord)]
+pub struct UnixReady(Ready);
+
+const ERROR: usize = 0b00100;
+const HUP: usize = 0b01000;
+const AIO: usize = 0b10000;
+
+impl UnixReady {
+ /// Returns a `Ready` representing AIO completion readiness
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::unix::UnixReady;
+ ///
+ /// let ready = UnixReady::aio();
+ ///
+ /// assert!(ready.is_aio());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn aio() -> UnixReady {
+ UnixReady(ready_from_usize(AIO))
+ }
+
+ /// Returns a `Ready` representing error readiness.
+ ///
+ /// **Note that only readable and writable readiness is guaranteed to be
+ /// supported on all platforms**. This means that `error` readiness
+ /// should be treated as a hint. For more details, see [readiness] in the
+ /// poll documentation.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::error();
+ ///
+ /// assert!(ready.is_error());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ /// [readiness]: struct.Poll.html#readiness-operations
+ #[inline]
+ pub fn error() -> UnixReady {
+ UnixReady(ready_from_usize(ERROR))
+ }
+
+ /// Returns a `Ready` representing HUP readiness.
+ ///
+ /// A HUP (or hang-up) signifies that a stream socket **peer** closed the
+ /// connection, or shut down the writing half of the connection.
+ ///
+ /// **Note that only readable and writable readiness is guaranteed to be
+ /// supported on all platforms**. This means that `hup` readiness
+ /// should be treated as a hint. For more details, see [readiness] in the
+ /// poll documentation.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::hup();
+ ///
+ /// assert!(ready.is_hup());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ /// [readiness]: struct.Poll.html#readiness-operations
+ #[inline]
+ pub fn hup() -> UnixReady {
+ UnixReady(ready_from_usize(HUP))
+ }
+
+ /// Returns true if `Ready` contains AIO readiness
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::unix::UnixReady;
+ ///
+ /// let ready = UnixReady::aio();
+ ///
+ /// assert!(ready.is_aio());
+ /// ```
+ #[inline]
+ pub fn is_aio(&self) -> bool {
+ self.contains(ready_from_usize(AIO))
+ }
+
+ /// Returns true if the value includes error readiness
+ ///
+ /// **Note that only readable and writable readiness is guaranteed to be
+ /// supported on all platforms**. This means that `error` readiness should
+ /// be treated as a hint. For more details, see [readiness] in the poll
+ /// documentation.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::error();
+ ///
+ /// assert!(ready.is_error());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn is_error(&self) -> bool {
+ self.contains(ready_from_usize(ERROR))
+ }
+
+ /// Returns true if the value includes HUP readiness
+ ///
+ /// A HUP (or hang-up) signifies that a stream socket **peer** closed the
+ /// connection, or shut down the writing half of the connection.
+ ///
+ /// **Note that only readable and writable readiness is guaranteed to be
+ /// supported on all platforms**. This means that `hup` readiness
+ /// should be treated as a hint. For more details, see [readiness] in the
+ /// poll documentation.
+ ///
+ /// See [`Poll`] for more documentation on polling.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mio::Ready;
+ ///
+ /// let ready = Ready::hup();
+ ///
+ /// assert!(ready.is_hup());
+ /// ```
+ ///
+ /// [`Poll`]: struct.Poll.html
+ #[inline]
+ pub fn is_hup(&self) -> bool {
+ self.contains(ready_from_usize(HUP))
+ }
+}
+
+impl From<Ready> for UnixReady {
+ fn from(src: Ready) -> UnixReady {
+ UnixReady(src)
+ }
+}
+
+impl From<UnixReady> for Ready {
+ fn from(src: UnixReady) -> Ready {
+ src.0
+ }
+}
+
+impl ops::Deref for UnixReady {
+ type Target = Ready;
+
+ fn deref(&self) -> &Ready {
+ &self.0
+ }
+}
+
+impl ops::DerefMut for UnixReady {
+ fn deref_mut(&mut self) -> &mut Ready {
+ &mut self.0
+ }
+}
+
+impl ops::BitOr for UnixReady {
+ type Output = UnixReady;
+
+ #[inline]
+ fn bitor(self, other: UnixReady) -> UnixReady {
+ (self.0 | other.0).into()
+ }
+}
+
+impl ops::BitXor for UnixReady {
+ type Output = UnixReady;
+
+ #[inline]
+ fn bitxor(self, other: UnixReady) -> UnixReady {
+ (self.0 ^ other.0).into()
+ }
+}
+
+impl ops::BitAnd for UnixReady {
+ type Output = UnixReady;
+
+ #[inline]
+ fn bitand(self, other: UnixReady) -> UnixReady {
+ (self.0 & other.0).into()
+ }
+}
+
+impl ops::Sub for UnixReady {
+ type Output = UnixReady;
+
+ #[inline]
+ fn sub(self, other: UnixReady) -> UnixReady {
+ (self.0 & !other.0).into()
+ }
+}
+
+impl ops::Not for UnixReady {
+ type Output = UnixReady;
+
+ #[inline]
+ fn not(self) -> UnixReady {
+ (!self.0).into()
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/tcp.rs
@@ -0,0 +1,299 @@
+use std::cmp;
+use std::io::{Read, Write};
+use std::net::{self, SocketAddr};
+use std::os::unix::io::{RawFd, FromRawFd, IntoRawFd, AsRawFd};
+use std::time::Duration;
+
+use libc;
+use net2::TcpStreamExt;
+use iovec::IoVec;
+use iovec::unix as iovec;
+
+use {io, Ready, Poll, PollOpt, Token};
+use event::Evented;
+
+use sys::unix::eventedfd::EventedFd;
+use sys::unix::io::set_nonblock;
+
+#[derive(Debug)]
+pub struct TcpStream {
+ inner: net::TcpStream,
+}
+
+#[derive(Debug)]
+pub struct TcpListener {
+ inner: net::TcpListener,
+}
+
+impl TcpStream {
+ pub fn connect(stream: net::TcpStream, addr: &SocketAddr) -> io::Result<TcpStream> {
+ try!(set_nonblock(stream.as_raw_fd()));
+
+ match stream.connect(addr) {
+ Ok(..) => {}
+ Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
+ Err(e) => return Err(e),
+ }
+
+ Ok(TcpStream {
+ inner: stream,
+ })
+ }
+
+ pub fn from_stream(stream: net::TcpStream) -> TcpStream {
+ TcpStream {
+ inner: stream,
+ }
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ self.inner.peer_addr()
+ }
+
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.inner.local_addr()
+ }
+
+ pub fn try_clone(&self) -> io::Result<TcpStream> {
+ self.inner.try_clone().map(|s| {
+ TcpStream {
+ inner: s,
+ }
+ })
+ }
+
+ pub fn shutdown(&self, how: net::Shutdown) -> io::Result<()> {
+ self.inner.shutdown(how)
+ }
+
+ 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_recv_buffer_size(&self, size: usize) -> io::Result<()> {
+ self.inner.set_recv_buffer_size(size)
+ }
+
+ pub fn recv_buffer_size(&self) -> io::Result<usize> {
+ self.inner.recv_buffer_size()
+ }
+
+ pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
+ self.inner.set_send_buffer_size(size)
+ }
+
+ pub fn send_buffer_size(&self) -> io::Result<usize> {
+ self.inner.send_buffer_size()
+ }
+
+ pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
+ self.inner.set_keepalive(keepalive)
+ }
+
+ pub fn keepalive(&self) -> io::Result<Option<Duration>> {
+ self.inner.keepalive()
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.inner.set_ttl(ttl)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.inner.ttl()
+ }
+
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ self.inner.set_only_v6(only_v6)
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ self.inner.only_v6()
+ }
+
+ pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_linger(dur)
+ }
+
+ pub fn linger(&self) -> io::Result<Option<Duration>> {
+ self.inner.linger()
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ pub fn readv(&self, bufs: &mut [&mut IoVec]) -> io::Result<usize> {
+ unsafe {
+ let slice = iovec::as_os_slice_mut(bufs);
+ let len = cmp::min(<libc::c_int>::max_value() as usize, slice.len());
+ let rc = libc::readv(self.inner.as_raw_fd(),
+ slice.as_ptr(),
+ len as libc::c_int);
+ if rc < 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(rc as usize)
+ }
+ }
+ }
+
+ pub fn writev(&self, bufs: &[&IoVec]) -> io::Result<usize> {
+ unsafe {
+ let slice = iovec::as_os_slice(bufs);
+ let len = cmp::min(<libc::c_int>::max_value() as usize, slice.len());
+ let rc = libc::writev(self.inner.as_raw_fd(),
+ slice.as_ptr(),
+ len as libc::c_int);
+ if rc < 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(rc as usize)
+ }
+ }
+ }
+}
+
+impl<'a> Read for &'a TcpStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (&self.inner).read(buf)
+ }
+}
+
+impl<'a> Write for &'a TcpStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ (&self.inner).write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ (&self.inner).flush()
+ }
+}
+
+impl Evented for TcpStream {
+ fn register(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).deregister(poll)
+ }
+}
+
+impl FromRawFd for TcpStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> TcpStream {
+ TcpStream {
+ inner: net::TcpStream::from_raw_fd(fd),
+ }
+ }
+}
+
+impl IntoRawFd for TcpStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.inner.into_raw_fd()
+ }
+}
+
+impl AsRawFd for TcpStream {
+ fn as_raw_fd(&self) -> RawFd {
+ self.inner.as_raw_fd()
+ }
+}
+
+impl TcpListener {
+ pub fn new(inner: net::TcpListener, _addr: &SocketAddr) -> io::Result<TcpListener> {
+ try!(set_nonblock(inner.as_raw_fd()));
+ Ok(TcpListener {
+ inner: inner,
+ })
+ }
+
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.inner.local_addr()
+ }
+
+ pub fn try_clone(&self) -> io::Result<TcpListener> {
+ self.inner.try_clone().map(|s| {
+ TcpListener {
+ inner: s,
+ }
+ })
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ self.inner.accept().and_then(|(s, a)| {
+ try!(set_nonblock(s.as_raw_fd()));
+ Ok((TcpStream {
+ inner: s,
+ }, a))
+ })
+ }
+
+ #[allow(deprecated)]
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ self.inner.set_only_v6(only_v6)
+ }
+
+ #[allow(deprecated)]
+ pub fn only_v6(&self) -> io::Result<bool> {
+ self.inner.only_v6()
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.inner.set_ttl(ttl)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.inner.ttl()
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+}
+
+impl Evented for TcpListener {
+ fn register(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).deregister(poll)
+ }
+}
+
+impl FromRawFd for TcpListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
+ TcpListener {
+ inner: net::TcpListener::from_raw_fd(fd),
+ }
+ }
+}
+
+impl IntoRawFd for TcpListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.inner.into_raw_fd()
+ }
+}
+
+impl AsRawFd for TcpListener {
+ fn as_raw_fd(&self) -> RawFd {
+ self.inner.as_raw_fd()
+ }
+}
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/udp.rs
@@ -0,0 +1,157 @@
+use {io, Ready, Poll, PollOpt, Token};
+use event::Evented;
+use unix::EventedFd;
+use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr};
+use std::os::unix::io::{RawFd, IntoRawFd, AsRawFd, FromRawFd};
+
+#[allow(unused_imports)] // only here for Rust 1.8
+use net2::UdpSocketExt;
+
+#[derive(Debug)]
+pub struct UdpSocket {
+ io: net::UdpSocket,
+}
+
+impl UdpSocket {
+ pub fn new(socket: net::UdpSocket) -> io::Result<UdpSocket> {
+ try!(socket.set_nonblocking(true));
+ Ok(UdpSocket {
+ io: socket,
+ })
+ }
+
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.io.local_addr()
+ }
+
+ pub fn try_clone(&self) -> io::Result<UdpSocket> {
+ self.io.try_clone().map(|io| {
+ UdpSocket {
+ io: io,
+ }
+ })
+ }
+
+ pub fn send_to(&self, buf: &[u8], target: &SocketAddr) -> io::Result<usize> {
+ self.io.send_to(buf, target)
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.io.recv_from(buf)
+ }
+
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ self.io.send(buf)
+ }
+
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.io.recv(buf)
+ }
+
+ pub fn connect(&self, addr: SocketAddr)
+ -> io::Result<()> {
+ self.io.connect(addr)
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ self.io.broadcast()
+ }
+
+ pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
+ self.io.set_broadcast(on)
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ self.io.multicast_loop_v4()
+ }
+
+ pub fn set_multicast_loop_v4(&self, on: bool) -> io::Result<()> {
+ self.io.set_multicast_loop_v4(on)
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ self.io.multicast_ttl_v4()
+ }
+
+ pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
+ self.io.set_multicast_ttl_v4(ttl)
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ self.io.multicast_loop_v6()
+ }
+
+ pub fn set_multicast_loop_v6(&self, on: bool) -> io::Result<()> {
+ self.io.set_multicast_loop_v6(on)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.io.ttl()
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.io.set_ttl(ttl)
+ }
+
+ pub fn join_multicast_v4(&self,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr) -> io::Result<()> {
+ self.io.join_multicast_v4(multiaddr, interface)
+ }
+
+ pub fn join_multicast_v6(&self,
+ multiaddr: &Ipv6Addr,
+ interface: u32) -> io::Result<()> {
+ self.io.join_multicast_v6(multiaddr, interface)
+ }
+
+ pub fn leave_multicast_v4(&self,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr) -> io::Result<()> {
+ self.io.leave_multicast_v4(multiaddr, interface)
+ }
+
+ pub fn leave_multicast_v6(&self,
+ multiaddr: &Ipv6Addr,
+ interface: u32) -> io::Result<()> {
+ self.io.leave_multicast_v6(multiaddr, interface)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.io.take_error()
+ }
+}
+
+impl Evented for UdpSocket {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ EventedFd(&self.as_raw_fd()).deregister(poll)
+ }
+}
+
+impl FromRawFd for UdpSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> UdpSocket {
+ UdpSocket {
+ io: net::UdpSocket::from_raw_fd(fd),
+ }
+ }
+}
+
+impl IntoRawFd for UdpSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.io.into_raw_fd()
+ }
+}
+
+impl AsRawFd for UdpSocket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.io.as_raw_fd()
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/unix/uds.rs
@@ -0,0 +1,273 @@
+use std::io::{Read, Write};
+use std::mem;
+use std::net::Shutdown;
+use std::os::unix::prelude::*;
+use std::path::Path;
+
+use libc;
+
+use {io, Evented, Ready, Poll, PollOpt, Token};
+use sys::unix::{cvt, Io};
+use sys::unix::io::{set_nonblock, set_cloexec};
+
+trait MyInto<T> {
+ fn my_into(self) -> T;
+}
+
+impl MyInto<u32> for usize {
+ fn my_into(self) -> u32 { self as u32 }
+}
+
+impl MyInto<usize> for usize {
+ fn my_into(self) -> usize { self }
+}
+
+unsafe fn sockaddr_un(path: &Path)
+ -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+ let mut addr: libc::sockaddr_un = mem::zeroed();
+ addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+ let bytes = path.as_os_str().as_bytes();
+
+ if bytes.len() >= addr.sun_path.len() {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "path must be shorter than SUN_LEN"))
+ }
+ for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
+ *dst = *src as libc::c_char;
+ }
+ // null byte for pathname addresses is already there because we zeroed the
+ // struct
+
+ let mut len = sun_path_offset() + bytes.len();
+ match bytes.get(0) {
+ Some(&0) | None => {}
+ Some(_) => len += 1,
+ }
+ Ok((addr, len as libc::socklen_t))
+}
+
+fn sun_path_offset() -> usize {
+ unsafe {
+ // Work with an actual instance of the type since using a null pointer is UB
+ let addr: libc::sockaddr_un = mem::uninitialized();
+ let base = &addr as *const _ as usize;
+ let path = &addr.sun_path as *const _ as usize;
+ path - base
+ }
+}
+
+#[derive(Debug)]
+pub struct UnixSocket {
+ io: Io,
+}
+
+impl UnixSocket {
+ /// Returns a new, unbound, non-blocking Unix domain socket
+ pub fn stream() -> io::Result<UnixSocket> {
+ #[cfg(target_os = "linux")]
+ use libc::{SOCK_CLOEXEC, SOCK_NONBLOCK};
+ #[cfg(not(target_os = "linux"))]
+ const SOCK_CLOEXEC: libc::c_int = 0;
+ #[cfg(not(target_os = "linux"))]
+ const SOCK_NONBLOCK: libc::c_int = 0;
+
+ unsafe {
+ if cfg!(target_os = "linux") {
+ let flags = libc::SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
+ match cvt(libc::socket(libc::AF_UNIX, flags, 0)) {
+ Ok(fd) => return Ok(UnixSocket::from_raw_fd(fd)),
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ let fd = try!(cvt(libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0)));
+ let fd = UnixSocket::from_raw_fd(fd);
+ try!(set_cloexec(fd.as_raw_fd()));
+ try!(set_nonblock(fd.as_raw_fd()));
+ Ok(fd)
+ }
+ }
+
+ /// Connect the socket to the specified address
+ pub fn connect<P: AsRef<Path> + ?Sized>(&self, addr: &P) -> io::Result<()> {
+ unsafe {
+ let (addr, len) = try!(sockaddr_un(addr.as_ref()));
+ try!(cvt(libc::connect(self.as_raw_fd(),
+ &addr as *const _ as *const _,
+ len)));
+ Ok(())
+ }
+ }
+
+ /// Listen for incoming requests
+ pub fn listen(&self, backlog: usize) -> io::Result<()> {
+ unsafe {
+ try!(cvt(libc::listen(self.as_raw_fd(), backlog as i32)));
+ Ok(())
+ }
+ }
+
+ pub fn accept(&self) -> io::Result<UnixSocket> {
+ unsafe {
+ let fd = try!(cvt(libc::accept(self.as_raw_fd(),
+ 0 as *mut _,
+ 0 as *mut _)));
+ let fd = Io::from_raw_fd(fd);
+ try!(set_cloexec(fd.as_raw_fd()));
+ try!(set_nonblock(fd.as_raw_fd()));
+ Ok(UnixSocket { io: fd })
+ }
+ }
+
+ /// Bind the socket to the specified address
+ #[cfg(not(all(target_arch = "aarch64",target_os = "android")))]
+ pub fn bind<P: AsRef<Path> + ?Sized>(&self, addr: &P) -> io::Result<()> {
+ unsafe {
+ let (addr, len) = try!(sockaddr_un(addr.as_ref()));
+ try!(cvt(libc::bind(self.as_raw_fd(),
+ &addr as *const _ as *const _,
+ len)));
+ Ok(())
+ }
+ }
+
+ #[cfg(all(target_arch = "aarch64",target_os = "android"))]
+ pub fn bind<P: AsRef<Path> + ?Sized>(&self, addr: &P) -> io::Result<()> {
+ unsafe {
+ let (addr, len) = try!(sockaddr_un(addr.as_ref()));
+ let len_i32 = len as i32;
+ try!(cvt(libc::bind(self.as_raw_fd(),
+ &addr as *const _ as *const _,
+ len_i32)));
+ Ok(())
+ }
+ }
+
+ pub fn try_clone(&self) -> io::Result<UnixSocket> {
+ Ok(UnixSocket { io: try!(self.io.try_clone()) })
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ let how = match how {
+ Shutdown::Read => libc::SHUT_RD,
+ Shutdown::Write => libc::SHUT_WR,
+ Shutdown::Both => libc::SHUT_RDWR,
+ };
+ unsafe {
+ try!(cvt(libc::shutdown(self.as_raw_fd(), how)));
+ Ok(())
+ }
+ }
+
+ pub fn read_recv_fd(&mut self, buf: &mut [u8]) -> io::Result<(usize, Option<RawFd>)> {
+ unsafe {
+ let mut iov = libc::iovec {
+ iov_base: buf.as_mut_ptr() as *mut _,
+ iov_len: buf.len(),
+ };
+ struct Cmsg {
+ hdr: libc::cmsghdr,
+ data: [libc::c_int; 1],
+ }
+ let mut cmsg: Cmsg = mem::zeroed();
+ let mut msg: libc::msghdr = mem::zeroed();
+ msg.msg_iov = &mut iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &mut cmsg as *mut _ as *mut _;
+ msg.msg_controllen = mem::size_of_val(&cmsg).my_into();
+ let bytes = try!(cvt(libc::recvmsg(self.as_raw_fd(), &mut msg, 0)));
+
+ const SCM_RIGHTS: libc::c_int = 1;
+
+ let fd = if cmsg.hdr.cmsg_level == libc::SOL_SOCKET &&
+ cmsg.hdr.cmsg_type == SCM_RIGHTS {
+ Some(cmsg.data[0])
+ } else {
+ None
+ };
+ Ok((bytes as usize, fd))
+ }
+ }
+
+ pub fn write_send_fd(&mut self, buf: &[u8], fd: RawFd) -> io::Result<usize> {
+ unsafe {
+ let mut iov = libc::iovec {
+ iov_base: buf.as_ptr() as *mut _,
+ iov_len: buf.len(),
+ };
+ struct Cmsg {
+ hdr: libc::cmsghdr,
+ data: [libc::c_int; 1],
+ }
+ let mut cmsg: Cmsg = mem::zeroed();
+ cmsg.hdr.cmsg_len = mem::size_of_val(&cmsg).my_into();
+ cmsg.hdr.cmsg_level = libc::SOL_SOCKET;
+ cmsg.hdr.cmsg_type = 1; // SCM_RIGHTS
+ cmsg.data[0] = fd;
+ let mut msg: libc::msghdr = mem::zeroed();
+ msg.msg_iov = &mut iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &mut cmsg as *mut _ as *mut _;
+ msg.msg_controllen = mem::size_of_val(&cmsg).my_into();
+ let bytes = try!(cvt(libc::sendmsg(self.as_raw_fd(), &msg, 0)));
+ Ok(bytes as usize)
+ }
+ }
+}
+
+impl Read for UnixSocket {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.io.read(buf)
+ }
+}
+
+impl Write for UnixSocket {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.io.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.io.flush()
+ }
+}
+
+impl Evented for UnixSocket {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.io.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.io.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.io.deregister(poll)
+ }
+}
+
+
+impl From<Io> for UnixSocket {
+ fn from(io: Io) -> UnixSocket {
+ UnixSocket { io: io }
+ }
+}
+
+impl FromRawFd for UnixSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixSocket {
+ UnixSocket { io: Io::from_raw_fd(fd) }
+ }
+}
+
+impl IntoRawFd for UnixSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.io.into_raw_fd()
+ }
+}
+
+impl AsRawFd for UnixSocket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.io.as_raw_fd()
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/windows/awakener.rs
@@ -0,0 +1,66 @@
+use std::sync::Mutex;
+
+use miow::iocp::CompletionStatus;
+use {io, poll, Ready, Poll, PollOpt, Token};
+use event::Evented;
+use sys::windows::Selector;
+
+pub struct Awakener {
+ inner: Mutex<Option<AwakenerInner>>,
+}
+
+struct AwakenerInner {
+ token: Token,
+ selector: Selector,
+}
+
+impl Awakener {
+ pub fn new() -> io::Result<Awakener> {
+ Ok(Awakener {
+ inner: Mutex::new(None),
+ })
+ }
+
+ pub fn wakeup(&self) -> io::Result<()> {
+ // Each wakeup notification has NULL as its `OVERLAPPED` pointer to
+ // indicate that it's from this awakener and not part of an I/O
+ // operation. This is specially recognized by the selector.
+ //
+ // If we haven't been registered with an event loop yet just silently
+ // succeed.
+ if let Some(inner) = self.inner.lock().unwrap().as_ref() {
+ let status = CompletionStatus::new(0,
+ usize::from(inner.token),
+ 0 as *mut _);
+ try!(inner.selector.port().post(status));
+ }
+ Ok(())
+ }
+
+ pub fn cleanup(&self) {
+ // noop
+ }
+}
+
+impl Evented for Awakener {
+ fn register(&self, poll: &Poll, token: Token, events: Ready,
+ opts: PollOpt) -> io::Result<()> {
+ assert_eq!(opts, PollOpt::edge());
+ assert_eq!(events, Ready::readable());
+ *self.inner.lock().unwrap() = Some(AwakenerInner {
+ selector: poll::selector(poll).clone_ref(),
+ token: token,
+ });
+ Ok(())
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, events: Ready,
+ opts: PollOpt) -> io::Result<()> {
+ self.register(poll, token, events, opts)
+ }
+
+ fn deregister(&self, _poll: &Poll) -> io::Result<()> {
+ *self.inner.lock().unwrap() = None;
+ Ok(())
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/windows/buffer_pool.rs
@@ -0,0 +1,20 @@
+pub struct BufferPool {
+ pool: Vec<Vec<u8>>,
+}
+
+impl BufferPool {
+ pub fn new(cap: usize) -> BufferPool {
+ BufferPool { pool: Vec::with_capacity(cap) }
+ }
+
+ pub fn get(&mut self, default_cap: usize) -> Vec<u8> {
+ self.pool.pop().unwrap_or_else(|| Vec::with_capacity(default_cap))
+ }
+
+ pub fn put(&mut self, mut buf: Vec<u8>) {
+ if self.pool.len() < self.pool.capacity(){
+ unsafe { buf.set_len(0); }
+ self.pool.push(buf);
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/windows/from_raw_arc.rs
@@ -0,0 +1,116 @@
+//! A "Manual Arc" which allows manually frobbing the reference count
+//!
+//! This module contains a copy of the `Arc` found in the standard library,
+//! stripped down to the bare bones of what we actually need. The reason this is
+//! done is for the ability to concretely know the memory layout of the `Inner`
+//! structure of the arc pointer itself (e.g. `ArcInner` in the standard
+//! library).
+//!
+//! We do some unsafe casting from `*mut OVERLAPPED` to a `FromRawArc<T>` to
+//! ensure that data lives for the length of an I/O operation, but this means
+//! that we have to know the layouts of the structures involved. This
+//! representation primarily guarantees that the data, `T` is at the front of
+//! the inner pointer always.
+//!
+//! Note that we're missing out on some various optimizations implemented in the
+//! standard library:
+//!
+//! * The size of `FromRawArc` is actually two words because of the drop flag
+//! * The compiler doesn't understand that the pointer in `FromRawArc` is never
+//! null, so Option<FromRawArc<T>> is not a nullable pointer.
+
+use std::ops::Deref;
+use std::mem;
+use std::sync::atomic::{self, AtomicUsize, Ordering};
+
+pub struct FromRawArc<T> {
+ _inner: *mut Inner<T>,
+}
+
+unsafe impl<T: Sync + Send> Send for FromRawArc<T> { }
+unsafe impl<T: Sync + Send> Sync for FromRawArc<T> { }
+
+#[repr(C)]
+struct Inner<T> {
+ data: T,
+ cnt: AtomicUsize,
+}
+
+impl<T> FromRawArc<T> {
+ pub fn new(data: T) -> FromRawArc<T> {
+ let x = Box::new(Inner {
+ data: data,
+ cnt: AtomicUsize::new(1),
+ });
+ FromRawArc { _inner: unsafe { mem::transmute(x) } }
+ }
+
+ pub unsafe fn from_raw(ptr: *mut T) -> FromRawArc<T> {
+ // Note that if we could use `mem::transmute` here to get a libstd Arc
+ // (guaranteed) then we could just use std::sync::Arc, but this is the
+ // crucial reason this currently exists.
+ FromRawArc { _inner: ptr as *mut Inner<T> }
+ }
+}
+
+impl<T> Clone for FromRawArc<T> {
+ fn clone(&self) -> FromRawArc<T> {
+ // Atomic ordering of Relaxed lifted from libstd, but the general idea
+ // is that you need synchronization to communicate this increment to
+ // another thread, so this itself doesn't need to be synchronized.
+ unsafe {
+ (*self._inner).cnt.fetch_add(1, Ordering::Relaxed);
+ }
+ FromRawArc { _inner: self._inner }
+ }
+}
+
+impl<T> Deref for FromRawArc<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ unsafe { &(*self._inner).data }
+ }
+}
+
+impl<T> Drop for FromRawArc<T> {
+ fn drop(&mut self) {
+ unsafe {
+ // Atomic orderings lifted from the standard library
+ if (*self._inner).cnt.fetch_sub(1, Ordering::Release) != 1 {
+ return
+ }
+ atomic::fence(Ordering::Acquire);
+ drop(mem::transmute::<_, Box<T>>(self._inner));
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::FromRawArc;
+
+ #[test]
+ fn smoke() {
+ let a = FromRawArc::new(1);
+ assert_eq!(*a, 1);
+ assert_eq!(*a.clone(), 1);
+ }
+
+ #[test]
+ fn drops() {
+ struct A<'a>(&'a mut bool);
+ impl<'a> Drop for A<'a> {
+ fn drop(&mut self) {
+ *self.0 = true;
+ }
+ }
+ let mut a = false;
+ {
+ let a = FromRawArc::new(A(&mut a));
+ a.clone();
+ assert!(!*a.0);
+ }
+ assert!(a);
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/windows/mod.rs
@@ -0,0 +1,191 @@
+//! Implementation of mio for Windows using IOCP
+//!
+//! This module uses I/O Completion Ports (IOCP) on Windows to implement mio's
+//! Unix epoll-like interface. Unfortunately these two I/O models are
+//! fundamentally incompatible:
+//!
+//! * IOCP is a completion-based model where work is submitted to the kernel and
+//! a program is notified later when the work finished.
+//! * epoll is a readiness-based model where the kernel is queried as to what
+//! work can be done, and afterwards the work is done.
+//!
+//! As a result, this implementation for Windows is much less "low level" than
+//! the Unix implementation of mio. This design decision was intentional,
+//! however.
+//!
+//! ## What is IOCP?
+//!
+//! The [official docs][docs] have a comprehensive explanation of what IOCP is,
+//! but at a high level it requires the following operations to be executed to
+//! perform some I/O:
+//!
+//! 1. A completion port is created
+//! 2. An I/O handle and a token is registered with this completion port
+//! 3. Some I/O is issued on the handle. This generally means that an API was
+//! invoked with a zeroed `OVERLAPPED` structure. The API will immediately
+//! return.
+//! 4. After some time, the application queries the I/O port for completed
+//! events. The port will returned a pointer to the `OVERLAPPED` along with
+//! the token presented at registration time.
+//!
+//! Many I/O operations can be fired off before waiting on a port, and the port
+//! will block execution of the calling thread until an I/O event has completed
+//! (or a timeout has elapsed).
+//!
+//! Currently all of these low-level operations are housed in a separate `miow`
+//! crate to provide a 0-cost abstraction over IOCP. This crate uses that to
+//! implement all fiddly bits so there's very few actual Windows API calls or
+//! `unsafe` blocks as a result.
+//!
+//! [docs]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365198%28v=vs.85%29.aspx
+//!
+//! ## Safety of IOCP
+//!
+//! Unfortunately for us, IOCP is pretty unsafe in terms of Rust lifetimes and
+//! such. When an I/O operation is submitted to the kernel, it involves handing
+//! the kernel a few pointers like a buffer to read/write, an `OVERLAPPED`
+//! structure pointer, and perhaps some other buffers such as for socket
+//! addresses. These pointers all have to remain valid **for the entire I/O
+//! operation's duration**.
+//!
+//! There's no way to define a safe lifetime for these pointers/buffers over
+//! the span of an I/O operation, so we're forced to add a layer of abstraction
+//! (not 0-cost) to make these APIs safe. Currently this implementation
+//! basically just boxes everything up on the heap to give it a stable address
+//! and then keys off that most of the time.
+//!
+//! ## From completion to readiness
+//!
+//! Translating a completion-based model to a readiness-based model is also no
+//! easy task, and a significant portion of this implementation is managing this
+//! translation. The basic idea behind this implementation is to issue I/O
+//! operations preemptively and then translate their completions to a "I'm
+//! ready" event.
+//!
+//! For example, in the case of reading a `TcpSocket`, as soon as a socket is
+//! connected (or registered after an accept) a read operation is executed.
+//! While the read is in progress calls to `read` will return `WouldBlock`, and
+//! once the read is completed we translate the completion notification into a
+//! `readable` event. Once the internal buffer is drained (e.g. all data from it
+//! has been read) a read operation is re-issued.
+//!
+//! Write operations are a little different from reads, and the current
+//! implementation is to just schedule a write as soon as `write` is first
+//! called. While that write operation is in progress all future calls to
+//! `write` will return `WouldBlock`. Completion of the write then translates to
+//! a `writable` event. Note that this will probably want to add some layer of
+//! internal buffering in the future.
+//!
+//! ## Buffer Management
+//!
+//! As there's lots of I/O operations in flight at any one point in time,
+//! there's lots of live buffers that need to be juggled around (e.g. this
+//! implementation's own internal buffers).
+//!
+//! Currently all buffers are created for the I/O operation at hand and are then
+//! discarded when it completes (this is listed as future work below).
+//!
+//! ## Callback Management
+//!
+//! When the main event loop receives a notification that an I/O operation has
+//! completed, some work needs to be done to translate that to a set of events
+//! or perhaps some more I/O needs to be scheduled. For example after a
+//! `TcpStream` is connected it generates a writable event and also schedules a
+//! read.
+//!
+//! To manage all this the `Selector` uses the `OVERLAPPED` pointer from the
+//! completion status. The selector assumes that all `OVERLAPPED` pointers are
+//! actually pointers to the interior of a `selector::Overlapped` which means
+//! that right after the `OVERLAPPED` itself there's a function pointer. This
+//! function pointer is given the completion status as well as another callback
+//! to push events onto the selector.
+//!
+//! The callback for each I/O operation doesn't have any environment, so it
+//! relies on memory layout and unsafe casting to translate an `OVERLAPPED`
+//! pointer (or in this case a `selector::Overlapped` pointer) to a type of
+//! `FromRawArc<T>` (see module docs for why this type exists).
+//!
+//! ## Thread Safety
+//!
+//! Currently all of the I/O primitives make liberal use of `Arc` and `Mutex`
+//! as an implementation detail. The main reason for this is to ensure that the
+//! types are `Send` and `Sync`, but the implementations have not been stressed
+//! in multithreaded situations yet. As a result, there are bound to be
+//! functional surprises in using these concurrently.
+//!
+//! ## Future Work
+//!
+//! First up, let's take a look at unimplemented portions of this module:
+//!
+//! * The `PollOpt::level()` option is currently entirely unimplemented.
+//! * Each `EventLoop` currently owns its completion port, but this prevents an
+//! I/O handle from being added to multiple event loops (something that can be
+//! done on Unix). Additionally, it hinders event loops moving across threads.
+//! This should be solved by likely having a global `Selector` which all
+//! others then communicate with.
+//! * Although Unix sockets don't exist on Windows, there are named pipes and
+//! those should likely be bound here in a similar fashion to `TcpStream`.
+//!
+//! Next up, there are a few performance improvements and optimizations that can
+//! still be implemented
+//!
+//! * Buffer management right now is pretty bad, they're all just allocated
+//! right before an I/O operation and discarded right after. There should at
+//! least be some form of buffering buffers.
+//! * No calls to `write` are internally buffered before being scheduled, which
+//! means that writing performance is abysmal compared to Unix. There should
+//! be some level of buffering of writes probably.
+
+use std::io;
+use std::os::windows::prelude::*;
+
+use kernel32;
+use winapi;
+
+mod awakener;
+#[macro_use]
+mod selector;
+mod tcp;
+mod udp;
+mod from_raw_arc;
+mod buffer_pool;
+
+pub use self::awakener::Awakener;
+pub use self::selector::{Events, Selector, Overlapped, Binding};
+pub use self::tcp::{TcpStream, TcpListener};
+pub use self::udp::UdpSocket;
+
+#[derive(Copy, Clone)]
+enum Family {
+ V4, V6,
+}
+
+fn wouldblock() -> io::Error {
+ io::Error::new(io::ErrorKind::WouldBlock, "operation would block")
+}
+
+unsafe fn cancel(socket: &AsRawSocket,
+ overlapped: &Overlapped) -> io::Result<()> {
+ let handle = socket.as_raw_socket() as winapi::HANDLE;
+ let ret = kernel32::CancelIoEx(handle, overlapped.as_mut_ptr());
+ if ret == 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(())
+ }
+}
+
+unsafe fn no_notify_on_instant_completion(handle: winapi::HANDLE) -> io::Result<()> {
+ // TODO: move those to winapi
+ const FILE_SKIP_COMPLETION_PORT_ON_SUCCESS: winapi::UCHAR = 1;
+ const FILE_SKIP_SET_EVENT_ON_HANDLE: winapi::UCHAR = 2;
+
+ let flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE;
+
+ let r = kernel32::SetFileCompletionNotificationModes(handle, flags);
+ if r == winapi::TRUE {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/windows/selector.rs
@@ -0,0 +1,528 @@
+#![allow(deprecated)]
+
+use std::{fmt, io, u32};
+use std::cell::UnsafeCell;
+use std::os::windows::prelude::*;
+use std::sync::{Arc, Mutex};
+use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+use std::time::Duration;
+
+use lazycell::AtomicLazyCell;
+
+use winapi::*;
+use miow;
+use miow::iocp::{CompletionPort, CompletionStatus};
+
+use event_imp::{Event, Evented, Ready};
+use poll::{self, Poll};
+use sys::windows::buffer_pool::BufferPool;
+use {Token, PollOpt};
+
+/// Each Selector has a globally unique(ish) ID associated with it. This ID
+/// gets tracked by `TcpStream`, `TcpListener`, etc... when they are first
+/// registered with the `Selector`. If a type that is previously associated with
+/// a `Selector` attempts to register itself with a different `Selector`, the
+/// operation will return with an error. This matches windows behavior.
+static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+
+/// The guts of the Windows event loop, this is the struct which actually owns
+/// a completion port.
+///
+/// Internally this is just an `Arc`, and this allows handing out references to
+/// the internals to I/O handles registered on this selector. This is
+/// required to schedule I/O operations independently of being inside the event
+/// loop (e.g. when a call to `write` is seen we're not "in the event loop").
+pub struct Selector {
+ inner: Arc<SelectorInner>,
+}
+
+struct SelectorInner {
+ /// Unique identifier of the `Selector`
+ id: usize,
+
+ /// The actual completion port that's used to manage all I/O
+ port: CompletionPort,
+
+ /// A pool of buffers usable by this selector.
+ ///
+ /// Primitives will take buffers from this pool to perform I/O operations,
+ /// and once complete they'll be put back in.
+ buffers: Mutex<BufferPool>,
+}
+
+impl Selector {
+ pub fn new() -> io::Result<Selector> {
+ // offset by 1 to avoid choosing 0 as the id of a selector
+ let id = NEXT_ID.fetch_add(1, Ordering::Relaxed) + 1;
+
+ CompletionPort::new(1).map(|cp| {
+ Selector {
+ inner: Arc::new(SelectorInner {
+ id: id,
+ port: cp,
+ buffers: Mutex::new(BufferPool::new(256)),
+ }),
+ }
+ })
+ }
+
+ pub fn select(&self,
+ events: &mut Events,
+ awakener: Token,
+ timeout: Option<Duration>) -> io::Result<bool> {
+ trace!("select; timeout={:?}", timeout);
+
+ // Clear out the previous list of I/O events and get some more!
+ events.events.truncate(0);
+
+ trace!("polling IOCP");
+ let n = match self.inner.port.get_many(&mut events.statuses, timeout) {
+ Ok(statuses) => statuses.len(),
+ Err(ref e) if e.raw_os_error() == Some(WAIT_TIMEOUT as i32) => 0,
+ Err(e) => return Err(e),
+ };
+
+ let mut ret = false;
+ for status in events.statuses[..n].iter() {
+ // This should only ever happen from the awakener, and we should
+ // only ever have one awakener right not, so assert as such.
+ if status.overlapped() as usize == 0 {
+ assert_eq!(status.token(), usize::from(awakener));
+ ret = true;
+ continue;
+ }
+
+ let callback = unsafe {
+ (*(status.overlapped() as *mut Overlapped)).callback
+ };
+
+ trace!("select; -> got overlapped");
+ callback(status.entry());
+ }
+
+ trace!("returning");
+ Ok(ret)
+ }
+
+ /// Gets a reference to the underlying `CompletionPort` structure.
+ pub fn port(&self) -> &CompletionPort {
+ &self.inner.port
+ }
+
+ /// Gets a new reference to this selector, although all underlying data
+ /// structures will refer to the same completion port.
+ pub fn clone_ref(&self) -> Selector {
+ Selector { inner: self.inner.clone() }
+ }
+
+ /// Return the `Selector`'s identifier
+ pub fn id(&self) -> usize {
+ self.inner.id
+ }
+}
+
+impl SelectorInner {
+ fn identical(&self, other: &SelectorInner) -> bool {
+ (self as *const SelectorInner) == (other as *const SelectorInner)
+ }
+}
+
+// A registration is stored in each I/O object which keeps track of how it is
+// associated with a `Selector` above.
+//
+// Once associated with a `Selector`, a registration can never be un-associated
+// (due to IOCP requirements). This is actually implemented through the
+// `poll::Registration` and `poll::SetReadiness` APIs to keep track of all the
+// level/edge/filtering business.
+/// A `Binding` is embedded in all I/O objects associated with a `Poll`
+/// object.
+///
+/// Each registration keeps track of which selector the I/O object is
+/// associated with, ensuring that implementations of `Evented` can be
+/// conformant for the various methods on Windows.
+///
+/// If you're working with custom IOCP-enabled objects then you'll want to
+/// ensure that one of these instances is stored in your object and used in the
+/// implementation of `Evented`.
+///
+/// For more information about how to use this see the `windows` module
+/// documentation in this crate.
+pub struct Binding {
+ selector: AtomicLazyCell<Arc<SelectorInner>>,
+}
+
+impl Binding {
+ /// Creates a new blank binding ready to be inserted into an I/O
+ /// object.
+ ///
+ /// Won't actually do anything until associated with a `Poll` loop.
+ pub fn new() -> Binding {
+ Binding { selector: AtomicLazyCell::new() }
+ }
+
+ /// Registers a new handle with the `Poll` specified, also assigning the
+ /// `token` specified.
+ ///
+ /// This function is intended to be used as part of `Evented::register` for
+ /// custom IOCP objects. It will add the specified handle to the internal
+ /// IOCP object with the provided `token`. All future events generated by
+ /// the handled provided will be received by the `Poll`'s internal IOCP
+ /// object.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe as the `Poll` instance has assumptions about
+ /// what the `OVERLAPPED` pointer used for each I/O operation looks like.
+ /// Specifically they must all be instances of the `Overlapped` type in
+ /// this crate. More information about this can be found on the
+ /// `windows` module in this crate.
+ pub unsafe fn register_handle(&self,
+ handle: &AsRawHandle,
+ token: Token,
+ poll: &Poll) -> io::Result<()> {
+ let selector = poll::selector(poll);
+
+ // Ignore errors, we'll see them on the next line.
+ drop(self.selector.fill(selector.inner.clone()));
+ try!(self.check_same_selector(poll));
+
+ selector.inner.port.add_handle(usize::from(token), handle)
+ }
+
+ /// Same as `register_handle` but for sockets.
+ pub unsafe fn register_socket(&self,
+ handle: &AsRawSocket,
+ token: Token,
+ poll: &Poll) -> io::Result<()> {
+ let selector = poll::selector(poll);
+ drop(self.selector.fill(selector.inner.clone()));
+ try!(self.check_same_selector(poll));
+ selector.inner.port.add_socket(usize::from(token), handle)
+ }
+
+ /// Reregisters the handle provided from the `Poll` provided.
+ ///
+ /// This is intended to be used as part of `Evented::reregister` but note
+ /// that this function does not currently reregister the provided handle
+ /// with the `poll` specified. IOCP has a special binding for changing the
+ /// token which has not yet been implemented. Instead this function should
+ /// be used to assert that the call to `reregister` happened on the same
+ /// `Poll` that was passed into to `register`.
+ ///
+ /// Eventually, though, the provided `handle` will be re-assigned to have
+ /// the token `token` on the given `poll` assuming that it's been
+ /// previously registered with it.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe for similar reasons to `register`. That is,
+ /// there may be pending I/O events and such which aren't handled correctly.
+ pub unsafe fn reregister_handle(&self,
+ _handle: &AsRawHandle,
+ _token: Token,
+ poll: &Poll) -> io::Result<()> {
+ self.check_same_selector(poll)
+ }
+
+ /// Same as `reregister_handle`, but for sockets.
+ pub unsafe fn reregister_socket(&self,
+ _socket: &AsRawSocket,
+ _token: Token,
+ poll: &Poll) -> io::Result<()> {
+ self.check_same_selector(poll)
+ }
+
+ /// Deregisters the handle provided from the `Poll` provided.
+ ///
+ /// This is intended to be used as part of `Evented::deregister` but note
+ /// that this function does not currently deregister the provided handle
+ /// from the `poll` specified. IOCP has a special binding for that which has
+ /// not yet been implemented. Instead this function should be used to assert
+ /// that the call to `deregister` happened on the same `Poll` that was
+ /// passed into to `register`.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe for similar reasons to `register`. That is,
+ /// there may be pending I/O events and such which aren't handled correctly.
+ pub unsafe fn deregister_handle(&self,
+ _handle: &AsRawHandle,
+ poll: &Poll) -> io::Result<()> {
+ self.check_same_selector(poll)
+ }
+
+ /// Same as `deregister_handle`, but for sockets.
+ pub unsafe fn deregister_socket(&self,
+ _socket: &AsRawSocket,
+ poll: &Poll) -> io::Result<()> {
+ self.check_same_selector(poll)
+ }
+
+ fn check_same_selector(&self, poll: &Poll) -> io::Result<()> {
+ let selector = poll::selector(poll);
+ match self.selector.borrow() {
+ Some(prev) if prev.identical(&selector.inner) => Ok(()),
+ Some(_) |
+ None => Err(other("socket already registered")),
+ }
+ }
+}
+
+impl fmt::Debug for Binding {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Binding")
+ }
+}
+
+/// Helper struct used for TCP and UDP which bundles a `binding` with a
+/// `SetReadiness` handle.
+pub struct ReadyBinding {
+ binding: Binding,
+ readiness: Option<poll::SetReadiness>,
+}
+
+impl ReadyBinding {
+ /// Creates a new blank binding ready to be inserted into an I/O object.
+ ///
+ /// Won't actually do anything until associated with an `Selector` loop.
+ pub fn new() -> ReadyBinding {
+ ReadyBinding {
+ binding: Binding::new(),
+ readiness: None,
+ }
+ }
+
+ /// Returns whether this binding has been associated with a selector
+ /// yet.
+ pub fn registered(&self) -> bool {
+ self.readiness.is_some()
+ }
+
+ /// Acquires a buffer with at least `size` capacity.
+ ///
+ /// If associated with a selector, this will attempt to pull a buffer from
+ /// that buffer pool. If not associated with a selector, this will allocate
+ /// a fresh buffer.
+ pub fn get_buffer(&self, size: usize) -> Vec<u8> {
+ match self.binding.selector.borrow() {
+ Some(i) => i.buffers.lock().unwrap().get(size),
+ None => Vec::with_capacity(size),
+ }
+ }
+
+ /// Returns a buffer to this binding.
+ ///
+ /// If associated with a selector, this will push the buffer back into the
+ /// selector's pool of buffers. Otherwise this will just drop the buffer.
+ pub fn put_buffer(&self, buf: Vec<u8>) {
+ if let Some(i) = self.binding.selector.borrow() {
+ i.buffers.lock().unwrap().put(buf);
+ }
+ }
+
+ /// Sets the readiness of this I/O object to a particular `set`.
+ ///
+ /// This is later used to fill out and respond to requests to `poll`. Note
+ /// that this is all implemented through the `SetReadiness` structure in the
+ /// `poll` module.
+ pub fn set_readiness(&self, set: Ready) {
+ if let Some(ref i) = self.readiness {
+ trace!("set readiness to {:?}", set);
+ i.set_readiness(set).expect("event loop disappeared?");
+ }
+ }
+
+ /// Queries what the current readiness of this I/O object is.
+ ///
+ /// This is what's being used to generate events returned by `poll`.
+ pub fn readiness(&self) -> Ready {
+ match self.readiness {
+ Some(ref i) => i.readiness(),
+ None => Ready::empty(),
+ }
+ }
+
+ /// Implementation of the `Evented::register` function essentially.
+ ///
+ /// Returns an error if we're already registered with another event loop,
+ /// and otherwise just reassociates ourselves with the event loop to
+ /// possible change tokens.
+ pub fn register_socket(&mut self,
+ socket: &AsRawSocket,
+ poll: &Poll,
+ token: Token,
+ events: Ready,
+ opts: PollOpt,
+ registration: &Mutex<Option<poll::Registration>>)
+ -> io::Result<()> {
+ trace!("register {:?} {:?}", token, events);
+ unsafe {
+ try!(self.binding.register_socket(socket, token, poll));
+ }
+
+ let (r, s) = poll::new_registration(poll, token, events, opts);
+ self.readiness = Some(s);
+ *registration.lock().unwrap() = Some(r);
+ Ok(())
+ }
+
+ /// Implementation of `Evented::reregister` function.
+ pub fn reregister_socket(&mut self,
+ socket: &AsRawSocket,
+ poll: &Poll,
+ token: Token,
+ events: Ready,
+ opts: PollOpt,
+ registration: &Mutex<Option<poll::Registration>>)
+ -> io::Result<()> {
+ trace!("reregister {:?} {:?}", token, events);
+ unsafe {
+ try!(self.binding.reregister_socket(socket, token, poll));
+ }
+
+ registration.lock().unwrap()
+ .as_mut().unwrap()
+ .reregister(poll, token, events, opts)
+ }
+
+ /// Implementation of the `Evented::deregister` function.
+ ///
+ /// Doesn't allow registration with another event loop, just shuts down
+ /// readiness notifications and such.
+ pub fn deregister(&mut self,
+ socket: &AsRawSocket,
+ poll: &Poll,
+ registration: &Mutex<Option<poll::Registration>>)
+ -> io::Result<()> {
+ trace!("deregistering");
+ unsafe {
+ try!(self.binding.deregister_socket(socket, poll));
+ }
+
+ registration.lock().unwrap()
+ .as_ref().unwrap()
+ .deregister(poll)
+ }
+}
+
+fn other(s: &str) -> io::Error {
+ io::Error::new(io::ErrorKind::Other, s)
+}
+
+#[derive(Debug)]
+pub struct Events {
+ /// Raw I/O event completions are filled in here by the call to `get_many`
+ /// on the completion port above. These are then processed to run callbacks
+ /// which figure out what to do after the event is done.
+ statuses: Box<[CompletionStatus]>,
+
+ /// Literal events returned by `get` to the upwards `EventLoop`. This file
+ /// doesn't really modify this (except for the awakener), instead almost all
+ /// events are filled in by the `ReadinessQueue` from the `poll` module.
+ events: Vec<Event>,
+}
+
+impl Events {
+ pub fn with_capacity(cap: usize) -> Events {
+ // Note that it's possible for the output `events` to grow beyond the
+ // capacity as it can also include deferred events, but that's certainly
+ // not the end of the world!
+ Events {
+ statuses: vec![CompletionStatus::zero(); cap].into_boxed_slice(),
+ events: Vec::with_capacity(cap),
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.events.is_empty()
+ }
+
+ pub fn len(&self) -> usize {
+ self.events.len()
+ }
+
+ pub fn capacity(&self) -> usize {
+ self.events.capacity()
+ }
+
+ pub fn get(&self, idx: usize) -> Option<Event> {
+ self.events.get(idx).map(|e| *e)
+ }
+
+ pub fn push_event(&mut self, event: Event) {
+ self.events.push(event);
+ }
+}
+
+macro_rules! overlapped2arc {
+ ($e:expr, $t:ty, $($field:ident).+) => ({
+ let offset = offset_of!($t, $($field).+);
+ debug_assert!(offset < mem::size_of::<$t>());
+ FromRawArc::from_raw(($e as usize - offset) as *mut $t)
+ })
+}
+
+macro_rules! offset_of {
+ ($t:ty, $($field:ident).+) => (
+ &(*(0 as *const $t)).$($field).+ as *const _ as usize
+ )
+}
+
+// See sys::windows module docs for why this exists.
+//
+// The gist of it is that `Selector` assumes that all `OVERLAPPED` pointers are
+// actually inside one of these structures so it can use the `Callback` stored
+// right after it.
+//
+// We use repr(C) here to ensure that we can assume the overlapped pointer is
+// at the start of the structure so we can just do a cast.
+/// A wrapper around an internal instance over `miow::Overlapped` which is in
+/// turn a wrapper around the Windows type `OVERLAPPED`.
+///
+/// This type is required to be used for all IOCP operations on handles that are
+/// registered with an event loop. The event loop will receive notifications
+/// over `OVERLAPPED` pointers that have completed, and it will cast that
+/// pointer to a pointer to this structure and invoke the associated callback.
+#[repr(C)]
+pub struct Overlapped {
+ inner: UnsafeCell<miow::Overlapped>,
+ callback: fn(&OVERLAPPED_ENTRY),
+}
+
+impl Overlapped {
+ /// Creates a new `Overlapped` which will invoke the provided `cb` callback
+ /// whenever it's triggered.
+ ///
+ /// The returned `Overlapped` must be used as the `OVERLAPPED` passed to all
+ /// I/O operations that are registered with mio's event loop. When the I/O
+ /// operation associated with an `OVERLAPPED` pointer completes the event
+ /// loop will invoke the function pointer provided by `cb`.
+ pub fn new(cb: fn(&OVERLAPPED_ENTRY)) -> Overlapped {
+ Overlapped {
+ inner: UnsafeCell::new(miow::Overlapped::zero()),
+ callback: cb,
+ }
+ }
+
+ /// Get the underlying `Overlapped` instance as a raw pointer.
+ ///
+ /// This can be useful when only a shared borrow is held and the overlapped
+ /// pointer needs to be passed down to winapi.
+ pub fn as_mut_ptr(&self) -> *mut OVERLAPPED {
+ unsafe {
+ (*self.inner.get()).raw()
+ }
+ }
+}
+
+impl fmt::Debug for Overlapped {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Overlapped")
+ }
+}
+
+// Overlapped's APIs are marked as unsafe Overlapped's APIs are marked as
+// unsafe as they must be used with caution to ensure thread safety. The
+// structure itself is safe to send across threads.
+unsafe impl Send for Overlapped {}
+unsafe impl Sync for Overlapped {}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/windows/tcp.rs
@@ -0,0 +1,827 @@
+use std::fmt;
+use std::io::{self, Read, ErrorKind};
+use std::mem;
+use std::net::{self, SocketAddr, Shutdown};
+use std::os::windows::prelude::*;
+use std::sync::{Mutex, MutexGuard};
+use std::time::Duration;
+
+use miow::iocp::CompletionStatus;
+use miow::net::*;
+use net2::{TcpBuilder, TcpStreamExt as Net2TcpExt};
+use winapi::*;
+use iovec::IoVec;
+
+use {poll, Ready, Poll, PollOpt, Token};
+use event::Evented;
+use sys::windows::from_raw_arc::FromRawArc;
+use sys::windows::selector::{Overlapped, ReadyBinding};
+use sys::windows::{wouldblock, Family};
+
+pub struct TcpStream {
+ /// Separately stored implementation to ensure that the `Drop`
+ /// implementation on this type is only executed when it's actually dropped
+ /// (many clones of this `imp` are made).
+ imp: StreamImp,
+ registration: Mutex<Option<poll::Registration>>,
+}
+
+pub struct TcpListener {
+ imp: ListenerImp,
+ registration: Mutex<Option<poll::Registration>>,
+}
+
+#[derive(Clone)]
+struct StreamImp {
+ /// A stable address and synchronized access for all internals. This serves
+ /// to ensure that all `Overlapped` pointers are valid for a long period of
+ /// time as well as allowing completion callbacks to have access to the
+ /// internals without having ownership.
+ ///
+ /// Note that the reference count also allows us "loan out" copies to
+ /// completion ports while I/O is running to guarantee that this stays alive
+ /// until the I/O completes. You'll notice a number of calls to
+ /// `mem::forget` below, and these only happen on successful scheduling of
+ /// I/O and are paired with `overlapped2arc!` macro invocations in the
+ /// completion callbacks (to have a decrement match the increment).
+ inner: FromRawArc<StreamIo>,
+}
+
+#[derive(Clone)]
+struct ListenerImp {
+ inner: FromRawArc<ListenerIo>,
+}
+
+struct StreamIo {
+ inner: Mutex<StreamInner>,
+ read: Overlapped, // also used for connect
+ write: Overlapped,
+ socket: net::TcpStream,
+}
+
+struct ListenerIo {
+ inner: Mutex<ListenerInner>,
+ accept: Overlapped,
+ family: Family,
+ socket: net::TcpListener,
+}
+
+struct StreamInner {
+ iocp: ReadyBinding,
+ deferred_connect: Option<SocketAddr>,
+ read: State<(), ()>,
+ write: State<(Vec<u8>, usize), (Vec<u8>, usize)>,
+ /// whether we are instantly notified of success
+ /// (FILE_SKIP_COMPLETION_PORT_ON_SUCCESS,
+ /// without a roundtrip through the event loop)
+ instant_notify: bool,
+}
+
+struct ListenerInner {
+ iocp: ReadyBinding,
+ accept: State<net::TcpStream, (net::TcpStream, SocketAddr)>,
+ accept_buf: AcceptAddrsBuf,
+ instant_notify: bool,
+}
+
+enum State<T, U> {
+ Empty, // no I/O operation in progress
+ Pending(T), // an I/O operation is in progress
+ Ready(U), // I/O has finished with this value
+ Error(io::Error), // there was an I/O error
+}
+
+impl TcpStream {
+ fn new(socket: net::TcpStream,
+ deferred_connect: Option<SocketAddr>) -> TcpStream {
+ TcpStream {
+ registration: Mutex::new(None),
+ imp: StreamImp {
+ inner: FromRawArc::new(StreamIo {
+ read: Overlapped::new(read_done),
+ write: Overlapped::new(write_done),
+ socket: socket,
+ inner: Mutex::new(StreamInner {
+ iocp: ReadyBinding::new(),
+ deferred_connect: deferred_connect,
+ read: State::Empty,
+ write: State::Empty,
+ instant_notify: false,
+ }),
+ }),
+ },
+ }
+ }
+
+ pub fn connect(socket: net::TcpStream, addr: &SocketAddr)
+ -> io::Result<TcpStream> {
+ try!(socket.set_nonblocking(true));
+ Ok(TcpStream::new(socket, Some(*addr)))
+ }
+
+ pub fn from_stream(stream: net::TcpStream) -> TcpStream {
+ TcpStream::new(stream, None)
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ self.imp.inner.socket.peer_addr()
+ }
+
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.imp.inner.socket.local_addr()
+ }
+
+ pub fn try_clone(&self) -> io::Result<TcpStream> {
+ self.imp.inner.socket.try_clone().map(|s| TcpStream::new(s, None))
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.imp.inner.socket.shutdown(how)
+ }
+
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ self.imp.inner.socket.set_nodelay(nodelay)
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ self.imp.inner.socket.nodelay()
+ }
+
+ pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
+ self.imp.inner.socket.set_recv_buffer_size(size)
+ }
+
+ pub fn recv_buffer_size(&self) -> io::Result<usize> {
+ self.imp.inner.socket.recv_buffer_size()
+ }
+
+ pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
+ self.imp.inner.socket.set_send_buffer_size(size)
+ }
+
+ pub fn send_buffer_size(&self) -> io::Result<usize> {
+ self.imp.inner.socket.send_buffer_size()
+ }
+
+ pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
+ self.imp.inner.socket.set_keepalive(keepalive)
+ }
+
+ pub fn keepalive(&self) -> io::Result<Option<Duration>> {
+ self.imp.inner.socket.keepalive()
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.imp.inner.socket.set_ttl(ttl)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.imp.inner.socket.ttl()
+ }
+
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ self.imp.inner.socket.set_only_v6(only_v6)
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ self.imp.inner.socket.only_v6()
+ }
+
+ pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.imp.inner.socket.set_linger(dur)
+ }
+
+ pub fn linger(&self) -> io::Result<Option<Duration>> {
+ self.imp.inner.socket.linger()
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ if let Some(e) = try!(self.imp.inner.socket.take_error()) {
+ return Ok(Some(e))
+ }
+
+ // If the syscall didn't return anything then also check to see if we've
+ // squirreled away an error elsewhere for example as part of a connect
+ // operation.
+ //
+ // Typically this is used like so:
+ //
+ // 1. A `connect` is issued
+ // 2. Wait for the socket to be writable
+ // 3. Call `take_error` to see if the connect succeeded.
+ //
+ // Right now the `connect` operation finishes in `read_done` below and
+ // fill will in `State::Error` in the `read` slot if it fails, so we
+ // extract that here.
+ let mut me = self.inner();
+ match mem::replace(&mut me.read, State::Empty) {
+ State::Error(e) => {
+ self.imp.schedule_read(&mut me);
+ Ok(Some(e))
+ }
+ other => {
+ me.read = other;
+ Ok(None)
+ }
+ }
+ }
+
+ fn inner(&self) -> MutexGuard<StreamInner> {
+ self.imp.inner()
+ }
+
+ fn post_register(&self, interest: Ready, me: &mut StreamInner) {
+ if interest.is_readable() {
+ self.imp.schedule_read(me);
+ }
+
+ // At least with epoll, if a socket is registered with an interest in
+ // writing and it's immediately writable then a writable event is
+ // generated immediately, so do so here.
+ if interest.is_writable() {
+ if let State::Empty = me.write {
+ self.imp.add_readiness(me, Ready::writable());
+ }
+ }
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.readv(&mut [buf.into()])
+ }
+
+ pub fn readv(&self, bufs: &mut [&mut IoVec]) -> io::Result<usize> {
+ let mut me = self.inner();
+
+ match me.read {
+ // Empty == we're not associated yet, and if we're pending then
+ // these are both cases where we return "would block"
+ State::Empty |
+ State::Pending(()) => return Err(wouldblock()),
+
+ // If we got a delayed error as part of a `read_overlapped` below,
+ // return that here. Also schedule another read in case it was
+ // transient.
+ State::Error(_) => {
+ let e = match mem::replace(&mut me.read, State::Empty) {
+ State::Error(e) => e,
+ _ => panic!(),
+ };
+ self.imp.schedule_read(&mut me);
+ return Err(e)
+ }
+
+ // If we're ready for a read then some previous 0-byte read has
+ // completed. In that case the OS's socket buffer has something for
+ // us, so we just keep pulling out bytes while we can in the loop
+ // below.
+ State::Ready(()) => {}
+ }
+
+ // TODO: Does WSARecv work on a nonblocking sockets? We ideally want to
+ // call that instead of looping over all the buffers and calling
+ // `recv` on each buffer. I'm not sure though if an overlapped
+ // socket in nonblocking mode would work with that use case,
+ // however, so for now we just call `recv`.
+
+ let mut amt = 0;
+ for buf in bufs {
+ match (&self.imp.inner.socket).read(buf) {
+ // If we did a partial read, then return what we've read so far
+ Ok(n) if n < buf.len() => return Ok(amt + n),
+
+ // Otherwise filled this buffer entirely, so try to fill the
+ // next one as well.
+ Ok(n) => amt += n,
+
+ // If we hit an error then things get tricky if we've already
+ // read some data. If the error is "would block" then we just
+ // return the data we've read so far while scheduling another
+ // 0-byte read.
+ //
+ // If we've read data and the error kind is not "would block",
+ // then we stash away the error to get returned later and return
+ // the data that we've read.
+ //
+ // Finally if we haven't actually read any data we just
+ // reschedule a 0-byte read to happen again and then return the
+ // error upwards.
+ Err(e) => {
+ if amt > 0 && e.kind() == io::ErrorKind::WouldBlock {
+ me.read = State::Empty;
+ self.imp.schedule_read(&mut me);
+ return Ok(amt)
+ } else if amt > 0 {
+ me.read = State::Error(e);
+ return Ok(amt)
+ } else {
+ me.read = State::Empty;
+ self.imp.schedule_read(&mut me);
+ return Err(e)
+ }
+ }
+ }
+ }
+
+ Ok(amt)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.writev(&[buf.into()])
+ }
+
+ pub fn writev(&self, bufs: &[&IoVec]) -> io::Result<usize> {
+ let mut me = self.inner();
+ let me = &mut *me;
+
+ match me.write {
+ State::Empty => {}
+ _ => return Err(wouldblock())
+ }
+
+ if !me.iocp.registered() {
+ return Err(wouldblock())
+ }
+
+ if bufs.len() == 0 {
+ return Ok(0)
+ }
+
+ let len = bufs.iter().map(|b| b.len()).fold(0, |a, b| a + b);
+ let mut intermediate = me.iocp.get_buffer(len);
+ for buf in bufs {
+ intermediate.extend_from_slice(buf);
+ }
+ self.imp.schedule_write(intermediate, 0, me);
+ Ok(len)
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl StreamImp {
+ fn inner(&self) -> MutexGuard<StreamInner> {
+ self.inner.inner.lock().unwrap()
+ }
+
+ fn schedule_connect(&self, addr: &SocketAddr) -> io::Result<()> {
+ unsafe {
+ trace!("scheduling a connect");
+ try!(self.inner.socket.connect_overlapped(addr, &[], self.inner.read.as_mut_ptr()));
+ }
+ // see docs above on StreamImp.inner for rationale on forget
+ mem::forget(self.clone());
+ Ok(())
+ }
+
+ /// Schedule a read to happen on this socket, enqueuing us to receive a
+ /// notification when a read is ready.
+ ///
+ /// Note that this does *not* work with a buffer. When reading a TCP stream
+ /// we actually read into a 0-byte buffer so Windows will send us a
+ /// notification when the socket is otherwise ready for reading. This allows
+ /// us to avoid buffer allocations for in-flight reads.
+ fn schedule_read(&self, me: &mut StreamInner) {
+ match me.read {
+ State::Empty => {}
+ State::Ready(_) | State::Error(_) => {
+ self.add_readiness(me, Ready::readable());
+ return;
+ }
+ _ => return,
+ }
+
+ me.iocp.set_readiness(me.iocp.readiness() & !Ready::readable());
+
+ trace!("scheduling a read");
+ let res = unsafe {
+ self.inner.socket.read_overlapped(&mut [], self.inner.read.as_mut_ptr())
+ };
+ match res {
+ // Note that `Ok(true)` means that this completed immediately and
+ // our socket is readable. This typically means that the caller of
+ // this function (likely `read` above) can try again as an
+ // optimization and return bytes quickly.
+ //
+ // Normally, though, although the read completed immediately
+ // there's still an IOCP completion packet enqueued that we're going
+ // to receive.
+ //
+ // You can configure this behavior (miow) with
+ // SetFileCompletionNotificationModes to indicate that `Ok(true)`
+ // does **not** enqueue a completion packet. (This is the case
+ // for me.instant_notify)
+ //
+ // Note that apparently libuv has scary code to work around bugs in
+ // `WSARecv` for UDP sockets apparently for handles which have had
+ // the `SetFileCompletionNotificationModes` function called on them,
+ // worth looking into!
+ Ok(Some(_)) if me.instant_notify => {
+ me.read = State::Ready(());
+ self.add_readiness(me, Ready::readable());
+ }
+ Ok(_) => {
+ // see docs above on StreamImp.inner for rationale on forget
+ me.read = State::Pending(());
+ mem::forget(self.clone());
+ }
+ Err(e) => {
+ me.read = State::Error(e);
+ self.add_readiness(me, Ready::readable());
+ }
+ }
+ }
+
+ /// Similar to `schedule_read`, except that this issues, well, writes.
+ ///
+ /// This function will continually attempt to write the entire contents of
+ /// the buffer `buf` until they have all been written. The `pos` argument is
+ /// the current offset within the buffer up to which the contents have
+ /// already been written.
+ ///
+ /// A new writable event (e.g. allowing another write) will only happen once
+ /// the buffer has been written completely (or hit an error).
+ fn schedule_write(&self,
+ buf: Vec<u8>,
+ mut pos: usize,
+ me: &mut StreamInner) {
+
+ // About to write, clear any pending level triggered events
+ me.iocp.set_readiness(me.iocp.readiness() & !Ready::writable());
+
+ trace!("scheduling a write");
+ loop {
+ let ret = unsafe {
+ self.inner.socket.write_overlapped(&buf[pos..], self.inner.write.as_mut_ptr())
+ };
+ match ret {
+ Ok(Some(transferred_bytes)) if me.instant_notify => {
+ if transferred_bytes == buf.len() - pos {
+ self.add_readiness(me, Ready::writable());
+ me.write = State::Empty;
+ break;
+ }
+ pos += transferred_bytes;
+ }
+ Ok(_) => {
+ // see docs above on StreamImp.inner for rationale on forget
+ me.write = State::Pending((buf, pos));
+ mem::forget(self.clone());
+ break;
+ }
+ Err(e) => {
+ me.write = State::Error(e);
+ self.add_readiness(me, Ready::writable());
+ me.iocp.put_buffer(buf);
+ break;
+ }
+ }
+ }
+ }
+
+ /// Pushes an event for this socket onto the selector its registered for.
+ ///
+ /// When an event is generated on this socket, if it happened after the
+ /// socket was closed then we don't want to actually push the event onto our
+ /// selector as otherwise it's just a spurious notification.
+ fn add_readiness(&self, me: &mut StreamInner, set: Ready) {
+ me.iocp.set_readiness(set | me.iocp.readiness());
+ }
+}
+
+fn read_done(status: &OVERLAPPED_ENTRY) {
+ let status = CompletionStatus::from_entry(status);
+ let me2 = StreamImp {
+ inner: unsafe { overlapped2arc!(status.overlapped(), StreamIo, read) },
+ };
+
+ let mut me = me2.inner();
+ match mem::replace(&mut me.read, State::Empty) {
+ State::Pending(()) => {
+ trace!("finished a read: {}", status.bytes_transferred());
+ assert_eq!(status.bytes_transferred(), 0);
+ me.read = State::Ready(());
+ return me2.add_readiness(&mut me, Ready::readable())
+ }
+ s => me.read = s,
+ }
+
+ // If a read didn't complete, then the connect must have just finished.
+ trace!("finished a connect");
+
+ // By guarding with socket.result(), we ensure that a connection
+ // was successfully made before performing operations requiring a
+ // connected socket.
+ match unsafe { me2.inner.socket.result(status.overlapped()) }
+ .and_then(|_| me2.inner.socket.connect_complete())
+ {
+ Ok(()) => {
+ me2.add_readiness(&mut me, Ready::writable());
+ me2.schedule_read(&mut me);
+ }
+ Err(e) => {
+ me2.add_readiness(&mut me, Ready::readable() | Ready::writable());
+ me.read = State::Error(e);
+ }
+ }
+}
+
+fn write_done(status: &OVERLAPPED_ENTRY) {
+ let status = CompletionStatus::from_entry(status);
+ trace!("finished a write {}", status.bytes_transferred());
+ let me2 = StreamImp {
+ inner: unsafe { overlapped2arc!(status.overlapped(), StreamIo, write) },
+ };
+ let mut me = me2.inner();
+ let (buf, pos) = match mem::replace(&mut me.write, State::Empty) {
+ State::Pending(pair) => pair,
+ _ => unreachable!(),
+ };
+ let new_pos = pos + (status.bytes_transferred() as usize);
+ if new_pos == buf.len() {
+ me2.add_readiness(&mut me, Ready::writable());
+ } else {
+ me2.schedule_write(buf, new_pos, &mut me);
+ }
+}
+
+impl Evented for TcpStream {
+ fn register(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ let mut me = self.inner();
+ try!(me.iocp.register_socket(&self.imp.inner.socket, poll, token,
+ interest, opts, &self.registration));
+
+ unsafe {
+ try!(super::no_notify_on_instant_completion(self.imp.inner.socket.as_raw_socket() as HANDLE));
+ me.instant_notify = true;
+ }
+
+ // If we were connected before being registered process that request
+ // here and go along our merry ways. Note that the callback for a
+ // successful connect will worry about generating writable/readable
+ // events and scheduling a new read.
+ if let Some(addr) = me.deferred_connect.take() {
+ return self.imp.schedule_connect(&addr).map(|_| ())
+ }
+ self.post_register(interest, &mut me);
+ Ok(())
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ let mut me = self.inner();
+ try!(me.iocp.reregister_socket(&self.imp.inner.socket, poll, token,
+ interest, opts, &self.registration));
+ self.post_register(interest, &mut me);
+ Ok(())
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.inner().iocp.deregister(&self.imp.inner.socket,
+ poll, &self.registration)
+ }
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ "TcpStream { ... }".fmt(f)
+ }
+}
+
+impl Drop for TcpStream {
+ fn drop(&mut self) {
+ // If we're still internally reading, we're no longer interested. Note
+ // though that we don't cancel any writes which may have been issued to
+ // preserve the same semantics as Unix.
+ //
+ // Note that "Empty" here may mean that a connect is pending, so we
+ // cancel even if that happens as well.
+ unsafe {
+ match self.inner().read {
+ State::Pending(_) | State::Empty => {
+ trace!("cancelling active TCP read");
+ drop(super::cancel(&self.imp.inner.socket,
+ &self.imp.inner.read));
+ }
+ State::Ready(_) | State::Error(_) => {}
+ }
+ }
+ }
+}
+
+impl TcpListener {
+ pub fn new(socket: net::TcpListener, addr: &SocketAddr)
+ -> io::Result<TcpListener> {
+ Ok(TcpListener::new_family(socket, match *addr {
+ SocketAddr::V4(..) => Family::V4,
+ SocketAddr::V6(..) => Family::V6,
+ }))
+ }
+
+ fn new_family(socket: net::TcpListener, family: Family) -> TcpListener {
+ TcpListener {
+ registration: Mutex::new(None),
+ imp: ListenerImp {
+ inner: FromRawArc::new(ListenerIo {
+ accept: Overlapped::new(accept_done),
+ family: family,
+ socket: socket,
+ inner: Mutex::new(ListenerInner {
+ iocp: ReadyBinding::new(),
+ accept: State::Empty,
+ accept_buf: AcceptAddrsBuf::new(),
+ instant_notify: false,
+ }),
+ }),
+ },
+ }
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ let mut me = self.inner();
+
+ let ret = match mem::replace(&mut me.accept, State::Empty) {
+ State::Empty => return Err(would_block()),
+ State::Pending(t) => {
+ me.accept = State::Pending(t);
+ return Err(would_block());
+ }
+ State::Ready((s, a)) => {
+ try!(s.set_nonblocking(true));
+ Ok((TcpStream::new(s, None), a))
+ }
+ State::Error(e) => Err(e),
+ };
+
+ self.imp.schedule_accept(&mut me);
+
+ return ret
+ }
+
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.imp.inner.socket.local_addr()
+ }
+
+ pub fn try_clone(&self) -> io::Result<TcpListener> {
+ self.imp.inner.socket.try_clone().map(|s| {
+ TcpListener::new_family(s, self.imp.inner.family)
+ })
+ }
+
+ #[allow(deprecated)]
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ self.imp.inner.socket.set_only_v6(only_v6)
+ }
+
+ #[allow(deprecated)]
+ pub fn only_v6(&self) -> io::Result<bool> {
+ self.imp.inner.socket.only_v6()
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.imp.inner.socket.set_ttl(ttl)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.imp.inner.socket.ttl()
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.imp.inner.socket.take_error()
+ }
+
+ fn inner(&self) -> MutexGuard<ListenerInner> {
+ self.imp.inner()
+ }
+}
+
+impl ListenerImp {
+ fn inner(&self) -> MutexGuard<ListenerInner> {
+ self.inner.inner.lock().unwrap()
+ }
+
+ fn schedule_accept(&self, me: &mut ListenerInner) {
+ match me.accept {
+ State::Empty => {}
+ _ => return
+ }
+
+ me.iocp.set_readiness(me.iocp.readiness() & !Ready::readable());
+
+ let res = match self.inner.family {
+ Family::V4 => TcpBuilder::new_v4(),
+ Family::V6 => TcpBuilder::new_v6(),
+ }.and_then(|builder| unsafe {
+ trace!("scheduling an accept");
+ self.inner.socket.accept_overlapped(&builder, &mut me.accept_buf,
+ self.inner.accept.as_mut_ptr())
+ });
+ match res {
+ Ok((socket, _)) => {
+ // see docs above on StreamImp.inner for rationale on forget
+ me.accept = State::Pending(socket);
+ mem::forget(self.clone());
+ }
+ Err(e) => {
+ me.accept = State::Error(e);
+ self.add_readiness(me, Ready::readable());
+ }
+ }
+ }
+
+ // See comments in StreamImp::push
+ fn add_readiness(&self, me: &mut ListenerInner, set: Ready) {
+ me.iocp.set_readiness(set | me.iocp.readiness());
+ }
+}
+
+fn accept_done(status: &OVERLAPPED_ENTRY) {
+ let status = CompletionStatus::from_entry(status);
+ let me2 = ListenerImp {
+ inner: unsafe { overlapped2arc!(status.overlapped(), ListenerIo, accept) },
+ };
+
+ let mut me = me2.inner();
+ let socket = match mem::replace(&mut me.accept, State::Empty) {
+ State::Pending(s) => s,
+ _ => unreachable!(),
+ };
+ trace!("finished an accept");
+ let result = me2.inner.socket.accept_complete(&socket).and_then(|()| {
+ me.accept_buf.parse(&me2.inner.socket)
+ }).and_then(|buf| {
+ buf.remote().ok_or_else(|| {
+ io::Error::new(ErrorKind::Other, "could not obtain remote address")
+ })
+ });
+ me.accept = match result {
+ Ok(remote_addr) => State::Ready((socket, remote_addr)),
+ Err(e) => State::Error(e),
+ };
+ me2.add_readiness(&mut me, Ready::readable());
+}
+
+impl Evented for TcpListener {
+ fn register(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ let mut me = self.inner();
+ try!(me.iocp.register_socket(&self.imp.inner.socket, poll, token,
+ interest, opts, &self.registration));
+
+ unsafe {
+ try!(super::no_notify_on_instant_completion(self.imp.inner.socket.as_raw_socket() as HANDLE));
+ me.instant_notify = true;
+ }
+
+ self.imp.schedule_accept(&mut me);
+ Ok(())
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ let mut me = self.inner();
+ try!(me.iocp.reregister_socket(&self.imp.inner.socket, poll, token,
+ interest, opts, &self.registration));
+ self.imp.schedule_accept(&mut me);
+ Ok(())
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.inner().iocp.deregister(&self.imp.inner.socket,
+ poll, &self.registration)
+ }
+}
+
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ "TcpListener { ... }".fmt(f)
+ }
+}
+
+impl Drop for TcpListener {
+ fn drop(&mut self) {
+ // If we're still internally reading, we're no longer interested.
+ unsafe {
+ match self.inner().accept {
+ State::Pending(_) => {
+ trace!("cancelling active TCP accept");
+ drop(super::cancel(&self.imp.inner.socket,
+ &self.imp.inner.accept));
+ }
+ State::Empty |
+ State::Ready(_) |
+ State::Error(_) => {}
+ }
+ }
+ }
+}
+
+// TODO: Use std's allocation free io::Error
+const WOULDBLOCK: i32 = ::winapi::winerror::WSAEWOULDBLOCK as i32;
+
+/// Returns a std `WouldBlock` error without allocating
+pub fn would_block() -> ::std::io::Error {
+ ::std::io::Error::from_raw_os_error(WOULDBLOCK)
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/sys/windows/udp.rs
@@ -0,0 +1,412 @@
+//! UDP for IOCP
+//!
+//! Note that most of this module is quite similar to the TCP module, so if
+//! something seems odd you may also want to try the docs over there.
+
+use std::fmt;
+use std::io::prelude::*;
+use std::io;
+use std::mem;
+use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr};
+use std::sync::{Mutex, MutexGuard};
+
+#[allow(unused_imports)]
+use net2::{UdpBuilder, UdpSocketExt};
+use winapi::*;
+use miow::iocp::CompletionStatus;
+use miow::net::SocketAddrBuf;
+use miow::net::UdpSocketExt as MiowUdpSocketExt;
+
+use {poll, Ready, Poll, PollOpt, Token};
+use event::Evented;
+use sys::windows::from_raw_arc::FromRawArc;
+use sys::windows::selector::{Overlapped, ReadyBinding};
+
+pub struct UdpSocket {
+ imp: Imp,
+ registration: Mutex<Option<poll::Registration>>,
+}
+
+#[derive(Clone)]
+struct Imp {
+ inner: FromRawArc<Io>,
+}
+
+struct Io {
+ read: Overlapped,
+ write: Overlapped,
+ socket: net::UdpSocket,
+ inner: Mutex<Inner>,
+}
+
+struct Inner {
+ iocp: ReadyBinding,
+ read: State<Vec<u8>, Vec<u8>>,
+ write: State<Vec<u8>, (Vec<u8>, usize)>,
+ read_buf: SocketAddrBuf,
+}
+
+enum State<T, U> {
+ Empty,
+ Pending(T),
+ Ready(U),
+ Error(io::Error),
+}
+
+impl UdpSocket {
+ pub fn new(socket: net::UdpSocket) -> io::Result<UdpSocket> {
+ Ok(UdpSocket {
+ registration: Mutex::new(None),
+ imp: Imp {
+ inner: FromRawArc::new(Io {
+ read: Overlapped::new(recv_done),
+ write: Overlapped::new(send_done),
+ socket: socket,
+ inner: Mutex::new(Inner {
+ iocp: ReadyBinding::new(),
+ read: State::Empty,
+ write: State::Empty,
+ read_buf: SocketAddrBuf::new(),
+ }),
+ }),
+ },
+ })
+ }
+
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.imp.inner.socket.local_addr()
+ }
+
+ pub fn try_clone(&self) -> io::Result<UdpSocket> {
+ self.imp.inner.socket.try_clone().and_then(UdpSocket::new)
+ }
+
+ /// Note that unlike `TcpStream::write` this function will not attempt to
+ /// continue writing `buf` until its entirely written.
+ ///
+ /// TODO: This... may be wrong in the long run. We're reporting that we
+ /// successfully wrote all of the bytes in `buf` but it's possible
+ /// that we don't actually end up writing all of them!
+ pub fn send_to(&self, buf: &[u8], target: &SocketAddr)
+ -> io::Result<usize> {
+ let mut me = self.inner();
+ let me = &mut *me;
+
+ match me.write {
+ State::Empty => {}
+ _ => return Err(would_block()),
+ }
+
+ if !me.iocp.registered() {
+ return Err(would_block())
+ }
+
+ let interest = me.iocp.readiness();
+ me.iocp.set_readiness(interest & !Ready::writable());
+
+ let mut owned_buf = me.iocp.get_buffer(64 * 1024);
+ let amt = try!(owned_buf.write(buf));
+ try!(unsafe {
+ trace!("scheduling a send");
+ self.imp.inner.socket.send_to_overlapped(&owned_buf, target,
+ self.imp.inner.write.as_mut_ptr())
+ });
+ me.write = State::Pending(owned_buf);
+ mem::forget(self.imp.clone());
+ Ok(amt)
+ }
+
+ /// Note that unlike `TcpStream::write` this function will not attempt to
+ /// continue writing `buf` until its entirely written.
+ ///
+ /// TODO: This... may be wrong in the long run. We're reporting that we
+ /// successfully wrote all of the bytes in `buf` but it's possible
+ /// that we don't actually end up writing all of them!
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ let mut me = self.inner();
+ let me = &mut *me;
+
+ match me.write {
+ State::Empty => {}
+ _ => return Err(would_block()),
+ }
+
+ if !me.iocp.registered() {
+ return Err(would_block())
+ }
+
+ let interest = me.iocp.readiness();
+ me.iocp.set_readiness(interest & !Ready::writable());
+
+ let mut owned_buf = me.iocp.get_buffer(64 * 1024);
+ let amt = try!(owned_buf.write(buf));
+ try!(unsafe {
+ trace!("scheduling a send");
+ self.imp.inner.socket.send_overlapped(&owned_buf, self.imp.inner.write.as_mut_ptr())
+
+ });
+ me.write = State::Pending(owned_buf);
+ mem::forget(self.imp.clone());
+ Ok(amt)
+ }
+
+ pub fn recv_from(&self, mut buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ let mut me = self.inner();
+ match mem::replace(&mut me.read, State::Empty) {
+ State::Empty => Err(would_block()),
+ State::Pending(b) => { me.read = State::Pending(b); Err(would_block()) }
+ State::Ready(data) => {
+ // If we weren't provided enough space to receive the message
+ // then don't actually read any data, just return an error.
+ if buf.len() < data.len() {
+ me.read = State::Ready(data);
+ Err(io::Error::from_raw_os_error(WSAEMSGSIZE as i32))
+ } else {
+ let r = if let Some(addr) = me.read_buf.to_socket_addr() {
+ buf.write(&data).unwrap();
+ Ok((data.len(), addr))
+ } else {
+ Err(io::Error::new(io::ErrorKind::Other,
+ "failed to parse socket address"))
+ };
+ me.iocp.put_buffer(data);
+ self.imp.schedule_read_from(&mut me);
+ r
+ }
+ }
+ State::Error(e) => {
+ self.imp.schedule_read_from(&mut me);
+ Err(e)
+ }
+ }
+ }
+
+ pub fn recv(&self, mut buf: &mut [u8])
+ -> io::Result<usize> {
+ //Since recv_from can be used on connected sockets just call it and drop the address.
+ self.recv_from(buf).map(|(size,_)| size)
+ }
+
+ pub fn connect(&self, addr: SocketAddr) -> io::Result<()> {
+ self.imp.inner.socket.connect(addr)
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ self.imp.inner.socket.broadcast()
+ }
+
+ pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
+ self.imp.inner.socket.set_broadcast(on)
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ self.imp.inner.socket.multicast_loop_v4()
+ }
+
+ pub fn set_multicast_loop_v4(&self, on: bool) -> io::Result<()> {
+ self.imp.inner.socket.set_multicast_loop_v4(on)
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ self.imp.inner.socket.multicast_ttl_v4()
+ }
+
+ pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
+ self.imp.inner.socket.set_multicast_ttl_v4(ttl)
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ self.imp.inner.socket.multicast_loop_v6()
+ }
+
+ pub fn set_multicast_loop_v6(&self, on: bool) -> io::Result<()> {
+ self.imp.inner.socket.set_multicast_loop_v6(on)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.imp.inner.socket.ttl()
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.imp.inner.socket.set_ttl(ttl)
+ }
+
+ pub fn join_multicast_v4(&self,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr) -> io::Result<()> {
+ self.imp.inner.socket.join_multicast_v4(multiaddr, interface)
+ }
+
+ pub fn join_multicast_v6(&self,
+ multiaddr: &Ipv6Addr,
+ interface: u32) -> io::Result<()> {
+ self.imp.inner.socket.join_multicast_v6(multiaddr, interface)
+ }
+
+ pub fn leave_multicast_v4(&self,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr) -> io::Result<()> {
+ self.imp.inner.socket.leave_multicast_v4(multiaddr, interface)
+ }
+
+ pub fn leave_multicast_v6(&self,
+ multiaddr: &Ipv6Addr,
+ interface: u32) -> io::Result<()> {
+ self.imp.inner.socket.leave_multicast_v6(multiaddr, interface)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.imp.inner.socket.take_error()
+ }
+
+ fn inner(&self) -> MutexGuard<Inner> {
+ self.imp.inner()
+ }
+
+ fn post_register(&self, interest: Ready, me: &mut Inner) {
+ if interest.is_readable() {
+ //We use recv_from here since it is well specified for both
+ //connected and non-connected sockets and we can discard the address
+ //when calling recv().
+ self.imp.schedule_read_from(me);
+ }
+ // See comments in TcpSocket::post_register for what's going on here
+ if interest.is_writable() {
+ if let State::Empty = me.write {
+ self.imp.add_readiness(me, Ready::writable());
+ }
+ }
+ }
+}
+
+impl Imp {
+ fn inner(&self) -> MutexGuard<Inner> {
+ self.inner.inner.lock().unwrap()
+ }
+
+ fn schedule_read_from(&self, me: &mut Inner) {
+ match me.read {
+ State::Empty => {}
+ _ => return,
+ }
+
+ let interest = me.iocp.readiness();
+ me.iocp.set_readiness(interest & !Ready::readable());
+
+ let mut buf = me.iocp.get_buffer(64 * 1024);
+ let res = unsafe {
+ trace!("scheduling a read");
+ let cap = buf.capacity();
+ buf.set_len(cap);
+ self.inner.socket.recv_from_overlapped(&mut buf, &mut me.read_buf,
+ self.inner.read.as_mut_ptr())
+ };
+ match res {
+ Ok(_) => {
+ me.read = State::Pending(buf);
+ mem::forget(self.clone());
+ }
+ Err(e) => {
+ me.read = State::Error(e);
+ self.add_readiness(me, Ready::readable());
+ me.iocp.put_buffer(buf);
+ }
+ }
+ }
+
+ // See comments in tcp::StreamImp::push
+ fn add_readiness(&self, me: &Inner, set: Ready) {
+ me.iocp.set_readiness(set | me.iocp.readiness());
+ }
+}
+
+impl Evented for UdpSocket {
+ fn register(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ let mut me = self.inner();
+ try!(me.iocp.register_socket(&self.imp.inner.socket,
+ poll, token, interest, opts,
+ &self.registration));
+ self.post_register(interest, &mut me);
+ Ok(())
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token,
+ interest: Ready, opts: PollOpt) -> io::Result<()> {
+ let mut me = self.inner();
+ try!(me.iocp.reregister_socket(&self.imp.inner.socket,
+ poll, token, interest,
+ opts, &self.registration));
+ self.post_register(interest, &mut me);
+ Ok(())
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.inner().iocp.deregister(&self.imp.inner.socket,
+ poll, &self.registration)
+ }
+}
+
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ "UdpSocket { ... }".fmt(f)
+ }
+}
+
+impl Drop for UdpSocket {
+ fn drop(&mut self) {
+ let inner = self.inner();
+
+ // If we're still internally reading, we're no longer interested. Note
+ // though that we don't cancel any writes which may have been issued to
+ // preserve the same semantics as Unix.
+ unsafe {
+ match inner.read {
+ State::Pending(_) => {
+ drop(super::cancel(&self.imp.inner.socket,
+ &self.imp.inner.read));
+ }
+ State::Empty |
+ State::Ready(_) |
+ State::Error(_) => {}
+ }
+ }
+ }
+}
+
+fn send_done(status: &OVERLAPPED_ENTRY) {
+ let status = CompletionStatus::from_entry(status);
+ trace!("finished a send {}", status.bytes_transferred());
+ let me2 = Imp {
+ inner: unsafe { overlapped2arc!(status.overlapped(), Io, write) },
+ };
+ let mut me = me2.inner();
+ me.write = State::Empty;
+ me2.add_readiness(&mut me, Ready::writable());
+}
+
+fn recv_done(status: &OVERLAPPED_ENTRY) {
+ let status = CompletionStatus::from_entry(status);
+ trace!("finished a recv {}", status.bytes_transferred());
+ let me2 = Imp {
+ inner: unsafe { overlapped2arc!(status.overlapped(), Io, read) },
+ };
+ let mut me = me2.inner();
+ let mut buf = match mem::replace(&mut me.read, State::Empty) {
+ State::Pending(buf) => buf,
+ _ => unreachable!(),
+ };
+ unsafe {
+ buf.set_len(status.bytes_transferred() as usize);
+ }
+ me.read = State::Ready(buf);
+ me2.add_readiness(&mut me, Ready::readable());
+}
+
+// TODO: Use std's allocation free io::Error
+const WOULDBLOCK: i32 = ::winapi::winerror::WSAEWOULDBLOCK as i32;
+
+/// Returns a std `WouldBlock` error without allocating
+pub fn would_block() -> ::std::io::Error {
+ ::std::io::Error::from_raw_os_error(WOULDBLOCK)
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/timer.rs
@@ -0,0 +1,526 @@
+//! Timer optimized for I/O related operations
+
+#![allow(deprecated, missing_debug_implementations)]
+
+use {convert, io, Evented, Ready, Poll, PollOpt, Registration, SetReadiness, Token};
+use lazycell::LazyCell;
+use std::{cmp, error, fmt, u64, usize, iter, thread};
+use std::sync::Arc;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::time::{Duration, Instant};
+
+use self::TimerErrorKind::TimerOverflow;
+
+pub struct Timer<T> {
+ // Size of each tick in milliseconds
+ tick_ms: u64,
+ // Slab of timeout entries
+ entries: Slab<Entry<T>>,
+ // Timeout wheel. Each tick, the timer will look at the next slot for
+ // timeouts that match the current tick.
+ wheel: Vec<WheelEntry>,
+ // Tick 0's time instant
+ start: Instant,
+ // The current tick
+ tick: Tick,
+ // The next entry to possibly timeout
+ next: Token,
+ // Masks the target tick to get the slot
+ mask: u64,
+ // Set on registration with Poll
+ inner: LazyCell<Inner>,
+}
+
+pub struct Builder {
+ // Approximate duration of each tick
+ tick: Duration,
+ // Number of slots in the timer wheel
+ num_slots: usize,
+ // Max number of timeouts that can be in flight at a given time.
+ capacity: usize,
+}
+
+#[derive(Clone, Debug)]
+pub struct Timeout {
+ // Reference into the timer entry slab
+ token: Token,
+ // Tick that it should match up with
+ tick: u64,
+}
+
+struct Inner {
+ registration: Registration,
+ set_readiness: SetReadiness,
+ wakeup_state: WakeupState,
+ wakeup_thread: thread::JoinHandle<()>,
+}
+
+impl Drop for Inner {
+ fn drop(&mut self) {
+ // 1. Set wakeup state to TERMINATE_THREAD (https://github.com/carllerche/mio/blob/master/src/timer.rs#L451)
+ self.wakeup_state.store(TERMINATE_THREAD, Ordering::Release);
+ // 2. Wake him up
+ self.wakeup_thread.thread().unpark();
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+struct WheelEntry {
+ next_tick: Tick,
+ head: Token,
+}
+
+// Doubly linked list of timer entries. Allows for efficient insertion /
+// removal of timeouts.
+struct Entry<T> {
+ state: T,
+ links: EntryLinks,
+}
+
+#[derive(Copy, Clone)]
+struct EntryLinks {
+ tick: Tick,
+ prev: Token,
+ next: Token
+}
+
+type Tick = u64;
+
+const TICK_MAX: Tick = u64::MAX;
+
+// Manages communication with wakeup thread
+type WakeupState = Arc<AtomicUsize>;
+
+type Slab<T> = ::slab::Slab<T, ::Token>;
+
+pub type Result<T> = ::std::result::Result<T, TimerError>;
+// TODO: remove
+pub type TimerResult<T> = Result<T>;
+
+
+#[derive(Debug)]
+pub struct TimerError {
+ kind: TimerErrorKind,
+ desc: &'static str,
+}
+
+#[derive(Debug)]
+pub enum TimerErrorKind {
+ TimerOverflow,
+}
+
+// TODO: Remove
+pub type OldTimerResult<T> = Result<T>;
+
+const TERMINATE_THREAD: usize = 0;
+const EMPTY: Token = Token(usize::MAX);
+
+impl Builder {
+ pub fn tick_duration(mut self, duration: Duration) -> Builder {
+ self.tick = duration;
+ self
+ }
+
+ pub fn num_slots(mut self, num_slots: usize) -> Builder {
+ self.num_slots = num_slots;
+ self
+ }
+
+ pub fn capacity(mut self, capacity: usize) -> Builder {
+ self.capacity = capacity;
+ self
+ }
+
+ pub fn build<T>(self) -> Timer<T> {
+ Timer::new(convert::millis(self.tick), self.num_slots, self.capacity, Instant::now())
+ }
+}
+
+impl Default for Builder {
+ fn default() -> Builder {
+ Builder {
+ tick: Duration::from_millis(100),
+ num_slots: 256,
+ capacity: 65_536,
+ }
+ }
+}
+
+impl<T> Timer<T> {
+ fn new(tick_ms: u64, num_slots: usize, capacity: usize, start: Instant) -> Timer<T> {
+ let num_slots = num_slots.next_power_of_two();
+ let capacity = capacity.next_power_of_two();
+ let mask = (num_slots as u64) - 1;
+ let wheel = iter::repeat(WheelEntry { next_tick: TICK_MAX, head: EMPTY })
+ .take(num_slots).collect();
+
+ Timer {
+ tick_ms: tick_ms,
+ entries: Slab::with_capacity(capacity),
+ wheel: wheel,
+ start: start,
+ tick: 0,
+ next: EMPTY,
+ mask: mask,
+ inner: LazyCell::new(),
+ }
+ }
+
+ pub fn set_timeout(&mut self, delay_from_now: Duration, state: T) -> Result<Timeout> {
+ let delay_from_start = self.start.elapsed() + delay_from_now;
+ self.set_timeout_at(delay_from_start, state)
+ }
+
+ fn set_timeout_at(&mut self, delay_from_start: Duration, state: T) -> Result<Timeout> {
+ let mut tick = duration_to_tick(delay_from_start, self.tick_ms);
+ trace!("setting timeout; delay={:?}; tick={:?}; current-tick={:?}", delay_from_start, tick, self.tick);
+
+ // Always target at least 1 tick in the future
+ if tick <= self.tick {
+ tick = self.tick + 1;
+ }
+
+ self.insert(tick, state)
+ }
+
+ fn insert(&mut self, tick: Tick, state: T) -> Result<Timeout> {
+ // Get the slot for the requested tick
+ let slot = (tick & self.mask) as usize;
+ let curr = self.wheel[slot];
+
+ // Insert the new entry
+ let token = try!(
+ self.entries.insert(Entry::new(state, tick, curr.head))
+ .map_err(|_| TimerError::overflow()));
+
+ if curr.head != EMPTY {
+ // If there was a previous entry, set its prev pointer to the new
+ // entry
+ self.entries[curr.head].links.prev = token;
+ }
+
+ // Update the head slot
+ self.wheel[slot] = WheelEntry {
+ next_tick: cmp::min(tick, curr.next_tick),
+ head: token,
+ };
+
+ self.schedule_readiness(tick);
+
+ trace!("inserted timout; slot={}; token={:?}", slot, token);
+
+ // Return the new timeout
+ Ok(Timeout {
+ token: token,
+ tick: tick
+ })
+ }
+
+ pub fn cancel_timeout(&mut self, timeout: &Timeout) -> Option<T> {
+ let links = match self.entries.get(timeout.token) {
+ Some(e) => e.links,
+ None => return None
+ };
+
+ // Sanity check
+ if links.tick != timeout.tick {
+ return None;
+ }
+
+ self.unlink(&links, timeout.token);
+ self.entries.remove(timeout.token).map(|e| e.state)
+ }
+
+ pub fn poll(&mut self) -> Option<T> {
+ let target_tick = current_tick(self.start, self.tick_ms);
+ self.poll_to(target_tick)
+ }
+
+ fn poll_to(&mut self, mut target_tick: Tick) -> Option<T> {
+ trace!("tick_to; target_tick={}; current_tick={}", target_tick, self.tick);
+
+ if target_tick < self.tick {
+ target_tick = self.tick;
+ }
+
+ while self.tick <= target_tick {
+ let curr = self.next;
+
+ trace!("ticking; curr={:?}", curr);
+
+ if curr == EMPTY {
+ self.tick += 1;
+
+ let slot = self.slot_for(self.tick);
+ self.next = self.wheel[slot].head;
+
+ // Handle the case when a slot has a single timeout which gets
+ // canceled before the timeout expires. In this case, the
+ // slot's head is EMPTY but there is a value for next_tick. Not
+ // resetting next_tick here causes the timer to get stuck in a
+ // loop.
+ if self.next == EMPTY {
+ self.wheel[slot].next_tick = TICK_MAX;
+ }
+ } else {
+ let slot = self.slot_for(self.tick);
+
+ if curr == self.wheel[slot].head {
+ self.wheel[slot].next_tick = TICK_MAX;
+ }
+
+ let links = self.entries[curr].links;
+
+ if links.tick <= self.tick {
+ trace!("triggering; token={:?}", curr);
+
+ // Unlink will also advance self.next
+ self.unlink(&links, curr);
+
+ // Remove and return the token
+ return self.entries.remove(curr)
+ .map(|e| e.state);
+ } else {
+ let next_tick = self.wheel[slot].next_tick;
+ self.wheel[slot].next_tick = cmp::min(next_tick, links.tick);
+ self.next = links.next;
+ }
+ }
+ }
+
+ // No more timeouts to poll
+ if let Some(inner) = self.inner.borrow() {
+ trace!("unsetting readiness");
+ let _ = inner.set_readiness.set_readiness(Ready::empty());
+
+ if let Some(tick) = self.next_tick() {
+ self.schedule_readiness(tick);
+ }
+ }
+
+ None
+ }
+
+ fn unlink(&mut self, links: &EntryLinks, token: Token) {
+ trace!("unlinking timeout; slot={}; token={:?}",
+ self.slot_for(links.tick), token);
+
+ if links.prev == EMPTY {
+ let slot = self.slot_for(links.tick);
+ self.wheel[slot].head = links.next;
+ } else {
+ self.entries[links.prev].links.next = links.next;
+ }
+
+ if links.next != EMPTY {
+ self.entries[links.next].links.prev = links.prev;
+
+ if token == self.next {
+ self.next = links.next;
+ }
+ } else if token == self.next {
+ self.next = EMPTY;
+ }
+ }
+
+ fn schedule_readiness(&self, tick: Tick) {
+ if let Some(inner) = self.inner.borrow() {
+ // Coordinate setting readiness w/ the wakeup thread
+ let mut curr = inner.wakeup_state.load(Ordering::Acquire);
+
+ loop {
+ if curr as Tick <= tick {
+ // Nothing to do, wakeup is already scheduled
+ return;
+ }
+
+ // Attempt to move the wakeup time forward
+ trace!("advancing the wakeup time; target={}; curr={}", tick, curr);
+ let actual = inner.wakeup_state.compare_and_swap(curr, tick as usize, Ordering::Release);
+
+ if actual == curr {
+ // Signal to the wakeup thread that the wakeup time has
+ // been changed.
+ trace!("unparking wakeup thread");
+ inner.wakeup_thread.thread().unpark();
+ return;
+ }
+
+ curr = actual;
+ }
+ }
+ }
+
+ // Next tick containing a timeout
+ fn next_tick(&self) -> Option<Tick> {
+ if self.next != EMPTY {
+ let slot = self.slot_for(self.entries[self.next].links.tick);
+
+ if self.wheel[slot].next_tick == self.tick {
+ // There is data ready right now
+ return Some(self.tick);
+ }
+ }
+
+ self.wheel.iter().map(|e| e.next_tick).min()
+ }
+
+ fn slot_for(&self, tick: Tick) -> usize {
+ (self.mask & tick) as usize
+ }
+}
+
+impl<T> Default for Timer<T> {
+ fn default() -> Timer<T> {
+ Builder::default().build()
+ }
+}
+
+impl<T> Evented for Timer<T> {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ if self.inner.borrow().is_some() {
+ return Err(io::Error::new(io::ErrorKind::Other, "timer already registered"));
+ }
+
+ let (registration, set_readiness) = Registration::new(poll, token, interest, opts);
+ let wakeup_state = Arc::new(AtomicUsize::new(usize::MAX));
+ let thread_handle = spawn_wakeup_thread(
+ wakeup_state.clone(),
+ set_readiness.clone(),
+ self.start, self.tick_ms);
+
+ self.inner.fill(Inner {
+ registration: registration,
+ set_readiness: set_readiness,
+ wakeup_state: wakeup_state,
+ wakeup_thread: thread_handle,
+ }).ok().expect("timer already registered");
+
+ if let Some(next_tick) = self.next_tick() {
+ self.schedule_readiness(next_tick);
+ }
+
+ Ok(())
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ match self.inner.borrow() {
+ Some(inner) => inner.registration.update(poll, token, interest, opts),
+ None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
+ }
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ match self.inner.borrow() {
+ Some(inner) => inner.registration.deregister(poll),
+ None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
+ }
+ }
+}
+
+impl fmt::Debug for Inner {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("Inner")
+ .field("registration", &self.registration)
+ .field("wakeup_state", &self.wakeup_state.load(Ordering::Relaxed))
+ .finish()
+ }
+}
+
+fn spawn_wakeup_thread(state: WakeupState, set_readiness: SetReadiness, start: Instant, tick_ms: u64) -> thread::JoinHandle<()> {
+ thread::spawn(move || {
+ let mut sleep_until_tick = state.load(Ordering::Acquire) as Tick;
+
+ loop {
+ if sleep_until_tick == TERMINATE_THREAD as Tick {
+ return;
+ }
+
+ let now_tick = current_tick(start, tick_ms);
+
+ trace!("wakeup thread: sleep_until_tick={:?}; now_tick={:?}", sleep_until_tick, now_tick);
+
+ if now_tick < sleep_until_tick {
+ // Calling park_timeout with u64::MAX leads to undefined
+ // behavior in pthread, causing the park to return immediately
+ // and causing the thread to tightly spin. Instead of u64::MAX
+ // on large values, simply use a blocking park.
+ match tick_ms.checked_mul(sleep_until_tick - now_tick) {
+ Some(sleep_duration) => {
+ trace!("sleeping; tick_ms={}; now_tick={}; sleep_until_tick={}; duration={:?}",
+ tick_ms, now_tick, sleep_until_tick, sleep_duration);
+ thread::park_timeout(Duration::from_millis(sleep_duration));
+ }
+ None => {
+ trace!("sleeping; tick_ms={}; now_tick={}; blocking sleep",
+ tick_ms, now_tick);
+ thread::park();
+ }
+ }
+ sleep_until_tick = state.load(Ordering::Acquire) as Tick;
+ } else {
+ let actual = state.compare_and_swap(sleep_until_tick as usize, usize::MAX, Ordering::AcqRel) as Tick;
+
+ if actual == sleep_until_tick {
+ trace!("setting readiness from wakeup thread");
+ let _ = set_readiness.set_readiness(Ready::readable());
+ sleep_until_tick = usize::MAX as Tick;
+ } else {
+ sleep_until_tick = actual as Tick;
+ }
+ }
+ }
+ })
+}
+
+fn duration_to_tick(elapsed: Duration, tick_ms: u64) -> Tick {
+ // Calculate tick rounding up to the closest one
+ let elapsed_ms = convert::millis(elapsed);
+ elapsed_ms.saturating_add(tick_ms / 2) / tick_ms
+}
+
+fn current_tick(start: Instant, tick_ms: u64) -> Tick {
+ duration_to_tick(start.elapsed(), tick_ms)
+}
+
+impl<T> Entry<T> {
+ fn new(state: T, tick: u64, next: Token) -> Entry<T> {
+ Entry {
+ state: state,
+ links: EntryLinks {
+ tick: tick,
+ prev: EMPTY,
+ next: next,
+ },
+ }
+ }
+}
+
+impl fmt::Display for TimerError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "{}: {}", self.kind, self.desc)
+ }
+}
+
+impl TimerError {
+ fn overflow() -> TimerError {
+ TimerError {
+ kind: TimerOverflow,
+ desc: "too many timer entries"
+ }
+ }
+}
+
+impl error::Error for TimerError {
+ fn description(&self) -> &str {
+ self.desc
+ }
+}
+
+impl fmt::Display for TimerErrorKind {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ TimerOverflow => write!(fmt, "TimerOverflow"),
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/token.rs
@@ -0,0 +1,145 @@
+/// Associates readiness notifications with [`Evented`] handles.
+///
+/// `Token` is a wrapper around `usize` and is used as an argument to
+/// [`Poll::register`] and [`Poll::reregister`].
+///
+/// See [`Poll`] for more documentation on polling.
+///
+/// # Example
+///
+/// Using `Token` to track which socket generated the notification. In this
+/// example, `HashMap` is used, but usually something like [`slab`] is better.
+///
+/// ```
+/// use mio::{Events, Ready, Poll, PollOpt, Token};
+/// use mio::tcp::TcpListener;
+///
+/// use std::thread;
+/// use std::io::{self, Read};
+/// use std::collections::HashMap;
+///
+/// // After this number of sockets is accepted, the server will shutdown.
+/// const MAX_SOCKETS: usize = 32;
+///
+/// // Pick a token that will not be used by any other socket and use that one
+/// // for the listener.
+/// const LISTENER: Token = Token(1024);
+///
+/// // Used to store the sockets.
+/// let mut sockets = HashMap::new();
+///
+/// // This is used to generate a unique token for a socket
+/// let mut next_socket_index = 0;
+///
+/// // The `Poll` instance
+/// let poll = Poll::new().unwrap();
+///
+/// // Tcp listener
+/// let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
+///
+/// // Register the listener
+/// poll.register(&listener,
+/// LISTENER,
+/// Ready::readable(),
+/// PollOpt::edge()).unwrap();
+///
+/// // Spawn a thread that will connect a bunch of sockets then close them
+/// let addr = listener.local_addr().unwrap();
+/// thread::spawn(move || {
+/// use std::net::TcpStream;
+///
+/// // +1 here is to connect an extra socket to signal the socket to close
+/// for _ in 0..(MAX_SOCKETS+1) {
+/// // Connect then drop the socket
+/// let _ = TcpStream::connect(&addr).unwrap();
+/// }
+/// });
+///
+/// // Event storage
+/// let mut events = Events::with_capacity(1024);
+///
+/// // Read buffer, this will never actually get filled
+/// let mut buf = [0; 256];
+///
+/// // The main event loop
+/// loop {
+/// // Wait for events
+/// poll.poll(&mut events, None).unwrap();
+///
+/// for event in &events {
+/// match event.token() {
+/// LISTENER => {
+/// // Perform operations in a loop until `WouldBlock` is
+/// // encountered.
+/// loop {
+/// match listener.accept() {
+/// Ok((socket, _)) => {
+/// // Shutdown the server
+/// if next_socket_index == MAX_SOCKETS {
+/// return;
+/// }
+///
+/// // Get the token for the socket
+/// let token = Token(next_socket_index);
+/// next_socket_index += 1;
+///
+/// // Register the new socket w/ poll
+/// poll.register(&socket,
+/// token,
+/// Ready::readable(),
+/// PollOpt::edge()).unwrap();
+///
+/// // Store the socket
+/// sockets.insert(token, socket);
+/// }
+/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+/// // Socket is not ready anymore, stop accepting
+/// break;
+/// }
+/// e => panic!("err={:?}", e), // Unexpected error
+/// }
+/// }
+/// }
+/// token => {
+/// // Always operate in a loop
+/// loop {
+/// match sockets.get_mut(&token).unwrap().read(&mut buf) {
+/// Ok(0) => {
+/// // Socket is closed, remove it from the map
+/// sockets.remove(&token);
+/// break;
+/// }
+/// // Data is not actually sent in this example
+/// Ok(_) => unreachable!(),
+/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+/// // Socket is not ready anymore, stop reading
+/// continue;
+/// }
+/// e => panic!("err={:?}", e), // Unexpected error
+/// }
+/// }
+/// }
+/// }
+/// }
+/// }
+/// ```
+///
+/// [`Evented`]: event/trait.Evented.html
+/// [`Poll`]: struct.Poll.html
+/// [`Poll::register`]: struct.Poll.html#method.register
+/// [`Poll::reregister`]: struct.Poll.html#method.reregister
+/// [`slab`]: https://crates.io/crates/slab
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Token(pub usize);
+
+impl From<usize> for Token {
+ fn from(val: usize) -> Token {
+ Token(val)
+ }
+}
+
+impl From<Token> for usize {
+ fn from(val: Token) -> usize {
+ val.0
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mio/src/udp.rs
@@ -0,0 +1,311 @@
+//! Primitives for working with UDP
+//!
+//! The types provided in this module are non-blocking by default and are
+//! designed to be portable across all supported Mio platforms. As long as the
+//! [portability guidelines] are followed, the behavior should be identical no
+//! matter the target platform.
+//!
+//! [portability guidelines]: ../struct.Poll.html#portability
+
+#![allow(deprecated)]
+
+use {sys, Ready, Poll, PollOpt, Token};
+use io::{self, MapNonBlock};
+use event::Evented;
+use poll::SelectorId;
+use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr};
+
+/// A User Datagram Protocol socket.
+///
+/// This is an implementation of a bound UDP socket. This supports both IPv4 and
+/// IPv6 addresses, and there is no corresponding notion of a server because UDP
+/// is a datagram protocol.
+#[derive(Debug)]
+pub struct UdpSocket {
+ sys: sys::UdpSocket,
+ selector_id: SelectorId,
+}
+
+impl UdpSocket {
+ /// Creates a UDP socket from the given address.
+ pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
+ let socket = try!(net::UdpSocket::bind(addr));
+ UdpSocket::from_socket(socket)
+ }
+
+ /// Creates a new mio-wrapped socket from an underlying and bound std
+ /// socket.
+ ///
+ /// This function requires that `socket` has previously been bound to an
+ /// address to work correctly, and returns an I/O object which can be used
+ /// with mio to send/receive UDP messages.
+ ///
+ /// This can be used in conjunction with net2's `UdpBuilder` interface to
+ /// configure a socket before it's handed off to mio, such as setting
+ /// options like `reuse_address` or binding to multiple addresses.
+ pub fn from_socket(socket: net::UdpSocket) -> io::Result<UdpSocket> {
+ Ok(UdpSocket {
+ sys: try!(sys::UdpSocket::new(socket)),
+ selector_id: SelectorId::new(),
+ })
+ }
+
+ /// Returns the socket address that this socket was created from.
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.sys.local_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.
+ pub fn try_clone(&self) -> io::Result<UdpSocket> {
+ self.sys.try_clone()
+ .map(|s| {
+ UdpSocket {
+ sys: s,
+ selector_id: self.selector_id.clone(),
+ }
+ })
+ }
+
+ /// 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.
+ pub fn send_to(&self, buf: &[u8], target: &SocketAddr)
+ -> io::Result<Option<usize>> {
+ self.sys.send_to(buf, target).map_non_block()
+ }
+
+ /// Receives data from the socket. On success, returns the number of bytes
+ /// read and the address from whence the data came.
+ pub fn recv_from(&self, buf: &mut [u8])
+ -> io::Result<Option<(usize, SocketAddr)>> {
+ self.sys.recv_from(buf).map_non_block()
+ }
+
+ /// Sends data on the socket to the address previously bound via connect(). On success,
+ /// returns the number of bytes written.
+ ///
+ /// Address type can be any implementor of `ToSocketAddrs` trait. See its
+ /// documentation for concrete examples.
+ pub fn send(&self, buf: &[u8])
+ -> io::Result<Option<usize>> {
+ self.sys.send(buf).map_non_block()
+ }
+
+ /// Receives data from the socket previously bound with connect(). On success, returns
+ /// the number of bytes read and the address from whence the data came.
+ pub fn recv(&self, buf: &mut [u8])
+ -> io::Result<Option<usize>> {
+ self.sys.recv(buf).map_non_block()
+ }
+
+ /// Connects the UDP socket setting the default destination for `send()`
+ /// and limiting packets that are read via `recv` from the address specified
+ /// in `addr`.
+ pub fn connect(&self, addr: SocketAddr)
+ -> io::Result<()> {
+ self.sys.connect(addr)
+ }
+
+ /// 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
+ pub fn broadcast(&self) -> io::Result<bool> {
+ self.sys.broadcast()
+ }
+
+ /// Sets the value of the `SO_BROADCAST` option for this socket.
+ ///
+ /// When enabled, this socket is allowed to send packets to a broadcast
+ /// address.
+ pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
+ self.sys.set_broadcast(on)
+ }
+
+ /// 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
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ self.sys.multicast_loop_v4()
+ }
+
+ /// 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.
+ pub fn set_multicast_loop_v4(&self, on: bool) -> io::Result<()> {
+ self.sys.set_multicast_loop_v4(on)
+ }
+
+ /// 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
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ self.sys.multicast_ttl_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.
+ pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
+ self.sys.set_multicast_ttl_v4(ttl)
+ }
+
+ /// 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
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ self.sys.multicast_loop_v6()
+ }
+
+ /// 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.
+ pub fn set_multicast_loop_v6(&self, on: bool) -> io::Result<()> {
+ self.sys.set_multicast_loop_v6(on)
+ }
+
+ /// 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
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.sys.ttl()
+ }
+
+ /// 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.
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.sys.set_ttl(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.
+ pub fn join_multicast_v4(&self,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr) -> io::Result<()> {
+ self.sys.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).
+ pub fn join_multicast_v6(&self,
+ multiaddr: &Ipv6Addr,
+ interface: u32) -> io::Result<()> {
+ self.sys.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
+ pub fn leave_multicast_v4(&self,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr) -> io::Result<()> {
+ self.sys.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
+ pub fn leave_multicast_v6(&self,
+ multiaddr: &Ipv6Addr,
+ interface: u32) -> io::Result<()> {
+ self.sys.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.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.sys.take_error()
+ }
+}
+
+impl Evented for UdpSocket {
+ fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ try!(self.selector_id.associate_selector(poll));
+ self.sys.register(poll, token, interest, opts)
+ }
+
+ fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
+ self.sys.reregister(poll, token, interest, opts)
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ self.sys.deregister(poll)
+ }
+}
+
+/*
+ *
+ * ===== UNIX ext =====
+ *
+ */
+
+#[cfg(unix)]
+use std::os::unix::io::{IntoRawFd, AsRawFd, FromRawFd, RawFd};
+
+#[cfg(unix)]
+impl IntoRawFd for UdpSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.sys.into_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl AsRawFd for UdpSocket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.sys.as_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl FromRawFd for UdpSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> UdpSocket {
+ UdpSocket {
+ sys: FromRawFd::from_raw_fd(fd),
+ selector_id: SelectorId::new(),
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","Cargo.toml":"7a72c6e4b9cce0cd1105ab0234e8b3caae6c1bd7af2c41eae39f031becfc5a37","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"05cefe09de4f980658e2868df1a220e3da5fd6ddb6d6c1eab1b5e6f5cb000879","appveyor.yml":"ffdfb9572a6362866bea6787a726b0d4e43f6bb6516f3a38ebdd561859531602","src/handle.rs":"ada6cf8482d49bc7be6d26adeb8ae47df9ff0a5637424474aa4a86ad699be63d","src/iocp.rs":"002fef559bbaf52ada0fcb7b94d6dbbaaedc94840b5870c186243e79120b7cfc","src/lib.rs":"0d30428e89c7a2be7e479148211360a56d6c6b3b5a86d5ee7254277484506efa","src/net.rs":"054b8772bf51acc80b74a261f2d759645332288e03c72e2bd05c555364fe05bf","src/overlapped.rs":"b3c7f7b45fd9b22090bd11563decb09e9c412db8757c0e7484cfaa9ec5e29b9c","src/pipe.rs":"97ef5d456d7e5a72af2c4509a8155bd45a2a755275524ce1cd2d79f44f264c65"},"package":"8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "miow"
+version = "0.2.1"
+authors = ["Alex Crichton <alex@alexcrichton.com>"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+keywords = ["iocp", "windows", "io", "overlapped"]
+repository = "https://github.com/alexcrichton/miow"
+homepage = "https://github.com/alexcrichton/miow"
+documentation = "https://docs.rs/miow/0.1/x86_64-pc-windows-msvc/miow/"
+description = """
+A zero overhead I/O library for Windows, focusing on IOCP and Async I/O
+abstractions.
+"""
+
+[dependencies]
+winapi = "0.2"
+kernel32-sys = "0.2"
+ws2_32-sys = "0.2"
+net2 = { version = "0.2.5", default-features = false }
+
+[dev-dependencies]
+rand = "0.3"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 Alex Crichton
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/README.md
@@ -0,0 +1,22 @@
+# miow
+
+[![Build status](https://ci.appveyor.com/api/projects/status/tc5lsxokjk86949l?svg=true)](https://ci.appveyor.com/project/alexcrichton/miow)
+
+[Documentation](https://docs.rs/miow/0.1/x86_64-pc-windows-msvc/miow/)
+
+A zero overhead Windows I/O library focusing on IOCP and other async I/O
+features.
+
+```toml
+# Cargo.toml
+[dependencies]
+miow = "0.1"
+```
+
+# License
+
+`miow` is primarily distributed under the terms of both the MIT license and
+the Apache License (Version 2.0), with portions covered by various BSD-like
+licenses.
+
+See LICENSE-APACHE, and LICENSE-MIT for details.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/appveyor.yml
@@ -0,0 +1,20 @@
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+ - TARGET: i686-pc-windows-msvc
+ - TARGET: i686-pc-windows-gnu
+ GH_TOKEN:
+ secure: nHB4fVo+y/Aak+L0nYfrT8Rcs8OfUNm0F2xcIVFVYJ9ehf0CzvCmSMUvWguM0kKp
+
+install:
+ - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
+ - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
+ - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
+ - SET PATH=%PATH%;C:\MinGW\bin
+ - rustc -V
+ - cargo -V
+
+build: false
+
+test_script:
+ - cargo test --target %TARGET%
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/src/handle.rs
@@ -0,0 +1,93 @@
+use std::io;
+use std::cmp;
+
+use winapi::*;
+use kernel32::*;
+
+#[derive(Debug)]
+pub struct Handle(HANDLE);
+
+unsafe impl Send for Handle {}
+unsafe impl Sync for Handle {}
+
+impl Handle {
+ pub fn new(handle: HANDLE) -> Handle {
+ Handle(handle)
+ }
+
+ pub fn raw(&self) -> HANDLE { self.0 }
+
+ pub fn into_raw(self) -> HANDLE {
+ use std::mem;
+
+ let ret = self.0;
+ mem::forget(self);
+ ret
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ let mut bytes = 0;
+ let len = cmp::min(buf.len(), <DWORD>::max_value() as usize) as DWORD;
+ try!(::cvt(unsafe {
+ WriteFile(self.0, buf.as_ptr() as *const _, len, &mut bytes,
+ 0 as *mut _)
+ }));
+ Ok(bytes as usize)
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ let mut bytes = 0;
+ let len = cmp::min(buf.len(), <DWORD>::max_value() as usize) as DWORD;
+ try!(::cvt(unsafe {
+ ReadFile(self.0, buf.as_mut_ptr() as *mut _, len, &mut bytes,
+ 0 as *mut _)
+ }));
+ Ok(bytes as usize)
+ }
+
+ pub unsafe fn read_overlapped(&self, buf: &mut [u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ let len = cmp::min(buf.len(), <DWORD>::max_value() as usize) as DWORD;
+ let mut bytes = 0;
+ let res = ::cvt({
+ ReadFile(self.0,
+ buf.as_mut_ptr() as *mut _,
+ len,
+ &mut bytes,
+ overlapped)
+ });
+ match res {
+ Ok(_) => Ok(Some(bytes as usize)),
+ Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32)
+ => Ok(None),
+ Err(e) => Err(e),
+ }
+ }
+
+ pub unsafe fn write_overlapped(&self, buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ let len = cmp::min(buf.len(), <DWORD>::max_value() as usize) as DWORD;
+ let mut bytes = 0;
+ let res = ::cvt({
+ WriteFile(self.0,
+ buf.as_ptr() as *const _,
+ len,
+ &mut bytes,
+ overlapped)
+ });
+ match res {
+ Ok(_) => Ok(Some(bytes as usize)),
+ Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32)
+ => Ok(None),
+ Err(e) => Err(e),
+ }
+ }
+}
+
+impl Drop for Handle {
+ fn drop(&mut self) {
+ unsafe { CloseHandle(self.0) };
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/src/iocp.rs
@@ -0,0 +1,313 @@
+//! Bindings to IOCP, I/O Completion Ports
+
+use std::cmp;
+use std::io;
+use std::mem;
+use std::os::windows::io::*;
+use std::time::Duration;
+
+use handle::Handle;
+use winapi::*;
+use kernel32::*;
+use Overlapped;
+
+/// A handle to an Windows I/O Completion Port.
+#[derive(Debug)]
+pub struct CompletionPort {
+ handle: Handle,
+}
+
+/// A status message received from an I/O completion port.
+///
+/// These statuses can be created via the `new` or `empty` constructors and then
+/// provided to a completion port, or they are read out of a completion port.
+/// The fields of each status are read through its accessor methods.
+#[derive(Clone, Copy, Debug)]
+pub struct CompletionStatus(OVERLAPPED_ENTRY);
+
+unsafe impl Send for CompletionStatus {}
+unsafe impl Sync for CompletionStatus {}
+
+impl CompletionPort {
+ /// Creates a new I/O completion port with the specified concurrency value.
+ ///
+ /// The number of threads given corresponds to the level of concurrency
+ /// allowed for threads associated with this port. Consult the Windows
+ /// documentation for more information about this value.
+ pub fn new(threads: u32) -> io::Result<CompletionPort> {
+ let ret = unsafe {
+ CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0 as *mut _,
+ 0, threads)
+ };
+ if ret.is_null() {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(CompletionPort { handle: Handle::new(ret) })
+ }
+ }
+
+ /// Associates a new `HANDLE` to this I/O completion port.
+ ///
+ /// This function will associate the given handle to this port with the
+ /// given `token` to be returned in status messages whenever it receives a
+ /// notification.
+ ///
+ /// Any object which is convertible to a `HANDLE` via the `AsRawHandle`
+ /// trait can be provided to this function, such as `std::fs::File` and
+ /// friends.
+ pub fn add_handle<T: AsRawHandle + ?Sized>(&self, token: usize,
+ t: &T) -> io::Result<()> {
+ self._add(token, t.as_raw_handle())
+ }
+
+ /// Associates a new `SOCKET` to this I/O completion port.
+ ///
+ /// This function will associate the given socket to this port with the
+ /// given `token` to be returned in status messages whenever it receives a
+ /// notification.
+ ///
+ /// Any object which is convertible to a `SOCKET` via the `AsRawSocket`
+ /// trait can be provided to this function, such as `std::net::TcpStream`
+ /// and friends.
+ pub fn add_socket<T: AsRawSocket + ?Sized>(&self, token: usize,
+ t: &T) -> io::Result<()> {
+ self._add(token, t.as_raw_socket() as HANDLE)
+ }
+
+ fn _add(&self, token: usize, handle: HANDLE) -> io::Result<()> {
+ assert_eq!(mem::size_of_val(&token), mem::size_of::<ULONG_PTR>());
+ let ret = unsafe {
+ CreateIoCompletionPort(handle, self.handle.raw(),
+ token as ULONG_PTR, 0)
+ };
+ if ret.is_null() {
+ Err(io::Error::last_os_error())
+ } else {
+ debug_assert_eq!(ret, self.handle.raw());
+ Ok(())
+ }
+ }
+
+ /// Dequeue a completion status from this I/O completion port.
+ ///
+ /// This function will associate the calling thread with this completion
+ /// port and then wait for a status message to become available. The precise
+ /// semantics on when this function returns depends on the concurrency value
+ /// specified when the port was created.
+ ///
+ /// A timeout can optionally be specified to this function. If `None` is
+ /// provided this function will not time out, and otherwise it will time out
+ /// after the specified duration has passed.
+ ///
+ /// On success this will return the status message which was dequeued from
+ /// this completion port.
+ pub fn get(&self, timeout: Option<Duration>) -> io::Result<CompletionStatus> {
+ let mut bytes = 0;
+ let mut token = 0;
+ let mut overlapped = 0 as *mut _;
+ let timeout = ::dur2ms(timeout);
+ let ret = unsafe {
+ GetQueuedCompletionStatus(self.handle.raw(),
+ &mut bytes,
+ &mut token,
+ &mut overlapped,
+ timeout)
+ };
+ ::cvt(ret).map(|_| {
+ CompletionStatus(OVERLAPPED_ENTRY {
+ dwNumberOfBytesTransferred: bytes,
+ lpCompletionKey: token,
+ lpOverlapped: overlapped,
+ Internal: 0,
+ })
+ })
+ }
+
+ /// Dequeues a number of completion statuses from this I/O completion port.
+ ///
+ /// This function is the same as `get` except that it may return more than
+ /// one status. A buffer of "zero" statuses is provided (the contents are
+ /// not read) and then on success this function will return a sub-slice of
+ /// statuses which represent those which were dequeued from this port. This
+ /// function does not wait to fill up the entire list of statuses provided.
+ ///
+ /// Like with `get`, a timeout may be specified for this operation.
+ pub fn get_many<'a>(&self,
+ list: &'a mut [CompletionStatus],
+ timeout: Option<Duration>)
+ -> io::Result<&'a mut [CompletionStatus]>
+ {
+ debug_assert_eq!(mem::size_of::<CompletionStatus>(),
+ mem::size_of::<OVERLAPPED_ENTRY>());
+ let mut removed = 0;
+ let timeout = ::dur2ms(timeout);
+ let len = cmp::min(list.len(), <ULONG>::max_value() as usize) as ULONG;
+ let ret = unsafe {
+ GetQueuedCompletionStatusEx(self.handle.raw(),
+ list.as_ptr() as *mut _,
+ len,
+ &mut removed,
+ timeout,
+ FALSE)
+ };
+ match ::cvt(ret) {
+ Ok(_) => Ok(&mut list[..removed as usize]),
+ Err(e) => Err(e),
+ }
+ }
+
+ /// Posts a new completion status onto this I/O completion port.
+ ///
+ /// This function will post the given status, with custom parameters, to the
+ /// port. Threads blocked in `get` or `get_many` will eventually receive
+ /// this status.
+ pub fn post(&self, status: CompletionStatus) -> io::Result<()> {
+ let ret = unsafe {
+ PostQueuedCompletionStatus(self.handle.raw(),
+ status.0.dwNumberOfBytesTransferred,
+ status.0.lpCompletionKey,
+ status.0.lpOverlapped)
+ };
+ ::cvt(ret).map(|_| ())
+ }
+}
+
+impl AsRawHandle for CompletionPort {
+ fn as_raw_handle(&self) -> HANDLE {
+ self.handle.raw()
+ }
+}
+
+impl FromRawHandle for CompletionPort {
+ unsafe fn from_raw_handle(handle: HANDLE) -> CompletionPort {
+ CompletionPort { handle: Handle::new(handle) }
+ }
+}
+
+impl IntoRawHandle for CompletionPort {
+ fn into_raw_handle(self) -> HANDLE {
+ self.handle.into_raw()
+ }
+}
+
+impl CompletionStatus {
+ /// Creates a new completion status with the provided parameters.
+ ///
+ /// This function is useful when creating a status to send to a port with
+ /// the `post` method. The parameters are opaquely passed through and not
+ /// interpreted by the system at all.
+ pub fn new(bytes: u32, token: usize, overlapped: *mut Overlapped)
+ -> CompletionStatus {
+ assert_eq!(mem::size_of_val(&token), mem::size_of::<ULONG_PTR>());
+ CompletionStatus(OVERLAPPED_ENTRY {
+ dwNumberOfBytesTransferred: bytes,
+ lpCompletionKey: token as ULONG_PTR,
+ lpOverlapped: overlapped as *mut _,
+ Internal: 0,
+ })
+ }
+
+ /// Creates a new borrowed completion status from the borrowed
+ /// `OVERLAPPED_ENTRY` argument provided.
+ ///
+ /// This method will wrap the `OVERLAPPED_ENTRY` in a `CompletionStatus`,
+ /// returning the wrapped structure.
+ pub fn from_entry(entry: &OVERLAPPED_ENTRY) -> &CompletionStatus {
+ unsafe { &*(entry as *const _ as *const _) }
+ }
+
+ /// Creates a new "zero" completion status.
+ ///
+ /// This function is useful when creating a stack buffer or vector of
+ /// completion statuses to be passed to the `get_many` function.
+ pub fn zero() -> CompletionStatus {
+ CompletionStatus::new(0, 0, 0 as *mut _)
+ }
+
+ /// Returns the number of bytes that were transferred for the I/O operation
+ /// associated with this completion status.
+ pub fn bytes_transferred(&self) -> u32 {
+ self.0.dwNumberOfBytesTransferred
+ }
+
+ /// Returns the completion key value associated with the file handle whose
+ /// I/O operation has completed.
+ ///
+ /// A completion key is a per-handle key that is specified when it is added
+ /// to an I/O completion port via `add_handle` or `add_socket`.
+ pub fn token(&self) -> usize {
+ self.0.lpCompletionKey as usize
+ }
+
+ /// Returns a pointer to the `Overlapped` structure that was specified when
+ /// the I/O operation was started.
+ pub fn overlapped(&self) -> *mut OVERLAPPED {
+ self.0.lpOverlapped
+ }
+
+ /// Returns a pointer to the internal `OVERLAPPED_ENTRY` object.
+ pub fn entry(&self) -> &OVERLAPPED_ENTRY {
+ &self.0
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::mem;
+ use std::time::Duration;
+
+ use winapi::*;
+
+ use iocp::{CompletionPort, CompletionStatus};
+
+ #[test]
+ fn is_send_sync() {
+ fn is_send_sync<T: Send + Sync>() {}
+ is_send_sync::<CompletionPort>();
+ }
+
+ #[test]
+ fn token_right_size() {
+ assert_eq!(mem::size_of::<usize>(), mem::size_of::<ULONG_PTR>());
+ }
+
+ #[test]
+ fn timeout() {
+ let c = CompletionPort::new(1).unwrap();
+ let err = c.get(Some(Duration::from_millis(1))).unwrap_err();
+ assert_eq!(err.raw_os_error(), Some(WAIT_TIMEOUT as i32));
+ }
+
+ #[test]
+ fn get() {
+ let c = CompletionPort::new(1).unwrap();
+ c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap();
+ let s = c.get(None).unwrap();
+ assert_eq!(s.bytes_transferred(), 1);
+ assert_eq!(s.token(), 2);
+ assert_eq!(s.overlapped(), 3 as *mut _);
+ }
+
+ #[test]
+ fn get_many() {
+ let c = CompletionPort::new(1).unwrap();
+
+ c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap();
+ c.post(CompletionStatus::new(4, 5, 6 as *mut _)).unwrap();
+
+ let mut s = vec![CompletionStatus::zero(); 4];
+ {
+ let s = c.get_many(&mut s, None).unwrap();
+ assert_eq!(s.len(), 2);
+ assert_eq!(s[0].bytes_transferred(), 1);
+ assert_eq!(s[0].token(), 2);
+ assert_eq!(s[0].overlapped(), 3 as *mut _);
+ assert_eq!(s[1].bytes_transferred(), 4);
+ assert_eq!(s[1].token(), 5);
+ assert_eq!(s[1].overlapped(), 6 as *mut _);
+ }
+ assert_eq!(s[2].bytes_transferred(), 0);
+ assert_eq!(s[2].token(), 0);
+ assert_eq!(s[2].overlapped(), 0 as *mut _);
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/src/lib.rs
@@ -0,0 +1,57 @@
+//! A zero overhead Windows I/O library
+
+#![cfg(windows)]
+#![deny(missing_docs)]
+#![allow(bad_style)]
+#![doc(html_root_url = "https://docs.rs/miow/0.1/x86_64-pc-windows-msvc/")]
+
+extern crate kernel32;
+extern crate net2;
+extern crate winapi;
+extern crate ws2_32;
+
+#[cfg(test)] extern crate rand;
+
+use std::cmp;
+use std::io;
+use std::time::Duration;
+
+use winapi::*;
+
+macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
+ })
+}
+
+mod handle;
+mod overlapped;
+
+pub mod iocp;
+pub mod net;
+pub mod pipe;
+
+pub use overlapped::Overlapped;
+
+fn cvt(i: BOOL) -> io::Result<BOOL> {
+ if i == 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(i)
+ }
+}
+
+fn dur2ms(dur: Option<Duration>) -> u32 {
+ let dur = match dur {
+ Some(dur) => dur,
+ None => return INFINITE,
+ };
+ let ms = dur.as_secs().checked_mul(1_000);
+ let ms_extra = dur.subsec_nanos() / 1_000_000;
+ ms.and_then(|ms| {
+ ms.checked_add(ms_extra as u64)
+ }).map(|ms| {
+ cmp::min(u32::max_value() as u64, ms) as u32
+ }).unwrap_or(INFINITE - 1)
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/src/net.rs
@@ -0,0 +1,1183 @@
+//! Extensions and types for the standard networking primitives.
+//!
+//! This module contains a number of extension traits for the types in
+//! `std::net` for Windows-specific functionality.
+
+use std::cmp;
+use std::io;
+use std::mem;
+use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+use std::net::{TcpStream, UdpSocket, SocketAddr, TcpListener};
+use std::net::{SocketAddrV4, Ipv4Addr, SocketAddrV6, Ipv6Addr};
+use std::os::windows::prelude::*;
+
+use net2::TcpBuilder;
+use winapi::*;
+use ws2_32::*;
+
+/// A type to represent a buffer in which a socket address will be stored.
+///
+/// This type is used with the `recv_from_overlapped` function on the
+/// `UdpSocketExt` trait to provide space for the overlapped I/O operation to
+/// fill in the address upon completion.
+#[derive(Clone, Copy)]
+pub struct SocketAddrBuf {
+ buf: SOCKADDR_STORAGE,
+ len: c_int,
+}
+
+/// A type to represent a buffer in which an accepted socket's address will be
+/// stored.
+///
+/// This type is used with the `accept_overlapped` method on the
+/// `TcpListenerExt` trait to provide space for the overlapped I/O operation to
+/// fill in the socket addresses upon completion.
+#[repr(C)]
+pub struct AcceptAddrsBuf {
+ // For AcceptEx we've got the restriction that the addresses passed in that
+ // buffer need to be at least 16 bytes more than the maximum address length
+ // for the protocol in question, so add some extra here and there
+ local: SOCKADDR_STORAGE,
+ _pad1: [u8; 16],
+ remote: SOCKADDR_STORAGE,
+ _pad2: [u8; 16],
+}
+
+/// The parsed return value of `AcceptAddrsBuf`.
+pub struct AcceptAddrs<'a> {
+ local: LPSOCKADDR,
+ local_len: c_int,
+ remote: LPSOCKADDR,
+ remote_len: c_int,
+ _data: &'a AcceptAddrsBuf,
+}
+
+struct WsaExtension {
+ guid: GUID,
+ val: AtomicUsize,
+}
+
+/// Additional methods for the `TcpStream` type in the standard library.
+pub trait TcpStreamExt {
+ /// Execute an overlapped read I/O operation on this TCP stream.
+ ///
+ /// This function will issue an overlapped I/O read (via `WSARecv`) on this
+ /// socket. The provided buffer will be filled in when the operation
+ /// completes and the given `OVERLAPPED` instance is used to track the
+ /// overlapped operation.
+ ///
+ /// If the operation succeeds, `Ok(Some(n))` is returned indicating how
+ /// many bytes were read. If the operation returns an error indicating that
+ /// the I/O is currently pending, `Ok(None)` is returned. Otherwise, the
+ /// error associated with the operation is returned and no overlapped
+ /// operation is enqueued.
+ ///
+ /// The number of bytes read will be returned as part of the completion
+ /// notification when the I/O finishes.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the `buf` and
+ /// `overlapped` pointers are valid until the end of the I/O operation. The
+ /// kernel also requires that `overlapped` is unique for this I/O operation
+ /// and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that these two input
+ /// pointers are valid until the I/O operation is completed, typically via
+ /// completion ports and waiting to receive the completion notification on
+ /// the port.
+ unsafe fn read_overlapped(&self,
+ buf: &mut [u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>>;
+
+ /// Execute an overlapped write I/O operation on this TCP stream.
+ ///
+ /// This function will issue an overlapped I/O write (via `WSASend`) on this
+ /// socket. The provided buffer will be written when the operation completes
+ /// and the given `OVERLAPPED` instance is used to track the overlapped
+ /// operation.
+ ///
+ /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the
+ /// number of bytes that were written. If the operation returns an error
+ /// indicating that the I/O is currently pending, `Ok(None)` is returned.
+ /// Otherwise, the error associated with the operation is returned and no
+ /// overlapped operation is enqueued.
+ ///
+ /// The number of bytes written will be returned as part of the completion
+ /// notification when the I/O finishes.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the `buf` and
+ /// `overlapped` pointers are valid until the end of the I/O operation. The
+ /// kernel also requires that `overlapped` is unique for this I/O operation
+ /// and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that these two input
+ /// pointers are valid until the I/O operation is completed, typically via
+ /// completion ports and waiting to receive the completion notification on
+ /// the port.
+ unsafe fn write_overlapped(&self,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>>;
+
+ /// Execute a connection operation for this socket.
+ ///
+ /// For more information about this method, see the
+ /// [`TcpBuilderExt::connect_overlapped`][link] documentation.
+ ///
+ /// [link]: trait.TcpBuilderExt.html#tymethod.connect_overlapped
+ unsafe fn connect_overlapped(&self,
+ addr: &SocketAddr,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>>;
+
+ /// Once a `connect_overlapped` has finished, this function needs to be
+ /// called to finish the connect operation.
+ ///
+ /// Currently this just calls `setsockopt` with `SO_UPDATE_CONNECT_CONTEXT`
+ /// to ensure that further functions like `getpeername` and `getsockname`
+ /// work correctly.
+ fn connect_complete(&self) -> io::Result<()>;
+
+ /// Calls the `GetOverlappedResult` function to get the result of an
+ /// overlapped operation for this handle.
+ ///
+ /// This function takes the `OVERLAPPED` argument which must have been used
+ /// to initiate an overlapped I/O operation, and returns either the
+ /// successful number of bytes transferred during the operation or an error
+ /// if one occurred, along with the results of the `lpFlags` parameter of
+ /// the relevant operation, if applicable.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe as `overlapped` must have previously been used
+ /// to execute an operation for this handle, and it must also be a valid
+ /// pointer to an `OVERLAPPED` instance.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic
+ unsafe fn result(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<(usize, u32)>;
+}
+
+/// Additional methods for the `UdpSocket` type in the standard library.
+pub trait UdpSocketExt {
+ /// Execute an overlapped receive I/O operation on this UDP socket.
+ ///
+ /// This function will issue an overlapped I/O read (via `WSARecvFrom`) on
+ /// this socket. The provided buffer will be filled in when the operation
+ /// completes, the source from where the data came from will be written to
+ /// `addr`, and the given `OVERLAPPED` instance is used to track the
+ /// overlapped operation.
+ ///
+ /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the
+ /// number of bytes that were read. If the operation returns an error
+ /// indicating that the I/O is currently pending, `Ok(None)` is returned.
+ /// Otherwise, the error associated with the operation is returned and no
+ /// overlapped operation is enqueued.
+ ///
+ /// The number of bytes read will be returned as part of the completion
+ /// notification when the I/O finishes.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the `buf`,
+ /// `addr`, and `overlapped` pointers are valid until the end of the I/O
+ /// operation. The kernel also requires that `overlapped` is unique for this
+ /// I/O operation and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that these two input
+ /// pointers are valid until the I/O operation is completed, typically via
+ /// completion ports and waiting to receive the completion notification on
+ /// the port.
+ unsafe fn recv_from_overlapped(&self,
+ buf: &mut [u8],
+ addr: *mut SocketAddrBuf,
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>>;
+
+ /// Execute an overlapped receive I/O operation on this UDP socket.
+ ///
+ /// This function will issue an overlapped I/O read (via `WSARecv`) on
+ /// this socket. The provided buffer will be filled in when the operation
+ /// completes, the source from where the data came from will be written to
+ /// `addr`, and the given `OVERLAPPED` instance is used to track the
+ /// overlapped operation.
+ ///
+ /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the
+ /// number of bytes that were read. If the operation returns an error
+ /// indicating that the I/O is currently pending, `Ok(None)` is returned.
+ /// Otherwise, the error associated with the operation is returned and no
+ /// overlapped operation is enqueued.
+ ///
+ /// The number of bytes read will be returned as part of the completion
+ /// notification when the I/O finishes.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the `buf`,
+ /// and `overlapped` pointers are valid until the end of the I/O
+ /// operation. The kernel also requires that `overlapped` is unique for this
+ /// I/O operation and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that these two input
+ /// pointers are valid until the I/O operation is completed, typically via
+ /// completion ports and waiting to receive the completion notification on
+ /// the port.
+ unsafe fn recv_overlapped(&self,
+ buf: &mut [u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>>;
+
+ /// Execute an overlapped send I/O operation on this UDP socket.
+ ///
+ /// This function will issue an overlapped I/O write (via `WSASendTo`) on
+ /// this socket to the address specified by `addr`. The provided buffer will
+ /// be written when the operation completes and the given `OVERLAPPED`
+ /// instance is used to track the overlapped operation.
+ ///
+ /// If the operation succeeds, `Ok(Some(n0)` is returned where `n` byte
+ /// were written. If the operation returns an error indicating that the I/O
+ /// is currently pending, `Ok(None)` is returned. Otherwise, the error
+ /// associated with the operation is returned and no overlapped operation
+ /// is enqueued.
+ ///
+ /// The number of bytes written will be returned as part of the completion
+ /// notification when the I/O finishes.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the `buf` and
+ /// `overlapped` pointers are valid until the end of the I/O operation. The
+ /// kernel also requires that `overlapped` is unique for this I/O operation
+ /// and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that these two input
+ /// pointers are valid until the I/O operation is completed, typically via
+ /// completion ports and waiting to receive the completion notification on
+ /// the port.
+ unsafe fn send_to_overlapped(&self,
+ buf: &[u8],
+ addr: &SocketAddr,
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>>;
+
+ /// Execute an overlapped send I/O operation on this UDP socket.
+ ///
+ /// This function will issue an overlapped I/O write (via `WSASend`) on
+ /// this socket to the address it was previously connected to. The provided
+ /// buffer will be written when the operation completes and the given `OVERLAPPED`
+ /// instance is used to track the overlapped operation.
+ ///
+ /// If the operation succeeds, `Ok(Some(n0)` is returned where `n` byte
+ /// were written. If the operation returns an error indicating that the I/O
+ /// is currently pending, `Ok(None)` is returned. Otherwise, the error
+ /// associated with the operation is returned and no overlapped operation
+ /// is enqueued.
+ ///
+ /// The number of bytes written will be returned as part of the completion
+ /// notification when the I/O finishes.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the `buf` and
+ /// `overlapped` pointers are valid until the end of the I/O operation. The
+ /// kernel also requires that `overlapped` is unique for this I/O operation
+ /// and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that these two input
+ /// pointers are valid until the I/O operation is completed, typically via
+ /// completion ports and waiting to receive the completion notification on
+ /// the port.
+ unsafe fn send_overlapped(&self,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>>;
+
+ /// Calls the `GetOverlappedResult` function to get the result of an
+ /// overlapped operation for this handle.
+ ///
+ /// This function takes the `OVERLAPPED` argument which must have been used
+ /// to initiate an overlapped I/O operation, and returns either the
+ /// successful number of bytes transferred during the operation or an error
+ /// if one occurred, along with the results of the `lpFlags` parameter of
+ /// the relevant operation, if applicable.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe as `overlapped` must have previously been used
+ /// to execute an operation for this handle, and it must also be a valid
+ /// pointer to an `OVERLAPPED` instance.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic
+ unsafe fn result(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<(usize, u32)>;
+}
+
+/// Additional methods for the `TcpBuilder` type in the `net2` library.
+pub trait TcpBuilderExt {
+ /// Attempt to consume the internal socket in this builder by executing an
+ /// overlapped connect operation.
+ ///
+ /// This function will issue a connect operation to the address specified on
+ /// the underlying socket, flagging it as an overlapped operation which will
+ /// complete asynchronously. If successful this function will return the
+ /// corresponding TCP stream.
+ ///
+ /// The `buf` argument provided is an initial buffer of data that should be
+ /// sent after the connection is initiated. It's acceptable to
+ /// pass an empty slice here.
+ ///
+ /// This function will also return whether the connect immediately
+ /// succeeded or not. If `None` is returned then the I/O operation is still
+ /// pending and will complete at a later date, and if `Some(bytes)` is
+ /// returned then that many bytes were transferred.
+ ///
+ /// Note that to succeed this requires that the underlying socket has
+ /// previously been bound via a call to `bind` to a local address.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the
+ /// `overlapped` and `buf` pointers to be valid until the end of the I/O
+ /// operation. The kernel also requires that `overlapped` is unique for
+ /// this I/O operation and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that this pointer is
+ /// valid until the I/O operation is completed, typically via completion
+ /// ports and waiting to receive the completion notification on the port.
+ unsafe fn connect_overlapped(&self,
+ addr: &SocketAddr,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<(TcpStream, Option<usize>)>;
+
+ /// Calls the `GetOverlappedResult` function to get the result of an
+ /// overlapped operation for this handle.
+ ///
+ /// This function takes the `OVERLAPPED` argument which must have been used
+ /// to initiate an overlapped I/O operation, and returns either the
+ /// successful number of bytes transferred during the operation or an error
+ /// if one occurred, along with the results of the `lpFlags` parameter of
+ /// the relevant operation, if applicable.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe as `overlapped` must have previously been used
+ /// to execute an operation for this handle, and it must also be a valid
+ /// pointer to an `OVERLAPPED` instance.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic
+ unsafe fn result(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<(usize, u32)>;
+}
+
+/// Additional methods for the `TcpListener` type in the standard library.
+pub trait TcpListenerExt {
+ /// Perform an accept operation on this listener, accepting a connection in
+ /// an overlapped fashion.
+ ///
+ /// This function will issue an I/O request to accept an incoming connection
+ /// with the specified overlapped instance. The `socket` provided must be a
+ /// configured but not bound or connected socket, and if successful this
+ /// will consume the internal socket of the builder to return a TCP stream.
+ ///
+ /// The `addrs` buffer provided will be filled in with the local and remote
+ /// addresses of the connection upon completion.
+ ///
+ /// If the accept succeeds immediately, `Ok(stream, true)` is returned. If
+ /// the connect indicates that the I/O is currently pending, `Ok(stream,
+ /// false)` is returned. Otherwise, the error associated with the operation
+ /// is returned and no overlapped operation is enqueued.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the
+ /// `addrs` and `overlapped` pointers are valid until the end of the I/O
+ /// operation. The kernel also requires that `overlapped` is unique for this
+ /// I/O operation and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that the pointers are
+ /// valid until the I/O operation is completed, typically via completion
+ /// ports and waiting to receive the completion notification on the port.
+ unsafe fn accept_overlapped(&self,
+ socket: &TcpBuilder,
+ addrs: &mut AcceptAddrsBuf,
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<(TcpStream, bool)>;
+
+ /// Once an `accept_overlapped` has finished, this function needs to be
+ /// called to finish the accept operation.
+ ///
+ /// Currently this just calls `setsockopt` with `SO_UPDATE_ACCEPT_CONTEXT`
+ /// to ensure that further functions like `getpeername` and `getsockname`
+ /// work correctly.
+ fn accept_complete(&self, socket: &TcpStream) -> io::Result<()>;
+
+ /// Calls the `GetOverlappedResult` function to get the result of an
+ /// overlapped operation for this handle.
+ ///
+ /// This function takes the `OVERLAPPED` argument which must have been used
+ /// to initiate an overlapped I/O operation, and returns either the
+ /// successful number of bytes transferred during the operation or an error
+ /// if one occurred, along with the results of the `lpFlags` parameter of
+ /// the relevant operation, if applicable.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe as `overlapped` must have previously been used
+ /// to execute an operation for this handle, and it must also be a valid
+ /// pointer to an `OVERLAPPED` instance.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic
+ unsafe fn result(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<(usize, u32)>;
+}
+
+#[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 last_err() -> io::Result<Option<usize>> {
+ let err = unsafe { WSAGetLastError() };
+ if err == WSA_IO_PENDING as i32 {
+ Ok(None)
+ } else {
+ Err(io::Error::from_raw_os_error(err))
+ }
+}
+
+fn cvt(i: c_int, size: DWORD) -> io::Result<Option<usize>> {
+ if i == SOCKET_ERROR {
+ last_err()
+ } else {
+ Ok(Some(size as usize))
+ }
+}
+
+fn socket_addr_to_ptrs(addr: &SocketAddr) -> (*const SOCKADDR, c_int) {
+ match *addr {
+ SocketAddr::V4(ref a) => {
+ (a as *const _ as *const _, mem::size_of::<SOCKADDR_IN>() as c_int)
+ }
+ SocketAddr::V6(ref a) => {
+ (a as *const _ as *const _, mem::size_of::<sockaddr_in6>() as c_int)
+ }
+ }
+}
+
+unsafe fn ptrs_to_socket_addr(ptr: *const SOCKADDR,
+ len: c_int) -> Option<SocketAddr> {
+ if (len as usize) < mem::size_of::<c_int>() {
+ return None
+ }
+ match (*ptr).sa_family as i32 {
+ AF_INET if len as usize >= mem::size_of::<SOCKADDR_IN>() => {
+ let b = &*(ptr as *const SOCKADDR_IN);
+ let ip = ntoh(b.sin_addr.S_un);
+ let ip = Ipv4Addr::new((ip >> 24) as u8,
+ (ip >> 16) as u8,
+ (ip >> 8) as u8,
+ (ip >> 0) as u8);
+ Some(SocketAddr::V4(SocketAddrV4::new(ip, ntoh(b.sin_port))))
+ }
+ AF_INET6 if len as usize >= mem::size_of::<sockaddr_in6>() => {
+ let b = &*(ptr as *const sockaddr_in6);
+ let arr = &b.sin6_addr.s6_addr;
+ let ip = Ipv6Addr::new(
+ ((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));
+ let addr = SocketAddrV6::new(ip, ntoh(b.sin6_port),
+ ntoh(b.sin6_flowinfo),
+ ntoh(b.sin6_scope_id));
+ Some(SocketAddr::V6(addr))
+ }
+ _ => None
+ }
+}
+
+unsafe fn slice2buf(slice: &[u8]) -> WSABUF {
+ WSABUF {
+ len: cmp::min(slice.len(), <u_long>::max_value() as usize) as u_long,
+ buf: slice.as_ptr() as *mut _,
+ }
+}
+
+unsafe fn result(socket: SOCKET, overlapped: *mut OVERLAPPED)
+ -> io::Result<(usize, u32)> {
+ let mut transferred = 0;
+ let mut flags = 0;
+ let r = WSAGetOverlappedResult(socket,
+ overlapped,
+ &mut transferred,
+ FALSE,
+ &mut flags);
+ if r == 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok((transferred as usize, flags))
+ }
+}
+
+impl TcpStreamExt for TcpStream {
+ unsafe fn read_overlapped(&self,
+ buf: &mut [u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ let mut buf = slice2buf(buf);
+ let mut flags = 0;
+ let mut bytes_read: DWORD = 0;
+ let r = WSARecv(self.as_raw_socket(), &mut buf, 1,
+ &mut bytes_read, &mut flags, overlapped, None);
+ cvt(r, bytes_read)
+ }
+
+ unsafe fn write_overlapped(&self,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ let mut buf = slice2buf(buf);
+ let mut bytes_written = 0;
+
+ // Note here that we capture the number of bytes written. The
+ // documentation on MSDN, however, states:
+ //
+ // > Use NULL for this parameter if the lpOverlapped parameter is not
+ // > NULL to avoid potentially erroneous results. This parameter can be
+ // > NULL only if the lpOverlapped parameter is not NULL.
+ //
+ // If we're not passing a null overlapped pointer here, then why are we
+ // then capturing the number of bytes! Well so it turns out that this is
+ // clearly faster to learn the bytes here rather than later calling
+ // `WSAGetOverlappedResult`, and in practice almost all implementations
+ // use this anyway [1].
+ //
+ // As a result we use this to and report back the result.
+ //
+ // [1]: https://github.com/carllerche/mio/pull/520#issuecomment-273983823
+ let r = WSASend(self.as_raw_socket(), &mut buf, 1,
+ &mut bytes_written, 0, overlapped, None);
+ cvt(r, bytes_written)
+ }
+
+ unsafe fn connect_overlapped(&self,
+ addr: &SocketAddr,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ connect_overlapped(self.as_raw_socket(), addr, buf, overlapped)
+ }
+
+ fn connect_complete(&self) -> io::Result<()> {
+ const SO_UPDATE_CONNECT_CONTEXT: c_int = 0x7010;
+ let result = unsafe {
+ setsockopt(self.as_raw_socket(),
+ SOL_SOCKET,
+ SO_UPDATE_CONNECT_CONTEXT,
+ 0 as *const _,
+ 0)
+ };
+ if result == 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ unsafe fn result(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<(usize, u32)> {
+ result(self.as_raw_socket(), overlapped)
+ }
+}
+
+unsafe fn connect_overlapped(socket: SOCKET,
+ addr: &SocketAddr,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ static CONNECTEX: WsaExtension = WsaExtension {
+ guid: GUID {
+ Data1: 0x25a207b9,
+ Data2: 0xddf3,
+ Data3: 0x4660,
+ Data4: [0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e],
+ },
+ val: ATOMIC_USIZE_INIT,
+ };
+ type ConnectEx = unsafe extern "system" fn(SOCKET, *const SOCKADDR,
+ c_int, PVOID, DWORD, LPDWORD,
+ LPOVERLAPPED) -> BOOL;
+
+ let ptr = try!(CONNECTEX.get(socket));
+ assert!(ptr != 0);
+ let connect_ex = mem::transmute::<_, ConnectEx>(ptr);
+
+ let (addr_buf, addr_len) = socket_addr_to_ptrs(addr);
+ let mut bytes_sent: DWORD = 0;
+ let r = connect_ex(socket, addr_buf, addr_len,
+ buf.as_ptr() as *mut _,
+ buf.len() as u32,
+ &mut bytes_sent, overlapped);
+ if r == TRUE {
+ Ok(Some(bytes_sent as usize))
+ } else {
+ last_err()
+ }
+}
+
+impl UdpSocketExt for UdpSocket {
+ unsafe fn recv_from_overlapped(&self,
+ buf: &mut [u8],
+ addr: *mut SocketAddrBuf,
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ let mut buf = slice2buf(buf);
+ let mut flags = 0;
+ let mut received_bytes: DWORD = 0;
+ let r = WSARecvFrom(self.as_raw_socket(), &mut buf, 1,
+ &mut received_bytes, &mut flags,
+ &mut (*addr).buf as *mut _ as *mut _,
+ &mut (*addr).len,
+ overlapped, None);
+ cvt(r, received_bytes)
+ }
+
+ unsafe fn recv_overlapped(&self,
+ buf: &mut [u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ let mut buf = slice2buf(buf);
+ let mut flags = 0;
+ let mut received_bytes: DWORD = 0;
+ let r = WSARecv(self.as_raw_socket(), &mut buf, 1,
+ &mut received_bytes, &mut flags,
+ overlapped, None);
+ cvt(r, received_bytes)
+ }
+
+ unsafe fn send_to_overlapped(&self,
+ buf: &[u8],
+ addr: &SocketAddr,
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ let (addr_buf, addr_len) = socket_addr_to_ptrs(addr);
+ let mut buf = slice2buf(buf);
+ let mut sent_bytes = 0;
+ let r = WSASendTo(self.as_raw_socket(), &mut buf, 1,
+ &mut sent_bytes, 0,
+ addr_buf as *const _, addr_len,
+ overlapped, None);
+ cvt(r, sent_bytes)
+ }
+
+ unsafe fn send_overlapped(&self,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ let mut buf = slice2buf(buf);
+ let mut sent_bytes = 0;
+ let r = WSASend(self.as_raw_socket(), &mut buf, 1,
+ &mut sent_bytes, 0,
+ overlapped, None);
+ cvt(r, sent_bytes)
+ }
+
+ unsafe fn result(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<(usize, u32)> {
+ result(self.as_raw_socket(), overlapped)
+ }
+}
+
+impl TcpBuilderExt for TcpBuilder {
+ unsafe fn connect_overlapped(&self,
+ addr: &SocketAddr,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<(TcpStream, Option<usize>)> {
+ connect_overlapped(self.as_raw_socket(), addr, buf, overlapped).map(|s| {
+ (self.to_tcp_stream().unwrap(), s)
+ })
+ }
+
+ unsafe fn result(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<(usize, u32)> {
+ result(self.as_raw_socket(), overlapped)
+ }
+}
+
+impl TcpListenerExt for TcpListener {
+ unsafe fn accept_overlapped(&self,
+ socket: &TcpBuilder,
+ addrs: &mut AcceptAddrsBuf,
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<(TcpStream, bool)> {
+ static ACCEPTEX: WsaExtension = WsaExtension {
+ guid: GUID {
+ Data1: 0xb5367df1,
+ Data2: 0xcbac,
+ Data3: 0x11cf,
+ Data4: [0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92],
+ },
+ val: ATOMIC_USIZE_INIT,
+ };
+ type AcceptEx = unsafe extern "system" fn(SOCKET, SOCKET, PVOID,
+ DWORD, DWORD, DWORD, LPDWORD,
+ LPOVERLAPPED) -> BOOL;
+
+ let ptr = try!(ACCEPTEX.get(self.as_raw_socket()));
+ assert!(ptr != 0);
+ let accept_ex = mem::transmute::<_, AcceptEx>(ptr);
+
+ let mut bytes = 0;
+ let (a, b, c, d) = (*addrs).args();
+ let r = accept_ex(self.as_raw_socket(), socket.as_raw_socket(),
+ a, b, c, d, &mut bytes, overlapped);
+ let succeeded = if r == TRUE {
+ true
+ } else {
+ try!(last_err());
+ false
+ };
+ // NB: this unwrap() should be guaranteed to succeed, and this is an
+ // assert that it does indeed succeed.
+ Ok((socket.to_tcp_stream().unwrap(), succeeded))
+ }
+
+ fn accept_complete(&self, socket: &TcpStream) -> io::Result<()> {
+ const SO_UPDATE_ACCEPT_CONTEXT: c_int = 0x700B;
+ let me = self.as_raw_socket();
+ let result = unsafe {
+ setsockopt(socket.as_raw_socket(),
+ SOL_SOCKET,
+ SO_UPDATE_ACCEPT_CONTEXT,
+ &me as *const _ as *const _,
+ mem::size_of_val(&me) as c_int)
+ };
+ if result == 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ unsafe fn result(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<(usize, u32)> {
+ result(self.as_raw_socket(), overlapped)
+ }
+}
+
+impl SocketAddrBuf {
+ /// Creates a new blank socket address buffer.
+ ///
+ /// This should be used before a call to `recv_from_overlapped` overlapped
+ /// to create an instance to pass down.
+ pub fn new() -> SocketAddrBuf {
+ SocketAddrBuf {
+ buf: unsafe { mem::zeroed() },
+ len: mem::size_of::<SOCKADDR_STORAGE>() as c_int,
+ }
+ }
+
+ /// Parses this buffer to return a standard socket address.
+ ///
+ /// This function should be called after the buffer has been filled in with
+ /// a call to `recv_from_overlapped` being completed. It will interpret the
+ /// address filled in and return the standard socket address type.
+ ///
+ /// If an error is encountered then `None` is returned.
+ pub fn to_socket_addr(&self) -> Option<SocketAddr> {
+ unsafe {
+ ptrs_to_socket_addr(&self.buf as *const _ as *const _, self.len)
+ }
+ }
+}
+
+static GETACCEPTEXSOCKADDRS: WsaExtension = WsaExtension {
+ guid: GUID {
+ Data1: 0xb5367df2,
+ Data2: 0xcbac,
+ Data3: 0x11cf,
+ Data4: [0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92],
+ },
+ val: ATOMIC_USIZE_INIT,
+};
+type GetAcceptExSockaddrs = unsafe extern "system" fn(PVOID, DWORD, DWORD, DWORD,
+ *mut LPSOCKADDR, LPINT,
+ *mut LPSOCKADDR, LPINT);
+
+impl AcceptAddrsBuf {
+ /// Creates a new blank buffer ready to be passed to a call to
+ /// `accept_overlapped`.
+ pub fn new() -> AcceptAddrsBuf {
+ unsafe { mem::zeroed() }
+ }
+
+ /// Parses the data contained in this address buffer, returning the parsed
+ /// result if successful.
+ ///
+ /// This function can be called after a call to `accept_overlapped` has
+ /// succeeded to parse out the data that was written in.
+ pub fn parse(&self, socket: &TcpListener) -> io::Result<AcceptAddrs> {
+ let mut ret = AcceptAddrs {
+ local: 0 as *mut _, local_len: 0,
+ remote: 0 as *mut _, remote_len: 0,
+ _data: self,
+ };
+ let ptr = try!(GETACCEPTEXSOCKADDRS.get(socket.as_raw_socket()));
+ assert!(ptr != 0);
+ unsafe {
+ let get_sockaddrs = mem::transmute::<_, GetAcceptExSockaddrs>(ptr);
+ let (a, b, c, d) = self.args();
+ get_sockaddrs(a, b, c, d,
+ &mut ret.local, &mut ret.local_len,
+ &mut ret.remote, &mut ret.remote_len);
+ Ok(ret)
+ }
+ }
+
+ fn args(&self) -> (PVOID, DWORD, DWORD, DWORD) {
+ let remote_offset = unsafe {
+ &(*(0 as *const AcceptAddrsBuf)).remote as *const _ as usize
+ };
+ (self as *const _ as *mut _, 0, remote_offset as DWORD,
+ (mem::size_of_val(self) - remote_offset) as DWORD)
+ }
+}
+
+impl<'a> AcceptAddrs<'a> {
+ /// Returns the local socket address contained in this buffer.
+ pub fn local(&self) -> Option<SocketAddr> {
+ unsafe { ptrs_to_socket_addr(self.local, self.local_len) }
+ }
+
+ /// Returns the remote socket address contained in this buffer.
+ pub fn remote(&self) -> Option<SocketAddr> {
+ unsafe { ptrs_to_socket_addr(self.remote, self.remote_len) }
+ }
+}
+
+impl WsaExtension {
+ fn get(&self, socket: SOCKET) -> io::Result<usize> {
+ let prev = self.val.load(Ordering::SeqCst);
+ if prev != 0 && !cfg!(debug_assertions) {
+ return Ok(prev)
+ }
+ let mut ret = 0 as usize;
+ let mut bytes = 0;
+ let r = unsafe {
+ WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &self.guid as *const _ as *mut _,
+ mem::size_of_val(&self.guid) as DWORD,
+ &mut ret as *mut _ as *mut _,
+ mem::size_of_val(&ret) as DWORD,
+ &mut bytes,
+ 0 as *mut _, None)
+ };
+ cvt(r, 0).map(|_| {
+ debug_assert_eq!(bytes as usize, mem::size_of_val(&ret));
+ debug_assert!(prev == 0 || prev == ret);
+ self.val.store(ret, Ordering::SeqCst);
+ ret
+ })
+
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::net::{TcpListener, UdpSocket, TcpStream, SocketAddr};
+ use std::thread;
+ use std::io::prelude::*;
+
+ use Overlapped;
+ use iocp::CompletionPort;
+ use net::{TcpStreamExt, UdpSocketExt, SocketAddrBuf};
+ use net::{TcpBuilderExt, TcpListenerExt, AcceptAddrsBuf};
+ use net2::TcpBuilder;
+
+ fn each_ip(f: &mut FnMut(SocketAddr)) {
+ f(t!("127.0.0.1:0".parse()));
+ f(t!("[::1]:0".parse()));
+ }
+
+ #[test]
+ fn tcp_read() {
+ each_ip(&mut |addr| {
+ let l = t!(TcpListener::bind(addr));
+ let addr = t!(l.local_addr());
+ let t = thread::spawn(move || {
+ let mut a = t!(l.accept()).0;
+ t!(a.write_all(&[1, 2, 3]));
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ let s = t!(TcpStream::connect(addr));
+ t!(cp.add_socket(1, &s));
+
+ let mut b = [0; 10];
+ let a = Overlapped::zero();
+ unsafe {
+ t!(s.read_overlapped(&mut b, a.raw()));
+ }
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 3);
+ assert_eq!(status.token(), 1);
+ assert_eq!(status.overlapped(), a.raw());
+ assert_eq!(&b[0..3], &[1, 2, 3]);
+
+ t!(t.join());
+ })
+ }
+
+ #[test]
+ fn tcp_write() {
+ each_ip(&mut |addr| {
+ let l = t!(TcpListener::bind(addr));
+ let addr = t!(l.local_addr());
+ let t = thread::spawn(move || {
+ let mut a = t!(l.accept()).0;
+ let mut b = [0; 10];
+ let n = t!(a.read(&mut b));
+ assert_eq!(n, 3);
+ assert_eq!(&b[0..3], &[1, 2, 3]);
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ let s = t!(TcpStream::connect(addr));
+ t!(cp.add_socket(1, &s));
+
+ let b = [1, 2, 3];
+ let a = Overlapped::zero();
+ unsafe {
+ t!(s.write_overlapped(&b, a.raw()));
+ }
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 3);
+ assert_eq!(status.token(), 1);
+ assert_eq!(status.overlapped(), a.raw());
+
+ t!(t.join());
+ })
+ }
+
+ #[test]
+ fn tcp_connect() {
+ each_ip(&mut |addr_template| {
+ let l = t!(TcpListener::bind(addr_template));
+ let addr = t!(l.local_addr());
+ let t = thread::spawn(move || {
+ t!(l.accept());
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ let builder = match addr {
+ SocketAddr::V4(..) => t!(TcpBuilder::new_v4()),
+ SocketAddr::V6(..) => t!(TcpBuilder::new_v6()),
+ };
+ t!(cp.add_socket(1, &builder));
+
+ let a = Overlapped::zero();
+ t!(builder.bind(addr_template));
+ let (s, _) = unsafe {
+ t!(builder.connect_overlapped(&addr, &[], a.raw()))
+ };
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 0);
+ assert_eq!(status.token(), 1);
+ assert_eq!(status.overlapped(), a.raw());
+ t!(s.connect_complete());
+
+ t!(t.join());
+ })
+ }
+
+ #[test]
+ fn udp_recv_from() {
+ each_ip(&mut |addr| {
+ let a = t!(UdpSocket::bind(addr));
+ let b = t!(UdpSocket::bind(addr));
+ let a_addr = t!(a.local_addr());
+ let b_addr = t!(b.local_addr());
+ let t = thread::spawn(move || {
+ t!(a.send_to(&[1, 2, 3], b_addr));
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ t!(cp.add_socket(1, &b));
+
+ let mut buf = [0; 10];
+ let a = Overlapped::zero();
+ let mut addr = SocketAddrBuf::new();
+ unsafe {
+ t!(b.recv_from_overlapped(&mut buf, &mut addr, a.raw()));
+ }
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 3);
+ assert_eq!(status.token(), 1);
+ assert_eq!(status.overlapped(), a.raw());
+ assert_eq!(&buf[..3], &[1, 2, 3]);
+ assert_eq!(addr.to_socket_addr(), Some(a_addr));
+
+ t!(t.join());
+ })
+ }
+
+ #[test]
+ fn udp_recv() {
+ each_ip(&mut |addr| {
+ let a = t!(UdpSocket::bind(addr));
+ let b = t!(UdpSocket::bind(addr));
+ let a_addr = t!(a.local_addr());
+ let b_addr = t!(b.local_addr());
+ assert!(b.connect(a_addr).is_ok());
+ assert!(a.connect(b_addr).is_ok());
+ let t = thread::spawn(move || {
+ t!(a.send_to(&[1, 2, 3], b_addr));
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ t!(cp.add_socket(1, &b));
+
+ let mut buf = [0; 10];
+ let a = Overlapped::zero();
+ unsafe {
+ t!(b.recv_overlapped(&mut buf, a.raw()));
+ }
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 3);
+ assert_eq!(status.token(), 1);
+ assert_eq!(status.overlapped(), a.raw());
+ assert_eq!(&buf[..3], &[1, 2, 3]);
+
+ t!(t.join());
+ })
+ }
+
+ #[test]
+ fn udp_send_to() {
+ each_ip(&mut |addr| {
+ let a = t!(UdpSocket::bind(addr));
+ let b = t!(UdpSocket::bind(addr));
+ let a_addr = t!(a.local_addr());
+ let b_addr = t!(b.local_addr());
+ let t = thread::spawn(move || {
+ let mut b = [0; 100];
+ let (n, addr) = t!(a.recv_from(&mut b));
+ assert_eq!(n, 3);
+ assert_eq!(addr, b_addr);
+ assert_eq!(&b[..3], &[1, 2, 3]);
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ t!(cp.add_socket(1, &b));
+
+ let a = Overlapped::zero();
+ unsafe {
+ t!(b.send_to_overlapped(&[1, 2, 3], &a_addr, a.raw()));
+ }
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 3);
+ assert_eq!(status.token(), 1);
+ assert_eq!(status.overlapped(), a.raw());
+
+ t!(t.join());
+ })
+ }
+
+ #[test]
+ fn udp_send() {
+ each_ip(&mut |addr| {
+ let a = t!(UdpSocket::bind(addr));
+ let b = t!(UdpSocket::bind(addr));
+ let a_addr = t!(a.local_addr());
+ let b_addr = t!(b.local_addr());
+ assert!(b.connect(a_addr).is_ok());
+ assert!(a.connect(b_addr).is_ok());
+ let t = thread::spawn(move || {
+ let mut b = [0; 100];
+ let (n, addr) = t!(a.recv_from(&mut b));
+ assert_eq!(n, 3);
+ assert_eq!(addr, b_addr);
+ assert_eq!(&b[..3], &[1, 2, 3]);
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ t!(cp.add_socket(1, &b));
+
+ let a = Overlapped::zero();
+ unsafe {
+ t!(b.send_overlapped(&[1, 2, 3], a.raw()));
+ }
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 3);
+ assert_eq!(status.token(), 1);
+ assert_eq!(status.overlapped(), a.raw());
+
+ t!(t.join());
+ })
+ }
+
+ #[test]
+ fn tcp_accept() {
+ each_ip(&mut |addr_template| {
+ let l = t!(TcpListener::bind(addr_template));
+ let addr = t!(l.local_addr());
+ let t = thread::spawn(move || {
+ let socket = t!(TcpStream::connect(addr));
+ (socket.local_addr().unwrap(), socket.peer_addr().unwrap())
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ let builder = match addr {
+ SocketAddr::V4(..) => t!(TcpBuilder::new_v4()),
+ SocketAddr::V6(..) => t!(TcpBuilder::new_v6()),
+ };
+ t!(cp.add_socket(1, &l));
+
+ let a = Overlapped::zero();
+ let mut addrs = AcceptAddrsBuf::new();
+ let (s, _) = unsafe {
+ t!(l.accept_overlapped(&builder, &mut addrs, a.raw()))
+ };
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 0);
+ assert_eq!(status.token(), 1);
+ assert_eq!(status.overlapped(), a.raw());
+ t!(l.accept_complete(&s));
+
+ let (remote, local) = t!(t.join());
+ let addrs = addrs.parse(&l).unwrap();
+ assert_eq!(addrs.local(), Some(local));
+ assert_eq!(addrs.remote(), Some(remote));
+ })
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/src/overlapped.rs
@@ -0,0 +1,66 @@
+use std::mem;
+
+use winapi::*;
+
+/// A wrapper around `OVERLAPPED` to provide "rustic" accessors and
+/// initializers.
+#[derive(Debug)]
+pub struct Overlapped(OVERLAPPED);
+
+unsafe impl Send for Overlapped {}
+unsafe impl Sync for Overlapped {}
+
+impl Overlapped {
+ /// Creates a new zeroed out instance of an overlapped I/O tracking state.
+ ///
+ /// This is suitable for passing to methods which will then later get
+ /// notified via an I/O Completion Port.
+ pub fn zero() -> Overlapped {
+ Overlapped(unsafe { mem::zeroed() })
+ }
+
+ /// Creates a new `Overlapped` function pointer from the underlying
+ /// `OVERLAPPED`, wrapping in the "rusty" wrapper for working with
+ /// accessors.
+ ///
+ /// # Unsafety
+ ///
+ /// This function doesn't validate `ptr` nor the lifetime of the returned
+ /// pointer at all, it's recommended to use this method with extreme
+ /// caution.
+ pub unsafe fn from_raw<'a>(ptr: *mut OVERLAPPED) -> &'a mut Overlapped {
+ &mut *(ptr as *mut Overlapped)
+ }
+
+ /// Gain access to the raw underlying data
+ pub fn raw(&self) -> *mut OVERLAPPED {
+ &self.0 as *const _ as *mut _
+ }
+
+ /// Sets the offset inside this overlapped structure.
+ ///
+ /// Note that for I/O operations in general this only has meaning for I/O
+ /// handles that are on a seeking device that supports the concept of an
+ /// offset.
+ pub fn set_offset(&mut self, offset: u64) {
+ self.0.Offset = offset as u32;
+ self.0.OffsetHigh = (offset >> 32) as u32;
+ }
+
+ /// Reads the offset inside this overlapped structure.
+ pub fn offset(&self) -> u64 {
+ (self.0.Offset as u64) | ((self.0.OffsetHigh as u64) << 32)
+ }
+
+ /// Sets the `hEvent` field of this structure.
+ ///
+ /// The event specified can be null.
+ pub fn set_event(&mut self, event: HANDLE) {
+ self.0.hEvent = event;
+ }
+
+ /// Reads the `hEvent` field of this structure, may return null.
+ pub fn event(&self) -> HANDLE {
+ self.0.hEvent
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/miow/src/pipe.rs
@@ -0,0 +1,611 @@
+//! Named pipes
+
+use std::ffi::OsStr;
+use std::fs::{OpenOptions, File};
+use std::io::prelude::*;
+use std::io;
+use std::os::windows::ffi::*;
+use std::os::windows::io::*;
+use std::time::Duration;
+
+use winapi::*;
+use kernel32::*;
+use handle::Handle;
+
+/// Readable half of an anonymous pipe.
+#[derive(Debug)]
+pub struct AnonRead(Handle);
+
+/// Writable half of an anonymous pipe.
+#[derive(Debug)]
+pub struct AnonWrite(Handle);
+
+/// A named pipe that can accept connections.
+#[derive(Debug)]
+pub struct NamedPipe(Handle);
+
+/// A builder structure for creating a new named pipe.
+#[derive(Debug)]
+pub struct NamedPipeBuilder {
+ name: Vec<u16>,
+ dwOpenMode: DWORD,
+ dwPipeMode: DWORD,
+ nMaxInstances: DWORD,
+ nOutBufferSize: DWORD,
+ nInBufferSize: DWORD,
+ nDefaultTimeOut: DWORD,
+}
+
+/// Creates a new anonymous in-memory pipe, returning the read/write ends of the
+/// pipe.
+///
+/// The buffer size for this pipe may also be specified, but the system will
+/// normally use this as a suggestion and it's not guaranteed that the buffer
+/// will be precisely this size.
+pub fn anonymous(buffer_size: u32) -> io::Result<(AnonRead, AnonWrite)> {
+ let mut read = 0 as HANDLE;
+ let mut write = 0 as HANDLE;
+ try!(::cvt(unsafe {
+ CreatePipe(&mut read, &mut write, 0 as *mut _, buffer_size)
+ }));
+ Ok((AnonRead(Handle::new(read)), AnonWrite(Handle::new(write))))
+}
+
+impl Read for AnonRead {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+}
+impl<'a> Read for &'a AnonRead {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+}
+
+impl AsRawHandle for AnonRead {
+ fn as_raw_handle(&self) -> HANDLE { self.0.raw() }
+}
+impl FromRawHandle for AnonRead {
+ unsafe fn from_raw_handle(handle: HANDLE) -> AnonRead {
+ AnonRead(Handle::new(handle))
+ }
+}
+impl IntoRawHandle for AnonRead {
+ fn into_raw_handle(self) -> HANDLE { self.0.into_raw() }
+}
+
+impl Write for AnonWrite {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+impl<'a> Write for &'a AnonWrite {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+impl AsRawHandle for AnonWrite {
+ fn as_raw_handle(&self) -> HANDLE { self.0.raw() }
+}
+impl FromRawHandle for AnonWrite {
+ unsafe fn from_raw_handle(handle: HANDLE) -> AnonWrite {
+ AnonWrite(Handle::new(handle))
+ }
+}
+impl IntoRawHandle for AnonWrite {
+ fn into_raw_handle(self) -> HANDLE { self.0.into_raw() }
+}
+
+/// A convenience function to connect to a named pipe.
+///
+/// This function will block the calling process until it can connect to the
+/// pipe server specified by `addr`. This will use `NamedPipe::wait` internally
+/// to block until it can connect.
+pub fn connect<A: AsRef<OsStr>>(addr: A) -> io::Result<File> {
+ _connect(addr.as_ref())
+}
+
+fn _connect(addr: &OsStr) -> io::Result<File> {
+ let mut r = OpenOptions::new();
+ let mut w = OpenOptions::new();
+ let mut rw = OpenOptions::new();
+ r.read(true);
+ w.write(true);
+ rw.read(true).write(true);
+ loop {
+ let res = rw.open(addr).or_else(|_| r.open(addr))
+ .or_else(|_| w.open(addr));
+ match res {
+ Ok(f) => return Ok(f),
+ Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32)
+ => {}
+ Err(e) => return Err(e),
+ }
+
+ try!(NamedPipe::wait(addr, Some(Duration::new(20, 0))));
+ }
+}
+
+impl NamedPipe {
+ /// Creates a new initial named pipe.
+ ///
+ /// This function is equivalent to:
+ ///
+ /// ```
+ /// use miow::pipe::NamedPipeBuilder;
+ ///
+ /// # let addr = "foo";
+ /// NamedPipeBuilder::new(addr)
+ /// .first(true)
+ /// .inbound(true)
+ /// .outbound(true)
+ /// .out_buffer_size(65536)
+ /// .in_buffer_size(65536)
+ /// .create();
+ /// ```
+ pub fn new<A: AsRef<OsStr>>(addr: A) -> io::Result<NamedPipe> {
+ NamedPipeBuilder::new(addr).create()
+ }
+
+ /// Waits until either a time-out interval elapses or an instance of the
+ /// specified named pipe is available for connection.
+ ///
+ /// If this function succeeds the process can create a `File` to connect to
+ /// the named pipe.
+ pub fn wait<A: AsRef<OsStr>>(addr: A, timeout: Option<Duration>)
+ -> io::Result<()> {
+ NamedPipe::_wait(addr.as_ref(), timeout)
+ }
+
+ fn _wait(addr: &OsStr, timeout: Option<Duration>) -> io::Result<()> {
+ let addr = addr.encode_wide().chain(Some(0)).collect::<Vec<_>>();
+ let timeout = ::dur2ms(timeout);
+ ::cvt(unsafe {
+ WaitNamedPipeW(addr.as_ptr(), timeout)
+ }).map(|_| ())
+ }
+
+ /// Connects this named pipe to a client, blocking until one becomes
+ /// available.
+ ///
+ /// This function will call the `ConnectNamedPipe` function to await for a
+ /// client to connect. This can be called immediately after the pipe is
+ /// created, or after it has been disconnected from a previous client.
+ pub fn connect(&self) -> io::Result<()> {
+ match ::cvt(unsafe { ConnectNamedPipe(self.0.raw(), 0 as *mut _) }) {
+ Ok(_) => Ok(()),
+ Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32)
+ => Ok(()),
+ Err(e) => Err(e),
+ }
+ }
+
+ /// Issue a connection request with the specified overlapped operation.
+ ///
+ /// This function will issue a request to connect a client to this server,
+ /// returning immediately after starting the overlapped operation.
+ ///
+ /// If this function immediately succeeds then `Ok(true)` is returned. If
+ /// the overlapped operation is enqueued and pending, then `Ok(false)` is
+ /// returned. Otherwise an error is returned indicating what went wrong.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the
+ /// `overlapped` pointer is valid until the end of the I/O operation. The
+ /// kernel also requires that `overlapped` is unique for this I/O operation
+ /// and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that this pointer is
+ /// valid until the I/O operation is completed, typically via completion
+ /// ports and waiting to receive the completion notification on the port.
+ pub unsafe fn connect_overlapped(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<bool> {
+ match ::cvt(ConnectNamedPipe(self.0.raw(), overlapped)) {
+ Ok(_) => Ok(true),
+ Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32)
+ => Ok(true),
+ Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32)
+ => Ok(false),
+ Err(e) => Err(e),
+ }
+ }
+
+ /// Disconnects this named pipe from any connected client.
+ pub fn disconnect(&self) -> io::Result<()> {
+ ::cvt(unsafe {
+ DisconnectNamedPipe(self.0.raw())
+ }).map(|_| ())
+ }
+
+ /// Issues an overlapped read operation to occur on this pipe.
+ ///
+ /// This function will issue an asynchronous read to occur in an overlapped
+ /// fashion, returning immediately. The `buf` provided will be filled in
+ /// with data and the request is tracked by the `overlapped` function
+ /// provided.
+ ///
+ /// If the operation succeeds immediately, `Ok(Some(n))` is returned where
+ /// `n` is the number of bytes read. If an asynchronous operation is
+ /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred
+ /// it is returned.
+ ///
+ /// When this operation completes (or if it completes immediately), another
+ /// mechanism must be used to learn how many bytes were transferred (such as
+ /// looking at the filed in the IOCP status message).
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the `buf` and
+ /// `overlapped` pointers to be valid until the end of the I/O operation.
+ /// The kernel also requires that `overlapped` is unique for this I/O
+ /// operation and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that the pointers are
+ /// valid until the I/O operation is completed, typically via completion
+ /// ports and waiting to receive the completion notification on the port.
+ pub unsafe fn read_overlapped(&self,
+ buf: &mut [u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ self.0.read_overlapped(buf, overlapped)
+ }
+
+ /// Issues an overlapped write operation to occur on this pipe.
+ ///
+ /// This function will issue an asynchronous write to occur in an overlapped
+ /// fashion, returning immediately. The `buf` provided will be filled in
+ /// with data and the request is tracked by the `overlapped` function
+ /// provided.
+ ///
+ /// If the operation succeeds immediately, `Ok(Some(n))` is returned where
+ /// `n` is the number of bytes written. If an asynchronous operation is
+ /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred
+ /// it is returned.
+ ///
+ /// When this operation completes (or if it completes immediately), another
+ /// mechanism must be used to learn how many bytes were transferred (such as
+ /// looking at the filed in the IOCP status message).
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because the kernel requires that the `buf` and
+ /// `overlapped` pointers to be valid until the end of the I/O operation.
+ /// The kernel also requires that `overlapped` is unique for this I/O
+ /// operation and is not in use for any other I/O.
+ ///
+ /// To safely use this function callers must ensure that the pointers are
+ /// valid until the I/O operation is completed, typically via completion
+ /// ports and waiting to receive the completion notification on the port.
+ pub unsafe fn write_overlapped(&self,
+ buf: &[u8],
+ overlapped: *mut OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ self.0.write_overlapped(buf, overlapped)
+ }
+
+ /// Calls the `GetOverlappedResult` function to get the result of an
+ /// overlapped operation for this handle.
+ ///
+ /// This function takes the `OVERLAPPED` argument which must have been used
+ /// to initiate an overlapped I/O operation, and returns either the
+ /// successful number of bytes transferred during the operation or an error
+ /// if one occurred.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe as `overlapped` must have previously been used
+ /// to execute an operation for this handle, and it must also be a valid
+ /// pointer to an `Overlapped` instance.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic
+ pub unsafe fn result(&self, overlapped: *mut OVERLAPPED)
+ -> io::Result<usize> {
+ let mut transferred = 0;
+ let r = GetOverlappedResult(self.0.raw(),
+ overlapped,
+ &mut transferred,
+ FALSE);
+ if r == 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(transferred as usize)
+ }
+ }
+}
+
+impl Read for NamedPipe {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+}
+impl<'a> Read for &'a NamedPipe {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+}
+
+impl Write for NamedPipe {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+ fn flush(&mut self) -> io::Result<()> {
+ <&NamedPipe as Write>::flush(&mut &*self)
+ }
+}
+impl<'a> Write for &'a NamedPipe {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+ fn flush(&mut self) -> io::Result<()> {
+ ::cvt(unsafe { FlushFileBuffers(self.0.raw()) }).map(|_| ())
+ }
+}
+
+impl AsRawHandle for NamedPipe {
+ fn as_raw_handle(&self) -> HANDLE { self.0.raw() }
+}
+impl FromRawHandle for NamedPipe {
+ unsafe fn from_raw_handle(handle: HANDLE) -> NamedPipe {
+ NamedPipe(Handle::new(handle))
+ }
+}
+impl IntoRawHandle for NamedPipe {
+ fn into_raw_handle(self) -> HANDLE { self.0.into_raw() }
+}
+
+fn flag(slot: &mut DWORD, on: bool, val: DWORD) {
+ if on {
+ *slot |= val;
+ } else {
+ *slot &= !val;
+ }
+}
+
+impl NamedPipeBuilder {
+ /// Creates a new named pipe builder with the default settings.
+ pub fn new<A: AsRef<OsStr>>(addr: A) -> NamedPipeBuilder {
+ NamedPipeBuilder {
+ name: addr.as_ref().encode_wide().chain(Some(0)).collect(),
+ dwOpenMode: PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE |
+ FILE_FLAG_OVERLAPPED,
+ dwPipeMode: PIPE_TYPE_BYTE,
+ nMaxInstances: PIPE_UNLIMITED_INSTANCES,
+ nOutBufferSize: 65536,
+ nInBufferSize: 65536,
+ nDefaultTimeOut: 0,
+ }
+ }
+
+ /// Indicates whether data is allowed to flow from the client to the server.
+ pub fn inbound(&mut self, allowed: bool) -> &mut Self {
+ flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_INBOUND);
+ self
+ }
+
+ /// Indicates whether data is allowed to flow from the server to the client.
+ pub fn outbound(&mut self, allowed: bool) -> &mut Self {
+ flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_OUTBOUND);
+ self
+ }
+
+ /// Indicates that this pipe must be the first instance.
+ ///
+ /// If set to true, then creation will fail if there's already an instance
+ /// elsewhere.
+ pub fn first(&mut self, first: bool) -> &mut Self {
+ flag(&mut self.dwOpenMode, first, FILE_FLAG_FIRST_PIPE_INSTANCE);
+ self
+ }
+
+ /// Indicates whether this server can accept remote clients or not.
+ pub fn accept_remote(&mut self, accept: bool) -> &mut Self {
+ flag(&mut self.dwPipeMode, !accept, PIPE_REJECT_REMOTE_CLIENTS);
+ self
+ }
+
+ /// Specifies the maximum number of instances of the server pipe that are
+ /// allowed.
+ ///
+ /// The first instance of a pipe can specify this value. A value of 255
+ /// indicates that there is no limit to the number of instances.
+ pub fn max_instances(&mut self, instances: u8) -> &mut Self {
+ self.nMaxInstances = instances as DWORD;
+ self
+ }
+
+ /// Specifies the number of bytes to reserver for the output buffer
+ pub fn out_buffer_size(&mut self, buffer: u32) -> &mut Self {
+ self.nOutBufferSize = buffer as DWORD;
+ self
+ }
+
+ /// Specifies the number of bytes to reserver for the input buffer
+ pub fn in_buffer_size(&mut self, buffer: u32) -> &mut Self {
+ self.nInBufferSize = buffer as DWORD;
+ self
+ }
+
+ /// Using the options in this builder, attempt to create a new named pipe.
+ ///
+ /// This function will call the `CreateNamedPipe` function and return the
+ /// result.
+ pub fn create(&mut self) -> io::Result<NamedPipe> {
+ let h = unsafe {
+ CreateNamedPipeW(self.name.as_ptr(),
+ self.dwOpenMode, self.dwPipeMode,
+ self.nMaxInstances, self.nOutBufferSize,
+ self.nInBufferSize, self.nDefaultTimeOut,
+ 0 as *mut _)
+ };
+ if h == INVALID_HANDLE_VALUE {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(NamedPipe(Handle::new(h)))
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::fs::{File, OpenOptions};
+ use std::io::prelude::*;
+ use std::sync::mpsc::channel;
+ use std::thread;
+ use std::time::Duration;
+
+ use rand::{thread_rng, Rng};
+
+ use super::{anonymous, NamedPipe, NamedPipeBuilder};
+ use iocp::CompletionPort;
+ use Overlapped;
+
+ fn name() -> String {
+ let name = thread_rng().gen_ascii_chars().take(30).collect::<String>();
+ format!(r"\\.\pipe\{}", name)
+ }
+
+ #[test]
+ fn anon() {
+ let (mut read, mut write) = t!(anonymous(256));
+ assert_eq!(t!(write.write(&[1, 2, 3])), 3);
+ let mut b = [0; 10];
+ assert_eq!(t!(read.read(&mut b)), 3);
+ assert_eq!(&b[..3], &[1, 2, 3]);
+ }
+
+ #[test]
+ fn named_not_first() {
+ let name = name();
+ let _a = t!(NamedPipe::new(&name));
+ assert!(NamedPipe::new(&name).is_err());
+
+ t!(NamedPipeBuilder::new(&name).first(false).create());
+ }
+
+ #[test]
+ fn named_connect() {
+ let name = name();
+ let a = t!(NamedPipe::new(&name));
+
+ let t = thread::spawn(move || {
+ t!(File::open(name));
+ });
+
+ t!(a.connect());
+ t!(a.disconnect());
+ t!(t.join());
+ }
+
+ #[test]
+ fn named_wait() {
+ let name = name();
+ let a = t!(NamedPipe::new(&name));
+
+ let (tx, rx) = channel();
+ let t = thread::spawn(move || {
+ t!(NamedPipe::wait(&name, None));
+ t!(File::open(&name));
+ assert!(NamedPipe::wait(&name, Some(Duration::from_millis(1))).is_err());
+ t!(tx.send(()));
+ });
+
+ t!(a.connect());
+ t!(rx.recv());
+ t!(a.disconnect());
+ t!(t.join());
+ }
+
+ #[test]
+ fn named_connect_overlapped() {
+ let name = name();
+ let a = t!(NamedPipe::new(&name));
+
+ let t = thread::spawn(move || {
+ t!(File::open(name));
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ t!(cp.add_handle(2, &a));
+
+ let over = Overlapped::zero();
+ unsafe {
+ t!(a.connect_overlapped(over.raw()));
+ }
+
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 0);
+ assert_eq!(status.token(), 2);
+ assert_eq!(status.overlapped(), over.raw());
+ t!(t.join());
+ }
+
+ #[test]
+ fn named_read_write() {
+ let name = name();
+ let mut a = t!(NamedPipe::new(&name));
+
+ let t = thread::spawn(move || {
+ let mut f = t!(OpenOptions::new().read(true).write(true).open(name));
+ t!(f.write_all(&[1, 2, 3]));
+ let mut b = [0; 10];
+ assert_eq!(t!(f.read(&mut b)), 3);
+ assert_eq!(&b[..3], &[1, 2, 3]);
+ });
+
+ t!(a.connect());
+ let mut b = [0; 10];
+ assert_eq!(t!(a.read(&mut b)), 3);
+ assert_eq!(&b[..3], &[1, 2, 3]);
+ t!(a.write_all(&[1, 2, 3]));
+ t!(a.flush());
+ t!(a.disconnect());
+ t!(t.join());
+ }
+
+ #[test]
+ fn named_read_overlapped() {
+ let name = name();
+ let a = t!(NamedPipe::new(&name));
+
+ let t = thread::spawn(move || {
+ let mut f = t!(File::create(name));
+ t!(f.write_all(&[1, 2, 3]));
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ t!(cp.add_handle(3, &a));
+ t!(a.connect());
+
+ let mut b = [0; 10];
+ let over = Overlapped::zero();
+ unsafe {
+ t!(a.read_overlapped(&mut b, over.raw()));
+ }
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 3);
+ assert_eq!(status.token(), 3);
+ assert_eq!(status.overlapped(), over.raw());
+ assert_eq!(&b[..3], &[1, 2, 3]);
+
+ t!(t.join());
+ }
+
+ #[test]
+ fn named_write_overlapped() {
+ let name = name();
+ let a = t!(NamedPipe::new(&name));
+
+ let t = thread::spawn(move || {
+ let mut f = t!(super::connect(name));
+ let mut b = [0; 10];
+ assert_eq!(t!(f.read(&mut b)), 3);
+ assert_eq!(&b[..3], &[1, 2, 3])
+ });
+
+ let cp = t!(CompletionPort::new(1));
+ t!(cp.add_handle(3, &a));
+ t!(a.connect());
+
+ let over = Overlapped::zero();
+ unsafe {
+ t!(a.write_overlapped(&[1, 2, 3], over.raw()));
+ }
+
+ let status = t!(cp.get(None));
+ assert_eq!(status.bytes_transferred(), 3);
+ assert_eq!(status.token(), 3);
+ assert_eq!(status.overlapped(), over.raw());
+
+ t!(t.join());
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"4c3bd4917e81d86c9d1b9783e5bfaf690f2f87ac8a53d4518fab5c57851d74a5","Cargo.toml":"71b916e2e9121e4d1ddd49750b04ed92cf292eb94872c5576deed51fe1a540b6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"c367926adcb26dd48a679ba370b127efd37fc7a51354b3c9176f0576f2efb17b","appveyor.yml":"6e3173d907ccfa65e289c99042cb29d4a23b9d1f4ec5bf7afa6c0d65365bab54","src/ext.rs":"0b5d073592fc0720b3ca9f8821c79f3f7ca0fbb62e5ca618a5c5d6daac506568","src/lib.rs":"c8eedd4215f5a71f7faf4117c6c65b766bfecb7480013937b548d2310eda7d42","src/socket.rs":"a76f72198e33de37b7cf46e7ecf03b1f5c29a20174fd189e0cb97a60975d15a9","src/sys/unix/impls.rs":"05f123226e8fe7559317d50864021650b2455d25d01a9aff1c65c01ae26cf4ef","src/sys/unix/mod.rs":"1ac3a75714fd7a5ad11d9b97a25e2dbb6a0fa6db529f2752a0d83ff0fc212eaf","src/sys/windows/impls.rs":"5e8824f5477184a57e79809a0ca8c00db75ba230648d321aec44019cc9c1a362","src/sys/windows/mod.rs":"de6896d64217816719c8b974fd2c7ba78379edcd6e33ae33ea8abe2d19b6e68d","src/tcp.rs":"0bebf5cca75714151de30c8f2d7697ca519c57da065e93ba81796bce04673f8d","src/udp.rs":"8af5a55a4ae5e4120ffe18dcc4dc24072e18da34bf3591a02b18653e5d3e8ac8","src/unix.rs":"fe9cdbd75ef2e1fafc128d1abb5f32500eaf0b674aa618d837e06ab1d0dc6687","src/utils.rs":"d31de5333a6fa2f5c99b64cc937be596888d9863264632e6bc6b36b30197fa5b","tests/all.rs":"12cb4616c842f655ece1b477664d41821f95b3051053da641b1d85026ee18274"},"package":"3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/.travis.yml
@@ -0,0 +1,31 @@
+language: rust
+rust:
+ - stable
+ - beta
+ - nightly
+sudo: false
+before_script:
+ - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
+script:
+ - if [ "$TRAVIS_RUST_VERSION" = "1.1.0" ]; then
+ cargo test --no-default-features;
+ else
+ cargo test;
+ fi
+ - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then
+ cargo test --features nightly;
+ cargo doc --features nightly --no-deps;
+ fi
+ - rustdoc --test README.md -L target/debug -L target/debug/deps
+after_success:
+ - travis-cargo --only nightly doc-upload
+notifications:
+ email:
+ on_success: never
+env:
+ global:
+ secure: "n7C4SSdi9Q1WcPxc9BKQi/vhPhhxCfK/ljqG0l8PpNhkJ1BzFgb/0O4zA2W1/JzHxp0VB7rGwRCTSZkePvH1ycZuNtIezFc2HktElpRGwmo8X2OHp2+GLkTKozjhV0qZho+XoQnB0zgZRAdTq+MSN2EpTUKsaNvZwrTK90MprUPKU06Hvq93oEWmDh0jyKee0LlMezS6ihTgNk43zIa6bNumIWoaUM9ePnN7IvKSnoiynKjrBU52GPF5cWKih35mTXNxXW89Ht2h1NhIAHwmUpNfyOsBb2LOfvathVitfqk81R6+1qWzFyWSHdFoDAM0HHs8sySFK3P2YVcAp4tNIBw29oAtCpSGK6XeDyxmEU9VAq2H7DzEaBnkZM5A4oNnJWsValBmY+8m21OwV/XRed+eiqg5WUfnjeEoBn/5BJxMsc+kkVztS1Yos1meHZazTIaSpICxJ8fieHnzTOKD3wKgHwXSQaCAQHAErM301DRlChkXj61txDCmLVrU4qVRSMrAQQFPUBeploNaQtvCr/JI7huOhw5A6DphnGH8bbNivwATuUnbvQRJF+VGU3yOkJieJAQzArjGQ1A+qMds+DKlfFH/mPMxQcKv7bEE7cTZ3DY8ZzJfMzsh6YIa/YP0hpDZ5z4tJaeEXRyNVPEAwMGk4pCITP949WaTs97XOpM="
+
+os:
+ - linux
+ - osx
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/Cargo.toml
@@ -0,0 +1,47 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "net2"
+version = "0.2.31"
+authors = ["Alex Crichton <alex@alexcrichton.com>"]
+description = "Extensions to the standard library's networking types as proposed in RFC 1158.\n"
+homepage = "https://github.com/rust-lang-nursery/net2-rs"
+documentation = "https://doc.rust-lang.org/net2-rs/"
+readme = "README.md"
+license = "MIT/Apache-2.0"
+repository = "https://github.com/rust-lang-nursery/net2-rs"
+[dependencies.cfg-if]
+version = "0.1"
+
+[features]
+nightly = []
+default = ["duration"]
+duration = []
+[target.i686-unknown-linux-gnu.dependencies.libc]
+version = "0.2.16"
+[target.x86_64-unknown-linux-gnu.dependencies.libc]
+version = "0.2.16"
+[target.i686-apple-darwin.dependencies.libc]
+version = "0.2.16"
+[target.x86_64-apple-darwin.dependencies.libc]
+version = "0.2.16"
+[target."cfg(windows)".dependencies.kernel32-sys]
+version = "0.2"
+
+[target."cfg(windows)".dependencies.winapi]
+version = "0.2"
+
+[target."cfg(windows)".dependencies.ws2_32-sys]
+version = "0.2"
+[target."cfg(unix)".dependencies.libc]
+version = "0.2.16"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/README.md
@@ -0,0 +1,26 @@
+# net2
+
+[![Build Status](https://travis-ci.org/rust-lang-nursery/net2-rs.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/net2-rs)
+[![Build status](https://ci.appveyor.com/api/projects/status/ns78f02jt2uvd2lp?svg=true)](https://ci.appveyor.com/project/alexcrichton/net2-rs)
+
+[Documentation](https://doc.rust-lang.org/net2-rs/)
+
+Extensions to the standard library's networking types, proposed in [RFC
+1158][rfc].
+
+
+[rfc]: https://github.com/alexcrichton/rfcs/blob/net2.1/text/0000-io-net-2.1.md
+
+```toml
+# Cargo.toml
+[dependencies]
+net2 = "0.2"
+```
+
+# License
+
+`net2-rs` is primarily distributed under the terms of both the MIT license and
+the Apache License (Version 2.0), with portions covered by various BSD-like
+licenses.
+
+See LICENSE-APACHE, and LICENSE-MIT for details.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/appveyor.yml
@@ -0,0 +1,17 @@
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+ - TARGET: i686-pc-windows-msvc
+ - TARGET: i686-pc-windows-gnu
+install:
+ - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
+ - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
+ - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
+ - SET PATH=%PATH%;C:\MinGW\bin
+ - rustc -V
+ - cargo -V
+
+build: false
+
+test_script:
+ - cargo test --verbose --features nightly --target %TARGET%
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/ext.rs
@@ -0,0 +1,1308 @@
+// 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(bad_style, dead_code)]
+
+use std::io;
+use std::mem;
+use std::net::{TcpStream, TcpListener, UdpSocket, Ipv4Addr, Ipv6Addr};
+use std::net::ToSocketAddrs;
+
+use {TcpBuilder, UdpBuilder, FromInner};
+use sys;
+use socket;
+
+cfg_if! {
+ if #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris",
+ target_env = "uclibc"))] {
+ use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
+ use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
+ } else {
+ // ...
+ }
+}
+
+use std::time::Duration;
+
+#[cfg(unix)] pub type Socket = c_int;
+#[cfg(unix)] use std::os::unix::prelude::*;
+#[cfg(unix)] use libc::*;
+#[cfg(windows)] pub type Socket = SOCKET;
+#[cfg(windows)] use std::os::windows::prelude::*;
+#[cfg(windows)] use ws2_32::*;
+#[cfg(windows)] use winapi::*;
+
+#[cfg(windows)] const SIO_KEEPALIVE_VALS: DWORD = 0x98000004;
+#[cfg(windows)]
+#[repr(C)]
+struct tcp_keepalive {
+ onoff: c_ulong,
+ keepalivetime: c_ulong,
+ keepaliveinterval: c_ulong,
+}
+
+#[cfg(windows)] fn v(opt: IPPROTO) -> c_int { opt.0 as c_int }
+#[cfg(unix)] fn v(opt: c_int) -> c_int { opt }
+
+pub fn set_opt<T: Copy>(sock: Socket, opt: c_int, val: c_int,
+ payload: T) -> io::Result<()> {
+ unsafe {
+ let payload = &payload as *const T as *const c_void;
+ try!(::cvt(setsockopt(sock, opt, val, payload as *const _,
+ mem::size_of::<T>() as socklen_t)));
+ Ok(())
+ }
+}
+
+pub fn get_opt<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 socklen_t;
+ try!(::cvt(getsockopt(sock, opt, val,
+ &mut slot as *mut _ as *mut _,
+ &mut len)));
+ assert_eq!(len as usize, mem::size_of::<T>());
+ Ok(slot)
+ }
+}
+
+/// Extension methods for the standard [`TcpStream` type][link] in `std::net`.
+///
+/// [link]: https://doc.rust-lang.org/std/net/struct.TcpStream.html
+pub trait TcpStreamExt {
+ /// 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.
+ fn set_nodelay(&self, nodelay: bool) -> io::Result<()>;
+
+ /// Gets the value of the `TCP_NODELAY` option on this socket.
+ ///
+ /// For more information about this option, see [`set_nodelay`][link].
+ ///
+ /// [link]: #tymethod.set_nodelay
+ fn nodelay(&self) -> io::Result<bool>;
+
+ /// Sets the value of the `SO_RCVBUF` option on this socket.
+ ///
+ /// Changes the size of the operating system's receive buffer associated with the socket.
+ fn set_recv_buffer_size(&self, size: usize) -> io::Result<()>;
+
+ /// Gets the value of the `SO_RCVBUF` option on this socket.
+ ///
+ /// For more information about this option, see [`set_recv_buffer_size`][link].
+ ///
+ /// [link]: #tymethod.set_recv_buffer_size
+ fn recv_buffer_size(&self) -> io::Result<usize>;
+
+ /// Sets the value of the `SO_SNDBUF` option on this socket.
+ ///
+ /// Changes the size of the operating system's send buffer associated with the socket.
+ fn set_send_buffer_size(&self, size: usize) -> io::Result<()>;
+
+ /// Gets the value of the `SO_SNDBUF` option on this socket.
+ ///
+ /// For more information about this option, see [`set_send_buffer`][link].
+ ///
+ /// [link]: #tymethod.set_send_buffer
+ fn send_buffer_size(&self) -> io::Result<usize>;
+
+ /// Sets whether keepalive messages are enabled to be sent on this socket.
+ ///
+ /// On Unix, this option will set the `SO_KEEPALIVE` as well as the
+ /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform).
+ /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option.
+ ///
+ /// If `None` is specified then keepalive messages are disabled, otherwise
+ /// the number of milliseconds specified will be the time to remain idle
+ /// before sending a TCP keepalive probe.
+ ///
+ /// Some platforms specify this value in seconds, so sub-second millisecond
+ /// specifications may be omitted.
+ fn set_keepalive_ms(&self, keepalive: Option<u32>) -> io::Result<()>;
+
+ /// Returns whether keepalive messages are enabled on this socket, and if so
+ /// the amount of milliseconds between them.
+ ///
+ /// For more information about this option, see [`set_keepalive_ms`][link].
+ ///
+ /// [link]: #tymethod.set_keepalive_ms
+ fn keepalive_ms(&self) -> io::Result<Option<u32>>;
+
+ /// Sets whether keepalive messages are enabled to be sent on this socket.
+ ///
+ /// On Unix, this option will set the `SO_KEEPALIVE` as well as the
+ /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform).
+ /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option.
+ ///
+ /// If `None` is specified then keepalive messages are disabled, otherwise
+ /// the duration specified will be the time to remain idle before sending a
+ /// TCP keepalive probe.
+ ///
+ /// Some platforms specify this value in seconds, so sub-second
+ /// specifications may be omitted.
+ fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()>;
+
+ /// Returns whether keepalive messages are enabled on this socket, and if so
+ /// the duration of time between them.
+ ///
+ /// For more information about this option, see [`set_keepalive`][link].
+ ///
+ /// [link]: #tymethod.set_keepalive
+ fn keepalive(&self) -> io::Result<Option<Duration>>;
+
+ /// Sets the `SO_RCVTIMEO` option for this socket.
+ ///
+ /// This option specifies the timeout, in milliseconds, of how long calls to
+ /// this socket's `read` function will wait before returning a timeout. A
+ /// value of `None` means that no read timeout should be specified and
+ /// otherwise `Some` indicates the number of milliseconds for the timeout.
+ fn set_read_timeout_ms(&self, val: Option<u32>) -> io::Result<()>;
+
+ /// Sets the `SO_RCVTIMEO` option for this socket.
+ ///
+ /// This option specifies the timeout of how long calls to this socket's
+ /// `read` function will wait before returning a timeout. A value of `None`
+ /// means that no read timeout should be specified and otherwise `Some`
+ /// indicates the number of duration of the timeout.
+ fn set_read_timeout(&self, val: Option<Duration>) -> io::Result<()>;
+
+ /// Gets the value of the `SO_RCVTIMEO` option for this socket.
+ ///
+ /// For more information about this option, see [`set_read_timeout_ms`][link].
+ ///
+ /// [link]: #tymethod.set_read_timeout_ms
+ fn read_timeout_ms(&self) -> io::Result<Option<u32>>;
+
+ /// Gets the value of the `SO_RCVTIMEO` option for this socket.
+ ///
+ /// For more information about this option, see [`set_read_timeout`][link].
+ ///
+ /// [link]: #tymethod.set_read_timeout
+ fn read_timeout(&self) -> io::Result<Option<Duration>>;
+
+ /// Sets the `SO_SNDTIMEO` option for this socket.
+ ///
+ /// This option specifies the timeout, in milliseconds, of how long calls to
+ /// this socket's `write` function will wait before returning a timeout. A
+ /// value of `None` means that no read timeout should be specified and
+ /// otherwise `Some` indicates the number of milliseconds for the timeout.
+ fn set_write_timeout_ms(&self, val: Option<u32>) -> io::Result<()>;
+
+ /// Sets the `SO_SNDTIMEO` option for this socket.
+ ///
+ /// This option specifies the timeout of how long calls to this socket's
+ /// `write` function will wait before returning a timeout. A value of `None`
+ /// means that no read timeout should be specified and otherwise `Some`
+ /// indicates the duration of the timeout.
+ fn set_write_timeout(&self, val: Option<Duration>) -> io::Result<()>;
+
+ /// Gets the value of the `SO_SNDTIMEO` option for this socket.
+ ///
+ /// For more information about this option, see [`set_write_timeout_ms`][link].
+ ///
+ /// [link]: #tymethod.set_write_timeout_ms
+ fn write_timeout_ms(&self) -> io::Result<Option<u32>>;
+
+ /// Gets the value of the `SO_SNDTIMEO` option for this socket.
+ ///
+ /// For more information about this option, see [`set_write_timeout`][link].
+ ///
+ /// [link]: #tymethod.set_write_timeout
+ fn write_timeout(&self) -> io::Result<Option<Duration>>;
+
+ /// 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.
+ fn set_ttl(&self, ttl: u32) -> io::Result<()>;
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see [`set_ttl`][link].
+ ///
+ /// [link]: #tymethod.set_ttl
+ fn ttl(&self) -> io::Result<u32>;
+
+ /// Sets the value for the `IPV6_V6ONLY` option on this socket.
+ ///
+ /// If this is set to `true` then the socket is restricted to sending and
+ /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
+ /// can bind the same port at the same time.
+ ///
+ /// If this is set to `false` then the socket can be used to send and
+ /// receive packets from an IPv4-mapped IPv6 address.
+ fn set_only_v6(&self, only_v6: bool) -> io::Result<()>;
+
+ /// Gets the value of the `IPV6_V6ONLY` option for this socket.
+ ///
+ /// For more information about this option, see [`set_only_v6`][link].
+ ///
+ /// [link]: #tymethod.set_only_v6
+ fn only_v6(&self) -> io::Result<bool>;
+
+ /// Executes a `connect` operation on this socket, establishing a connection
+ /// to the host specified by `addr`.
+ ///
+ /// Note that this normally does not need to be called on a `TcpStream`,
+ /// it's typically automatically done as part of a normal
+ /// `TcpStream::connect` function call or `TcpBuilder::connect` method call.
+ ///
+ /// This should only be necessary if an unconnected socket was extracted
+ /// from a `TcpBuilder` and then needs to be connected.
+ fn connect<T: ToSocketAddrs>(&self, addr: T) -> io::Result<()>;
+
+ /// 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.
+ fn take_error(&self) -> io::Result<Option<io::Error>>;
+
+ /// Moves this TCP stream into or out of nonblocking mode.
+ ///
+ /// On Unix this corresponds to calling fcntl, and on Windows this
+ /// corresponds to calling ioctlsocket.
+ fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>;
+
+ /// Sets the linger duration of this socket by setting the SO_LINGER option
+ fn set_linger(&self, dur: Option<Duration>) -> io::Result<()>;
+
+ /// reads the linger duration for this socket by getting the SO_LINGER option
+ fn linger(&self) -> io::Result<Option<Duration>>;
+}
+
+/// Extension methods for the standard [`TcpListener` type][link] in `std::net`.
+///
+/// [link]: https://doc.rust-lang.org/std/net/struct.TcpListener.html
+pub trait TcpListenerExt {
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This is the same as [`TcpStreamExt::set_ttl`][other].
+ ///
+ /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl
+ fn set_ttl(&self, ttl: u32) -> io::Result<()>;
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`TcpStreamExt::set_ttl`][link].
+ ///
+ /// [link]: trait.TcpStreamExt.html#tymethod.set_ttl
+ fn ttl(&self) -> io::Result<u32>;
+
+ /// Sets the value for the `IPV6_V6ONLY` option on this socket.
+ ///
+ /// For more information about this option, see
+ /// [`TcpStreamExt::set_only_v6`][link].
+ ///
+ /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6
+ fn set_only_v6(&self, only_v6: bool) -> io::Result<()>;
+
+ /// Gets the value of the `IPV6_V6ONLY` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`TcpStreamExt::set_only_v6`][link].
+ ///
+ /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6
+ fn only_v6(&self) -> io::Result<bool>;
+
+ /// 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.
+ fn take_error(&self) -> io::Result<Option<io::Error>>;
+
+ /// Moves this TCP listener into or out of nonblocking mode.
+ ///
+ /// For more information about this option, see
+ /// [`TcpStreamExt::set_nonblocking`][link].
+ ///
+ /// [link]: trait.TcpStreamExt.html#tymethod.set_nonblocking
+ fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>;
+
+ /// Sets the linger duration of this socket by setting the SO_LINGER option
+ fn set_linger(&self, dur: Option<Duration>) -> io::Result<()>;
+
+ /// reads the linger duration for this socket by getting the SO_LINGER option
+ fn linger(&self) -> io::Result<Option<Duration>>;
+}
+
+/// Extension methods for the standard [`UdpSocket` type][link] in `std::net`.
+///
+/// [link]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html
+pub trait UdpSocketExt {
+ /// Sets the value of the `SO_RCVBUF` option on this socket.
+ ///
+ /// Changes the size of the operating system's receive buffer associated with the socket.
+ fn set_recv_buffer_size(&self, size: usize) -> io::Result<()>;
+
+ /// Gets the value of the `SO_RCVBUF` option on this socket.
+ ///
+ /// For more information about this option, see [`set_recv_buffer_size`][link].
+ ///
+ /// [link]: #tymethod.set_recv_buffer_size
+ fn recv_buffer_size(&self) -> io::Result<usize>;
+
+ /// Sets the value of the `SO_SNDBUF` option on this socket.
+ ///
+ /// Changes the size of the operating system's send buffer associated with the socket.
+ fn set_send_buffer_size(&self, size: usize) -> io::Result<()>;
+
+ /// Gets the value of the `SO_SNDBUF` option on this socket.
+ ///
+ /// For more information about this option, see [`set_send_buffer`][link].
+ ///
+ /// [link]: #tymethod.set_send_buffer
+ fn send_buffer_size(&self) -> io::Result<usize>;
+
+ /// Sets the value of the `SO_BROADCAST` option for this socket.
+ ///
+ /// When enabled, this socket is allowed to send packets to a broadcast
+ /// address.
+ fn set_broadcast(&self, broadcast: bool) -> io::Result<()>;
+
+ /// Gets the value of the `SO_BROADCAST` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_broadcast`][link].
+ ///
+ /// [link]: #tymethod.set_broadcast
+ fn broadcast(&self) -> io::Result<bool>;
+
+ /// 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.
+ fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()>;
+
+ /// 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]: #tymethod.set_multicast_loop_v4
+ fn multicast_loop_v4(&self) -> io::Result<bool>;
+
+ /// 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.
+ fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()>;
+
+ /// 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]: #tymethod.set_multicast_ttl_v4
+ fn multicast_ttl_v4(&self) -> io::Result<u32>;
+
+ /// 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.
+ fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()>;
+
+ /// 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]: #tymethod.set_multicast_loop_v6
+ fn multicast_loop_v6(&self) -> io::Result<bool>;
+
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This is the same as [`TcpStreamExt::set_ttl`][other].
+ ///
+ /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl
+ fn set_ttl(&self, ttl: u32) -> io::Result<()>;
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`TcpStreamExt::set_ttl`][link].
+ ///
+ /// [link]: trait.TcpStreamExt.html#tymethod.set_ttl
+ fn ttl(&self) -> io::Result<u32>;
+
+ /// Sets the value for the `IPV6_V6ONLY` option on this socket.
+ ///
+ /// For more information about this option, see
+ /// [`TcpStreamExt::set_only_v6`][link].
+ ///
+ /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6
+ fn set_only_v6(&self, only_v6: bool) -> io::Result<()>;
+
+ /// Gets the value of the `IPV6_V6ONLY` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`TcpStreamExt::set_only_v6`][link].
+ ///
+ /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6
+ fn only_v6(&self) -> io::Result<bool>;
+
+ /// 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.
+ fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
+ -> io::Result<()>;
+
+ /// 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).
+ fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
+ -> io::Result<()>;
+
+ /// Executes an operation of the `IP_DROP_MEMBERSHIP` type.
+ ///
+ /// For more information about this option, see
+ /// [`join_multicast_v4`][link].
+ ///
+ /// [link]: #tymethod.join_multicast_v4
+ fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
+ -> io::Result<()>;
+
+ /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type.
+ ///
+ /// For more information about this option, see
+ /// [`join_multicast_v6`][link].
+ ///
+ /// [link]: #tymethod.join_multicast_v6
+ fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
+ -> io::Result<()>;
+
+ /// Sets the `SO_RCVTIMEO` option for this socket.
+ ///
+ /// This option specifies the timeout, in milliseconds, of how long calls to
+ /// this socket's `read` function will wait before returning a timeout. A
+ /// value of `None` means that no read timeout should be specified and
+ /// otherwise `Some` indicates the number of milliseconds for the timeout.
+ fn set_read_timeout_ms(&self, val: Option<u32>) -> io::Result<()>;
+
+ /// Sets the `SO_RCVTIMEO` option for this socket.
+ ///
+ /// This option specifies the timeout of how long calls to this socket's
+ /// `read` function will wait before returning a timeout. A value of `None`
+ /// means that no read timeout should be specified and otherwise `Some`
+ /// indicates the number of duration of the timeout.
+ fn set_read_timeout(&self, val: Option<Duration>) -> io::Result<()>;
+
+ /// Gets the value of the `SO_RCVTIMEO` option for this socket.
+ ///
+ /// For more information about this option, see [`set_read_timeout_ms`][link].
+ ///
+ /// [link]: #tymethod.set_read_timeout_ms
+ fn read_timeout_ms(&self) -> io::Result<Option<u32>>;
+
+ /// Gets the value of the `SO_RCVTIMEO` option for this socket.
+ ///
+ /// For more information about this option, see [`set_read_timeout`][link].
+ ///
+ /// [link]: #tymethod.set_read_timeout
+ fn read_timeout(&self) -> io::Result<Option<Duration>>;
+
+ /// Sets the `SO_SNDTIMEO` option for this socket.
+ ///
+ /// This option specifies the timeout, in milliseconds, of how long calls to
+ /// this socket's `write` function will wait before returning a timeout. A
+ /// value of `None` means that no read timeout should be specified and
+ /// otherwise `Some` indicates the number of milliseconds for the timeout.
+ fn set_write_timeout_ms(&self, val: Option<u32>) -> io::Result<()>;
+
+ /// Sets the `SO_SNDTIMEO` option for this socket.
+ ///
+ /// This option specifies the timeout of how long calls to this socket's
+ /// `write` function will wait before returning a timeout. A value of `None`
+ /// means that no read timeout should be specified and otherwise `Some`
+ /// indicates the duration of the timeout.
+ fn set_write_timeout(&self, val: Option<Duration>) -> io::Result<()>;
+
+ /// Gets the value of the `SO_SNDTIMEO` option for this socket.
+ ///
+ /// For more information about this option, see [`set_write_timeout_ms`][link].
+ ///
+ /// [link]: #tymethod.set_write_timeout_ms
+ fn write_timeout_ms(&self) -> io::Result<Option<u32>>;
+
+ /// Gets the value of the `SO_SNDTIMEO` option for this socket.
+ ///
+ /// For more information about this option, see [`set_write_timeout`][link].
+ ///
+ /// [link]: #tymethod.set_write_timeout
+ fn write_timeout(&self) -> io::Result<Option<Duration>>;
+
+ /// 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.
+ fn take_error(&self) -> io::Result<Option<io::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.
+ fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()>;
+
+ /// 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.
+ fn send(&self, buf: &[u8]) -> io::Result<usize>;
+
+ /// Receives data on the socket from 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.
+ fn recv(&self, buf: &mut [u8]) -> io::Result<usize>;
+
+ /// Moves this UDP socket into or out of nonblocking mode.
+ ///
+ /// For more information about this option, see
+ /// [`TcpStreamExt::set_nonblocking`][link].
+ ///
+ /// [link]: trait.TcpStreamExt.html#tymethod.set_nonblocking
+ fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>;
+}
+
+#[doc(hidden)]
+pub trait AsSock {
+ fn as_sock(&self) -> Socket;
+}
+
+#[cfg(unix)]
+impl<T: AsRawFd> AsSock for T {
+ fn as_sock(&self) -> Socket { self.as_raw_fd() }
+}
+#[cfg(windows)]
+impl<T: AsRawSocket> AsSock for T {
+ fn as_sock(&self) -> Socket { self.as_raw_socket() }
+}
+
+cfg_if! {
+ if #[cfg(any(target_os = "macos", target_os = "ios"))] {
+ use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION;
+ } else if #[cfg(any(target_os = "openbsd", target_os = "netbsd"))] {
+ use libc::SO_KEEPALIVE as KEEPALIVE_OPTION;
+ } else if #[cfg(unix)] {
+ use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION;
+ } else {
+ // ...
+ }
+}
+
+impl TcpStreamExt for TcpStream {
+
+ fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
+ // TODO: casting usize to a c_int should be a checked cast
+ set_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF, size as c_int)
+ }
+
+ fn recv_buffer_size(&self) -> io::Result<usize> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF).map(int2usize)
+ }
+
+ fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF, size as c_int)
+ }
+
+ fn send_buffer_size(&self) -> io::Result<usize> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF).map(int2usize)
+ }
+
+ fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ set_opt(self.as_sock(), v(IPPROTO_TCP), TCP_NODELAY,
+ nodelay as c_int)
+ }
+ fn nodelay(&self) -> io::Result<bool> {
+ get_opt(self.as_sock(), v(IPPROTO_TCP), TCP_NODELAY)
+ .map(int2bool)
+ }
+
+ fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
+ self.set_keepalive_ms(keepalive.map(dur2ms))
+ }
+
+ fn keepalive(&self) -> io::Result<Option<Duration>> {
+ self.keepalive_ms().map(|o| o.map(ms2dur))
+ }
+
+ #[cfg(unix)]
+ fn set_keepalive_ms(&self, keepalive: Option<u32>) -> io::Result<()> {
+ try!(set_opt(self.as_sock(), SOL_SOCKET, SO_KEEPALIVE,
+ keepalive.is_some() as c_int));
+ if let Some(dur) = keepalive {
+ try!(set_opt(self.as_sock(), v(IPPROTO_TCP), KEEPALIVE_OPTION,
+ (dur / 1000) as c_int));
+ }
+ Ok(())
+ }
+
+ #[cfg(unix)]
+ fn keepalive_ms(&self) -> io::Result<Option<u32>> {
+ let keepalive = try!(get_opt::<c_int>(self.as_sock(), SOL_SOCKET,
+ SO_KEEPALIVE));
+ if keepalive == 0 {
+ return Ok(None)
+ }
+ let secs = try!(get_opt::<c_int>(self.as_sock(), v(IPPROTO_TCP),
+ KEEPALIVE_OPTION));
+ Ok(Some((secs as u32) * 1000))
+ }
+
+ #[cfg(windows)]
+ fn set_keepalive_ms(&self, keepalive: Option<u32>) -> io::Result<()> {
+ let ms = keepalive.unwrap_or(INFINITE);
+ let ka = tcp_keepalive {
+ onoff: keepalive.is_some() as c_ulong,
+ keepalivetime: ms as c_ulong,
+ keepaliveinterval: ms as c_ulong,
+ };
+ unsafe {
+ ::cvt_win(WSAIoctl(self.as_sock(),
+ SIO_KEEPALIVE_VALS,
+ &ka as *const _ as *mut _,
+ mem::size_of_val(&ka) as DWORD,
+ 0 as *mut _,
+ 0,
+ 0 as *mut _,
+ 0 as *mut _,
+ None)).map(|_| ())
+ }
+ }
+
+ #[cfg(windows)]
+ fn keepalive_ms(&self) -> io::Result<Option<u32>> {
+ let mut ka = tcp_keepalive {
+ onoff: 0,
+ keepalivetime: 0,
+ keepaliveinterval: 0,
+ };
+ unsafe {
+ try!(::cvt_win(WSAIoctl(self.as_sock(),
+ SIO_KEEPALIVE_VALS,
+ 0 as *mut _,
+ 0,
+ &mut ka as *mut _ as *mut _,
+ mem::size_of_val(&ka) as DWORD,
+ 0 as *mut _,
+ 0 as *mut _,
+ None)));
+ }
+ Ok({
+ if ka.onoff == 0 {
+ None
+ } else {
+ timeout2ms(ka.keepaliveinterval as DWORD)
+ }
+ })
+ }
+
+ fn set_read_timeout_ms(&self, dur: Option<u32>) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO,
+ ms2timeout(dur))
+ }
+
+ fn read_timeout_ms(&self) -> io::Result<Option<u32>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO)
+ .map(timeout2ms)
+ }
+
+ fn set_write_timeout_ms(&self, dur: Option<u32>) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO,
+ ms2timeout(dur))
+ }
+
+ fn write_timeout_ms(&self) -> io::Result<Option<u32>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO)
+ .map(timeout2ms)
+ }
+
+ fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.set_read_timeout_ms(dur.map(dur2ms))
+ }
+
+ fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.read_timeout_ms().map(|o| o.map(ms2dur))
+ }
+
+ fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.set_write_timeout_ms(dur.map(dur2ms))
+ }
+
+ fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.write_timeout_ms().map(|o| o.map(ms2dur))
+ }
+
+ fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int)
+ }
+
+ fn ttl(&self) -> io::Result<u32> {
+ get_opt::<c_int>(self.as_sock(), IPPROTO_IP, IP_TTL)
+ .map(|b| b as u32)
+ }
+
+ fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int)
+ }
+
+ fn only_v6(&self) -> io::Result<bool> {
+ get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool)
+ }
+
+ fn connect<T: ToSocketAddrs>(&self, addr: T) -> io::Result<()> {
+ do_connect(self.as_sock(), addr)
+ }
+
+ fn take_error(&self) -> io::Result<Option<io::Error>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err)
+ }
+
+ fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ set_nonblocking(self.as_sock(), nonblocking)
+ }
+
+ fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur))
+ }
+
+ fn linger(&self) -> io::Result<Option<Duration>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur)
+ }
+}
+
+#[cfg(unix)]
+fn ms2timeout(dur: Option<u32>) -> timeval {
+ // TODO: be more rigorous
+ match dur {
+ Some(d) => timeval {
+ tv_sec: (d / 1000) as time_t,
+ tv_usec: (d % 1000) as suseconds_t,
+ },
+ None => timeval { tv_sec: 0, tv_usec: 0 },
+ }
+}
+
+#[cfg(unix)]
+fn timeout2ms(dur: timeval) -> Option<u32> {
+ if dur.tv_sec == 0 && dur.tv_usec == 0 {
+ None
+ } else {
+ Some(dur.tv_sec as u32 * 1000 + dur.tv_usec as u32 / 1000)
+ }
+}
+
+#[cfg(windows)]
+fn ms2timeout(dur: Option<u32>) -> DWORD {
+ dur.unwrap_or(0)
+}
+
+#[cfg(windows)]
+fn timeout2ms(dur: DWORD) -> Option<u32> {
+ if dur == 0 {
+ None
+ } else {
+ Some(dur)
+ }
+}
+
+fn linger2dur(linger_opt: linger) -> Option<Duration> {
+ if linger_opt.l_onoff == 0 {
+ None
+ }
+ else {
+ Some(Duration::from_secs(linger_opt.l_linger as u64))
+ }
+}
+
+#[cfg(windows)]
+fn dur2linger(dur: Option<Duration>) -> linger {
+ match dur {
+ Some(d) => {
+ linger {
+ l_onoff: 1,
+ l_linger: d.as_secs() as u16,
+ }
+ },
+ None => linger { l_onoff: 0, l_linger: 0 },
+ }
+}
+
+#[cfg(unix)]
+fn dur2linger(dur: Option<Duration>) -> linger {
+ match dur {
+ Some(d) => {
+ linger {
+ l_onoff: 1,
+ l_linger: d.as_secs() as c_int,
+ }
+ },
+ None => linger { l_onoff: 0, l_linger: 0 },
+ }
+}
+
+fn ms2dur(ms: u32) -> Duration {
+ Duration::new((ms as u64) / 1000, (ms as u32) % 1000 * 1_000_000)
+}
+
+fn dur2ms(dur: Duration) -> u32 {
+ (dur.as_secs() as u32 * 1000) + (dur.subsec_nanos() / 1_000_000)
+}
+
+pub fn int2bool(n: c_int) -> bool {
+ if n == 0 {false} else {true}
+}
+
+pub fn int2usize(n: c_int) -> usize {
+ // TODO: casting c_int to a usize should be a checked cast
+ n as usize
+}
+
+pub fn int2err(n: c_int) -> Option<io::Error> {
+ if n == 0 {
+ None
+ } else {
+ Some(io::Error::from_raw_os_error(n as i32))
+ }
+}
+
+impl UdpSocketExt for UdpSocket {
+
+ fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF, size as c_int)
+ }
+
+ fn recv_buffer_size(&self) -> io::Result<usize> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF).map(int2usize)
+ }
+
+ fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF, size as c_int)
+ }
+
+ fn send_buffer_size(&self) -> io::Result<usize> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF).map(int2usize)
+ }
+
+ fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_BROADCAST,
+ broadcast as c_int)
+ }
+ fn broadcast(&self) -> io::Result<bool> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_BROADCAST)
+ .map(int2bool)
+ }
+ fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
+ set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_LOOP,
+ multicast_loop_v4 as c_int)
+ }
+ fn multicast_loop_v4(&self) -> io::Result<bool> {
+ get_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_LOOP)
+ .map(int2bool)
+ }
+ fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
+ set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_TTL,
+ multicast_ttl_v4 as c_int)
+ }
+ fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ get_opt::<c_int>(self.as_sock(), IPPROTO_IP, IP_MULTICAST_TTL)
+ .map(|b| b as u32)
+ }
+ fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
+ set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_LOOP,
+ multicast_loop_v6 as c_int)
+ }
+ fn multicast_loop_v6(&self) -> io::Result<bool> {
+ get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_LOOP)
+ .map(int2bool)
+ }
+
+ fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int)
+ }
+
+ fn ttl(&self) -> io::Result<u32> {
+ get_opt::<c_int>(self.as_sock(), IPPROTO_IP, IP_TTL)
+ .map(|b| b as u32)
+ }
+
+ fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int)
+ }
+
+ fn only_v6(&self) -> io::Result<bool> {
+ get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool)
+ }
+
+ fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
+ -> io::Result<()> {
+ let mreq = ip_mreq {
+ imr_multiaddr: ip2in_addr(multiaddr),
+ imr_interface: ip2in_addr(interface),
+ };
+ set_opt(self.as_sock(), IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq)
+ }
+
+ fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
+ -> io::Result<()> {
+ let mreq = ipv6_mreq {
+ ipv6mr_multiaddr: ip2in6_addr(multiaddr),
+ ipv6mr_interface: to_ipv6mr_interface(interface),
+ };
+ set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_ADD_MEMBERSHIP,
+ mreq)
+ }
+
+ fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
+ -> io::Result<()> {
+ let mreq = ip_mreq {
+ imr_multiaddr: ip2in_addr(multiaddr),
+ imr_interface: ip2in_addr(interface),
+ };
+ set_opt(self.as_sock(), IPPROTO_IP, IP_DROP_MEMBERSHIP, mreq)
+ }
+
+ fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
+ -> io::Result<()> {
+ let mreq = ipv6_mreq {
+ ipv6mr_multiaddr: ip2in6_addr(multiaddr),
+ ipv6mr_interface: to_ipv6mr_interface(interface),
+ };
+ set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_DROP_MEMBERSHIP,
+ mreq)
+ }
+
+ fn set_read_timeout_ms(&self, dur: Option<u32>) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO,
+ ms2timeout(dur))
+ }
+
+ fn read_timeout_ms(&self) -> io::Result<Option<u32>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO)
+ .map(timeout2ms)
+ }
+
+ fn set_write_timeout_ms(&self, dur: Option<u32>) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO,
+ ms2timeout(dur))
+ }
+
+ fn write_timeout_ms(&self) -> io::Result<Option<u32>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO)
+ .map(timeout2ms)
+ }
+
+ fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.set_read_timeout_ms(dur.map(dur2ms))
+ }
+
+ fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.read_timeout_ms().map(|o| o.map(ms2dur))
+ }
+
+ fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.set_write_timeout_ms(dur.map(dur2ms))
+ }
+
+ fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.write_timeout_ms().map(|o| o.map(ms2dur))
+ }
+
+ fn take_error(&self) -> io::Result<Option<io::Error>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err)
+ }
+
+ fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
+ do_connect(self.as_sock(), addr)
+ }
+
+ #[cfg(unix)]
+ fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ unsafe {
+ ::cvt(send(self.as_sock(), buf.as_ptr() as *const _, buf.len(), 0)).map(|n| n as usize)
+ }
+ }
+
+ #[cfg(windows)]
+ fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ let len = ::std::cmp::min(buf.len(), c_int::max_value() as usize);
+ let buf = &buf[..len];
+ unsafe {
+ ::cvt(send(self.as_sock(), buf.as_ptr() as *const _, len as c_int, 0))
+ .map(|n| n as usize)
+ }
+ }
+
+ #[cfg(unix)]
+ fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ unsafe {
+ ::cvt(recv(self.as_sock(), buf.as_mut_ptr() as *mut _, buf.len(), 0))
+ .map(|n| n as usize)
+ }
+ }
+
+ #[cfg(windows)]
+ fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ let len = ::std::cmp::min(buf.len(), c_int::max_value() as usize);
+ let buf = &mut buf[..len];
+ unsafe {
+ ::cvt(recv(self.as_sock(), buf.as_mut_ptr() as *mut _, buf.len() as c_int, 0))
+ .map(|n| n as usize)
+ }
+ }
+
+ fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ set_nonblocking(self.as_sock(), nonblocking)
+ }
+}
+
+fn do_connect<A: ToSocketAddrs>(sock: Socket, addr: A) -> io::Result<()> {
+ let err = io::Error::new(io::ErrorKind::Other,
+ "no socket addresses resolved");
+ let addrs = try!(addr.to_socket_addrs());
+ let sys = sys::Socket::from_inner(sock);
+ let sock = socket::Socket::from_inner(sys);
+ let ret = addrs.fold(Err(err), |prev, addr| {
+ prev.or_else(|_| sock.connect(&addr))
+ });
+ mem::forget(sock);
+ return ret
+}
+
+#[cfg(unix)]
+fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> {
+ let mut nonblocking = nonblocking as c_ulong;
+ ::cvt(unsafe {
+ ioctl(sock, FIONBIO, &mut nonblocking)
+ }).map(|_| ())
+}
+
+#[cfg(windows)]
+fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> {
+ let mut nonblocking = nonblocking as c_ulong;
+ ::cvt(unsafe {
+ ioctlsocket(sock, FIONBIO as c_int, &mut nonblocking)
+ }).map(|_| ())
+}
+
+#[cfg(unix)]
+fn ip2in_addr(ip: &Ipv4Addr) -> in_addr {
+ let oct = ip.octets();
+ in_addr {
+ s_addr: ::hton(((oct[0] as u32) << 24) |
+ ((oct[1] as u32) << 16) |
+ ((oct[2] as u32) << 8) |
+ ((oct[3] as u32) << 0)),
+ }
+}
+
+#[cfg(windows)]
+fn ip2in_addr(ip: &Ipv4Addr) -> in_addr {
+ let oct = ip.octets();
+ in_addr {
+ S_un: ::hton(((oct[0] as u32) << 24) |
+ ((oct[1] as u32) << 16) |
+ ((oct[2] as u32) << 8) |
+ ((oct[3] as u32) << 0)),
+ }
+}
+
+#[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) -> c_uint {
+ value as c_uint
+}
+
+fn ip2in6_addr(ip: &Ipv6Addr) -> in6_addr {
+ let mut ret: in6_addr = unsafe { mem::zeroed() };
+ let seg = ip.segments();
+ ret.s6_addr = [
+ (seg[0] >> 8) as u8,
+ (seg[0] >> 0) as u8,
+ (seg[1] >> 8) as u8,
+ (seg[1] >> 0) as u8,
+ (seg[2] >> 8) as u8,
+ (seg[2] >> 0) as u8,
+ (seg[3] >> 8) as u8,
+ (seg[3] >> 0) as u8,
+ (seg[4] >> 8) as u8,
+ (seg[4] >> 0) as u8,
+ (seg[5] >> 8) as u8,
+ (seg[5] >> 0) as u8,
+ (seg[6] >> 8) as u8,
+ (seg[6] >> 0) as u8,
+ (seg[7] >> 8) as u8,
+ (seg[7] >> 0) as u8,
+ ];
+ return ret
+}
+
+impl TcpListenerExt for TcpListener {
+ fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int)
+ }
+
+ fn ttl(&self) -> io::Result<u32> {
+ get_opt::<c_int>(self.as_sock(), IPPROTO_IP, IP_TTL)
+ .map(|b| b as u32)
+ }
+
+ fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int)
+ }
+
+ fn only_v6(&self) -> io::Result<bool> {
+ get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool)
+ }
+
+ fn take_error(&self) -> io::Result<Option<io::Error>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err)
+ }
+
+ fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ set_nonblocking(self.as_sock(), nonblocking)
+ }
+
+ fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur))
+ }
+
+ fn linger(&self) -> io::Result<Option<Duration>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur)
+ }
+}
+
+impl TcpBuilder {
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This is the same as [`TcpStreamExt::set_ttl`][other].
+ ///
+ /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl
+ pub fn ttl(&self, ttl: u32) -> io::Result<&Self> {
+ set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int)
+ .map(|()| self)
+ }
+
+ /// Sets the value for the `IPV6_V6ONLY` option on this socket.
+ ///
+ /// This is the same as [`TcpStreamExt::set_only_v6`][other].
+ ///
+ /// [other]: trait.TcpStreamExt.html#tymethod.set_only_v6
+ pub fn only_v6(&self, only_v6: bool) -> io::Result<&Self> {
+ set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int)
+ .map(|()| self)
+ }
+
+ /// Set value for the `SO_REUSEADDR` option on this socket.
+ ///
+ /// This indicates that futher calls to `bind` may allow reuse of local
+ /// addresses. For IPv4 sockets this means that a socket may bind even when
+ /// there's a socket already listening on this port.
+ pub fn reuse_address(&self, reuse: bool) -> io::Result<&Self> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR,
+ reuse as c_int).map(|()| self)
+ }
+
+ /// Check the `SO_REUSEADDR` option on this socket.
+ pub fn get_reuse_address(&self) -> io::Result<bool> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR).map(int2bool)
+ }
+
+ /// 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.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err)
+ }
+
+ /// Sets the linger option for this socket
+ fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur))
+ }
+
+ /// Gets the linger option for this socket
+ fn linger(&self) -> io::Result<Option<Duration>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur)
+ }
+}
+
+impl UdpBuilder {
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This is the same as [`TcpStreamExt::set_ttl`][other].
+ ///
+ /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl
+ pub fn ttl(&self, ttl: u32) -> io::Result<&Self> {
+ set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int)
+ .map(|()| self)
+ }
+
+ /// Sets the value for the `IPV6_V6ONLY` option on this socket.
+ ///
+ /// This is the same as [`TcpStream::only_v6`][other].
+ ///
+ /// [other]: struct.TcpBuilder.html#method.only_v6
+ pub fn only_v6(&self, only_v6: bool) -> io::Result<&Self> {
+ set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int)
+ .map(|()| self)
+ }
+
+ /// Set value for the `SO_REUSEADDR` option on this socket.
+ ///
+ /// This is the same as [`TcpBuilder::reuse_address`][other].
+ ///
+ /// [other]: struct.TcpBuilder.html#method.reuse_address
+ pub fn reuse_address(&self, reuse: bool) -> io::Result<&Self> {
+ set_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR,
+ reuse as c_int).map(|()| self)
+ }
+
+ /// Check the `SO_REUSEADDR` option on this socket.
+ pub fn get_reuse_address(&self) -> io::Result<bool> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR).map(int2bool)
+ }
+
+ /// 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.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err)
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/lib.rs
@@ -0,0 +1,123 @@
+// 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.
+
+//! Extensions to `std::net` networking types.
+//!
+//! This crate implements a number of extensions to the standard `std::net`
+//! networking types, hopefully being slated for inclusion into the standard
+//! library in the future. The goal of this crate is to expose all sorts of
+//! cross-platform and platform-specific configuration options of UDP/TCP
+//! sockets. System APIs are wrapped with as thin a layer as possible instead of
+//! bundling multiple actions into one API call.
+//!
+//! More information about the design of this crate can be found in the
+//! [associated rfc][rfc]
+//!
+//! [rfc]: https://github.com/rust-lang/rfcs/pull/1158
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use net2::TcpBuilder;
+//!
+//! let tcp = TcpBuilder::new_v4().unwrap();
+//! tcp.reuse_address(true).unwrap()
+//! .only_v6(false).unwrap();
+//!
+//! let mut stream = tcp.connect("127.0.0.1:80").unwrap();
+//!
+//! // use `stream` as a TcpStream
+//! ```
+
+#![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/net2-rs")]
+#![deny(missing_docs, warnings)]
+
+
+#[cfg(unix)] extern crate libc;
+
+#[cfg(windows)] extern crate kernel32;
+#[cfg(windows)] extern crate winapi;
+#[cfg(windows)] extern crate ws2_32;
+
+#[macro_use] extern crate cfg_if;
+
+use std::io;
+use std::ops::Neg;
+use std::net::{ToSocketAddrs, SocketAddr};
+
+use utils::{One, NetInt};
+
+mod tcp;
+mod udp;
+mod socket;
+mod ext;
+mod utils;
+
+#[cfg(unix)] #[path = "sys/unix/mod.rs"] mod sys;
+#[cfg(windows)] #[path = "sys/windows/mod.rs"] mod sys;
+#[cfg(all(unix, not(any(target_os = "solaris"))))] pub mod unix;
+
+pub use tcp::TcpBuilder;
+pub use udp::UdpBuilder;
+pub use ext::{TcpStreamExt, TcpListenerExt, UdpSocketExt};
+
+fn one_addr<T: ToSocketAddrs>(tsa: T) -> io::Result<SocketAddr> {
+ let mut addrs = try!(tsa.to_socket_addrs());
+ let addr = match addrs.next() {
+ Some(addr) => addr,
+ None => return Err(io::Error::new(io::ErrorKind::Other,
+ "no socket addresses could be resolved"))
+ };
+ if addrs.next().is_none() {
+ Ok(addr)
+ } else {
+ Err(io::Error::new(io::ErrorKind::Other,
+ "more than one address resolved"))
+ }
+}
+
+fn cvt<T: One + PartialEq + Neg<Output=T>>(t: T) -> io::Result<T> {
+ let one: T = T::one();
+ if t == -one {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(t)
+ }
+}
+
+#[cfg(windows)]
+fn cvt_win<T: PartialEq + utils::Zero>(t: T) -> io::Result<T> {
+ if t == T::zero() {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(t)
+ }
+}
+
+fn hton<I: NetInt>(i: I) -> I { i.to_be() }
+
+fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }
+
+trait AsInner {
+ type Inner;
+ fn as_inner(&self) -> &Self::Inner;
+}
+
+trait FromInner {
+ type Inner;
+ fn from_inner(inner: Self::Inner) -> Self;
+}
+
+trait IntoInner {
+ type Inner;
+ fn into_inner(self) -> Self::Inner;
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/socket.rs
@@ -0,0 +1,143 @@
+// 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 std::fmt;
+use std::io;
+use std::mem;
+use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+#[cfg(unix)]
+use libc::c_int;
+#[cfg(windows)]
+use winapi::c_int;
+
+use sys;
+use sys::c;
+
+pub struct Socket {
+ inner: sys::Socket,
+}
+
+impl Socket {
+ pub fn new(family: c_int, ty: c_int) -> io::Result<Socket> {
+ Ok(Socket { inner: try!(sys::Socket::new(family, ty)) })
+ }
+
+ pub fn bind(&self, addr: &SocketAddr) -> io::Result<()> {
+ #[cfg(not(all(any(target_arch = "aarch64", target_arch = "x86_64"), target_os = "android")))]
+ use sys::c::socklen_t as len_t;
+ #[cfg(all(any(target_arch = "aarch64", target_arch = "x86_64"), target_os = "android"))]
+ use libc::c_int as len_t;
+
+ let (addr, len) = addr2raw(addr);
+ unsafe {
+ ::cvt(c::bind(self.inner.raw(), addr, len as len_t)).map(|_| ())
+ }
+ }
+
+ pub fn listen(&self, backlog: i32) -> io::Result<()> {
+ unsafe {
+ ::cvt(c::listen(self.inner.raw(), backlog)).map(|_| ())
+ }
+ }
+
+ pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
+ let (addr, len) = addr2raw(addr);
+ unsafe {
+ ::cvt(c::connect(self.inner.raw(), addr, len)).map(|_| ())
+ }
+ }
+
+ pub fn getsockname(&self) -> io::Result<SocketAddr> {
+ unsafe {
+ let mut storage: c::sockaddr_storage = mem::zeroed();
+ let mut len = mem::size_of_val(&storage) as c::socklen_t;
+ try!(::cvt(c::getsockname(self.inner.raw(),
+ &mut storage as *mut _ as *mut _,
+ &mut len)));
+ raw2addr(&storage, len)
+ }
+ }
+}
+
+impl fmt::Debug for Socket {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.raw().fmt(f)
+ }
+}
+
+impl ::AsInner for Socket {
+ type Inner = sys::Socket;
+ fn as_inner(&self) -> &sys::Socket { &self.inner }
+}
+
+impl ::FromInner for Socket {
+ type Inner = sys::Socket;
+ fn from_inner(sock: sys::Socket) -> Socket {
+ Socket { inner: sock }
+ }
+}
+
+impl ::IntoInner for Socket {
+ type Inner = sys::Socket;
+ fn into_inner(self) -> sys::Socket { self.inner }
+}
+
+fn addr2raw(addr: &SocketAddr) -> (*const c::sockaddr, c::socklen_t) {
+ match *addr {
+ 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)
+ }
+ }
+}
+
+fn raw2addr(storage: &c::sockaddr_storage, len: c::socklen_t) -> io::Result<SocketAddr> {
+ match storage.ss_family as c_int {
+ c::AF_INET => {
+ unsafe {
+ assert!(len as usize >= mem::size_of::<c::sockaddr_in>());
+ let sa = storage as *const _ as *const c::sockaddr_in;
+ let bits = c::sockaddr_in_u32(&(*sa));
+ let ip = Ipv4Addr::new((bits >> 24) as u8,
+ (bits >> 16) as u8,
+ (bits >> 8) as u8,
+ bits as u8);
+ Ok(SocketAddr::V4(SocketAddrV4::new(ip, ::ntoh((*sa).sin_port))))
+ }
+ }
+ c::AF_INET6 => {
+ unsafe {
+ assert!(len as usize >= mem::size_of::<c::sockaddr_in6>());
+
+ let sa = storage as *const _ as *const c::sockaddr_in6;
+ let arr = (*sa).sin6_addr.s6_addr;
+
+ let ip = Ipv6Addr::new(
+ (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),
+ );
+
+ Ok(SocketAddr::V6(SocketAddrV6::new(ip,
+ ::ntoh((*sa).sin6_port),
+ (*sa).sin6_flowinfo,
+ (*sa).sin6_scope_id)))
+ }
+ }
+ _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid argument")),
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/sys/unix/impls.rs
@@ -0,0 +1,44 @@
+// 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 std::os::unix::io::{FromRawFd, AsRawFd};
+use libc::c_int;
+
+use {TcpBuilder, UdpBuilder, FromInner, AsInner};
+use socket::Socket;
+use sys;
+
+impl FromRawFd for TcpBuilder {
+ unsafe fn from_raw_fd(fd: c_int) -> TcpBuilder {
+ let sock = sys::Socket::from_inner(fd);
+ TcpBuilder::from_inner(Socket::from_inner(sock))
+ }
+}
+
+impl AsRawFd for TcpBuilder {
+ fn as_raw_fd(&self) -> c_int {
+ // TODO: this unwrap() is very bad
+ self.as_inner().borrow().as_ref().unwrap().as_inner().raw()
+ }
+}
+
+impl FromRawFd for UdpBuilder {
+ unsafe fn from_raw_fd(fd: c_int) -> UdpBuilder {
+ let sock = sys::Socket::from_inner(fd);
+ UdpBuilder::from_inner(Socket::from_inner(sock))
+ }
+}
+
+impl AsRawFd for UdpBuilder {
+ fn as_raw_fd(&self) -> c_int {
+ // TODO: this unwrap() is very bad
+ self.as_inner().borrow().as_ref().unwrap().as_inner().raw()
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/sys/unix/mod.rs
@@ -0,0 +1,100 @@
+// 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 std::io;
+use std::mem;
+use std::net::{TcpListener, TcpStream, UdpSocket};
+use std::os::unix::io::FromRawFd;
+use libc::{self, c_int};
+#[cfg(not(any(target_os = "solaris", target_os = "emscripten")))]
+use libc::{ioctl, FIOCLEX};
+
+mod impls;
+
+pub mod c {
+ pub use libc::*;
+
+ pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 {
+ ::ntoh((*sa).sin_addr.s_addr)
+ }
+}
+
+pub struct Socket {
+ fd: c_int,
+}
+
+impl Socket {
+ #[cfg(not(any(target_os = "solaris", target_os = "emscripten")))]
+ pub fn new(family: c_int, ty: c_int) -> io::Result<Socket> {
+ unsafe {
+ // Linux >2.6.26 overloads the type argument to accept SOCK_CLOEXEC,
+ // avoiding a race with another thread running fork/exec between
+ // socket() and ioctl()
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ match ::cvt(libc::socket(family, ty | libc::SOCK_CLOEXEC, 0)) {
+ Ok(fd) => return Ok(Socket { fd: fd }),
+ // Older versions of Linux return EINVAL; fall back to ioctl
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
+ Err(e) => return Err(e),
+ }
+
+ let fd = try!(::cvt(libc::socket(family, ty, 0)));
+ ioctl(fd, FIOCLEX);
+ Ok(Socket { fd: fd })
+ }
+ }
+
+ // ioctl(FIOCLEX) is not supported by Solaris/Illumos or emscripten,
+ // use fcntl(FD_CLOEXEC) instead
+ #[cfg(any(target_os = "solaris", target_os = "emscripten"))]
+ pub fn new(family: c_int, ty: c_int) -> io::Result<Socket> {
+ unsafe {
+ let fd = try!(::cvt(libc::socket(family, ty, 0)));
+ libc::fcntl(fd, libc::FD_CLOEXEC);
+ Ok(Socket { fd: fd })
+ }
+ }
+
+ pub fn raw(&self) -> c_int { self.fd }
+
+ fn into_fd(self) -> c_int {
+ let fd = self.fd;
+ mem::forget(self);
+ fd
+ }
+
+ pub fn into_tcp_listener(self) -> TcpListener {
+ unsafe { TcpListener::from_raw_fd(self.into_fd()) }
+ }
+
+ pub fn into_tcp_stream(self) -> TcpStream {
+ unsafe { TcpStream::from_raw_fd(self.into_fd()) }
+ }
+
+ pub fn into_udp_socket(self) -> UdpSocket {
+ unsafe { UdpSocket::from_raw_fd(self.into_fd()) }
+ }
+}
+
+impl ::FromInner for Socket {
+ type Inner = c_int;
+ fn from_inner(fd: c_int) -> Socket {
+ Socket { fd: fd }
+ }
+}
+
+impl Drop for Socket {
+ fn drop(&mut self) {
+ unsafe {
+ let _ = libc::close(self.fd);
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/sys/windows/impls.rs
@@ -0,0 +1,44 @@
+// 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 std::os::windows::io::{FromRawSocket, AsRawSocket};
+use winapi::SOCKET;
+
+use {TcpBuilder, UdpBuilder, FromInner, AsInner};
+use socket::Socket;
+use sys;
+
+impl FromRawSocket for TcpBuilder {
+ unsafe fn from_raw_socket(fd: SOCKET) -> TcpBuilder {
+ let sock = sys::Socket::from_inner(fd);
+ TcpBuilder::from_inner(Socket::from_inner(sock))
+ }
+}
+
+impl AsRawSocket for TcpBuilder {
+ fn as_raw_socket(&self) -> SOCKET {
+ // TODO: this unwrap() is very bad
+ self.as_inner().borrow().as_ref().unwrap().as_inner().raw()
+ }
+}
+
+impl FromRawSocket for UdpBuilder {
+ unsafe fn from_raw_socket(fd: SOCKET) -> UdpBuilder {
+ let sock = sys::Socket::from_inner(fd);
+ UdpBuilder::from_inner(Socket::from_inner(sock))
+ }
+}
+
+impl AsRawSocket for UdpBuilder {
+ fn as_raw_socket(&self) -> SOCKET {
+ // TODO: this unwrap() is very bad
+ self.as_inner().borrow().as_ref().unwrap().as_inner().raw()
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/sys/windows/mod.rs
@@ -0,0 +1,110 @@
+// 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(bad_style)]
+
+use std::io;
+use std::mem;
+use std::net::{TcpListener, TcpStream, UdpSocket};
+use std::os::windows::io::FromRawSocket;
+use std::sync::{Once, ONCE_INIT};
+
+use winapi::*;
+use ws2_32::*;
+use kernel32::*;
+
+const WSA_FLAG_OVERLAPPED: DWORD = 0x01;
+const HANDLE_FLAG_INHERIT: DWORD = 0x00000001;
+
+pub mod c {
+ pub use winapi::*;
+ pub use ws2_32::*;
+
+ pub use winapi::SOCKADDR as sockaddr;
+ pub use winapi::SOCKADDR_STORAGE as sockaddr_storage;
+ pub use winapi::SOCKADDR_IN as sockaddr_in;
+
+ pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 {
+ ::ntoh(sa.sin_addr.S_un)
+ }
+}
+
+mod impls;
+
+fn init() {
+ static INIT: Once = ONCE_INIT;
+
+ INIT.call_once(|| {
+ // Initialize winsock through the standard library by just creating a
+ // dummy socket. Whether this is successful or not we drop the result as
+ // libstd will be sure to have initialized winsock.
+ let _ = UdpSocket::bind("127.0.0.1:34254");
+ });
+}
+
+pub struct Socket {
+ socket: SOCKET,
+}
+
+impl Socket {
+ pub fn new(family: c_int, ty: c_int) -> io::Result<Socket> {
+ init();
+ let socket = try!(unsafe {
+ match WSASocketW(family, ty, 0, 0 as *mut _, 0,
+ WSA_FLAG_OVERLAPPED) {
+ INVALID_SOCKET => Err(io::Error::last_os_error()),
+ n => Ok(Socket { socket: n }),
+ }
+ });
+ try!(socket.set_no_inherit());
+ Ok(socket)
+ }
+
+ pub fn raw(&self) -> SOCKET { self.socket }
+
+ fn into_socket(self) -> SOCKET {
+ let socket = self.socket;
+ mem::forget(self);
+ socket
+ }
+
+ pub fn into_tcp_listener(self) -> TcpListener {
+ unsafe { TcpListener::from_raw_socket(self.into_socket()) }
+ }
+
+ pub fn into_tcp_stream(self) -> TcpStream {
+ unsafe { TcpStream::from_raw_socket(self.into_socket()) }
+ }
+
+ pub fn into_udp_socket(self) -> UdpSocket {
+ unsafe { UdpSocket::from_raw_socket(self.into_socket()) }
+ }
+
+ fn set_no_inherit(&self) -> io::Result<()> {
+ ::cvt_win(unsafe {
+ SetHandleInformation(self.socket as HANDLE, HANDLE_FLAG_INHERIT, 0)
+ }).map(|_| ())
+ }
+}
+
+impl ::FromInner for Socket {
+ type Inner = SOCKET;
+ fn from_inner(socket: SOCKET) -> Socket {
+ Socket { socket: socket }
+ }
+}
+
+impl Drop for Socket {
+ fn drop(&mut self) {
+ unsafe {
+ let _ = closesocket(self.socket);
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/tcp.rs
@@ -0,0 +1,161 @@
+// 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 std::cell::RefCell;
+use std::io;
+use std::net::{SocketAddr, ToSocketAddrs, TcpListener, TcpStream};
+use std::fmt;
+
+use IntoInner;
+use socket::Socket;
+use sys::c;
+
+/// An "in progress" TCP socket which has not yet been connected or listened.
+///
+/// Allows configuration of a socket before one of these operations is executed.
+pub struct TcpBuilder {
+ socket: RefCell<Option<Socket>>,
+}
+
+impl TcpBuilder {
+ /// Constructs a new TcpBuilder with the `AF_INET` domain, the `SOCK_STREAM`
+ /// type, and with a protocol argument of 0.
+ ///
+ /// Note that passing other kinds of flags or arguments can be done through
+ /// the `FromRaw{Fd,Socket}` implementation.
+ pub fn new_v4() -> io::Result<TcpBuilder> {
+ Socket::new(c::AF_INET, c::SOCK_STREAM).map(::FromInner::from_inner)
+ }
+
+ /// Constructs a new TcpBuilder with the `AF_INET6` domain, the `SOCK_STREAM`
+ /// type, and with a protocol argument of 0.
+ ///
+ /// Note that passing other kinds of flags or arguments can be done through
+ /// the `FromRaw{Fd,Socket}` implementation.
+ pub fn new_v6() -> io::Result<TcpBuilder> {
+ Socket::new(c::AF_INET6, c::SOCK_STREAM).map(::FromInner::from_inner)
+ }
+
+ /// Binds this socket to the specified address.
+ ///
+ /// This function directly corresponds to the bind(2) function on Windows
+ /// and Unix.
+ pub fn bind<T>(&self, addr: T) -> io::Result<&TcpBuilder>
+ where T: ToSocketAddrs
+ {
+ self.with_socket(|sock| {
+ let addr = try!(::one_addr(addr));
+ sock.bind(&addr)
+ }).map(|()| self)
+ }
+
+ /// Mark a socket as ready to accept incoming connection requests using
+ /// accept()
+ ///
+ /// This function directly corresponds to the listen(2) function on Windows
+ /// and Unix.
+ ///
+ /// An error will be returned if `listen` or `connect` has already been
+ /// called on this builder.
+ pub fn listen(&self, backlog: i32) -> io::Result<TcpListener> {
+ self.with_socket(|sock| {
+ sock.listen(backlog)
+ }).and_then(|()| {
+ self.to_tcp_listener()
+ })
+ }
+
+ /// Initiate a connection on this socket to the specified address.
+ ///
+ /// This function directly corresponds to the connect(2) function on Windows
+ /// and Unix.
+ ///
+ /// An error will be returned if `listen` or `connect` has already been
+ /// called on this builder.
+ pub fn connect<T>(&self, addr: T) -> io::Result<TcpStream>
+ where T: ToSocketAddrs
+ {
+ self.with_socket(|sock| {
+ let err = io::Error::new(io::ErrorKind::Other,
+ "no socket addresses resolved");
+ try!(addr.to_socket_addrs()).fold(Err(err), |prev, addr| {
+ prev.or_else(|_| sock.connect(&addr))
+ })
+ }).and_then(|()| {
+ self.to_tcp_stream()
+ })
+ }
+
+ /// Converts this builder into a `TcpStream`
+ ///
+ /// This function will consume the internal socket and return it re-wrapped
+ /// as a `TcpStream`. An error will be returned if the internal socket has
+ /// already been consumed from a successful call to `connect`, `listen`,
+ /// etc.
+ pub fn to_tcp_stream(&self) -> io::Result<TcpStream> {
+ self.socket.borrow_mut().take().map(|s| s.into_inner().into_tcp_stream())
+ .ok_or(io::Error::new(io::ErrorKind::Other,
+ "socket has already been consumed"))
+ }
+
+ /// Converts this builder into a `TcpListener`
+ ///
+ /// This function will consume the internal socket and return it re-wrapped
+ /// as a `TcpListener`. An error will be returned if the internal socket has
+ /// already been consumed from a successful call to `connect`, `listen`,
+ /// etc.
+ pub fn to_tcp_listener(&self) -> io::Result<TcpListener> {
+ self.socket.borrow_mut().take()
+ .map(|s| s.into_inner().into_tcp_listener())
+ .ok_or(io::Error::new(io::ErrorKind::Other,
+ "socket has already been consumed"))
+ }
+
+ /// Returns the address of the local half of this TCP socket.
+ ///
+ /// An error will be returned if `listen` or `connect` has already been
+ /// called on this builder.
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ match *self.socket.borrow() {
+ Some(ref s) => s.getsockname(),
+ None => Err(io::Error::new(io::ErrorKind::Other,
+ "builder has already finished its socket")),
+ }
+ }
+
+ fn with_socket<F>(&self, f: F) -> io::Result<()>
+ where F: FnOnce(&Socket) -> io::Result<()>
+ {
+ match *self.socket.borrow() {
+ Some(ref s) => f(s),
+ None => Err(io::Error::new(io::ErrorKind::Other,
+ "builder has already finished its socket")),
+ }
+ }
+}
+
+impl fmt::Debug for TcpBuilder {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TcpBuilder {{ socket: {:?} }}",
+ self.socket.borrow().as_ref().unwrap())
+ }
+}
+
+impl ::AsInner for TcpBuilder {
+ type Inner = RefCell<Option<Socket>>;
+ fn as_inner(&self) -> &RefCell<Option<Socket>> { &self.socket }
+}
+
+impl ::FromInner for TcpBuilder {
+ type Inner = Socket;
+ fn from_inner(sock: Socket) -> TcpBuilder {
+ TcpBuilder { socket: RefCell::new(Some(sock)) }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/udp.rs
@@ -0,0 +1,89 @@
+// 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 std::cell::RefCell;
+use std::fmt;
+use std::io;
+use std::net::{ToSocketAddrs, UdpSocket};
+
+use IntoInner;
+use socket::Socket;
+use sys::c;
+
+/// An "in progress" UDP socket which has not yet been connected.
+///
+/// Allows configuration of a socket before the socket is connected.
+pub struct UdpBuilder {
+ socket: RefCell<Option<Socket>>,
+}
+
+impl UdpBuilder {
+ /// Constructs a new UdpBuilder with the `AF_INET` domain, the `SOCK_DGRAM`
+ /// type, and with a protocol argument of 0.
+ ///
+ /// Note that passing other kinds of flags or arguments can be done through
+ /// the `FromRaw{Fd,Socket}` implementation.
+ pub fn new_v4() -> io::Result<UdpBuilder> {
+ Socket::new(c::AF_INET, c::SOCK_DGRAM).map(::FromInner::from_inner)
+ }
+
+ /// Constructs a new UdpBuilder with the `AF_INET6` domain, the `SOCK_DGRAM`
+ /// type, and with a protocol argument of 0.
+ ///
+ /// Note that passing other kinds of flags or arguments can be done through
+ /// the `FromRaw{Fd,Socket}` implementation.
+ pub fn new_v6() -> io::Result<UdpBuilder> {
+ Socket::new(c::AF_INET6, c::SOCK_DGRAM).map(::FromInner::from_inner)
+ }
+
+ /// Binds this socket to the specified address.
+ ///
+ /// This function directly corresponds to the bind(2) function on Windows
+ /// and Unix.
+ pub fn bind<T>(&self, addr: T) -> io::Result<UdpSocket>
+ where T: ToSocketAddrs
+ {
+ try!(self.with_socket(|sock| {
+ let addr = try!(::one_addr(addr));
+ sock.bind(&addr)
+ }));
+ Ok(self.socket.borrow_mut().take().unwrap().into_inner().into_udp_socket())
+ }
+
+ fn with_socket<F>(&self, f: F) -> io::Result<()>
+ where F: FnOnce(&Socket) -> io::Result<()>
+ {
+ match *self.socket.borrow() {
+ Some(ref s) => f(s),
+ None => Err(io::Error::new(io::ErrorKind::Other,
+ "builder has already finished its socket")),
+ }
+ }
+}
+
+impl fmt::Debug for UdpBuilder {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "UdpBuilder {{ socket: {:?} }}",
+ self.socket.borrow().as_ref().unwrap())
+ }
+}
+
+impl ::AsInner for UdpBuilder {
+ type Inner = RefCell<Option<Socket>>;
+ fn as_inner(&self) -> &RefCell<Option<Socket>> { &self.socket }
+}
+
+impl ::FromInner for UdpBuilder {
+ type Inner = Socket;
+ fn from_inner(sock: Socket) -> UdpBuilder {
+ UdpBuilder { socket: RefCell::new(Some(sock)) }
+ }
+}
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/unix.rs
@@ -0,0 +1,57 @@
+//! Unix-specific extensions to the `std::net` types.
+
+use std::io;
+use sys::c::{self, c_int};
+
+use {TcpBuilder, UdpBuilder};
+use ext::{self, AsSock};
+
+/// Unix-specific extensions for the `TcpBuilder` type in this library.
+pub trait UnixTcpBuilderExt {
+ /// Set value for the `SO_REUSEPORT` option on this socket.
+ ///
+ /// This indicates that futher calls to `bind` may allow reuse of local
+ /// addresses. For IPv4 sockets this means that a socket may bind even when
+ /// there's a socket already listening on this port.
+ fn reuse_port(&self, reuse: bool) -> io::Result<&Self>;
+
+ /// Check the value of the `SO_REUSEPORT` option on this socket.
+ fn get_reuse_port(&self) -> io::Result<bool>;
+}
+
+impl UnixTcpBuilderExt for TcpBuilder {
+ fn reuse_port(&self, reuse: bool) -> io::Result<&Self> {
+ ext::set_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT,
+ reuse as c_int).map(|()| self)
+ }
+
+ fn get_reuse_port(&self) -> io::Result<bool> {
+ ext::get_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT)
+ .map(ext::int2bool)
+ }
+}
+
+/// Unix-specific extensions for the `UdpBuilder` type in this library.
+pub trait UnixUdpBuilderExt {
+ /// Set value for the `SO_REUSEPORT` option on this socket.
+ ///
+ /// This indicates that futher calls to `bind` may allow reuse of local
+ /// addresses. For IPv4 sockets this means that a socket may bind even when
+ /// there's a socket already listening on this port.
+ fn reuse_port(&self, reuse: bool) -> io::Result<&Self>;
+
+ /// Check the value of the `SO_REUSEPORT` option on this socket.
+ fn get_reuse_port(&self) -> io::Result<bool>;
+}
+
+impl UnixUdpBuilderExt for UdpBuilder {
+ fn reuse_port(&self, reuse: bool) -> io::Result<&Self> {
+ ext::set_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT,
+ reuse as c_int).map(|()| self)
+ }
+
+ fn get_reuse_port(&self) -> io::Result<bool> {
+ ext::get_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT)
+ .map(ext::int2bool)
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/src/utils.rs
@@ -0,0 +1,51 @@
+// 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(hidden)]
+pub 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 }
+
+#[doc(hidden)]
+pub trait One {
+ fn one() -> Self;
+}
+
+macro_rules! one {
+ ($($t:ident)*) => ($(
+ impl One for $t { fn one() -> $t { 1 } }
+ )*)
+}
+
+one! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
+
+
+#[doc(hidden)]
+pub trait Zero {
+ fn zero() -> Self;
+}
+
+macro_rules! zero {
+ ($($t:ident)*) => ($(
+ impl Zero for $t { fn zero() -> $t { 0 } }
+ )*)
+}
+
+zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/net2/tests/all.rs
@@ -0,0 +1,45 @@
+extern crate net2;
+
+use std::net::{TcpStream, IpAddr, Ipv4Addr, Ipv6Addr};
+use std::io::prelude::*;
+use std::thread;
+
+use net2::TcpBuilder;
+
+macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+ })
+}
+
+#[test]
+fn smoke_build_listener() {
+ let b = t!(TcpBuilder::new_v4());
+ t!(b.bind("127.0.0.1:0"));
+
+ let addr = t!(b.local_addr());
+ assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+
+ let listener = t!(b.listen(200));
+
+ let t = thread::spawn(move || {
+ let mut s = t!(listener.accept()).0;
+ let mut b = [0; 4];
+ t!(s.read(&mut b));
+ assert_eq!(b, [1, 2, 3, 0]);
+ });
+
+ let mut stream = t!(TcpStream::connect(&addr));
+ t!(stream.write(&[1,2,3]));
+ t.join().unwrap();
+}
+
+#[test]
+fn smoke_build_listener_v6() {
+ let b = t!(TcpBuilder::new_v6());
+ t!(b.bind("::1:0"));
+
+ let addr = t!(b.local_addr());
+ assert_eq!(addr.ip(), IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)));
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/slab/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","Cargo.toml":"4cd8cbaedfe34dd4e0cc476e1484dc950b7ae90b693073fa89a298b014e6c0a1","README.md":"36ba748d4deb1875f5355dbf997be6ef1cb857709d78db7127c24d640e90300a","src/lib.rs":"003277f46755d1870148756841dbaad216109812cd659e4862e220e7a5b0c963"},"package":"17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/slab/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+
+name = "slab"
+version = "0.3.0"
+license = "MIT"
+authors = ["Carl Lerche <me@carllerche.com>"]
+description = "Simple slab allocator"
+documentation = "https://docs.rs/slab/0.3.0/slab/"
+homepage = "https://github.com/carllerche/slab"
+repository = "https://github.com/carllerche/slab"
+readme = "README.md"
+keywords = ["slab", "allocator"]
+exclude = [
+ ".gitignore",
+ ".travis.yml",
+ "test/**/*",
+]
new file mode 100644
--- /dev/null
+++ b/third_party/rust/slab/README.md
@@ -0,0 +1,3 @@
+Slab Allocator for Rust
+
+Preallocate memory for values of a given type.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/slab/src/lib.rs
@@ -0,0 +1,837 @@
+use std::{fmt, mem, usize};
+use std::iter::IntoIterator;
+use std::ops;
+use std::marker::PhantomData;
+
+/// A preallocated chunk of memory for storing objects of the same type.
+pub struct Slab<T, I = usize> {
+ // Chunk of memory
+ entries: Vec<Slot<T>>,
+
+ // Number of Filled elements currently in the slab
+ len: usize,
+
+ // Offset of the next available slot in the slab. Set to the slab's
+ // capacity when the slab is full.
+ next: usize,
+
+ _marker: PhantomData<I>,
+}
+
+/// A handle to an occupied slot in the `Slab`
+pub struct Entry<'a, T: 'a, I: 'a> {
+ slab: &'a mut Slab<T, I>,
+ idx: usize,
+}
+
+/// A handle to a vacant slot in the `Slab`
+pub struct VacantEntry<'a, T: 'a, I: 'a> {
+ slab: &'a mut Slab<T, I>,
+ idx: usize,
+}
+
+/// An iterator over the values stored in the `Slab`
+pub struct Iter<'a, T: 'a, I: 'a> {
+ slab: &'a Slab<T, I>,
+ cur_idx: usize,
+ yielded: usize,
+}
+
+/// A mutable iterator over the values stored in the `Slab`
+pub struct IterMut<'a, T: 'a, I: 'a> {
+ slab: *mut Slab<T, I>,
+ cur_idx: usize,
+ yielded: usize,
+ _marker: PhantomData<&'a mut ()>,
+}
+
+enum Slot<T> {
+ Empty(usize),
+ Filled(T),
+ Invalid,
+}
+
+unsafe impl<T, I> Send for Slab<T, I> where T: Send {}
+
+macro_rules! some {
+ ($expr:expr) => (match $expr {
+ Some(val) => val,
+ None => return None,
+ })
+}
+
+impl<T, I> Slab<T, I> {
+ /// Returns an empty `Slab` with the requested capacity
+ pub fn with_capacity(capacity: usize) -> Slab<T, I> {
+ let entries = (1..capacity + 1)
+ .map(Slot::Empty)
+ .collect::<Vec<_>>();
+
+ Slab {
+ entries: entries,
+ next: 0,
+ len: 0,
+ _marker: PhantomData,
+ }
+ }
+
+ /// Returns the number of values stored by the `Slab`
+ pub fn len(&self) -> usize {
+ self.len
+ }
+
+ /// Returns the total capacity of the `Slab`
+ pub fn capacity(&self) -> usize {
+ self.entries.len()
+ }
+
+ /// Returns true if the `Slab` is storing no values
+ pub fn is_empty(&self) -> bool {
+ self.len == 0
+ }
+
+ /// Returns the number of available slots remaining in the `Slab`
+ pub fn available(&self) -> usize {
+ self.entries.len() - self.len
+ }
+
+ /// Returns true if the `Slab` has available slots
+ pub fn has_available(&self) -> bool {
+ self.available() > 0
+ }
+}
+
+impl<T, I: Into<usize> + From<usize>> Slab<T, I> {
+ /// Returns true if the `Slab` contains a value for the given token
+ pub fn contains(&self, idx: I) -> bool {
+ self.get(idx).is_some()
+ }
+
+ /// Get a reference to the value associated with the given token
+ pub fn get(&self, idx: I) -> Option<&T> {
+ let idx = some!(self.local_index(idx));
+
+ match self.entries[idx] {
+ Slot::Filled(ref val) => Some(val),
+ Slot::Empty(_) => None,
+ Slot::Invalid => panic!("Slab corrupt"),
+ }
+ }
+
+ /// Get a mutable reference to the value associated with the given token
+ pub fn get_mut(&mut self, idx: I) -> Option<&mut T> {
+ let idx = some!(self.local_index(idx));
+
+ match self.entries[idx] {
+ Slot::Filled(ref mut v) => Some(v),
+ _ => None,
+ }
+ }
+
+ /// Insert a value into the slab, returning the associated token
+ pub fn insert(&mut self, val: T) -> Result<I, T> {
+ match self.vacant_entry() {
+ Some(entry) => Ok(entry.insert(val).index()),
+ None => Err(val),
+ }
+ }
+
+ /// Returns a handle to an entry.
+ ///
+ /// This allows more advanced manipulation of the value stored at the given
+ /// index.
+ pub fn entry(&mut self, idx: I) -> Option<Entry<T, I>> {
+ let idx = some!(self.local_index(idx));
+
+ match self.entries[idx] {
+ Slot::Filled(_) => {
+ Some(Entry {
+ slab: self,
+ idx: idx,
+ })
+ }
+ Slot::Empty(_) => None,
+ Slot::Invalid => panic!("Slab corrupt"),
+ }
+ }
+
+ /// Returns a handle to a vacant entry.
+ ///
+ /// This allows optionally inserting a value that is constructed with the
+ /// index.
+ pub fn vacant_entry(&mut self) -> Option<VacantEntry<T, I>> {
+ let idx = self.next;
+
+ if idx >= self.entries.len() {
+ return None;
+ }
+
+ Some(VacantEntry {
+ slab: self,
+ idx: idx,
+ })
+ }
+
+ /// Releases the given slot
+ pub fn remove(&mut self, idx: I) -> Option<T> {
+ self.entry(idx).map(Entry::remove)
+ }
+
+ /// Retain only the elements specified by the predicate.
+ ///
+ /// In other words, remove all elements `e` such that `f(&e)` returns false.
+ /// This method operates in place and preserves the order of the retained
+ /// elements.
+ pub fn retain<F>(&mut self, mut f: F)
+ where F: FnMut(&T) -> bool
+ {
+ for i in 0..self.entries.len() {
+ if let Some(e) = self.entry(I::from(i)) {
+ if !f(e.get()) {
+ e.remove();
+ }
+ }
+ }
+ }
+
+ /// An iterator for visiting all elements stored in the `Slab`
+ pub fn iter(&self) -> Iter<T, I> {
+ Iter {
+ slab: self,
+ cur_idx: 0,
+ yielded: 0,
+ }
+ }
+
+ /// A mutable iterator for visiting all elements stored in the `Slab`
+ pub fn iter_mut(&mut self) -> IterMut<T, I> {
+ IterMut {
+ slab: self as *mut Slab<T, I>,
+ cur_idx: 0,
+ yielded: 0,
+ _marker: PhantomData,
+ }
+ }
+
+ /// Empty the slab, by freeing all entries
+ pub fn clear(&mut self) {
+ for (i, e) in self.entries.iter_mut().enumerate() {
+ *e = Slot::Empty(i + 1)
+ }
+ self.next = 0;
+ self.len = 0;
+ }
+
+ /// Reserves the minimum capacity for exactly `additional` more elements to
+ /// be inserted in the given `Slab`. Does nothing if the capacity is
+ /// already sufficient.
+ pub fn reserve_exact(&mut self, additional: usize) {
+ let prev_len = self.entries.len();
+
+ // Ensure `entries_num` isn't too big
+ assert!(additional < usize::MAX - prev_len, "capacity too large");
+
+ let prev_len_next = prev_len + 1;
+ self.entries.extend((prev_len_next..(prev_len_next + additional)).map(Slot::Empty));
+
+ debug_assert_eq!(self.entries.len(), prev_len + additional);
+ }
+
+ fn insert_at(&mut self, idx: usize, value: T) -> I {
+ self.next = match self.entries[idx] {
+ Slot::Empty(next) => next,
+ Slot::Filled(_) => panic!("Index already contains value"),
+ Slot::Invalid => panic!("Slab corrupt"),
+ };
+
+ self.entries[idx] = Slot::Filled(value);
+ self.len += 1;
+
+ I::from(idx)
+ }
+
+ fn replace(&mut self, idx: usize, e: Slot<T>) -> Option<T> {
+ if let Slot::Filled(val) = mem::replace(&mut self.entries[idx], e) {
+ self.next = idx;
+ return Some(val);
+ }
+
+ None
+ }
+
+ fn local_index(&self, idx: I) -> Option<usize> {
+ let idx: usize = idx.into();
+
+ if idx >= self.entries.len() {
+ return None;
+ }
+
+ Some(idx)
+ }
+}
+
+impl<T, I: From<usize> + Into<usize>> ops::Index<I> for Slab<T, I> {
+ type Output = T;
+
+ fn index(&self, index: I) -> &T {
+ self.get(index).expect("invalid index")
+ }
+}
+
+impl<T, I: From<usize> + Into<usize>> ops::IndexMut<I> for Slab<T, I> {
+ fn index_mut(&mut self, index: I) -> &mut T {
+ self.get_mut(index).expect("invalid index")
+ }
+}
+
+impl<T, I> fmt::Debug for Slab<T, I>
+ where T: fmt::Debug,
+ I: fmt::Debug,
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt,
+ "Slab {{ len: {}, cap: {} }}",
+ self.len,
+ self.capacity())
+ }
+}
+
+impl<'a, T, I: From<usize> + Into<usize>> IntoIterator for &'a Slab<T, I> {
+ type Item = &'a T;
+ type IntoIter = Iter<'a, T, I>;
+
+ fn into_iter(self) -> Iter<'a, T, I> {
+ self.iter()
+ }
+}
+
+impl<'a, T, I: From<usize> + Into<usize>> IntoIterator for &'a mut Slab<T, I> {
+ type Item = &'a mut T;
+ type IntoIter = IterMut<'a, T, I>;
+
+ fn into_iter(self) -> IterMut<'a, T, I> {
+ self.iter_mut()
+ }
+}
+
+/*
+ *
+ * ===== Entry =====
+ *
+ */
+
+impl<'a, T, I: From<usize> + Into<usize>> Entry<'a, T, I> {
+
+ /// Replace the value stored in the entry
+ pub fn replace(&mut self, val: T) -> T {
+ match mem::replace(&mut self.slab.entries[self.idx], Slot::Filled(val)) {
+ Slot::Filled(v) => v,
+ _ => panic!("Slab corrupt"),
+ }
+ }
+
+ /// Apply the function to the current value, replacing it with the result
+ /// of the function.
+ pub fn replace_with<F>(&mut self, f: F)
+ where F: FnOnce(T) -> T
+ {
+ let idx = self.idx;
+
+ // Take the value out of the entry, temporarily setting it to Invalid
+ let val = match mem::replace(&mut self.slab.entries[idx], Slot::Invalid) {
+ Slot::Filled(v) => f(v),
+ _ => panic!("Slab corrupt"),
+ };
+
+ self.slab.entries[idx] = Slot::Filled(val);
+ }
+
+ /// Remove and return the value stored in the entry
+ pub fn remove(self) -> T {
+ let next = self.slab.next;
+
+ if let Some(v) = self.slab.replace(self.idx, Slot::Empty(next)) {
+ self.slab.len -= 1;
+ v
+ } else {
+ panic!("Slab corrupt");
+ }
+ }
+
+ /// Get a reference to the value stored in the entry
+ pub fn get(&self) -> &T {
+ let idx = self.index();
+ self.slab
+ .get(idx)
+ .expect("Filled slot in Entry")
+ }
+
+ /// Get a mutable reference to the value stored in the entry
+ pub fn get_mut(&mut self) -> &mut T {
+ let idx = self.index();
+ self.slab
+ .get_mut(idx)
+ .expect("Filled slot in Entry")
+ }
+
+ /// Convert the entry handle to a mutable reference
+ pub fn into_mut(self) -> &'a mut T {
+ let idx = self.index();
+ self.slab
+ .get_mut(idx)
+ .expect("Filled slot in Entry")
+ }
+
+ /// Return the entry index
+ pub fn index(&self) -> I {
+ I::from(self.idx)
+ }
+}
+
+/*
+ *
+ * ===== VacantEntry =====
+ *
+ */
+
+impl<'a, T, I: From<usize> + Into<usize>> VacantEntry<'a, T, I> {
+ /// Insert a value into the entry
+ pub fn insert(self, val: T) -> Entry<'a, T, I> {
+ self.slab.insert_at(self.idx, val);
+
+ Entry {
+ slab: self.slab,
+ idx: self.idx,
+ }
+ }
+
+ /// Returns the entry index
+ pub fn index(&self) -> I {
+ I::from(self.idx)
+ }
+}
+
+/*
+ *
+ * ===== Iter =====
+ *
+ */
+
+impl<'a, T, I> Iterator for Iter<'a, T, I> {
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<&'a T> {
+ while self.yielded < self.slab.len {
+ match self.slab.entries[self.cur_idx] {
+ Slot::Filled(ref v) => {
+ self.cur_idx += 1;
+ self.yielded += 1;
+ return Some(v);
+ }
+ Slot::Empty(_) => {
+ self.cur_idx += 1;
+ }
+ Slot::Invalid => {
+ panic!("Slab corrupt");
+ }
+ }
+ }
+
+ None
+ }
+}
+
+/*
+ *
+ * ===== IterMut =====
+ *
+ */
+
+impl<'a, T, I> Iterator for IterMut<'a, T, I> {
+ type Item = &'a mut T;
+
+ fn next(&mut self) -> Option<&'a mut T> {
+ unsafe {
+ while self.yielded < (*self.slab).len {
+ let idx = self.cur_idx;
+
+ match (*self.slab).entries[idx] {
+ Slot::Filled(ref mut v) => {
+ self.cur_idx += 1;
+ self.yielded += 1;
+ return Some(v);
+ }
+ Slot::Empty(_) => {
+ self.cur_idx += 1;
+ }
+ Slot::Invalid => {
+ panic!("Slab corrupt");
+ }
+ }
+ }
+
+ None
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub struct MyIndex(pub usize);
+
+ impl From<usize> for MyIndex {
+ fn from(i: usize) -> MyIndex {
+ MyIndex(i)
+ }
+ }
+
+ impl Into<usize> for MyIndex {
+ fn into(self) -> usize {
+ self.0
+ }
+ }
+
+ #[test]
+ fn test_index_trait() {
+ let mut slab = Slab::<usize, MyIndex>::with_capacity(1);
+ let idx = slab.insert(10).ok().expect("Failed to insert");
+ assert_eq!(idx, MyIndex(0));
+ assert_eq!(slab[idx], 10);
+ }
+
+ #[test]
+ fn test_insertion() {
+ let mut slab = Slab::<usize, usize>::with_capacity(1);
+ assert_eq!(slab.is_empty(), true);
+ assert_eq!(slab.has_available(), true);
+ assert_eq!(slab.available(), 1);
+ let idx = slab.insert(10).ok().expect("Failed to insert");
+ assert_eq!(slab[idx], 10);
+ assert_eq!(slab.is_empty(), false);
+ assert_eq!(slab.has_available(), false);
+ assert_eq!(slab.available(), 0);
+ }
+
+ #[test]
+ fn test_insert_with() {
+ let mut slab = Slab::<usize, usize>::with_capacity(1);
+
+ {
+ let e = slab.vacant_entry().unwrap();
+ assert_eq!(e.index(), 0);
+ let e = e.insert(5);
+ assert_eq!(5, *e.get());
+ }
+
+ assert_eq!(Some(&5), slab.get(0));
+ }
+
+ #[test]
+ fn test_repeated_insertion() {
+ let mut slab = Slab::<usize, usize>::with_capacity(10);
+
+ for i in 0..10 {
+ let idx = slab.insert(i + 10).ok().expect("Failed to insert");
+ assert_eq!(slab[idx], i + 10);
+ }
+
+ slab.insert(20).err().expect("Inserted when full");
+ }
+
+ #[test]
+ fn test_repeated_insertion_and_removal() {
+ let mut slab = Slab::<usize, usize>::with_capacity(10);
+ let mut indices = vec![];
+
+ for i in 0..10 {
+ let idx = slab.insert(i + 10).ok().expect("Failed to insert");
+ indices.push(idx);
+ assert_eq!(slab[idx], i + 10);
+ }
+
+ for &i in indices.iter() {
+ slab.remove(i);
+ }
+
+ slab.insert(20).ok().expect("Failed to insert in newly empty slab");
+ }
+
+ #[test]
+ fn test_insertion_when_full() {
+ let mut slab = Slab::<usize, usize>::with_capacity(1);
+ slab.insert(10).ok().expect("Failed to insert");
+ slab.insert(10).err().expect("Inserted into a full slab");
+ }
+
+ #[test]
+ fn test_removal_at_boundries() {
+ let mut slab = Slab::<usize, usize>::with_capacity(1);
+ assert_eq!(slab.remove(0), None);
+ assert_eq!(slab.remove(1), None);
+ }
+
+ #[test]
+ fn test_removal_is_successful() {
+ let mut slab = Slab::<usize, usize>::with_capacity(1);
+ let t1 = slab.insert(10).ok().expect("Failed to insert");
+ slab.remove(t1);
+ let t2 = slab.insert(20).ok().expect("Failed to insert");
+ assert_eq!(slab[t2], 20);
+ }
+
+ #[test]
+ fn test_remove_empty_entry() {
+ let mut s = Slab::<(), usize>::with_capacity(3);
+ let t1 = s.insert(()).unwrap();
+ assert!(s.remove(t1).is_some());
+ assert!(s.remove(t1).is_none());
+ assert!(s.insert(()).is_ok());
+ assert!(s.insert(()).is_ok());
+ }
+
+ #[test]
+ fn test_mut_retrieval() {
+ let mut slab = Slab::<_, usize>::with_capacity(1);
+ let t1 = slab.insert("foo".to_string()).ok().expect("Failed to insert");
+
+ slab[t1].push_str("bar");
+
+ assert_eq!(&slab[t1][..], "foobar");
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_reusing_slots_1() {
+ let mut slab = Slab::<usize, usize>::with_capacity(16);
+
+ let t0 = slab.insert(123).unwrap();
+ let t1 = slab.insert(456).unwrap();
+
+ assert!(slab.len() == 2);
+ assert!(slab.available() == 14);
+
+ slab.remove(t0);
+
+ assert!(slab.len() == 1, "actual={}", slab.len());
+ assert!(slab.available() == 15);
+
+ slab.remove(t1);
+
+ assert!(slab.len() == 0);
+ assert!(slab.available() == 16);
+
+ let _ = slab[t1];
+ }
+
+ #[test]
+ fn test_reusing_slots_2() {
+ let mut slab = Slab::<usize, usize>::with_capacity(16);
+
+ let t0 = slab.insert(123).unwrap();
+
+ assert!(slab[t0] == 123);
+ assert!(slab.remove(t0) == Some(123));
+
+ let t0 = slab.insert(456).unwrap();
+
+ assert!(slab[t0] == 456);
+
+ let t1 = slab.insert(789).unwrap();
+
+ assert!(slab[t0] == 456);
+ assert!(slab[t1] == 789);
+
+ assert!(slab.remove(t0).unwrap() == 456);
+ assert!(slab.remove(t1).unwrap() == 789);
+
+ assert!(slab.len() == 0);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_accessing_out_of_bounds() {
+ let slab = Slab::<usize, usize>::with_capacity(16);
+ slab[0];
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_capacity_too_large1() {
+ use std::usize;
+ Slab::<usize, usize>::with_capacity(usize::MAX);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_capacity_too_large_in_reserve_exact() {
+ use std::usize;
+ let mut slab = Slab::<usize, usize>::with_capacity(100);
+ slab.reserve_exact(usize::MAX - 100);
+ }
+
+ #[test]
+ fn test_contains() {
+ let mut slab = Slab::with_capacity(16);
+ assert!(!slab.contains(0));
+
+ let idx = slab.insert(111).unwrap();
+ assert!(slab.contains(idx));
+ }
+
+ #[test]
+ fn test_get() {
+ let mut slab = Slab::<usize, usize>::with_capacity(16);
+ let tok = slab.insert(5).unwrap();
+ assert_eq!(slab.get(tok), Some(&5));
+ assert_eq!(slab.get(1), None);
+ assert_eq!(slab.get(23), None);
+ }
+
+ #[test]
+ fn test_get_mut() {
+ let mut slab = Slab::<u32, usize>::with_capacity(16);
+ let tok = slab.insert(5u32).unwrap();
+ {
+ let mut_ref = slab.get_mut(tok).unwrap();
+ assert_eq!(*mut_ref, 5);
+ *mut_ref = 12;
+ }
+ assert_eq!(slab[tok], 12);
+ assert_eq!(slab.get_mut(1), None);
+ assert_eq!(slab.get_mut(23), None);
+ }
+
+ #[test]
+ fn test_replace() {
+ let mut slab = Slab::<usize, usize>::with_capacity(16);
+ let tok = slab.insert(5).unwrap();
+
+ slab.entry(tok).unwrap().replace(6);
+ assert!(slab.entry(tok + 1).is_none());
+
+ assert_eq!(slab[tok], 6);
+ assert_eq!(slab.len(), 1);
+ }
+
+ #[test]
+ fn test_replace_again() {
+ let mut slab = Slab::<usize, usize>::with_capacity(16);
+ let tok = slab.insert(5).unwrap();
+
+ slab.entry(tok).unwrap().replace(6);
+ slab.entry(tok).unwrap().replace(7);
+ slab.entry(tok).unwrap().replace(8);
+ assert_eq!(slab[tok], 8);
+ }
+
+ #[test]
+ fn test_replace_with() {
+ let mut slab = Slab::<u32, usize>::with_capacity(16);
+ let tok = slab.insert(5u32).unwrap();
+ slab.entry(tok).unwrap().replace_with(|x| x + 1);
+ assert_eq!(slab[tok], 6);
+ }
+
+ #[test]
+ fn test_retain() {
+ let mut slab = Slab::<usize, usize>::with_capacity(2);
+ let tok1 = slab.insert(0).unwrap();
+ let tok2 = slab.insert(1).unwrap();
+ slab.retain(|x| x % 2 == 0);
+ assert_eq!(slab.len(), 1);
+ assert_eq!(slab[tok1], 0);
+ assert_eq!(slab.contains(tok2), false);
+ }
+
+ #[test]
+ fn test_iter() {
+ let mut slab = Slab::<u32, usize>::with_capacity(4);
+ for i in 0..4 {
+ slab.insert(i).unwrap();
+ }
+
+ let vals: Vec<u32> = slab.iter().map(|r| *r).collect();
+ assert_eq!(vals, vec![0, 1, 2, 3]);
+
+ slab.remove(1);
+
+ let vals: Vec<u32> = slab.iter().map(|r| *r).collect();
+ assert_eq!(vals, vec![0, 2, 3]);
+ }
+
+ #[test]
+ fn test_iter_mut() {
+ let mut slab = Slab::<u32, usize>::with_capacity(4);
+ for i in 0..4 {
+ slab.insert(i).unwrap();
+ }
+ for e in slab.iter_mut() {
+ *e = *e + 1;
+ }
+
+ let vals: Vec<u32> = slab.iter().map(|r| *r).collect();
+ assert_eq!(vals, vec![1, 2, 3, 4]);
+
+ slab.remove(2);
+ for e in slab.iter_mut() {
+ *e = *e + 1;
+ }
+
+ let vals: Vec<u32> = slab.iter().map(|r| *r).collect();
+ assert_eq!(vals, vec![2, 3, 5]);
+ }
+
+ #[test]
+ fn test_reserve_exact() {
+ let mut slab = Slab::<u32, usize>::with_capacity(4);
+ for i in 0..4 {
+ slab.insert(i).unwrap();
+ }
+
+ assert!(slab.insert(0).is_err());
+
+ slab.reserve_exact(3);
+
+ let vals: Vec<u32> = slab.iter().map(|r| *r).collect();
+ assert_eq!(vals, vec![0, 1, 2, 3]);
+
+ for i in 0..3 {
+ slab.insert(i).unwrap();
+ }
+ assert!(slab.insert(0).is_err());
+
+ let vals: Vec<u32> = slab.iter().map(|r| *r).collect();
+ assert_eq!(vals, vec![0, 1, 2, 3, 0, 1, 2]);
+ }
+
+ #[test]
+ fn test_clear() {
+ let mut slab = Slab::<u32, usize>::with_capacity(4);
+ for i in 0..4 {
+ slab.insert(i).unwrap();
+ }
+
+ // clear full
+ slab.clear();
+
+ let vals: Vec<u32> = slab.iter().map(|r| *r).collect();
+ assert_eq!(vals, vec![]);
+
+ for i in 0..2 {
+ slab.insert(i).unwrap();
+ }
+
+ let vals: Vec<u32> = slab.iter().map(|r| *r).collect();
+ assert_eq!(vals, vec![0, 1]);
+
+
+ // clear half-filled
+ slab.clear();
+
+ let vals: Vec<u32> = slab.iter().map(|r| *r).collect();
+ assert_eq!(vals, vec![]);
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/ws2_32-sys/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","Cargo.toml":"b5c32ebeb474fcf68bd5d6f296f12163d1627dca02dbe06341ee3d378535cdaa","README.md":"ad92627d07dcd015a10440590041e72723b1e5a3ca86f50d6d059e7e4e78433f","build.rs":"84b7d5871797983a021d1ae8cd9698687b7d2bddd4622e82b30c693218400f09","src/lib.rs":"71b9f929fe5227d63326e71ed2f49a96adb560318b8862d55927aac2d247e82d"},"package":"d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/ws2_32-sys/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "ws2_32-sys"
+version = "0.2.1"
+authors = ["Peter Atashian <retep998@gmail.com>"]
+description = "Contains function definitions for the Windows API library ws2_32. See winapi for types and constants."
+documentation = "https://retep998.github.io/doc/ws2_32/"
+repository = "https://github.com/retep998/winapi-rs"
+readme = "README.md"
+keywords = ["windows", "ffi", "win32"]
+license = "MIT"
+build = "build.rs"
+[lib]
+name = "ws2_32"
+[dependencies]
+winapi = { version = "0.2.5", path = "../.." }
+[build-dependencies]
+winapi-build = { version = "0.1.1", path = "../../build" }
new file mode 100644
--- /dev/null
+++ b/third_party/rust/ws2_32-sys/README.md
@@ -0,0 +1,13 @@
+# ws2_32 #
+Contains function definitions for the Windows API library ws2_32. See winapi for types and constants.
+
+```toml
+[dependencies]
+ws2_32-sys = "0.2.0"
+```
+
+```rust
+extern crate ws2_32;
+```
+
+[Documentation](https://retep998.github.io/doc/ws2_32/)
new file mode 100644
--- /dev/null
+++ b/third_party/rust/ws2_32-sys/build.rs
@@ -0,0 +1,6 @@
+// Copyright © 2015, Peter Atashian
+// Licensed under the MIT License <LICENSE.md>
+extern crate build;
+fn main() {
+ build::link("ws2_32", false)
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/ws2_32-sys/src/lib.rs
@@ -0,0 +1,483 @@
+// Copyright © 2015, Peter Atashian
+// Licensed under the MIT License <LICENSE.md>
+//! FFI bindings to ws2_32.
+#![cfg(windows)]
+extern crate winapi;
+use winapi::*;
+extern "system" {
+ pub fn FreeAddrInfoEx(pAddrInfoEx: PADDRINFOEXA);
+ pub fn FreeAddrInfoExW(pAddrInfoEx: PADDRINFOEXW);
+ pub fn FreeAddrInfoW(pAddrInfo: PADDRINFOW);
+ pub fn GetAddrInfoExA(
+ pName: PCSTR, pServiceName: PCSTR, dwNameSpace: DWORD, lpNspId: LPGUID,
+ hints: *const ADDRINFOEXA, ppResult: *mut PADDRINFOEXA, timeout: *mut timeval,
+ lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE,
+ lpNameHandle: LPHANDLE,
+ ) -> INT;
+ pub fn GetAddrInfoExCancel(lpHandle: LPHANDLE) -> INT;
+ pub fn GetAddrInfoExOverlappedResult(lpOverlapped: LPOVERLAPPED) -> INT;
+ pub fn GetAddrInfoExW(
+ pName: PCWSTR, pServiceName: PCWSTR, dwNameSpace: DWORD, lpNspId: LPGUID,
+ hints: *const ADDRINFOEXW, ppResult: *mut PADDRINFOEXW, timeout: *mut timeval,
+ lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE,
+ lpNameHandle: LPHANDLE,
+ ) -> INT;
+ pub fn GetAddrInfoW(
+ pNodeName: PCWSTR, pServiceName: PCWSTR, pHints: *const ADDRINFOW,
+ ppResult: *mut PADDRINFOW,
+ ) -> INT;
+ pub fn GetHostNameW(name: PWSTR, namelen: c_int) -> c_int;
+ pub fn GetNameInfoW(
+ pSockaddr: *const SOCKADDR, SockaddrLength: socklen_t, pNodeBuffer: PWCHAR,
+ NodeBufferSize: DWORD, pServiceBuffer: PWCHAR, ServiceBufferSize: DWORD, Flags: INT,
+ ) -> INT;
+ pub fn InetNtopW(Family: INT, pAddr: PVOID, pStringBuf: PWSTR, StringBufSize: size_t) -> PCWSTR;
+ pub fn InetPtonW(Family: INT, pszAddrString: PCWSTR, pAddrBuf: PVOID) -> INT;
+ pub fn SetAddrInfoExA(
+ pName: PCSTR, pServiceName: PCSTR, pAddresses: *mut SOCKET_ADDRESS, dwAddressCount: DWORD,
+ lpBlob: LPBLOB, dwFlags: DWORD, dwNameSpace: DWORD, lpNspId: LPGUID, timeout: *mut timeval,
+ lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE,
+ lpNameHandle: LPHANDLE,
+ ) -> INT;
+ pub fn SetAddrInfoExW(
+ pName: PCWSTR, pServiceName: PCWSTR, pAddresses: *mut SOCKET_ADDRESS, dwAddressCount: DWORD,
+ lpBlob: LPBLOB, dwFlags: DWORD, dwNameSpace: DWORD, lpNspId: LPGUID, timeout: *mut timeval,
+ lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE,
+ lpNameHandle: LPHANDLE,
+ ) -> INT;
+ // pub fn WEP();
+ pub fn WPUCompleteOverlappedRequest(
+ s: SOCKET, lpOverlapped: LPWSAOVERLAPPED, dwError: DWORD, cbTransferred: DWORD,
+ lpErrno: LPINT,
+ ) -> c_int;
+ // pub fn WPUGetProviderPathEx();
+ pub fn WSAAccept(
+ s: SOCKET, addr: *mut SOCKADDR, addrlen: LPINT, lpfnCondition: LPCONDITIONPROC,
+ dwCallbackData: DWORD_PTR,
+ ) -> SOCKET;
+ pub fn WSAAddressToStringA(
+ lpsaAddress: LPSOCKADDR, dwAddressLength: DWORD, lpProtocolInfo: LPWSAPROTOCOL_INFOA,
+ lpszAddressString: LPSTR, lpdwAddressStringLength: LPDWORD,
+ ) -> INT;
+ pub fn WSAAddressToStringW(
+ lpsaAddress: LPSOCKADDR, dwAddressLength: DWORD, lpProtocolInfo: LPWSAPROTOCOL_INFOW,
+ lpszAddressString: LPWSTR, lpdwAddressStringLength: LPDWORD,
+ ) -> INT;
+ pub fn WSAAdvertiseProvider(
+ puuidProviderId: *const GUID, pNSPv2Routine: *const LPCNSPV2_ROUTINE,
+ ) -> INT;
+ pub fn WSAAsyncGetHostByAddr(
+ hWnd: HWND, wMsg: u_int, addr: *const c_char, len: c_int, _type: c_int, buf: *mut c_char,
+ buflen: c_int,
+ ) -> HANDLE;
+ pub fn WSAAsyncGetHostByName(
+ hWnd: HWND, wMsg: u_int, name: *const c_char, buf: *mut c_char, buflen: c_int,
+ ) -> HANDLE;
+ pub fn WSAAsyncGetProtoByName(
+ hWnd: HWND, wMsg: u_int, name: *const c_char, buf: *mut c_char, buflen: c_int,
+ ) -> HANDLE;
+ pub fn WSAAsyncGetProtoByNumber(
+ hWnd: HWND, wMsg: u_int, number: c_int, buf: *mut c_char, buflen: c_int,
+ ) -> HANDLE;
+ pub fn WSAAsyncGetServByName(
+ hWnd: HWND, wMsg: u_int, name: *const c_char, proto: *const c_char, buf: *mut c_char,
+ buflen: c_int,
+ ) -> HANDLE;
+ pub fn WSAAsyncGetServByPort(
+ hWnd: HWND, wMsg: u_int, port: c_int, proto: *const c_char, buf: *mut c_char, buflen: c_int,
+ ) -> HANDLE;
+ pub fn WSAAsyncSelect(s: SOCKET, hWnd: HWND, wMsg: u_int, lEvent: c_long) -> c_int;
+ pub fn WSACancelAsyncRequest(hAsyncTaskHandle: HANDLE) -> c_int;
+ pub fn WSACancelBlockingCall() -> c_int;
+ pub fn WSACleanup() -> c_int;
+ pub fn WSACloseEvent(hEvent: WSAEVENT) -> BOOL;
+ pub fn WSAConnect(
+ s: SOCKET, name: *const SOCKADDR, namelen: c_int, lpCallerData: LPWSABUF,
+ lpCalleeData: LPWSABUF, lpSQOS: LPQOS, lpGQOS: LPQOS,
+ ) -> c_int;
+ pub fn WSAConnectByList(
+ s: SOCKET, SocketAddress: PSOCKET_ADDRESS_LIST, LocalAddressLength: LPDWORD,
+ LocalAddress: LPSOCKADDR, RemoteAddressLength: LPDWORD, RemoteAddress: LPSOCKADDR,
+ timeout: *const timeval, Reserved: LPWSAOVERLAPPED,
+ ) -> BOOL;
+ pub fn WSAConnectByNameA(
+ s: SOCKET, nodename: LPCSTR, servicename: LPCSTR, LocalAddressLength: LPDWORD,
+ LocalAddress: LPSOCKADDR, RemoteAddressLength: LPDWORD, RemoteAddress: LPSOCKADDR,
+ timeout: *const timeval, Reserved: LPWSAOVERLAPPED,
+ ) -> BOOL;
+ pub fn WSAConnectByNameW(
+ s: SOCKET, nodename: LPWSTR, servicename: LPWSTR, LocalAddressLength: LPDWORD,
+ LocalAddress: LPSOCKADDR, RemoteAddressLength: LPDWORD, RemoteAddress: LPSOCKADDR,
+ timeout: *const timeval, Reserved: LPWSAOVERLAPPED,
+ ) -> BOOL;
+ pub fn WSACreateEvent() -> WSAEVENT;
+ pub fn WSADuplicateSocketA(
+ s: SOCKET, dwProcessId: DWORD, lpProtocolInfo: LPWSAPROTOCOL_INFOA,
+ ) -> c_int;
+ pub fn WSADuplicateSocketW(
+ s: SOCKET, dwProcessId: DWORD, lpProtocolInfo: LPWSAPROTOCOL_INFOW,
+ ) -> c_int;
+ pub fn WSAEnumNameSpaceProvidersA(
+ lpdwBufferLength: LPDWORD, lpnspBuffer: LPWSANAMESPACE_INFOA,
+ ) -> INT;
+ pub fn WSAEnumNameSpaceProvidersExA(
+ lpdwBufferLength: LPDWORD, lpnspBuffer: LPWSANAMESPACE_INFOEXA,
+ ) -> INT;
+ pub fn WSAEnumNameSpaceProvidersExW(
+ lpdwBufferLength: LPDWORD, lpnspBuffer: LPWSANAMESPACE_INFOEXW,
+ ) -> INT;
+ pub fn WSAEnumNameSpaceProvidersW(
+ lpdwBufferLength: LPDWORD, lpnspBuffer: LPWSANAMESPACE_INFOW,
+ ) -> INT;
+ pub fn WSAEnumNetworkEvents(
+ s: SOCKET, hEventObject: WSAEVENT, lpNetworkEvents: LPWSANETWORKEVENTS,
+ ) -> c_int;
+ pub fn WSAEnumProtocolsA(
+ lpiProtocols: LPINT, lpProtocolBuffer: LPWSAPROTOCOL_INFOA, lpdwBufferLength: LPDWORD,
+ ) -> c_int;
+ pub fn WSAEnumProtocolsW(
+ lpiProtocols: LPINT, lpProtocolBuffer: LPWSAPROTOCOL_INFOW, lpdwBufferLength: LPDWORD,
+ ) -> c_int;
+ pub fn WSAEventSelect(s: SOCKET, hEventObject: WSAEVENT, lNetworkEvents: c_long) -> c_int;
+ pub fn WSAGetLastError() -> c_int;
+ pub fn WSAGetOverlappedResult(
+ s: SOCKET, lpOverlapped: LPWSAOVERLAPPED, lpcbTransfer: LPDWORD, fWait: BOOL,
+ lpdwFlags: LPDWORD,
+ ) -> BOOL;
+ pub fn WSAGetQOSByName(s: SOCKET, lpQOSName: LPWSABUF, lpQOS: LPQOS) -> BOOL;
+ pub fn WSAGetServiceClassInfoA(
+ lpProviderId: LPGUID, lpServiceClassId: LPGUID, lpdwBufSize: LPDWORD,
+ lpServiceClassInfo: LPWSASERVICECLASSINFOA,
+ ) -> INT;
+ pub fn WSAGetServiceClassInfoW(
+ lpProviderId: LPGUID, lpServiceClassId: LPGUID, lpdwBufSize: LPDWORD,
+ lpServiceClassInfo: LPWSASERVICECLASSINFOW,
+ ) -> INT;
+ pub fn WSAGetServiceClassNameByClassIdA(
+ lpServiceClassId: LPGUID, lpszServiceClassName: LPSTR, lpdwBufferLength: LPDWORD,
+ ) -> INT;
+ pub fn WSAGetServiceClassNameByClassIdW(
+ lpServiceClassId: LPGUID, lpszServiceClassName: LPWSTR, lpdwBufferLength: LPDWORD,
+ ) -> INT;
+ pub fn WSAHtonl(s: SOCKET, hostlong: u_long, lpnetlong: *mut u_long) -> c_int;
+ pub fn WSAHtons(s: SOCKET, hostshort: u_short, lpnetshort: *mut u_short) -> c_int;
+ pub fn WSAInstallServiceClassA(lpServiceClassInfo: LPWSASERVICECLASSINFOA) -> INT;
+ pub fn WSAInstallServiceClassW(lpServiceClassInfo: LPWSASERVICECLASSINFOW) -> INT;
+ pub fn WSAIoctl(
+ s: SOCKET, dwIoControlCode: DWORD, lpvInBuffer: LPVOID, cbInBuffer: DWORD,
+ lpvOutBuffer: LPVOID, cbOutBuffer: DWORD, lpcbBytesReturned: LPDWORD,
+ lpOverlapped: LPWSAOVERLAPPED, lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+ ) -> c_int;
+ pub fn WSAIsBlocking() -> BOOL;
+ pub fn WSAJoinLeaf(
+ s: SOCKET, name: *const SOCKADDR, namelen: c_int, lpCallerData: LPWSABUF,
+ lpCalleeData: LPWSABUF, lpSQOS: LPQOS, lpGQOS: LPQOS, dwFlags: DWORD,
+ ) -> SOCKET;
+ pub fn WSALookupServiceBeginA(
+ lpqsRestrictions: LPWSAQUERYSETA, dwControlFlags: DWORD, lphLookup: LPHANDLE,
+ ) -> INT;
+ pub fn WSALookupServiceBeginW(
+ lpqsRestrictions: LPWSAQUERYSETW, dwControlFlags: DWORD, lphLookup: LPHANDLE,
+ ) -> INT;
+ pub fn WSALookupServiceEnd(hLookup: HANDLE) -> INT;
+ pub fn WSALookupServiceNextA(
+ hLookup: HANDLE, dwControlFlags: DWORD, lpdwBufferLength: LPDWORD,
+ lpqsResults: LPWSAQUERYSETA,
+ ) -> INT;
+ pub fn WSALookupServiceNextW(
+ hLookup: HANDLE, dwControlFlags: DWORD, lpdwBufferLength: LPDWORD,
+ lpqsResults: LPWSAQUERYSETW,
+ ) -> INT;
+ pub fn WSANSPIoctl(
+ hLookup: HANDLE, dwControlFlags: DWORD, lpvInBuffer: LPVOID, cbInBuffer: DWORD,
+ lpvOutBuffer: LPVOID, cbOutBuffer: DWORD, lpcbBytesReturned: LPDWORD,
+ lpCompletion: LPWSACOMPLETION,
+ ) -> INT;
+ pub fn WSANtohl(s: SOCKET, netlong: u_long, lphostlong: *mut c_long) -> c_int;
+ pub fn WSANtohs(s: SOCKET, netshort: u_short, lphostshort: *mut c_short) -> c_int;
+ pub fn WSAPoll(fdArray: LPWSAPOLLFD, fds: ULONG, timeout: INT) -> c_int;
+ pub fn WSAProviderCompleteAsyncCall(hAsyncCall: HANDLE, iRetCode: INT) -> INT;
+ pub fn WSAProviderConfigChange(
+ lpNotificationHandle: LPHANDLE, lpOverlapped: LPWSAOVERLAPPED,
+ lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+ ) -> INT;
+ pub fn WSARecv(
+ s: SOCKET, lpBuffers: LPWSABUF, dwBufferCount: DWORD, lpNumberOfBytesRecvd: LPDWORD,
+ lpFlags: LPDWORD, lpOverlapped: LPWSAOVERLAPPED,
+ lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+ ) -> c_int;
+ pub fn WSARecvDisconnect(s: SOCKET, lpInboundDisconnectData: LPWSABUF) -> c_int;
+ pub fn WSARecvFrom(
+ s: SOCKET, lpBuffers: LPWSABUF, dwBufferCount: DWORD, lpNumberOfBytesRecvd: LPDWORD,
+ lpFlags: LPDWORD, lpFrom: *mut SOCKADDR, lpFromlen: LPINT, lpOverlapped: LPWSAOVERLAPPED,
+ lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+ ) -> c_int;
+ pub fn WSARemoveServiceClass(lpServiceClassId: LPGUID) -> INT;
+ pub fn WSAResetEvent(hEvent: WSAEVENT) -> BOOL;
+ pub fn WSASend(
+ s: SOCKET, lpBuffers: LPWSABUF, dwBufferCount: DWORD, lpNumberOfBytesSent: LPDWORD,
+ dwFlags: DWORD, lpOverlapped: LPWSAOVERLAPPED,
+ lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+ ) -> c_int;
+ pub fn WSASendDisconnect(s: SOCKET, lpOutboundDisconnectData: LPWSABUF) -> c_int;
+ pub fn WSASendMsg(
+ Handle: SOCKET, lpMsg: LPWSAMSG, dwFlags: DWORD, lpNumberOfBytesSent: LPDWORD,
+ lpOverlapped: LPWSAOVERLAPPED, lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+ ) -> c_int;
+ pub fn WSASendTo(
+ s: SOCKET, lpBuffers: LPWSABUF, dwBufferCount: DWORD, lpNumberOfBytesSent: LPDWORD,
+ dwFlags: DWORD, lpTo: *const SOCKADDR, iToLen: c_int, lpOverlapped: LPWSAOVERLAPPED,
+ lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+ ) -> c_int;
+ pub fn WSASetBlockingHook(lpBlockFunc: FARPROC) -> FARPROC;
+ pub fn WSASetEvent(hEvent: WSAEVENT) -> BOOL;
+ pub fn WSASetLastError(iError: c_int);
+ pub fn WSASetServiceA(
+ lpqsRegInfo: LPWSAQUERYSETA, essoperation: WSAESETSERVICEOP, dwControlFlags: DWORD,
+ ) -> INT;
+ pub fn WSASetServiceW(
+ lpqsRegInfo: LPWSAQUERYSETW, essoperation: WSAESETSERVICEOP, dwControlFlags: DWORD,
+ ) -> INT;
+ pub fn WSASocketA(
+ af: c_int, _type: c_int, protocol: c_int, lpProtocolInfo: LPWSAPROTOCOL_INFOA, g: GROUP,
+ dwFlags: DWORD,
+ ) -> SOCKET;
+ pub fn WSASocketW(
+ af: c_int, _type: c_int, protocol: c_int, lpProtocolInfo: LPWSAPROTOCOL_INFOW, g: GROUP,
+ dwFlags: DWORD,
+ ) -> SOCKET;
+ pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int;
+ pub fn WSAStringToAddressA(
+ AddressString: LPSTR, AddressFamily: INT, lpProtocolInfo: LPWSAPROTOCOL_INFOA,
+ lpAddress: LPSOCKADDR, lpAddressLength: LPINT,
+ ) -> INT;
+ pub fn WSAStringToAddressW(
+ AddressString: LPWSTR, AddressFamily: INT, lpProtocolInfo: LPWSAPROTOCOL_INFOW,
+ lpAddress: LPSOCKADDR, lpAddressLength: LPINT,
+ ) -> INT;
+ pub fn WSAUnadvertiseProvider(puuidProviderId: *const GUID) -> INT;
+ pub fn WSAUnhookBlockingHook() -> c_int;
+ pub fn WSAWaitForMultipleEvents(
+ cEvents: DWORD, lphEvents: *const WSAEVENT, fWaitAll: BOOL, dwTimeout: DWORD,
+ fAlertable: BOOL,
+ ) -> DWORD;
+ pub fn WSCDeinstallProvider(lpProviderId: LPGUID, lpErrno: LPINT) -> c_int;
+ // pub fn WSCDeinstallProviderEx();
+ pub fn WSCEnableNSProvider(lpProviderId: LPGUID, fEnable: BOOL) -> INT;
+ pub fn WSCEnumProtocols(
+ lpiProtocols: LPINT, lpProtocolBuffer: LPWSAPROTOCOL_INFOW, lpdwBufferLength: LPDWORD,
+ lpErrno: LPINT,
+ ) -> c_int;
+ // pub fn WSCEnumProtocolsEx();
+ pub fn WSCGetApplicationCategory(
+ Path: LPCWSTR, PathLength: DWORD, Extra: LPCWSTR, ExtraLength: DWORD,
+ pPermittedLspCategories: *mut DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ // pub fn WSCGetApplicationCategoryEx();
+ pub fn WSCGetProviderInfo(
+ lpProviderId: LPGUID, InfoType: WSC_PROVIDER_INFO_TYPE, Info: PBYTE, InfoSize: *mut size_t,
+ Flags: DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCGetProviderPath(
+ lpProviderId: LPGUID, lpszProviderDllPath: *mut WCHAR, lpProviderDllPathLen: LPINT,
+ lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCInstallNameSpace(
+ lpszIdentifier: LPWSTR, lpszPathName: LPWSTR, dwNameSpace: DWORD, dwVersion: DWORD,
+ lpProviderId: LPGUID,
+ ) -> INT;
+ pub fn WSCInstallNameSpaceEx(
+ lpszIdentifier: LPWSTR, lpszPathName: LPWSTR, dwNameSpace: DWORD, dwVersion: DWORD,
+ lpProviderId: LPGUID, lpProviderSpecific: LPBLOB,
+ ) -> INT;
+ // pub fn WSCInstallNameSpaceEx2();
+ pub fn WSCInstallProvider(
+ lpProviderId: LPGUID, lpszProviderDllPath: *const WCHAR,
+ lpProtocolInfoList: LPWSAPROTOCOL_INFOW, dwNumberOfEntries: DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ // pub fn WSCInstallProviderEx();
+ pub fn WSCSetApplicationCategory(
+ Path: LPCWSTR, PathLength: DWORD, Extra: LPCWSTR, ExtraLength: DWORD,
+ PermittedLspCategories: DWORD, pPrevPermLspCat: *mut DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ // pub fn WSCSetApplicationCategoryEx();
+ pub fn WSCSetProviderInfo(
+ lpProviderId: LPGUID, InfoType: WSC_PROVIDER_INFO_TYPE, Info: PBYTE, InfoSize: size_t,
+ Flags: DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCUnInstallNameSpace(lpProviderId: LPGUID) -> INT;
+ // pub fn WSCUnInstallNameSpaceEx2();
+ pub fn WSCUpdateProvider(
+ lpProviderId: LPGUID, lpszProviderDllPath: *const WCHAR,
+ lpProtocolInfoList: LPWSAPROTOCOL_INFOW, dwNumberOfEntries: DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ // pub fn WSCUpdateProviderEx();
+ pub fn WSCWriteNameSpaceOrder(lpProviderId: LPGUID, dwNumberOfEntries: DWORD) -> c_int;
+ pub fn WSCWriteProviderOrder(lpwdCatalogEntryId: LPDWORD, dwNumberOfEntries: DWORD) -> c_int;
+ // pub fn WSCWriteProviderOrderEx();
+ // pub fn WahCloseApcHelper();
+ // pub fn WahCloseHandleHelper();
+ // pub fn WahCloseNotificationHandleHelper();
+ // pub fn WahCloseSocketHandle();
+ // pub fn WahCloseThread();
+ // pub fn WahCompleteRequest();
+ // pub fn WahCreateHandleContextTable();
+ // pub fn WahCreateNotificationHandle();
+ // pub fn WahCreateSocketHandle();
+ // pub fn WahDestroyHandleContextTable();
+ // pub fn WahDisableNonIFSHandleSupport();
+ // pub fn WahEnableNonIFSHandleSupport();
+ // pub fn WahEnumerateHandleContexts();
+ // pub fn WahInsertHandleContext();
+ // pub fn WahNotifyAllProcesses();
+ // pub fn WahOpenApcHelper();
+ // pub fn WahOpenCurrentThread();
+ // pub fn WahOpenHandleHelper();
+ // pub fn WahOpenNotificationHandleHelper();
+ // pub fn WahQueueUserApc();
+ // pub fn WahReferenceContextByHandle();
+ // pub fn WahRemoveHandleContext();
+ // pub fn WahWaitForNotification();
+ // pub fn WahWriteLSPEvent();
+ pub fn __WSAFDIsSet(fd: SOCKET, _: *mut fd_set) -> c_int;
+ pub fn accept(s: SOCKET, addr: *mut SOCKADDR, addrlen: *mut c_int) -> SOCKET;
+ pub fn bind(s: SOCKET, name: *const SOCKADDR, namelen: c_int) -> c_int;
+ pub fn closesocket(s: SOCKET) -> c_int;
+ pub fn connect(s: SOCKET, name: *const SOCKADDR, namelen: c_int) -> c_int;
+ pub fn freeaddrinfo(pAddrInfo: PADDRINFOA);
+ pub fn getaddrinfo(
+ pNodeName: PCSTR, pServiceName: PCSTR, pHints: *const ADDRINFOA, ppResult: *mut PADDRINFOA,
+ ) -> INT;
+ pub fn gethostbyaddr(addr: *const c_char, len: c_int, _type: c_int) -> *mut hostent;
+ pub fn gethostbyname(name: *const c_char) -> *mut hostent;
+ pub fn gethostname(name: *mut c_char, namelen: c_int) -> c_int;
+ pub fn getnameinfo(
+ pSockaddr: *const SOCKADDR, SockaddrLength: socklen_t, pNodeBuffer: PCHAR,
+ NodeBufferSize: DWORD, pServiceBuffer: PCHAR, ServiceBufferSize: DWORD, Flags: INT,
+ ) -> INT;
+ pub fn getpeername(s: SOCKET, name: *mut SOCKADDR, namelen: *mut c_int) -> c_int;
+ pub fn getprotobyname(name: *const c_char) -> *mut protoent;
+ pub fn getprotobynumber(number: c_int) -> *mut protoent;
+ pub fn getservbyname(name: *const c_char, proto: *const c_char) -> *mut servent;
+ pub fn getservbyport(port: c_int, proto: *const c_char) -> *mut servent;
+ pub fn getsockname(s: SOCKET, name: *mut SOCKADDR, namelen: *mut c_int) -> c_int;
+ pub fn getsockopt(
+ s: SOCKET, level: c_int, optname: c_int, optval: *mut c_char, optlen: *mut c_int,
+ ) -> c_int;
+ pub fn htonl(hostlong: u_long) -> u_long;
+ pub fn htons(hostshort: u_short) -> u_short;
+ pub fn inet_addr(cp: *const c_char) -> c_ulong;
+ pub fn inet_ntoa(_in: in_addr) -> *mut c_char;
+ pub fn inet_ntop(Family: INT, pAddr: PVOID, pStringBuf: PSTR, StringBufSize: size_t) -> PCSTR;
+ pub fn inet_pton(Family: INT, pszAddrString: PCSTR, pAddrBuf: PVOID) -> INT;
+ pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut u_long) -> c_int;
+ pub fn listen(s: SOCKET, backlog: c_int) -> c_int;
+ pub fn ntohl(netlong: u_long) -> u_long;
+ pub fn ntohs(netshort: u_short) -> u_short;
+ pub fn recv(s: SOCKET, buf: *mut c_char, len: c_int, flags: c_int) -> c_int;
+ pub fn recvfrom(
+ s: SOCKET, buf: *mut c_char, len: c_int, flags: c_int, from: *mut SOCKADDR,
+ fromlen: *mut c_int,
+ ) -> c_int;
+ pub fn select(
+ nfds: c_int, readfds: *mut fd_set, writefds: *mut fd_set, exceptfds: *mut fd_set,
+ timeout: *const timeval,
+ ) -> c_int;
+ pub fn send(s: SOCKET, buf: *const c_char, len: c_int, flags: c_int) -> c_int;
+ pub fn sendto(
+ s: SOCKET, buf: *const c_char, len: c_int, flags: c_int, to: *const SOCKADDR, tolen: c_int,
+ ) -> c_int;
+ pub fn setsockopt(
+ s: SOCKET, level: c_int, optname: c_int, optval: *const c_char, optlen: c_int,
+ ) -> c_int;
+ pub fn shutdown(s: SOCKET, how: c_int) -> c_int;
+ pub fn socket(af: c_int, _type: c_int, protocol: c_int) -> SOCKET;
+}
+#[cfg(any(target_arch = "x86", target_arch = "arm"))]
+extern "system" {
+ pub fn WSCInstallProviderAndChains(
+ lpProviderId: LPGUID, lpszProviderDllPath: LPWSTR, lpszLspName: LPWSTR,
+ dwServiceFlags: DWORD, lpProtocolInfoList: LPWSAPROTOCOL_INFOW, dwNumberOfEntries: DWORD,
+ lpdwCatalogEntryId: LPDWORD, lpErrno: LPINT,
+ ) -> c_int;
+}
+#[cfg(target_arch = "x86_64")]
+extern "system" {
+ pub fn WSCDeinstallProvider32(lpProviderId: LPGUID, lpErrno: LPINT) -> c_int;
+ pub fn WSCEnableNSProvider32(lpProviderId: LPGUID, fEnable: BOOL) -> INT;
+ pub fn WSCEnumNameSpaceProviders32(
+ lpdwBufferLength: LPDWORD, lpnspBuffer: LPWSANAMESPACE_INFOW,
+ ) -> INT;
+ pub fn WSCEnumNameSpaceProvidersEx32(
+ lpdwBufferLength: LPDWORD, lpnspBuffer: LPWSANAMESPACE_INFOEXW,
+ ) -> INT;
+ pub fn WSCEnumProtocols32(
+ lpiProtocols: LPINT, lpProtocolBuffer: LPWSAPROTOCOL_INFOW, lpdwBufferLength: LPDWORD,
+ lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCGetProviderInfo32(
+ lpProviderId: LPGUID, InfoType: WSC_PROVIDER_INFO_TYPE, Info: PBYTE, InfoSize: *mut size_t,
+ Flags: DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCGetProviderPath32(
+ lpProviderId: LPGUID, lpszProviderDllPath: *mut WCHAR, lpProviderDllPathLen: LPINT,
+ lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCInstallNameSpace32(
+ lpszIdentifier: LPWSTR, lpszPathName: LPWSTR, dwNameSpace: DWORD, dwVersion: DWORD,
+ lpProviderId: LPGUID,
+ ) -> INT;
+ pub fn WSCInstallNameSpaceEx32(
+ lpszIdentifier: LPWSTR, lpszPathName: LPWSTR, dwNameSpace: DWORD, dwVersion: DWORD,
+ lpProviderId: LPGUID, lpProviderSpecific: LPBLOB,
+ ) -> INT;
+ pub fn WSCInstallProvider64_32(
+ lpProviderId: LPGUID, lpszProviderDllPath: *const WCHAR,
+ lpProtocolInfoList: LPWSAPROTOCOL_INFOW, dwNumberOfEntries: DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCInstallProviderAndChains64_32(
+ lpProviderId: LPGUID, lpszProviderDllPath: LPWSTR, lpszProviderDllPath32: LPWSTR,
+ lpszLspName: LPWSTR, dwServiceFlags: DWORD, lpProtocolInfoList: LPWSAPROTOCOL_INFOW,
+ dwNumberOfEntries: DWORD, lpdwCatalogEntryId: LPDWORD, lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCSetProviderInfo32(
+ lpProviderId: LPGUID, InfoType: WSC_PROVIDER_INFO_TYPE, Info: PBYTE, InfoSize: size_t,
+ Flags: DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCUnInstallNameSpace32(lpProviderId: LPGUID) -> INT;
+ pub fn WSCUpdateProvider32(
+ lpProviderId: LPGUID, lpszProviderDllPath: *const WCHAR,
+ lpProtocolInfoList: LPWSAPROTOCOL_INFOW, dwNumberOfEntries: DWORD, lpErrno: LPINT,
+ ) -> c_int;
+ pub fn WSCWriteNameSpaceOrder32(lpProviderId: LPGUID, dwNumberOfEntries: DWORD) -> c_int;
+ pub fn WSCWriteProviderOrder32(lpwdCatalogEntryId: LPDWORD, dwNumberOfEntries: DWORD) -> c_int;
+}
+extern {
+ // pub static AddressFamilyInformation;
+ // pub static eui48_broadcast;
+ // pub static in4addr_alligmpv3routersonlink;
+ // pub static in4addr_allnodesonlink;
+ // pub static in4addr_allroutersonlink;
+ // pub static in4addr_allteredohostsonlink;
+ // pub static in4addr_any;
+ // pub static in4addr_broadcast;
+ // pub static in4addr_linklocalprefix;
+ // pub static in4addr_loopback;
+ // pub static in4addr_multicastprefix;
+ // pub static in6addr_6to4prefix;
+ // pub static in6addr_allmldv2routersonlink;
+ // pub static in6addr_allnodesonlink;
+ // pub static in6addr_allnodesonnode;
+ // pub static in6addr_allroutersonlink;
+ // pub static in6addr_any;
+ // pub static in6addr_linklocalprefix;
+ // pub static in6addr_loopback;
+ // pub static in6addr_multicastprefix;
+ // pub static in6addr_solicitednodemulticastprefix;
+ // pub static in6addr_teredoinitiallinklocaladdress;
+ // pub static in6addr_teredoprefix;
+ // pub static in6addr_teredoprefix_old;
+ // pub static in6addr_v4mappedprefix;
+ // pub static scopeid_unspecified;
+ // pub static sockaddr_size;
+}
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -68,16 +68,80 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "audioipc"
+version = "0.1.0"
+dependencies = [
+ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cubeb-core 0.1.0",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "audioipc-client"
+version = "0.1.0"
+dependencies = [
+ "audioipc 0.1.0",
+ "cubeb-backend 0.2.0",
+ "cubeb-core 0.1.0",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "audioipc-server"
+version = "0.1.0"
+dependencies = [
+ "audioipc 0.1.0",
+ "cubeb 0.3.0",
+ "cubeb-core 0.1.0",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "binary-space-partition"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bincode"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -251,16 +315,38 @@ source = "registry+https://github.com/ru
dependencies = [
"phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
"procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "cubeb"
+version = "0.3.0"
+dependencies = [
+ "cubeb-core 0.1.0",
+ "libcubeb-sys 0.1.0",
+]
+
+[[package]]
+name = "cubeb-backend"
+version = "0.2.0"
+dependencies = [
+ "cubeb-core 0.1.0",
+]
+
+[[package]]
+name = "cubeb-core"
+version = "0.1.0"
+dependencies = [
+ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "cubeb-ffi"
version = "0.0.1"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cubeb-pulse"
@@ -298,16 +384,25 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "dbghelp-sys"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "dtoa"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "dtoa-short"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -365,16 +460,24 @@ name = "env_logger"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "error-chain"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "euclid"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -389,16 +492,26 @@ source = "registry+https://github.com/ru
name = "freetype"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "fs2"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "futures"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -410,16 +523,21 @@ dependencies = [
name = "gamma-lut"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "gcc"
+version = "0.3.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "gdi32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -439,16 +557,21 @@ dependencies = [
"style 0.0.1",
"style_traits 0.0.1",
]
[[package]]
name = "gkrust-shared"
version = "0.1.0"
dependencies = [
+ "audioipc-client 0.1.0",
+ "audioipc-server 0.1.0",
+ "cubeb 0.3.0",
+ "cubeb-backend 0.2.0",
+ "cubeb-core 0.1.0",
"cubeb-pulse 0.0.1",
"encoding_c 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_glue 0.1.0",
"geckoservo 0.0.1",
"mp4parse_capi 0.8.0",
"nserror 0.1.0",
"nsstring 0.1.0",
"rust_url_capi 0.0.1",
@@ -498,16 +621,25 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "iovec"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "itertools"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -530,21 +662,33 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "lazycell"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "libc"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "libcubeb-sys"
+version = "0.1.0"
+dependencies = [
+ "cubeb-core 0.1.0",
+]
+
+[[package]]
name = "libloading"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -563,16 +707,63 @@ source = "registry+https://github.com/ru
name = "memchr"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "memmap"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mio"
+version = "0.6.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mio-uds"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "miow"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "mp4parse"
version = "0.8.0"
dependencies = [
"bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -585,16 +776,28 @@ name = "mp4parse_capi"
version = "0.8.0"
dependencies = [
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mp4parse 0.8.0",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "net2"
+version = "0.2.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "nodrop"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -864,16 +1067,21 @@ version = "0.0.1"
dependencies = [
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
"nserror 0.1.0",
"nsstring 0.1.0",
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "rustc-demangle"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "rustc-serialize"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "same-file"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -957,16 +1165,21 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "siphasher"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "slab"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "smallvec"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1308,32 +1521,43 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "ws2_32-sys"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "xml-rs"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum app_units 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ff4f3fe57393a150b39b026b6f6f4b9a6c4f49b52d0a4e2d61d08d926358438"
"checksum arraydeque 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "96e774cadb24c2245225280c6799793f9802b918a58a79615e9490607489a717"
"checksum arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "699e63a93b79d717e8c3b5eb1b28b7780d0d6d9e59a72eb769291c83b0c8dc67"
"checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0"
"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
+"checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"
+"checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842"
"checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff"
"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e"
"checksum bindgen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c338079dafc81bef7d581f494b906603d12359c4306979eae6ca081925a4984"
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
@@ -1348,46 +1572,57 @@ dependencies = [
"checksum core-foundation-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41115a6aa5d3e1e5ef98148373f25971d1fad53818553f216495f9e67e90a624"
"checksum core-graphics 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a9f841e9637adec70838c537cae52cb4c751cc6514ad05669b51d107c2021c79"
"checksum core-text 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16ce16d9ed00181016c11ff48e561314bec92bfbce9fe48f319366618d4e5de6"
"checksum cssparser 0.19.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f9442c00898020a56c9485d64c9c8f14ae30ba45be89d15846046593383467f"
"checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
"checksum darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9861a8495606435477df581bc858ccf15a3469747edf175b94a4704fd9aaedac"
"checksum darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1486a8b00b45062c997f767738178b43219133dd0c8c826cb811e60563810821"
"checksum darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a86ec160aa0c3dd492dd4a14ec8104ad8f1a9400a820624db857998cc1f80f9"
+"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum dtoa-short 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe6f727b406462fd57c95fed84d1b0dbfb5f0136fcac005adba9ea0367c05cc8"
"checksum dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36e3b27cd0b8a68e00f07e8d8e1e4f4d8a6b8b873290a734f63bd56d792d23e1"
"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
"checksum encoding_c 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1e563195f16d7439103c49281b8b00bd0f223c16e19f0d500448239a27712570"
"checksum encoding_rs 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e00a1b1e95eb46988805ceee6f34cd95c46a6753e290cb3ff0486931989d4a4c"
"checksum env_logger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ed39959122ea027670b704fb70539f4286ddf4a49eefede23bf0b4b2a069ec03"
+"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
"checksum euclid 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7be9fcb1ce77782eb620253eb02bc1f000545f3c360841a26cda572f10fad4ff"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "398b8a11884898184d55aca9806f002b3cf68f0e860e0cbb4586f834ee39b0e7"
+"checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
"checksum futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
"checksum gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f72af1e933f296b827361eb9e70d0267abf8ad0de9ec7fa667bbe67177b297"
+"checksum gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "291055c78f59ca3d84c99026c9501c469413d386bb46be1e1cf1d285cd1db3b0"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum gl_generator 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0940975a4ca12b088d32b5d5134826c47d2e73de4b0b459b05244c01503eccbb"
"checksum gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "bf887141f0c2a83eae026cbf3fba74f0a5cb0f01d20e5cdfcd8c4ad39295be1e"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c7593b1522161003928c959c20a2ca421c68e940d63d75573316a009e48a6d4"
"checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa"
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
+"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
"checksum itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4833d6978da405305126af4ac88569b5d71ff758581ce5a987dbfa3755f694fc"
"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum khronos_api 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d5a08e2a31d665af8f1ca437eab6d00a93c9d62a549f73f9ed8fc2e55b5a91a7"
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
+"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
"checksum libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "38f5c2b18a287cf78b4097db62e20f43cace381dc76ae5c0a3073067f78b7ddc"
"checksum libloading 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be99f814beb3e9503a786a592c909692bb6d4fc5a695f6ed7987223acfbd5194"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
+"checksum memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b"
+"checksum mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9e965267d4d58496fc4f740e9861118367f13570cadf66316ed2c3f2f14d87c7"
+"checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"
+"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
"checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2"
"checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
"checksum num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "21e4df1098d1d797d27ef0c69c178c3fab64941559b290fcae198e0825c9c8b5"
"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99"
"checksum num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a225d1e2717567599c24f88e49f00856c6e825a12125181ee42c4257e3688d39"
"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba"
"checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
@@ -1408,26 +1643,28 @@ dependencies = [
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "705cf28d52a26a9ab548930a9a3d9799eb77cf84d66d7cc6e52fa222ca662424"
"checksum rayon-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c21a92a5dca958fb030787c1158446c6deb7f976399b72fa8074603f169e2a"
"checksum redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd35cc9a8bdec562c757e3d43c1526b5c6d2653e23e2315065bc25556550753"
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
+"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918"
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f530d36fb84ec48fb7146936881f026cdbf4892028835fd9398475f82c1bb4"
"checksum serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "10552fad5500771f3902d0c5ba187c5881942b811b7ba0d8fbbfbf84d80806d3"
"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a"
"checksum simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a94d14a2ae1f1f110937de5fb69e494372560181c7e1739a097fcc2cee37ba0"
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
+"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
"checksum smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f8266519bc1d17d0b5b16f6c21295625d562841c708f6376f49028a43e9c11e"
"checksum smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e40af10aafe98b4d8294ae8388d8a5cd0707c65d364872efe72d063ec44bee0"
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27e31aa4b09b9f4cb12dff3c30ba503e17b1a624413d764d32dab76e3920e5bc"
"checksum synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cf318c34a2f8381a4f3d4db2c91b45bca2b1cd8cbe56caced900647be164800c"
"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e"
@@ -1449,9 +1686,10 @@ dependencies = [
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562"
--- a/toolkit/library/gtest/rust/Cargo.toml
+++ b/toolkit/library/gtest/rust/Cargo.toml
@@ -4,16 +4,17 @@ version = "0.1.0"
authors = ["nobody@mozilla.org"]
license = "MPL-2.0"
description = "Testing code for libgkrust"
[features]
bindgen = ["gkrust-shared/bindgen"]
servo = ["gkrust-shared/servo"]
quantum_render = ["gkrust-shared/quantum_render"]
+cubeb-remoting = ["gkrust-shared/cubeb-remoting"]
cubeb_pulse_rust = ["gkrust-shared/cubeb_pulse_rust"]
gecko_debug = ["gkrust-shared/gecko_debug"]
simd-accel = ["gkrust-shared/simd-accel"]
no-static-ideograph-encoder-tables = ["gkrust-shared/no-static-ideograph-encoder-tables"]
# parallel-utf8 = ["gkrust-shared/parallel-utf8"]
[dependencies]
mp4parse-gtest = { path = "../../../../dom/media/gtest" }
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -66,16 +66,80 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "audioipc"
+version = "0.1.0"
+dependencies = [
+ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cubeb-core 0.1.0",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "audioipc-client"
+version = "0.1.0"
+dependencies = [
+ "audioipc 0.1.0",
+ "cubeb-backend 0.2.0",
+ "cubeb-core 0.1.0",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "audioipc-server"
+version = "0.1.0"
+dependencies = [
+ "audioipc 0.1.0",
+ "cubeb 0.3.0",
+ "cubeb-core 0.1.0",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "binary-space-partition"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bincode"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -249,16 +313,38 @@ source = "registry+https://github.com/ru
dependencies = [
"phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
"procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "cubeb"
+version = "0.3.0"
+dependencies = [
+ "cubeb-core 0.1.0",
+ "libcubeb-sys 0.1.0",
+]
+
+[[package]]
+name = "cubeb-backend"
+version = "0.2.0"
+dependencies = [
+ "cubeb-core 0.1.0",
+]
+
+[[package]]
+name = "cubeb-core"
+version = "0.1.0"
+dependencies = [
+ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "cubeb-ffi"
version = "0.0.1"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cubeb-pulse"
@@ -296,16 +382,25 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "dbghelp-sys"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "dtoa"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "dtoa-short"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -363,16 +458,24 @@ name = "env_logger"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "error-chain"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "euclid"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -387,16 +490,26 @@ source = "registry+https://github.com/ru
name = "freetype"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "fs2"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "futures"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -408,16 +521,21 @@ dependencies = [
name = "gamma-lut"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "gcc"
+version = "0.3.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "gdi32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -437,16 +555,21 @@ dependencies = [
"style 0.0.1",
"style_traits 0.0.1",
]
[[package]]
name = "gkrust-shared"
version = "0.1.0"
dependencies = [
+ "audioipc-client 0.1.0",
+ "audioipc-server 0.1.0",
+ "cubeb 0.3.0",
+ "cubeb-backend 0.2.0",
+ "cubeb-core 0.1.0",
"cubeb-pulse 0.0.1",
"encoding_c 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_glue 0.1.0",
"geckoservo 0.0.1",
"mp4parse_capi 0.8.0",
"nserror 0.1.0",
"nsstring 0.1.0",
"rust_url_capi 0.0.1",
@@ -496,16 +619,25 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "iovec"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "itertools"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -528,21 +660,33 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "lazycell"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "libc"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "libcubeb-sys"
+version = "0.1.0"
+dependencies = [
+ "cubeb-core 0.1.0",
+]
+
+[[package]]
name = "libloading"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -561,16 +705,63 @@ source = "registry+https://github.com/ru
name = "memchr"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "memmap"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mio"
+version = "0.6.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mio-uds"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "miow"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "mp4parse"
version = "0.8.0"
dependencies = [
"bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -579,16 +770,28 @@ name = "mp4parse_capi"
version = "0.8.0"
dependencies = [
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mp4parse 0.8.0",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "net2"
+version = "0.2.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "nodrop"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -851,16 +1054,21 @@ version = "0.0.1"
dependencies = [
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
"nserror 0.1.0",
"nsstring 0.1.0",
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "rustc-demangle"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "rustc-serialize"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "same-file"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -944,16 +1152,21 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "siphasher"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "slab"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "smallvec"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1295,32 +1508,43 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "ws2_32-sys"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "xml-rs"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum app_units 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ff4f3fe57393a150b39b026b6f6f4b9a6c4f49b52d0a4e2d61d08d926358438"
"checksum arraydeque 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "96e774cadb24c2245225280c6799793f9802b918a58a79615e9490607489a717"
"checksum arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "699e63a93b79d717e8c3b5eb1b28b7780d0d6d9e59a72eb769291c83b0c8dc67"
"checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0"
"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
+"checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"
+"checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842"
"checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff"
"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e"
"checksum bindgen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c338079dafc81bef7d581f494b906603d12359c4306979eae6ca081925a4984"
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
@@ -1335,46 +1559,57 @@ dependencies = [
"checksum core-foundation-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41115a6aa5d3e1e5ef98148373f25971d1fad53818553f216495f9e67e90a624"
"checksum core-graphics 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a9f841e9637adec70838c537cae52cb4c751cc6514ad05669b51d107c2021c79"
"checksum core-text 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16ce16d9ed00181016c11ff48e561314bec92bfbce9fe48f319366618d4e5de6"
"checksum cssparser 0.19.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f9442c00898020a56c9485d64c9c8f14ae30ba45be89d15846046593383467f"
"checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
"checksum darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9861a8495606435477df581bc858ccf15a3469747edf175b94a4704fd9aaedac"
"checksum darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1486a8b00b45062c997f767738178b43219133dd0c8c826cb811e60563810821"
"checksum darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a86ec160aa0c3dd492dd4a14ec8104ad8f1a9400a820624db857998cc1f80f9"
+"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum dtoa-short 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe6f727b406462fd57c95fed84d1b0dbfb5f0136fcac005adba9ea0367c05cc8"
"checksum dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36e3b27cd0b8a68e00f07e8d8e1e4f4d8a6b8b873290a734f63bd56d792d23e1"
"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
"checksum encoding_c 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1e563195f16d7439103c49281b8b00bd0f223c16e19f0d500448239a27712570"
"checksum encoding_rs 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e00a1b1e95eb46988805ceee6f34cd95c46a6753e290cb3ff0486931989d4a4c"
"checksum env_logger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ed39959122ea027670b704fb70539f4286ddf4a49eefede23bf0b4b2a069ec03"
+"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
"checksum euclid 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7be9fcb1ce77782eb620253eb02bc1f000545f3c360841a26cda572f10fad4ff"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "398b8a11884898184d55aca9806f002b3cf68f0e860e0cbb4586f834ee39b0e7"
+"checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
"checksum futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
"checksum gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f72af1e933f296b827361eb9e70d0267abf8ad0de9ec7fa667bbe67177b297"
+"checksum gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "291055c78f59ca3d84c99026c9501c469413d386bb46be1e1cf1d285cd1db3b0"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum gl_generator 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0940975a4ca12b088d32b5d5134826c47d2e73de4b0b459b05244c01503eccbb"
"checksum gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "bf887141f0c2a83eae026cbf3fba74f0a5cb0f01d20e5cdfcd8c4ad39295be1e"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c7593b1522161003928c959c20a2ca421c68e940d63d75573316a009e48a6d4"
"checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa"
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
+"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
"checksum itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4833d6978da405305126af4ac88569b5d71ff758581ce5a987dbfa3755f694fc"
"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum khronos_api 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d5a08e2a31d665af8f1ca437eab6d00a93c9d62a549f73f9ed8fc2e55b5a91a7"
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
+"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
"checksum libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "38f5c2b18a287cf78b4097db62e20f43cace381dc76ae5c0a3073067f78b7ddc"
"checksum libloading 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be99f814beb3e9503a786a592c909692bb6d4fc5a695f6ed7987223acfbd5194"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
+"checksum memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b"
+"checksum mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9e965267d4d58496fc4f740e9861118367f13570cadf66316ed2c3f2f14d87c7"
+"checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"
+"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
"checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2"
"checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
"checksum num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "21e4df1098d1d797d27ef0c69c178c3fab64941559b290fcae198e0825c9c8b5"
"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99"
"checksum num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a225d1e2717567599c24f88e49f00856c6e825a12125181ee42c4257e3688d39"
"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba"
"checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
@@ -1395,26 +1630,28 @@ dependencies = [
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "705cf28d52a26a9ab548930a9a3d9799eb77cf84d66d7cc6e52fa222ca662424"
"checksum rayon-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c21a92a5dca958fb030787c1158446c6deb7f976399b72fa8074603f169e2a"
"checksum redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd35cc9a8bdec562c757e3d43c1526b5c6d2653e23e2315065bc25556550753"
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
+"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918"
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f530d36fb84ec48fb7146936881f026cdbf4892028835fd9398475f82c1bb4"
"checksum serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "10552fad5500771f3902d0c5ba187c5881942b811b7ba0d8fbbfbf84d80806d3"
"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a"
"checksum simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a94d14a2ae1f1f110937de5fb69e494372560181c7e1739a097fcc2cee37ba0"
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
+"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
"checksum smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f8266519bc1d17d0b5b16f6c21295625d562841c708f6376f49028a43e9c11e"
"checksum smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e40af10aafe98b4d8294ae8388d8a5cd0707c65d364872efe72d063ec44bee0"
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27e31aa4b09b9f4cb12dff3c30ba503e17b1a624413d764d32dab76e3920e5bc"
"checksum synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cf318c34a2f8381a4f3d4db2c91b45bca2b1cd8cbe56caced900647be164800c"
"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e"
@@ -1436,9 +1673,10 @@ dependencies = [
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562"
--- a/toolkit/library/rust/Cargo.toml
+++ b/toolkit/library/rust/Cargo.toml
@@ -4,16 +4,17 @@ version = "0.1.0"
authors = ["nobody@mozilla.org"]
license = "MPL-2.0"
description = "Rust code for libxul"
[features]
bindgen = ["gkrust-shared/bindgen"]
servo = ["gkrust-shared/servo"]
quantum_render = ["gkrust-shared/quantum_render"]
+cubeb-remoting = ["gkrust-shared/cubeb-remoting"]
cubeb_pulse_rust = ["gkrust-shared/cubeb_pulse_rust"]
gecko_debug = ["gkrust-shared/gecko_debug"]
simd-accel = ["gkrust-shared/simd-accel"]
no-static-ideograph-encoder-tables = ["gkrust-shared/no-static-ideograph-encoder-tables"]
# parallel-utf8 = ["gkrust-shared/parallel-utf8"]
[dependencies]
gkrust-shared = { path = "shared" }
--- a/toolkit/library/rust/gkrust-features.mozbuild
+++ b/toolkit/library/rust/gkrust-features.mozbuild
@@ -18,9 +18,12 @@ if CONFIG['MOZ_BUILD_WEBRENDER']:
gkrust_features += ['quantum_render']
if CONFIG['MOZ_PULSEAUDIO']:
gkrust_features += ['cubeb_pulse_rust']
if CONFIG['MOZ_RUST_SIMD']:
gkrust_features += ['simd-accel']
+if CONFIG['MOZ_CUBEB_REMOTING']:
+ gkrust_features += ['cubeb-remoting']
+
gkrust_features += ['no-static-ideograph-encoder-tables']
--- a/toolkit/library/rust/shared/Cargo.toml
+++ b/toolkit/library/rust/shared/Cargo.toml
@@ -8,24 +8,30 @@ description = "Shared Rust code for libx
[dependencies]
geckoservo = { path = "../../../../servo/ports/geckolib", optional = true }
mp4parse_capi = { path = "../../../../media/libstagefright/binding/mp4parse_capi" }
nsstring = { path = "../../../../xpcom/rust/nsstring" }
nserror = { path = "../../../../xpcom/rust/nserror" }
rust_url_capi = { path = "../../../../netwerk/base/rust-url-capi" }
webrender_bindings = { path = "../../../../gfx/webrender_bindings", optional = true }
cubeb-pulse = { path = "../../../../media/libcubeb/cubeb-pulse-rs", optional = true, features=["pulse-dlopen"] }
+cubeb-core = { path = "../../../../media/cubeb-rs/cubeb-core", optional = true }
+cubeb = { path = "../../../../media/cubeb-rs/cubeb-api", optional = true }
+cubeb-backend = { path = "../../../../media/cubeb-rs/cubeb-backend", optional = true }
encoding_c = "0.7.1"
encoding_glue = { path = "../../../../intl/encoding_glue" }
+audioipc-client = { path = "../../../../media/audioipc/client", optional = true }
+audioipc-server = { path = "../../../../media/audioipc/server", optional = true }
[features]
default = []
bindgen = ["geckoservo/bindgen"]
servo = ["geckoservo"]
quantum_render = ["webrender_bindings"]
+cubeb-remoting = ["cubeb-core", "cubeb", "cubeb-backend", "audioipc-client", "audioipc-server"]
cubeb_pulse_rust = ["cubeb-pulse"]
gecko_debug = ["geckoservo/gecko_debug"]
simd-accel = ["encoding_c/simd-accel", "encoding_glue/simd-accel"]
no-static-ideograph-encoder-tables = ["encoding_c/no-static-ideograph-encoder-tables", "encoding_glue/no-static-ideograph-encoder-tables"]
parallel-utf8 = ["encoding_c/parallel-utf8", "encoding_glue/parallel-utf8"]
[lib]
path = "lib.rs"
--- a/toolkit/library/rust/shared/lib.rs
+++ b/toolkit/library/rust/shared/lib.rs
@@ -10,16 +10,20 @@ extern crate nsstring;
extern crate nserror;
extern crate rust_url_capi;
#[cfg(feature = "quantum_render")]
extern crate webrender_bindings;
#[cfg(feature = "cubeb_pulse_rust")]
extern crate cubeb_pulse;
extern crate encoding_c;
extern crate encoding_glue;
+#[cfg(feature = "cubeb-remoting")]
+extern crate audioipc_client;
+#[cfg(feature = "cubeb-remoting")]
+extern crate audioipc_server;
use std::boxed::Box;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::panic;
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -1171,8 +1171,22 @@ option('--enable-coverage', env='MOZ_COD
@depends('--enable-coverage')
def code_coverage(value):
if value:
return True
set_config('MOZ_CODE_COVERAGE', code_coverage)
set_define('MOZ_CODE_COVERAGE', code_coverage)
+
+# Cubeb Audio Remoting
+# ==============================================================
+
+option('--enable-cubeb-remoting', env='MOZ_CUBEB_REMOTING',
+ help='Enable cubeb audio remoting')
+
+@depends('--enable-cubeb-remoting')
+def cubeb_remoting(value):
+ if value:
+ return True
+
+set_config('MOZ_CUBEB_REMOTING', cubeb_remoting)
+set_define('MOZ_CUBEB_REMOTING', cubeb_remoting)