<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 random number generator of the operating system.
//!
//! # Platform sources
//!
//! | OS               | interface
//! |------------------|---------------------------------------------------------
//! | Linux, Android   | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
//! | Windows          | [`RtlGenRandom`][3]
//! | macOS            | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS              | [`SecRandomCopyBytes`][4]
//! | FreeBSD          | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
//! | OpenBSD          | [`getentropy`][6]
//! | NetBSD           | [`kern.arandom`][7]
//! | Dragonfly BSD    | [`/dev/random`][8]
//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
//! | Fuchsia OS       | [`cprng_draw`][11]
//! | Redox            | [`rand:`][12]
//! | CloudABI         | [`cloudabi_sys_random_get`][13]
//! | Haiku            | `/dev/random` (identical to `/dev/urandom`)
//! | L4RE, SGX, UEFI  | [RDRAND][18]
//! | Hermit           | [RDRAND][18] as [`sys_rand`][22] is currently broken.
//! | VxWorks          | `randABytes` after checking entropy pool initialization with `randSecure`
//! | Web browsers     | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and asm.js][16])
//! | Node.js          | [`crypto.randomBytes`][15] (see [Support for WebAssembly and asm.js][16])
//! | WASI             | [`__wasi_random_get`][17]
//!
//! Getrandom doesn't have a blanket implementation for all Unix-like operating
//! systems that reads from `/dev/urandom`. This ensures all supported operating
//! systems are using the recommended interface and respect maximum buffer
//! sizes.
//!
//! ## Unsupported targets
//!
//! By default, compiling `getrandom` for an unsupported target will result in
//! a compilation error. If you want to build an application which uses `getrandom`
//! for such target, you can either:
//! - Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml`
//! to switch to a custom implementation with a support of your target.
//!
//! [replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section
//! [patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section
//!
//! ## Support for WebAssembly and asm.js
//!
//! Getrandom supports all of Rust's current `wasm32` targets, and it works with
//! both Node.js and web browsers. The three Emscripten targets
//! `asmjs-unknown-emscripten`, `wasm32-unknown-emscripten`, and
//! `wasm32-experimental-emscripten` use Emscripten's `/dev/random` emulation.
//! The WASI target `wasm32-wasi` uses the [`__wasi_random_get`][17] function
//! defined by the WASI standard.
//!
//! Getrandom also supports `wasm32-unknown-unknown` by directly calling
//! JavaScript methods. Rust currently has two ways to do this: [bindgen] and
//! [stdweb]. Getrandom supports using either one by enabling the
//! `wasm-bindgen` or `stdweb` crate features. Note that if both features are
//! enabled, `wasm-bindgen` will be used. If neither feature is enabled, calls
//! to `getrandom` will always fail at runtime.
//!
//! [bindgen]: https://github.com/rust-lang/rust-bindgen
//! [stdweb]: https://github.com/koute/stdweb
//!
//! ## Early boot
//!
//! It is possible that early in the boot process the OS hasn't had enough time
//! yet to collect entropy to securely seed its RNG, especially on virtual
//! machines.
//!
//! Some operating systems always block the thread until the RNG is securely
//! seeded. This can take anywhere from a few seconds to more than a minute.
//! Others make a best effort to use a seed from before the shutdown and don't
//! document much.
//!
//! 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) and on NetBSD
//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected
//! enough entropy yet. To avoid returning low-entropy bytes, we first read from
//! `/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.
//!
//! On unsupported platforms, `getrandom` always fails. See the [`Error`] type
//! for more information on what data is returned on failure.
//!
//! [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/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//! [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
//! [13]: https://github.com/nuxinl/cloudabi#random_get
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [16]: #support-for-webassembly-and-asmjs
//! [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
//! [22]: https://github.com/hermitcore/libhermit-rs/blob/09c38b0371cee6f56a541400ba453e319e43db53/src/syscalls/random.rs#L21

#![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://rust-random.github.io/rand/"
)]
#![no_std]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]

#[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 = "cloudabi")] {
        #[path = "cloudabi.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(all(windows, getrandom_uwp))] {
        #[path = "windows_uwp.rs"] mod imp;
    } else if #[cfg(windows)] {
        #[path = "windows.rs"] mod imp;
    } else if #[cfg(all(target_arch = "x86_64", any(
                  target_os = "hermit",
                  target_os = "l4re",
                  target_os = "uefi",
                  target_env = "sgx",
              )))] {
        #[path = "rdrand.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>target: Drop support for some x86_64 targets<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 random number generator of the operating system.
//!
//! # Platform sources
//!
//! | OS               | interface
//! |------------------|---------------------------------------------------------
//! | Linux, Android   | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
//! | Windows          | [`RtlGenRandom`][3]
//! | macOS            | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS              | [`SecRandomCopyBytes`][4]
//! | FreeBSD          | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
//! | OpenBSD          | [`getentropy`][6]
//! | NetBSD           | [`kern.arandom`][7]
//! | Dragonfly BSD    | [`/dev/random`][8]
//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
//! | Fuchsia OS       | [`cprng_draw`][11]
//! | Redox            | [`rand:`][12]
//! | CloudABI         | [`cloudabi_sys_random_get`][13]
//! | Haiku            | `/dev/random` (identical to `/dev/urandom`)
//! | SGX              | [RDRAND][18]
//! | VxWorks          | `randABytes` after checking entropy pool initialization with `randSecure`
//! | Web browsers     | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and asm.js][16])
//! | Node.js          | [`crypto.randomBytes`][15] (see [Support for WebAssembly and asm.js][16])
//! | WASI             | [`__wasi_random_get`][17]
//!
//! Getrandom doesn't have a blanket implementation for all Unix-like operating
//! systems that reads from `/dev/urandom`. This ensures all supported operating
//! systems are using the recommended interface and respect maximum buffer
//! sizes.
//!
//! ## Unsupported targets
//!
//! By default, compiling `getrandom` for an unsupported target will result in
//! a compilation error. If you want to build an application which uses `getrandom`
//! for such target, you can either:
//! - Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml`
//! to switch to a custom implementation with a support of your target.
//!
//! [replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section
//! [patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section
//!
//! ## Support for WebAssembly and asm.js
//!
//! Getrandom supports all of Rust's current `wasm32` targets, and it works with
//! both Node.js and web browsers. The three Emscripten targets
//! `asmjs-unknown-emscripten`, `wasm32-unknown-emscripten`, and
//! `wasm32-experimental-emscripten` use Emscripten's `/dev/random` emulation.
//! The WASI target `wasm32-wasi` uses the [`__wasi_random_get`][17] function
//! defined by the WASI standard.
//!
//! Getrandom also supports `wasm32-unknown-unknown` by directly calling
//! JavaScript methods. Rust currently has two ways to do this: [bindgen] and
//! [stdweb]. Getrandom supports using either one by enabling the
//! `wasm-bindgen` or `stdweb` crate features. Note that if both features are
//! enabled, `wasm-bindgen` will be used. If neither feature is enabled, calls
//! to `getrandom` will always fail at runtime.
//!
//! [bindgen]: https://github.com/rust-lang/rust-bindgen
//! [stdweb]: https://github.com/koute/stdweb
//!
//! ## Early boot
//!
//! It is possible that early in the boot process the OS hasn't had enough time
//! yet to collect entropy to securely seed its RNG, especially on virtual
//! machines.
//!
//! Some operating systems always block the thread until the RNG is securely
//! seeded. This can take anywhere from a few seconds to more than a minute.
//! Others make a best effort to use a seed from before the shutdown and don't
//! document much.
//!
//! 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) and on NetBSD
//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected
//! enough entropy yet. To avoid returning low-entropy bytes, we first read from
//! `/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.
//!
//! On unsupported platforms, `getrandom` always fails. See the [`Error`] type
//! for more information on what data is returned on failure.
//!
//! [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/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//! [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
//! [13]: https://github.com/nuxinl/cloudabi#random_get
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [16]: #support-for-webassembly-and-asmjs
//! [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://rust-random.github.io/rand/"
)]
#![no_std]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]

#[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 = "cloudabi")] {
        #[path = "cloudabi.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(all(windows, getrandom_uwp))] {
        #[path = "windows_uwp.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(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>//! Struct and methods for union-find operation.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

use std::{mem, usize};
use std::iter::FromIterator;

#[derive(Clone, Show)]
enum UFNode<T> {
    Key(usize),
    Value(T)
}

impl<T> UFNode<T> {
    fn value(&self) -> &T {
        match self {
            &UFNode::Value(ref val) => val,
            &UFNode::Key(_) => panic!()
        }
    }
    fn unwrap_value(self) -> T {
        match self {
            UFNode::Value(val) => val,
            UFNode::Key(_) => panic!()
        }
    }
}

