Bug 1550903 - Part 2: Revendor dependencies. r=emilio,kats,froydnj

It was unhappy about the new LICENSE (fuchsia-cprng) but it's the same
as the other fuschia crates. Since I don't think this is used at build
time but has the same license as the other fuschia crates, I put it in
the RUNTIME_LICENSE_PACKAGE_WHITELIST list. I also removed sha1 from
that list as it's not used anymore

Differential Revision: https://phabricator.services.mozilla.com/D30746

--HG--
rename : third_party/rust/httparse/Cargo.toml => third_party/rust/autocfg/Cargo.toml
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/autocfg/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/autocfg/LICENSE-MIT
rename : third_party/rust/httparse/Cargo.toml => third_party/rust/cloudabi/Cargo.toml
rename : third_party/rust/httparse/Cargo.toml => third_party/rust/fuchsia-cprng/Cargo.toml
rename : third_party/rust/sha1/LICENSE => third_party/rust/fuchsia-cprng/LICENSE
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/mio-extras/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/mio-extras/LICENSE-MIT
rename : third_party/rust/rand/.cargo-checksum.json => third_party/rust/rand-0.4.3/.cargo-checksum.json
rename : third_party/rust/rand/CHANGELOG.md => third_party/rust/rand-0.4.3/CHANGELOG.md
rename : third_party/rust/rand/Cargo.toml => third_party/rust/rand-0.4.3/Cargo.toml
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand-0.4.3/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand-0.4.3/LICENSE-MIT
rename : third_party/rust/rand/README.md => third_party/rust/rand-0.4.3/README.md
rename : third_party/rust/rand/appveyor.yml => third_party/rust/rand-0.4.3/appveyor.yml
rename : third_party/rust/rand/benches/bench.rs => third_party/rust/rand-0.4.3/benches/bench.rs
rename : third_party/rust/rand/benches/distributions/exponential.rs => third_party/rust/rand-0.4.3/benches/distributions/exponential.rs
rename : third_party/rust/rand/benches/distributions/gamma.rs => third_party/rust/rand-0.4.3/benches/distributions/gamma.rs
rename : third_party/rust/rand/benches/distributions/mod.rs => third_party/rust/rand-0.4.3/benches/distributions/mod.rs
rename : third_party/rust/rand/benches/distributions/normal.rs => third_party/rust/rand-0.4.3/benches/distributions/normal.rs
rename : third_party/rust/rand/benches/generators.rs => third_party/rust/rand-0.4.3/benches/generators.rs
rename : third_party/rust/rand/benches/misc.rs => third_party/rust/rand-0.4.3/benches/misc.rs
rename : third_party/rust/rand/src/distributions/exponential.rs => third_party/rust/rand-0.4.3/src/distributions/exponential.rs
rename : third_party/rust/rand/src/distributions/gamma.rs => third_party/rust/rand-0.4.3/src/distributions/gamma.rs
rename : third_party/rust/rand/src/distributions/mod.rs => third_party/rust/rand-0.4.3/src/distributions/mod.rs
rename : third_party/rust/rand/src/distributions/normal.rs => third_party/rust/rand-0.4.3/src/distributions/normal.rs
rename : third_party/rust/rand/src/distributions/range.rs => third_party/rust/rand-0.4.3/src/distributions/range.rs
rename : third_party/rust/rand/src/distributions/ziggurat_tables.rs => third_party/rust/rand-0.4.3/src/distributions/ziggurat_tables.rs
rename : third_party/rust/rand/src/jitter.rs => third_party/rust/rand-0.4.3/src/jitter.rs
rename : third_party/rust/rand/src/lib.rs => third_party/rust/rand-0.4.3/src/lib.rs
rename : third_party/rust/rand/src/os.rs => third_party/rust/rand-0.4.3/src/os.rs
rename : third_party/rust/rand/src/prng/chacha.rs => third_party/rust/rand-0.4.3/src/prng/chacha.rs
rename : third_party/rust/rand/src/prng/isaac.rs => third_party/rust/rand-0.4.3/src/prng/isaac.rs
rename : third_party/rust/rand/src/prng/isaac64.rs => third_party/rust/rand-0.4.3/src/prng/isaac64.rs
rename : third_party/rust/rand/src/prng/mod.rs => third_party/rust/rand-0.4.3/src/prng/mod.rs
rename : third_party/rust/rand/src/prng/xorshift.rs => third_party/rust/rand-0.4.3/src/prng/xorshift.rs
rename : third_party/rust/rand/src/rand_impls.rs => third_party/rust/rand-0.4.3/src/rand_impls.rs
rename : third_party/rust/rand/src/read.rs => third_party/rust/rand-0.4.3/src/read.rs
rename : third_party/rust/rand/src/reseeding.rs => third_party/rust/rand-0.4.3/src/reseeding.rs
rename : third_party/rust/rand/src/seq.rs => third_party/rust/rand-0.4.3/src/seq.rs
rename : third_party/rust/rand/utils/ziggurat_tables.py => third_party/rust/rand-0.4.3/utils/ziggurat_tables.py
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_chacha/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_chacha/LICENSE-MIT
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_core-0.3.1/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_core-0.3.1/LICENSE-MIT
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_core/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_core/LICENSE-MIT
rename : third_party/rust/httparse/Cargo.toml => third_party/rust/rand_hc/Cargo.toml
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_hc/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_hc/LICENSE-MIT
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_isaac/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_isaac/LICENSE-MIT
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_jitter/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_jitter/LICENSE-MIT
rename : third_party/rust/rand/src/jitter.rs => third_party/rust/rand_jitter/src/lib.rs
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_os/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_os/LICENSE-MIT
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_pcg/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_pcg/LICENSE-MIT
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_xorshift/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_xorshift/LICENSE-MIT
rename : third_party/rust/httparse/Cargo.toml => third_party/rust/rdrand/Cargo.toml
rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/sha-1/LICENSE-APACHE
rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/sha-1/LICENSE-MIT
extra : moz-landing-system : lando
This commit is contained in:
Bastien Orivel 2019-05-18 13:39:31 +00:00
parent cf92185937
commit 8a3f3e785c
332 changed files with 38996 additions and 4598 deletions

View File

@ -165,6 +165,7 @@ Please commit or stash these changes before vendoring, or re-run with `--ignore-
'bindgen',
'fuchsia-zircon',
'fuchsia-zircon-sys',
'fuchsia-cprng',
]
}
@ -172,7 +173,6 @@ Please commit or stash these changes before vendoring, or re-run with `--ignore-
# license, but that also need to explicitly mentioned in about:license.
RUNTIME_LICENSE_PACKAGE_WHITELIST = {
'BSD-3-Clause': [
'sha1',
]
}

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"59b541962c15f51087a11d7296e3b69ec6d9b8a8e9e8db949e7629ea28183564","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac","README.md":"d0e320dccace525a2cbcf3bc5d43ac9b7b61ee86b9c9713bf68993c3ad789d0a","examples/integers.rs":"589ff4271566dfa322becddf3e2c7b592e6e0bc97b02892ce75619b7e452e930","examples/paths.rs":"1b30e466b824ce8df7ad0a55334424131d9d2573d6cf9f7d5d50c09c8901d526","examples/traits.rs":"cbee6a3e1f7db60b02ae25b714926517144a77cb492021f492774cf0e1865a9e","examples/versions.rs":"38535e6d9f5bfae0de474a3db79a40e8f5da8ba9334c5ff4c363de9bc99d4d12","src/error.rs":"12de7dafea4a35d1dc2f0fa79bfa038386bbbea72bf083979f4ddf227999eeda","src/lib.rs":"7392068683dc86107bcf8073c81ff8fb7026f5fb98a355a4d47301c5946eeccb","src/tests.rs":"34bdceeffdbdd7f2535a6ed8272482b17325dba044c91bb96f3f8caeec58a83d","src/version.rs":"165324950f2195aaf068c47a4f2f0992b2bf18d8b7f4f17b6b264767523c0e5d"},"package":"a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"}

24
third_party/rust/autocfg/Cargo.toml vendored Normal file
View File

@ -0,0 +1,24 @@
# 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 = "autocfg"
version = "0.1.2"
authors = ["Josh Stone <cuviper@gmail.com>"]
description = "Automatic cfg for Rust compiler features"
readme = "README.md"
keywords = ["rustc", "build", "autoconf"]
categories = ["development-tools::build-utils"]
license = "Apache-2.0/MIT"
repository = "https://github.com/cuviper/autocfg"
[dependencies]

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

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

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

@ -0,0 +1,25 @@
Copyright (c) 2018 Josh Stone
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.

68
third_party/rust/autocfg/README.md vendored Normal file
View File

