Bug 1391523 - P5: Compile in audioipc crates. r=kamidphish

MozReview-Commit-ID: 6BC0fu1rrEE

--HG--
extra : rebase_source : b986541c97eee9eaa70bbc54ccfcd63b2d3fa006
This commit is contained in:
Dan Glastonbury 2017-08-11 12:41:35 +10:00
parent f65b7278f8
commit f1e1b786c6
190 changed files with 28002 additions and 0 deletions

View File

@ -0,0 +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"}

View File

View File

@ -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

View File

@ -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

26
third_party/rust/error-chain/Cargo.toml vendored Normal file
View File

@ -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 }

36
third_party/rust/error-chain/README.md vendored Normal file
View File

@ -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

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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(())
}

View File

@ -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));
}
}

View File

@ -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])*])*) => {}
}

View File

@ -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
}
}

659
third_party/rust/error-chain/src/lib.rs vendored Normal file
View File

@ -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!{}
}

View File

@ -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 }
}

View File

@ -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 }
}

View File

@ -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(())
});
}

View File

@ -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())
);
}

18
third_party/rust/fs2/.appveyor.yml vendored Normal file
View File

@ -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

View File

@ -0,0 +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"}

0
third_party/rust/fs2/.cargo-ok vendored Normal file
View File

21
third_party/rust/fs2/.travis.yml vendored Normal file
View File

@ -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

30
third_party/rust/fs2/Cargo.toml vendored Normal file
View File

@ -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"

201
third_party/rust/fs2/LICENSE-APACHE vendored Normal file
View File

@ -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.

25
third_party/rust/fs2/LICENSE-MIT vendored Normal file
View File

@ -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.

50
third_party/rust/fs2/README.md vendored Normal file
View File

@ -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.

452
third_party/rust/fs2/src/lib.rs vendored Normal file
View File

@ -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());
});
}
}

250
third_party/rust/fs2/src/unix.rs vendored Normal file
View File

@ -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();
}
}

271
third_party/rust/fs2/src/windows.rs vendored Normal file
View File

@ -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());
}
}

View File

@ -0,0 +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"}

0
third_party/rust/iovec/.cargo-ok vendored Normal file
View File

24
third_party/rust/iovec/.travis.yml vendored Normal file
View File

@ -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

20
third_party/rust/iovec/Cargo.toml vendored Normal file
View File

@ -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"

201
third_party/rust/iovec/LICENSE-APACHE vendored Normal file
View File

@ -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.

25
third_party/rust/iovec/LICENSE-MIT vendored Normal file
View File

@ -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.

35
third_party/rust/iovec/README.md vendored Normal file
View File

@ -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.

16
third_party/rust/iovec/appveyor.yml vendored Normal file
View File

@ -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

134
third_party/rust/iovec/src/lib.rs vendored Normal file
View File

@ -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"[..]);
}
}

17
third_party/rust/iovec/src/sys/mod.rs vendored Normal file
View File

@ -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,
};

50
third_party/rust/iovec/src/sys/unix.rs vendored Normal file
View File

@ -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(),
})
}
}
}

View File

@ -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,
})
}
}
}

68
third_party/rust/iovec/src/unix.rs vendored Normal file
View File

@ -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) }
}

0
third_party/rust/iovec/src/windows.rs vendored Normal file
View File

View File

@ -0,0 +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"}

0
third_party/rust/lazycell/.cargo-ok vendored Normal file
View File

80
third_party/rust/lazycell/CHANGELOG.md vendored Normal file
View File

@ -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))

26
third_party/rust/lazycell/Cargo.toml vendored Normal file
View File

@ -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"]

201
third_party/rust/lazycell/LICENSE-APACHE vendored Normal file
View File

@ -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.

26
third_party/rust/lazycell/LICENSE-MIT vendored Normal file
View File

@ -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.

76
third_party/rust/lazycell/README.md vendored Normal file
View File

@ -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"

234
third_party/rust/lazycell/src/lib.rs vendored Normal file
View File

@ -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));
}
}

59
third_party/rust/memmap/.appveyor.yml vendored Normal file
View File

@ -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

View File

@ -0,0 +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"}

0
third_party/rust/memmap/.cargo-ok vendored Normal file
View File

69
third_party/rust/memmap/.travis.yml vendored Normal file
View File

@ -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

20
third_party/rust/memmap/Cargo.toml vendored Normal file
View File

@ -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"

201
third_party/rust/memmap/LICENSE-APACHE vendored Normal file
View File

@ -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.

25
third_party/rust/memmap/LICENSE-MIT vendored Normal file
View File

@ -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.

53
third_party/rust/memmap/README.md vendored Normal file
View File

@ -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.

31
third_party/rust/memmap/ci/install.sh vendored Normal file
View File

@ -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

21
third_party/rust/memmap/ci/script.sh vendored Normal file
View File

@ -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

16
third_party/rust/memmap/examples/cat.rs vendored Normal file
View File

@ -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();
}

933
third_party/rust/memmap/src/lib.rs vendored Normal file
View File

@ -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() });
}
}

182
third_party/rust/memmap/src/unix.rs vendored Normal file
View File

@ -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
}
}

194
third_party/rust/memmap/src/windows.rs vendored Normal file
View File

@ -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;
}
}

View File

@ -0,0 +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"}

0
third_party/rust/mio-uds/.cargo-ok vendored Normal file
View File

23
third_party/rust/mio-uds/.travis.yml vendored Normal file
View File

@ -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

23
third_party/rust/mio-uds/Cargo.toml vendored Normal file
View File

@ -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"

201
third_party/rust/mio-uds/LICENSE-APACHE vendored Normal file
View File

@ -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.

25
third_party/rust/mio-uds/LICENSE-MIT vendored Normal file
View File

@ -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.

35
third_party/rust/mio-uds/README.md vendored Normal file
View File

@ -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.

183
third_party/rust/mio-uds/src/datagram.rs vendored Normal file
View File

@ -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) }
}
}

27
third_party/rust/mio-uds/src/lib.rs vendored Normal file
View File

@ -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)
}
}

134
third_party/rust/mio-uds/src/listener.rs vendored Normal file
View File

@ -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) }
}
}

141
third_party/rust/mio-uds/src/socket.rs vendored Normal file
View File

@ -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
}
}

189
third_party/rust/mio-uds/src/stream.rs vendored Normal file
View File

@ -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) }
}
}

276
third_party/rust/mio-uds/tests/echo.rs vendored Normal file
View File

@ -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());
}
}
}

66
third_party/rust/mio-uds/tests/smoke.rs vendored Normal file
View File

@ -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);
}

File diff suppressed because one or more lines are too long

0
third_party/rust/mio/.cargo-ok vendored Normal file
View File

128
third_party/rust/mio/CHANGELOG.md vendored Normal file
View File

@ -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

47
third_party/rust/mio/Cargo.toml vendored Normal file
View File

@ -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"

19
third_party/rust/mio/LICENSE vendored Normal file
View File

@ -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.

89
third_party/rust/mio/README.md vendored Normal file
View File

@ -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).

20
third_party/rust/mio/appveyor.yml vendored Normal file
View File

@ -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

View File

@ -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();
}
})
}

View File

@ -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

View File

@ -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
}

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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();
}

33
third_party/rust/mio/ci/run-docker.sh vendored Normal file
View File

@ -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

34
third_party/rust/mio/ci/run-ios.sh vendored Executable file
View File

@ -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

42
third_party/rust/mio/ci/run.sh vendored Executable file
View File

@ -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

Some files were not shown because too many files have changed in this diff Show More