/// The value that can be contained with `UFValue`.
pub trait UFValue: Sized {
    /// Initialize the value.
    fn init(key: usize) -> Self;

    /// Merge two value into one.
    ///
    /// This is used by `UnionFind::union` operation.
    fn merge(lval: Self, rval: Self) -> Merge<Self>;
}

/// Return value of the `UFValue::merege`
#[allow(missing_docs)]
pub enum Merge<T> {
    Left(T), Right(T)
}

/// Reperesents the size of the group.
#[derive(Copy, Clone, Show, Eq, PartialEq, Ord, PartialOrd)]
pub struct Size(usize);

impl UFValue for Size {
    fn init(_key: usize) -> Size { Size(1) }
    fn merge(Size(lval): Size, Size(rval): Size) -> Merge<Size> {
        if lval >= rval {
            Merge::Left(Size(lval + rval))
        } else {
            Merge::Right(Size(lval + rval))
        }
    }
}

/// Struct for union-find operation.
#[derive(Clone, Show)]
pub struct UnionFind<V = Size> {
    data: Vec<UFNode<V>>
}

impl<T: UFValue = Size> UnionFind<T> {
    /// Creates empty `UnionFind` struct.
    #[inline]
    pub fn new(len: usize) -> UnionFind<T> {
        let data = (0 .. len).map(UFValue::init).map(UFNode::Value).collect();
        UnionFind { data: data }
    }

    /// Join two sets that contains given keys (Union operation).
    ///
    /// Returns `true` if these keys are belonged to different sets.
    #[inline]
    pub fn union(&mut self, key0: usize, key1: usize) -> bool {
        let k0 = self.get_key(key0);
        let k1 = self.get_key(key1);
        if k0 == k1 { return false; }

        // Temporary replace with dummy to move out the elements of the vector.
        let v0 = mem::replace(&mut self.data[k0], UFNode::Key(usize::MAX)).unwrap_value();
        let v1 = mem::replace(&mut self.data[k1], UFNode::Key(usize::MAX)).unwrap_value();

        match UFValue::merge(v0, v1) {
            Merge::Left(val) => {
                self.data[k0] = UFNode::Value(val);
                self.data[k1] = UFNode::Key(k0);
            }
            Merge::Right(val) => {
                self.data[k1] = UFNode::Value(val);
                self.data[k0] = UFNode::Key(k1);
            }
        }

        true
    }

    /// Returns `true` if two keys contained by the same set (find operation).
    #[inline]
    pub fn find(&mut self, key0: usize, key1: usize) -> bool {
         self.get_key(key0) == self.get_key(key1)
    }

    /// Returns the number of the elements that belongs to the same set with key.
    #[inline]
    pub fn get_value(&mut self, key: usize) -> &T {
        let root_key = self.get_key(key);
        self.data[root_key].value()
    }

    fn get_key(&mut self, key: usize) -> usize {
        let root_key = match self.data[key] {
            UFNode::Value(_) => return key,
            UFNode::Key(key) => self.get_key(key)
        };

        self.data[key] = UFNode::Key(root_key);
        root_key
    }
}

impl<T: UFValue> FromIterator<T> for UnionFind<T> {
    /// Creates `UnionFind` struct from iterator.
    #[inline]
    fn from_iter<I: Iterator<Item = T>>(iterator: I) -> UnionFind<T> {
        UnionFind { data: iterator.map(UFNode::Value).collect() }
    }
}

#[cfg(test)]
mod tests {
    use super::{UnionFind, Size};

    #[test]
    fn test_union_find() {
        let mut uf = UnionFind::new(100);
        assert_eq!(&Size(1), uf.get_value(0));
        assert_eq!(&Size(1), uf.get_value(1));
        assert!(!uf.find(0, 1));
        assert!(!uf.find(1, 2));
        assert!(uf.union(0, 1));
        assert!(uf.find(0, 1));
        assert_eq!(&Size(2), uf.get_value(0));
        assert_eq!(&Size(2), uf.get_value(1));
        assert_eq!(&Size(1), uf.get_value(2));
        assert!(!uf.union(0, 1));
        assert_eq!(&Size(2), uf.get_value(0));
        assert_eq!(&Size(2), uf.get_value(1));
        assert_eq!(&Size(1), uf.get_value(2));
        assert!(uf.union(1, 2));
        assert_eq!(&Size(3), uf.get_value(0));
        assert_eq!(&Size(3), uf.get_value(1));
        assert_eq!(&Size(3), uf.get_value(2));
        assert!(uf.find(0, 1));
        assert!(uf.find(2, 1));
    }
}
<commit_msg>rename `UnionFind::get_value` -> `UnionFind::get`<commit_after>//! Struct and methods for union-find operation.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

use std::{mem, usize};
use std::iter::FromIterator;

#[derive(Clone, Show)]
enum UFNode<T> {
    Key(usize),
    Value(T)
}

impl<T> UFNode<T> {
    fn get(&self) -> &T {
        match self {
            &UFNode::Value(ref val) => val,
            &UFNode::Key(_) => panic!()
        }
    }
    fn unwrap_value(self) -> T {
        match self {
            UFNode::Value(val) => val,
            UFNode::Key(_) => panic!()
        }
    }
}

/// The value that can be contained with `UFValue`.
pub trait UFValue: Sized {
    /// Initialize the value.
    fn init(key: usize) -> Self;

    /// Merge two value into one.
    ///
    /// This is used by `UnionFind::union` operation.
    fn merge(lval: Self, rval: Self) -> Merge<Self>;
}

/// Return value of the `UFValue::merege`
#[allow(missing_docs)]
pub enum Merge<T> {
    Left(T), Right(T)
}

/// Reperesents the size of the group.
#[derive(Copy, Clone, Show, Eq, PartialEq, Ord, PartialOrd)]
pub struct Size(usize);

impl UFValue for Size {
    fn init(_key: usize) -> Size { Size(1) }
    fn merge(Size(lval): Size, Size(rval): Size) -> Merge<Size> {
        if lval >= rval {
            Merge::Left(Size(lval + rval))
        } else {
            Merge::Right(Size(lval + rval))
        }
    }
}

/// Struct for union-find operation.
#[derive(Clone, Show)]
pub struct UnionFind<V = Size> {
    data: Vec<UFNode<V>>
}

impl<T: UFValue = Size> UnionFind<T> {
    /// Creates empty `UnionFind` struct.
    #[inline]
    pub fn new(len: usize) -> UnionFind<T> {
        let data = (0 .. len).map(UFValue::init).map(UFNode::Value).collect();
        UnionFind { data: data }
    }

    /// Join two sets that contains given keys (Union operation).
    ///
    /// Returns `true` if these keys are belonged to different sets.
    #[inline]
    pub fn union(&mut self, key0: usize, key1: usize) -> bool {
        let k0 = self.get_key(key0);
        let k1 = self.get_key(key1);
        if k0 == k1 { return false; }

        // Temporary replace with dummy to move out the elements of the vector.
        let v0 = mem::replace(&mut self.data[k0], UFNode::Key(usize::MAX)).unwrap_value();
        let v1 = mem::replace(&mut self.data[k1], UFNode::Key(usize::MAX)).unwrap_value();

        match UFValue::merge(v0, v1) {
            Merge::Left(val) => {
                self.data[k0] = UFNode::Value(val);
                self.data[k1] = UFNode::Key(k0);
            }
            Merge::Right(val) => {
                self.data[k1] = UFNode::Value(val);
                self.data[k0] = UFNode::Key(k1);
            }
        }

        true
    }

    /// Returns `true` if two keys contained by the same set (find operation).
    #[inline]
    pub fn find(&mut self, key0: usize, key1: usize) -> bool {
         self.get_key(key0) == self.get_key(key1)
    }

    /// Returns the reference to the value of the set that the key belongs to.
    #[inline]
    pub fn get(&mut self, key: usize) -> &T {
        let root_key = self.get_key(key);
        self.data[root_key].get()
    }

    fn get_key(&mut self, key: usize) -> usize {
        let root_key = match self.data[key] {
            UFNode::Value(_) => return key,
            UFNode::Key(key) => self.get_key(key)
        };

        self.data[key] = UFNode::Key(root_key);
        root_key
    }
}

impl<T: UFValue> FromIterator<T> for UnionFind<T> {
    /// Creates `UnionFind` struct from iterator.
    #[inline]
    fn from_iter<I: Iterator<Item = T>>(iterator: I) -> UnionFind<T> {
        UnionFind { data: iterator.map(UFNode::Value).collect() }
    }
}

#[cfg(test)]
mod tests {
    use super::{UnionFind, Size};

