<commit_before>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interface to the operating system's random number generator.
//!
//! # Supported targets
//!
//! | Target            | Target Triple      | Implementation
//! | ----------------- | ------------------ | --------------
//! | Linux, Android    | `*‑linux‑*`        | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` |
//! | Windows           | `*‑windows‑*`      | [`BCryptGenRandom`][3] |
//! | macOS             | `*‑apple‑darwin`   | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS               | `*‑apple‑ios`      | [`SecRandomCopyBytes`][4]
//! | FreeBSD           | `*‑freebsd`        | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
//! | OpenBSD           | `*‑openbsd`        | [`getentropy`][6]
//! | NetBSD            | `*‑netbsd`         | [`kern.arandom`][7]
//! | Dragonfly BSD     | `*‑dragonfly`      | [`/dev/random`][8]
//! | Solaris, illumos  | `*‑solaris`, `*‑illumos` | [`getrandom()`][9] if available, otherwise [`/dev/random`][10]
//! | Fuchsia OS        | `*‑fuchsia`        | [`cprng_draw`][11]
//! | Redox             | `*‑redox`          | [`rand:`][12]
//! | Haiku             | `*‑haiku`          | `/dev/random` (identical to `/dev/urandom`)
//! | SGX               | `x86_64‑*‑sgx`     | [RDRAND][18]
//! | VxWorks           | `*‑wrs‑vxworks‑*`  | `randABytes` after checking entropy pool initialization with `randSecure`
//! | Emscripten        | `*‑emscripten`     | `/dev/random` (identical to `/dev/urandom`)
//! | WASI              | `wasm32‑wasi`      | [`__wasi_random_get`][17]
//! | Web Browser       | `wasm32‑*‑unknown` | [`Crypto.getRandomValues()`][14], see [WebAssembly support][16]
//! | Node.js           | `wasm32‑*‑unknown` | [`crypto.randomBytes`][15], see [WebAssembly support][16]
//!
//! There is no blanket implementation on `unix` targets that reads from
//! `/dev/urandom`. This ensures all supported targets are using the recommended
//! interface and respect maximum buffer sizes.
//!
//! Pull Requests that add support for new targets to `getrandom` are always welcome.
//!
//! ## Unsupported targets
//!
//! By default, `getrandom` will not compile on unsupported targets, but certain
//! features allow a user to select a "fallback" implementation if no supported
//! implementation exists.
//!
//! All of the below mechanisms only affect unsupported
//! targets. Supported targets will _always_ use their supported implementations.
//! This prevents a crate from overriding a secure source of randomness
//! (either accidentally or intentionally).
//!
//! ### RDRAND on x86
//!
//! *If the `"rdrand"` Cargo feature is enabled*, `getrandom` will fallback to using
//! the [`RDRAND`][18] instruction to get randomness on `no_std` `x86`/`x86_64`
//! targets. This feature has no effect on other CPU architectures.
//!
//! ### WebAssembly support
//!
//! This crate fully supports the
//! [`wasm32-wasi`](https://github.com/CraneStation/wasi) and
//! [`wasm32-unknown-emscripten`](https://www.hellorust.com/setup/emscripten/)
//! targets. However, the `wasm32-unknown-unknown` target is not automatically
//! supported since, from the target name alone, we cannot deduce which
//! JavaScript interface is in use (or if JavaScript is available at all).
//!
//! Instead, *if the `"js"` Cargo feature is enabled*, this crate will assume
//! that you are building for an environment containing JavaScript, and will
//! call the appropriate methods. Both web browser (main window and Web Workers)
//! and Node.js environments are supported, invoking the methods
//! [described above](#supported-targets) using the
//! [wasm-bindgen](https://github.com/rust-lang/rust-bindgen) toolchain.
//!
//! This feature has no effect on targets other than `wasm32-unknown-unknown`.
//!
//! ### Custom implementations
//!
//! The [`register_custom_getrandom!`] macro allows a user to mark their own
//! function as the backing implementation for [`getrandom`]. See the macro's
//! documentation for more information about writing and registering your own
//! custom implementations.
//!
//! Note that registering a custom implementation only has an effect on targets
//! that would otherwise not compile. Any supported targets (including those
//! using `"rdrand"` and `"js"` Cargo features) continue using their normal
//! implementations even if a function is registered.
//!
//! ### Indirect Dependencies
//!
//! If `getrandom` is not a direct dependency of your crate, you can still
//! enable any of the above fallback behaviors by enabling the relevant
//! feature in your root crate's `Cargo.toml`:
//! ```toml
//! [dependencies]
//! getrandom = { version = "0.2", features = ["js"] }
//! ```
//!
//! ## Early boot
//!
//! Sometimes, early in the boot process, the OS has not collected enough
//! entropy to securely seed its RNG. This is especially common on virtual
//! machines, where standard "random" events are hard to come by.
//!
//! Some operating system interfaces always block until the RNG is securely
//! seeded. This can take anywhere from a few seconds to more than a minute.
//! A few (Linux, NetBSD and Solaris) offer a choice between blocking and
//! getting an error; in these cases, we always choose to block.
//!
//! On Linux (when the `getrandom` system call is not available), reading from
//! `/dev/urandom` never blocks, even when the OS hasn't collected enough
//! entropy yet. To avoid returning low-entropy bytes, we first poll
//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
//!
//! ## Error handling
//!
//! We always choose failure over returning insecure "random" bytes. In general,
//! on supported platforms, failure is highly unlikely, though not impossible.
//! If an error does occur, then it is likely that it will occur on every call to
//! `getrandom`, hence after the first successful call one can be reasonably
//! confident that no errors will occur.
//!
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
//! [3]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
//! [6]: https://man.openbsd.org/getentropy.2
//! [7]: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7+NetBSD-8.0
//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
//! [11]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [16]: #webassembly-support
//! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [20]: https://www.unix.com/man-page/mojave/4/random/
//! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable

#![doc(
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
    html_root_url = "https://docs.rs/getrandom/0.2.2"
)]
#![no_std]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]

#[macro_use]
extern crate cfg_if;

mod error;
mod util;
// To prevent a breaking change when targets are added, we always export the
// register_custom_getrandom macro, so old Custom RNG crates continue to build.
#[cfg(feature = "custom")]
mod custom;
#[cfg(feature = "std")]
mod error_impls;

pub use crate::error::Error;

// System-specific implementations.
//
// These should all provide getrandom_inner with the same signature as getrandom.
cfg_if! {
    if #[cfg(any(target_os = "dragonfly", target_os = "emscripten",
                 target_os = "haiku",     target_os = "redox"))] {
        mod util_libc;
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(any(target_os = "android", target_os = "linux"))] {
        mod util_libc;
        mod use_file;
        #[path = "linux_android.rs"] mod imp;
    } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
        mod util_libc;
        mod use_file;
        #[path = "solaris_illumos.rs"] mod imp;
    } else if #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] {
        mod util_libc;
        #[path = "bsd_arandom.rs"] mod imp;
    } else if #[cfg(target_os = "fuchsia")] {
        #[path = "fuchsia.rs"] mod imp;
    } else if #[cfg(target_os = "ios")] {
        #[path = "ios.rs"] mod imp;
    } else if #[cfg(target_os = "macos")] {
        mod util_libc;
        mod use_file;
        #[path = "macos.rs"] mod imp;
    } else if #[cfg(target_os = "openbsd")] {
        mod util_libc;
        #[path = "openbsd.rs"] mod imp;
    } else if #[cfg(target_os = "wasi")] {
        #[path = "wasi.rs"] mod imp;
    } else if #[cfg(target_os = "vxworks")] {
        mod util_libc;
        #[path = "vxworks.rs"] mod imp;
    } else if #[cfg(windows)] {
        #[path = "windows.rs"] mod imp;
    } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(all(feature = "rdrand",
                        any(target_arch = "x86_64", target_arch = "x86")))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(all(feature = "js",
                        target_arch = "wasm32", target_os = "unknown"))] {
        #[path = "js.rs"] mod imp;
    } else if #[cfg(feature = "custom")] {
        use custom as imp;
    } else {
        compile_error!("target is not supported, for more information see: \
                        https://docs.rs/getrandom/#unsupported-targets");
    }
}