@ -0,0 +1,68 @@
autocfg
=======
[![autocfg crate](https://img.shields.io/crates/v/autocfg.svg)](https://crates.io/crates/autocfg)
[![autocfg documentation](https://docs.rs/autocfg/badge.svg)](https://docs.rs/autocfg)
![minimum rustc 1.0](https://img.shields.io/badge/rustc-1.0+-red.svg)
[![Travis Status](https://travis-ci.org/cuviper/autocfg.svg?branch=master)](https://travis-ci.org/cuviper/autocfg)
A Rust library for build scripts to automatically configure code based on
compiler support. Code snippets are dynamically tested to see if the `rustc`
will accept them, rather than hard-coding specific version support.
## Usage
Add this to your `Cargo.toml`:
```toml
[build-dependencies]
autocfg = "0.1"
```
Then use it in your `build.rs` script to detect compiler features. For
example, to test for 128-bit integer support, it might look like:
```rust
extern crate autocfg;
fn main() {
let ac = autocfg::new();
ac.emit_has_type("i128");
// (optional) We don't need to rerun for anything external.
autocfg::rerun_path(file!());
}
```
If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line
for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the
rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that
should only be used when the compiler supports it.
## Release Notes
- 0.1.2 (2018-01-16)
- Add `rerun_env(ENV)` to print `cargo:rerun-if-env-changed=ENV`
- Add `rerun_path(PATH)` to print `cargo:rerun-if-changed=PATH`
## Minimum Rust version policy
This crate's minimum supported `rustc` version is `1.0.0`. Compatibility is
its entire reason for existence, so this crate will be extremely conservative
about raising this requirement. If this is ever deemed necessary, it will be
treated as a major breaking change for semver purposes.
## License
This project is licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
http://opensource.org/licenses/MIT)
at your option.

View File

@ -0,0 +1,9 @@
extern crate autocfg;
fn main() {
// Normally, cargo will set `OUT_DIR` for build scripts.
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
for i in 3..8 {
ac.emit_has_type(&format!("i{}", 1 << i));
}
}

View File

@ -0,0 +1,22 @@
extern crate autocfg;
fn main() {
// Normally, cargo will set `OUT_DIR` for build scripts.
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
// since ancient times...
ac.emit_has_path("std::vec::Vec");
ac.emit_path_cfg("std::vec::Vec", "has_vec");
// rustc 1.10.0
ac.emit_has_path("std::panic::PanicInfo");
ac.emit_path_cfg("std::panic::PanicInfo", "has_panic_info");
// rustc 1.20.0
ac.emit_has_path("std::mem::ManuallyDrop");
ac.emit_path_cfg("std::mem::ManuallyDrop", "has_manually_drop");
// rustc 1.25.0
ac.emit_has_path("std::ptr::NonNull");
ac.emit_path_cfg("std::ptr::NonNull", "has_non_null");
}

View File

@ -0,0 +1,26 @@
extern crate autocfg;
fn main() {
// Normally, cargo will set `OUT_DIR` for build scripts.
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
// since ancient times...
ac.emit_has_trait("std::ops::Add");
ac.emit_trait_cfg("std::ops::Add", "has_ops");
// trait parameters have to be provided
ac.emit_has_trait("std::borrow::Borrow<str>");
ac.emit_trait_cfg("std::borrow::Borrow<str>", "has_borrow");
// rustc 1.8.0
ac.emit_has_trait("std::ops::AddAssign");
ac.emit_trait_cfg("std::ops::AddAssign", "has_assign_ops");
// rustc 1.12.0
ac.emit_has_trait("std::iter::Sum");
ac.emit_trait_cfg("std::iter::Sum", "has_sum");
// rustc 1.28.0
ac.emit_has_trait("std::alloc::GlobalAlloc");
ac.emit_trait_cfg("std::alloc::GlobalAlloc", "has_global_alloc");
}

View File

@ -0,0 +1,9 @@
extern crate autocfg;
fn main() {
// Normally, cargo will set `OUT_DIR` for build scripts.
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
for i in 0..100 {
ac.emit_rustc_version(1, i);
}
}

69
third_party/rust/autocfg/src/error.rs vendored Normal file
View File

@ -0,0 +1,69 @@
use std::error;
use std::fmt;
use std::io;
use std::num;
use std::str;
/// A common error type for the `autocfg` crate.
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
}
impl error::Error for Error {
fn description(&self) -> &str {
"AutoCfg error"
}
fn cause(&self) -> Option<&error::Error> {
match self.kind {
ErrorKind::Io(ref e) => Some(e),
ErrorKind::Num(ref e) => Some(e),
ErrorKind::Utf8(ref e) => Some(e),
ErrorKind::Other(_) => None,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self.kind {
ErrorKind::Io(ref e) => e.fmt(f),
ErrorKind::Num(ref e) => e.fmt(f),
ErrorKind::Utf8(ref e) => e.fmt(f),
ErrorKind::Other(s) => s.fmt(f),
}
}
}
#[derive(Debug)]
enum ErrorKind {
Io(io::Error),
Num(num::ParseIntError),
Utf8(str::Utf8Error),
Other(&'static str),
}
pub fn from_io(e: io::Error) -> Error {
Error {
kind: ErrorKind::Io(e),
}
}
pub fn from_num(e: num::ParseIntError) -> Error {
Error {
kind: ErrorKind::Num(e),
}
}
pub fn from_utf8(e: str::Utf8Error) -> Error {
Error {
kind: ErrorKind::Utf8(e),
}
}
pub fn from_str(s: &'static str) -> Error {
Error {
kind: ErrorKind::Other(s),
}
}

288
third_party/rust/autocfg/src/lib.rs vendored Normal file
View File

@ -0,0 +1,288 @@
//! A Rust library for build scripts to automatically configure code based on
//! compiler support. Code snippets are dynamically tested to see if the `rustc`
//! will accept them, rather than hard-coding specific version support.
//!
//!
//! ## Usage
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [build-dependencies]
//! autocfg = "0.1"
//! ```
//!
//! Then use it in your `build.rs` script to detect compiler features. For
//! example, to test for 128-bit integer support, it might look like:
//!
//! ```rust
//! extern crate autocfg;
//!
//! fn main() {
//! # // Normally, cargo will set `OUT_DIR` for build scripts.
//! # std::env::set_var("OUT_DIR", "target");
//! let ac = autocfg::new();
//! ac.emit_has_type("i128");
//!
//! // (optional) We don't need to rerun for anything external.
//! autocfg::rerun_path(file!());
//! }
//! ```
//!
//! If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line
//! for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the
//! rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that
//! should only be used when the compiler supports it.
#![deny(missing_debug_implementations)]
#![deny(missing_docs)]
use std::env;
use std::ffi::OsString;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};
mod error;
pub use error::Error;
mod version;
use version::Version;
#[cfg(test)]
mod tests;
/// Helper to detect compiler features for `cfg` output in build scripts.
#[derive(Clone, Debug)]
pub struct AutoCfg {
out_dir: PathBuf,
rustc: PathBuf,
rustc_version: Version,
target: Option<OsString>,
}
/// Writes a config flag for rustc on standard out.
///
/// This looks like: `cargo:rustc-cfg=CFG`
///
/// Cargo will use this in arguments to rustc, like `--cfg CFG`.
pub fn emit(cfg: &str) {
println!("cargo:rustc-cfg={}", cfg);
}
/// Writes a line telling Cargo to rerun the build script if `path` changes.
///
/// This looks like: `cargo:rerun-if-changed=PATH`
///
/// This requires at least cargo 0.7.0, corresponding to rustc 1.6.0. Earlier
/// versions of cargo will simply ignore the directive.
pub fn rerun_path(path: &str) {
println!("cargo:rerun-if-changed={}", path);
}
/// Writes a line telling Cargo to rerun the build script if the environment
/// variable `var` changes.
///
/// This looks like: `cargo:rerun-if-env-changed=VAR`
///
/// This requires at least cargo 0.21.0, corresponding to rustc 1.20.0. Earlier
/// versions of cargo will simply ignore the directive.
pub fn rerun_env(var: &str) {
println!("cargo:rerun-if-env-changed={}", var);
}
/// Create a new `AutoCfg` instance.
///
/// # Panics
///
/// Panics if `AutoCfg::new()` returns an error.
pub fn new() -> AutoCfg {
AutoCfg::new().unwrap()
}
impl AutoCfg {
/// Create a new `AutoCfg` instance.
///
/// # Common errors
///
/// - `rustc` can't be executed, from `RUSTC` or in the `PATH`.
/// - The version output from `rustc` can't be parsed.
/// - `OUT_DIR` is not set in the environment, or is not a writable directory.
///
pub fn new() -> Result<Self, Error> {
match env::var_os("OUT_DIR") {
Some(d) => Self::with_dir(d),
None => Err(error::from_str("no OUT_DIR specified!")),
}
}
/// Create a new `AutoCfg` instance with the specified output directory.
///
/// # Common errors
///
/// - `rustc` can't be executed, from `RUSTC` or in the `PATH`.
/// - The version output from `rustc` can't be parsed.
/// - `dir` is not a writable directory.
///
pub fn with_dir<T: Into<PathBuf>>(dir: T) -> Result<Self, Error> {
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let rustc: PathBuf = rustc.into();
let rustc_version = try!(Version::from_rustc(&rustc));
// Sanity check the output directory
let dir = dir.into();
let meta = try!(fs::metadata(&dir).map_err(error::from_io));
if !meta.is_dir() || meta.permissions().readonly() {
return Err(error::from_str("output path is not a writable directory"));
}
Ok(AutoCfg {
out_dir: dir,
rustc: rustc,
rustc_version: rustc_version,
target: env::var_os("TARGET"),
})
}
/// Test whether the current `rustc` reports a version greater than
/// or equal to "`major`.`minor`".
pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool {
self.rustc_version >= Version::new(major, minor, 0)
}
/// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`,
/// if the current `rustc` is at least that version.
pub fn emit_rustc_version(&self, major: usize, minor: usize) {
if self.probe_rustc_version(major, minor) {
emit(&format!("rustc_{}_{}", major, minor));
}
}
fn probe<T: AsRef<[u8]>>(&self, code: T) -> Result<bool, Error> {
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
static ID: AtomicUsize = ATOMIC_USIZE_INIT;
let id = ID.fetch_add(1, Ordering::Relaxed);
let mut command = Command::new(&self.rustc);
command
.arg(format!("--crate-name=probe{}", id))
.arg("--crate-type=lib")
.arg("--out-dir")
.arg(&self.out_dir)
.arg("--emit=llvm-ir");
if let Some(target) = self.target.as_ref() {
command.arg("--target").arg(target);
}
command.arg("-").stdin(Stdio::piped());
let mut child = try!(command.spawn().map_err(error::from_io));
try!(
child
.stdin
.take()
.expect("rustc stdin")
.write_all(code.as_ref())
.map_err(error::from_io)
);
let status = try!(child.wait().map_err(error::from_io));
Ok(status.success())
}
/// Tests whether the given path can be used.
///
/// The test code is subject to change, but currently looks like:
///
/// ```ignore
/// pub use PATH;
/// ```
pub fn probe_path(&self, path: &str) -> bool {
self.probe(format!("pub use {};", path)).unwrap_or(false)
}
/// Emits a config value `has_PATH` if `probe_path` returns true.
///
/// Any non-identifier characters in the `path` will be replaced with
/// `_` in the generated config value.
pub fn emit_has_path(&self, path: &str) {
if self.probe_path(path) {
emit(&format!("has_{}", mangle(path)));
}
}
/// Emits the given `cfg` value if `probe_path` returns true.
pub fn emit_path_cfg(&self, path: &str, cfg: &str) {
if self.probe_path(path) {
emit(cfg);
}
}
/// Tests whether the given trait can be used.
///
/// The test code is subject to change, but currently looks like:
///
/// ```ignore
/// pub trait Probe: TRAIT + Sized {}
/// ```
pub fn probe_trait(&self, name: &str) -> bool {
self.probe(format!("pub trait Probe: {} + Sized {{}}", name))
.unwrap_or(false)
}
/// Emits a config value `has_TRAIT` if `probe_trait` returns true.
///
/// Any non-identifier characters in the trait `name` will be replaced with
/// `_` in the generated config value.
pub fn emit_has_trait(&self, name: &str) {
if self.probe_trait(name) {
emit(&format!("has_{}", mangle(name)));
}
}
/// Emits the given `cfg` value if `probe_trait` returns true.
pub fn emit_trait_cfg(&self, name: &str, cfg: &str) {
if self.probe_trait(name) {
emit(cfg);
}
}
/// Tests whether the given type can be used.
///
/// The test code is subject to change, but currently looks like:
///
/// ```ignore
/// pub type Probe = TYPE;
/// ```
pub fn probe_type(&self, name: &str) -> bool {
self.probe(format!("pub type Probe = {};", name))
.unwrap_or(false)
}
/// Emits a config value `has_TYPE` if `probe_type` returns true.
///
/// Any non-identifier characters in the type `name` will be replaced with
/// `_` in the generated config value.
pub fn emit_has_type(&self, name: &str) {
if self.probe_type(name) {
emit(&format!("has_{}", mangle(name)));
}
}
/// Emits the given `cfg` value if `probe_type` returns true.
pub fn emit_type_cfg(&self, name: &str, cfg: &str) {
if self.probe_type(name) {
emit(cfg);
}
}
}
fn mangle(s: &str) -> String {
s.chars()
.map(|c| match c {
'A'...'Z' | 'a'...'z' | '0'...'9' => c,
_ => '_',
}).collect()
}

57
third_party/rust/autocfg/src/tests.rs vendored Normal file
View File

@ -0,0 +1,57 @@
use super::AutoCfg;
#[test]
fn autocfg_version() {
let ac = AutoCfg::with_dir("target").unwrap();
println!("version: {:?}", ac.rustc_version);
assert!(ac.probe_rustc_version(1, 0));
}
#[test]
fn version_cmp() {
use super::version::Version;
let v123 = Version::new(1, 2, 3);
assert!(Version::new(1, 0, 0) < v123);
assert!(Version::new(1, 2, 2) < v123);
assert!(Version::new(1, 2, 3) == v123);
assert!(Version::new(1, 2, 4) > v123);
assert!(Version::new(1, 10, 0) > v123);
assert!(Version::new(2, 0, 0) > v123);
}
#[test]
fn probe_add() {
let ac = AutoCfg::with_dir("target").unwrap();
assert!(ac.probe_path("std::ops::Add"));
assert!(ac.probe_trait("std::ops::Add"));
assert!(ac.probe_trait("std::ops::Add<i32>"));
assert!(ac.probe_trait("std::ops::Add<i32, Output = i32>"));
assert!(ac.probe_type("std::ops::Add<i32, Output = i32>"));
}
#[test]
fn probe_as_ref() {
let ac = AutoCfg::with_dir("target").unwrap();
assert!(ac.probe_path("std::convert::AsRef"));
assert!(ac.probe_trait("std::convert::AsRef<str>"));
assert!(ac.probe_type("std::convert::AsRef<str>"));
}
#[test]
fn probe_i128() {
let ac = AutoCfg::with_dir("target").unwrap();
let missing = !ac.probe_rustc_version(1, 26);
assert!(missing ^ ac.probe_path("std::i128"));
assert!(missing ^ ac.probe_type("i128"));
}
#[test]
fn probe_sum() {
let ac = AutoCfg::with_dir("target").unwrap();
let missing = !ac.probe_rustc_version(1, 12);
assert!(missing ^ ac.probe_path("std::iter::Sum"));
assert!(missing ^ ac.probe_trait("std::iter::Sum"));
assert!(missing ^ ac.probe_trait("std::iter::Sum<i32>"));
assert!(missing ^ ac.probe_type("std::iter::Sum<i32>"));
}

62
third_party/rust/autocfg/src/version.rs vendored Normal file
View File

@ -0,0 +1,62 @@
use std::path::Path;
use std::process::Command;
use std::str;
use super::{error, Error};
/// A version structure for making relative comparisons.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Version {
major: usize,
minor: usize,
patch: usize,
}
impl Version {
/// Creates a `Version` instance for a specific `major.minor.patch` version.
pub fn new(major: usize, minor: usize, patch: usize) -> Self {
Version {
major: major,
minor: minor,
patch: patch,
}
}
pub fn from_rustc(rustc: &Path) -> Result<Self, Error> {
// Get rustc's verbose version
let output = try!(
Command::new(rustc)
.args(&["--version", "--verbose"])
.output()
.map_err(error::from_io)
);
if !output.status.success() {
return Err(error::from_str("could not execute rustc"));
}
let output = try!(str::from_utf8(&output.stdout).map_err(error::from_utf8));
// Find the release line in the verbose version output.
let release = match output.lines().find(|line| line.starts_with("release: ")) {
Some(line) => &line["release: ".len()..],
None => return Err(error::from_str("could not find rustc release")),
};
// Strip off any extra channel info, e.g. "-beta.N", "-nightly"
let version = match release.find('-') {
Some(i) => &release[..i],
None => release,
};
// Split the version into semver components.
let mut iter = version.splitn(3, '.');
let major = try!(iter.next().ok_or(error::from_str("missing major version")));
let minor = try!(iter.next().ok_or(error::from_str("missing minor version")));
let patch = try!(iter.next().ok_or(error::from_str("missing patch version")));
Ok(Version::new(
try!(major.parse().map_err(error::from_num)),
try!(minor.parse().map_err(error::from_num)),
try!(patch.parse().map_err(error::from_num)),
))
}
}

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"16ef935056e2aaf48b28c1340a63cc75febaabc901c752da9a3a2edbe081b429","bitflags.rs":"4621173dcf1307094cf240d26955b6f25c2f770dfd4e975ec2728771209006b5","cloudabi.rs":"93e139ba72a04db4934b04a6f21b054757a218a687e0bd2f6ba32514ec8c5f38"},"package":"ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"}

31
third_party/rust/cloudabi/Cargo.toml vendored Normal file
View File

@ -0,0 +1,31 @@
# 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 = "cloudabi"
version = "0.0.3"
authors = ["Nuxi (https://nuxi.nl/) and contributors"]
description = "Low level interface to CloudABI. Contains all syscalls and related types."
homepage = "https://nuxi.nl/cloudabi/"
documentation = "https://docs.rs/cloudabi/"
keywords = ["cloudabi"]
license = "BSD-2-Clause"
repository = "https://github.com/nuxinl/cloudabi"
[lib]
path = "cloudabi.rs"
[dependencies.bitflags]
version = "1.0"
optional = true
[features]
default = ["bitflags"]

51
third_party/rust/cloudabi/bitflags.rs vendored Normal file
View File

@ -0,0 +1,51 @@
// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
// Appease Rust's tidy.
// ignore-license
#[cfg(feature = "bitflags")]
#[macro_use]
extern crate bitflags;
// Minimal implementation of bitflags! in case we can't depend on the bitflags
// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't
// actually truncate.
#[cfg(not(feature = "bitflags"))]
macro_rules! bitflags {
(
$(#[$attr:meta])*
pub struct $name:ident: $type:ty {
$($(#[$const_attr:meta])* const $const:ident = $val:expr;)*
}
) => {
$(#[$attr])*
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct $name { bits: $type }
impl $name {
$($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)*
pub fn bits(&self) -> $type { self.bits }
pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } }
}
}
}

2847
third_party/rust/cloudabi/cloudabi.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
{"files":{"AUTHORS":"f82920a5bcfc71b86c1de4be4cdea8af2009ba9e5735824f95ed5043a03e46f0","Cargo.toml":"bb2497b2907c3af499ce7ac3722dae044968e13409a372b7760150f8a01c74c5","LICENSE":"03b114f53e6587a398931762ee11e2395bfdba252a329940e2c8c9e81813845b","PATENTS":"52beb3ac72a0e7f5060384d16e4e6f91573016448fbff363c0b01a66fe99f547","src/lib.rs":"3d76c35c13203093ddf7ce2a3be5e98d768a8091cd9d99bd083fe8db35364096"},"package":"a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"}

10
third_party/rust/fuchsia-cprng/AUTHORS vendored Normal file
View File

@ -0,0 +1,10 @@
# This is the list of Fuchsia Authors.
# Names should be added to this file as one of
# Organization's name
# Individual's name <submission email address>
# Individual's name <submission email address> <email2> <emailN>
Google Inc.
The Chromium Authors
The Go Authors

View File

@ -0,0 +1,22 @@
# 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]
edition = "2018"
name = "fuchsia-cprng"
version = "0.1.1"
authors = ["Erick Tryzelaar <etryzelaar@google.com>"]
include = ["src/*.rs", "Cargo.toml", "AUTHORS", "LICENSE", "PATENTS"]
description = "Rust crate for the Fuchsia cryptographically secure pseudorandom number generator"
readme = "README.md"
license-file = "LICENSE"
repository = "https://fuchsia.googlesource.com/fuchsia/+/master/garnet/public/rust/fuchsia-cprng"

View File

@ -1,24 +1,18 @@
Copyright (c) 2014 by Armin Ronacher.
Copyright (c) 2013 Koka El Kiwi
Some rights reserved.
Copyright 2019 The Fuchsia Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

22
third_party/rust/fuchsia-cprng/PATENTS vendored Normal file
View File

@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Fuchsia project.
Google 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, transfer, and otherwise run, modify and propagate the contents
of this implementation of Fuchsia, where such license applies only to
those patent claims, both currently owned by Google and acquired in
the future, licensable by Google that are necessarily infringed by
this implementation. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute
or order or agree to the institution of patent litigation or any other
patent enforcement activity against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that this
implementation of Fuchsia constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of
Fuchsia shall terminate as of the date such litigation is filed.

View File

@ -0,0 +1,57 @@
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Type-safe bindings for the Zircon kernel's CPRNG.
#![no_std]
#![deny(warnings)]
/// Draw random bytes from the kernel's CPRNG to fill the given buffer.
///
/// Wraps the
/// [zx_cprng_draw](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/cprng_draw.md)
/// syscall.
pub fn cprng_draw(buffer: &mut [u8]) {
unsafe { zx_cprng_draw(buffer.as_mut_ptr(), buffer.len()) };
}
#[link(name = "zircon")]
extern "C" {
fn zx_cprng_draw(buffer: *mut u8, length: usize);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cprng() {
let mut buffer = [0; 20];
cprng_draw(&mut buffer);
let mut first_zero = 0;
let mut last_zero = 0;
for _ in 0..30 {
let mut buffer = [0; 20];
cprng_draw(&mut buffer);
if buffer[0] == 0 {
first_zero += 1;
}
if buffer[19] == 0 {
last_zero += 1;
}
}
assert_ne!(first_zero, 30);
assert_ne!(last_zero, 30);
}
#[test]
fn cprng_large() {
let mut buffer = [0; 1024];
cprng_draw(&mut buffer);
for mut s in buffer.chunks_mut(256) {
cprng_draw(&mut s);
}
}
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"ce89721483a37a5e21e4c7c8bd36b64a03067c23b3c6a9569e552a2a0364522e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ad5ce29918424008bdd8c6e7851bb064533456cbb32ec0d0955b2bc9444613d3","README.md":"8777517c90cff609e5a00a46b548f44803a4943cc7430a0ca6ddc4712af8d4ac","benches/parse.rs":"07f7d63b625090f1ccb086679e24c104de450d8733bb517e38a6eda8511e35e3","src/iter.rs":"9782faa1736e7988feceecdd5169f51b8b7926cbcf6611bbef9e018763e3cec8","src/lib.rs":"d95d4de02b19f2f921e13f0f477092d202fe0e707dc007b9bbd05282d7e69ebc"},"package":"af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"}
{"files":{"Cargo.toml":"2d893bf5d1e9a5445e74c2a7a75b804492245647004155a798f5456e5c0f4712","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ad5ce29918424008bdd8c6e7851bb064533456cbb32ec0d0955b2bc9444613d3","README.md":"b54e1e379daa12d26aadad7c1bef578a3cbcf243f2f229d8b17868c90a384d7d","benches/parse.rs":"caabd31cbcb00172bb7f31a1398dbed27a3bf36b01d69729c3d6fbd9a4008e05","build.rs":"00bab146ec6a10fac91958a06bdd4b7b4d71932e0480b6e84a4248cb339dbe79","src/iter.rs":"3f165be2f0d3bb7e0cbe37cb67560e36e06cdb5921e145446a5985c3580a6b6e","src/lib.rs":"21436cacd3b33b20ad75877e6260f34391a9215ffa6ad2c10ebf1a0c67ac07dc","src/macros.rs":"25de190f894eefb48a6992f9dc3d039d9065f908f381d683f0395d568d992275","src/simd/avx2.rs":"1b27cad7b5c210f8a1283d423ca18372127ea50f5565b9be0b83d2a51a1eb826","src/simd/fallback.rs":"0234cc11459f3225d6e3d329068a01206e39625a538bdc292e0d1beaa06a37e5","src/simd/mod.rs":"c67e118a45da679d41de0d51c2f632f64902083db4be8f636021dbfe08f0f9b4","src/simd/sse42.rs":"373f5bf0596942b9ba4497a8a89975117ec0da6d8b8c2345fe03e0d28e68627f","tests/uri.rs":"92a0dc4cfa8eee2e6b8e9109e2e0062ccb50b9ec8cb4b7c06794dab1a3e68c9c"},"package":"e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"}

View File

@ -12,9 +12,14 @@
[package]
name = "httparse"
version = "1.2.3"
authors = ["Sean McArthur <sean.monstar@gmail.com>"]
version = "1.3.3"
authors = ["Sean McArthur <sean@seanmonstar.com>"]
build = "build.rs"
description = "A tiny, safe, speedy, zero-copy HTTP/1.x parser."
documentation = "https://docs.rs/httparse"
readme = "README.md"
keywords = ["http", "parser", "no_std"]
categories = ["network-programming", "no-std", "parser-implementations", "web-programming"]
license = "MIT/Apache-2.0"
repository = "https://github.com/seanmonstar/httparse"
[profile.bench]

View File

@ -2,11 +2,14 @@
[![Build Status](https://travis-ci.org/seanmonstar/httparse.svg?branch=master)](https://travis-ci.org/seanmonstar/httparse)
[![Coverage Status](https://coveralls.io/repos/seanmonstar/httparse/badge.svg)](https://coveralls.io/r/seanmonstar/httparse)
[![crates.io](http://meritbadge.herokuapp.com/httparse)](https://crates.io/crates/httparse)
[![crates.io](https://img.shields.io/crates/v/httparse.svg)](https://crates.io/crates/httparse)
A push parser for the HTTP 1.x protocol. Avoids allocations. Fast.
A push parser for the HTTP 1.x protocol. Avoids allocations. No copy. **Fast.**
Works with `no_std`, simply disable the `std` Cargo feature.
[Documentation](https://docs.rs/httparse)
[Changelog](https://github.com/seanmonstar/httparse/releases)
## Usage
@ -15,12 +18,12 @@ let mut headers = [httparse::EMPTY_HEADER; 16];
let mut req = httparse::Request::new(&mut headers);
let buf = b"GET /index.html HTTP/1.1\r\nHost";
assert!(try!(req.parse(buf)).is_partial());
assert!(req.parse(buf)?.is_partial());
// a partial request, so we try again once we have more data
let buf = b"GET /index.html HTTP/1.1\r\nHost: example.domain\r\n\r\n";
assert!(try!(req.parse(buf)).is_complete());
assert!(req.parse(buf)?.is_complete());
```
## License

View File

@ -5,6 +5,11 @@ extern crate httparse;
extern crate test;
const REQ_SHORT: &'static [u8] = b"\
GET / HTTP/1.0\r\n\
Host: example.com\r\n\
Cookie: session=60; user_id=1\r\n\r\n";
const REQ: &'static [u8] = b"\
GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n\
Host: www.kittyhell.com\r\n\
@ -15,9 +20,7 @@ Accept-Encoding: gzip,deflate\r\n\
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n\
Keep-Alive: 115\r\n\
Connection: keep-alive\r\n\
Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral\r\n\r\n";
Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral|padding=under256\r\n\r\n";
#[bench]
@ -68,3 +71,52 @@ fn bench_httparse(b: &mut test::Bencher) {
});
b.bytes = REQ.len() as u64;
}
#[bench]
fn bench_pico_short(b: &mut test::Bencher) {
use std::mem;
#[repr(C)]
#[derive(Clone, Copy)]
struct Header<'a>(&'a [u8], &'a [u8]);
#[repr(C)]
struct Headers<'a>(&'a mut [Header<'a>]);
let method = [0i8; 16];
let path = [0i8; 16];
let mut minor_version = 0;
let mut h = [Header(&[], &[]); 16];
let mut h_len = h.len();
let headers = Headers(&mut h);
let prev_buf_len = 0;
b.iter(|| {
let ret = unsafe {
pico::ffi::phr_parse_request(
REQ_SHORT.as_ptr() as *const _,
REQ_SHORT.len(),
&mut method.as_ptr(),
&mut 16,
&mut path.as_ptr(),
&mut 16,
&mut minor_version,
mem::transmute::<*mut Header, *mut pico::ffi::phr_header>(headers.0.as_mut_ptr()),
&mut h_len as *mut usize as *mut _,
prev_buf_len
)
};
assert_eq!(ret, REQ_SHORT.len() as i32);
});
b.bytes = REQ_SHORT.len() as u64;
}
#[bench]
fn bench_httparse_short(b: &mut test::Bencher) {
let mut headers = [httparse::Header{ name: "", value: &[] }; 16];
let mut req = httparse::Request::new(&mut headers);
b.iter(|| {
assert_eq!(req.parse(REQ_SHORT).unwrap(), httparse::Status::Complete(REQ_SHORT.len()));
});
b.bytes = REQ_SHORT.len() as u64;
}

155
third_party/rust/httparse/build.rs vendored Normal file
View File

@ -0,0 +1,155 @@
use std::env;
use std::ffi::OsString;
use std::process::Command;
fn main() {
let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc"));
let output = Command::new(&rustc)
.arg("--version")
.output()
.expect("failed to check 'rustc --version'")
.stdout;
let version = String::from_utf8(output)
.expect("rustc version output should be utf-8");
enable_new_features(&version);
}
fn enable_new_features(raw_version: &str) {
let version = match Version::parse(raw_version) {
Ok(version) => version,
Err(err) => {
println!("cargo:warning=failed to parse `rustc --version`: {}", err);
return;
}
};
enable_simd(version);
}
fn enable_simd(version: Version) {
if env::var_os("CARGO_FEATURE_STD").is_none() {
println!("cargo:warning=building for no_std disables httparse SIMD");
return;
}
let env_disable = "CARGO_CFG_HTTPARSE_DISABLE_SIMD";
if env::var_os(env_disable).is_some() {
println!("cargo:warning=detected {} environment variable, disabling SIMD", env_disable);
return;
}
let min_simd_version = Version {
major: 1,
minor: 27,
patch: 0,
};
if version >= min_simd_version {
println!("cargo:rustc-cfg=httparse_simd");
}
// cfg(target_feature) isn't stable yet, but CARGO_CFG_TARGET_FEATURE has
// a list... We aren't doing anything unsafe, since the is_x86_feature_detected
// macro still checks in the actual lib, BUT!
//
// By peeking at the list here, we can change up slightly how we do feature
// detection in the lib. If our features aren't in the feature list, we
// stick with a cached runtime detection strategy.
//
// But if the features *are* in the list, we benefit from removing our cache,
// since the compiler will eliminate several branches with its internal
// cfg(target_feature) usage.
let env_runtime_only = "CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME";
if env::var_os(env_runtime_only).is_some() {
println!("cargo:warning=detected {} environment variable, using runtime SIMD detection only", env_runtime_only);
return;
}
let feature_list = match env::var_os("CARGO_CFG_TARGET_FEATURE") {
Some(var) => match var.into_string() {
Ok(s) => s,
Err(_) => {
println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not valid utf-8");
return;
},
},
None => {
println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not set");
return
},
};
let mut saw_sse42 = false;
let mut saw_avx2 = false;
for feature in feature_list.split(',') {
let feature = feature.trim();
if !saw_sse42 && feature == "sse4.2" {
saw_sse42 = true;
println!("cargo:rustc-cfg=httparse_simd_target_feature_sse42");
}
if !saw_avx2 && feature == "avx2" {
saw_avx2 = true;
println!("cargo:rustc-cfg=httparse_simd_target_feature_avx2");
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
struct Version {
major: u32,
minor: u32,
patch: u32,
}
impl Version {
fn parse(mut s: &str) -> Result<Version, String> {
if !s.starts_with("rustc ") {
return Err(format!("unrecognized version string: {}", s));
}
s = &s["rustc ".len()..];
let parts: Vec<&str> = s.split(".").collect();
if parts.len() < 3 {
return Err(format!("not enough version parts: {:?}", parts));
}
let mut num = String::new();
for c in parts[0].chars() {
if !c.is_digit(10) {
break;
}
num.push(c);
}
let major = try!(num.parse::<u32>().map_err(|e| e.to_string()));
num.clear();
for c in parts[1].chars() {
if !c.is_digit(10) {
break;
}
num.push(c);
}
let minor = try!(num.parse::<u32>().map_err(|e| e.to_string()));
num.clear();
for c in parts[2].chars() {
if !c.is_digit(10) {
break;
}
num.push(c);
}
let patch = try!(num.parse::<u32>().map_err(|e| e.to_string()));
Ok(Version {
major: major,
minor: minor,
patch: patch,
})
}
}

View File

@ -25,10 +25,18 @@ impl<'a> Bytes<'a> {
}
#[inline]
pub fn bump(&mut self) {
pub unsafe fn bump(&mut self) {
debug_assert!(self.pos + 1 <= self.slice.len(), "overflow");
self.pos += 1;
}
#[allow(unused)]
#[inline]
pub unsafe fn advance(&mut self, n: usize) {
debug_assert!(self.pos + n <= self.slice.len(), "overflow");
self.pos += n;
}
#[inline]
pub fn len(&self) -> usize {
self.slice.len()
@ -36,21 +44,22 @@ impl<'a> Bytes<'a> {
#[inline]
pub fn slice(&mut self) -> &'a [u8] {
self.slice_skip(0)
// not moving position at all, so it's safe
unsafe {
self.slice_skip(0)
}
}
#[inline]
pub fn slice_skip(&mut self, skip: usize) -> &'a [u8] {
pub unsafe fn slice_skip(&mut self, skip: usize) -> &'a [u8] {
debug_assert!(self.pos >= skip);
let head_pos = self.pos - skip;
unsafe {
let ptr = self.slice.as_ptr();
let head = slice::from_raw_parts(ptr, head_pos);
let tail = slice::from_raw_parts(ptr.offset(self.pos as isize), self.slice.len() - self.pos);
self.pos = 0;
self.slice = tail;
head
}
let ptr = self.slice.as_ptr();
let head = slice::from_raw_parts(ptr, head_pos);
let tail = slice::from_raw_parts(ptr.offset(self.pos as isize), self.slice.len() - self.pos);
self.pos = 0;
self.slice = tail;
head
}
#[inline]
@ -63,6 +72,13 @@ impl<'a> Bytes<'a> {
}
}
impl<'a> AsRef<[u8]> for Bytes<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.slice[self.pos..]
}
}
impl<'a> Iterator for Bytes<'a> {
type Item = u8;

View File

@ -1,6 +1,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![doc(html_root_url = "https://docs.rs/httparse/1.3.3")]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]
//! # httparse
//!
//! A push library for parsing HTTP/1.x requests and responses.
@ -10,44 +12,25 @@
//! parsing internals use an `Iterator` instead of direct indexing, while
//! skipping bounds checks.
//!
//! The speed is faster than picohttpparser, when SIMD is not available.
#[cfg(feature = "std")] extern crate std as core;
//! With Rust 1.27.0 or later, support for SIMD is enabled automatically.
//! If building an executable to be run on multiple platforms, and thus
//! not passing `target_feature` or `target_cpu` flags to the compiler,
//! runtime detection can still detect SSE4.2 or AVX2 support to provide
//! massive wins.
//!
//! If compiling for a specific target, remembering to include
//! `-C target_cpu=native` allows the detection to become compile time checks,
//! making it *even* faster.
#[cfg(feature = "std")]
extern crate std as core;
use core::{fmt, result, str, slice};
use iter::Bytes;
mod iter;
macro_rules! next {
($bytes:ident) => ({
match $bytes.next() {
Some(b) => b,
None => return Ok(Status::Partial)
}
})
}
macro_rules! expect {
($bytes:ident.next() == $pat:pat => $ret:expr) => {
expect!(next!($bytes) => $pat |? $ret)
};
($e:expr => $pat:pat |? $ret:expr) => {
match $e {
v@$pat => v,
_ => return $ret
}
};
}
macro_rules! complete {
($e:expr) => {
match try!($e) {
Status::Complete(v) => v,
Status::Partial => return Ok(Status::Partial)
}
}
}
#[macro_use] mod macros;
mod simd;
#[inline]
fn shrink<T>(slice: &mut &mut [T], len: usize) {
@ -70,10 +53,41 @@ fn shrink<T>(slice: &mut &mut [T], len: usize) {
fn is_token(b: u8) -> bool {
b > 0x1F && b < 0x7F
}
macro_rules! byte_map {
($($flag:expr,)*) => ([
$($flag != 0,)*
])
// ASCII codes to accept URI string.
// i.e. A-Z a-z 0-9 !#$%&'*+-._();:@=,/?[]~^
// TODO: Make a stricter checking for URI string?
static URI_MAP: [bool; 256] = byte_map![
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// \0 \n
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// commands
0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
// \w ! " # $ % & ' ( ) * + , - . /
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
// 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
// @ A B C D E F G H I J K L M N O
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
// P Q R S T U V W X Y Z [ \ ] ^ _
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
// ` a b c d e f g h i j k l m n o
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
// p q r s t u v w x y z { | } ~ del
// ====== Extended ASCII (aka. obs-text) ======
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
#[inline]
fn is_uri_token(b: u8) -> bool {
URI_MAP[b as usize]
}
static HEADER_NAME_MAP: [bool; 256] = byte_map![
@ -101,7 +115,7 @@ fn is_header_name_token(b: u8) -> bool {
}
static HEADER_VALUE_MAP: [bool; 256] = byte_map![
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -125,29 +139,6 @@ fn is_header_value_token(b: u8) -> bool {
HEADER_VALUE_MAP[b as usize]
}
macro_rules! space {
($bytes:ident or $err:expr) => ({
expect!($bytes.next() == b' ' => Err($err));
$bytes.slice();
})
}
macro_rules! newline {
($bytes:ident) => ({
match next!($bytes) {
b'\r' => {
expect!($bytes.next() == b'\n' => Err(Error::NewLine));
$bytes.slice();
},
b'\n' => {
$bytes.slice();
},
_ => return Err(Error::NewLine)
}
})
}
/// An error in parsing.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Error {
@ -311,7 +302,7 @@ impl<'h, 'b> Request<'h, 'b> {
let mut bytes = Bytes::new(buf);
complete!(skip_empty_lines(&mut bytes));
self.method = Some(complete!(parse_token(&mut bytes)));
self.path = Some(complete!(parse_token(&mut bytes)));
self.path = Some(complete!(parse_uri(&mut bytes)));
self.version = Some(complete!(parse_version(&mut bytes)));
newline!(bytes);
@ -328,11 +319,13 @@ fn skip_empty_lines(bytes: &mut Bytes) -> Result<()> {
let b = bytes.peek();
match b {
Some(b'\r') => {
bytes.bump();
// there's `\r`, so it's safe to bump 1 pos
unsafe { bytes.bump() };
expect!(bytes.next() == b'\n' => Err(Error::NewLine));
},
Some(b'\n') => {
bytes.bump();
// there's `\n`, so it's safe to bump 1 pos
unsafe { bytes.bump(); }
},
Some(..) => {
bytes.slice();
@ -396,6 +389,7 @@ impl<'h, 'b> Response<'h, 'b> {
},
b'\r' => {
expect!(bytes.next() == b'\n' => Err(Error::Status));
bytes.slice();
self.reason = Some("");
},
b'\n' => self.reason = Some(""),
@ -448,10 +442,21 @@ fn parse_version(bytes: &mut Bytes) -> Result<u8> {
b'1' => 1,
_ => return Err(Error::Version)
};
Ok(Status::Complete(v))
} else {
Ok(Status::Partial)
return Ok(Status::Complete(v))
}
// else (but not in `else` because of borrow checker)
// If there aren't at least 8 bytes, we still want to detect early
// if this is a valid version or not. If it is, we'll return Partial.
expect!(bytes.next() == b'H' => Err(Error::Version));
expect!(bytes.next() == b'T' => Err(Error::Version));
expect!(bytes.next() == b'T' => Err(Error::Version));
expect!(bytes.next() == b'P' => Err(Error::Version));
expect!(bytes.next() == b'/' => Err(Error::Version));
expect!(bytes.next() == b'1' => Err(Error::Version));
expect!(bytes.next() == b'.' => Err(Error::Version));
Ok(Status::Partial)
}
/// From [RFC 7230](https://tools.ietf.org/html/rfc7230):
@ -508,6 +513,24 @@ fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
}
}
#[inline]
fn parse_uri<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
simd::match_uri_vectored(bytes);
loop {
let b = next!(bytes);
if b == b' ' {
return Ok(Status::Complete(unsafe {
// all bytes up till `i` must have been `is_token`.
str::from_utf8_unchecked(bytes.slice_skip(1))
}));
} else if !is_uri_token(b) {
return Err(Error::Token);
}
}
}
#[inline]
fn parse_code(bytes: &mut Bytes) -> Result<u16> {
let hundreds = expect!(bytes.next() == b'0'...b'9' => Err(Error::Status));
@ -515,8 +538,8 @@ fn parse_code(bytes: &mut Bytes) -> Result<u16> {
let ones = expect!(bytes.next() == b'0'...b'9' => Err(Error::Status));
Ok(Status::Complete((hundreds - b'0') as u16 * 100 +
(tens - b'0') as u16 * 10 +
(ones - b'0') as u16))
(tens - b'0') as u16 * 10 +
(ones - b'0') as u16))
}
/// Parse a buffer of bytes as headers.
@ -544,6 +567,7 @@ pub fn parse_headers<'b: 'h, 'h>(src: &'b [u8], mut dst: &'h mut [Header<'b>])
Ok(Status::Complete((pos, dst)))
}
#[inline]
fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut Bytes<'a>)
-> Result<usize> {
@ -609,7 +633,7 @@ fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut By
// parse value till EOL
simd::match_header_value_vectored(bytes);
macro_rules! check {
($bytes:ident, $i:ident) => ({
@ -641,17 +665,31 @@ fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut By
}
//found_ctl
if b == b'\r' {
let value_slice : &[u8] = if b == b'\r' {
expect!(bytes.next() == b'\n' => Err(Error::HeaderValue));
count += bytes.pos();
header.value = bytes.slice_skip(2);
// having just check that `\r\n` exists, it's safe to skip those 2 bytes
unsafe {
bytes.slice_skip(2)
}
} else if b == b'\n' {
count += bytes.pos();
header.value = bytes.slice_skip(1);
// having just check that `\r\n` exists, it's safe to skip 1 byte
unsafe {
bytes.slice_skip(1)
}
} else {
return Err(Error::HeaderValue);
};
// trim trailing whitespace in the header
if let Some(last_visible) = value_slice.iter().rposition(|b| *b != b' ' && *b != b'\t' ) {
// There is at least one non-whitespace character.
header.value = &value_slice[0..last_visible+1];
} else {
// There is no non-whitespace character. This can only happen when value_slice is
// empty.
header.value = value_slice;
}
}
} // drop iter
@ -672,7 +710,7 @@ fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut By
/// Ok(httparse::Status::Complete((3, 4))));
/// ```
pub fn parse_chunk_size(buf: &[u8])
-> result::Result<Status<(usize, u64)>, InvalidChunkSize> {
-> result::Result<Status<(usize, u64)>, InvalidChunkSize> {
const RADIX: u64 = 16;
let mut bytes = Bytes::new(buf);
let mut size = 0;
@ -682,7 +720,7 @@ pub fn parse_chunk_size(buf: &[u8])
loop {
let b = next!(bytes);
match b {
b'0'...b'9' if in_chunk_size => {
b'0' ... b'9' if in_chunk_size => {
if count > 15 {
return Err(InvalidChunkSize);
}
@ -690,7 +728,7 @@ pub fn parse_chunk_size(buf: &[u8])
size *= RADIX;
size += (b - b'0') as u64;
},
b'a'...b'f' if in_chunk_size => {
b'a' ... b'f' if in_chunk_size => {
if count > 15 {
return Err(InvalidChunkSize);
}
@ -698,7 +736,7 @@ pub fn parse_chunk_size(buf: &[u8])
size *= RADIX;
size += (b + 10 - b'a') as u64;
}
b'A'...b'F' if in_chunk_size => {
b'A' ... b'F' if in_chunk_size => {
if count > 15 {
return Err(InvalidChunkSize);
}
@ -785,6 +823,28 @@ mod tests {
}
}
req! {
test_request_simple_with_query_params,
b"GET /thing?data=a HTTP/1.1\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "GET");
assert_eq!(req.path.unwrap(), "/thing?data=a");
assert_eq!(req.version.unwrap(), 1);
assert_eq!(req.headers.len(), 0);
}
}
req! {
test_request_simple_with_whatwg_query_params,
b"GET /thing?data=a^ HTTP/1.1\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "GET");
assert_eq!(req.path.unwrap(), "/thing?data=a^");
assert_eq!(req.version.unwrap(), 1);
assert_eq!(req.headers.len(), 0);
}
}
req! {
test_request_headers,
b"GET / HTTP/1.1\r\nHost: foo.com\r\nCookie: \r\n\r\n",
@ -800,6 +860,63 @@ mod tests {
}
}
req! {
test_request_headers_optional_whitespace,
b"GET / HTTP/1.1\r\nHost: \tfoo.com\t \r\nCookie: \t \r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "GET");
assert_eq!(req.path.unwrap(), "/");
assert_eq!(req.version.unwrap(), 1);
assert_eq!(req.headers.len(), 2);
assert_eq!(req.headers[0].name, "Host");
assert_eq!(req.headers[0].value, b"foo.com");
assert_eq!(req.headers[1].name, "Cookie");
assert_eq!(req.headers[1].value, b"");
}
}
req! {
// test the scalar parsing
test_request_header_value_htab_short,
b"GET / HTTP/1.1\r\nUser-Agent: some\tagent\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "GET");
assert_eq!(req.path.unwrap(), "/");
assert_eq!(req.version.unwrap(), 1);
assert_eq!(req.headers.len(), 1);
assert_eq!(req.headers[0].name, "User-Agent");
assert_eq!(req.headers[0].value, b"some\tagent");
}
}
req! {
// test the sse42 parsing
test_request_header_value_htab_med,
b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\tagent\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "GET");
assert_eq!(req.path.unwrap(), "/");
assert_eq!(req.version.unwrap(), 1);
assert_eq!(req.headers.len(), 1);
assert_eq!(req.headers[0].name, "User-Agent");
assert_eq!(req.headers[0].value, b"1234567890some\tagent");
}
}
req! {
// test the avx2 parsing
test_request_header_value_htab_long,
b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\t1234567890agent1234567890\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "GET");
assert_eq!(req.path.unwrap(), "/");
assert_eq!(req.version.unwrap(), 1);
assert_eq!(req.headers.len(), 1);
assert_eq!(req.headers[0].name, "User-Agent");
assert_eq!(req.headers[0].value, &b"1234567890some\t1234567890agent1234567890"[..]);
}
}
req! {
test_request_headers_max,
b"GET / HTTP/1.1\r\nA: A\r\nB: B\r\nC: C\r\nD: D\r\n\r\n",
@ -829,6 +946,12 @@ mod tests {
|_req| {}
}
req! {
test_request_partial_version,
b"GET / HTTP/1.", Ok(Status::Partial),
|_req| {}
}
req! {
test_request_newlines,
b"GET / HTTP/1.1\nHost: foo.bar\n\n",
@ -864,6 +987,14 @@ mod tests {
|_r| {}
}
req! {
test_request_with_invalid_but_short_version,
b"GET / HTTP/1!",
Err(::Error::Version),
|_r| {}
}
macro_rules! res {
($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
@ -920,6 +1051,19 @@ mod tests {
}
}
res! {
test_response_reason_missing_no_space_with_headers,
b"HTTP/1.1 200\r\nFoo: bar\r\n\r\n",
|res| {
assert_eq!(res.version.unwrap(), 1);
assert_eq!(res.code.unwrap(), 200);
assert_eq!(res.reason.unwrap(), "");
assert_eq!(res.headers.len(), 1);
assert_eq!(res.headers[0].name, "Foo");
assert_eq!(res.headers[0].value, b"bar");
}
}
res! {
test_response_reason_with_space_and_tab,
b"HTTP/1.1 101 Switching Protocols\t\r\n\r\n",

59
third_party/rust/httparse/src/macros.rs vendored Normal file
View File

@ -0,0 +1,59 @@
///! Utility macros
macro_rules! next {
($bytes:ident) => ({
match $bytes.next() {
Some(b) => b,
None => return Ok(Status::Partial)
}
})
}
macro_rules! expect {
($bytes:ident.next() == $pat:pat => $ret:expr) => {
expect!(next!($bytes) => $pat |? $ret)
};
($e:expr => $pat:pat |? $ret:expr) => {
match $e {
v@$pat => v,
_ => return $ret
}
};
}
macro_rules! complete {
($e:expr) => {
match try!($e) {
Status::Complete(v) => v,
Status::Partial => return Ok(Status::Partial)
}
}
}
macro_rules! byte_map {
($($flag:expr,)*) => ([
$($flag != 0,)*
])
}
macro_rules! space {
($bytes:ident or $err:expr) => ({
expect!($bytes.next() == b' ' => Err($err));
$bytes.slice();
})
}
macro_rules! newline {
($bytes:ident) => ({
match next!($bytes) {
b'\r' => {
expect!($bytes.next() == b'\n' => Err(Error::NewLine));
$bytes.slice();
},
b'\n' => {
$bytes.slice();
},
_ => return Err(Error::NewLine)
}
})
}

View File

@ -0,0 +1,116 @@
use ::iter::Bytes;
pub enum Scan {
/// Returned when an implementation finds a noteworthy token.
Found,
/// Returned when an implementation couldn't keep running because the input was too short.
TooShort,
}
pub unsafe fn parse_uri_batch_32<'a>(bytes: &mut Bytes<'a>) -> Scan {
while bytes.as_ref().len() >= 32 {
let advance = match_url_char_32_avx(bytes.as_ref());
bytes.advance(advance);
if advance != 32 {
return Scan::Found;
}
}
Scan::TooShort
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
#[inline]
#[allow(non_snake_case, overflowing_literals)]
unsafe fn match_url_char_32_avx(buf: &[u8]) -> usize {
debug_assert!(buf.len() >= 32);
/*
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
*/
use core::arch::x86_64::*;
let ptr = buf.as_ptr();
let LSH: __m256i = _mm256_set1_epi8(0x0f);
let URI: __m256i = _mm256_setr_epi8(
0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c,
0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c,
);
let ARF: __m256i = _mm256_setr_epi8(
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
);
let data = _mm256_lddqu_si256(ptr as *const _);
let rbms = _mm256_shuffle_epi8(URI, data);
let cols = _mm256_and_si256(LSH, _mm256_srli_epi16(data, 4));
let bits = _mm256_and_si256(_mm256_shuffle_epi8(ARF, cols), rbms);
let v = _mm256_cmpeq_epi8(bits, _mm256_setzero_si256());
let r = 0xffffffff_00000000 | _mm256_movemask_epi8(v) as u64;
_tzcnt_u64(r) as usize
}
#[cfg(target_arch = "x86")]
unsafe fn match_url_char_32_avx(_: &[u8]) -> usize {
unreachable!("AVX2 detection should be disabled for x86");
}
pub unsafe fn match_header_value_batch_32(bytes: &mut Bytes) -> Scan {
while bytes.as_ref().len() >= 32 {
let advance = match_header_value_char_32_avx(bytes.as_ref());
bytes.advance(advance);
if advance != 32 {
return Scan::Found;
}
}
Scan::TooShort
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
#[inline]
#[allow(non_snake_case)]
unsafe fn match_header_value_char_32_avx(buf: &[u8]) -> usize {
debug_assert!(buf.len() >= 32);
/*
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
*/
use core::arch::x86_64::*;
let ptr = buf.as_ptr();
// %x09 %x20-%x7e %x80-%xff
let TAB: __m256i = _mm256_set1_epi8(0x09);
let DEL: __m256i = _mm256_set1_epi8(0x7f);
let LOW: __m256i = _mm256_set1_epi8(0x1f);
let dat = _mm256_lddqu_si256(ptr as *const _);
let low = _mm256_cmpgt_epi8(dat, LOW);
let tab = _mm256_cmpeq_epi8(dat, TAB);
let del = _mm256_cmpeq_epi8(dat, DEL);
let bit = _mm256_andnot_si256(del, _mm256_or_si256(low, tab));
let rev = _mm256_cmpeq_epi8(bit, _mm256_setzero_si256());
let res = 0xffffffff_00000000 | _mm256_movemask_epi8(rev) as u64;
_tzcnt_u64(res) as usize
}
#[cfg(target_arch = "x86")]
unsafe fn match_header_value_char_32_avx(_: &[u8]) -> usize {
unreachable!("AVX2 detection should be disabled for x86");
}

View File

@ -0,0 +1,8 @@
use ::iter::Bytes;
// Fallbacks that do nothing...
#[inline(always)]
pub fn match_uri_vectored(_: &mut Bytes) {}
#[inline(always)]
pub fn match_header_value_vectored(_: &mut Bytes) {}

View File

@ -0,0 +1,238 @@
#[cfg(not(all(
httparse_simd,
any(
target_arch = "x86",
target_arch = "x86_64",
),
)))]
mod fallback;
#[cfg(not(all(
httparse_simd,
any(
target_arch = "x86",
target_arch = "x86_64",
),
)))]
pub use self::fallback::*;
#[cfg(all(
httparse_simd,
any(
target_arch = "x86",
target_arch = "x86_64",
),
))]
mod sse42;
#[cfg(all(
httparse_simd,
any(
httparse_simd_target_feature_avx2,
not(httparse_simd_target_feature_sse42),
),
any(
target_arch = "x86",
target_arch = "x86_64",
),
))]
mod avx2;
#[cfg(all(
httparse_simd,
not(any(
httparse_simd_target_feature_sse42,
httparse_simd_target_feature_avx2,
)),
any(
target_arch = "x86",
target_arch = "x86_64",
),
))]
mod runtime {
//! Runtime detection of simd features. Used when the build script
//! doesn't notice any target features at build time.
//!
//! While `is_x86_feature_detected!` has it's own caching built-in,
//! at least in 1.27.0, the functions don't inline, leaving using it
//! actually *slower* than just using the scalar fallback.
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
static FEATURE: AtomicUsize = ATOMIC_USIZE_INIT;
const INIT: usize = 0;
const SSE_42: usize = 1;
const AVX_2: usize = 2;
const AVX_2_AND_SSE_42: usize = 3;
const NONE: usize = ::core::usize::MAX;
fn detect() -> usize {
let feat = FEATURE.load(Ordering::Relaxed);
if feat == INIT {
if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") {
if is_x86_feature_detected!("sse4.2") {
FEATURE.store(AVX_2_AND_SSE_42, Ordering::Relaxed);
return AVX_2_AND_SSE_42;
} else {
FEATURE.store(AVX_2, Ordering::Relaxed);
return AVX_2;
}
} else if is_x86_feature_detected!("sse4.2") {
FEATURE.store(SSE_42, Ordering::Relaxed);
return SSE_42;
} else {
FEATURE.store(NONE, Ordering::Relaxed);
}
}
feat
}
pub fn match_uri_vectored(bytes: &mut ::Bytes) {
unsafe {
match detect() {
SSE_42 => super::sse42::parse_uri_batch_16(bytes),
AVX_2 => { super::avx2::parse_uri_batch_32(bytes); },
AVX_2_AND_SSE_42 => {
if let super::avx2::Scan::Found = super::avx2::parse_uri_batch_32(bytes) {
return;
}
super::sse42::parse_uri_batch_16(bytes)
},
_ => ()
}
}
// else do nothing
}
pub fn match_header_value_vectored(bytes: &mut ::Bytes) {
unsafe {
match detect() {
SSE_42 => super::sse42::match_header_value_batch_16(bytes),
AVX_2 => { super::avx2::match_header_value_batch_32(bytes); },
AVX_2_AND_SSE_42 => {
if let super::avx2::Scan::Found = super::avx2::match_header_value_batch_32(bytes) {
return;
}
super::sse42::match_header_value_batch_16(bytes)
},
_ => ()
}
}
// else do nothing
}
}
#[cfg(all(
httparse_simd,
not(any(
httparse_simd_target_feature_sse42,
httparse_simd_target_feature_avx2,
)),
any(
target_arch = "x86",
target_arch = "x86_64",
),
))]
pub use self::runtime::*;
#[cfg(all(
httparse_simd,
httparse_simd_target_feature_sse42,
not(httparse_simd_target_feature_avx2),
any(
target_arch = "x86",
target_arch = "x86_64",
),
))]
mod sse42_compile_time {
pub fn match_uri_vectored(bytes: &mut ::Bytes) {
if is_x86_feature_detected!("sse4.2") {
unsafe {
super::sse42::parse_uri_batch_16(bytes);
}
}
// else do nothing
}
pub fn match_header_value_vectored(bytes: &mut ::Bytes) {
if is_x86_feature_detected!("sse4.2") {
unsafe {
super::sse42::match_header_value_batch_16(bytes);
}
}
// else do nothing
}
}
#[cfg(all(
httparse_simd,
httparse_simd_target_feature_sse42,
not(httparse_simd_target_feature_avx2),
any(
target_arch = "x86",
target_arch = "x86_64",
),
))]
pub use self::sse42_compile_time::*;
#[cfg(all(
httparse_simd,
httparse_simd_target_feature_avx2,
any(
target_arch = "x86",
target_arch = "x86_64",
),
))]
mod avx2_compile_time {
pub fn match_uri_vectored(bytes: &mut ::Bytes) {
// do both, since avx2 only works when bytes.len() >= 32
if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") {
unsafe {
super::avx2::parse_uri_batch_32(bytes);
}
}
if is_x86_feature_detected!("sse4.2") {
unsafe {
super::sse42::parse_uri_batch_16(bytes);
}
}
// else do nothing
}
pub fn match_header_value_vectored(bytes: &mut ::Bytes) {
// do both, since avx2 only works when bytes.len() >= 32
if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") {
let scanned = unsafe {
super::avx2::match_header_value_batch_32(bytes)
};
if let super::avx2::Scan::Found = scanned {
return;
}
}
if is_x86_feature_detected!("sse4.2") {
unsafe {
super::sse42::match_header_value_batch_16(bytes);
}
}
// else do nothing
}
}
#[cfg(all(
httparse_simd,
httparse_simd_target_feature_avx2,
any(
target_arch = "x86",
target_arch = "x86_64",
),
))]
pub use self::avx2_compile_time::*;