    #[test]
    fn test_union_find() {
        let mut uf = UnionFind::new(100);
        assert_eq!(&Size(1), uf.get(0));
        assert_eq!(&Size(1), uf.get(1));
        assert!(!uf.find(0, 1));
        assert!(!uf.find(1, 2));
        assert!(uf.union(0, 1));
        assert!(uf.find(0, 1));
        assert_eq!(&Size(2), uf.get(0));
        assert_eq!(&Size(2), uf.get(1));
        assert_eq!(&Size(1), uf.get(2));
        assert!(!uf.union(0, 1));
        assert_eq!(&Size(2), uf.get(0));
        assert_eq!(&Size(2), uf.get(1));
        assert_eq!(&Size(1), uf.get(2));
        assert!(uf.union(1, 2));
        assert_eq!(&Size(3), uf.get(0));
        assert_eq!(&Size(3), uf.get(1));
        assert_eq!(&Size(3), uf.get(2));
        assert!(uf.find(0, 1));
        assert!(uf.find(2, 1));
    }
}
<|endoftext|>


<commit_before>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

// To avoid rather annoying warnings when matching with CXCursor_xxx as a
// constant.
#![allow(non_upper_case_globals)]

extern crate syntex_syntax as syntax;
extern crate aster;
extern crate quasi;
extern crate clang_sys;
extern crate libc;
extern crate regex;
#[macro_use]
extern crate log;

mod clangll;
mod clang;
mod ir;
mod parse;
mod regex_set;
mod codegen {
    include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
}

use std::borrow::Borrow;
use std::io::{self, Write};
use std::fs::OpenOptions;
use std::path::Path;
use std::collections::HashSet;

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use ir::context::BindgenContext;
use ir::item::{Item, ItemId};
use parse::{ClangItemParser, ParseError};
use regex_set::RegexSet;

#[derive(Debug,Default)]
pub struct Builder {
    options: BindgenOptions,
}

pub fn builder() -> Builder {
    Default::default()
}

impl Builder {
    pub fn header<T: Into<String>>(self, header: T) -> Builder {
        self.clang_arg(header)
    }

    pub fn hide_type<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.hidden_types.insert(arg.into());
        self
    }

    pub fn opaque_type<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.opaque_types.insert(arg.into());
        self
    }

    pub fn whitelisted_type<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_types.insert(&arg);
        self
    }

    pub fn whitelisted_function<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_functions.insert(&arg);
        self
    }

    pub fn whitelisted_var<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_vars.insert(&arg);
        self
    }

    pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.raw_lines.push(arg.into());
        self
    }

    pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.clang_args.push(arg.into());
        self
    }

    pub fn link<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Default));
        self
    }

    pub fn link_static<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Static));
        self
    }

    pub fn link_framework<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Framework));
        self
    }

    pub fn dtor_attr<T: Into<String>>(mut self, attr: T) -> Builder {
        self.options.dtor_attrs.push(attr.into());
        self
    }

    pub fn forbid_unknown_types(mut self) -> Builder {
        self.options.fail_on_unknown_type = true;
        self
    }

    pub fn emit_builtins(mut self) -> Builder {
        self.options.builtins = true;
        self
    }

    pub fn no_bitfield_methods(mut self) -> Builder {
        self.options.gen_bitfield_methods = false;
        self
    }

    pub fn no_unstable_rust(mut self) -> Builder {
        self.options.unstable_rust = false;
        self
    }
    pub fn rust_enums(mut self, value: bool) -> Builder {
        self.options.rust_enums = value;
        self
    }

    pub fn rename_types(mut self, value: bool) -> Builder {
        self.options.rename_types = value;
        self
    }

    pub fn disable_class_constants(mut self) -> Builder {
        self.options.class_constants = false;
        self
    }

    pub fn generate(self) -> Result<Bindings, ()> {
        Bindings::generate(self.options, None)
    }
}

/// Deprecated - use a `Builder` instead
#[derive(Debug)]
pub struct BindgenOptions {
    pub hidden_types: HashSet<String>,
    pub opaque_types: HashSet<String>,
    pub whitelisted_types: RegexSet,
    pub whitelisted_functions: RegexSet,
    pub whitelisted_vars: RegexSet,
    pub builtins: bool,
    pub rust_enums: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub ignore_functions: bool,
    pub ignore_methods: bool,
    pub gen_bitfield_methods: bool,
    pub fail_on_unknown_type: bool,
    pub enable_cxx_namespaces: bool,
    pub rename_types: bool,
    pub derive_debug: bool,
    /// Generate or not only stable rust.
    pub unstable_rust: bool,
    /// Whether to generate C++ class constants.
    pub class_constants: bool,
    /// Wether to generate names that are **directly** under namespaces.
    pub namespaced_constants: bool,
    /// Whether to use msvc mangling rules
    pub msvc_mangling: bool,
    pub override_enum_ty: String,
    pub raw_lines: Vec<String>,
    /// Attributes for a type with destructor
    pub dtor_attrs: Vec<String>,
    pub clang_args: Vec<String>,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        BindgenOptions {
            hidden_types: Default::default(),
            opaque_types: Default::default(),
            whitelisted_types: Default::default(),
            whitelisted_functions: Default::default(),
            whitelisted_vars: Default::default(),
            builtins: false,
            rust_enums: true,
            links: vec![],
            emit_ast: false,
            ignore_functions: false,
            ignore_methods: false,
            gen_bitfield_methods: true,
            fail_on_unknown_type: true,
            rename_types: true,
            derive_debug: true,
            enable_cxx_namespaces: false,
            override_enum_ty: "".to_string(),
            unstable_rust: true,
            class_constants: true,
            namespaced_constants: true,
            msvc_mangling: false,
            raw_lines: vec![],
            dtor_attrs: vec![],
            clang_args: vec![],
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    Default,
    Static,
    Framework
}

#[derive(Debug, Clone)]
pub struct Bindings {
    module: ast::Mod,
    raw_lines: Vec<String>,
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    pub fn generate(options: BindgenOptions, span: Option<Span>) -> Result<Bindings, ()> {
        let span = span.unwrap_or(DUMMY_SP);

        let mut context = BindgenContext::new(options);
        parse(&mut context);

        let module = ast::Mod {
            inner: span,
            items: codegen::codegen(&mut context),
        };

        Ok(Bindings {
            module: module,
            raw_lines: context.options().raw_lines.clone(),
        })
    }

    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    pub fn to_string(&self) -> String {
        let mut mod_str = vec![];
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    // https://github.com/Manishearth/rust-clippy/issues/740
    #[cfg_attr(feature = "clippy", allow(needless_lifetimes))]
    pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));

        for line in self.raw_lines.iter() {
            try!(writer.write(line.as_bytes()));
            try!(writer.write("\n".as_bytes()));
        }
        if !self.raw_lines.is_empty() {
            try!(writer.write("\n".as_bytes()));
        }

        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &[]));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

/// Determines whether the given cursor is in any of the files matched by the
/// options.
fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
    let (file, _, _, _) = cursor.location().location();

    match file.name() {
        None => ctx.options().builtins,
        Some(..) => true,
    }
}

pub fn parse_one(ctx: &mut BindgenContext,
                 cursor: clang::Cursor,
                 parent: Option<ItemId>,
                 children: &mut Vec<ItemId>) -> clangll::Enum_CXVisitorResult {
    if !filter_builtins(ctx, &cursor) {
        return CXChildVisit_Continue
    }

    use clangll::CXChildVisit_Continue;
    match Item::parse(cursor, parent, ctx) {
        Ok(id) => children.push(id),
        Err(ParseError::Continue) => {},
        Err(ParseError::Recurse) => {
            cursor.visit(|child, _| parse_one(ctx, *child, parent, children));
        }
    }
    CXChildVisit_Continue
}

fn parse(context: &mut BindgenContext) {
    use clang::Diagnostic;
    use clangll::*;

    for d in context.translation_unit().diags().iter() {
        let msg = d.format(Diagnostic::default_opts());
        let is_err = d.severity() >= CXDiagnostic_Error;
        println!("{}, err: {}", msg, is_err);
    }

    let cursor = context.translation_unit().cursor();
    if context.options().emit_ast {
        cursor.visit(|cur, _| clang::ast_dump(cur, 0));
    }

    let root = context.root_module();
    context.with_module(root, |context, children| {
        cursor.visit(|cursor, _| parse_one(context, *cursor, None, children))
    });

    assert!(context.current_module() == context.root_module(),
            "How did this happen?");
}
<commit_msg>Remove the dtor_attrs option<commit_after>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

// To avoid rather annoying warnings when matching with CXCursor_xxx as a
// constant.
#![allow(non_upper_case_globals)]