/// Fill `dest` with random bytes from the system's preferred random number
/// source.
///
/// This function returns an error on any failure, including partial reads. We
/// make no guarantees regarding the contents of `dest` on error. If `dest` is
/// empty, `getrandom` immediately returns success, making no calls to the
/// underlying operating system.
///
/// Blocking is possible, at least during early boot; see module documentation.
///
/// In general, `getrandom` will be fast enough for interactive usage, though
/// significantly slower than a user-space CSPRNG; for the latter consider
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
    if dest.is_empty() {
        return Ok(());
    }
    imp::getrandom_inner(dest)
}
<commit_msg>Fix WASI function name and doc link (#202)<commit_after>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interface to the operating system's random number generator.
//!
//! # Supported targets
//!
//! | Target            | Target Triple      | Implementation
//! | ----------------- | ------------------ | --------------
//! | Linux, Android    | `*‑linux‑*`        | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` |
//! | Windows           | `*‑windows‑*`      | [`BCryptGenRandom`][3] |
//! | macOS             | `*‑apple‑darwin`   | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS               | `*‑apple‑ios`      | [`SecRandomCopyBytes`][4]
//! | FreeBSD           | `*‑freebsd`        | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
//! | OpenBSD           | `*‑openbsd`        | [`getentropy`][6]
//! | NetBSD            | `*‑netbsd`         | [`kern.arandom`][7]
//! | Dragonfly BSD     | `*‑dragonfly`      | [`/dev/random`][8]
//! | Solaris, illumos  | `*‑solaris`, `*‑illumos` | [`getrandom()`][9] if available, otherwise [`/dev/random`][10]
//! | Fuchsia OS        | `*‑fuchsia`        | [`cprng_draw`][11]
//! | Redox             | `*‑redox`          | [`rand:`][12]
//! | Haiku             | `*‑haiku`          | `/dev/random` (identical to `/dev/urandom`)
//! | SGX               | `x86_64‑*‑sgx`     | [RDRAND][18]
//! | VxWorks           | `*‑wrs‑vxworks‑*`  | `randABytes` after checking entropy pool initialization with `randSecure`
//! | Emscripten        | `*‑emscripten`     | `/dev/random` (identical to `/dev/urandom`)
//! | WASI              | `wasm32‑wasi`      | [`random_get`][17]
//! | Web Browser       | `wasm32‑*‑unknown` | [`Crypto.getRandomValues()`][14], see [WebAssembly support][16]
//! | Node.js           | `wasm32‑*‑unknown` | [`crypto.randomBytes`][15], see [WebAssembly support][16]
//!
//! There is no blanket implementation on `unix` targets that reads from
//! `/dev/urandom`. This ensures all supported targets are using the recommended
//! interface and respect maximum buffer sizes.
//!
//! Pull Requests that add support for new targets to `getrandom` are always welcome.
//!
//! ## Unsupported targets
//!
//! By default, `getrandom` will not compile on unsupported targets, but certain
//! features allow a user to select a "fallback" implementation if no supported
//! implementation exists.
//!
//! All of the below mechanisms only affect unsupported
//! targets. Supported targets will _always_ use their supported implementations.
//! This prevents a crate from overriding a secure source of randomness
//! (either accidentally or intentionally).
//!
//! ### RDRAND on x86
//!
//! *If the `"rdrand"` Cargo feature is enabled*, `getrandom` will fallback to using
//! the [`RDRAND`][18] instruction to get randomness on `no_std` `x86`/`x86_64`
//! targets. This feature has no effect on other CPU architectures.
//!
//! ### WebAssembly support
//!
//! This crate fully supports the
//! [`wasm32-wasi`](https://github.com/CraneStation/wasi) and
//! [`wasm32-unknown-emscripten`](https://www.hellorust.com/setup/emscripten/)
//! targets. However, the `wasm32-unknown-unknown` target is not automatically
//! supported since, from the target name alone, we cannot deduce which
//! JavaScript interface is in use (or if JavaScript is available at all).
//!
//! Instead, *if the `"js"` Cargo feature is enabled*, this crate will assume
//! that you are building for an environment containing JavaScript, and will
//! call the appropriate methods. Both web browser (main window and Web Workers)
//! and Node.js environments are supported, invoking the methods
//! [described above](#supported-targets) using the
//! [wasm-bindgen](https://github.com/rust-lang/rust-bindgen) toolchain.
//!
//! This feature has no effect on targets other than `wasm32-unknown-unknown`.
//!
//! ### Custom implementations
//!
//! The [`register_custom_getrandom!`] macro allows a user to mark their own
//! function as the backing implementation for [`getrandom`]. See the macro's
//! documentation for more information about writing and registering your own
//! custom implementations.
//!
//! Note that registering a custom implementation only has an effect on targets
//! that would otherwise not compile. Any supported targets (including those
//! using `"rdrand"` and `"js"` Cargo features) continue using their normal
//! implementations even if a function is registered.
//!
//! ### Indirect Dependencies
//!
//! If `getrandom` is not a direct dependency of your crate, you can still
//! enable any of the above fallback behaviors by enabling the relevant
//! feature in your root crate's `Cargo.toml`:
//! ```toml
//! [dependencies]
//! getrandom = { version = "0.2", features = ["js"] }
//! ```
//!
//! ## Early boot
//!
//! Sometimes, early in the boot process, the OS has not collected enough
//! entropy to securely seed its RNG. This is especially common on virtual
//! machines, where standard "random" events are hard to come by.
//!
//! Some operating system interfaces always block until the RNG is securely
//! seeded. This can take anywhere from a few seconds to more than a minute.
//! A few (Linux, NetBSD and Solaris) offer a choice between blocking and
//! getting an error; in these cases, we always choose to block.
//!
//! On Linux (when the `getrandom` system call is not available), reading from
//! `/dev/urandom` never blocks, even when the OS hasn't collected enough
//! entropy yet. To avoid returning low-entropy bytes, we first poll
//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
//!
//! ## Error handling
//!
//! We always choose failure over returning insecure "random" bytes. In general,
//! on supported platforms, failure is highly unlikely, though not impossible.
//! If an error does occur, then it is likely that it will occur on every call to
//! `getrandom`, hence after the first successful call one can be reasonably
//! confident that no errors will occur.
//!
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
//! [3]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
//! [6]: https://man.openbsd.org/getentropy.2
//! [7]: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7+NetBSD-8.0
//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
//! [11]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [16]: #webassembly-support
//! [17]: https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [20]: https://www.unix.com/man-page/mojave/4/random/
//! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable

#![doc(
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
    html_root_url = "https://docs.rs/getrandom/0.2.2"
)]
#![no_std]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]

#[macro_use]
extern crate cfg_if;

mod error;
mod util;
// To prevent a breaking change when targets are added, we always export the
// register_custom_getrandom macro, so old Custom RNG crates continue to build.
#[cfg(feature = "custom")]
mod custom;
#[cfg(feature = "std")]
mod error_impls;

pub use crate::error::Error;

// System-specific implementations.
//
// These should all provide getrandom_inner with the same signature as getrandom.
cfg_if! {
    if #[cfg(any(target_os = "dragonfly", target_os = "emscripten",
                 target_os = "haiku",     target_os = "redox"))] {
        mod util_libc;
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(any(target_os = "android", target_os = "linux"))] {
        mod util_libc;
        mod use_file;
        #[path = "linux_android.rs"] mod imp;
    } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
        mod util_libc;
        mod use_file;
        #[path = "solaris_illumos.rs"] mod imp;
    } else if #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] {
        mod util_libc;
        #[path = "bsd_arandom.rs"] mod imp;
    } else if #[cfg(target_os = "fuchsia")] {
        #[path = "fuchsia.rs"] mod imp;
    } else if #[cfg(target_os = "ios")] {
        #[path = "ios.rs"] mod imp;
    } else if #[cfg(target_os = "macos")] {
        mod util_libc;
        mod use_file;
        #[path = "macos.rs"] mod imp;
    } else if #[cfg(target_os = "openbsd")] {
        mod util_libc;
        #[path = "openbsd.rs"] mod imp;
    } else if #[cfg(target_os = "wasi")] {
        #[path = "wasi.rs"] mod imp;
    } else if #[cfg(target_os = "vxworks")] {
        mod util_libc;
        #[path = "vxworks.rs"] mod imp;
    } else if #[cfg(windows)] {
        #[path = "windows.rs"] mod imp;
    } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(all(feature = "rdrand",
                        any(target_arch = "x86_64", target_arch = "x86")))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(all(feature = "js",
                        target_arch = "wasm32", target_os = "unknown"))] {
        #[path = "js.rs"] mod imp;
    } else if #[cfg(feature = "custom")] {
        use custom as imp;
    } else {
        compile_error!("target is not supported, for more information see: \
                        https://docs.rs/getrandom/#unsupported-targets");
    }
}

/// Fill `dest` with random bytes from the system's preferred random number
/// source.
///
/// This function returns an error on any failure, including partial reads. We
/// make no guarantees regarding the contents of `dest` on error. If `dest` is
/// empty, `getrandom` immediately returns success, making no calls to the
/// underlying operating system.
///
/// Blocking is possible, at least during early boot; see module documentation.
///
/// In general, `getrandom` will be fast enough for interactive usage, though
/// significantly slower than a user-space CSPRNG; for the latter consider
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
    if dest.is_empty() {
        return Ok(());
    }
    imp::getrandom_inner(dest)
}
<|endoftext|>


<commit_before>// Copyright 2017-2021 int08h LLC
//
// 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.

//!
//! An implementation of the [Roughtime](https://roughtime.googlesource.com/roughtime)
//! secure time synchronization protocol.
//!
//! Roughtime aims to achieve rough time synchronisation in a secure way that doesn't
//! depend on any particular time server, and in such a way that, if a time server does
//! misbehave, clients end up with cryptographic proof of it.
//!
//! # Protocol
//!
//! Roughtime messages are represented by [`RtMessage`](struct.RtMessage.html) which
//! implements the mapping of Roughtime `u32` [`tags`](enum.Tag.html) to byte-strings.
//!
//! # Keys and Signing
//!
//! Roughtime uses an [Ed25519](https://ed25519.cr.yp.to/) key pair as the server's
//! long-term identity and a second key pair (signed by the long-term key) as a
//! delegated on-line (ephemeral) key.
//!
//! [`LongTermKey`](key/struct.LongTermKey.html) and [`OnlineKey`](key/struct.OnlineKey.html)
//! implement these elements of the protocol. The [`sign`](sign/index.html) module provides
//! signing and verification operations.
//!
//! # Client
//!
//! A Roughtime client can be found in `src/bin/client.rs`. To run the client:
//!
//! ```bash
//! $ cargo run --release --bin client roughtime.int08h.com 2002
//! ```
//!
//! Consult the client's `--help` output for all runtime options.
//!
//! # Server
//!
//! The core Roughtime server implementation is in `src/server.rs` and the server's CLI can
//! be found in `src/bin/roughenough-server.rs`.
//!
//! The server has multiple ways it can be configured,
//! see [`ServerConfig`](config/trait.ServerConfig.html) for the configuration trait and
//!
//!

#[macro_use]
extern crate log;

pub use crate::error::Error;
pub use crate::message::RtMessage;
pub use crate::tag::Tag;

mod error;
mod message;
mod tag;

pub mod config;
pub mod grease;
pub mod key;
pub mod kms;
pub mod merkle;
pub mod request;
pub mod responder;
pub mod server;
pub mod sign;
pub mod stats;
pub mod version;

/// Version of Roughenough
pub const VERSION: &str = "1.2.0-draft-5";

/// Roughenough version string enriched with any compile-time optional features
pub fn roughenough_version() -> String {
    let kms_str = if cfg!(feature = "awskms") {
        " (+AWS KMS)"
    } else if cfg!(feature = "gcpkms") {
        " (+GCP KMS)"
    } else {
        ""
    };

    format!("{}{}", VERSION, kms_str)
}

//  Constants and magic numbers of the Roughtime protocol

/// Minimum size (in bytes) of a client request
pub const MIN_REQUEST_LENGTH: u32 = 1024;

/// Size (in bytes) of seeds used to derive private keys
pub const SEED_LENGTH: u32 = 32;

/// Size (in bytes) of an Ed25519 public key
pub const PUBKEY_LENGTH: u32 = 32;

/// Size (in bytes) of an Ed25519 signature
pub const SIGNATURE_LENGTH: u32 = 64;