View File

@ -0,0 +1,84 @@
use ::iter::Bytes;
pub unsafe fn parse_uri_batch_16<'a>(bytes: &mut Bytes<'a>) {
while bytes.as_ref().len() >= 16 {
let advance = match_url_char_16_sse(bytes.as_ref());
bytes.advance(advance);
if advance != 16 {
break;
}
}
}
#[target_feature(enable = "sse4.2")]
#[allow(non_snake_case, overflowing_literals)]
unsafe fn match_url_char_16_sse(buf: &[u8]) -> usize {
debug_assert!(buf.len() >= 16);
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
let ptr = buf.as_ptr();
let LSH: __m128i = _mm_set1_epi8(0x0f);
let URI: __m128i = _mm_setr_epi8(
0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c,
);
let ARF: __m128i = _mm_setr_epi8(
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
);
let data = _mm_lddqu_si128(ptr as *const _);
let rbms = _mm_shuffle_epi8(URI, data);
let cols = _mm_and_si128(LSH, _mm_srli_epi16(data, 4));
let bits = _mm_and_si128(_mm_shuffle_epi8(ARF, cols), rbms);
let v = _mm_cmpeq_epi8(bits, _mm_setzero_si128());
let r = 0xffff_0000 | _mm_movemask_epi8(v) as u32;
_tzcnt_u32(r) as usize
}
pub unsafe fn match_header_value_batch_16(bytes: &mut Bytes) {
while bytes.as_ref().len() >= 16 {
let advance = match_header_value_char_16_sse(bytes.as_ref());
bytes.advance(advance);
if advance != 16 {
break;
}
}
}
#[target_feature(enable = "sse4.2")]
#[allow(non_snake_case)]
unsafe fn match_header_value_char_16_sse(buf: &[u8]) -> usize {
debug_assert!(buf.len() >= 16);
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
let ptr = buf.as_ptr();
// %x09 %x20-%x7e %x80-%xff
let TAB: __m128i = _mm_set1_epi8(0x09);
let DEL: __m128i = _mm_set1_epi8(0x7f);
let LOW: __m128i = _mm_set1_epi8(0x1f);
let dat = _mm_lddqu_si128(ptr as *const _);
let low = _mm_cmpgt_epi8(dat, LOW);
let tab = _mm_cmpeq_epi8(dat, TAB);
let del = _mm_cmpeq_epi8(dat, DEL);
let bit = _mm_andnot_si128(del, _mm_or_si128(low, tab));
let rev = _mm_cmpeq_epi8(bit, _mm_setzero_si128());
let res = 0xffff_0000 | _mm_movemask_epi8(rev) as u32;
_tzcnt_u32(res) as usize
}