extern crate syntex_syntax as syntax;
extern crate aster;
extern crate quasi;
extern crate clang_sys;
extern crate libc;
extern crate regex;
#[macro_use]
extern crate log;

mod clangll;
mod clang;
mod ir;
mod parse;
mod regex_set;
mod codegen {
    include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
}

use std::borrow::Borrow;
use std::io::{self, Write};
use std::fs::OpenOptions;
use std::path::Path;
use std::collections::HashSet;

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use ir::context::BindgenContext;
use ir::item::{Item, ItemId};
use parse::{ClangItemParser, ParseError};
use regex_set::RegexSet;

#[derive(Debug,Default)]
pub struct Builder {
    options: BindgenOptions,
}

pub fn builder() -> Builder {
    Default::default()
}

impl Builder {
    pub fn header<T: Into<String>>(self, header: T) -> Builder {
        self.clang_arg(header)
    }

    pub fn hide_type<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.hidden_types.insert(arg.into());
        self
    }

    pub fn opaque_type<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.opaque_types.insert(arg.into());
        self
    }

    pub fn whitelisted_type<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_types.insert(&arg);
        self
    }

    pub fn whitelisted_function<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_functions.insert(&arg);
        self
    }

    pub fn whitelisted_var<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_vars.insert(&arg);
        self
    }

    pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.raw_lines.push(arg.into());
        self
    }

    pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.clang_args.push(arg.into());
        self
    }

    pub fn link<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Default));
        self
    }

    pub fn link_static<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Static));
        self
    }

    pub fn link_framework<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Framework));
        self
    }

    pub fn forbid_unknown_types(mut self) -> Builder {
        self.options.fail_on_unknown_type = true;
        self
    }

    pub fn emit_builtins(mut self) -> Builder {
        self.options.builtins = true;
        self
    }

    pub fn no_bitfield_methods(mut self) -> Builder {
        self.options.gen_bitfield_methods = false;
        self
    }

    pub fn no_unstable_rust(mut self) -> Builder {
        self.options.unstable_rust = false;
        self
    }
    pub fn rust_enums(mut self, value: bool) -> Builder {
        self.options.rust_enums = value;
        self
    }

    pub fn rename_types(mut self, value: bool) -> Builder {
        self.options.rename_types = value;
        self
    }

    pub fn disable_class_constants(mut self) -> Builder {
        self.options.class_constants = false;
        self
    }

    pub fn generate(self) -> Result<Bindings, ()> {
        Bindings::generate(self.options, None)
    }
}

/// Deprecated - use a `Builder` instead
#[derive(Debug)]
pub struct BindgenOptions {
    pub hidden_types: HashSet<String>,
    pub opaque_types: HashSet<String>,
    pub whitelisted_types: RegexSet,
    pub whitelisted_functions: RegexSet,
    pub whitelisted_vars: RegexSet,
    pub builtins: bool,
    pub rust_enums: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub ignore_functions: bool,
    pub ignore_methods: bool,
    pub gen_bitfield_methods: bool,
    pub fail_on_unknown_type: bool,
    pub enable_cxx_namespaces: bool,
    pub rename_types: bool,
    pub derive_debug: bool,
    /// Generate or not only stable rust.
    pub unstable_rust: bool,
    /// Whether to generate C++ class constants.
    pub class_constants: bool,
    /// Wether to generate names that are **directly** under namespaces.
    pub namespaced_constants: bool,
    /// Whether to use msvc mangling rules
    pub msvc_mangling: bool,
    pub override_enum_ty: String,
    pub raw_lines: Vec<String>,
    pub clang_args: Vec<String>,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        BindgenOptions {
            hidden_types: Default::default(),
            opaque_types: Default::default(),
            whitelisted_types: Default::default(),
            whitelisted_functions: Default::default(),
            whitelisted_vars: Default::default(),
            builtins: false,
            rust_enums: true,
            links: vec![],
            emit_ast: false,
            ignore_functions: false,
            ignore_methods: false,
            gen_bitfield_methods: true,
            fail_on_unknown_type: true,
            rename_types: true,
            derive_debug: true,
            enable_cxx_namespaces: false,
            override_enum_ty: "".to_string(),
            unstable_rust: true,
            class_constants: true,
            namespaced_constants: true,
            msvc_mangling: false,
            raw_lines: vec![],
            clang_args: vec![],
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    Default,
    Static,
    Framework
}

#[derive(Debug, Clone)]
pub struct Bindings {
    module: ast::Mod,
    raw_lines: Vec<String>,
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    pub fn generate(options: BindgenOptions, span: Option<Span>) -> Result<Bindings, ()> {
        let span = span.unwrap_or(DUMMY_SP);

        let mut context = BindgenContext::new(options);
        parse(&mut context);

        let module = ast::Mod {
            inner: span,
            items: codegen::codegen(&mut context),
        };

        Ok(Bindings {
            module: module,
            raw_lines: context.options().raw_lines.clone(),
        })
    }

    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    pub fn to_string(&self) -> String {
        let mut mod_str = vec![];
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    // https://github.com/Manishearth/rust-clippy/issues/740
    #[cfg_attr(feature = "clippy", allow(needless_lifetimes))]
    pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));

        for line in self.raw_lines.iter() {
            try!(writer.write(line.as_bytes()));
            try!(writer.write("\n".as_bytes()));
        }
        if !self.raw_lines.is_empty() {
            try!(writer.write("\n".as_bytes()));
        }

        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &[]));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

/// Determines whether the given cursor is in any of the files matched by the
/// options.
fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
    let (file, _, _, _) = cursor.location().location();

    match file.name() {
        None => ctx.options().builtins,
        Some(..) => true,
    }
}

pub fn parse_one(ctx: &mut BindgenContext,
                 cursor: clang::Cursor,
                 parent: Option<ItemId>,
                 children: &mut Vec<ItemId>) -> clangll::Enum_CXVisitorResult {
    if !filter_builtins(ctx, &cursor) {
        return CXChildVisit_Continue
    }

    use clangll::CXChildVisit_Continue;
    match Item::parse(cursor, parent, ctx) {
        Ok(id) => children.push(id),
        Err(ParseError::Continue) => {},
        Err(ParseError::Recurse) => {
            cursor.visit(|child, _| parse_one(ctx, *child, parent, children));
        }
    }
    CXChildVisit_Continue
}

fn parse(context: &mut BindgenContext) {
    use clang::Diagnostic;
    use clangll::*;

    for d in context.translation_unit().diags().iter() {
        let msg = d.format(Diagnostic::default_opts());
        let is_err = d.severity() >= CXDiagnostic_Error;
        println!("{}, err: {}", msg, is_err);
    }

    let cursor = context.translation_unit().cursor();
    if context.options().emit_ast {
        cursor.visit(|cur, _| clang::ast_dump(cur, 0));
    }

    let root = context.root_module();
    context.with_module(root, |context, children| {
        cursor.visit(|cursor, _| parse_one(context, *cursor, None, children))
    });

    assert!(context.current_module() == context.root_module(),
            "How did this happen?");
}
<|endoftext|>


<commit_before>extern crate bincode;
extern crate rustc_serialize;

use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, decode};
use rustc_serialize::{Encodable, Decodable};

use std::cmp::max;
use std::convert::From;
use std::collections::BTreeMap;
use std::error::Error;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::{Read, Write, Seek, SeekFrom, ErrorKind};
use std::mem::{size_of};
use std::str;

const NUM_CHILDREN: usize = 32;
const FILE_HEADER: &'static str = "B+Tree\0";
const CURRENT_VERSION: u8 = 0x01;

// specify the types for the keys & values
pub trait KeyType: Ord + Encodable + Decodable {}
pub trait ValueType: Encodable + Decodable {}

// provide generic implementations
impl<T> KeyType for T where T: Ord + Encodable + Decodable {}
impl<T> ValueType for T where T: Encodable + Decodable {}

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
enum Payload<K: KeyType, V: ValueType> {
        Value(V),
        Children([(K,u64); NUM_CHILDREN]),
    }

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct Node<K: KeyType, V: ValueType> {
    key: K,
    parent: u64,
    payload: Payload<K,V>, // either children, or actual values
}

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct WALRecord<K: KeyType, V: ValueType> {
    key: K,
    value: V,
}