/// Size (in bytes) of server's timestamp value
pub const TIMESTAMP_LENGTH: u32 = 8;

/// Size (in bytes) of server's time uncertainty value
pub const RADIUS_LENGTH: u32 = 4;

/// Prefixed to the server's certificate before generating or verifying certificate's signature
pub const CERTIFICATE_CONTEXT: &str = "RoughTime v1 delegation signature--\x00";

/// Prefixed to the server's response before generating or verifying the server's signature
pub const SIGNED_RESPONSE_CONTEXT: &str = "RoughTime v1 response signature\x00";

/// Value prepended to leaves prior to hashing
pub const TREE_LEAF_TWEAK: &[u8] = &[0x00];

/// Value prepended to nodes prior to hashing
pub const TREE_NODE_TWEAK: &[u8] = &[0x01];

/// RFC first field magic value
pub const RFC_REQUEST_FRAME_BYTES: &[u8] = b"ROUGHTIM";
<commit_msg>Fix version number typo<commit_after>// Copyright 2017-2021 int08h LLC
//
// 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.

//!
//! An implementation of the [Roughtime](https://roughtime.googlesource.com/roughtime)
//! secure time synchronization protocol.
//!
//! Roughtime aims to achieve rough time synchronisation in a secure way that doesn't
//! depend on any particular time server, and in such a way that, if a time server does
//! misbehave, clients end up with cryptographic proof of it.
//!
//! # Protocol
//!
//! Roughtime messages are represented by [`RtMessage`](struct.RtMessage.html) which
//! implements the mapping of Roughtime `u32` [`tags`](enum.Tag.html) to byte-strings.
//!
//! # Keys and Signing
//!
//! Roughtime uses an [Ed25519](https://ed25519.cr.yp.to/) key pair as the server's
//! long-term identity and a second key pair (signed by the long-term key) as a
//! delegated on-line (ephemeral) key.
//!
//! [`LongTermKey`](key/struct.LongTermKey.html) and [`OnlineKey`](key/struct.OnlineKey.html)
//! implement these elements of the protocol. The [`sign`](sign/index.html) module provides
//! signing and verification operations.
//!
//! # Client
//!
//! A Roughtime client can be found in `src/bin/client.rs`. To run the client:
//!
//! ```bash
//! $ cargo run --release --bin client roughtime.int08h.com 2002
//! ```
//!
//! Consult the client's `--help` output for all runtime options.
//!
//! # Server
//!
//! The core Roughtime server implementation is in `src/server.rs` and the server's CLI can
//! be found in `src/bin/roughenough-server.rs`.
//!
//! The server has multiple ways it can be configured,
//! see [`ServerConfig`](config/trait.ServerConfig.html) for the configuration trait and
//!
//!

#[macro_use]
extern crate log;

pub use crate::error::Error;
pub use crate::message::RtMessage;
pub use crate::tag::Tag;

mod error;
mod message;
mod tag;

pub mod config;
pub mod grease;
pub mod key;
pub mod kms;
pub mod merkle;
pub mod request;
pub mod responder;
pub mod server;
pub mod sign;
pub mod stats;
pub mod version;

/// Version of Roughenough
pub const VERSION: &str = "1.2.0-draft5";

/// Roughenough version string enriched with any compile-time optional features
pub fn roughenough_version() -> String {
    let kms_str = if cfg!(feature = "awskms") {
        " (+AWS KMS)"
    } else if cfg!(feature = "gcpkms") {
        " (+GCP KMS)"
    } else {
        ""
    };

    format!("{}{}", VERSION, kms_str)
}

//  Constants and magic numbers of the Roughtime protocol

/// Minimum size (in bytes) of a client request
pub const MIN_REQUEST_LENGTH: u32 = 1024;

/// Size (in bytes) of seeds used to derive private keys
pub const SEED_LENGTH: u32 = 32;

/// Size (in bytes) of an Ed25519 public key
pub const PUBKEY_LENGTH: u32 = 32;

/// Size (in bytes) of an Ed25519 signature
pub const SIGNATURE_LENGTH: u32 = 64;

/// Size (in bytes) of server's timestamp value
pub const TIMESTAMP_LENGTH: u32 = 8;

/// Size (in bytes) of server's time uncertainty value
pub const RADIUS_LENGTH: u32 = 4;

/// Prefixed to the server's certificate before generating or verifying certificate's signature
pub const CERTIFICATE_CONTEXT: &str = "RoughTime v1 delegation signature--\x00";

/// Prefixed to the server's response before generating or verifying the server's signature
pub const SIGNED_RESPONSE_CONTEXT: &str = "RoughTime v1 response signature\x00";

/// Value prepended to leaves prior to hashing
pub const TREE_LEAF_TWEAK: &[u8] = &[0x00];

/// Value prepended to nodes prior to hashing
pub const TREE_NODE_TWEAK: &[u8] = &[0x01];

/// RFC first field magic value
pub const RFC_REQUEST_FRAME_BYTES: &[u8] = b"ROUGHTIM";
<|endoftext|>


<commit_before>#![deny(warnings)]

#[macro_use]
extern crate error_chain;
extern crate fs2;
#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "macos"))]
extern crate libc;
extern crate rustc_version;
extern crate serde_json;
extern crate tempdir;
extern crate toml;
extern crate walkdir;
extern crate dirs;

use std::hash::{Hash, Hasher};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::ExitStatus;
use std::{env, io, process};

use rustc_version::Channel;

use errors::*;
use rustc::Target;

mod cargo;
mod cli;
mod errors;
mod extensions;
mod flock;
mod rustc;
mod sysroot;
mod util;
mod xargo;

pub use sysroot::XargoMode;

// We use a different sysroot for Native compilation to avoid file locking
//
// Cross compilation requires `lib/rustlib/$HOST` to match `rustc`'s sysroot,
// whereas Native compilation wants to use a custom `lib/rustlib/$HOST`. If each
// mode has its own sysroot then we avoid sharing that directory and thus file
// locking it.
pub enum CompilationMode {
    Cross(Target),
    Native(String),
}

impl CompilationMode {
    fn hash<H>(&self, hasher: &mut H) -> Result<()>
    where
        H: Hasher,
    {
        match *self {
            CompilationMode::Cross(ref target) => target.hash(hasher)?,
            CompilationMode::Native(ref triple) => triple.hash(hasher),
        }

        Ok(())
    }

    fn triple(&self) -> &str {
        match *self {
            CompilationMode::Cross(ref target) => target.triple(),
            CompilationMode::Native(ref triple) => triple,
        }
    }

    fn is_native(&self) -> bool {
        match *self {
            CompilationMode::Native(_) => true,
            _ => false,
        }
    }
}

pub fn main_inner(xargo_mode: XargoMode) {
    fn show_backtrace() -> bool {
        env::var("RUST_BACKTRACE").as_ref().map(|s| &s[..]) == Ok("1")
    }

    match run(xargo_mode) {
        Err(e) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();

            writeln!(stderr, "error: {}", e).ok();

            for e in e.iter().skip(1) {
                writeln!(stderr, "caused by: {}", e).ok();
            }

            if show_backtrace() {
                if let Some(backtrace) = e.backtrace() {
                    writeln!(stderr, "{:?}", backtrace).ok();
                }
            } else {
                writeln!(stderr, "note: run with `RUST_BACKTRACE=1` for a backtrace").ok();
            }

            process::exit(1)
        }
        Ok(Some(status)) => if !status.success() {
            process::exit(status.code().unwrap_or(1))
        },
        Ok(None) => {}
    }
}

fn run(cargo_mode: XargoMode) -> Result<Option<ExitStatus>> {
    let args = cli::args();
    let verbose = args.verbose();

    let meta = rustc::version();

    if let Some(sc) = args.subcommand() {
        if !sc.needs_sysroot() {
            return cargo::run(&args, verbose).map(Some);
        }
    } else if args.version() {
        writeln!(
            io::stderr(),
            concat!("xargo ", env!("CARGO_PKG_VERSION"), "{}"),
            include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
        ).ok();

        return cargo::run(&args, verbose).map(Some);
    }

    let cd = CurrentDirectory::get()?;

    let config = cargo::config()?;
    if let Some(root) = cargo::root(cargo_mode)? {
        // We can't build sysroot with stable or beta due to unstable features
        let sysroot = rustc::sysroot(verbose)?;
        let src = match meta.channel {
            Channel::Dev => rustc::Src::from_env().ok_or(
                "The XARGO_RUST_SRC env variable must be set and point to the \
                 Rust source directory when working with the 'dev' channel",
            )?,
            Channel::Nightly => if let Some(src) = rustc::Src::from_env() {
                src
            } else {
                sysroot.src()?
            },
            Channel::Stable | Channel::Beta => {
                writeln!(
                    io::stderr(),
                    "WARNING: the sysroot can't be built for the {:?} channel. \
                     Switch to nightly.",
                    meta.channel
                ).ok();
                return cargo::run(&args, verbose).map(Some);
            }
        };

        let cmode = if let Some(triple) = args.target() {
            if Path::new(triple).is_file() {
                bail!(
                    "Xargo doesn't support files as an argument to --target. \
                     Use `--target foo` instead of `--target foo.json`."
                )
            } else if triple == meta.host {
                Some(CompilationMode::Native(meta.host.clone()))
            } else {
                Target::new(triple, &cd, verbose)?.map(CompilationMode::Cross)
            }
        } else {
            if let Some(ref config) = config {
                if let Some(triple) = config.target()? {
                    Target::new(triple, &cd, verbose)?.map(CompilationMode::Cross)
                } else {
                    Some(CompilationMode::Native(meta.host.clone()))
                }
            } else {
                Some(CompilationMode::Native(meta.host.clone()))
            }
        };

        if let Some(cmode) = cmode {
            let home = xargo::home(&cmode)?;
            let rustflags = cargo::rustflags(config.as_ref(), cmode.triple())?;

            sysroot::update(
                &cmode,
                &home,
                &root,
                &rustflags,
                &meta,
                &src,
                &sysroot,
                verbose,
                args.message_format(),
                cargo_mode,
            )?;

            if args.subcommand().is_some() || cargo_mode == XargoMode::Build {
                return xargo::run(
                    &args,
                    &cmode,
                    rustflags,
                    &home,
                    &meta,
                    config.as_ref(),
                    verbose,
                ).map(Some);
            } else {
                return Ok(None)
            }
        }
    }

    cargo::run(&args, verbose).map(Some)
}