3677
third_party/rust/httparse/tests/uri.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
{"files":{"CHANGELOG.md":"0ac479629dc1cde30432141baf12e6ee347b14bd3cd07a44ea3e645fdb1a0d7c","Cargo.toml":"152d2f4435ce45bd83a0f3842a04c0aed7223f458c843c9ad1cc10ad6f0acca6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"4d3959aeee87b7924faecca7e7369370a2ac603422e7bb3fea86191b2574899d","README.md":"ea7850a3e9cc388dd40c7e5ea26e08cec788219fc4cd01280ea52cb7382d184f","src/lib.rs":"226ef2985de8085b4edd780578f4cf5e77f58512c566b2fa8462086db8f96e15"},"package":"a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"}
{"files":{"CHANGELOG.md":"0aa4629e399d08ad3a446366d465449a5e92ba95aac708be76961100a9c7df48","Cargo.toml":"15c8e40c3c9ed8635ed338b633d343702b6f4a90dcd5aa759673d31af401dd0a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"03f6ccb4e6040abccf12b31551bbbd1800a5069a17950bbd6db850d85744800f","README.md":"c0798b2c9b0d3b9c0da509fdd9001eb2d80e6ed0850d312e36136ac269dbe49f","src/lib.rs":"7ea882864c246d78be6ea3558b92a8a7dd5732f55556cd641efb7a8caf4e64e3"},"package":"b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"}

View File

@ -1,3 +1,49 @@
<a name="v1.2.1"></a>
## v1.2.1 (2018-12-03)
#### Features
* Implement Clone for LazyCell and AtomicLazyCell ([30fe4a8f](https://github.com/indiv0/lazycell/commit/30fe4a8f568059b3c78ed149a810962a676cb2b2))
<a name="v1.2.0"></a>
## v1.2.0 (2018-09-19)
#### Features
* add `LazyCell::replace` for infallible access ([a63ffb90](https://github.com/indiv0/lazycell/commit/a63ffb9040a5e0683a9bbf9d3d5ef589f2ca8b7c))
<a name="v1.1.0"></a>
## v1.1.0 (2018-09-10)
#### Documentation
* add note regarding LazyCell::borrow_mut ([9d634d1f](https://github.com/indiv0/lazycell/commit/9d634d1fd9a21b7aa075d407bedf9fe77ba8b79f))
* describe mutability more consistently ([b8078029](https://github.com/indiv0/lazycell/commit/b80780294611e92efddcdd33a701b3049ab5c5eb), closes [#78](https://github.com/indiv0/lazycell/issues/78))
#### Improvements
* add NONE constant for an empty AtomicLazyCell ([31aff0da](https://github.com/indiv0/lazycell/commit/31aff0dacf824841c5f38ef4acf0aa71ec4c36eb), closes [#87](https://github.com/indiv0/lazycell/issues/87))
* add `LazyCell::borrow_mut_with` and `LazyCell::try_borrow_mut_with` ([fdc6d268](https://github.com/indiv0/lazycell/commit/fdc6d268f0e9a6668768302f45fe2bb4aa9a7c34), closes [#79](https://github.com/indiv0/lazycell/issues/79), [#80](https://github.com/indiv0/lazycell/issues/80))
<a name="v1.0.0"></a>
## v1.0.0 (2018-06-06)
#### Features
* Add #![no_std] ([e59f6b55](https://github.com/indiv0/lazycell/commit/e59f6b5531e310d3df26b0eb40b1431937f38096))
<a name="0.6.0"></a>
## 0.6.0 (2017-11-25)

View File

@ -12,7 +12,7 @@
[package]
name = "lazycell"
version = "0.6.0"
version = "1.2.1"
authors = ["Alex Crichton <alex@alexcrichton.com>", "Nikita Pekin <contact@nikitapek.in>"]
include = ["CHANGELOG.md", "Cargo.toml", "LICENSE-MIT", "LICENSE-APACHE", "README.md", "src/**/*.rs"]
description = "A library providing a lazily filled Cell struct"

View File

@ -1,5 +1,5 @@
Original work Copyright (c) 2014 The Rust Project Developers
Modified work Copyright (c) 2016-2017 Nikita Pekin and lazycell contributors
Modified work Copyright (c) 2016-2018 Nikita Pekin and lazycell contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated

View File

@ -30,7 +30,7 @@ Add the following to your `Cargo.toml`:
```toml
[dependencies]
lazycell = "0.6"
lazycell = "1.2"
```
And in your `lib.rs` or `main.rs`:

View File

@ -1,5 +1,5 @@
// Original work Copyright (c) 2014 The Rust Project Developers
// Modified work Copyright (c) 2016-2017 Nikita Pekin and the lazycell contributors
// Modified work Copyright (c) 2016-2018 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
@ -8,21 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(not(test), no_std)]
#![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.
//! `Cell`.
//!
//! 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 and shared,
//! it can be modified.
//!
//! # Example
//!
//! The following example shows a quick example of the basic functionality of
@ -42,12 +41,23 @@
//! ```
//!
//! `AtomicLazyCell` is a variant that uses an atomic variable to manage
//! coordination in a thread-safe fashion.
//! coordination in a thread-safe fashion. The limitation of an `AtomicLazyCell`
//! is that after it is initialized, it can't be modified.
#[cfg(not(test))]
#[macro_use]
extern crate core as std;
use std::cell::UnsafeCell;
use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
/// A lazily filled `Cell`, with frozen contents.
/// A lazily filled `Cell`, with mutable contents.
///
/// A `LazyCell` is completely frozen once filled, **unless** you have `&mut`
/// access to it, in which case `LazyCell::borrow_mut` may be used to mutate the
/// contents.
#[derive(Debug, Default)]
pub struct LazyCell<T> {
inner: UnsafeCell<Option<T>>,
@ -63,7 +73,7 @@ impl<T> LazyCell<T> {
///
/// This function will return `Err(value)` is the cell is already full.
pub fn fill(&self, value: T) -> Result<(), T> {
let mut slot = unsafe { &mut *self.inner.get() };
let slot = unsafe { &mut *self.inner.get() };
if slot.is_some() {
return Err(value);
}
@ -72,6 +82,20 @@ impl<T> LazyCell<T> {
Ok(())
}
/// Put a value into this cell.
///
/// Note that this function is infallible but requires `&mut self`. By
/// requiring `&mut self` we're guaranteed that no active borrows to this
/// cell can exist so we can always fill in the value. This may not always
/// be usable, however, as `&mut self` may not be possible to borrow.
///
/// # Return value
///
/// This function returns the previous value, if any.
pub fn replace(&mut self, value: T) -> Option<T> {
mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
}
/// Test whether this cell has been previously filled.
pub fn filled(&self) -> bool {
self.borrow().is_some()
@ -115,6 +139,26 @@ impl<T> LazyCell<T> {
self.borrow().unwrap()
}
/// Borrows the contents of this `LazyCell` mutably for the duration of the
/// cell itself.
///
/// If the cell has not yet been filled, the cell is first filled using the
/// function provided.
///
/// # Panics
///
/// Panics if the cell becomes filled as a side effect of `f`.
pub fn borrow_mut_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
if !self.filled() {
let value = f();
if self.fill(value).is_err() {
panic!("borrow_mut_with: cell was filled by closure")
}
}
self.borrow_mut().unwrap()
}
/// Same as `borrow_with`, but allows the initializing function to fail.
///
/// # Panics
@ -133,8 +177,30 @@ impl<T> LazyCell<T> {
Ok(self.borrow().unwrap())
}
/// Same as `borrow_mut_with`, but allows the initializing function to fail.
///
/// # Panics
///
/// Panics if the cell becomes filled as a side effect of `f`.
pub fn try_borrow_mut_with<E, F>(&mut self, f: F) -> Result<&mut T, E>
where F: FnOnce() -> Result<T, E>
{
if self.filled() {
return Ok(self.borrow_mut().unwrap());
}
let value = f()?;
if self.fill(value).is_err() {
panic!("try_borrow_mut_with: cell was filled by closure")
}
Ok(self.borrow_mut().unwrap())
}
/// Consumes this `LazyCell`, returning the underlying value.
pub fn into_inner(self) -> Option<T> {
// Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe
// function. This unsafe can be removed when supporting Rust older than
// 1.25 is not needed.
#[allow(unused_unsafe)]
unsafe { self.inner.into_inner() }
}
}
@ -149,12 +215,23 @@ impl<T: Copy> LazyCell<T> {
}
}
impl <T: Clone> Clone for LazyCell<T> {
/// Create a clone of this `LazyCell`
///
/// If self has not been initialized, returns an uninitialized `LazyCell`
/// otherwise returns a `LazyCell` already initialized with a clone of the
/// contents of self.
fn clone(&self) -> LazyCell<T> {
LazyCell { inner: UnsafeCell::new(self.borrow().map(Clone::clone) ) }
}
}
// Tracks the AtomicLazyCell inner state
const NONE: usize = 0;
const LOCK: usize = 1;
const SOME: usize = 2;
/// A lazily filled `Cell`, with frozen contents.
/// A lazily filled and thread-safe `Cell`, with frozen contents.
#[derive(Debug, Default)]
pub struct AtomicLazyCell<T> {
inner: UnsafeCell<Option<T>>,
@ -162,12 +239,15 @@ pub struct AtomicLazyCell<T> {
}
impl<T> AtomicLazyCell<T> {
/// An empty `AtomicLazyCell`.
pub const NONE: Self = Self {
inner: UnsafeCell::new(None),
state: AtomicUsize::new(NONE),
};
/// Creates a new, empty, `AtomicLazyCell`.
pub fn new() -> AtomicLazyCell<T> {
AtomicLazyCell {
inner: UnsafeCell::new(None),
state: AtomicUsize::new(NONE),
}
Self::NONE
}
/// Put a value into this cell.
@ -187,6 +267,24 @@ impl<T> AtomicLazyCell<T> {
Ok(())
}
/// Put a value into this cell.
///
/// Note that this function is infallible but requires `&mut self`. By
/// requiring `&mut self` we're guaranteed that no active borrows to this
/// cell can exist so we can always fill in the value. This may not always
/// be usable, however, as `&mut self` may not be possible to borrow.
///
/// # Return value
///
/// This function returns the previous value, if any.
pub fn replace(&mut self, value: T) -> Option<T> {
match mem::replace(self.state.get_mut(), SOME) {
NONE | SOME => {}
_ => panic!("cell in inconsistent state"),
}
mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
}
/// Test whether this cell has been previously filled.
pub fn filled(&self) -> bool {
self.state.load(Ordering::Acquire) == SOME
@ -206,6 +304,10 @@ impl<T> AtomicLazyCell<T> {
/// Consumes this `LazyCell`, returning the underlying value.
pub fn into_inner(self) -> Option<T> {
// Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe
// function. This unsafe can be removed when supporting Rust older than
// 1.25 is not needed.
#[allow(unused_unsafe)]
unsafe { self.inner.into_inner() }
}
}
@ -223,6 +325,23 @@ impl<T: Copy> AtomicLazyCell<T> {
}
}
impl<T: Clone> Clone for AtomicLazyCell<T> {
/// Create a clone of this `AtomicLazyCell`
///
/// If self has not been initialized, returns an uninitialized `AtomicLazyCell`
/// otherwise returns an `AtomicLazyCell` already initialized with a clone of the
/// contents of self.
fn clone(&self) -> AtomicLazyCell<T> {
self.borrow().map_or(
Self::NONE,
|v| AtomicLazyCell {
inner: UnsafeCell::new(Some(v.clone())),
state: AtomicUsize::new(SOME),
}
)
}
}
unsafe impl<T: Sync + Send> Sync for AtomicLazyCell<T> {}
unsafe impl<T: Send> Send for AtomicLazyCell<T> {}
@ -324,6 +443,37 @@ mod tests {
});
}
#[test]
fn test_borrow_mut_with() {
let mut lazycell = LazyCell::new();
{
let value = lazycell.borrow_mut_with(|| 1);
assert_eq!(&mut 1, value);
*value = 2;
}
assert_eq!(&2, lazycell.borrow().unwrap());
}
#[test]
fn test_borrow_mut_with_already_filled() {
let mut lazycell = LazyCell::new();
lazycell.fill(1).unwrap();
let value = lazycell.borrow_mut_with(|| 1);
assert_eq!(&1, value);
}
#[test]
fn test_borrow_mut_with_not_called_when_filled() {
let mut lazycell = LazyCell::new();
lazycell.fill(1).unwrap();
let value = lazycell.borrow_mut_with(|| 2);
assert_eq!(&1, value);
}
#[test]
fn test_try_borrow_with_ok() {
let lazycell = LazyCell::new();
@ -360,6 +510,32 @@ mod tests {
});
}
#[test]
fn test_try_borrow_mut_with_ok() {
let mut lazycell = LazyCell::new();
{
let result = lazycell.try_borrow_mut_with::<(), _>(|| Ok(1));
assert_eq!(result, Ok(&mut 1));
*result.unwrap() = 2;
}
assert_eq!(&mut 2, lazycell.borrow().unwrap());
}
#[test]
fn test_try_borrow_mut_with_err() {
let mut lazycell = LazyCell::<()>::new();
let result = lazycell.try_borrow_mut_with(|| Err(1));
assert_eq!(result, Err(1));
}
#[test]
fn test_try_borrow_mut_with_already_filled() {
let mut lazycell = LazyCell::new();
lazycell.fill(1).unwrap();
let result = lazycell.try_borrow_mut_with::<(), _>(|| unreachable!());
assert_eq!(result, Ok(&mut 1));
}
#[test]
fn test_into_inner() {
let lazycell = LazyCell::new();
@ -411,4 +587,63 @@ mod tests {
let value = lazycell.into_inner();
assert_eq!(value, Some(1));
}
#[test]
fn normal_replace() {
let mut cell = LazyCell::new();
assert_eq!(cell.fill(1), Ok(()));
assert_eq!(cell.replace(2), Some(1));
assert_eq!(cell.replace(3), Some(2));
assert_eq!(cell.borrow(), Some(&3));
let mut cell = LazyCell::new();
assert_eq!(cell.replace(2), None);
}
#[test]
fn atomic_replace() {
let mut cell = AtomicLazyCell::new();
assert_eq!(cell.fill(1), Ok(()));
assert_eq!(cell.replace(2), Some(1));
assert_eq!(cell.replace(3), Some(2));
assert_eq!(cell.borrow(), Some(&3));
}
#[test]
fn clone() {
let mut cell = LazyCell::new();
let clone1 = cell.clone();
assert_eq!(clone1.borrow(), None);
assert_eq!(cell.fill(1), Ok(()));
let mut clone2 = cell.clone();
assert_eq!(clone1.borrow(), None);
assert_eq!(clone2.borrow(), Some(&1));
assert_eq!(cell.replace(2), Some(1));
assert_eq!(clone1.borrow(), None);
assert_eq!(clone2.borrow(), Some(&1));
assert_eq!(clone1.fill(3), Ok(()));
assert_eq!(clone2.replace(4), Some(1));
assert_eq!(clone1.borrow(), Some(&3));
assert_eq!(clone2.borrow(), Some(&4));
assert_eq!(cell.borrow(), Some(&2));
}
#[test]
fn clone_atomic() {
let mut cell = AtomicLazyCell::new();
let clone1 = cell.clone();
assert_eq!(clone1.borrow(), None);
assert_eq!(cell.fill(1), Ok(()));
let mut clone2 = cell.clone();
assert_eq!(clone1.borrow(), None);
assert_eq!(clone2.borrow(), Some(&1));
assert_eq!(cell.replace(2), Some(1));
assert_eq!(clone1.borrow(), None);
assert_eq!(clone2.borrow(), Some(&1));
assert_eq!(clone1.fill(3), Ok(()));
assert_eq!(clone2.replace(4), Some(1));
assert_eq!(clone1.borrow(), Some(&3));
assert_eq!(clone2.borrow(), Some(&4));
assert_eq!(cell.borrow(), Some(&2));
}
}

View File

@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"9f7efb5e07d7bba6e6db9142f35d8379144d3707eaf767ca41759bbfa91e0422","Cargo.toml":"37ea791a7fee2939e800737d62c2cd3189e6c71b57935de9ae02519b04d4dc4c","LICENSE-APACHE":"406e5cbaa2ad1178c300cf28ac5258e8d0db0de4f061e78db559d30e6f38e25c","LICENSE-MIT":"8aa414e6c821efd8be6bade07368a5d9f51f5cc55718bc54e10a59eb826b8d58","README.md":"337973d4db2bd42559bded991de98bf3929d39df00d5f17221e4b493075f8317","src/channel.rs":"bfc4f386595291418a5975250f12431d4fe92714cf422369e6a7960754719b51","src/lib.rs":"2ed1572d3255208681d017265df7f642eb4898b1c2dace91676935f55e03eb04","src/timer.rs":"2aa0070b4d59f74262c926d5378781896260c2264d06e47aa2fc1cafb6cf104b","test/mod.rs":"aa3afc2582f00e5e2a2e5b87d12eb9810b0eed3248b48abef7094fd8d02d9c41","test/test_poll_channel.rs":"a96f5749438853cb8c0727e304eabfd7f23400802da73938337ab29210787bcd","test/test_timer.rs":"082c48a320f603d8a99f6ed13c0efe7f48638d33222782e85364575ce805c20c"},"package":"46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"}

View File

@ -0,0 +1,31 @@
## 2.0.5 (18 Jun 2018)
* update `lazycell` from 0.6 -> 1.0
## 2.0.4 (7 Apr 2018)
* Bump mio dependency (fixes minimal-versions build)
## 2.0.3 (28 Dec 2017)
* update `log` from 0.3 -> 0.4
## 2.0.2
* More docs tidying.
## 2.0.1
* Another try at documenting the timer interface.
## 2.0.0
* Remove channel implementation details from the API. Specifically, the following are no longer public:
* `ctl_pair()`
* `SenderCtl`
* `ReceiverCtl`
* Document all APIs
## 1.0.0
* Initial release. Essentially identical to [mio-more](https://github.com/carllerche/mio-more).

39
third_party/rust/mio-extras/Cargo.toml vendored Normal file
View File

@ -0,0 +1,39 @@
# 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 = "mio-extras"
version = "2.0.5"
authors = ["Carl Lerche <me@carllerche.com>", "David Hotham"]
exclude = [".gitignore"]
description = "Extra components for use with Mio"
documentation = "https://docs.rs/mio-extras"
readme = "README.md"
keywords = ["io", "async", "non-blocking"]
categories = ["asynchronous"]
license = "MIT"
repository = "https://github.com/dimbleby/mio-extras"
[[test]]
name = "test"
path = "test/mod.rs"
[dependencies.lazycell]
version = "1"
[dependencies.log]
version = "0.4"
[dependencies.mio]
version = "0.6.14"
[dependencies.slab]
version = "0.4"

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 Mio authors
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-extras/LICENSE-MIT vendored Normal file
View File

@ -0,0 +1,25 @@
Copyright (c) 2017 Mio authors
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.

28
third_party/rust/mio-extras/README.md vendored Normal file
View File

@ -0,0 +1,28 @@
# mio-extras
Extra components for use with [Mio](https://github.com/carllerche/mio):
* a channel that implements `Evented`
* a timer that implements `Evented`
[![Build Status](https://travis-ci.org/dimbleby/mio-extras.svg?branch=master)](https://travis-ci.org/dimbleby/mio-extras)
[![crates.io](http://meritbadge.herokuapp.com/mio-extras)](https://crates.io/crates/mio-extras)
[Documentation](https://docs.rs/mio-extras).
## History and maintenance
This repository is forked from [`mio-more`](https://github.com/carllerche/mio-more), which is unmaintained.
I don't intend to do very much with this except for routine maintenance - bug fixes, updating dependencies, and suchlike.
However if you have some code that you think belongs here, then by all means raise an issue or open a pull request.
# License
`mio-extras` 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.

View File

@ -0,0 +1,431 @@
//! Thread safe communication channel implementing `Evented`
use lazycell::{AtomicLazyCell, LazyCell};
use mio::{Evented, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use std::any::Any;
use std::error;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{mpsc, Arc};
use std::{fmt, io};
/// Creates a new asynchronous channel, where the `Receiver` can be registered
/// with `Poll`.
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let (tx_ctl, rx_ctl) = ctl_pair();
let (tx, rx) = mpsc::channel();
let tx = Sender { tx, ctl: tx_ctl };
let rx = Receiver { rx, ctl: rx_ctl };
(tx, rx)
}
/// Creates a new synchronous, bounded channel where the `Receiver` can be
/// registered with `Poll`.
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
let (tx_ctl, rx_ctl) = ctl_pair();
let (tx, rx) = mpsc::sync_channel(bound);
let tx = SyncSender { tx, ctl: tx_ctl };
let rx = Receiver { rx, ctl: rx_ctl };
(tx, rx)
}
fn ctl_pair() -> (SenderCtl, ReceiverCtl) {
let inner = Arc::new(Inner {
pending: AtomicUsize::new(0),
senders: AtomicUsize::new(1),
set_readiness: AtomicLazyCell::new(),
});
let tx = SenderCtl {
inner: Arc::clone(&inner),
};
let rx = ReceiverCtl {
registration: LazyCell::new(),
inner,
};
(tx, rx)
}
/// Tracks messages sent on a channel in order to update readiness.
struct SenderCtl {
inner: Arc<Inner>,
}
/// Tracks messages received on a channel in order to track readiness.
struct ReceiverCtl {
registration: LazyCell<Registration>,
inner: Arc<Inner>,
}
/// The sending half of a channel.
pub struct Sender<T> {
tx: mpsc::Sender<T>,
ctl: SenderCtl,
}
/// The sending half of a synchronous channel.
pub struct SyncSender<T> {
tx: mpsc::SyncSender<T>,
ctl: SenderCtl,
}
/// The receiving half of a channel.
pub struct Receiver<T> {
rx: mpsc::Receiver<T>,
ctl: ReceiverCtl,
}
/// An error returned from the `Sender::send` or `SyncSender::send` function.
pub enum SendError<T> {
/// An IO error.
Io(io::Error),
/// The receiving half of the channel has disconnected.
Disconnected(T),
}
/// An error returned from the `SyncSender::try_send` function.
pub enum TrySendError<T> {
/// An IO error.
Io(io::Error),
/// Data could not be sent because it would require the callee to block.
Full(T),
/// The receiving half of the channel has disconnected.
Disconnected(T),
}
struct Inner {
// The number of outstanding messages for the receiver to read
pending: AtomicUsize,
// The number of sender handles
senders: AtomicUsize,
// The set readiness handle
set_readiness: AtomicLazyCell<SetReadiness>,
}
impl<T> Sender<T> {
/// Attempts to send a value on this channel, returning it back if it could not be sent.
pub fn send(&self, t: T) -> Result<(), SendError<T>> {
self.tx.send(t).map_err(SendError::from).and_then(|_| {
try!(self.ctl.inc());
Ok(())
})
}
}
impl<T> Clone for Sender<T> {
fn clone(&self) -> Sender<T> {
Sender {
tx: self.tx.clone(),
ctl: self.ctl.clone(),
}
}
}
impl<T> SyncSender<T> {
/// Sends a value on this synchronous channel.
///
/// This function will *block* until space in the internal buffer becomes
/// available or a receiver is available to hand off the message to.
pub fn send(&self, t: T) -> Result<(), SendError<T>> {
self.tx.send(t).map_err(From::from).and_then(|_| {
try!(self.ctl.inc());
Ok(())
})
}
/// Attempts to send a value on this channel without blocking.
///
/// This method differs from `send` by returning immediately if the channel's
/// buffer is full or no receiver is waiting to acquire some data.
pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
self.tx.try_send(t).map_err(From::from).and_then(|_| {
try!(self.ctl.inc());
Ok(())
})
}
}
impl<T> Clone for SyncSender<T> {
fn clone(&self) -> SyncSender<T> {
SyncSender {
tx: self.tx.clone(),
ctl: self.ctl.clone(),
}
}
}
impl<T> Receiver<T> {
/// Attempts to return a pending value on this receiver without blocking.
pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
self.rx.try_recv().and_then(|res| {
let _ = self.ctl.dec();
Ok(res)
})
}
}
impl<T> Evented for Receiver<T> {
fn register(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
self.ctl.register(poll, token, interest, opts)
}
fn reregister(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
self.ctl.reregister(poll, token, interest, opts)
}
fn deregister(&self, poll: &Poll) -> io::Result<()> {
self.ctl.deregister(poll)
}
}
/*
*
* ===== SenderCtl / ReceiverCtl =====
*
*/
impl SenderCtl {
/// Call to track that a message has been sent
fn inc(&self) -> io::Result<()> {
let cnt = self.inner.pending.fetch_add(1, Ordering::Acquire);
if 0 == cnt {
// Toggle readiness to readable
if let Some(set_readiness) = self.inner.set_readiness.borrow() {
try!(set_readiness.set_readiness(Ready::readable()));
}
}
Ok(())
}
}
impl Clone for SenderCtl {
fn clone(&self) -> SenderCtl {
self.inner.senders.fetch_add(1, Ordering::Relaxed);
SenderCtl {
inner: Arc::clone(&self.inner),
}
}
}
impl Drop for SenderCtl {
fn drop(&mut self) {
if self.inner.senders.fetch_sub(1, Ordering::Release) == 1 {
let _ = self.inc();
}
}
}
impl ReceiverCtl {
fn dec(&self) -> io::Result<()> {
let first = self.inner.pending.load(Ordering::Acquire);
if first == 1 {
// Unset readiness
if let Some(set_readiness) = self.inner.set_readiness.borrow() {
try!(set_readiness.set_readiness(Ready::empty()));
}
}
// Decrement
let second = self.inner.pending.fetch_sub(1, Ordering::AcqRel);
if first == 1 && second > 1 {
// There are still pending messages. Since readiness was
// previously unset, it must be reset here
if let Some(set_readiness) = self.inner.set_readiness.borrow() {
try!(set_readiness.set_readiness(Ready::readable()));
}
}
Ok(())
}
}
impl Evented for ReceiverCtl {
fn register(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
if self.registration.borrow().is_some() {
return Err(io::Error::new(
io::ErrorKind::Other,
"receiver already registered",
));
}
let (registration, set_readiness) = Registration::new2();
poll.register(&registration, token, interest, opts)?;
if self.inner.pending.load(Ordering::Relaxed) > 0 {
// TODO: Don't drop readiness
let _ = set_readiness.set_readiness(Ready::readable());
}
self.registration
.fill(registration)
.expect("unexpected state encountered");
self.inner
.set_readiness
.fill(set_readiness)
.expect("unexpected state encountered");
Ok(())
}
fn reregister(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
match self.registration.borrow() {
Some(registration) => poll.reregister(registration, token, interest, opts),
None => Err(io::Error::new(
io::ErrorKind::Other,
"receiver not registered",
)),
}
}
fn deregister(&self, poll: &Poll) -> io::Result<()> {
match self.registration.borrow() {
Some(registration) => poll.deregister(registration),
None => Err(io::Error::new(
io::ErrorKind::Other,
"receiver not registered",
)),
}
}
}
/*
*
* ===== Error conversions =====
*
*/
impl<T> From<mpsc::SendError<T>> for SendError<T> {
fn from(src: mpsc::SendError<T>) -> SendError<T> {
SendError::Disconnected(src.0)
}
}
impl<T> From<io::Error> for SendError<T> {
fn from(src: io::Error) -> SendError<T> {
SendError::Io(src)
}
}
impl<T> From<mpsc::TrySendError<T>> for TrySendError<T> {
fn from(src: mpsc::TrySendError<T>) -> TrySendError<T> {
match src {
mpsc::TrySendError::Full(v) => TrySendError::Full(v),
mpsc::TrySendError::Disconnected(v) => TrySendError::Disconnected(v),
}
}
}
impl<T> From<mpsc::SendError<T>> for TrySendError<T> {
fn from(src: mpsc::SendError<T>) -> TrySendError<T> {
TrySendError::Disconnected(src.0)
}
}
impl<T> From<io::Error> for TrySendError<T> {
fn from(src: io::Error) -> TrySendError<T> {
TrySendError::Io(src)
}
}
/*
*
* ===== Implement Error, Debug and Display for Errors =====
*
*/
impl<T: Any> error::Error for SendError<T> {
fn description(&self) -> &str {
match *self {
SendError::Io(ref io_err) => io_err.description(),
SendError::Disconnected(..) => "Disconnected",
}
}
}
impl<T: Any> error::Error for TrySendError<T> {
fn description(&self) -> &str {
match *self {
TrySendError::Io(ref io_err) => io_err.description(),
TrySendError::Full(..) => "Full",
TrySendError::Disconnected(..) => "Disconnected",
}
}
}
impl<T> fmt::Debug for SendError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format_send_error(self, f)
}
}
impl<T> fmt::Display for SendError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format_send_error(self, f)
}
}
impl<T> fmt::Debug for TrySendError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format_try_send_error(self, f)
}
}
impl<T> fmt::Display for TrySendError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format_try_send_error(self, f)
}
}
#[inline]
fn format_send_error<T>(e: &SendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
match *e {
SendError::Io(ref io_err) => write!(f, "{}", io_err),
SendError::Disconnected(..) => write!(f, "Disconnected"),
}
}
#[inline]
fn format_try_send_error<T>(e: &TrySendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
match *e {
TrySendError::Io(ref io_err) => write!(f, "{}", io_err),
TrySendError::Full(..) => write!(f, "Full"),
TrySendError::Disconnected(..) => write!(f, "Disconnected"),
}
}

33
third_party/rust/mio-extras/src/lib.rs vendored Normal file
View File

@ -0,0 +1,33 @@
//! Extra components for use with Mio.
#![deny(missing_docs)]
extern crate lazycell;
extern crate mio;
extern crate slab;
#[macro_use]
extern crate log;
pub mod channel;
pub mod timer;
// Conversion utilities
mod convert {
use std::time::Duration;
const NANOS_PER_MILLI: u32 = 1_000_000;
const MILLIS_PER_SEC: u64 = 1_000;
/// Convert a `Duration` to milliseconds, rounding up and saturating at
/// `u64::MAX`.
///
/// The saturating is fine because `u64::MAX` milliseconds are still many
/// million years.
pub fn millis(duration: Duration) -> u64 {
// Round up.
let millis = (duration.subsec_nanos() + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
duration
.as_secs()
.saturating_mul(MILLIS_PER_SEC)
.saturating_add(u64::from(millis))
}
}

751
third_party/rust/mio-extras/src/timer.rs vendored Normal file
View File

@ -0,0 +1,751 @@
//! Timer optimized for I/O related operations
use convert;
use lazycell::LazyCell;
use mio::{Evented, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use slab::Slab;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::{cmp, fmt, io, iter, thread, u64, usize};
/// A timer.
///
/// Typical usage goes like this:
///
/// * register the timer with a `mio::Poll`.
/// * set a timeout, by calling `Timer::set_timeout`. Here you provide some
/// state to be associated with this timeout.
/// * poll the `Poll`, to learn when a timeout has occurred.
/// * retrieve state associated with the timeout by calling `Timer::poll`.
///
/// You can omit use of the `Poll` altogether, if you like, and just poll the
/// `Timer` directly.
pub struct Timer<T> {
// Size of each tick in milliseconds
tick_ms: u64,
// Slab of timeout entries
entries: Slab<Entry<T>>,
// Timeout wheel. Each tick, the timer will look at the next slot for
// timeouts that match the current tick.
wheel: Vec<WheelEntry>,
// Tick 0's time instant
start: Instant,
// The current tick
tick: Tick,
// The next entry to possibly timeout
next: Token,
// Masks the target tick to get the slot
mask: u64,
// Set on registration with Poll
inner: LazyCell<Inner>,
}
/// Used to create a `Timer`.
pub struct Builder {
// Approximate duration of each tick
tick: Duration,
// Number of slots in the timer wheel
num_slots: usize,
// Max number of timeouts that can be in flight at a given time.
capacity: usize,
}
/// A timeout, as returned by `Timer::set_timeout`.
///
/// Use this as the argument to `Timer::cancel_timeout`, to cancel this timeout.
#[derive(Clone, Debug)]
pub struct Timeout {
// Reference into the timer entry slab
token: Token,
// Tick that it should match up with
tick: u64,
}
struct Inner {
registration: Registration,
set_readiness: SetReadiness,
wakeup_state: WakeupState,
wakeup_thread: thread::JoinHandle<()>,
}
impl Drop for Inner {
fn drop(&mut self) {
// 1. Set wakeup state to TERMINATE_THREAD
self.wakeup_state.store(TERMINATE_THREAD, Ordering::Release);
// 2. Wake him up
self.wakeup_thread.thread().unpark();
}
}
#[derive(Copy, Clone, Debug)]
struct WheelEntry {
next_tick: Tick,
head: Token,
}
// Doubly linked list of timer entries. Allows for efficient insertion /
// removal of timeouts.
struct Entry<T> {
state: T,
links: EntryLinks,
}
#[derive(Copy, Clone)]
struct EntryLinks {
tick: Tick,
prev: Token,
next: Token,
}
type Tick = u64;
const TICK_MAX: Tick = u64::MAX;
// Manages communication with wakeup thread
type WakeupState = Arc<AtomicUsize>;
const TERMINATE_THREAD: usize = 0;
const EMPTY: Token = Token(usize::MAX);
impl Builder {
/// Set the tick duration. Default is 100ms.
pub fn tick_duration(mut self, duration: Duration) -> Builder {
self.tick = duration;
self
}
/// Set the number of slots. Default is 256.
pub fn num_slots(mut self, num_slots: usize) -> Builder {
self.num_slots = num_slots;
self
}
/// Set the capacity. Default is 65536.
pub fn capacity(mut self, capacity: usize) -> Builder {
self.capacity = capacity;
self
}
/// Build a `Timer` with the parameters set on this `Builder`.
pub fn build<T>(self) -> Timer<T> {
Timer::new(
convert::millis(self.tick),
self.num_slots,
self.capacity,
Instant::now(),
)
}
}
impl Default for Builder {
fn default() -> Builder {
Builder {
tick: Duration::from_millis(100),
num_slots: 1 << 8,
capacity: 1 << 16,
}
}
}
impl<T> Timer<T> {
fn new(tick_ms: u64, num_slots: usize, capacity: usize, start: Instant) -> Timer<T> {
let num_slots = num_slots.next_power_of_two();
let capacity = capacity.next_power_of_two();
let mask = (num_slots as u64) - 1;
let wheel = iter::repeat(WheelEntry {
next_tick: TICK_MAX,
head: EMPTY,
}).take(num_slots)
.collect();
Timer {
tick_ms,
entries: Slab::with_capacity(capacity),
wheel,
start,
tick: 0,
next: EMPTY,
mask,
inner: LazyCell::new(),
}
}
/// Set a timeout.
///
/// When the timeout occurs, the given state becomes available via `poll`.
pub fn set_timeout(&mut self, delay_from_now: Duration, state: T) -> Timeout {
let delay_from_start = self.start.elapsed() + delay_from_now;
self.set_timeout_at(delay_from_start, state)
}
fn set_timeout_at(&mut self, delay_from_start: Duration, state: T) -> Timeout {
let mut tick = duration_to_tick(delay_from_start, self.tick_ms);
trace!(
"setting timeout; delay={:?}; tick={:?}; current-tick={:?}",
delay_from_start,
tick,
self.tick
);
// Always target at least 1 tick in the future
if tick <= self.tick {
tick = self.tick + 1;
}
self.insert(tick, state)
}
fn insert(&mut self, tick: Tick, state: T) -> Timeout {
// Get the slot for the requested tick
let slot = (tick & self.mask) as usize;
let curr = self.wheel[slot];
// Insert the new entry
let entry = Entry::new(state, tick, curr.head);
let token = Token(self.entries.insert(entry));
if curr.head != EMPTY {
// If there was a previous entry, set its prev pointer to the new
// entry
self.entries[curr.head.into()].links.prev = token;
}
// Update the head slot
self.wheel[slot] = WheelEntry {
next_tick: cmp::min(tick, curr.next_tick),
head: token,
};
self.schedule_readiness(tick);
trace!("inserted timout; slot={}; token={:?}", slot, token);
// Return the new timeout
Timeout { token, tick }
}
/// Cancel a timeout.
///
/// If the timeout has not yet occurred, the return value holds the
/// associated state.
pub fn cancel_timeout(&mut self, timeout: &Timeout) -> Option<T> {
let links = match self.entries.get(timeout.token.into()) {
Some(e) => e.links,
None => return None,
};
// Sanity check
if links.tick != timeout.tick {
return None;
}
self.unlink(&links, timeout.token);
Some(self.entries.remove(timeout.token.into()).state)
}
/// Poll for an expired timer.
///
/// The return value holds the state associated with the first expired
/// timer, if any.
pub fn poll(&mut self) -> Option<T> {
let target_tick = current_tick(self.start, self.tick_ms);
self.poll_to(target_tick)
}
fn poll_to(&mut self, mut target_tick: Tick) -> Option<T> {
trace!(
"tick_to; target_tick={}; current_tick={}",
target_tick,
self.tick
);
if target_tick < self.tick {
target_tick = self.tick;
}
while self.tick <= target_tick {
let curr = self.next;
trace!("ticking; curr={:?}", curr);
if curr == EMPTY {
self.tick += 1;
let slot = self.slot_for(self.tick);
self.next = self.wheel[slot].head;
// Handle the case when a slot has a single timeout which gets
// canceled before the timeout expires. In this case, the
// slot's head is EMPTY but there is a value for next_tick. Not
// resetting next_tick here causes the timer to get stuck in a
// loop.
if self.next == EMPTY {
self.wheel[slot].next_tick = TICK_MAX;
}
} else {
let slot = self.slot_for(self.tick);
if curr == self.wheel[slot].head {
self.wheel[slot].next_tick = TICK_MAX;
}
let links = self.entries[curr.into()].links;
if links.tick <= self.tick {
trace!("triggering; token={:?}", curr);
// Unlink will also advance self.next
self.unlink(&links, curr);
// Remove and return the token
return Some(self.entries.remove(curr.into()).state);
} else {
let next_tick = self.wheel[slot].next_tick;
self.wheel[slot].next_tick = cmp::min(next_tick, links.tick);
self.next = links.next;
}
}
}
// No more timeouts to poll
if let Some(inner) = self.inner.borrow() {
trace!("unsetting readiness");
let _ = inner.set_readiness.set_readiness(Ready::empty());
if let Some(tick) = self.next_tick() {
self.schedule_readiness(tick);
}
}
None
}
fn unlink(&mut self, links: &EntryLinks, token: Token) {
trace!(
"unlinking timeout; slot={}; token={:?}",
self.slot_for(links.tick),
token
);
if links.prev == EMPTY {
let slot = self.slot_for(links.tick);
self.wheel[slot].head = links.next;
} else {
self.entries[links.prev.into()].links.next = links.next;
}
if links.next != EMPTY {
self.entries[links.next.into()].links.prev = links.prev;
if token == self.next {
self.next = links.next;
}
} else if token == self.next {
self.next = EMPTY;
}
}
fn schedule_readiness(&self, tick: Tick) {
if let Some(inner) = self.inner.borrow() {
// Coordinate setting readiness w/ the wakeup thread
let mut curr = inner.wakeup_state.load(Ordering::Acquire);
loop {
if curr as Tick <= tick {
// Nothing to do, wakeup is already scheduled
return;
}
// Attempt to move the wakeup time forward
trace!("advancing the wakeup time; target={}; curr={}", tick, curr);
let actual =
inner
.wakeup_state
.compare_and_swap(curr, tick as usize, Ordering::Release);
if actual == curr {
// Signal to the wakeup thread that the wakeup time has
// been changed.
trace!("unparking wakeup thread");
inner.wakeup_thread.thread().unpark();
return;
}
curr = actual;
}
}
}
// Next tick containing a timeout
fn next_tick(&self) -> Option<Tick> {
if self.next != EMPTY {
let slot = self.slot_for(self.entries[self.next.into()].links.tick);
if self.wheel[slot].next_tick == self.tick {
// There is data ready right now
return Some(self.tick);
}
}
self.wheel.iter().map(|e| e.next_tick).min()
}
fn slot_for(&self, tick: Tick) -> usize {
(self.mask & tick) as usize
}
}
impl<T> Default for Timer<T> {
fn default() -> Timer<T> {
Builder::default().build()
}
}
impl<T> Evented for Timer<T> {
fn register(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
if self.inner.borrow().is_some() {
return Err(io::Error::new(
io::ErrorKind::Other,
"timer already registered",
));
}
let (registration, set_readiness) = Registration::new2();
poll.register(&registration, token, interest, opts)?;
let wakeup_state = Arc::new(AtomicUsize::new(usize::MAX));
let thread_handle = spawn_wakeup_thread(
Arc::clone(&wakeup_state),
set_readiness.clone(),
self.start,
self.tick_ms,
);
self.inner
.fill(Inner {
registration,
set_readiness,
wakeup_state,
wakeup_thread: thread_handle,
})
.expect("timer already registered");
if let Some(next_tick) = self.next_tick() {
self.schedule_readiness(next_tick);
}
Ok(())
}
fn reregister(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
match self.inner.borrow() {
Some(inner) => poll.reregister(&inner.registration, token, interest, opts),
None => Err(io::Error::new(
io::ErrorKind::Other,
"receiver not registered",
)),
}
}
fn deregister(&self, poll: &Poll) -> io::Result<()> {
match self.inner.borrow() {
Some(inner) => poll.deregister(&inner.registration),
None => Err(io::Error::new(
io::ErrorKind::Other,
"receiver not registered",
)),
}
}
}
impl fmt::Debug for Inner {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Inner")
.field("registration", &self.registration)
.field("wakeup_state", &self.wakeup_state.load(Ordering::Relaxed))
.finish()
}
}
fn spawn_wakeup_thread(
state: WakeupState,
set_readiness: SetReadiness,
start: Instant,
tick_ms: u64,
) -> thread::JoinHandle<()> {
thread::spawn(move || {
let mut sleep_until_tick = state.load(Ordering::Acquire) as Tick;
loop {
if sleep_until_tick == TERMINATE_THREAD as Tick {
return;
}
let now_tick = current_tick(start, tick_ms);
trace!(
"wakeup thread: sleep_until_tick={:?}; now_tick={:?}",
sleep_until_tick,
now_tick
);
if now_tick < sleep_until_tick {
// Calling park_timeout with u64::MAX leads to undefined
// behavior in pthread, causing the park to return immediately
// and causing the thread to tightly spin. Instead of u64::MAX
// on large values, simply use a blocking park.
match tick_ms.checked_mul(sleep_until_tick - now_tick) {
Some(sleep_duration) => {
trace!(
"sleeping; tick_ms={}; now_tick={}; sleep_until_tick={}; duration={:?}",
tick_ms,
now_tick,
sleep_until_tick,
sleep_duration
);
thread::park_timeout(Duration::from_millis(sleep_duration));
}
None => {
trace!(
"sleeping; tick_ms={}; now_tick={}; blocking sleep",
tick_ms,
now_tick
);
thread::park();
}
}
sleep_until_tick = state.load(Ordering::Acquire) as Tick;
} else {
let actual =
state.compare_and_swap(sleep_until_tick as usize, usize::MAX, Ordering::AcqRel)
as Tick;
if actual == sleep_until_tick {
trace!("setting readiness from wakeup thread");
let _ = set_readiness.set_readiness(Ready::readable());
sleep_until_tick = usize::MAX as Tick;
} else {
sleep_until_tick = actual as Tick;
}
}
}
})
}
fn duration_to_tick(elapsed: Duration, tick_ms: u64) -> Tick {
// Calculate tick rounding up to the closest one
let elapsed_ms = convert::millis(elapsed);
elapsed_ms.saturating_add(tick_ms / 2) / tick_ms
}
fn current_tick(start: Instant, tick_ms: u64) -> Tick {
duration_to_tick(start.elapsed(), tick_ms)
}
impl<T> Entry<T> {
fn new(state: T, tick: u64, next: Token) -> Entry<T> {
Entry {
state,
links: EntryLinks {
tick,
prev: EMPTY,
next,
},
}
}
}
#[cfg(test)]
mod test {
use super::*;
use std::time::{Duration, Instant};
#[test]
pub fn test_timeout_next_tick() {
let mut t = timer();
let mut tick;
t.set_timeout_at(Duration::from_millis(100), "a");
tick = ms_to_tick(&t, 50);
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 100);
assert_eq!(Some("a"), t.poll_to(tick));
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 150);
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 200);
assert_eq!(None, t.poll_to(tick));
assert_eq!(count(&t), 0);
}
#[test]
pub fn test_clearing_timeout() {
let mut t = timer();
let mut tick;
let to = t.set_timeout_at(Duration::from_millis(100), "a");
assert_eq!("a", t.cancel_timeout(&to).unwrap());
tick = ms_to_tick(&t, 100);
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 200);
assert_eq!(None, t.poll_to(tick));
assert_eq!(count(&t), 0);
}
#[test]
pub fn test_multiple_timeouts_same_tick() {
let mut t = timer();
let mut tick;
t.set_timeout_at(Duration::from_millis(100), "a");
t.set_timeout_at(Duration::from_millis(100), "b");
let mut rcv = vec![];
tick = ms_to_tick(&t, 100);
rcv.push(t.poll_to(tick).unwrap());
rcv.push(t.poll_to(tick).unwrap());
assert_eq!(None, t.poll_to(tick));
rcv.sort();
assert!(rcv == ["a", "b"], "actual={:?}", rcv);
tick = ms_to_tick(&t, 200);
assert_eq!(None, t.poll_to(tick));
assert_eq!(count(&t), 0);
}
#[test]
pub fn test_multiple_timeouts_diff_tick() {
let mut t = timer();
let mut tick;
t.set_timeout_at(Duration::from_millis(110), "a");
t.set_timeout_at(Duration::from_millis(220), "b");
t.set_timeout_at(Duration::from_millis(230), "c");
t.set_timeout_at(Duration::from_millis(440), "d");
t.set_timeout_at(Duration::from_millis(560), "e");
tick = ms_to_tick(&t, 100);
assert_eq!(Some("a"), t.poll_to(tick));
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 200);
assert_eq!(Some("c"), t.poll_to(tick));
assert_eq!(Some("b"), t.poll_to(tick));
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 300);
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 400);
assert_eq!(Some("d"), t.poll_to(tick));
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 500);
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 600);
assert_eq!(Some("e"), t.poll_to(tick));
assert_eq!(None, t.poll_to(tick));
}
#[test]
pub fn test_catching_up() {
let mut t = timer();
t.set_timeout_at(Duration::from_millis(110), "a");
t.set_timeout_at(Duration::from_millis(220), "b");
t.set_timeout_at(Duration::from_millis(230), "c");
t.set_timeout_at(Duration::from_millis(440), "d");
let tick = ms_to_tick(&t, 600);
assert_eq!(Some("a"), t.poll_to(tick));
assert_eq!(Some("c"), t.poll_to(tick));
assert_eq!(Some("b"), t.poll_to(tick));
assert_eq!(Some("d"), t.poll_to(tick));
assert_eq!(None, t.poll_to(tick));
}
#[test]
pub fn test_timeout_hash_collision() {
let mut t = timer();
let mut tick;
t.set_timeout_at(Duration::from_millis(100), "a");
t.set_timeout_at(Duration::from_millis(100 + TICK * SLOTS as u64), "b");
tick = ms_to_tick(&t, 100);
assert_eq!(Some("a"), t.poll_to(tick));
assert_eq!(1, count(&t));
tick = ms_to_tick(&t, 200);
assert_eq!(None, t.poll_to(tick));
assert_eq!(1, count(&t));
tick = ms_to_tick(&t, 100 + TICK * SLOTS as u64);
assert_eq!(Some("b"), t.poll_to(tick));
assert_eq!(0, count(&t));
}
#[test]
pub fn test_clearing_timeout_between_triggers() {
let mut t = timer();
let mut tick;
let a = t.set_timeout_at(Duration::from_millis(100), "a");
let _ = t.set_timeout_at(Duration::from_millis(100), "b");
let _ = t.set_timeout_at(Duration::from_millis(200), "c");
tick = ms_to_tick(&t, 100);
assert_eq!(Some("b"), t.poll_to(tick));
assert_eq!(2, count(&t));
t.cancel_timeout(&a);
assert_eq!(1, count(&t));
assert_eq!(None, t.poll_to(tick));
tick = ms_to_tick(&t, 200);
assert_eq!(Some("c"), t.poll_to(tick));
assert_eq!(0, count(&t));
}
const TICK: u64 = 100;
const SLOTS: usize = 16;
const CAPACITY: usize = 32;
fn count<T>(timer: &Timer<T>) -> usize {
timer.entries.len()
}
fn timer() -> Timer<&'static str> {
Timer::new(TICK, SLOTS, CAPACITY, Instant::now())
}
fn ms_to_tick<T>(timer: &Timer<T>, ms: u64) -> u64 {
ms / timer.tick_ms
}
}

45
third_party/rust/mio-extras/test/mod.rs vendored Normal file
View File

@ -0,0 +1,45 @@
extern crate mio;
extern crate mio_extras;
use mio::event::Event;
use mio::{Events, Poll};
use std::time::Duration;
mod test_poll_channel;
mod test_timer;
pub fn expect_events(
poll: &Poll,
event_buffer: &mut Events,
poll_try_count: usize,
mut expected: Vec<Event>,
) {
const MS: u64 = 1_000;
for _ in 0..poll_try_count {
poll.poll(event_buffer, Some(Duration::from_millis(MS)))
.unwrap();
for event in event_buffer.iter() {
let pos_opt = match expected.iter().position(|exp_event| {
(event.token() == exp_event.token())
&& event.readiness().contains(exp_event.readiness())
}) {
Some(x) => Some(x),
None => None,
};
if let Some(pos) = pos_opt {
expected.remove(pos);
}
}
if expected.is_empty() {
break;
}
}
assert!(
expected.is_empty(),
"The following expected events were not found: {:?}",
expected
);
}

View File

@ -0,0 +1,338 @@
use expect_events;
use mio::event::Event;
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::channel;
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::time::Duration;
#[test]
pub fn test_poll_channel_edge() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let (tx, rx) = channel::channel();
poll.register(&rx, Token(123), Ready::readable(), PollOpt::edge())
.unwrap();
// Wait, but nothing should happen
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
// Push the value
tx.send("hello").unwrap();
// Polling will contain the event
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(1, num);
let event = events.iter().next().unwrap();
assert_eq!(event.token(), Token(123));
assert_eq!(event.readiness(), Ready::readable());
// Poll again and there should be no events
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
// Read the value
assert_eq!("hello", rx.try_recv().unwrap());
// Poll again, nothing
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
// Push a value
tx.send("goodbye").unwrap();
// Have an event
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(1, num);
let event = events.iter().next().unwrap();
assert_eq!(event.token(), Token(123));
assert_eq!(event.readiness(), Ready::readable());
// Read the value
rx.try_recv().unwrap();
// Drop the sender half
drop(tx);
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(1, num);
let event = events.iter().next().unwrap();
assert_eq!(event.token(), Token(123));
assert_eq!(event.readiness(), Ready::readable());
match rx.try_recv() {
Err(TryRecvError::Disconnected) => {}
no => panic!("unexpected value {:?}", no),
}
}
#[test]
pub fn test_poll_channel_oneshot() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let (tx, rx) = channel::channel();
poll.register(
&rx,
Token(123),
Ready::readable(),
PollOpt::edge() | PollOpt::oneshot(),
).unwrap();
// Wait, but nothing should happen
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
// Push the value
tx.send("hello").unwrap();
// Polling will contain the event
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(1, num);
let event = events.iter().next().unwrap();
assert_eq!(event.token(), Token(123));
assert_eq!(event.readiness(), Ready::readable());
// Poll again and there should be no events
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
// Read the value
assert_eq!("hello", rx.try_recv().unwrap());
// Poll again, nothing
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
// Push a value
tx.send("goodbye").unwrap();
// Poll again, nothing
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
// Reregistering will re-trigger the notification
for _ in 0..3 {
poll.reregister(
&rx,
Token(123),
Ready::readable(),
PollOpt::edge() | PollOpt::oneshot(),
).unwrap();
// Have an event
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(1, num);
let event = events.iter().next().unwrap();
assert_eq!(event.token(), Token(123));
assert_eq!(event.readiness(), Ready::readable());
}
// Get the value
assert_eq!("goodbye", rx.try_recv().unwrap());
poll.reregister(
&rx,
Token(123),
Ready::readable(),
PollOpt::edge() | PollOpt::oneshot(),
).unwrap();
// Have an event
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
poll.reregister(
&rx,
Token(123),
Ready::readable(),
PollOpt::edge() | PollOpt::oneshot(),
).unwrap();
// Have an event
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
}
#[test]
pub fn test_poll_channel_level() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let (tx, rx) = channel::channel();
poll.register(&rx, Token(123), Ready::readable(), PollOpt::level())
.unwrap();
// Wait, but nothing should happen
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
// Push the value
tx.send("hello").unwrap();
// Polling will contain the event
for i in 0..5 {
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert!(1 == num, "actually got {} on iteration {}", num, i);
let event = events.iter().next().unwrap();
assert_eq!(event.token(), Token(123));
assert_eq!(event.readiness(), Ready::readable());
}
// Read the value
assert_eq!("hello", rx.try_recv().unwrap());
// Wait, but nothing should happen
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
}
#[test]
pub fn test_poll_channel_writable() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let (tx, rx) = channel::channel();
poll.register(&rx, Token(123), Ready::writable(), PollOpt::edge())
.unwrap();
// Wait, but nothing should happen
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
// Push the value
tx.send("hello").unwrap();
// Wait, but nothing should happen
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
}
#[test]
pub fn test_dropping_receive_before_poll() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let (tx, rx) = channel::channel();
poll.register(&rx, Token(123), Ready::readable(), PollOpt::edge())
.unwrap();
// Push the value
tx.send("hello").unwrap();
// Drop the receive end
drop(rx);
// Wait, but nothing should happen
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(0, num);
}
#[test]
pub fn test_mixing_channel_with_socket() {
use mio::net::{TcpListener, TcpStream};
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let (tx, rx) = channel::channel();
// Create the listener
let l = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
// Register the listener with `Poll`
poll.register(&l, Token(0), Ready::readable(), PollOpt::edge())
.unwrap();
poll.register(&rx, Token(1), Ready::readable(), PollOpt::edge())
.unwrap();
// Push a value onto the channel
tx.send("hello").unwrap();
// Connect a TCP socket
let s1 = TcpStream::connect(&l.local_addr().unwrap()).unwrap();
// Register the socket
poll.register(&s1, Token(2), Ready::readable(), PollOpt::edge())
.unwrap();
// Sleep a bit to ensure it arrives at dest
thread::sleep(Duration::from_millis(250));
expect_events(
&poll,
&mut events,
2,
vec![
Event::new(Ready::empty(), Token(0)),
Event::new(Ready::empty(), Token(1)),
],
);
}
#[test]
pub fn test_sending_from_other_thread_while_polling() {
const ITERATIONS: usize = 20;
const THREADS: usize = 5;
// Make sure to run multiple times
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
for _ in 0..ITERATIONS {
let (tx, rx) = channel::channel();
poll.register(&rx, Token(0), Ready::readable(), PollOpt::edge())
.unwrap();
for _ in 0..THREADS {
let tx = tx.clone();
thread::spawn(move || {
thread::sleep(Duration::from_millis(50));
tx.send("ping").unwrap();
});
}
let mut recv = 0;
while recv < THREADS {
let num = poll.poll(&mut events, None).unwrap();
if num != 0 {
assert_eq!(1, num);
assert_eq!(events.iter().next().unwrap().token(), Token(0));
while let Ok(_) = rx.try_recv() {
recv += 1;
}
}
}
}
}