/// This struct represents an on-disk B+Tree. There are NUM_CHILDREN keys at each
/// level in the tree. The on-disk format is as follows where VV is the version
/// number:
/// |-------------------------------------------|
/// | 0x42 0x2b 0x54 0x72 | 0x65 0x65 0x00 0xVV |
/// | B    +    T    r    | e    e    \0   0xVV |
/// |-------------------------------------------|
/// | smallest record in bincode format         |
/// |-------------------------------------------|
/// | ...                                       |
/// |-------------------------------------------|
/// | largest record in bincode format          |
/// |-------------------------------------------|
/// | internal nodes ...                        |
/// |-------------------------------------------|
/// | root node                                 |
/// |-------------------------------------------|
pub struct BTree<K: KeyType, V: ValueType> {
    tree_file: File,          // the file backing the whole thing
    wal_file: File,           // write-ahead log for in-memory items
    root: Option<Node<K,V>>,  // optional in-memory copy of the root node
    max_key_size: usize,      // the size of the key in bytes
    max_value_size: usize,    // the size of the value in bytes
    mem_tree: BTreeMap<K, V>,
}

impl <K: KeyType, V: ValueType> BTree<K, V> {
    pub fn new(tree_file_path: &str, max_key_size: usize, max_value_size: usize) -> Result<BTree<K,V>, Box<Error>> {
        // create our mem_tree
        let mut mem_tree = BTreeMap::new();

        let mut wal_file = try!(OpenOptions::new().read(true).write(true).create(true).open(tree_file_path.to_owned() + ".wal"));

        let record_size = max_key_size + max_value_size;

        // if we have a WAL file, replay it into the mem_tree
        if try!(wal_file.metadata()).len() != 0 {
            let mut buff = vec![0; record_size];

            while true {
                match wal_file.read_exact(&mut buff) {
                    Ok(_) => {
                        let record: WALRecord<K,V> = try!(decode(&buff));  // decode the record
                        mem_tree.insert(record.key,record.value);  // add it to the in-memory table
                    },
                    Err(e) => if e.kind() == ErrorKind::UnexpectedEof {
                        break  // reached the end of our file, break from the loop
                    } else {
                        return Err(From::from(e));
                    }
                }
            }
        }

        // compute the size of a on-disk Node
        let node_size: usize = (max_key_size + size_of::<u64>() + max(max_value_size, (max_key_size + size_of::<u64>()) * NUM_CHILDREN)) as usize;

        // open the data file
        let mut tree_file = try!(OpenOptions::new().read(true).write(true).create(true).open(tree_file_path));

        let metadata = try!(tree_file.metadata());

        println!("FILE HAS LENGTH: {}", metadata.len());

        // check to see if this is a new file
        if metadata.len() == 0 {
            // write out our header
            try!(tree_file.write(FILE_HEADER.as_bytes()));

            // write out our version
            try!(tree_file.write(&[CURRENT_VERSION]));

            // construct and return our BTree object
            Ok(BTree{tree_file: tree_file,
                     wal_file: wal_file,
                     root: None,
                     max_key_size: max_key_size,
                     max_value_size: max_value_size,
                     mem_tree: mem_tree
            })
        } else {
            let mut version_string = vec![0; 8];

            try!(tree_file.read_exact(&mut version_string));

            // make sure we've opened a proper file
            if try!(str::from_utf8(&version_string[0..FILE_HEADER.len()])) != FILE_HEADER ||
               version_string[FILE_HEADER.len()] != CURRENT_VERSION {
                return Err(From::from(std::io::Error::new(ErrorKind::InvalidData, "Invalid BTree file or BTree version")));
            }

            let mut buff = vec![0; node_size];

            // make sure we have a root node to read
            if metadata.len() < (version_string.len() + node_size) as u64 {
                // if we don't have a root node yet, just return
                return Ok(BTree{tree_file: tree_file,
                                wal_file: wal_file,
                                root: None,
                                max_key_size: max_key_size,
                                max_value_size: max_value_size,
                                mem_tree: mem_tree
                });
            }

            // seek node_size in from the end of the file to read the root node
            try!(tree_file.seek(SeekFrom::End((node_size as isize * -1) as i64)));
            try!(tree_file.read_exact(&mut buff));

            let root_node: Node<K,V> = try!(decode(&buff[..]));

            Ok(BTree{tree_file: tree_file,
                     wal_file: wal_file,
                     root: Some(root_node),
                     max_key_size: max_key_size,
                     max_value_size: max_value_size,
                     mem_tree: mem_tree
            })
        }
    }
}

#[cfg(test)]
mod tests {
    use std::fs;
    use ::BTree;

    #[test]
    fn new_blank_file() {
        // make sure we remove any old files
        fs::remove_file("/tmp/btree_test.btr");

        BTree::<u8, u8>::new("/tmp/btree_test.btr", 1, 1).unwrap();
    }

    #[test]
    fn new_existing_file() {
        new_blank_file();  // assume this works

        let btree = BTree::<u8, u8>::new("/tmp/btree_test.btr", 1, 1).unwrap();
    }
}
<commit_msg>Updated unit tests<commit_after>extern crate bincode;
extern crate rustc_serialize;

use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, decode};
use rustc_serialize::{Encodable, Decodable};

use std::cmp::max;
use std::convert::From;
use std::collections::BTreeMap;
use std::error::Error;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::{Read, Write, Seek, SeekFrom, ErrorKind};
use std::mem::{size_of};
use std::str;

const NUM_CHILDREN: usize = 32;
const FILE_HEADER: &'static str = "B+Tree\0";
const CURRENT_VERSION: u8 = 0x01;

// specify the types for the keys & values
pub trait KeyType: Ord + Encodable + Decodable {}
pub trait ValueType: Encodable + Decodable {}

// provide generic implementations
impl<T> KeyType for T where T: Ord + Encodable + Decodable {}
impl<T> ValueType for T where T: Encodable + Decodable {}

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
enum Payload<K: KeyType, V: ValueType> {
        Value(V),
        Children([(K,u64); NUM_CHILDREN]),
    }

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct Node<K: KeyType, V: ValueType> {
    key: K,
    parent: u64,
    payload: Payload<K,V>, // either children, or actual values
}

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct WALRecord<K: KeyType, V: ValueType> {
    key: K,
    value: V,
}

/// This struct represents an on-disk B+Tree. There are NUM_CHILDREN keys at each
/// level in the tree. The on-disk format is as follows where VV is the version
/// number:
/// |-------------------------------------------|
/// | 0x42 0x2b 0x54 0x72 | 0x65 0x65 0x00 0xVV |
/// | B    +    T    r    | e    e    \0   0xVV |
/// |-------------------------------------------|
/// | smallest record in bincode format         |
/// |-------------------------------------------|
/// | ...                                       |
/// |-------------------------------------------|
/// | largest record in bincode format          |
/// |-------------------------------------------|
/// | internal nodes ...                        |
/// |-------------------------------------------|
/// | root node                                 |
/// |-------------------------------------------|
pub struct BTree<K: KeyType, V: ValueType> {
    tree_file: File,          // the file backing the whole thing
    wal_file: File,           // write-ahead log for in-memory items
    root: Option<Node<K,V>>,  // optional in-memory copy of the root node
    max_key_size: usize,      // the size of the key in bytes
    max_value_size: usize,    // the size of the value in bytes
    mem_tree: BTreeMap<K, V>,
}

impl <K: KeyType, V: ValueType> BTree<K, V> {
    pub fn new(tree_file_path: String, max_key_size: usize, max_value_size: usize) -> Result<BTree<K,V>, Box<Error>> {
        // create our mem_tree
        let mut mem_tree = BTreeMap::new();

        let mut wal_file = try!(OpenOptions::new().read(true).write(true).create(true).open(tree_file_path.to_owned() + ".wal"));

        let record_size = max_key_size + max_value_size;

        // if we have a WAL file, replay it into the mem_tree
        if try!(wal_file.metadata()).len() != 0 {
            let mut buff = vec![0; record_size];

            while true {
                match wal_file.read_exact(&mut buff) {
                    Ok(_) => {
                        let record: WALRecord<K,V> = try!(decode(&buff));  // decode the record
                        mem_tree.insert(record.key,record.value);  // add it to the in-memory table
                    },
                    Err(e) => if e.kind() == ErrorKind::UnexpectedEof {
                        break  // reached the end of our file, break from the loop
                    } else {
                        return Err(From::from(e));
                    }
                }
            }
        }

        // compute the size of a on-disk Node
        let node_size: usize = (max_key_size + size_of::<u64>() + max(max_value_size, (max_key_size + size_of::<u64>()) * NUM_CHILDREN)) as usize;

        // open the data file
        let mut tree_file = try!(OpenOptions::new().read(true).write(true).create(true).open(tree_file_path));

        let metadata = try!(tree_file.metadata());

        println!("FILE HAS LENGTH: {}", metadata.len());

        // check to see if this is a new file
        if metadata.len() == 0 {
            // write out our header
            try!(tree_file.write(FILE_HEADER.as_bytes()));

            // write out our version
            try!(tree_file.write(&[CURRENT_VERSION]));

            // construct and return our BTree object
            Ok(BTree{tree_file: tree_file,
                     wal_file: wal_file,
                     root: None,
                     max_key_size: max_key_size,
                     max_value_size: max_value_size,
                     mem_tree: mem_tree
            })
        } else {
            let mut version_string = vec![0; 8];

            try!(tree_file.read_exact(&mut version_string));

            // make sure we've opened a proper file
            if try!(str::from_utf8(&version_string[0..FILE_HEADER.len()])) != FILE_HEADER ||
               version_string[FILE_HEADER.len()] != CURRENT_VERSION {
                return Err(From::from(std::io::Error::new(ErrorKind::InvalidData, "Invalid BTree file or BTree version")));
            }

            let mut buff = vec![0; node_size];

            // make sure we have a root node to read
            if metadata.len() < (version_string.len() + node_size) as u64 {
                // if we don't have a root node yet, just return
                return Ok(BTree{tree_file: tree_file,
                                wal_file: wal_file,
                                root: None,
                                max_key_size: max_key_size,
                                max_value_size: max_value_size,
                                mem_tree: mem_tree
                });
            }

            // seek node_size in from the end of the file to read the root node
            try!(tree_file.seek(SeekFrom::End((node_size as isize * -1) as i64)));
            try!(tree_file.read_exact(&mut buff));

            let root_node: Node<K,V> = try!(decode(&buff[..]));

            Ok(BTree{tree_file: tree_file,
                     wal_file: wal_file,
                     root: Some(root_node),
                     max_key_size: max_key_size,
                     max_value_size: max_value_size,
                     mem_tree: mem_tree
            })
        }
    }
}