pub struct CurrentDirectory {
    path: PathBuf,
}

impl CurrentDirectory {
    fn get() -> Result<CurrentDirectory> {
        env::current_dir()
            .chain_err(|| "couldn't get the current directory")
            .map(|cd| CurrentDirectory { path: cd })
    }

    fn path(&self) -> &Path {
        &self.path
    }
}
<commit_msg>make xargo fail on non-nightly, instead of continuing with the wrong sysroot<commit_after>#![deny(warnings)]

#[macro_use]
extern crate error_chain;
extern crate fs2;
#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "macos"))]
extern crate libc;
extern crate rustc_version;
extern crate serde_json;
extern crate tempdir;
extern crate toml;
extern crate walkdir;
extern crate dirs;

use std::hash::{Hash, Hasher};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::ExitStatus;
use std::{env, io, process};

use rustc_version::Channel;

use errors::*;
use rustc::Target;

mod cargo;
mod cli;
mod errors;
mod extensions;
mod flock;
mod rustc;
mod sysroot;
mod util;
mod xargo;

pub use sysroot::XargoMode;

// We use a different sysroot for Native compilation to avoid file locking
//
// Cross compilation requires `lib/rustlib/$HOST` to match `rustc`'s sysroot,
// whereas Native compilation wants to use a custom `lib/rustlib/$HOST`. If each
// mode has its own sysroot then we avoid sharing that directory and thus file
// locking it.
pub enum CompilationMode {
    Cross(Target),
    Native(String),
}

impl CompilationMode {
    fn hash<H>(&self, hasher: &mut H) -> Result<()>
    where
        H: Hasher,
    {
        match *self {
            CompilationMode::Cross(ref target) => target.hash(hasher)?,
            CompilationMode::Native(ref triple) => triple.hash(hasher),
        }

        Ok(())
    }

    fn triple(&self) -> &str {
        match *self {
            CompilationMode::Cross(ref target) => target.triple(),
            CompilationMode::Native(ref triple) => triple,
        }
    }

    fn is_native(&self) -> bool {
        match *self {
            CompilationMode::Native(_) => true,
            _ => false,
        }
    }
}

pub fn main_inner(xargo_mode: XargoMode) {
    fn show_backtrace() -> bool {
        env::var("RUST_BACKTRACE").as_ref().map(|s| &s[..]) == Ok("1")
    }

    match run(xargo_mode) {
        Err(e) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();

            writeln!(stderr, "error: {}", e).ok();

            for e in e.iter().skip(1) {
                writeln!(stderr, "caused by: {}", e).ok();
            }

            if show_backtrace() {
                if let Some(backtrace) = e.backtrace() {
                    writeln!(stderr, "{:?}", backtrace).ok();
                }
            } else {
                writeln!(stderr, "note: run with `RUST_BACKTRACE=1` for a backtrace").ok();
            }

            process::exit(1)
        }
        Ok(Some(status)) => if !status.success() {
            process::exit(status.code().unwrap_or(1))
        },
        Ok(None) => {}
    }
}

fn run(cargo_mode: XargoMode) -> Result<Option<ExitStatus>> {
    let args = cli::args();
    let verbose = args.verbose();

    let meta = rustc::version();

    if let Some(sc) = args.subcommand() {
        if !sc.needs_sysroot() {
            return cargo::run(&args, verbose).map(Some);
        }
    } else if args.version() {
        writeln!(
            io::stderr(),
            concat!("xargo ", env!("CARGO_PKG_VERSION"), "{}"),
            include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
        ).ok();

        return cargo::run(&args, verbose).map(Some);
    }

    let cd = CurrentDirectory::get()?;

    let config = cargo::config()?;
    if let Some(root) = cargo::root(cargo_mode)? {
        // We can't build sysroot with stable or beta due to unstable features
        let sysroot = rustc::sysroot(verbose)?;
        let src = match meta.channel {
            Channel::Dev => rustc::Src::from_env().ok_or(
                "The XARGO_RUST_SRC env variable must be set and point to the \
                 Rust source directory when working with the 'dev' channel",
            )?,
            Channel::Nightly => if let Some(src) = rustc::Src::from_env() {
                src
            } else {
                sysroot.src()?
            },
            Channel::Stable | Channel::Beta => {
                eprintln!(
                    "ERROR: the sysroot can't be built for the {:?} channel. \
                     Switch to nightly.",
                    meta.channel
                );
                process::exit(1);
            }
        };

        let cmode = if let Some(triple) = args.target() {
            if Path::new(triple).is_file() {
                bail!(
                    "Xargo doesn't support files as an argument to --target. \
                     Use `--target foo` instead of `--target foo.json`."
                )
            } else if triple == meta.host {
                Some(CompilationMode::Native(meta.host.clone()))
            } else {
                Target::new(triple, &cd, verbose)?.map(CompilationMode::Cross)
            }
        } else {
            if let Some(ref config) = config {
                if let Some(triple) = config.target()? {
                    Target::new(triple, &cd, verbose)?.map(CompilationMode::Cross)
                } else {
                    Some(CompilationMode::Native(meta.host.clone()))
                }
            } else {
                Some(CompilationMode::Native(meta.host.clone()))
            }
        };

        if let Some(cmode) = cmode {
            let home = xargo::home(&cmode)?;
            let rustflags = cargo::rustflags(config.as_ref(), cmode.triple())?;

            sysroot::update(
                &cmode,
                &home,
                &root,
                &rustflags,
                &meta,
                &src,
                &sysroot,
                verbose,
                args.message_format(),
                cargo_mode,
            )?;

            if args.subcommand().is_some() || cargo_mode == XargoMode::Build {
                return xargo::run(
                    &args,
                    &cmode,
                    rustflags,
                    &home,
                    &meta,
                    config.as_ref(),
                    verbose,
                ).map(Some);
            } else {
                return Ok(None)
            }
        }
    }

    cargo::run(&args, verbose).map(Some)
}

pub struct CurrentDirectory {
    path: PathBuf,
}

impl CurrentDirectory {
    fn get() -> Result<CurrentDirectory> {
        env::current_dir()
            .chain_err(|| "couldn't get the current directory")
            .map(|cd| CurrentDirectory { path: cd })
    }

    fn path(&self) -> &Path {
        &self.path
    }
}
<|endoftext|>


<commit_before>//! Maman is a Rust Web Crawler saving pages on Redis.
//!
//! # Default environment variables
//!
//! * `MAMAN_ENV`=development
//! * `REDIS_URL`="redis://127.0.0.1/"
#![doc(html_root_url = "https://docs.rs/maman/0.13.1")]
#![deny(warnings)]
#![crate_name = "maman"]

#[macro_use]
extern crate html5ever;
#[macro_use]
extern crate log;
extern crate mime;
extern crate reqwest;
extern crate robotparser;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
extern crate sidekiq;
extern crate url;

#[macro_export]
macro_rules! maman_name {
    () => {
        "Maman"
    };
}
#[macro_export]
macro_rules! maman_version {
    () => {
        env!("CARGO_PKG_VERSION")
    };
}
#[macro_export]
macro_rules! maman_version_string {
    () => {
        concat!(maman_name!(), " v", maman_version!())
    };
}
#[macro_export]
macro_rules! maman_user_agent {
    () => {
        concat!(maman_version_string!(), " (https://crates.io/crates/maman)")
    };
}

pub use maman::{Page, Spider};
pub mod maman;
<commit_msg>Rust edition 2018 fix<commit_after>//! Maman is a Rust Web Crawler saving pages on Redis.
//!
//! # Default environment variables
//!
//! * `MAMAN_ENV`=development
//! * `REDIS_URL`="redis://127.0.0.1/"
#![doc(html_root_url = "https://docs.rs/maman/0.13.1")]
#![deny(warnings)]
#![crate_name = "maman"]

#[macro_use]
extern crate html5ever;
#[macro_use]
extern crate log;
extern crate mime;
extern crate reqwest;
extern crate robotparser;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
extern crate sidekiq;
extern crate url;

#[macro_export]
macro_rules! maman_name {
    () => {
        "Maman"
    };
}
#[macro_export]
macro_rules! maman_version {
    () => {
        env!("CARGO_PKG_VERSION")
    };
}
#[macro_export]
macro_rules! maman_version_string {
    () => {
        concat!(maman_name!(), " v", maman_version!())
    };
}
#[macro_export]
macro_rules! maman_user_agent {
    () => {
        concat!(maman_version_string!(), " (https://crates.io/crates/maman)")
    };
}

pub use crate::maman::{Page, Spider};
pub mod maman;
<|endoftext|>


<commit_before>// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.
//! This module provides stacks using the operating system's
//! anonymous memory mapping facility, usually `mmap`.
//! The stacks it provides come with a guard page, which is not included
//! in the stack limit.

extern crate std;
use core::prelude::*;
use self::std::io::Error as IoError;
use stack;
mod sys;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
  ptr: *mut u8,
  len: usize
}

unsafe impl Send for Stack {}

impl Stack {
  pub fn new(size: usize) -> Result<Stack, IoError> {
    let page_size = sys::page_size();

    // round the page size up,
    // using the fact that it is a power of two
    let len = (size + page_size - 1) & !(page_size - 1);

    let stack = unsafe {
      let ptr = try!(match sys::map_stack(size) {
        None => Err(IoError::last_os_error()),
        Some(ptr) => Ok(ptr)
      });

      Stack { ptr: ptr as *mut u8, len: len }
    };

    try!(unsafe {
      if sys::protect_stack(stack.ptr) { Ok(()) }
      else { Err(IoError::last_os_error()) }
    });

    Ok(stack)
  }
}

impl stack::Stack for Stack {
  fn top(&mut self) -> *mut u8 {
    unsafe {
      self.ptr.offset(self.len as isize)
    }
  }

  fn limit(&self) -> *const u8 {
    unsafe {
      self.ptr.offset(sys::page_size() as isize)
    }
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      if !sys::unmap_stack(self.ptr, self.len) {
        panic!("munmap for stack {:p} of size {} failed: {}",
               self.ptr, self.len, IoError::last_os_error())
      }
    }
  }
}
<commit_msg>let os::Stack's docs shine through the facade<commit_after>// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.