View File

@ -0,0 +1,304 @@
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::timer::{self, Timer};
use std::thread;
use std::time::Duration;
#[test]
fn test_basic_timer_without_poll() {
let mut timer = Timer::default();
// Set the timeout
timer.set_timeout(Duration::from_millis(200), "hello");
// Nothing when polled immediately
assert!(timer.poll().is_none());
// Wait for the timeout
thread::sleep(Duration::from_millis(250));
assert_eq!(Some("hello"), timer.poll());
assert!(timer.poll().is_none());
}
#[test]
fn test_basic_timer_with_poll_edge_set_timeout_after_register() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
.unwrap();
timer.set_timeout(Duration::from_millis(200), "hello");
let elapsed = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
let event = events.iter().next().unwrap();
assert_eq!(Token(0), event.token());
assert_eq!(Ready::readable(), event.readiness());
});
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
assert_eq!("hello", timer.poll().unwrap());
assert_eq!(None, timer.poll());
}
#[test]
fn test_basic_timer_with_poll_edge_set_timeout_before_register() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
timer.set_timeout(Duration::from_millis(200), "hello");
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
.unwrap();
let elapsed = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
let event = events.iter().next().unwrap();
assert_eq!(Token(0), event.token());
assert_eq!(Ready::readable(), event.readiness());
});
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
assert_eq!("hello", timer.poll().unwrap());
assert_eq!(None, timer.poll());
}
#[test]
fn test_setting_later_timeout_then_earlier_one() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
.unwrap();
timer.set_timeout(Duration::from_millis(600), "hello");
timer.set_timeout(Duration::from_millis(200), "world");
let elapsed = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
let event = events.iter().next().unwrap();
assert_eq!(Token(0), event.token());
assert_eq!(Ready::readable(), event.readiness());
});
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
assert_eq!("world", timer.poll().unwrap());
assert_eq!(None, timer.poll());
let elapsed = self::elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
let event = events.iter().next().unwrap();
assert_eq!(Token(0), event.token());
assert_eq!(Ready::readable(), event.readiness());
});
assert!(is_about(400, elapsed), "actual={:?}", elapsed);
assert_eq!("hello", timer.poll().unwrap());
assert_eq!(None, timer.poll());
}
#[test]
fn test_timer_with_looping_wheel() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = timer::Builder::default().num_slots(2).build();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
.unwrap();
const TOKENS: &[&str] = &["hello", "world", "some", "thing"];
for (i, msg) in TOKENS.iter().enumerate() {
timer.set_timeout(Duration::from_millis(500 * (i as u64 + 1)), msg);
}
for msg in TOKENS {
let elapsed = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
let event = events.iter().next().unwrap();
assert_eq!(Token(0), event.token());
assert_eq!(Ready::readable(), event.readiness());
});
assert!(
is_about(500, elapsed),
"actual={:?}; msg={:?}",
elapsed,
msg
);
assert_eq!(Some(msg), timer.poll());
assert_eq!(None, timer.poll());
}
}
#[test]
fn test_edge_without_polling() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
.unwrap();
timer.set_timeout(Duration::from_millis(400), "hello");
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
let event = events.iter().next().unwrap();
assert_eq!(Token(0), event.token());
assert_eq!(Ready::readable(), event.readiness());
});
assert!(is_about(400, ms), "actual={:?}", ms);
let ms = elapsed(|| {
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(num, 0);
});
assert!(is_about(300, ms), "actual={:?}", ms);
}
#[test]
fn test_level_triggered() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::level())
.unwrap();
timer.set_timeout(Duration::from_millis(400), "hello");
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
let event = events.iter().next().unwrap();
assert_eq!(Token(0), event.token());
assert_eq!(Ready::readable(), event.readiness());
});
assert!(is_about(400, ms), "actual={:?}", ms);
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
let event = events.iter().next().unwrap();
assert_eq!(Token(0), event.token());
assert_eq!(Ready::readable(), event.readiness());
});
assert!(is_about(0, ms), "actual={:?}", ms);
}
#[test]
fn test_edge_oneshot_triggered() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(
&timer,
Token(0),
Ready::readable(),
PollOpt::edge() | PollOpt::oneshot(),
).unwrap();
timer.set_timeout(Duration::from_millis(200), "hello");
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
});
assert!(is_about(200, ms), "actual={:?}", ms);
let ms = elapsed(|| {
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
.unwrap();
assert_eq!(num, 0);
});
assert!(is_about(300, ms), "actual={:?}", ms);
poll.reregister(
&timer,
Token(0),
Ready::readable(),
PollOpt::edge() | PollOpt::oneshot(),
).unwrap();
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
});
assert!(is_about(0, ms));
}
#[test]
fn test_cancel_timeout() {
use std::time::Instant;
let mut timer: Timer<u32> = Default::default();
let timeout = timer.set_timeout(Duration::from_millis(200), 1);
timer.cancel_timeout(&timeout);
let poll = Poll::new().unwrap();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
.unwrap();
let mut events = Events::with_capacity(16);
let now = Instant::now();
let dur = Duration::from_millis(500);
let mut i = 0;
while Instant::now() - now < dur {
if i > 10 {
panic!("iterated too many times");
}
i += 1;
let elapsed = Instant::now() - now;
poll.poll(&mut events, Some(dur - elapsed)).unwrap();
while let Some(_) = timer.poll() {
panic!("did not expect to receive timeout");
}
}
}
fn elapsed<F: FnMut()>(mut f: F) -> u64 {
use std::time::Instant;
let now = Instant::now();
f();
let elapsed = now.elapsed();
elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_nanos() / 1_000_000)
}
fn is_about(expect: u64, val: u64) -> bool {
const WINDOW: i64 = 200;
((expect as i64) - (val as i64)).abs() <= WINDOW
}

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,8 @@
# 0.6.16 (September 5, 2018)
* Add EPOLLPRI readiness to UnixReady on supported platforms (#867)
* Reduce spurious awaken calls (#875)
# 0.6.15 (July 3, 2018)
* Implement `Evented` for containers (#840).

View File

@ -12,12 +12,12 @@
[package]
name = "mio"
version = "0.6.15"
version = "0.6.16"
authors = ["Carl Lerche <me@carllerche.com>"]
exclude = [".gitignore", ".travis.yml", "deploy.sh"]
description = "Lightweight non-blocking IO"
homepage = "https://github.com/carllerche/mio"
documentation = "https://docs.rs/mio"
documentation = "https://docs.rs/mio/0.6.16/mio/"
readme = "README.md"
keywords = ["io", "async", "non-blocking"]
categories = ["asynchronous"]
@ -31,7 +31,7 @@ path = "test/mod.rs"
version = "0.1.1"
[dependencies.lazycell]
version = "0.6.0"
version = "1"
[dependencies.log]
version = "0.4"

View File

@ -1,202 +0,0 @@
// 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();
}

View File

@ -1,34 +0,0 @@
#!/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/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

View File

@ -718,6 +718,8 @@ impl Ready {
/// let ready = Ready::empty();
/// assert!(ready.is_empty());
/// ```
///
/// [`Poll`]: struct.Poll.html
#[inline]
pub fn is_empty(&self) -> bool {
*self == Ready::empty()

View File

@ -1,3 +1,7 @@
#![doc(html_root_url = "https://docs.rs/mio/0.6.16")]
#![deny(missing_docs, missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))]
//! A fast, low-level IO library for Rust focusing on non-blocking APIs, event
//! notification, and other useful utilities for building high performance IO
//! apps.
@ -90,11 +94,6 @@
//!
//! ```
#![doc(html_root_url = "https://docs.rs/mio/0.6.15")]
#![crate_name = "mio"]
#![deny(warnings, missing_docs, missing_debug_implementations)]
extern crate lazycell;
extern crate net2;
extern crate iovec;

View File

@ -695,8 +695,8 @@ impl Poll {
/// readiness. `Poll` will only return readiness events for operations
/// specified by this argument.
///
/// If a socket is registered with [`readable`] interest and the socket
/// becomes writable, no event will be returned from [`poll`].
/// If a socket is registered with readable interest and the socket becomes
/// writable, no event will be returned from [`poll`].
///
/// The readiness interest for an `Evented` handle can be changed at any
/// time by calling [`reregister`].
@ -860,7 +860,7 @@ impl Poll {
///
/// When an `Evented` handle is deregistered, the `Poll` instance will
/// no longer monitor it for readiness state changes. Unlike disabling
/// handles with [`oneshot`], deregistering clears up any internal resources
/// handles with oneshot, deregistering clears up any internal resources
/// needed to track the handle.
///
/// A handle can be passed back to `register` after it has been
@ -1157,6 +1157,8 @@ impl Poll {
if timeout == Some(Duration::from_millis(0)) {
// If blocking is not requested, then there is no need to prepare
// the queue for sleep
//
// The sleep_marker should be removed by readiness_queue.poll().
} else if self.readiness_queue.prepare_for_sleep() {
// The readiness queue is empty. The call to `prepare_for_sleep`
// inserts `sleep_marker` into the queue. This signals to any
@ -2116,6 +2118,13 @@ impl ReadinessQueue {
// loop where `Poll::poll` will keep dequeuing nodes it enqueues.
let mut until = ptr::null_mut();
if dst.len() == dst.capacity() {
// If `dst` is already full, the readiness queue won't be drained.
// This might result in `sleep_marker` staying in the queue and
// unecessary pipe writes occuring.
self.inner.clear_sleep_marker();
}
'outer:
while dst.len() < dst.capacity() {
// Dequeue a node. If the queue is in an inconsistent state, then
@ -2353,6 +2362,37 @@ impl ReadinessQueueInner {
}
}
fn clear_sleep_marker(&self) {
let end_marker = self.end_marker();
let sleep_marker = self.sleep_marker();
unsafe {
let tail = *self.tail_readiness.get();
if tail != self.sleep_marker() {
return;
}
// The empty markeer is *not* currently in the readiness queue
// (since the sleep markeris).
self.end_marker.next_readiness.store(ptr::null_mut(), Relaxed);
let actual = self.head_readiness.compare_and_swap(
sleep_marker, end_marker, AcqRel);
debug_assert!(actual != end_marker);
if actual != sleep_marker {
// The readiness queue is not empty, we cannot remove the sleep
// markeer
return;
}
// Update the tail pointer.
*self.tail_readiness.get() = end_marker;
}
}
/// Must only be called in `poll` or `drop`
unsafe fn dequeue_node(&self, until: *mut ReadinessNode) -> Dequeue {
// This is the 1024cores.net intrusive MPSC queue [1] "pop" function
@ -2362,6 +2402,10 @@ impl ReadinessQueueInner {
if tail == self.end_marker() || tail == self.sleep_marker() || tail == self.closed_marker() {
if next.is_null() {
// Make sure the sleep marker is removed (as we are no longer
// sleeping
self.clear_sleep_marker();
return Dequeue::Empty;
}

View File

@ -145,6 +145,11 @@ fn ioevent_to_epoll(interest: Ready, opts: PollOpt) -> u32 {
kind |= EPOLLRDHUP;
}
if UnixReady::from(interest).is_priority() {
kind |= EPOLLPRI;
}
if opts.is_edge() {
kind |= EPOLLET;
}
@ -206,10 +211,14 @@ impl Events {
let epoll = event.events as c_int;
let mut kind = Ready::empty();
if (epoll & EPOLLIN) != 0 || (epoll & EPOLLPRI) != 0 {
if (epoll & EPOLLIN) != 0 {
kind = kind | Ready::readable();
}
if (epoll & EPOLLPRI) != 0 {
kind = kind | Ready::readable() | UnixReady::priority();
}
if (epoll & EPOLLOUT) != 0 {
kind = kind | Ready::writable();
}

View File

@ -109,6 +109,11 @@ const LIO: usize = 0b100000;
#[cfg(not(any(target_os = "freebsd")))]
const LIO: usize = 0b000000;
#[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))]
const PRI: usize = ::libc::EPOLLPRI as usize;
// Export to support `Ready::all`
pub const READY_ALL: usize = ERROR | HUP | AIO | LIO;
@ -219,6 +224,28 @@ impl UnixReady {
UnixReady(ready_from_usize(LIO))
}
/// Returns a `Ready` representing priority (`EPOLLPRI`) readiness
///
/// See [`Poll`] for more documentation on polling.
///
/// # Examples
///
/// ```
/// use mio::unix::UnixReady;
///
/// let ready = UnixReady::priority();
///
/// assert!(ready.is_priority());
/// ```
///
/// [`Poll`]: struct.Poll.html
#[inline]
#[cfg(any(target_os = "linux",
target_os = "android", target_os = "solaris"))]
pub fn priority() -> UnixReady {
UnixReady(ready_from_usize(PRI))
}
/// Returns true if `Ready` contains AIO readiness
///
/// See [`Poll`] for more documentation on polling.
@ -323,6 +350,28 @@ impl UnixReady {
pub fn is_lio(&self) -> bool {
self.contains(ready_from_usize(LIO))
}
/// Returns true if `Ready` contains priority (`EPOLLPRI`) readiness
///
/// See [`Poll`] for more documentation on polling.
///
/// # Examples
///
/// ```
/// use mio::unix::UnixReady;
///
/// let ready = UnixReady::priority();
///
/// assert!(ready.is_priority());
/// ```
///
/// [`Poll`]: struct.Poll.html
#[inline]
#[cfg(any(target_os = "linux",
target_os = "android", target_os = "solaris"))]
pub fn is_priority(&self) -> bool {
self.contains(ready_from_usize(PRI))
}
}
impl From<Ready> for UnixReady {
@ -408,7 +457,11 @@ impl fmt::Debug for UnixReady {
(UnixReady::error(), "Error"),
(UnixReady::hup(), "Hup"),
#[allow(deprecated)]
(UnixReady::aio(), "Aio")];
(UnixReady::aio(), "Aio"),
#[cfg(any(target_os = "linux",
target_os = "android", target_os = "solaris"))]
(UnixReady::priority(), "Priority"),
];
for &(flag, msg) in &flags {
if self.contains(flag) {

View File

@ -45,9 +45,6 @@ mod test_tick;
// platforms that were supported from before the features were deprecated
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
#[cfg(feature = "with-deprecated")]
mod test_timer;
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
#[cfg(feature = "with-deprecated")]
mod test_battery;
#[cfg(any(target_os = "macos", target_os = "linux"))]

View File

@ -1,433 +0,0 @@
use {sleep_ms, TryRead, TryWrite};
use mio::*;
use mio::deprecated::{EventLoop, Handler};
use mio::timer::{Timer};
use mio::net::{TcpListener, TcpStream};
use bytes::{Buf, ByteBuf, SliceBuf};
use localhost;
use std::time::Duration;
use self::TestState::{Initial, AfterRead};
#[test]
fn test_basic_timer_without_poll() {
let mut timer = Timer::default();
// Set the timeout
timer.set_timeout(Duration::from_millis(200), "hello").unwrap();
// Nothing when polled immediately
assert!(timer.poll().is_none());
// Wait for the timeout
sleep_ms(200);
assert_eq!(Some("hello"), timer.poll());
assert!(timer.poll().is_none());
}
#[test]
fn test_basic_timer_with_poll_edge_set_timeout_after_register() {
let _ = ::env_logger::init();
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
timer.set_timeout(Duration::from_millis(200), "hello").unwrap();
let elapsed = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
assert_eq!(Token(0), events.get(0).unwrap().token());
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
});
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
assert_eq!("hello", timer.poll().unwrap());
assert_eq!(None, timer.poll());
}
#[test]
fn test_basic_timer_with_poll_edge_set_timeout_before_register() {
let _ = ::env_logger::init();
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
timer.set_timeout(Duration::from_millis(200), "hello").unwrap();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
let elapsed = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
assert_eq!(Token(0), events.get(0).unwrap().token());
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
});
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
assert_eq!("hello", timer.poll().unwrap());
assert_eq!(None, timer.poll());
}
#[test]
fn test_setting_later_timeout_then_earlier_one() {
let _ = ::env_logger::init();
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
timer.set_timeout(Duration::from_millis(600), "hello").unwrap();
timer.set_timeout(Duration::from_millis(200), "world").unwrap();
let elapsed = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
assert_eq!(Token(0), events.get(0).unwrap().token());
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
});
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
assert_eq!("world", timer.poll().unwrap());
assert_eq!(None, timer.poll());
let elapsed = self::elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
assert_eq!(Token(0), events.get(0).unwrap().token());
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
});
assert!(is_about(400, elapsed), "actual={:?}", elapsed);
assert_eq!("hello", timer.poll().unwrap());
assert_eq!(None, timer.poll());
}
#[test]
fn test_timer_with_looping_wheel() {
let _ = ::env_logger::init();
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = timer::Builder::default()
.num_slots(2)
.build();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
const TOKENS: &'static [ &'static str ] = &[ "hello", "world", "some", "thing" ];
for (i, msg) in TOKENS.iter().enumerate() {
timer.set_timeout(Duration::from_millis(500 * (i as u64 + 1)), msg).unwrap();
}
for msg in TOKENS {
let elapsed = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
assert_eq!(Token(0), events.get(0).unwrap().token());
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
});
assert!(is_about(500, elapsed), "actual={:?}; msg={:?}", elapsed, msg);
assert_eq!(Some(msg), timer.poll());
assert_eq!(None, timer.poll());
}
}
#[test]
fn test_edge_without_polling() {
let _ = ::env_logger::init();
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
timer.set_timeout(Duration::from_millis(400), "hello").unwrap();
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
assert_eq!(Token(0), events.get(0).unwrap().token());
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
});
assert!(is_about(400, ms), "actual={:?}", ms);
let ms = elapsed(|| {
let num = poll.poll(&mut events, Some(Duration::from_millis(300))).unwrap();
assert_eq!(num, 0);
});
assert!(is_about(300, ms), "actual={:?}", ms);
}
#[test]
fn test_level_triggered() {
let _ = ::env_logger::init();
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::level()).unwrap();
timer.set_timeout(Duration::from_millis(400), "hello").unwrap();
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
assert_eq!(Token(0), events.get(0).unwrap().token());
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
});
assert!(is_about(400, ms), "actual={:?}", ms);
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
assert_eq!(Token(0), events.get(0).unwrap().token());
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
});
assert!(is_about(0, ms), "actual={:?}", ms);
}
#[test]
fn test_edge_oneshot_triggered() {
let _ = ::env_logger::init();
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(1024);
let mut timer = Timer::default();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
timer.set_timeout(Duration::from_millis(200), "hello").unwrap();
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
});
assert!(is_about(200, ms), "actual={:?}", ms);
let ms = elapsed(|| {
let num = poll.poll(&mut events, Some(Duration::from_millis(300))).unwrap();
assert_eq!(num, 0);
});
assert!(is_about(300, ms), "actual={:?}", ms);
poll.reregister(&timer, Token(0), Ready::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
let ms = elapsed(|| {
let num = poll.poll(&mut events, None).unwrap();
assert_eq!(num, 1);
});
assert!(is_about(0, ms));
}
#[test]
fn test_cancel_timeout() {
use std::time::Instant;
let _ = ::env_logger::init();
let mut timer: Timer<u32> = Default::default();
let timeout = timer.set_timeout(Duration::from_millis(200), 1).unwrap();
timer.cancel_timeout(&timeout);
let poll = Poll::new().unwrap();
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
let mut events = Events::with_capacity(16);
let now = Instant::now();
let dur = Duration::from_millis(500);
let mut i = 0;
while Instant::now() - now < dur {
if i > 10 {
panic!("iterated too many times");
}
i += 1;
let elapsed = Instant::now() - now;
poll.poll(&mut events, Some(dur - elapsed)).unwrap();
while let Some(_) = timer.poll() {
panic!("did not expect to receive timeout");
}
}
}
fn elapsed<F: FnMut()>(mut f: F) -> u64 {
use std::time::Instant;
let now = Instant::now();
f();
let elapsed = now.elapsed();
elapsed.as_secs() * 1000 + (elapsed.subsec_nanos() / 1_000_000) as u64
}
fn is_about(expect: u64, val: u64) -> bool {
const WINDOW: i64 = 200;
((expect as i64) - (val as i64)).abs() <= WINDOW
}
/*
*
* ===== OLD TIMER =====
*
*/
const SERVER: Token = Token(0);
const CLIENT: Token = Token(1);
const CONN: Token = Token(2);
#[derive(Debug, PartialEq)]
enum TestState {
Initial,
AfterRead,
}
struct TestHandler {
srv: TcpListener,
cli: TcpStream,
state: TestState
}
impl TestHandler {
fn new(srv: TcpListener, cli: TcpStream) -> TestHandler {
TestHandler {
srv: srv,
cli: cli,
state: Initial
}
}
fn handle_read(&mut self, event_loop: &mut EventLoop<TestHandler>,
tok: Token, _events: Ready) {
match tok {
SERVER => {
debug!("server connection ready for accept");
let conn = self.srv.accept().unwrap().0;
event_loop.register(&conn, CONN, Ready::readable() | Ready::writable(),
PollOpt::edge()).unwrap();
event_loop.timeout(conn, Duration::from_millis(200)).unwrap();
event_loop.reregister(&self.srv, SERVER, Ready::readable(),
PollOpt::edge()).unwrap();
}
CLIENT => {
debug!("client readable");
match self.state {
Initial => self.state = AfterRead,
AfterRead => {}
}
let mut buf = ByteBuf::mut_with_capacity(2048);
match self.cli.try_read_buf(&mut buf) {
Ok(Some(0)) => return event_loop.shutdown(),
Ok(n) => {
debug!("read {:?} bytes", n);
assert!(b"zomg" == buf.flip().bytes());
}
Err(e) => {
debug!("client sock failed to read; err={:?}", e.kind());
}
}
event_loop.reregister(&self.cli, CLIENT,
Ready::readable() | Ready::hup(),
PollOpt::edge()).unwrap();
}
CONN => {}
_ => panic!("received unknown token {:?}", tok),
}
}
fn handle_write(&mut self, event_loop: &mut EventLoop<TestHandler>,
tok: Token, _: Ready) {
match tok {
SERVER => panic!("received writable for token 0"),
CLIENT => debug!("client connected"),
CONN => {}
_ => panic!("received unknown token {:?}", tok),
}
event_loop.reregister(&self.cli, CLIENT, Ready::readable(),
PollOpt::edge()).unwrap();
}
}
impl Handler for TestHandler {
type Timeout = TcpStream;
type Message = ();
fn ready(&mut self, event_loop: &mut EventLoop<TestHandler>, tok: Token, events: Ready) {
if events.is_readable() {
self.handle_read(event_loop, tok, events);
}
if events.is_writable() {
self.handle_write(event_loop, tok, events);
}
}
fn timeout(&mut self, _event_loop: &mut EventLoop<TestHandler>, mut sock: TcpStream) {
debug!("timeout handler : writing to socket");
sock.try_write_buf(&mut SliceBuf::wrap(b"zomg")).unwrap().unwrap();
}
}
#[test]
pub fn test_old_timer() {
let _ = ::env_logger::init();
debug!("Starting TEST_TIMER");
let mut event_loop = EventLoop::new().unwrap();
let addr = localhost();
let srv = TcpListener::bind(&addr).unwrap();
info!("listening for connections");
event_loop.register(&srv, SERVER, Ready::readable() | Ready::writable(), PollOpt::edge()).unwrap();
let sock = TcpStream::connect(&addr).unwrap();
// Connect to the server
event_loop.register(&sock, CLIENT, Ready::readable() | Ready::writable(), PollOpt::edge()).unwrap();
// Init the handler
let mut handler = TestHandler::new(srv, sock);
// Start the event loop
event_loop.run(&mut handler).unwrap();
assert!(handler.state == AfterRead, "actual={:?}", handler.state);
}

