mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1391523 - P5: Compile in audioipc crates. r=kamidphish
MozReview-Commit-ID: 6BC0fu1rrEE --HG-- extra : rebase_source : b986541c97eee9eaa70bbc54ccfcd63b2d3fa006
This commit is contained in:
parent
f65b7278f8
commit
f1e1b786c6
1
third_party/rust/error-chain/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/error-chain/.cargo-checksum.json
vendored
Normal 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"}
|
0
third_party/rust/error-chain/.cargo-ok
vendored
Normal file
0
third_party/rust/error-chain/.cargo-ok
vendored
Normal file
45
third_party/rust/error-chain/.travis.yml
vendored
Normal file
45
third_party/rust/error-chain/.travis.yml
vendored
Normal 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
|
100
third_party/rust/error-chain/CHANGELOG.md
vendored
Normal file
100
third_party/rust/error-chain/CHANGELOG.md
vendored
Normal 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
26
third_party/rust/error-chain/Cargo.toml
vendored
Normal 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
36
third_party/rust/error-chain/README.md
vendored
Normal 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
|
36
third_party/rust/error-chain/examples/all.rs
vendored
Normal file
36
third_party/rust/error-chain/examples/all.rs
vendored
Normal 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() {}
|
29
third_party/rust/error-chain/examples/doc.rs
vendored
Normal file
29
third_party/rust/error-chain/examples/doc.rs
vendored
Normal 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() {}
|
77
third_party/rust/error-chain/examples/quickstart.rs
vendored
Normal file
77
third_party/rust/error-chain/examples/quickstart.rs
vendored
Normal 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(())
|
||||
}
|
40
third_party/rust/error-chain/examples/size.rs
vendored
Normal file
40
third_party/rust/error-chain/examples/size.rs
vendored
Normal 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));
|
||||
}
|
||||
}
|
426
third_party/rust/error-chain/src/error_chain.rs
vendored
Normal file
426
third_party/rust/error-chain/src/error_chain.rs
vendored
Normal 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])*])*) => {}
|
||||
}
|
38
third_party/rust/error-chain/src/example_generated.rs
vendored
Normal file
38
third_party/rust/error-chain/src/example_generated.rs
vendored
Normal 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
659
third_party/rust/error-chain/src/lib.rs
vendored
Normal 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!{}
|
||||
}
|
529
third_party/rust/error-chain/src/quick_error.rs
vendored
Normal file
529
third_party/rust/error-chain/src/quick_error.rs
vendored
Normal 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 }
|
||||
}
|
73
third_party/rust/error-chain/src/quick_main.rs
vendored
Normal file
73
third_party/rust/error-chain/src/quick_main.rs
vendored
Normal 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 }
|
||||
}
|
30
third_party/rust/error-chain/tests/quick_main.rs
vendored
Normal file
30
third_party/rust/error-chain/tests/quick_main.rs
vendored
Normal 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(())
|
||||
});
|
||||
}
|
595
third_party/rust/error-chain/tests/tests.rs
vendored
Normal file
595
third_party/rust/error-chain/tests/tests.rs
vendored
Normal 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
18
third_party/rust/fs2/.appveyor.yml
vendored
Normal 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
|
1
third_party/rust/fs2/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/fs2/.cargo-checksum.json
vendored
Normal 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
0
third_party/rust/fs2/.cargo-ok
vendored
Normal file
21
third_party/rust/fs2/.travis.yml
vendored
Normal file
21
third_party/rust/fs2/.travis.yml
vendored
Normal 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
30
third_party/rust/fs2/Cargo.toml
vendored
Normal 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
201
third_party/rust/fs2/LICENSE-APACHE
vendored
Normal 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
25
third_party/rust/fs2/LICENSE-MIT
vendored
Normal 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
50
third_party/rust/fs2/README.md
vendored
Normal 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
452
third_party/rust/fs2/src/lib.rs
vendored
Normal 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
250
third_party/rust/fs2/src/unix.rs
vendored
Normal 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
271
third_party/rust/fs2/src/windows.rs
vendored
Normal 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());
|
||||
}
|
||||
}
|
1
third_party/rust/iovec/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/iovec/.cargo-checksum.json
vendored
Normal 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
0
third_party/rust/iovec/.cargo-ok
vendored
Normal file
24
third_party/rust/iovec/.travis.yml
vendored
Normal file
24
third_party/rust/iovec/.travis.yml
vendored
Normal 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
20
third_party/rust/iovec/Cargo.toml
vendored
Normal 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
201
third_party/rust/iovec/LICENSE-APACHE
vendored
Normal 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
25
third_party/rust/iovec/LICENSE-MIT
vendored
Normal 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
35
third_party/rust/iovec/README.md
vendored
Normal 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
16
third_party/rust/iovec/appveyor.yml
vendored
Normal 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
134
third_party/rust/iovec/src/lib.rs
vendored
Normal 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
17
third_party/rust/iovec/src/sys/mod.rs
vendored
Normal 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
50
third_party/rust/iovec/src/sys/unix.rs
vendored
Normal 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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
54
third_party/rust/iovec/src/sys/windows.rs
vendored
Normal file
54
third_party/rust/iovec/src/sys/windows.rs
vendored
Normal 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
68
third_party/rust/iovec/src/unix.rs
vendored
Normal 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
0
third_party/rust/iovec/src/windows.rs
vendored
Normal file
1
third_party/rust/lazycell/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/lazycell/.cargo-checksum.json
vendored
Normal 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
0
third_party/rust/lazycell/.cargo-ok
vendored
Normal file
80
third_party/rust/lazycell/CHANGELOG.md
vendored
Normal file
80
third_party/rust/lazycell/CHANGELOG.md
vendored
Normal 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
26
third_party/rust/lazycell/Cargo.toml
vendored
Normal 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
201
third_party/rust/lazycell/LICENSE-APACHE
vendored
Normal 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
26
third_party/rust/lazycell/LICENSE-MIT
vendored
Normal 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
76
third_party/rust/lazycell/README.md
vendored
Normal 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
234
third_party/rust/lazycell/src/lib.rs
vendored
Normal 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
59
third_party/rust/memmap/.appveyor.yml
vendored
Normal 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
|
1
third_party/rust/memmap/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/memmap/.cargo-checksum.json
vendored
Normal 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
0
third_party/rust/memmap/.cargo-ok
vendored
Normal file
69
third_party/rust/memmap/.travis.yml
vendored
Normal file
69
third_party/rust/memmap/.travis.yml
vendored
Normal 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
20
third_party/rust/memmap/Cargo.toml
vendored
Normal 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
201
third_party/rust/memmap/LICENSE-APACHE
vendored
Normal 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
25
third_party/rust/memmap/LICENSE-MIT
vendored
Normal 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
53
third_party/rust/memmap/README.md
vendored
Normal 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
31
third_party/rust/memmap/ci/install.sh
vendored
Normal 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
21
third_party/rust/memmap/ci/script.sh
vendored
Normal 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
16
third_party/rust/memmap/examples/cat.rs
vendored
Normal 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
933
third_party/rust/memmap/src/lib.rs
vendored
Normal 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
182
third_party/rust/memmap/src/unix.rs
vendored
Normal 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
194
third_party/rust/memmap/src/windows.rs
vendored
Normal 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;
|
||||
}
|
||||
}
|
1
third_party/rust/mio-uds/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/mio-uds/.cargo-checksum.json
vendored
Normal 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
0
third_party/rust/mio-uds/.cargo-ok
vendored
Normal file
23
third_party/rust/mio-uds/.travis.yml
vendored
Normal file
23
third_party/rust/mio-uds/.travis.yml
vendored
Normal 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
23
third_party/rust/mio-uds/Cargo.toml
vendored
Normal 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
201
third_party/rust/mio-uds/LICENSE-APACHE
vendored
Normal 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
25
third_party/rust/mio-uds/LICENSE-MIT
vendored
Normal 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
35
third_party/rust/mio-uds/README.md
vendored
Normal 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
183
third_party/rust/mio-uds/src/datagram.rs
vendored
Normal 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
27
third_party/rust/mio-uds/src/lib.rs
vendored
Normal 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
134
third_party/rust/mio-uds/src/listener.rs
vendored
Normal 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
141
third_party/rust/mio-uds/src/socket.rs
vendored
Normal 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
189
third_party/rust/mio-uds/src/stream.rs
vendored
Normal 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
276
third_party/rust/mio-uds/tests/echo.rs
vendored
Normal 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
66
third_party/rust/mio-uds/tests/smoke.rs
vendored
Normal 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);
|
||||
}
|
1
third_party/rust/mio/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/mio/.cargo-checksum.json
vendored
Normal file
File diff suppressed because one or more lines are too long
0
third_party/rust/mio/.cargo-ok
vendored
Normal file
0
third_party/rust/mio/.cargo-ok
vendored
Normal file
128
third_party/rust/mio/CHANGELOG.md
vendored
Normal file
128
third_party/rust/mio/CHANGELOG.md
vendored
Normal 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
47
third_party/rust/mio/Cargo.toml
vendored
Normal 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
19
third_party/rust/mio/LICENSE
vendored
Normal 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
89
third_party/rust/mio/README.md
vendored
Normal 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
20
third_party/rust/mio/appveyor.yml
vendored
Normal 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
|
52
third_party/rust/mio/benches/bench_poll.rs
vendored
Normal file
52
third_party/rust/mio/benches/bench_poll.rs
vendored
Normal 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();
|
||||
}
|
||||
})
|
||||
}
|
48
third_party/rust/mio/ci/docker/aarch64-linux-android/Dockerfile
vendored
Normal file
48
third_party/rust/mio/ci/docker/aarch64-linux-android/Dockerfile
vendored
Normal 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
|
15
third_party/rust/mio/ci/docker/aarch64-linux-android/accept-licenses.sh
vendored
Executable file
15
third_party/rust/mio/ci/docker/aarch64-linux-android/accept-licenses.sh
vendored
Executable 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
|
||||
}
|
16
third_party/rust/mio/ci/docker/aarch64-linux-android/cargo_config
vendored
Normal file
16
third_party/rust/mio/ci/docker/aarch64-linux-android/cargo_config
vendored
Normal 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"
|
21
third_party/rust/mio/ci/docker/aarch64-linux-android/install-ndk.sh
vendored
Normal file
21
third_party/rust/mio/ci/docker/aarch64-linux-android/install-ndk.sh
vendored
Normal 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
|
37
third_party/rust/mio/ci/docker/aarch64-linux-android/install-sdk.sh
vendored
Normal file
37
third_party/rust/mio/ci/docker/aarch64-linux-android/install-sdk.sh
vendored
Normal 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
|
37
third_party/rust/mio/ci/docker/arm-linux-androideabi/Dockerfile
vendored
Normal file
37
third_party/rust/mio/ci/docker/arm-linux-androideabi/Dockerfile
vendored
Normal 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
|
15
third_party/rust/mio/ci/docker/arm-linux-androideabi/accept-licenses.sh
vendored
Executable file
15
third_party/rust/mio/ci/docker/arm-linux-androideabi/accept-licenses.sh
vendored
Executable 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
|
||||
}
|
16
third_party/rust/mio/ci/docker/arm-linux-androideabi/cargo_config
vendored
Normal file
16
third_party/rust/mio/ci/docker/arm-linux-androideabi/cargo_config
vendored
Normal 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"
|
21
third_party/rust/mio/ci/docker/arm-linux-androideabi/install-ndk.sh
vendored
Normal file
21
third_party/rust/mio/ci/docker/arm-linux-androideabi/install-ndk.sh
vendored
Normal 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
|
33
third_party/rust/mio/ci/docker/arm-linux-androideabi/install-sdk.sh
vendored
Normal file
33
third_party/rust/mio/ci/docker/arm-linux-androideabi/install-sdk.sh
vendored
Normal 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
|
202
third_party/rust/mio/ci/ios/deploy_and_run_on_ios_simulator.rs
vendored
Normal file
202
third_party/rust/mio/ci/ios/deploy_and_run_on_ios_simulator.rs
vendored
Normal 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
33
third_party/rust/mio/ci/run-docker.sh
vendored
Normal 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
34
third_party/rust/mio/ci/run-ios.sh
vendored
Executable 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
42
third_party/rust/mio/ci/run.sh
vendored
Executable 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
Loading…
Reference in New Issue
Block a user