extern crate std;
use core::prelude::*;
use self::std::io::Error as IoError;
use stack;
mod sys;

/// This object represents a stack from the operating system's
/// anonymous memory mapping facility, usually `mmap`.
/// The stack it provides comes with a guard page, which is not included
/// in the stack limit.
#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
  ptr: *mut u8,
  len: usize
}

unsafe impl Send for Stack {}

impl Stack {
  pub fn new(size: usize) -> Result<Stack, IoError> {
    let page_size = sys::page_size();

    // round the page size up,
    // using the fact that it is a power of two
    let len = (size + page_size - 1) & !(page_size - 1);

    let stack = unsafe {
      let ptr = try!(match sys::map_stack(size) {
        None => Err(IoError::last_os_error()),
        Some(ptr) => Ok(ptr)
      });

      Stack { ptr: ptr as *mut u8, len: len }
    };

    try!(unsafe {
      if sys::protect_stack(stack.ptr) { Ok(()) }
      else { Err(IoError::last_os_error()) }
    });

    Ok(stack)
  }
}

impl stack::Stack for Stack {
  fn top(&mut self) -> *mut u8 {
    unsafe {
      self.ptr.offset(self.len as isize)
    }
  }

  fn limit(&self) -> *const u8 {
    unsafe {
      self.ptr.offset(sys::page_size() as isize)
    }
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      if !sys::unmap_stack(self.ptr, self.len) {
        panic!("munmap for stack {:p} of size {} failed: {}",
               self.ptr, self.len, IoError::last_os_error())
      }
    }
  }
}
<|endoftext|>


<commit_before>//! Crate retry provides functionality for retrying an operation until its return value satisfies a
//! specific condition.
//!
//! # Usage
//!
//! Retry an operation by calling the `retry` function, supplying a maximum number of times to try,
//! the number of milliseconds to wait after each unsuccessful try, a closure that produces a value,
//! and a closure that takes a reference to that value and returns a boolean indicating the success
//! or failure of the operation. The function will return a `Result` containing either the value
//! that satisfied the condition or an error indicating that a satisfactory value could not be
//! produced.
//!
//! You can also construct a retryable operation incrementally using the `Retry` type. `Retry::new`
//! takes the same two closures as mutable references, and returns a `Retry` value. You can then
//! call the `try` and `wait` methods on this value to add a maximum number of tries and a wait
//! time, respectively. Finally, run the `execute` method to produce the `Result`.
//!
//! If a maximum number of tries is not supplied, the operation will be executed infinitely or until
//! success. If a wait time is not supplied, there will be no wait between attempts.
//!
//! # Failures
//!
//! Retrying will fail when:
//!
//! 1. The operation reaches the maximum number of tries without success.
//! 2. A value of 0 is supplied for the maximum number of tries. It must be at least 1.
//!
//! # Examples
//!
//! Imagine an HTTP API with an endpoint that returns 204 No Content while a job is processing, and
//! eventually 200 OK when the job has completed. Retrying until the job is finished would be
//! written:
//!
//! ```
//! # use retry::retry;
//! # struct Client;
//! # impl Client {
//! #     fn query_job_status(&self) -> Response {
//! #         Response {
//! #             code: 200,
//! #             body: "success",
//! #         }
//! #     }
//! # }
//! # struct Response {
//! #     code: u16,
//! #     body: &'static str,
//! # }
//! # let api_client = Client;
//! match retry(10, 500, || api_client.query_job_status(), |response| response.code == 200) {
//!     Ok(response) => println!("Job completed with result: {}", response.body),
//!     Err(error) => println!("Job completion could not be verified: {}", error),
//! }
//! ```
//!
//!
//! This retries the API call up to 10 times, waiting 500 milliseconds after each unsuccessful
//! attempt. The same result can be achieved by building a `Retry` object incrementally:
//!
//! ```
//! # use retry::Retry;
//! # struct Client;
//! # impl Client {
//! #     fn query_job_status(&self) -> Response {
//! #         Response {
//! #             code: 200,
//! #             body: "success",
//! #         }
//! #     }
//! # }
//! # struct Response {
//! #     code: u16,
//! #     body: &'static str,
//! # }
//! # let api_client = Client;
//! match Retry::new(
//!     &mut || api_client.query_job_status(),
//!     &mut |response| response.code == 200
//! ).try(10).wait(500).execute() {
//!     Ok(response) => println!("Job completed with result: {}", response.body),
//!     Err(error) => println!("Job completion could not be verified: {}", error),
//! }
//! ```

extern crate rand;

use std::error::Error;
use std::fmt::{Display,Formatter};
use std::fmt::Error as FmtError;
use std::thread::sleep_ms;

use rand::distributions::{IndependentSample, Range};
use rand::thread_rng;

/// Builder object for a retryable operation.
#[derive(Debug)]
pub struct Retry<'a, F: FnMut() -> R + 'a, G: FnMut(&R) -> bool + 'a, R> {
    condition_fn: &'a mut G,
    tries: Option<u32>,
    value_fn: &'a mut F,
    timeout: Option<u32>,
    wait: Wait,
}

impl<'a, F: FnMut() -> R, G: FnMut(&R) -> bool, R> Retry<'a, F, G, R> {
    /// Builds a new `Retry` object.
    pub fn new(
        value_fn: &'a mut F,
        condition_fn: &'a mut G
    ) -> Retry<'a, F, G, R> where F: FnMut() -> R, G: FnMut(&R) -> bool {
        Retry {
            condition_fn: condition_fn,
            tries: None,
            value_fn: value_fn,
            wait: Wait::None,
            timeout: None,
        }
    }

    /// Begins executing the retryable operation.
    pub fn execute(self) -> Result<R, RetryError> {
        if self.tries.is_some() && self.tries.unwrap() == 0 {
            return Err(RetryError { message: "tries must be non-zero" });
        }

        let mut try = 0;

        loop {
            if self.tries.is_some() && self.tries.unwrap() == try {
                return Err(RetryError { message: "reached last try without condition match" })
            }

            let value = (self.value_fn)();

            if (self.condition_fn)(&value) {
                return Ok(value);
            }

            match self.wait {
                Wait::Exponential(_multiplier) => {
                    let multiplier = (_multiplier + try) as f64;
                    sleep_ms(multiplier.exp() as u32);
                },
                Wait::Fixed(ms) => sleep_ms(ms),
                Wait::None => {},
                Wait::Range(min, max) => {
                    let range = Range::new(min, max);
                    let mut rng = thread_rng();
                    sleep_ms(range.ind_sample(&mut rng));
                },
            }

            try += 1;
        }
    }

    /// Sets the maximum number of milliseconds retries will be made before failing.
    pub fn timeout(mut self, max: u32) -> Retry<'a, F, G, R> {
        self.timeout = Some(max);

        self
    }

    /// Sets the maximum number of tries to make before failing.
    pub fn try(mut self, tries: u32) -> Retry<'a, F, G, R> {
        self.tries = Some(tries);

        self
    }

    /// Sets the number of milliseconds to wait between tries.
    ///
    /// Mutually exclusive with `wait_between` and `wait_exponentially`.
    pub fn wait(mut self, wait: u32) -> Retry<'a, F, G, R> {
        self.wait = Wait::Fixed(wait);

        self
    }

    /// Sets a range for a randomly chosen number of milliseconds to wait between tries. A new
    /// random value from the range is chosen for each try.
    ///
    /// Mutually exclusive with `wait` and `wait_exponentially`.
    pub fn wait_between(mut self, min: u32, max: u32) -> Retry<'a, F, G, R> {
        self.wait = Wait::Range(min, max);

        self
    }

    /// Sets a multiplier in milliseconds to use in exponential backoff between tries.
    ///
    /// Mutually exclusive with `wait` and `wait_between`.
    pub fn wait_exponentially(mut self, multiplier: u32) -> Retry<'a, F, G, R> {
        self.wait = Wait::Exponential(multiplier);

        self
    }
}

#[derive(Debug)]
enum Wait {
    Exponential(u32),
    Fixed(u32),
    None,
    Range(u32, u32),
}

/// Invokes a function a certain number of times or until a condition is satisfied with a fixed
/// wait after each unsuccessful try.
pub fn retry<F, G, R>(
    tries: u32,
    wait: u32,
    mut value_fn: F,
    mut condition_fn: G
) -> Result<R, RetryError> where F: FnMut() -> R, G: FnMut(&R) -> bool {
    Retry::new(&mut value_fn, &mut condition_fn).try(tries).wait(wait).execute()
}

/// Invokes a function exponential backoff between tries is satisfied with a fixed
/// wait after each unsuccessful try.
pub fn retry_exponentially<F, G, R>(
    tries: u32,
    wait: u32,
    mut value_fn: F,
    mut condition_fn: G
) -> Result<R, RetryError> where F: FnMut() -> R, G: FnMut(&R) -> bool {
    Retry::new(&mut value_fn, &mut condition_fn).try(tries).wait_exponentially(wait).execute()
}

/// An error indicating that a retry call failed.
#[derive(Debug)]
pub struct RetryError {
    message: &'static str
}

impl Display for RetryError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.message)
    }
}

impl Error for RetryError {
    fn description(&self) -> &str {
        self.message
    }
}

#[cfg(test)]
mod tests {
    use super::{Retry, retry, retry_exponentially};