View File

@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"460c7dbfdf227b4c725f7da8131fd51a54d0355b3c5804c0d388c70d3c1c49ec","Cargo.toml":"7d29da51fe4bf73964b3b3dea0af88040514569e2d184c9e8eb2f1746d540fb7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"fb8071c3bc1013107b16ebcb303f31ef614e81440f2d58a46bfb9ff1e311b792","appveyor.yml":"8796156caf7041ef2a43f7a313df21ea639de3f2563b6181bba1096b1c489f1b","benches/bench.rs":"35c4ab609f2a5f5aab6c52c257415258dc0780621b492b5a82bb12d048cab6db","benches/distributions/exponential.rs":"99cb59c013a0b6bb390d34c5649b341fc3b88ea7df0caf2470bdda8798f9fe3d","benches/distributions/gamma.rs":"3533f311e4b55d743c5b01a7eb6529c94fd97726ef6702a6372f914f5f33666b","benches/distributions/mod.rs":"0028f1cb96f61152ed5b49a4fe91227d809ef6d19035592c36032a538af7f95e","benches/distributions/normal.rs":"4e10c18cb583ccb96301ea953c8e0aa9ee3b6662060271d1b8d19ca23364dc6b","benches/generators.rs":"aaa2f1dbfb399df8323d8a5796b92add6210cd5f0f1d916895ffdd81d60f812b","benches/misc.rs":"bd2f7c5a16f0fcb59022d5aeef66ed3c94e89ebf6c06667851dd23d0b1595504","src/distributions/exponential.rs":"103c8412c8a581b71835f1c00e40f6370e7702adf9d499243933a793d132d4e7","src/distributions/gamma.rs":"7a3f85c8daad4e56e334586ddb9fc9d83df3b0699738ed681a6c41e4ed455be9","src/distributions/mod.rs":"7943c4f83721bac816f831cca3b1574b6136932f7b4927aa6101130080ba62c5","src/distributions/normal.rs":"1562b43f80e4d5f83a8deb5af18de5a18dfeeeeda11fefc577da26672b14c949","src/distributions/range.rs":"a72a538d3ec4ed23f8d632aa55fd4793c464f24a5872d04ce8095ddd5db92115","src/distributions/ziggurat_tables.rs":"4eacf94fc352c91c455a6623de6a721e53842e1690f13a5662b6a79c7fbb73de","src/jitter.rs":"befd4b84bf753c107370b5b9498ad49611c220bdae2e4be9ee4398e9fa497042","src/lib.rs":"fbdc5f56ce1a52b15c85b0aa70a555c64be8f65d9f6f90fa0a3555d7862666b4","src/os.rs":"4860f165f68b7c978b0488c75d264cd9aaf54e7e4484036736ee5c4f5b6bd78d","src/prng/chacha.rs":"558007276f9c22933d39e5b8e853f4dd9533e823ed66df8dc1f23ad6925b1d51","src/prng/isaac.rs":"a8a2ee8b38d312663308e3bdf03376e342fd91330655f39144e5bba7392b2a8e","src/prng/isaac64.rs":"f28f7596ccab910db265b42671116abb9d2039fa8a421cbc75312bd0e7715d3a","src/prng/mod.rs":"c1a73450f49e819a20942a5b591f84a08ebb5ac33aa0f65b18ac1dc9a19a3084","src/prng/xorshift.rs":"606c308747293652c868b46dc3cad847d0c3717629c04ba75681c887c7634114","src/rand_impls.rs":"e1f27077fc13d5855bb66235f8ccfb216e116337eb38424d9c30c090e112215c","src/read.rs":"bd0eb508a6b659dc578d546fc2f231484aed80c73cfe8c475e0d65c8d699a769","src/reseeding.rs":"a97b86387b87ea1adc5262ddea480fe735c9c2a86762abaace29119022ac9f6e","src/seq.rs":"76dd58af0f580aed2721c393a5c036322186dc7cb3b4abed33436620c7c49288","utils/ziggurat_tables.py":"a9fc0a2fdae9b5c798c238788f94b720c156e13fd96f2356c409aa533191eb94"},"package":"8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"}