#[cfg(test)]
mod tests {
    use std::fs;
    use std::fs::OpenOptions;
    use ::BTree;

    const FILE_PATH: &'static str = "/tmp/btree_test.btr";

    #[test]
    fn new_blank_file() {
        // make sure we remove any old files
        fs::remove_file(FILE_PATH);
        fs::remove_file(FILE_PATH.to_owned() + ".wal");

        BTree::<u8, u8>::new(FILE_PATH.to_owned(), 1, 1).unwrap();

        // make sure our two files were created
        let btf = OpenOptions::new().read(true).write(false).create(false).open(FILE_PATH).unwrap();
        assert!(btf.metadata().unwrap().len() == 8);

        let wal = OpenOptions::new().read(true).write(false).create(false).open(FILE_PATH.to_owned() + ".wal").unwrap();
        assert!(wal.metadata().unwrap().len() == 0);
    }

    #[test]
    fn new_existing_file() {
        new_blank_file();  // assume this works

        let btree = BTree::<u8, u8>::new(FILE_PATH.to_owned(), 1, 1).unwrap();

        // check our file lengths from the struct
        assert!(btree.tree_file.metadata().unwrap().len() == 8);
        assert!(btree.wal_file.metadata().unwrap().len() == 0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Keegan McAllister.
// Copyright 2016 Corey Farwell.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See `LICENSE` in this repository.

use std::io::{self, Read};
use std::{panic, process};

/// Utility that reads a `Vec` of bytes from standard input (stdin)
/// and passes it to `closure`. All panics that occur within
/// `closure` will be treated as aborts. This is done so that
/// AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Image;
/// # impl Image {
/// #     fn parse(_: &[u8]) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_bytes(|read| {
///         Image::parse(&read)
///     })
/// }
/// ```
pub fn read_stdio_bytes<F>(closure: F)
where
    F: Fn(Vec<u8>) + panic::RefUnwindSafe,
{
    let mut input = vec![];
    let result = io::stdin().read_to_end(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

/// Utility that reads a `String` from standard input (stdin) and
/// passes it to `closure`. If a `String` cannot be constructed from
/// the data provided by standard input, `closure` will _not_ be
/// called. All panics that occur within `closure` will be treated as
/// aborts. This is done so that AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Url;
/// # impl Url {
/// #     fn parse(_: &str) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_string(|string| {
///         Url::parse(&string)
///     })
/// }
/// ```
pub fn read_stdio_string<F>(closure: F)
where
    F: Fn(String) + panic::RefUnwindSafe,
{
    let mut input = String::new();
    let result = io::stdin().read_to_string(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

// this function is provided by the afl-llvm-rt static library
extern "C" {
    fn __afl_persistent_loop(counter: usize) -> isize;
}

pub fn fuzz<F>(closure: F) where F: Fn(&[u8]) + std::panic::RefUnwindSafe {
    // this marker strings needs to be in the produced executable for
    // afl-fuzz to detect `persistent mode`
    static PERSIST_MARKER: &'static str = "##SIG_AFL_PERSISTENT##\0";

    // we now need a fake instruction to prevent the compiler from optimizing out
    // this marker string
    unsafe{std::ptr::read_volatile(&PERSIST_MARKER)}; // hack used in https://github.com/bluss/bencher for black_box()
    // unsafe { asm!("" : : "r"(&PERSIST_MARKER)) }; // hack used in nightly's back_box(), requires feature asm

    let mut input = vec![];

    while unsafe{__afl_persistent_loop(1000)} != 0 {
        // get buffer from AFL through stdin
        let result = io::stdin().read_to_end(&mut input);
        if result.is_err() {
            return;
        }

        let did_panic = std::panic::catch_unwind(|| {
            closure(&input);
        }).is_err();

        if did_panic {
            std::process::abort();
        }
        input.clear();
    }
}

#[cfg(test)]
mod test {
    /*
    use std::path::PathBuf;
    use std::process::{Command, Stdio};
    use std::thread;
    use std::time;

    extern crate libc;
    extern crate tempdir;

    fn target_path() -> PathBuf {
        if PathBuf::from("../target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("../target/debug/")
        } else if PathBuf::from("target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("target/debug/")
        } else {
            panic!("Could not find cargo-afl-fuzz!");
        }
    }

    #[test]
    fn test_cargo_afl_fuzz() {
        let temp_dir = tempdir::TempDir::new("aflrs").expect("Could not create temporary directory");
        let temp_dir_path = temp_dir.path();
        let mut child = Command::new(target_path().join("cargo-afl-fuzz"))
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .arg("-i")
            .arg(".")
            .arg("-o")
            .arg(temp_dir_path)
            .arg(target_path().join("examples").join("hello"))
            .spawn()
            .expect("Could not run cargo-afl-fuzz");
        thread::sleep(time::Duration::from_secs(7));
        child.kill().unwrap();
        assert!(temp_dir_path.join("fuzzer_stats").is_file());
    }
    */
}
<commit_msg>Use panic::set_hook() to abort process<commit_after>// Copyright 2015 Keegan McAllister.
// Copyright 2016 Corey Farwell.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See `LICENSE` in this repository.

use std::io::{self, Read};
use std::{panic, process};

/// Utility that reads a `Vec` of bytes from standard input (stdin)
/// and passes it to `closure`. All panics that occur within
/// `closure` will be treated as aborts. This is done so that
/// AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Image;
/// # impl Image {
/// #     fn parse(_: &[u8]) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_bytes(|read| {
///         Image::parse(&read)
///     })
/// }
/// ```
pub fn read_stdio_bytes<F>(closure: F)
where
    F: Fn(Vec<u8>) + panic::RefUnwindSafe,
{
    let mut input = vec![];
    let result = io::stdin().read_to_end(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

/// Utility that reads a `String` from standard input (stdin) and
/// passes it to `closure`. If a `String` cannot be constructed from
/// the data provided by standard input, `closure` will _not_ be
/// called. All panics that occur within `closure` will be treated as
/// aborts. This is done so that AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Url;
/// # impl Url {
/// #     fn parse(_: &str) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_string(|string| {
///         Url::parse(&string)
///     })
/// }
/// ```
pub fn read_stdio_string<F>(closure: F)
where
    F: Fn(String) + panic::RefUnwindSafe,
{
    let mut input = String::new();
    let result = io::stdin().read_to_string(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

// this function is provided by the afl-llvm-rt static library
extern "C" {
    fn __afl_persistent_loop(counter: usize) -> isize;
}

pub fn fuzz<F>(closure: F) where F: Fn(&[u8]) + std::panic::RefUnwindSafe {
    // this marker strings needs to be in the produced executable for
    // afl-fuzz to detect `persistent mode`
    static PERSIST_MARKER: &'static str = "##SIG_AFL_PERSISTENT##\0";

    // we now need a fake instruction to prevent the compiler from optimizing out
    // this marker string
    unsafe{std::ptr::read_volatile(&PERSIST_MARKER)}; // hack used in https://github.com/bluss/bencher for black_box()
    // unsafe { asm!("" : : "r"(&PERSIST_MARKER)) }; // hack used in nightly's back_box(), requires feature asm

    // sets panic hook to abort
    std::panic::set_hook(Box::new(|_| {
        std::process::abort();
    }));

    let mut input = vec![];

    while unsafe{__afl_persistent_loop(1000)} != 0 {
        // get buffer from AFL through stdin
        let result = io::stdin().read_to_end(&mut input);
        if result.is_err() {
            return;
        }

        // We still catch unwinding panics just in case the fuzzed code modifies
        // the panic hook.
        // If so, the fuzzer will be unable to tell different bugs appart and you will
        // only be able to find one bug at a time before fixing it to then find a new one.
        let did_panic = std::panic::catch_unwind(|| {
            closure(&input);
        }).is_err();

        if did_panic {
            // hopefully the custom panic hook will be called before and abort the
            // process before the stack frames are unwinded.
            std::process::abort();
        }
        input.clear();
    }
}

#[cfg(test)]
mod test {
    /*
    use std::path::PathBuf;
    use std::process::{Command, Stdio};
    use std::thread;
    use std::time;

    extern crate libc;
    extern crate tempdir;

    fn target_path() -> PathBuf {
        if PathBuf::from("../target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("../target/debug/")
        } else if PathBuf::from("target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("target/debug/")
        } else {
            panic!("Could not find cargo-afl-fuzz!");
        }
    }

    #[test]
    fn test_cargo_afl_fuzz() {
        let temp_dir = tempdir::TempDir::new("aflrs").expect("Could not create temporary directory");
        let temp_dir_path = temp_dir.path();
        let mut child = Command::new(target_path().join("cargo-afl-fuzz"))
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .arg("-i")
            .arg(".")
            .arg("-o")
            .arg(temp_dir_path)
            .arg(target_path().join("examples").join("hello"))
            .spawn()
            .expect("Could not run cargo-afl-fuzz");
        thread::sleep(time::Duration::from_secs(7));
        child.kill().unwrap();
        assert!(temp_dir_path.join("fuzzer_stats").is_file());
    }
    */
}
<|endoftext|>


<commit_before>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! Open the given URL in the default web browser.
//!
//! ```no_run
//! open::that("http://rust-lang.org").unwrap();
//! ```
//!
//! Alternatively, specify the program to be used to open the path or URL.
//!
//! ```no_run
//! open::with("http://rust-lang.org", "firefox").unwrap();
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, the open operation can fail.
//! Therefore, you are advised to at least check the result and behave
//! accordingly, e.g. by letting the user know that the open operation failed.
//!
//! ```no_run
//! let path = "http://rust-lang.org";
//!
//! match open::that(path) {
//!     Ok(()) => println!("Opened '{}' successfully.", path),
//!     Err(err) => eprintln!("An error occurred when opening '{}': {}", path, err),
//! }
//! ```

#[cfg(target_os = "windows")]
use windows as os;

#[cfg(target_os = "macos")]
use macos as os;

#[cfg(target_os = "ios")]
use ios as os;

#[cfg(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
use unix as os;

#[cfg(not(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris",
    target_os = "ios",
    target_os = "macos",
    target_os = "windows",
)))]
compile_error!("open is not supported on this platform");

use std::{
    ffi::OsStr,
    io,
    process::{Command, Output, Stdio},
    thread,
};

type Result = io::Result<()>;

/// Open path with the default application.
///
/// # Examples
///
/// ```no_run
/// let path = "http://rust-lang.org";
///
/// match open::that(path) {
///     Ok(()) => println!("Opened '{}' successfully.", path),
///     Err(err) => panic!("An error occurred when opening '{}': {}", path, err),
/// }
/// ```
///
/// # Errors
///
/// A [`std::io::Error`] is returned on failure. Because different operating systems
/// handle errors differently it is recommend to not match on a certain error.
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
    os::that(path)
}

/// Open path with the given application.
///
/// # Examples
///
/// ```no_run
/// let path = "http://rust-lang.org";
/// let app = "firefox";
///
/// match open::with(path, app) {
///     Ok(()) => println!("Opened '{}' successfully.", path),
///     Err(err) => panic!("An error occurred when opening '{}': {}", path, err),
/// }
/// ```
///
/// # Errors
///
/// A [`std::io::Error`] is returned on failure. Because different operating systems
/// handle errors differently it is recommend to not match on a certain error.
pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
    os::with(path, app)
}

/// Open path with the default application in a new thread.
///
/// See documentation of [`that`] for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(path: T) -> thread::JoinHandle<Result> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

/// Open path with the given application in a new thread.
///
/// See documentation of [`with`] for more details.
pub fn with_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
    app: impl Into<String>,
) -> thread::JoinHandle<Result> {
    let path = path.as_ref().to_os_string();
    let app = app.into();
    thread::spawn(|| with(path, app))
}

trait IntoResult<T> {
    fn into_result(self) -> T;
}

impl IntoResult<Result> for io::Result<Output> {
    fn into_result(self) -> Result {
        match self {
            Ok(o) if o.status.success() => Ok(()),
            Ok(o) => Err(from_output(o)),
            Err(err) => Err(err),
        }
    }
}

#[cfg(windows)]
impl IntoResult<Result> for winapi::ctypes::c_int {
    fn into_result(self) -> Result {
        match self {
            i if i > 32 => Ok(()),
            _ => Err(io::Error::last_os_error()),
        }
    }
}

fn from_output(output: Output) -> io::Error {
    let error_msg = match output.stderr.is_empty() {
        true => output.status.to_string(),
        false => format!(
            "{} ({})",
            String::from_utf8_lossy(&output.stderr).trim(),
            output.status
        ),
    };

    io::Error::new(io::ErrorKind::Other, error_msg)
}

trait CommandExt {
    fn output_stderr(&mut self) -> io::Result<Output>;
}

impl CommandExt for Command {
    fn output_stderr(&mut self) -> io::Result<Output> {
        let mut process = self
            .stdin(Stdio::null())
            .stdout(Stdio::null())
            .stderr(Stdio::piped())
            .spawn()?;

        // Consume all stderr - it's open just for a few programs which can't handle it being closed.
        use std::io::Read;
        let mut stderr = vec![0; 256];
        let mut stderr_src = process.stderr.take().expect("piped stderr");

        let len = stderr_src.read(&mut stderr).unwrap_or(0);
        stderr.truncate(len);

        // consume the rest to avoid blocking
        std::io::copy(&mut stderr_src, &mut std::io::sink()).ok();

        let status = process.wait()?;
        Ok(Output {
            status,
            stderr,
            stdout: vec![],
        })
    }
}

#[cfg(windows)]
mod windows {
    use std::{ffi::OsStr, io, os::windows::ffi::OsStrExt, ptr};

    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    use crate::{IntoResult, Result};

    fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                ptr::null(),
                SW_SHOW,
            )
        };
        (result as c_int).into_result()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into()))
            .encode_wide()
            .collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                app_name.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                SW_SHOW,
            )
        };
        (result as c_int).into_result()
    }
}