    #[test]
    fn succeeds_without_try_count() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 5
        ).execute().unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_on_first_try() {
        let value = Retry::new(&mut || 1, &mut |value| *value == 1).try(1).execute().ok().unwrap();

        assert_eq!(value, 1);
    }

    #[test]
    fn requires_non_zero_tries() {
        let error = Retry::new(&mut || 1, &mut |value| *value == 1).try(0).execute().err().unwrap();

        assert_eq!(error.message, "tries must be non-zero");
    }

    #[test]
    fn succeeds_on_subsequent_try() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).try(2).execute().ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let error = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).try(1).execute().err().unwrap();

        assert_eq!(error.message, "reached last try without condition match");
    }

    #[test]
    fn sets_custom_wait_time() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).wait(1).execute().ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn sets_wait_exponentially() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).wait_exponentially(1).execute().ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn retry_function() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(2, 0, || collection.next().unwrap(), |value| *value == 2).ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn retry_exponentially_function() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry_exponentially(2, 0, || collection.next().unwrap(), |value| *value == 2).ok().unwrap();

        assert_eq!(value, 2);
    }
}
<commit_msg>Fix a wrong function description<commit_after>//! Crate retry provides functionality for retrying an operation until its return value satisfies a
//! specific condition.
//!
//! # Usage
//!
//! Retry an operation by calling the `retry` function, supplying a maximum number of times to try,
//! the number of milliseconds to wait after each unsuccessful try, a closure that produces a value,
//! and a closure that takes a reference to that value and returns a boolean indicating the success
//! or failure of the operation. The function will return a `Result` containing either the value
//! that satisfied the condition or an error indicating that a satisfactory value could not be
//! produced.
//!
//! You can also construct a retryable operation incrementally using the `Retry` type. `Retry::new`
//! takes the same two closures as mutable references, and returns a `Retry` value. You can then
//! call the `try` and `wait` methods on this value to add a maximum number of tries and a wait
//! time, respectively. Finally, run the `execute` method to produce the `Result`.
//!
//! If a maximum number of tries is not supplied, the operation will be executed infinitely or until
//! success. If a wait time is not supplied, there will be no wait between attempts.
//!
//! # Failures
//!
//! Retrying will fail when:
//!
//! 1. The operation reaches the maximum number of tries without success.
//! 2. A value of 0 is supplied for the maximum number of tries. It must be at least 1.
//!
//! # Examples
//!
//! Imagine an HTTP API with an endpoint that returns 204 No Content while a job is processing, and
//! eventually 200 OK when the job has completed. Retrying until the job is finished would be
//! written:
//!
//! ```
//! # use retry::retry;
//! # struct Client;
//! # impl Client {
//! #     fn query_job_status(&self) -> Response {
//! #         Response {
//! #             code: 200,
//! #             body: "success",
//! #         }
//! #     }
//! # }
//! # struct Response {
//! #     code: u16,
//! #     body: &'static str,
//! # }
//! # let api_client = Client;
//! match retry(10, 500, || api_client.query_job_status(), |response| response.code == 200) {
//!     Ok(response) => println!("Job completed with result: {}", response.body),
//!     Err(error) => println!("Job completion could not be verified: {}", error),
//! }
//! ```
//!
//!
//! This retries the API call up to 10 times, waiting 500 milliseconds after each unsuccessful
//! attempt. The same result can be achieved by building a `Retry` object incrementally:
//!
//! ```
//! # use retry::Retry;
//! # struct Client;
//! # impl Client {
//! #     fn query_job_status(&self) -> Response {
//! #         Response {
//! #             code: 200,
//! #             body: "success",
//! #         }
//! #     }
//! # }
//! # struct Response {
//! #     code: u16,
//! #     body: &'static str,
//! # }
//! # let api_client = Client;
//! match Retry::new(
//!     &mut || api_client.query_job_status(),
//!     &mut |response| response.code == 200
//! ).try(10).wait(500).execute() {
//!     Ok(response) => println!("Job completed with result: {}", response.body),
//!     Err(error) => println!("Job completion could not be verified: {}", error),
//! }
//! ```

extern crate rand;

use std::error::Error;
use std::fmt::{Display,Formatter};
use std::fmt::Error as FmtError;
use std::thread::sleep_ms;

use rand::distributions::{IndependentSample, Range};
use rand::thread_rng;

/// Builder object for a retryable operation.
#[derive(Debug)]
pub struct Retry<'a, F: FnMut() -> R + 'a, G: FnMut(&R) -> bool + 'a, R> {
    condition_fn: &'a mut G,
    tries: Option<u32>,
    value_fn: &'a mut F,
    timeout: Option<u32>,
    wait: Wait,
}

impl<'a, F: FnMut() -> R, G: FnMut(&R) -> bool, R> Retry<'a, F, G, R> {
    /// Builds a new `Retry` object.
    pub fn new(
        value_fn: &'a mut F,
        condition_fn: &'a mut G
    ) -> Retry<'a, F, G, R> where F: FnMut() -> R, G: FnMut(&R) -> bool {
        Retry {
            condition_fn: condition_fn,
            tries: None,
            value_fn: value_fn,
            wait: Wait::None,
            timeout: None,
        }
    }

    /// Begins executing the retryable operation.
    pub fn execute(self) -> Result<R, RetryError> {
        if self.tries.is_some() && self.tries.unwrap() == 0 {
            return Err(RetryError { message: "tries must be non-zero" });
        }

        let mut try = 0;

        loop {
            if self.tries.is_some() && self.tries.unwrap() == try {
                return Err(RetryError { message: "reached last try without condition match" })
            }

            let value = (self.value_fn)();

            if (self.condition_fn)(&value) {
                return Ok(value);
            }

            match self.wait {
                Wait::Exponential(_multiplier) => {
                    let multiplier = (_multiplier + try) as f64;
                    sleep_ms(multiplier.exp() as u32);
                },
                Wait::Fixed(ms) => sleep_ms(ms),
                Wait::None => {},
                Wait::Range(min, max) => {
                    let range = Range::new(min, max);
                    let mut rng = thread_rng();
                    sleep_ms(range.ind_sample(&mut rng));
                },
            }

            try += 1;
        }
    }

    /// Sets the maximum number of milliseconds retries will be made before failing.
    pub fn timeout(mut self, max: u32) -> Retry<'a, F, G, R> {
        self.timeout = Some(max);

        self
    }

    /// Sets the maximum number of tries to make before failing.
    pub fn try(mut self, tries: u32) -> Retry<'a, F, G, R> {
        self.tries = Some(tries);

        self
    }

    /// Sets the number of milliseconds to wait between tries.
    ///
    /// Mutually exclusive with `wait_between` and `wait_exponentially`.
    pub fn wait(mut self, wait: u32) -> Retry<'a, F, G, R> {
        self.wait = Wait::Fixed(wait);

        self
    }

    /// Sets a range for a randomly chosen number of milliseconds to wait between tries. A new
    /// random value from the range is chosen for each try.
    ///
    /// Mutually exclusive with `wait` and `wait_exponentially`.
    pub fn wait_between(mut self, min: u32, max: u32) -> Retry<'a, F, G, R> {
        self.wait = Wait::Range(min, max);

        self
    }

    /// Sets a multiplier in milliseconds to use in exponential backoff between tries.
    ///
    /// Mutually exclusive with `wait` and `wait_between`.
    pub fn wait_exponentially(mut self, multiplier: u32) -> Retry<'a, F, G, R> {
        self.wait = Wait::Exponential(multiplier);

        self
    }
}

#[derive(Debug)]
enum Wait {
    Exponential(u32),
    Fixed(u32),
    None,
    Range(u32, u32),
}

/// Invokes a function a certain number of times or until a condition is satisfied with a fixed
/// wait after each unsuccessful try.
pub fn retry<F, G, R>(
    tries: u32,
    wait: u32,
    mut value_fn: F,
    mut condition_fn: G
) -> Result<R, RetryError> where F: FnMut() -> R, G: FnMut(&R) -> bool {
    Retry::new(&mut value_fn, &mut condition_fn).try(tries).wait(wait).execute()
}

/// Invokes a function a certain number of times or until a condition is satisfied
/// with an exponential backoff after each unsuccessful try.
pub fn retry_exponentially<F, G, R>(
    tries: u32,
    wait: u32,
    mut value_fn: F,
    mut condition_fn: G
) -> Result<R, RetryError> where F: FnMut() -> R, G: FnMut(&R) -> bool {
    Retry::new(&mut value_fn, &mut condition_fn).try(tries).wait_exponentially(wait).execute()
}

/// An error indicating that a retry call failed.
#[derive(Debug)]
pub struct RetryError {
    message: &'static str
}

impl Display for RetryError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.message)
    }
}

impl Error for RetryError {
    fn description(&self) -> &str {
        self.message
    }
}

#[cfg(test)]
mod tests {
    use super::{Retry, retry, retry_exponentially};

    #[test]
    fn succeeds_without_try_count() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 5
        ).execute().unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_on_first_try() {
        let value = Retry::new(&mut || 1, &mut |value| *value == 1).try(1).execute().ok().unwrap();

        assert_eq!(value, 1);
    }

    #[test]
    fn requires_non_zero_tries() {
        let error = Retry::new(&mut || 1, &mut |value| *value == 1).try(0).execute().err().unwrap();

        assert_eq!(error.message, "tries must be non-zero");
    }

    #[test]
    fn succeeds_on_subsequent_try() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).try(2).execute().ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let error = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).try(1).execute().err().unwrap();

        assert_eq!(error.message, "reached last try without condition match");
    }

    #[test]
    fn sets_custom_wait_time() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).wait(1).execute().ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn sets_wait_exponentially() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).wait_exponentially(1).execute().ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn retry_function() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(2, 0, || collection.next().unwrap(), |value| *value == 2).ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn retry_exponentially_function() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry_exponentially(2, 0, || collection.next().unwrap(), |value| *value == 2).ok().unwrap();

        assert_eq!(value, 2);
    }
}
<|endoftext|>


<commit_before>

extern crate openvr_sys;

pub struct IVRSystem(*const ());

#[derive(Debug, Copy, Clone)]
pub struct Size {
    pub width: u32,
    pub height: u32
}

#[derive(Debug, Copy, Clone)]
pub struct Position {
    pub x: i32,
    pub y: i32
}

#[derive(Debug, Copy, Clone)]
pub struct Rectangle {
    pub position: Position,
    pub size: Size
}