269
third_party/rust/rand-0.4.3/CHANGELOG.md vendored Normal file
View File

@ -0,0 +1,269 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [0.4.3] - 2018-08-16
### Fixed
- Use correct syscall number for PowerPC (#589)
## [0.4.2] - 2018-01-05
### Changed
- Use winapi on Windows
- Update for Fuchsia OS
- Remove dev-dependency on `log`
## [0.4.1] - 2017-12-17
### Added
- `no_std` support
## [0.4.0-pre.0] - 2017-12-11
### Added
- `JitterRng` added as a high-quality alternative entropy source using the
system timer
- new `seq` module with `sample_iter`, `sample_slice`, etc.
- WASM support via dummy implementations (fail at run-time)
- Additional benchmarks, covering generators and new seq code
### Changed
- `thread_rng` uses `JitterRng` if seeding from system time fails
(slower but more secure than previous method)
### Deprecated
- `sample` function deprecated (replaced by `sample_iter`)
## [0.3.18] - 2017-11-06
### Changed
- `thread_rng` is seeded from the system time if `OsRng` fails
- `weak_rng` now uses `thread_rng` internally
## [0.3.17] - 2017-10-07
### Changed
- Fuchsia: Magenta was renamed Zircon
## [0.3.16] - 2017-07-27
### Added
- Implement Debug for mote non-public types
- implement `Rand` for (i|u)i128
- Support for Fuchsia
### Changed
- Add inline attribute to SampleRange::construct_range.
This improves the benchmark for sample in 11% and for shuffle in 16%.
- Use `RtlGenRandom` instead of `CryptGenRandom`
## [0.3.15] - 2016-11-26
### Added
- Add `Rng` trait method `choose_mut`
- Redox support
### Changed
- Use `arc4rand` for `OsRng` on FreeBSD.
- Use `arc4random(3)` for `OsRng` on OpenBSD.
### Fixed
- Fix filling buffers 4 GiB or larger with `OsRng::fill_bytes` on Windows
## [0.3.14] - 2016-02-13
### Fixed
- Inline definitions from winapi/advapi32, wich decreases build times
## [0.3.13] - 2016-01-09
### Fixed
- Compatible with Rust 1.7.0-nightly (needed some extra type annotations)
## [0.3.12] - 2015-11-09
### Changed
- Replaced the methods in `next_f32` and `next_f64` with the technique described
Saito & Matsumoto at MCQMC'08. The new method should exhibit a slightly more
uniform distribution.
- Depend on libc 0.2
### Fixed
- Fix iterator protocol issue in `rand::sample`
## [0.3.11] - 2015-08-31
### Added
- Implement `Rand` for arrays with n <= 32
## [0.3.10] - 2015-08-17
### Added
- Support for NaCl platforms
### Changed
- Allow `Rng` to be `?Sized`, impl for `&mut R` and `Box<R>` where `R: ?Sized + Rng`
## [0.3.9] - 2015-06-18
### Changed
- Use `winapi` for Windows API things
### Fixed
- Fixed test on stable/nightly
- Fix `getrandom` syscall number for aarch64-unknown-linux-gnu
## [0.3.8] - 2015-04-23
### Changed
- `log` is a dev dependency
### Fixed
- Fix race condition of atomics in `is_getrandom_available`
## [0.3.7] - 2015-04-03
### Fixed
- Derive Copy/Clone changes
## [0.3.6] - 2015-04-02
### Changed
- Move to stable Rust!
## [0.3.5] - 2015-04-01
### Fixed
- Compatible with Rust master
## [0.3.4] - 2015-03-31
### Added
- Implement Clone for `Weighted`
### Fixed
- Compatible with Rust master
## [0.3.3] - 2015-03-26
### Fixed
- Fix compile on Windows
## [0.3.2] - 2015-03-26
## [0.3.1] - 2015-03-26
### Fixed
- Fix compile on Windows
## [0.3.0] - 2015-03-25
### Changed
- Update to use log version 0.3.x
## [0.2.1] - 2015-03-22
### Fixed
- Compatible with Rust master
- Fixed iOS compilation
## [0.2.0] - 2015-03-06
### Fixed
- Compatible with Rust master (move from `old_io` to `std::io`)
## [0.1.4] - 2015-03-04
### Fixed
- Compatible with Rust master (use wrapping ops)
## [0.1.3] - 2015-02-20
### Fixed
- Compatible with Rust master
### Removed
- Removed Copy inplementaions from RNGs
## [0.1.2] - 2015-02-03
### Added
- Imported functionality from `std::rand`, including:
- `StdRng`, `SeedableRng`, `TreadRng`, `weak_rng()`
- `ReaderRng`: A wrapper around any Reader to treat it as an RNG.
- Imported documentation from `std::rand`
- Imported tests from `std::rand`
## [0.1.1] - 2015-02-03
### Added
- Migrate to a cargo-compatible directory structure.
### Fixed
- Do not use entropy during `gen_weighted_bool(1)`
## [Rust 0.12.0] - 2014-10-09
### Added
- Impl Rand for tuples of arity 11 and 12
- Include ChaCha pseudorandom generator
- Add `next_f64` and `next_f32` to Rng
- Implement Clone for PRNGs
### Changed
- Rename `TaskRng` to `ThreadRng` and `task_rng` to `thread_rng` (since a
runtime is removed from Rust).
### Fixed
- Improved performance of ISAAC and ISAAC64 by 30% and 12 % respectively, by
informing the optimiser that indexing is never out-of-bounds.
### Removed
- Removed the Deprecated `choose_option`
## [Rust 0.11.0] - 2014-07-02
### Added
- document when to use `OSRng` in cryptographic context, and explain why we use `/dev/urandom` instead of `/dev/random`
- `Rng::gen_iter()` which will return an infinite stream of random values
- `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters
### Changed
- Now only depends on libcore! 2adf5363f88ffe06f6d2ea5c338d1b186d47f4a1
- Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()`
- Rename OSRng to OsRng
- The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
- The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
### Removed
- `Rng::gen_vec()` was removed. Previous behavior can be regained with
`rng.gen_iter().take(n).collect()`
- `Rng::gen_ascii_str()` was removed. Previous behavior can be regained with
`rng.gen_ascii_chars().take(n).collect()`
- {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
- Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported.
- Remove a slew of old deprecated functions
## [Rust 0.10] - 2014-04-03
### Changed
- replace `Rng.shuffle's` functionality with `.shuffle_mut`
- bubble up IO errors when creating an OSRng
### Fixed
- Use `fill()` instead of `read()`
- Rewrite OsRng in Rust for windows
## [0.10-pre] - 2014-03-02
### Added
- Seperate `rand` out of the standard library

39
third_party/rust/rand-0.4.3/Cargo.toml vendored Normal file
View File

@ -0,0 +1,39 @@
# 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 = "rand"
version = "0.4.3"
authors = ["The Rust Project Developers"]
description = "Random number generators and other randomness functionality.\n"
homepage = "https://github.com/rust-lang-nursery/rand"
documentation = "https://docs.rs/rand"
readme = "README.md"
keywords = ["random", "rng"]
categories = ["algorithms"]
license = "MIT/Apache-2.0"
repository = "https://github.com/rust-lang-nursery/rand"
[features]
alloc = []
default = ["std"]
i128_support = []
nightly = ["i128_support"]
std = ["libc"]
[target."cfg(target_os = \"fuchsia\")".dependencies.fuchsia-zircon]
version = "0.3.2"
[target."cfg(unix)".dependencies.libc]
version = "0.2"
optional = true
[target."cfg(windows)".dependencies.winapi]
version = "0.3"
features = ["minwindef", "ntsecapi", "profileapi", "winnt"]

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

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

@ -0,0 +1,25 @@
Copyright (c) 2014 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

139
third_party/rust/rand-0.4.3/README.md vendored Normal file
View File

@ -0,0 +1,139 @@
rand
====
A Rust library for random number generators and other randomness functionality.
[![Build Status](https://travis-ci.org/rust-lang-nursery/rand.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rand)
[![Build status](https://ci.appveyor.com/api/projects/status/rm5c9o33k3jhchbw?svg=true)](https://ci.appveyor.com/project/alexcrichton/rand)
[Documentation](https://docs.rs/rand)
## Usage
Add this to your `Cargo.toml`:
```toml
[dependencies]
rand = "0.4"
```
and this to your crate root:
```rust
extern crate rand;
```
### Versions
Version `0.4`was released in December 2017. It contains almost no breaking
changes since the `0.3` series, but nevertheless contains some significant
new code, including a new "external" entropy source (`JitterRng`) and `no_std`
support.
Version `0.5` is in development and contains significant performance
improvements for the ISAAC random number generators.
## Examples
There is built-in support for a random number generator (RNG) associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data.
```rust
let tuple = rand::random::<(f64, char)>();
println!("{:?}", tuple)
```
```rust
use rand::Rng;
let mut rng = rand::thread_rng();
if rng.gen() { // random bool
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
}
```
It is also possible to use other RNG types, which have a similar interface. The following uses the "ChaCha" algorithm instead of the default.
```rust
use rand::{Rng, ChaChaRng};
let mut rng = rand::ChaChaRng::new_unseeded();
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
```
## Features
By default, `rand` is built with all stable features available. The following
optional features are available:
- `i128_support` enables support for generating `u128` and `i128` values
- `nightly` enables all unstable features (`i128_support`)
- `std` enabled by default; by setting "default-features = false" `no_std`
mode is activated; this removes features depending on `std` functionality:
- `OsRng` is entirely unavailable
- `JitterRng` code is still present, but a nanosecond timer must be
provided via `JitterRng::new_with_timer`
- Since no external entropy is available, it is not possible to create
generators with fresh seeds (user must provide entropy)
- `thread_rng`, `weak_rng` and `random` are all disabled
- exponential, normal and gamma type distributions are unavailable
since `exp` and `log` functions are not provided in `core`
- any code requiring `Vec` or `Box`
- `alloc` can be used instead of `std` to provide `Vec` and `Box`
## Testing
Unfortunately, `cargo test` does not test everything. The following tests are
recommended:
```
# Basic tests for rand and sub-crates
cargo test --all
# Test no_std support (build only since nearly all tests require std)
cargo build --all --no-default-features
# Test 128-bit support (requires nightly)
cargo test --all --features nightly
# Benchmarks (requires nightly)
cargo bench
# or just to test the benchmark code:
cargo test --benches
```
# `derive(Rand)`
You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]`
directive. To use this first add this to your Cargo.toml:
```toml
rand = "0.4"
rand_derive = "0.3"
```
Next in your crate:
```rust
extern crate rand;
#[macro_use]
extern crate rand_derive;
#[derive(Rand, Debug)]
struct MyStruct {
a: i32,
b: u32,
}
fn main() {
println!("{:?}", rand::random::<MyStruct>());
}
```
# License
`rand` is primarily distributed under the terms of both the MIT
license and the Apache License (Version 2.0).
See LICENSE-APACHE, and LICENSE-MIT for details.

View File

@ -0,0 +1,133 @@
#![feature(test)]
extern crate test;
extern crate rand;
const RAND_BENCH_N: u64 = 1000;
const BYTES_LEN: usize = 1024;
use std::mem::size_of;
use test::{black_box, Bencher};
use rand::{Rng, StdRng, OsRng, JitterRng};
use rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng};
macro_rules! gen_bytes {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng: $gen = OsRng::new().unwrap().gen();
let mut buf = [0u8; BYTES_LEN];
b.iter(|| {
for _ in 0..RAND_BENCH_N {
rng.fill_bytes(&mut buf);
black_box(buf);
}
});
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
}
}
}
macro_rules! gen_bytes_new {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = $gen::new().unwrap();
let mut buf = [0u8; BYTES_LEN];
b.iter(|| {
for _ in 0..RAND_BENCH_N {
rng.fill_bytes(&mut buf);
black_box(buf);
}
});
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
}
}
}
gen_bytes!(gen_bytes_xorshift, XorShiftRng);
gen_bytes!(gen_bytes_isaac, IsaacRng);
gen_bytes!(gen_bytes_isaac64, Isaac64Rng);
gen_bytes!(gen_bytes_chacha, ChaChaRng);
gen_bytes_new!(gen_bytes_std, StdRng);
gen_bytes_new!(gen_bytes_os, OsRng);
macro_rules! gen_uint {
($fnn:ident, $ty:ty, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng: $gen = OsRng::new().unwrap().gen();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<$ty>());
}
});
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
}
}
}
macro_rules! gen_uint_new {
($fnn:ident, $ty:ty, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = $gen::new().unwrap();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<$ty>());
}
});
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
}
}
}
gen_uint!(gen_u32_xorshift, u32, XorShiftRng);
gen_uint!(gen_u32_isaac, u32, IsaacRng);
gen_uint!(gen_u32_isaac64, u32, Isaac64Rng);
gen_uint!(gen_u32_chacha, u32, ChaChaRng);
gen_uint_new!(gen_u32_std, u32, StdRng);
gen_uint_new!(gen_u32_os, u32, OsRng);
gen_uint!(gen_u64_xorshift, u64, XorShiftRng);
gen_uint!(gen_u64_isaac, u64, IsaacRng);
gen_uint!(gen_u64_isaac64, u64, Isaac64Rng);
gen_uint!(gen_u64_chacha, u64, ChaChaRng);
gen_uint_new!(gen_u64_std, u64, StdRng);
gen_uint_new!(gen_u64_os, u64, OsRng);
#[bench]
fn gen_u64_jitter(b: &mut Bencher) {
let mut rng = JitterRng::new().unwrap();
b.iter(|| {
black_box(rng.gen::<u64>());
});
b.bytes = size_of::<u64>() as u64;
}
macro_rules! init_gen {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng: XorShiftRng = OsRng::new().unwrap().gen();
b.iter(|| {
let r2: $gen = rng.gen();
black_box(r2);
});
}
}
}
init_gen!(init_xorshift, XorShiftRng);
init_gen!(init_isaac, IsaacRng);
init_gen!(init_isaac64, Isaac64Rng);
init_gen!(init_chacha, ChaChaRng);
#[bench]
fn init_jitter(b: &mut Bencher) {
b.iter(|| {
black_box(JitterRng::new().unwrap());
});
}

View File

@ -0,0 +1,62 @@
#![feature(test)]
extern crate test;
extern crate rand;
use test::{black_box, Bencher};
use rand::{Rng, weak_rng};
use rand::seq::*;
#[bench]
fn misc_shuffle_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &mut [usize] = &mut [1; 100];
b.iter(|| {
rng.shuffle(x);
black_box(&x);
})
}
#[bench]
fn misc_sample_iter_10_of_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &[usize] = &[1; 100];
b.iter(|| {
black_box(sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e));
})
}
#[bench]
fn misc_sample_slice_10_of_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &[usize] = &[1; 100];
b.iter(|| {
black_box(sample_slice(&mut rng, x, 10));
})
}
#[bench]
fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &[usize] = &[1; 100];
b.iter(|| {
black_box(sample_slice_ref(&mut rng, x, 10));
})
}
macro_rules! sample_indices {
($name:ident, $amount:expr, $length:expr) => {
#[bench]
fn $name(b: &mut Bencher) {
let mut rng = weak_rng();
b.iter(|| {
black_box(sample_indices(&mut rng, $length, $amount));
})
}
}
}
sample_indices!(misc_sample_indices_10_of_1k, 10, 1000);
sample_indices!(misc_sample_indices_50_of_1k, 50, 1000);
sample_indices!(misc_sample_indices_100_of_1k, 100, 1000);

View File

@ -0,0 +1,124 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The exponential distribution.
use {Rng, Rand};
use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
/// A wrapper around an `f64` to generate Exp(1) random numbers.
///
/// See `Exp` for the general exponential distribution.
///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
/// exact description in the paper was adjusted to use tables for the
/// exponential distribution rather than normal.
///
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
///
/// # Example
///
/// ```rust
/// use rand::distributions::exponential::Exp1;
///
/// let Exp1(x) = rand::random();
/// println!("{}", x);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Exp1(pub f64);
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
impl Rand for Exp1 {
#[inline]
fn rand<R:Rng>(rng: &mut R) -> Exp1 {
#[inline]
fn pdf(x: f64) -> f64 {
(-x).exp()
}
#[inline]
fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
}
Exp1(ziggurat(rng, false,
&ziggurat_tables::ZIG_EXP_X,
&ziggurat_tables::ZIG_EXP_F,
pdf, zero_case))
}
}
/// The exponential distribution `Exp(lambda)`.
///
/// This distribution has density function: `f(x) = lambda *
/// exp(-lambda * x)` for `x > 0`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{Exp, IndependentSample};
///
/// let exp = Exp::new(2.0);
/// let v = exp.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a Exp(2) distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Exp {
/// `lambda` stored as `1/lambda`, since this is what we scale by.
lambda_inverse: f64
}
impl Exp {
/// Construct a new `Exp` with the given shape parameter
/// `lambda`. Panics if `lambda <= 0`.
#[inline]
pub fn new(lambda: f64) -> Exp {
assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
Exp { lambda_inverse: 1.0 / lambda }
}
}
impl Sample<f64> for Exp {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Exp {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
let Exp1(n) = rng.gen::<Exp1>();
n * self.lambda_inverse
}
}
#[cfg(test)]
mod test {
use distributions::{Sample, IndependentSample};
use super::Exp;
#[test]
fn test_exp() {
let mut exp = Exp::new(10.0);
let mut rng = ::test::rng();
for _ in 0..1000 {
assert!(exp.sample(&mut rng) >= 0.0);
assert!(exp.ind_sample(&mut rng) >= 0.0);
}
}
#[test]
#[should_panic]
fn test_exp_invalid_lambda_zero() {
Exp::new(0.0);
}
#[test]
#[should_panic]
fn test_exp_invalid_lambda_neg() {
Exp::new(-10.0);
}
}

View File

@ -0,0 +1,386 @@
// Copyright 2013 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.
//
// ignore-lexer-test FIXME #15679
//! The Gamma and derived distributions.
use self::GammaRepr::*;
use self::ChiSquaredRepr::*;
use {Rng, Open01};
use super::normal::StandardNormal;
use super::{IndependentSample, Sample, Exp};
/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
/// The density function of this distribution is
///
/// ```text
/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
/// ```
///
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
/// scale and both `k` and `θ` are strictly positive.
///
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
/// falling back to directly sampling from an Exponential for `shape
/// == 1`, and using the boosting technique described in [1] for
/// `shape < 1`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{IndependentSample, Gamma};
///
/// let gamma = Gamma::new(2.0, 5.0);
/// let v = gamma.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
/// (September 2000),
/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
#[derive(Clone, Copy, Debug)]
pub struct Gamma {
repr: GammaRepr,
}
#[derive(Clone, Copy, Debug)]
enum GammaRepr {
Large(GammaLargeShape),
One(Exp),
Small(GammaSmallShape)
}
// These two helpers could be made public, but saving the
// match-on-Gamma-enum branch from using them directly (e.g. if one
// knows that the shape is always > 1) doesn't appear to be much
// faster.
/// Gamma distribution where the shape parameter is less than 1.
///
/// Note, samples from this require a compulsory floating-point `pow`
/// call, which makes it significantly slower than sampling from a
/// gamma distribution where the shape parameter is greater than or
/// equal to 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
#[derive(Clone, Copy, Debug)]
struct GammaSmallShape {
inv_shape: f64,
large_shape: GammaLargeShape
}
/// Gamma distribution where the shape parameter is larger than 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
#[derive(Clone, Copy, Debug)]
struct GammaLargeShape {
scale: f64,
c: f64,
d: f64
}
impl Gamma {
/// Construct an object representing the `Gamma(shape, scale)`
/// distribution.
///
/// Panics if `shape <= 0` or `scale <= 0`.
#[inline]
pub fn new(shape: f64, scale: f64) -> Gamma {
assert!(shape > 0.0, "Gamma::new called with shape <= 0");
assert!(scale > 0.0, "Gamma::new called with scale <= 0");
let repr = if shape == 1.0 {
One(Exp::new(1.0 / scale))
} else if shape < 1.0 {
Small(GammaSmallShape::new_raw(shape, scale))
} else {
Large(GammaLargeShape::new_raw(shape, scale))
};
Gamma { repr: repr }
}
}
impl GammaSmallShape {
fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
GammaSmallShape {
inv_shape: 1. / shape,
large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
}
}
}
impl GammaLargeShape {
fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
let d = shape - 1. / 3.;
GammaLargeShape {
scale: scale,
c: 1. / (9. * d).sqrt(),
d: d
}
}
}
impl Sample<f64> for Gamma {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaSmallShape {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaLargeShape {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Gamma {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
match self.repr {
Small(ref g) => g.ind_sample(rng),
One(ref g) => g.ind_sample(rng),
Large(ref g) => g.ind_sample(rng),
}
}
}
impl IndependentSample<f64> for GammaSmallShape {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
let Open01(u) = rng.gen::<Open01<f64>>();
self.large_shape.ind_sample(rng) * u.powf(self.inv_shape)
}
}
impl IndependentSample<f64> for GammaLargeShape {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
loop {
let StandardNormal(x) = rng.gen::<StandardNormal>();
let v_cbrt = 1.0 + self.c * x;
if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
continue
}
let v = v_cbrt * v_cbrt * v_cbrt;
let Open01(u) = rng.gen::<Open01<f64>>();
let x_sqr = x * x;
if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) {
return self.d * v * self.scale
}
}
}
}
/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
/// freedom.
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
/// `k`, this uses the equivalent characterisation
/// `χ²(k) = Gamma(k/2, 2)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{ChiSquared, IndependentSample};
///
/// let chi = ChiSquared::new(11.0);
/// let v = chi.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a χ²(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct ChiSquared {
repr: ChiSquaredRepr,
}
#[derive(Clone, Copy, Debug)]
enum ChiSquaredRepr {
// k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
// e.g. when alpha = 1/2 as it would be for this case, so special-
// casing and using the definition of N(0,1)^2 is faster.
DoFExactlyOne,
DoFAnythingElse(Gamma),
}
impl ChiSquared {
/// Create a new chi-squared distribution with degrees-of-freedom
/// `k`. Panics if `k < 0`.
pub fn new(k: f64) -> ChiSquared {
let repr = if k == 1.0 {
DoFExactlyOne
} else {
assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
};
ChiSquared { repr: repr }
}
}
impl Sample<f64> for ChiSquared {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for ChiSquared {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
match self.repr {
DoFExactlyOne => {
// k == 1 => N(0,1)^2
let StandardNormal(norm) = rng.gen::<StandardNormal>();
norm * norm
}
DoFAnythingElse(ref g) => g.ind_sample(rng)
}
}
}
/// The Fisher F distribution `F(m, n)`.
///
/// This distribution is equivalent to the ratio of two normalised
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
/// (χ²(n)/n)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{FisherF, IndependentSample};
///
/// let f = FisherF::new(2.0, 32.0);
/// let v = f.ind_sample(&mut rand::thread_rng());
/// println!("{} is from an F(2, 32) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct FisherF {
numer: ChiSquared,
denom: ChiSquared,
// denom_dof / numer_dof so that this can just be a straight
// multiplication, rather than a division.
dof_ratio: f64,
}
impl FisherF {
/// Create a new `FisherF` distribution, with the given
/// parameter. Panics if either `m` or `n` are not positive.
pub fn new(m: f64, n: f64) -> FisherF {
assert!(m > 0.0, "FisherF::new called with `m < 0`");
assert!(n > 0.0, "FisherF::new called with `n < 0`");
FisherF {
numer: ChiSquared::new(m),
denom: ChiSquared::new(n),
dof_ratio: n / m
}
}
}
impl Sample<f64> for FisherF {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for FisherF {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
}
}
/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
/// freedom.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{StudentT, IndependentSample};
///
/// let t = StudentT::new(11.0);
/// let v = t.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a t(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct StudentT {
chi: ChiSquared,
dof: f64
}
impl StudentT {
/// Create a new Student t distribution with `n` degrees of
/// freedom. Panics if `n <= 0`.
pub fn new(n: f64) -> StudentT {
assert!(n > 0.0, "StudentT::new called with `n <= 0`");
StudentT {
chi: ChiSquared::new(n),
dof: n
}
}
}
impl Sample<f64> for StudentT {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for StudentT {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
let StandardNormal(norm) = rng.gen::<StandardNormal>();
norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
}
}
#[cfg(test)]
mod test {
use distributions::{Sample, IndependentSample};
use super::{ChiSquared, StudentT, FisherF};
#[test]
fn test_chi_squared_one() {
let mut chi = ChiSquared::new(1.0);
let mut rng = ::test::rng();
for _ in 0..1000 {
chi.sample(&mut rng);
chi.ind_sample(&mut rng);
}
}
#[test]
fn test_chi_squared_small() {
let mut chi = ChiSquared::new(0.5);
let mut rng = ::test::rng();
for _ in 0..1000 {
chi.sample(&mut rng);
chi.ind_sample(&mut rng);
}
}
#[test]
fn test_chi_squared_large() {
let mut chi = ChiSquared::new(30.0);
let mut rng = ::test::rng();
for _ in 0..1000 {
chi.sample(&mut rng);
chi.ind_sample(&mut rng);
}
}
#[test]
#[should_panic]
fn test_chi_squared_invalid_dof() {
ChiSquared::new(-1.0);
}
#[test]
fn test_f() {
let mut f = FisherF::new(2.0, 32.0);
let mut rng = ::test::rng();
for _ in 0..1000 {
f.sample(&mut rng);
f.ind_sample(&mut rng);
}
}
#[test]
fn test_t() {
let mut t = StudentT::new(11.0);
let mut rng = ::test::rng();
for _ in 0..1000 {
t.sample(&mut rng);
t.ind_sample(&mut rng);
}
}
}