#[cfg(target_os = "macos")]
mod macos {
    use std::{ffi::OsStr, process::Command};

    use crate::{CommandExt, IntoResult, Result};

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
        Command::new("open")
            .arg(path.as_ref())
            .output_stderr()
            .into_result()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
        Command::new("open")
            .arg(path.as_ref())
            .arg("-a")
            .arg(app.into())
            .output_stderr()
            .into_result()
    }
}

#[cfg(target_os = "ios")]
mod ios {
    use std::{ffi::OsStr, process::Command};

    use crate::{CommandExt, IntoResult, Result};

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
        Command::new("uiopen")
            .arg("--url")
            .arg(path.as_ref())
            .output_stderr()
            .into_result()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
        Command::new("uiopen")
            .arg("--url")
            .arg(path.as_ref())
            .arg("--bundleid")
            .arg(app.into())
            .output_stderr()
            .into_result()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod unix {
    use std::{
        env,
        ffi::{OsStr, OsString},
        path::{Path, PathBuf},
        process::Command,
    };

    use crate::{CommandExt, IntoResult, Result};

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
        let path = path.as_ref();
        let open_handlers = [
            ("xdg-open", &[path] as &[_]),
            ("gio", &[OsStr::new("open"), path]),
            ("gnome-open", &[path]),
            ("kde-open", &[path]),
            ("wslview", &[&wsl_path(path)]),
        ];

        let mut unsuccessful = None;
        let mut io_error = None;

        for (command, args) in &open_handlers {
            let result = Command::new(command).args(*args).output_stderr();

            match result {
                Ok(o) if o.status.success() => return Ok(()),
                Ok(o) => unsuccessful = unsuccessful.or_else(|| Some(crate::from_output(o))),
                Err(err) => io_error = io_error.or(Some(err)),
            }
        }

        Err(unsuccessful
            .or(io_error)
            .expect("successful cases don't get here"))
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
        Command::new(app.into())
            .arg(path.as_ref())
            .output_stderr()
            .into_result()
    }