#[derive(Debug, Copy, Clone)]
pub struct DistortionCoordinates {
    pub red: [f32; 2],
    pub green: [f32; 2],
    pub blue: [f32; 2],
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Eye {
    Left, Right
}

impl Eye {
    /// Convert a eye to a HmdEye
    fn to_raw(&self) -> openvr_sys::Hmd_Eye {
        match self {
            &Eye::Left => openvr_sys::Hmd_Eye::Left,
            &Eye::Right => openvr_sys::Hmd_Eye::Right,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TextureBounds {
    u_min: f32,
    u_max: f32,
    v_min: f32,
    v_max: f32
}

impl TextureBounds {
    /// Convert a bounds to a openvr_bounds
    fn to_raw(self) -> openvr_sys::VRTextureBounds_t {
        openvr_sys::VRTextureBounds_t{
            uMin: self.u_min,
            uMax: self.u_max,
            vMin: self.v_min,
            vMax: self.v_max
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePose {
    pub to_device: [[f32; 4]; 3],
    pub velocity: [f32; 3],
    pub angular_velocity: [f32; 3],
    pub is_valid: bool,
    pub is_connected: bool,
}

#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePoses {
    pub count: usize,
    pub poses: [TrackedDevicePose; 16],
}

impl TrackedDevicePoses {
    pub fn as_slice(&self) -> &[TrackedDevicePose] {
        &self.poses[0..self.count]
    }
}

impl IVRSystem {
    /// Initialize the IVR System
    pub fn init() -> Result<IVRSystem, openvr_sys::HmdError> {
        let mut err = openvr_sys::HmdError::None;
        let ptr = unsafe {
            openvr_sys::VR_Init(&mut err as *mut openvr_sys::HmdError)
        };
        if ptr.is_null() {
            Err(err)
        } else {
            Ok(IVRSystem(ptr))
        }
    }

    /// Get the window bounds
    pub fn bounds(&self) -> Rectangle {
        unsafe {
            let mut size = Size{width: 0, height: 0};
            let mut pos = Position{x: 0, y: 0};
            openvr_sys::VR_IVRSystem_GetWindowBounds(
                self.0,
                &mut pos.x,
                &mut pos.y,
                &mut size.width,
                &mut size.height
            );
            Rectangle {
                position: pos,
                size: size
            }
        }
    }

    /// Get the recommended render target size
    pub fn recommended_render_target_size(&self) -> Size {
        unsafe {
            let mut size = Size{width: 0, height: 0};
            openvr_sys::VR_IVRSystem_GetRecommendedRenderTargetSize(
                self.0,
                &mut size.width,
                &mut size.height
            );
            size
        }
    }

    /// Get eye viewport size
    pub fn eye_viewport(&self, eye: Eye) -> Rectangle {
        use std::mem;
        unsafe {
            let mut size = Size{width: 0, height: 0};
            let mut pos = Position{x: 0, y: 0};
            openvr_sys::VR_IVRSystem_GetEyeOutputViewport(
                self.0,
                eye.to_raw(),
                mem::transmute(&mut pos.x),
                mem::transmute(&mut pos.y),
                &mut size.width,
                &mut size.height
            );
            Rectangle {
                position: pos,
                size: size
            }
        }
    }

    /// Get the projection matrix for an eye
    /// supply the near and the far position
    /// assumes opengl conventions
    pub fn projection_matrix(&self, eye: Eye, near: f32, far: f32) -> [[f32; 4]; 4] {
        unsafe {
            let mat = openvr_sys::VR_IVRSystem_GetProjectionMatrix(
                self.0,
                eye.to_raw(),
                near,
                far,
                openvr_sys::GraphicsAPIConvention::OpenGL
            );
            mat.m
        }
    }

    /// Computes the distortion caused by the optics
    pub fn compute_distortion(&self, eye: Eye, u: f32, v: f32) -> DistortionCoordinates {
        unsafe {
            let coord = openvr_sys::VR_IVRSystem_ComputeDistortion(
                self.0,
                eye.to_raw(),
                u, v
            );
            DistortionCoordinates {
                red: coord.rfRed,
                blue: coord.rfBlue,
                green: coord.rfGreen
            }
        }
    }

    /// Computes the distortion caused by the optics
    pub fn eye_to_head_transform(&self, eye: Eye) -> [[f32; 4]; 3] {
        unsafe {
            let mat = openvr_sys::VR_IVRSystem_GetEyeToHeadTransform(
                self.0,
                eye.to_raw(),
            );
            mat.m
        }
    }

    /// Computes the distortion caused by the optics
    pub fn time_since_last_vsync(&self) -> Option<(f32, u64)> {
        unsafe {
            let mut frame = 0;
            let mut sync = 0.;
            let found = openvr_sys::VR_IVRSystem_GetTimeSinceLastVsync(
                self.0,
                &mut sync,
                &mut frame
            );

            if found {
                Some((sync, frame))
            } else {
                None
            }
        }
    }

    /// Fetch the tracked results from the HMD
    pub fn tracked_devices(&self, time: f32) -> TrackedDevicePoses {
        unsafe {
            let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
            openvr_sys::VR_IVRSystem_GetDeviceToAbsoluteTrackingPose(
                self.0,
                openvr_sys::TrackingUniverseOrigin::TrackingUniverseSeated,
                time,
                &mut data[0],
                16
            );

            let mut out: TrackedDevicePoses = std::mem::zeroed();
            for (i, d) in data.iter().enumerate() {
                if d.bDeviceIsConnected {
                    out.count = i + 1;
                }
                out.poses[i].is_connected = d.bDeviceIsConnected;
                out.poses[i].is_valid = d.bPoseIsValid;
                out.poses[i].to_device = d.mDeviceToAbsoluteTracking.m;
                out.poses[i].velocity = d.vVelocity.v;
                out.poses[i].angular_velocity = d.vAngularVelocity.v;
            }

            out
        }
    }

    /// If the device supports a compositor return a instance
    pub fn compositor(&self) -> Result<Compositor, openvr_sys::HmdError> {
        unsafe {
            let mut err = openvr_sys::HmdError::None;
            let name = std::ffi::CString::new("IVRCompositor_006").unwrap();
            let ptr = openvr_sys::VR_GetGenericInterface(name.as_ptr(), &mut err as *mut openvr_sys::HmdError);
            match err {
                openvr_sys::HmdError::None => Ok(Compositor(ptr)),
                err => Err(err)
            }
        }
    }
}

impl Drop for IVRSystem {
    fn drop(&mut self) {
        unsafe {
            println!("Trying to shutdown openvr");
            openvr_sys::VR_Shutdown();
            println!("Should be done now.");
        }
    }
}

/// A VR compositor
pub struct Compositor(*const ());

impl Compositor {
    /// Check to see if the compositor is fullscreen
    pub fn is_fullscreen(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_IsFullscreen(self.0) }
    }

    /// Check if vsync in enabled
    pub fn get_vsync(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_GetVSync(self.0) }
    }

    /// Set the vsync value
    pub fn set_vsync(&self, v: bool) {
        unsafe { openvr_sys::VR_IVRCompositor_SetVSync(self.0, v) }
    }

    /// Check if vsync in enabled
    pub fn can_render_scene(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_CanRenderScene(self.0) }
    }

    /// Get the gamma value
    pub fn get_gamma(&self) -> f32 {
        unsafe { openvr_sys::VR_IVRCompositor_GetGamma(self.0) }
    }

    /// Get the gamma value
    pub fn set_gamma(&self, v: f32) {
        unsafe { openvr_sys::VR_IVRCompositor_SetGamma(self.0, v) }
    }

    /// Set the compositor to gl mode
    pub fn set_graphics_device_gl(&self) {
        unsafe {
            openvr_sys::VR_IVRCompositor_SetGraphicsDevice(
                self.0,
                openvr_sys::Compositor_DeviceType::DeviceType_OpenGL,
                std::ptr::null_mut()
            )
        }
    }

    /// Submit an eye to the render
    pub fn submit(&self, eye: Eye, texture: usize, bounds: TextureBounds) {
        let mut b = bounds.to_raw();
        let e = eye.to_raw();
        unsafe {
            use std::mem;
            let t = mem::transmute(texture);

            openvr_sys::VR_IVRCompositor_Submit(
                self.0,
                e,
                t,
                &mut b as *mut openvr_sys::VRTextureBounds_t
            );
        }
    }

    /// Get the poses
    pub fn wait_get_poses(&self) -> TrackedDevicePoses {
        unsafe {
            let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
            openvr_sys::VR_IVRCompositor_WaitGetPoses(
                self.0,
                &mut data[0],
                16,
                std::ptr::null_mut(),
                0
            );

            let mut out: TrackedDevicePoses = std::mem::zeroed();
            for (i, d) in data.iter().enumerate() {
                if d.bDeviceIsConnected {
                    out.count = i + 1;
                }
                out.poses[i].is_connected = d.bDeviceIsConnected;
                out.poses[i].is_valid = d.bPoseIsValid;
                out.poses[i].to_device = d.mDeviceToAbsoluteTracking.m;
                out.poses[i].velocity = d.vVelocity.v;
                out.poses[i].angular_velocity = d.vAngularVelocity.v;
            }

            out
        }
    }
}
<commit_msg>export u/v/max/min for TextureBounds<commit_after>

extern crate openvr_sys;

pub struct IVRSystem(*const ());

#[derive(Debug, Copy, Clone)]
pub struct Size {
    pub width: u32,
    pub height: u32
}

#[derive(Debug, Copy, Clone)]
pub struct Position {
    pub x: i32,
    pub y: i32
}

#[derive(Debug, Copy, Clone)]
pub struct Rectangle {
    pub position: Position,
    pub size: Size
}

#[derive(Debug, Copy, Clone)]
pub struct DistortionCoordinates {
    pub red: [f32; 2],
    pub green: [f32; 2],
    pub blue: [f32; 2],
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Eye {
    Left, Right
}

impl Eye {
    /// Convert a eye to a HmdEye
    fn to_raw(&self) -> openvr_sys::Hmd_Eye {
        match self {
            &Eye::Left => openvr_sys::Hmd_Eye::Left,
            &Eye::Right => openvr_sys::Hmd_Eye::Right,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TextureBounds {
    pub u_min: f32,
    pub u_max: f32,
    pub v_min: f32,
    pub v_max: f32
}

impl TextureBounds {
    /// Convert a bounds to a openvr_bounds
    fn to_raw(self) -> openvr_sys::VRTextureBounds_t {
        openvr_sys::VRTextureBounds_t{
            uMin: self.u_min,
            uMax: self.u_max,
            vMin: self.v_min,
            vMax: self.v_max
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePose {
    pub to_device: [[f32; 4]; 3],
    pub velocity: [f32; 3],
    pub angular_velocity: [f32; 3],
    pub is_valid: bool,
    pub is_connected: bool,
}

#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePoses {
    pub count: usize,
    pub poses: [TrackedDevicePose; 16],
}

impl TrackedDevicePoses {
    pub fn as_slice(&self) -> &[TrackedDevicePose] {
        &self.poses[0..self.count]
    }
}

impl IVRSystem {
    /// Initialize the IVR System
    pub fn init() -> Result<IVRSystem, openvr_sys::HmdError> {
        let mut err = openvr_sys::HmdError::None;
        let ptr = unsafe {
            openvr_sys::VR_Init(&mut err as *mut openvr_sys::HmdError)
        };
        if ptr.is_null() {
            Err(err)
        } else {
            Ok(IVRSystem(ptr))
        }
    }

    /// Get the window bounds
    pub fn bounds(&self) -> Rectangle {
        unsafe {
            let mut size = Size{width: 0, height: 0};
            let mut pos = Position{x: 0, y: 0};
            openvr_sys::VR_IVRSystem_GetWindowBounds(
                self.0,
                &mut pos.x,
                &mut pos.y,
                &mut size.width,
                &mut size.height
            );
            Rectangle {
                position: pos,
                size: size
            }
        }
    }

    /// Get the recommended render target size
    pub fn recommended_render_target_size(&self) -> Size {
        unsafe {
            let mut size = Size{width: 0, height: 0};
            openvr_sys::VR_IVRSystem_GetRecommendedRenderTargetSize(
                self.0,
                &mut size.width,
                &mut size.height
            );
            size
        }
    }

    /// Get eye viewport size
    pub fn eye_viewport(&self, eye: Eye) -> Rectangle {
        use std::mem;
        unsafe {
            let mut size = Size{width: 0, height: 0};
            let mut pos = Position{x: 0, y: 0};
            openvr_sys::VR_IVRSystem_GetEyeOutputViewport(
                self.0,
                eye.to_raw(),
                mem::transmute(&mut pos.x),
                mem::transmute(&mut pos.y),
                &mut size.width,
                &mut size.height
            );
            Rectangle {
                position: pos,
                size: size
            }
        }
    }

    /// Get the projection matrix for an eye
    /// supply the near and the far position
    /// assumes opengl conventions
    pub fn projection_matrix(&self, eye: Eye, near: f32, far: f32) -> [[f32; 4]; 4] {
        unsafe {
            let mat = openvr_sys::VR_IVRSystem_GetProjectionMatrix(
                self.0,
                eye.to_raw(),
                near,
                far,
                openvr_sys::GraphicsAPIConvention::OpenGL
            );
            mat.m
        }
    }

    /// Computes the distortion caused by the optics
    pub fn compute_distortion(&self, eye: Eye, u: f32, v: f32) -> DistortionCoordinates {
        unsafe {
            let coord = openvr_sys::VR_IVRSystem_ComputeDistortion(
                self.0,
                eye.to_raw(),
                u, v
            );
            DistortionCoordinates {
                red: coord.rfRed,
                blue: coord.rfBlue,
                green: coord.rfGreen
            }
        }
    }

    /// Computes the distortion caused by the optics
    pub fn eye_to_head_transform(&self, eye: Eye) -> [[f32; 4]; 3] {
        unsafe {
            let mat = openvr_sys::VR_IVRSystem_GetEyeToHeadTransform(
                self.0,
                eye.to_raw(),
            );
            mat.m
        }
    }

    /// Computes the distortion caused by the optics
    pub fn time_since_last_vsync(&self) -> Option<(f32, u64)> {
        unsafe {
            let mut frame = 0;
            let mut sync = 0.;
            let found = openvr_sys::VR_IVRSystem_GetTimeSinceLastVsync(
                self.0,
                &mut sync,
                &mut frame
            );

            if found {
                Some((sync, frame))
            } else {
                None
            }
        }
    }

    /// Fetch the tracked results from the HMD
    pub fn tracked_devices(&self, time: f32) -> TrackedDevicePoses {
        unsafe {
            let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
            openvr_sys::VR_IVRSystem_GetDeviceToAbsoluteTrackingPose(
                self.0,
                openvr_sys::TrackingUniverseOrigin::TrackingUniverseSeated,
                time,
                &mut data[0],
                16
            );

            let mut out: TrackedDevicePoses = std::mem::zeroed();
            for (i, d) in data.iter().enumerate() {
                if d.bDeviceIsConnected {
                    out.count = i + 1;
                }
                out.poses[i].is_connected = d.bDeviceIsConnected;
                out.poses[i].is_valid = d.bPoseIsValid;
                out.poses[i].to_device = d.mDeviceToAbsoluteTracking.m;
                out.poses[i].velocity = d.vVelocity.v;
                out.poses[i].angular_velocity = d.vAngularVelocity.v;
            }

            out
        }
    }

    /// If the device supports a compositor return a instance
    pub fn compositor(&self) -> Result<Compositor, openvr_sys::HmdError> {
        unsafe {
            let mut err = openvr_sys::HmdError::None;
            let name = std::ffi::CString::new("IVRCompositor_006").unwrap();
            let ptr = openvr_sys::VR_GetGenericInterface(name.as_ptr(), &mut err as *mut openvr_sys::HmdError);
            match err {
                openvr_sys::HmdError::None => Ok(Compositor(ptr)),
                err => Err(err)
            }
        }
    }
}

impl Drop for IVRSystem {
    fn drop(&mut self) {
        unsafe {
            println!("Trying to shutdown openvr");
            openvr_sys::VR_Shutdown();
            println!("Should be done now.");
        }
    }
}

/// A VR compositor
pub struct Compositor(*const ());

impl Compositor {
    /// Check to see if the compositor is fullscreen
    pub fn is_fullscreen(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_IsFullscreen(self.0) }
    }

    /// Check if vsync in enabled
    pub fn get_vsync(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_GetVSync(self.0) }
    }

    /// Set the vsync value
    pub fn set_vsync(&self, v: bool) {
        unsafe { openvr_sys::VR_IVRCompositor_SetVSync(self.0, v) }
    }

    /// Check if vsync in enabled
    pub fn can_render_scene(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_CanRenderScene(self.0) }
    }

    /// Get the gamma value
    pub fn get_gamma(&self) -> f32 {
        unsafe { openvr_sys::VR_IVRCompositor_GetGamma(self.0) }
    }

    /// Get the gamma value
    pub fn set_gamma(&self, v: f32) {
        unsafe { openvr_sys::VR_IVRCompositor_SetGamma(self.0, v) }
    }

    /// Set the compositor to gl mode
    pub fn set_graphics_device_gl(&self) {
        unsafe {
            openvr_sys::VR_IVRCompositor_SetGraphicsDevice(
                self.0,
                openvr_sys::Compositor_DeviceType::DeviceType_OpenGL,
                std::ptr::null_mut()
            )
        }
    }

    /// Submit an eye to the render
    pub fn submit(&self, eye: Eye, texture: usize, bounds: TextureBounds) {
        let mut b = bounds.to_raw();
        let e = eye.to_raw();
        unsafe {
            use std::mem;
            let t = mem::transmute(texture);

            openvr_sys::VR_IVRCompositor_Submit(
                self.0,
                e,
                t,
                &mut b as *mut openvr_sys::VRTextureBounds_t
            );
        }
    }

    /// Get the poses
    pub fn wait_get_poses(&self) -> TrackedDevicePoses {
        unsafe {
            let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
            openvr_sys::VR_IVRCompositor_WaitGetPoses(
                self.0,
                &mut data[0],
                16,
                std::ptr::null_mut(),
                0
            );

            let mut out: TrackedDevicePoses = std::mem::zeroed();
            for (i, d) in data.iter().enumerate() {
                if d.bDeviceIsConnected {
                    out.count = i + 1;
                }
                out.poses[i].is_connected = d.bDeviceIsConnected;
                out.poses[i].is_valid = d.bPoseIsValid;
                out.poses[i].to_device = d.mDeviceToAbsoluteTracking.m;
                out.poses[i].velocity = d.vVelocity.v;
                out.poses[i].angular_velocity = d.vAngularVelocity.v;
            }

            out
        }
    }
}
<|endoftext|>


<commit_before>// Copyright(C) 2016 Chris Liebert
#![crate_type = "lib"]
#![crate_name = "quick_3d"]
#[macro_use]
extern crate glium;

pub mod common;

pub mod loader;
#[macro_use]
pub mod renderer;

#[cfg(test)]
mod tests {
    use glium::glutin;
    use glium::backend::glutin_backend::GlutinFacade;
    use glium::DisplayBuild;
    use loader;
    use common::Scene;
    use renderer;

    fn create_test_display() -> GlutinFacade {
        let display = glutin::WindowBuilder::new()
            .with_visibility(false)
            .with_gl_debug_flag(true)
            .build_glium()
            .unwrap();
        return display;
    }

    fn load_test_scene() -> Scene {
        loader::load_db("test.db")
    }

    #[test]
    fn loader_load_db_not_empty() {
        println!("Running loader_load_db_not_empty test");
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
        assert!(scene.shaders.len() > 0);
    }

    #[test]
    fn load_and_render_db() {
        println!("Running load_and_render_db test");
        let display = create_test_display();
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
        assert!(scene.shaders.len() > 0);
        let renderer: renderer::Renderer = renderer::Renderer::new(&display, scene);
        renderer.render(&display);
    }
}
<commit_msg>updated unit tests so they would compile<commit_after>// Copyright(C) 2016 Chris Liebert
#![crate_type = "lib"]
#![crate_name = "quick_3d"]
#[macro_use]
extern crate glium;

pub mod common;

pub mod loader;
#[macro_use]
pub mod renderer;

#[cfg(test)]
mod tests {
    use glium::glutin;
    use glium::backend::glutin_backend::GlutinFacade;
    use glium::DisplayBuild;
    use loader;
    use common::Scene;
    use renderer;

    fn create_test_display() -> GlutinFacade {
        let display = glutin::WindowBuilder::new()
            .with_visibility(false)
            .with_gl_debug_flag(true)
            .build_glium()
            .unwrap();
        return display;
    }

    fn load_test_scene() -> Scene {
        let dbloader: loader::DBLoader = loader::DBLoader::new("test.db");
        return dbloader.load_scene();
    }

    #[test]
    fn loader_load_db_not_empty() {
        println!("Running loader_load_db_not_empty test");
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
        // assert!(scene.shaders.len() > 0);
    }

    #[test]
    fn load_and_render_db() {
        println!("Running load_and_render_db test");
        let display = create_test_display();
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
        // assert!(scene.shaders.len() > 0);
        // let renderer: renderer::Renderer = renderer::Renderer::new(&display, scene);
        // renderer.render(&display);
    }
}
<|endoftext|>