View File

@ -0,0 +1,409 @@
// Copyright 2013 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.
//! Sampling from random distributions.
//!
//! This is a generalization of `Rand` to allow parameters to control the
//! exact properties of the generated values, e.g. the mean and standard
//! deviation of a normal distribution. The `Sample` trait is the most
//! general, and allows for generating values that change some state
//! internally. The `IndependentSample` trait is for generating values
//! that do not need to record state.
use core::marker;
use {Rng, Rand};
pub use self::range::Range;
#[cfg(feature="std")]
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
#[cfg(feature="std")]
pub use self::normal::{Normal, LogNormal};
#[cfg(feature="std")]
pub use self::exponential::Exp;
pub mod range;
#[cfg(feature="std")]
pub mod gamma;
#[cfg(feature="std")]
pub mod normal;
#[cfg(feature="std")]
pub mod exponential;
#[cfg(feature="std")]
mod ziggurat_tables;
/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
/// Generate a random value of `Support`, using `rng` as the
/// source of randomness.
fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}
/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recorded, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// FIXME maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
/// Generate a random value.
fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}
/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
#[derive(Debug)]
pub struct RandSample<Sup> {
_marker: marker::PhantomData<fn() -> Sup>,
}
impl<Sup> Copy for RandSample<Sup> {}
impl<Sup> Clone for RandSample<Sup> {
fn clone(&self) -> Self { *self }
}
impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}
impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
rng.gen()
}
}
impl<Sup> RandSample<Sup> {
pub fn new() -> RandSample<Sup> {
RandSample { _marker: marker::PhantomData }
}
}
/// A value with a particular weight for use with `WeightedChoice`.
#[derive(Copy, Clone, Debug)]
pub struct Weighted<T> {
/// The numerical weight of this item
pub weight: u32,
/// The actual item which is being weighted
pub item: T,
}
/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
/// is to be chosen: higher weight is more likely.
///
/// The `Clone` restriction is a limitation of the `Sample` and
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
/// all `T`, as is `u32`, so one can store references or indices into
/// another vector.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{Weighted, WeightedChoice, IndependentSample};
///
/// let mut items = vec!(Weighted { weight: 2, item: 'a' },
/// Weighted { weight: 4, item: 'b' },
/// Weighted { weight: 1, item: 'c' });
/// let wc = WeightedChoice::new(&mut items);
/// let mut rng = rand::thread_rng();
/// for _ in 0..16 {
/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
/// println!("{}", wc.ind_sample(&mut rng));
/// }
/// ```
#[derive(Debug)]
pub struct WeightedChoice<'a, T:'a> {
items: &'a mut [Weighted<T>],
weight_range: Range<u32>
}
impl<'a, T: Clone> WeightedChoice<'a, T> {
/// Create a new `WeightedChoice`.
///
/// Panics if:
///
/// - `items` is empty
/// - the total weight is 0
/// - the total weight is larger than a `u32` can contain.
pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
// strictly speaking, this is subsumed by the total weight == 0 case
assert!(!items.is_empty(), "WeightedChoice::new called with no items");
let mut running_total: u32 = 0;
// we convert the list from individual weights to cumulative
// weights so we can binary search. This *could* drop elements
// with weight == 0 as an optimisation.
for item in items.iter_mut() {
running_total = match running_total.checked_add(item.weight) {
Some(n) => n,
None => panic!("WeightedChoice::new called with a total weight \
larger than a u32 can contain")
};
item.weight = running_total;
}
assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");
WeightedChoice {
items: items,
// we're likely to be generating numbers in this range
// relatively often, so might as well cache it
weight_range: Range::new(0, running_total)
}
}
}
impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
}
impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
// we want to find the first element that has cumulative
// weight > sample_weight, which we do by binary since the
// cumulative weights of self.items are sorted.
// choose a weight in [0, total_weight)
let sample_weight = self.weight_range.ind_sample(rng);
// short circuit when it's the first item
if sample_weight < self.items[0].weight {
return self.items[0].item.clone();
}
let mut idx = 0;
let mut modifier = self.items.len();
// now we know that every possibility has an element to the
// left, so we can just search for the last element that has
// cumulative weight <= sample_weight, then the next one will
// be "it". (Note that this greatest element will never be the
// last element of the vector, since sample_weight is chosen
// in [0, total_weight) and the cumulative weight of the last
// one is exactly the total weight.)
while modifier > 1 {
let i = idx + modifier / 2;
if self.items[i].weight <= sample_weight {
// we're small, so look to the right, but allow this
// exact element still.
idx = i;
// we need the `/ 2` to round up otherwise we'll drop
// the trailing elements when `modifier` is odd.
modifier += 1;
} else {
// otherwise we're too big, so go left. (i.e. do
// nothing)
}
modifier /= 2;
}
return self.items[idx + 1].item.clone();
}
}
/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
///
/// * `rng`: source of randomness
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
/// * `X`: the $x_i$ abscissae.
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
/// * `pdf`: the probability density function
/// * `zero_case`: manual sampling from the tail when we chose the
/// bottom box (i.e. i == 0)
// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[cfg(feature="std")]
#[inline(always)]
fn ziggurat<R: Rng, P, Z>(
rng: &mut R,
symmetric: bool,
x_tab: ziggurat_tables::ZigTable,
f_tab: ziggurat_tables::ZigTable,
mut pdf: P,
mut zero_case: Z)
-> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
const SCALE: f64 = (1u64 << 53) as f64;
loop {
// reimplement the f64 generation as an optimisation suggested
// by the Doornik paper: we have a lot of precision-space
// (i.e. there are 11 bits of the 64 of a u64 to use after
// creating a f64), so we might as well reuse some to save
// generating a whole extra random number. (Seems to be 15%
// faster.)
//
// This unfortunately misses out on the benefits of direct
// floating point generation if an RNG like dSMFT is
// used. (That is, such RNGs create floats directly, highly
// efficiently and overload next_f32/f64, so by not calling it
// this may be slower than it would be otherwise.)
// FIXME: investigate/optimise for the above.
let bits: u64 = rng.gen();
let i = (bits & 0xff) as usize;
let f = (bits >> 11) as f64 / SCALE;
// u is either U(-1, 1) or U(0, 1) depending on if this is a
// symmetric distribution or not.
let u = if symmetric {2.0 * f - 1.0} else {f};
let x = u * x_tab[i];
let test_x = if symmetric { x.abs() } else {x};
// algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
if test_x < x_tab[i + 1] {
return x;
}
if i == 0 {
return zero_case(rng, u);
}
// algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
return x;
}
}
}
#[cfg(test)]
mod tests {
use {Rng, Rand};
use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};
#[derive(PartialEq, Debug)]
struct ConstRand(usize);
impl Rand for ConstRand {
fn rand<R: Rng>(_: &mut R) -> ConstRand {
ConstRand(0)
}
}
// 0, 1, 2, 3, ...
struct CountingRng { i: u32 }
impl Rng for CountingRng {
fn next_u32(&mut self) -> u32 {
self.i += 1;
self.i - 1
}
fn next_u64(&mut self) -> u64 {
self.next_u32() as u64
}
}
#[test]
fn test_rand_sample() {
let mut rand_sample = RandSample::<ConstRand>::new();
assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
}
#[test]
fn test_weighted_choice() {
// this makes assumptions about the internal implementation of
// WeightedChoice, specifically: it doesn't reorder the items,
// it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
// 1, internally; modulo a modulo operation).
macro_rules! t {
($items:expr, $expected:expr) => {{
let mut items = $items;
let wc = WeightedChoice::new(&mut items);
let expected = $expected;
let mut rng = CountingRng { i: 0 };
for &val in expected.iter() {
assert_eq!(wc.ind_sample(&mut rng), val)
}
}}
}
t!(vec!(Weighted { weight: 1, item: 10}), [10]);
// skip some
t!(vec!(Weighted { weight: 0, item: 20},
Weighted { weight: 2, item: 21},
Weighted { weight: 0, item: 22},
Weighted { weight: 1, item: 23}),
[21,21, 23]);
// different weights
t!(vec!(Weighted { weight: 4, item: 30},
Weighted { weight: 3, item: 31}),
[30,30,30,30, 31,31,31]);
// check that we're binary searching
// correctly with some vectors of odd
// length.
t!(vec!(Weighted { weight: 1, item: 40},
Weighted { weight: 1, item: 41},
Weighted { weight: 1, item: 42},
Weighted { weight: 1, item: 43},
Weighted { weight: 1, item: 44}),
[40, 41, 42, 43, 44]);
t!(vec!(Weighted { weight: 1, item: 50},
Weighted { weight: 1, item: 51},
Weighted { weight: 1, item: 52},
Weighted { weight: 1, item: 53},
Weighted { weight: 1, item: 54},
Weighted { weight: 1, item: 55},
Weighted { weight: 1, item: 56}),
[50, 51, 52, 53, 54, 55, 56]);
}
#[test]
fn test_weighted_clone_initialization() {
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
let clone = initial.clone();
assert_eq!(initial.weight, clone.weight);
assert_eq!(initial.item, clone.item);
}
#[test] #[should_panic]
fn test_weighted_clone_change_weight() {
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
let mut clone = initial.clone();
clone.weight = 5;
assert_eq!(initial.weight, clone.weight);
}
#[test] #[should_panic]
fn test_weighted_clone_change_item() {
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
let mut clone = initial.clone();
clone.item = 5;
assert_eq!(initial.item, clone.item);
}
#[test] #[should_panic]
fn test_weighted_choice_no_items() {
WeightedChoice::<isize>::new(&mut []);
}
#[test] #[should_panic]
fn test_weighted_choice_zero_weight() {
WeightedChoice::new(&mut [Weighted { weight: 0, item: 0},
Weighted { weight: 0, item: 1}]);
}
#[test] #[should_panic]
fn test_weighted_choice_weight_overflows() {
let x = ::std::u32::MAX / 2; // x + x + 2 is the overflow
WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
Weighted { weight: 1, item: 1 },
Weighted { weight: x, item: 2 },
Weighted { weight: 1, item: 3 }]);
}
}

View File

@ -0,0 +1,201 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The normal and derived distributions.
use {Rng, Rand, Open01};
use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
/// A wrapper around an `f64` to generate N(0, 1) random numbers
/// (a.k.a. a standard normal, or Gaussian).
///
/// See `Normal` for the general normal distribution.
///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method.
///
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
///
/// # Example
///
/// ```rust
/// use rand::distributions::normal::StandardNormal;
///
/// let StandardNormal(x) = rand::random();
/// println!("{}", x);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct StandardNormal(pub f64);
impl Rand for StandardNormal {
fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
#[inline]
fn pdf(x: f64) -> f64 {
(-x*x/2.0).exp()
}
#[inline]
fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
// compute a random number in the tail by hand
// strange initial conditions, because the loop is not
// do-while, so the condition should be true on the first
// run, they get overwritten anyway (0 < 1, so these are
// good).
let mut x = 1.0f64;
let mut y = 0.0f64;
while -2.0 * y < x * x {
let Open01(x_) = rng.gen::<Open01<f64>>();
let Open01(y_) = rng.gen::<Open01<f64>>();
x = x_.ln() / ziggurat_tables::ZIG_NORM_R;
y = y_.ln();
}
if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
}
StandardNormal(ziggurat(
rng,
true, // this is symmetric
&ziggurat_tables::ZIG_NORM_X,
&ziggurat_tables::ZIG_NORM_F,
pdf, zero_case))
}
}
/// The normal distribution `N(mean, std_dev**2)`.
///
/// This uses the ZIGNOR variant of the Ziggurat method, see
/// `StandardNormal` for more details.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{Normal, IndependentSample};
///
/// // mean 2, standard deviation 3
/// let normal = Normal::new(2.0, 3.0);
/// let v = normal.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a N(2, 9) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Normal {
mean: f64,
std_dev: f64,
}
impl Normal {
/// Construct a new `Normal` distribution with the given mean and
/// standard deviation.
///
/// # Panics
///
/// Panics if `std_dev < 0`.
#[inline]
pub fn new(mean: f64, std_dev: f64) -> Normal {
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
Normal {
mean: mean,
std_dev: std_dev
}
}
}
impl Sample<f64> for Normal {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Normal {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
let StandardNormal(n) = rng.gen::<StandardNormal>();
self.mean + self.std_dev * n
}
}
/// The log-normal distribution `ln N(mean, std_dev**2)`.
///
/// If `X` is log-normal distributed, then `ln(X)` is `N(mean,
/// std_dev**2)` distributed.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{LogNormal, IndependentSample};
///
/// // mean 2, standard deviation 3
/// let log_normal = LogNormal::new(2.0, 3.0);
/// let v = log_normal.ind_sample(&mut rand::thread_rng());
/// println!("{} is from an ln N(2, 9) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct LogNormal {
norm: Normal
}
impl LogNormal {
/// Construct a new `LogNormal` distribution with the given mean
/// and standard deviation.
///
/// # Panics
///
/// Panics if `std_dev < 0`.
#[inline]
pub fn new(mean: f64, std_dev: f64) -> LogNormal {
assert!(std_dev >= 0.0, "LogNormal::new called with `std_dev` < 0");
LogNormal { norm: Normal::new(mean, std_dev) }
}
}
impl Sample<f64> for LogNormal {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for LogNormal {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
self.norm.ind_sample(rng).exp()
}
}
#[cfg(test)]
mod tests {
use distributions::{Sample, IndependentSample};
use super::{Normal, LogNormal};
#[test]
fn test_normal() {
let mut norm = Normal::new(10.0, 10.0);
let mut rng = ::test::rng();
for _ in 0..1000 {
norm.sample(&mut rng);
norm.ind_sample(&mut rng);
}
}
#[test]
#[should_panic]
fn test_normal_invalid_sd() {
Normal::new(10.0, -1.0);
}
#[test]
fn test_log_normal() {
let mut lnorm = LogNormal::new(10.0, 10.0);
let mut rng = ::test::rng();
for _ in 0..1000 {
lnorm.sample(&mut rng);
lnorm.ind_sample(&mut rng);
}
}
#[test]
#[should_panic]
fn test_log_normal_invalid_sd() {
LogNormal::new(10.0, -1.0);
}
}

View File

@ -0,0 +1,280 @@
// Copyright 2013 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.
// Tables for distributions which are sampled using the ziggurat
// algorithm. Autogenerated by `ziggurat_tables.py`.
pub type ZigTable = &'static [f64; 257];
pub const ZIG_NORM_R: f64 = 3.654152885361008796;
pub static ZIG_NORM_X: [f64; 257] =
[3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074,
3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434,
2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548,
2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056,
2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570,
2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761,
2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318,
2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520,
2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952,
2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565,
2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760,
2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995,
2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268,
2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957,
2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778,
2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715,
2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244,
1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896,
1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257,
1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081,
1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281,
1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566,
1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199,
1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933,
1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012,
1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086,
1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338,
1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526,
1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427,
1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339,
1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456,
1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553,
1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404,
1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369,
1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830,
1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425,
1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534,
1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964,
1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606,
1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679,
1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728,
1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732,
1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903,
1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552,
1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650,
1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240,
1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975,
1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151,
1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714,
1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538,
1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441,
1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750,
0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130,
0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997,
0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550,
0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752,
0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785,
0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653,
0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448,
0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928,
0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262,
0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393,
0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746,
0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806,
0.000000000000000000];
pub static ZIG_NORM_F: [f64; 257] =
[0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872,
0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100,
0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839,
0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237,
0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690,
0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918,
0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664,
0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916,
0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854,
0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965,
0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509,
0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229,
0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627,
0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880,
0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014,
0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349,
0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352,
0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926,
0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563,
0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071,
0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654,
0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926,
0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112,
0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651,
0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589,
0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525,
0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988,
0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150,
0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837,
0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316,
0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984,
0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274,
0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396,
0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099,
0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340,
0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515,
0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344,
0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958,
0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668,
0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784,
0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519,
0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750,
0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481,
0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788,
0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658,
0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142,
0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700,
0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941,
0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916,
0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473,
0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719,
0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205,
0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991,
0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357,
0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376,
0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409,
0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437,
0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500,
0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902,
0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935,
0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077,
0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839,
0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247,
0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328,
1.000000000000000000];
pub const ZIG_EXP_R: f64 = 7.697117470131050077;
pub static ZIG_EXP_X: [f64; 257] =
[8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696,
6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488,
5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530,
4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380,
4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857,
4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762,
3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744,
3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770,
3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608,
3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405,
3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160,
3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481,
3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601,
2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825,
2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780,
2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752,
2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489,
2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970,
2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815,
2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886,
2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372,
2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213,
2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027,
2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289,
2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526,
2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563,
1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943,
1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242,
1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954,
1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014,
1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566,
1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896,
1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334,
1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892,
1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092,
1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058,
1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504,
1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137,
1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189,
1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117,
1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330,
1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124,
1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677,
1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511,
1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813,
1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209,
1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735,
0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509,
0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311,
0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066,
0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206,
0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430,
0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102,
0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959,
0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947,
0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030,
0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626,
0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398,
0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235,
0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765,
0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122,
0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703,
0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842,
0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570,
0.000000000000000000];
pub static ZIG_EXP_F: [f64; 257] =
[0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573,
0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797,
0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991,
0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981,
0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943,
0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355,
0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581,
0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221,
0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622,
0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431,
0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139,
0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289,
0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379,
0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030,
0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660,
0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816,
0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752,
0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435,
0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146,
0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197,
0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213,
0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145,
0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283,
0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641,
0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671,
0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602,
0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146,
0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839,
0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129,
0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081,
0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829,
0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083,
0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189,
0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654,
0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628,
0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956,
0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560,
0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543,
0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173,
0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967,
0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746,
0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252,
0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185,
0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223,
0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717,
0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449,
0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379,
0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056,
0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350,
0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209,
0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907,
0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836,
0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708,
0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881,
0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931,
0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056,
0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150,
0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560,
0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398,
0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177,
0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456,
0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838,
0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101,
0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477,
1.000000000000000000];

1214
third_party/rust/rand-0.4.3/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
// 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.
//! Pseudo random number generators are algorithms to produce *apparently
//! random* numbers deterministically, and usually fairly quickly.
//!
//! So long as the algorithm is computationally secure, is initialised with
//! sufficient entropy (i.e. unknown by an attacker), and its internal state is
//! also protected (unknown to an attacker), the output will also be
//! *computationally secure*. Computationally Secure Pseudo Random Number
//! Generators (CSPRNGs) are thus suitable sources of random numbers for
//! cryptography. There are a couple of gotchas here, however. First, the seed
//! used for initialisation must be unknown. Usually this should be provided by
//! the operating system and should usually be secure, however this may not
//! always be the case (especially soon after startup). Second, user-space
//! memory may be vulnerable, for example when written to swap space, and after
//! forking a child process should reinitialise any user-space PRNGs. For this
//! reason it may be preferable to source random numbers directly from the OS
//! for cryptographic applications.
//!
//! PRNGs are also widely used for non-cryptographic uses: randomised
//! algorithms, simulations, games. In these applications it is usually not
//! important for numbers to be cryptographically *unguessable*, but even
//! distribution and independence from other samples (from the point of view
//! of someone unaware of the algorithm used, at least) may still be important.
//! Good PRNGs should satisfy these properties, but do not take them for
//! granted; Wikipedia's article on
//! [Pseudorandom number generators](https://en.wikipedia.org/wiki/Pseudorandom_number_generator)
//! provides some background on this topic.
//!
//! Care should be taken when seeding (initialising) PRNGs. Some PRNGs have
//! short periods for some seeds. If one PRNG is seeded from another using the
//! same algorithm, it is possible that both will yield the same sequence of
//! values (with some lag).
mod chacha;
mod isaac;
mod isaac64;
mod xorshift;
pub use self::chacha::ChaChaRng;
pub use self::isaac::IsaacRng;
pub use self::isaac64::Isaac64Rng;
pub use self::xorshift::XorShiftRng;

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