    // Polyfill to workaround absolute path bug in wslu(wslview). In versions before
    // v3.1.1, wslview is unable to find absolute paths. `wsl_path` converts an
    // absolute path into a relative path starting from the current directory. If
    // the path is already a relative path or the conversion fails the original path
    // is returned.
    fn wsl_path<T: AsRef<OsStr>>(path: T) -> OsString {
        fn path_relative_to_current_dir<T: AsRef<OsStr>>(path: T) -> Option<PathBuf> {
            let path = Path::new(&path);

            if path.is_relative() {
                return None;
            }

            let base = env::current_dir().ok()?;
            pathdiff::diff_paths(path, base)
        }

        match path_relative_to_current_dir(&path) {
            None => OsString::from(&path),
            Some(relative) => OsString::from(relative),
        }
    }
}
<commit_msg>use full path for `open` command on macOS<commit_after>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! Open the given URL in the default web browser.
//!
//! ```no_run
//! open::that("http://rust-lang.org").unwrap();
//! ```
//!
//! Alternatively, specify the program to be used to open the path or URL.
//!
//! ```no_run
//! open::with("http://rust-lang.org", "firefox").unwrap();
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, the open operation can fail.
//! Therefore, you are advised to at least check the result and behave
//! accordingly, e.g. by letting the user know that the open operation failed.
//!
//! ```no_run
//! let path = "http://rust-lang.org";
//!
//! match open::that(path) {
//!     Ok(()) => println!("Opened '{}' successfully.", path),
//!     Err(err) => eprintln!("An error occurred when opening '{}': {}", path, err),
//! }
//! ```

#[cfg(target_os = "windows")]
use windows as os;

#[cfg(target_os = "macos")]
use macos as os;

#[cfg(target_os = "ios")]
use ios as os;

#[cfg(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
use unix as os;

#[cfg(not(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris",
    target_os = "ios",
    target_os = "macos",
    target_os = "windows",
)))]
compile_error!("open is not supported on this platform");

use std::{
    ffi::OsStr,
    io,
    process::{Command, Output, Stdio},
    thread,
};

type Result = io::Result<()>;

/// Open path with the default application.
///
/// # Examples
///
/// ```no_run
/// let path = "http://rust-lang.org";
///
/// match open::that(path) {
///     Ok(()) => println!("Opened '{}' successfully.", path),
///     Err(err) => panic!("An error occurred when opening '{}': {}", path, err),
/// }
/// ```
///
/// # Errors
///
/// A [`std::io::Error`] is returned on failure. Because different operating systems
/// handle errors differently it is recommend to not match on a certain error.
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
    os::that(path)
}

/// Open path with the given application.
///
/// # Examples
///
/// ```no_run
/// let path = "http://rust-lang.org";
/// let app = "firefox";
///
/// match open::with(path, app) {
///     Ok(()) => println!("Opened '{}' successfully.", path),
///     Err(err) => panic!("An error occurred when opening '{}': {}", path, err),
/// }
/// ```
///
/// # Errors
///
/// A [`std::io::Error`] is returned on failure. Because different operating systems
/// handle errors differently it is recommend to not match on a certain error.
pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
    os::with(path, app)
}

/// Open path with the default application in a new thread.
///
/// See documentation of [`that`] for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(path: T) -> thread::JoinHandle<Result> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

/// Open path with the given application in a new thread.
///
/// See documentation of [`with`] for more details.
pub fn with_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
    app: impl Into<String>,
) -> thread::JoinHandle<Result> {
    let path = path.as_ref().to_os_string();
    let app = app.into();
    thread::spawn(|| with(path, app))
}

trait IntoResult<T> {
    fn into_result(self) -> T;
}

impl IntoResult<Result> for io::Result<Output> {
    fn into_result(self) -> Result {
        match self {
            Ok(o) if o.status.success() => Ok(()),
            Ok(o) => Err(from_output(o)),
            Err(err) => Err(err),
        }
    }
}

#[cfg(windows)]
impl IntoResult<Result> for winapi::ctypes::c_int {
    fn into_result(self) -> Result {
        match self {
            i if i > 32 => Ok(()),
            _ => Err(io::Error::last_os_error()),
        }
    }
}

fn from_output(output: Output) -> io::Error {
    let error_msg = match output.stderr.is_empty() {
        true => output.status.to_string(),
        false => format!(
            "{} ({})",
            String::from_utf8_lossy(&output.stderr).trim(),
            output.status
        ),
    };

    io::Error::new(io::ErrorKind::Other, error_msg)
}

trait CommandExt {
    fn output_stderr(&mut self) -> io::Result<Output>;
}

impl CommandExt for Command {
    fn output_stderr(&mut self) -> io::Result<Output> {
        let mut process = self
            .stdin(Stdio::null())
            .stdout(Stdio::null())
            .stderr(Stdio::piped())
            .spawn()?;

        // Consume all stderr - it's open just for a few programs which can't handle it being closed.
        use std::io::Read;
        let mut stderr = vec![0; 256];
        let mut stderr_src = process.stderr.take().expect("piped stderr");

        let len = stderr_src.read(&mut stderr).unwrap_or(0);
        stderr.truncate(len);

        // consume the rest to avoid blocking
        std::io::copy(&mut stderr_src, &mut std::io::sink()).ok();

        let status = process.wait()?;
        Ok(Output {
            status,
            stderr,
            stdout: vec![],
        })
    }
}

#[cfg(windows)]
mod windows {
    use std::{ffi::OsStr, io, os::windows::ffi::OsStrExt, ptr};

    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    use crate::{IntoResult, Result};

    fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                ptr::null(),
                SW_SHOW,
            )
        };
        (result as c_int).into_result()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into()))
            .encode_wide()
            .collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                app_name.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                SW_SHOW,
            )
        };
        (result as c_int).into_result()
    }
}

#[cfg(target_os = "macos")]
mod macos {
    use std::{ffi::OsStr, process::Command};

    use crate::{CommandExt, IntoResult, Result};

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
        Command::new("/usr/bin/open")
            .arg(path.as_ref())
            .output_stderr()
            .into_result()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
        Command::new("/usr/bin/open")
            .arg(path.as_ref())
            .arg("-a")
            .arg(app.into())
            .output_stderr()
            .into_result()
    }
}

#[cfg(target_os = "ios")]
mod ios {
    use std::{ffi::OsStr, process::Command};

    use crate::{CommandExt, IntoResult, Result};

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
        Command::new("uiopen")
            .arg("--url")
            .arg(path.as_ref())
            .output_stderr()
            .into_result()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
        Command::new("uiopen")
            .arg("--url")
            .arg(path.as_ref())
            .arg("--bundleid")
            .arg(app.into())
            .output_stderr()
            .into_result()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod unix {
    use std::{
        env,
        ffi::{OsStr, OsString},
        path::{Path, PathBuf},
        process::Command,
    };

    use crate::{CommandExt, IntoResult, Result};

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result {
        let path = path.as_ref();
        let open_handlers = [
            ("xdg-open", &[path] as &[_]),
            ("gio", &[OsStr::new("open"), path]),
            ("gnome-open", &[path]),
            ("kde-open", &[path]),
            ("wslview", &[&wsl_path(path)]),
        ];

        let mut unsuccessful = None;
        let mut io_error = None;

        for (command, args) in &open_handlers {
            let result = Command::new(command).args(*args).output_stderr();

            match result {
                Ok(o) if o.status.success() => return Ok(()),
                Ok(o) => unsuccessful = unsuccessful.or_else(|| Some(crate::from_output(o))),
                Err(err) => io_error = io_error.or(Some(err)),
            }
        }

        Err(unsuccessful
            .or(io_error)
            .expect("successful cases don't get here"))
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result {
        Command::new(app.into())
            .arg(path.as_ref())
            .output_stderr()
            .into_result()
    }

    // Polyfill to workaround absolute path bug in wslu(wslview). In versions before
    // v3.1.1, wslview is unable to find absolute paths. `wsl_path` converts an
    // absolute path into a relative path starting from the current directory. If
    // the path is already a relative path or the conversion fails the original path
    // is returned.
    fn wsl_path<T: AsRef<OsStr>>(path: T) -> OsString {
        fn path_relative_to_current_dir<T: AsRef<OsStr>>(path: T) -> Option<PathBuf> {
            let path = Path::new(&path);

            if path.is_relative() {
                return None;
            }

            let base = env::current_dir().ok()?;
            pathdiff::diff_paths(path, base)
        }

        match path_relative_to_current_dir(&path) {
            None => OsString::from(&path),
            Some(relative) => OsString::from(relative),
        }
    }
}
<|endoftext|>