<commit_before>//! The goal of this crate is to provide Rust bindings to the Web APIs and to allow
//! a high degree of interoperability between Rust and JavaScript.
//!
//! ## Examples
//!
//! You can directly embed JavaScript code into Rust:
//!
//! ```rust
//! let message = "Hello, 世界!";
//! let result = js! {
//!     alert( @{message} );
//!     return 2 + 2 * 2;
//! };
//!
//! println!( "2 + 2 * 2 = {:?}", result );
//! ```
//!
//! Even closures are supported:
//!
//! ```rust
//! let print_hello = |name: String| {
//!     println!( "Hello, {}!", name );
//! };
//!
//! js! {
//!     var print_hello = @{print_hello};
//!     print_hello( "Bob" );
//!     print_hello.drop(); // Necessary to clean up the closure on Rust's side.
//! }
//! ```
//!
//! You can also pass arbitrary structures thanks to [serde]:
//!
//! ```rust
//! #[derive(Serialize)]
//! struct Person {
//!     name: String,
//!     age: i32
//! }
//!
//! js_serializable!( Person );
//!
//! js! {
//!     var person = @{person};
//!     console.log( person.name + " is " + person.age + " years old." );
//! };
//! ```
//!
//! [serde]: https://serde.rs/
//!
//! This crate also exposes a number of Web APIs, for example:
//!
//! ```rust
//! let button = document().query_selector( "#hide-button" ).unwrap();
//! button.add_event_listener( move |_: ClickEvent| {
//!     for anchor in document().query_selector_all( "#main a" ) {
//!         js!( @{anchor}.style = "display: none;"; );
//!     }
//! });
//! ```

#![deny(
    missing_docs,
    missing_debug_implementations,
    trivial_numeric_casts,
    unused_import_braces,
    unused_qualifications
)]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![cfg_attr(
    all(target_arch = "wasm32", target_os = "unknown"),
    feature(proc_macro)
)]
#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
#![cfg_attr(feature = "nightly", feature(never_type))]
#![recursion_limit="1500"]

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde as serde_crate;

#[cfg(any(test, feature = "serde_json"))]
extern crate serde_json;

#[cfg(all(test, feature = "serde"))]
#[macro_use]
extern crate serde_derive;

#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
extern crate stdweb_internal_macros;

#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
pub use stdweb_internal_macros::js_export;

#[macro_use]
mod webcore;
mod webapi;
mod ecosystem;

pub use webcore::initialization::{
    initialize,
    event_loop
};
pub use webcore::value::{
    Undefined,
    Null,
    Value,
    Reference
};
pub use webcore::number::Number;
pub use webcore::object::Object;
pub use webcore::array::Array;

pub use webcore::unsafe_typed_array::UnsafeTypedArray;
pub use webcore::once::Once;

#[cfg(feature = "serde")]
/// A module with serde-related APIs.
pub mod serde {
    pub use ecosystem::serde::{
        ConversionError,
        Serde
    };
}

/// A module with bindings to the Web APIs.
pub mod web {
    pub use webapi::window::{
        Window,
        window
    };
    pub use webapi::document::{
        Document,
        document
    };
    pub use webapi::global::{
        set_timeout,
        alert
    };
    pub use webapi::cross_origin_setting::CrossOriginSetting;
    pub use webapi::date::Date;
    pub use webapi::event_target::{IEventTarget, EventTarget, EventListenerHandle};
    pub use webapi::window::RequestAnimationFrameHandle;
    pub use webapi::node::{INode, Node, CloneKind};
    pub use webapi::element::{IElement, Element};
    pub use webapi::text_node::TextNode;
    pub use webapi::html_element::{IHtmlElement, HtmlElement};
    pub use webapi::window_or_worker::IWindowOrWorker;
    pub use webapi::parent_node::IParentNode;
    pub use webapi::token_list::TokenList;
    pub use webapi::node_list::NodeList;
    pub use webapi::string_map::StringMap;
    pub use webapi::storage::Storage;
    pub use webapi::location::Location;
    pub use webapi::array_buffer::ArrayBuffer;
    pub use webapi::typed_array::TypedArray;
    pub use webapi::file_reader::{FileReader, FileReaderResult};
    pub use webapi::history::History;
    pub use webapi::web_socket::{WebSocket, SocketCloseCode};
    pub use webapi::rendering_context::{RenderingContext, CanvasRenderingContext2d};
    pub use webapi::mutation_observer::{MutationObserver, MutationObserverHandle, MutationObserverInit, MutationRecord};
    pub use webapi::xml_http_request::{XmlHttpRequest, XhrReadyState};

    /// A module containing error types.
    pub mod error {
        pub use webapi::dom_exception::{
            IDomException,
            DomException,
            ConcreteException,
            HierarchyRequestError,
            InvalidAccessError,
            NotFoundError,
            SecurityError,
            SyntaxError,
        };
        pub use webapi::error::{IError, Error};
    }

    /// A module containing HTML DOM elements.
    pub mod html_element {
        pub use webapi::html_elements::ImageElement;
        pub use webapi::html_elements::InputElement;
        pub use webapi::html_elements::TextAreaElement;
        pub use webapi::html_elements::CanvasElement;
    }

    /// A module containing JavaScript DOM events.
    pub mod event {
        pub use webapi::event::{
            IEvent,
            IUiEvent,
            ConcreteEvent,

            EventPhase
        };

        pub use webapi::events::mouse::{
            IMouseEvent,
            ClickEvent,
            DoubleClickEvent,
            MouseDownEvent,
            MouseUpEvent,
            MouseMoveEvent,

            MouseButton
        };

        pub use webapi::events::keyboard::{
            IKeyboardEvent,
            KeyPressEvent,
            KeyDownEvent,
            KeyUpEvent,

            KeyboardLocation,
            ModifierKey
        };

        pub use webapi::events::progress::{
            IProgressEvent,
            ProgressEvent,
            LoadStartEvent,
            LoadEndEvent,
            ProgressLoadEvent,
            ProgressAbortEvent,
            ProgressErrorEvent
        };

        pub use webapi::events::socket::{
            IMessageEvent,
            SocketCloseEvent,
            SocketErrorEvent,
            SocketOpenEvent,
            SocketMessageEvent
        };

        pub use webapi::events::history::{
            HashChangeEvent,
            PopStateEvent
        };

        pub use webapi::events::dom::{
            ChangeEvent,
            ResourceLoadEvent,
            ResourceAbortEvent,
            ResourceErrorEvent,
            ResizeEvent,
            InputEvent,
            ReadyStateChangeEvent
        };

        pub use webapi::events::focus::{
            IFocusEvent,
            FocusEvent,
            BlurEvent
        };
    }
}

/// A module containing stable counterparts to currently
/// unstable Rust features.
pub mod unstable {
    pub use webcore::try_from::{
        TryFrom,
        TryInto
    };

    pub use webcore::void::Void;
}

#[doc(hidden)]
pub mod private {
    pub use webcore::ffi::exports::*;
    pub use webcore::serialization::{
        JsSerializable,
        JsSerializableOwned,
        PreallocatedArena,
        SerializedValue
    };

    pub use webcore::newtype::{
        IntoNewtype,
        Newtype
    };

    pub use webcore::value::{
        FromReference,
        FromReferenceUnchecked
    };

    #[cfg(feature = "serde")]
    pub use ecosystem::serde::{
        to_value,
        from_value
    };

    // This is to prevent an unused_mut warnings in macros, because an `allow` doesn't work apparently?
    #[allow(dead_code)]
    #[inline(always)]
    pub fn noop< T >( _: &mut T ) {}

    // TODO: Remove this.
    #[derive(Debug)]
    pub struct UnimplementedException;
}
<commit_msg>Export `Blob` and `IBlob`<commit_after>//! The goal of this crate is to provide Rust bindings to the Web APIs and to allow
//! a high degree of interoperability between Rust and JavaScript.
//!
//! ## Examples
//!
//! You can directly embed JavaScript code into Rust:
//!
//! ```rust
//! let message = "Hello, 世界!";
//! let result = js! {
//!     alert( @{message} );
//!     return 2 + 2 * 2;
//! };
//!
//! println!( "2 + 2 * 2 = {:?}", result );
//! ```
//!
//! Even closures are supported:
//!
//! ```rust
//! let print_hello = |name: String| {
//!     println!( "Hello, {}!", name );
//! };
//!
//! js! {
//!     var print_hello = @{print_hello};
//!     print_hello( "Bob" );
//!     print_hello.drop(); // Necessary to clean up the closure on Rust's side.
//! }
//! ```
//!
//! You can also pass arbitrary structures thanks to [serde]:
//!
//! ```rust
//! #[derive(Serialize)]
//! struct Person {
//!     name: String,
//!     age: i32
//! }
//!
//! js_serializable!( Person );
//!
//! js! {
//!     var person = @{person};
//!     console.log( person.name + " is " + person.age + " years old." );
//! };
//! ```
//!
//! [serde]: https://serde.rs/
//!
//! This crate also exposes a number of Web APIs, for example:
//!
//! ```rust
//! let button = document().query_selector( "#hide-button" ).unwrap();
//! button.add_event_listener( move |_: ClickEvent| {
//!     for anchor in document().query_selector_all( "#main a" ) {
//!         js!( @{anchor}.style = "display: none;"; );
//!     }
//! });
//! ```

#![deny(
    missing_docs,
    missing_debug_implementations,
    trivial_numeric_casts,
    unused_import_braces,
    unused_qualifications
)]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![cfg_attr(
    all(target_arch = "wasm32", target_os = "unknown"),
    feature(proc_macro)
)]
#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
#![cfg_attr(feature = "nightly", feature(never_type))]
#![recursion_limit="1500"]

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde as serde_crate;

#[cfg(any(test, feature = "serde_json"))]
extern crate serde_json;

#[cfg(all(test, feature = "serde"))]
#[macro_use]
extern crate serde_derive;

#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
extern crate stdweb_internal_macros;

#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
pub use stdweb_internal_macros::js_export;

#[macro_use]
mod webcore;
mod webapi;
mod ecosystem;

pub use webcore::initialization::{
    initialize,
    event_loop
};
pub use webcore::value::{
    Undefined,
    Null,
    Value,
    Reference
};
pub use webcore::number::Number;
pub use webcore::object::Object;
pub use webcore::array::Array;

pub use webcore::unsafe_typed_array::UnsafeTypedArray;
pub use webcore::once::Once;

#[cfg(feature = "serde")]
/// A module with serde-related APIs.
pub mod serde {
    pub use ecosystem::serde::{
        ConversionError,
        Serde
    };
}

/// A module with bindings to the Web APIs.
pub mod web {
    pub use webapi::window::{
        Window,
        window
    };
    pub use webapi::document::{
        Document,
        document
    };
    pub use webapi::global::{
        set_timeout,
        alert
    };
    pub use webapi::cross_origin_setting::CrossOriginSetting;
    pub use webapi::date::Date;
    pub use webapi::event_target::{IEventTarget, EventTarget, EventListenerHandle};
    pub use webapi::window::RequestAnimationFrameHandle;
    pub use webapi::node::{INode, Node, CloneKind};
    pub use webapi::element::{IElement, Element};
    pub use webapi::text_node::TextNode;
    pub use webapi::html_element::{IHtmlElement, HtmlElement};
    pub use webapi::window_or_worker::IWindowOrWorker;
    pub use webapi::parent_node::IParentNode;
    pub use webapi::token_list::TokenList;
    pub use webapi::node_list::NodeList;
    pub use webapi::string_map::StringMap;
    pub use webapi::storage::Storage;
    pub use webapi::location::Location;
    pub use webapi::array_buffer::ArrayBuffer;
    pub use webapi::typed_array::TypedArray;
    pub use webapi::file_reader::{FileReader, FileReaderResult};
    pub use webapi::history::History;
    pub use webapi::web_socket::{WebSocket, SocketCloseCode};
    pub use webapi::rendering_context::{RenderingContext, CanvasRenderingContext2d};
    pub use webapi::mutation_observer::{MutationObserver, MutationObserverHandle, MutationObserverInit, MutationRecord};
    pub use webapi::xml_http_request::{XmlHttpRequest, XhrReadyState};
    pub use webapi::blob::{IBlob, Blob};

    /// A module containing error types.
    pub mod error {
        pub use webapi::dom_exception::{
            IDomException,
            DomException,
            ConcreteException,
            HierarchyRequestError,
            InvalidAccessError,
            NotFoundError,
            SecurityError,
            SyntaxError,
        };
        pub use webapi::error::{IError, Error};
    }

    /// A module containing HTML DOM elements.
    pub mod html_element {
        pub use webapi::html_elements::ImageElement;
        pub use webapi::html_elements::InputElement;
        pub use webapi::html_elements::TextAreaElement;
        pub use webapi::html_elements::CanvasElement;
    }

    /// A module containing JavaScript DOM events.
    pub mod event {
        pub use webapi::event::{
            IEvent,
            IUiEvent,
            ConcreteEvent,

            EventPhase
        };

        pub use webapi::events::mouse::{
            IMouseEvent,
            ClickEvent,
            DoubleClickEvent,
            MouseDownEvent,
            MouseUpEvent,
            MouseMoveEvent,

            MouseButton
        };

        pub use webapi::events::keyboard::{
            IKeyboardEvent,
            KeyPressEvent,
            KeyDownEvent,
            KeyUpEvent,

            KeyboardLocation,
            ModifierKey
        };

        pub use webapi::events::progress::{
            IProgressEvent,
            ProgressEvent,
            LoadStartEvent,
            LoadEndEvent,
            ProgressLoadEvent,
            ProgressAbortEvent,
            ProgressErrorEvent
        };

        pub use webapi::events::socket::{
            IMessageEvent,
            SocketCloseEvent,
            SocketErrorEvent,
            SocketOpenEvent,
            SocketMessageEvent
        };

        pub use webapi::events::history::{
            HashChangeEvent,
            PopStateEvent
        };

        pub use webapi::events::dom::{
            ChangeEvent,
            ResourceLoadEvent,
            ResourceAbortEvent,
            ResourceErrorEvent,
            ResizeEvent,
            InputEvent,
            ReadyStateChangeEvent
        };

        pub use webapi::events::focus::{
            IFocusEvent,
            FocusEvent,
            BlurEvent
        };
    }
}

/// A module containing stable counterparts to currently
/// unstable Rust features.
pub mod unstable {
    pub use webcore::try_from::{
        TryFrom,
        TryInto
    };

    pub use webcore::void::Void;
}

#[doc(hidden)]
pub mod private {
    pub use webcore::ffi::exports::*;
    pub use webcore::serialization::{
        JsSerializable,
        JsSerializableOwned,
        PreallocatedArena,
        SerializedValue
    };

    pub use webcore::newtype::{
        IntoNewtype,
        Newtype
    };

    pub use webcore::value::{
        FromReference,
        FromReferenceUnchecked
    };

    #[cfg(feature = "serde")]
    pub use ecosystem::serde::{
        to_value,
        from_value
    };

    // This is to prevent an unused_mut warnings in macros, because an `allow` doesn't work apparently?
    #[allow(dead_code)]
    #[inline(always)]
    pub fn noop< T >( _: &mut T ) {}

    // TODO: Remove this.
    #[derive(Debug)]
    pub struct UnimplementedException;
}
<|endoftext|>


<commit_before>#![deny(rust_2018_idioms)]
#![allow(clippy::too_many_arguments)]
#![recursion_limit = "1024"]

pub use crate::config::*;
pub use crate::currentprocess::varsource::*;
pub use crate::currentprocess::*;
pub use crate::errors::*;
pub use crate::notifications::*;
pub use crate::toolchain::*;
pub use crate::utils::{notify, toml_utils};

#[macro_use]
extern crate rs_tracing;

// A list of all binaries which Rustup will proxy.
pub static TOOLS: &[&str] = &[
    "rustc",
    "rustdoc",
    "cargo",
    "rust-lldb",
    "rust-gdb",
    "rls",
    "cargo-clippy",
    "clippy-driver",
    "cargo-miri",
];

// Tools which are commonly installed by Cargo as well as rustup. We take a bit
// more care with these to ensure we don't overwrite the user's previous
// installation.
pub static DUP_TOOLS: &[&str] = &["rustfmt", "cargo-fmt"];

fn component_for_bin(binary: &str) -> Option<&'static str> {
    use std::env::consts::EXE_SUFFIX;

    let binary_prefix = match binary.find(EXE_SUFFIX) {
        _ if EXE_SUFFIX.is_empty() => binary,
        Some(i) => &binary[..i],
        None => binary,
    };

    match binary_prefix {
        "rustc" | "rustdoc" => Some("rustc"),
        "cargo" => Some("cargo"),
        "rust-lldb" | "rust-gdb" => Some("rustc"), // These are not always available
        "rls" => Some("rls"),
        "cargo-clippy" => Some("clippy"),
        "clippy-driver" => Some("clippy"),
        "cargo-miri" => Some("miri"),
        "rustfmt" | "cargo-fmt" => Some("rustfmt"),
        _ => None,
    }
}

pub mod cli;
pub mod command;
mod config;
pub mod currentprocess;
pub mod diskio;
pub mod dist;
pub mod env_var;
pub mod errors;
pub mod fallback_settings;
mod install;
mod notifications;
pub mod settings;
pub mod toolchain;
pub mod utils;
<commit_msg>Add rust-analyzer proxy<commit_after>#![deny(rust_2018_idioms)]
#![allow(clippy::too_many_arguments)]
#![recursion_limit = "1024"]

pub use crate::config::*;
pub use crate::currentprocess::varsource::*;
pub use crate::currentprocess::*;
pub use crate::errors::*;
pub use crate::notifications::*;
pub use crate::toolchain::*;
pub use crate::utils::{notify, toml_utils};

#[macro_use]
extern crate rs_tracing;

// A list of all binaries which Rustup will proxy.
pub static TOOLS: &[&str] = &[
    "rustc",
    "rustdoc",
    "cargo",
    "rust-lldb",
    "rust-gdb",
    "rls",
    "rust-analyzer",
    "cargo-clippy",
    "clippy-driver",
    "cargo-miri",
];

// Tools which are commonly installed by Cargo as well as rustup. We take a bit
// more care with these to ensure we don't overwrite the user's previous
// installation.
pub static DUP_TOOLS: &[&str] = &["rustfmt", "cargo-fmt"];

fn component_for_bin(binary: &str) -> Option<&'static str> {
    use std::env::consts::EXE_SUFFIX;

    let binary_prefix = match binary.find(EXE_SUFFIX) {
        _ if EXE_SUFFIX.is_empty() => binary,
        Some(i) => &binary[..i],
        None => binary,
    };

    match binary_prefix {
        "rustc" | "rustdoc" => Some("rustc"),
        "cargo" => Some("cargo"),
        "rust-lldb" | "rust-gdb" => Some("rustc"), // These are not always available
        "rls" => Some("rls"),
        "cargo-clippy" => Some("clippy"),
        "clippy-driver" => Some("clippy"),
        "cargo-miri" => Some("miri"),
        "rustfmt" | "cargo-fmt" => Some("rustfmt"),
        _ => None,
    }
}

pub mod cli;
pub mod command;
mod config;
pub mod currentprocess;
pub mod diskio;
pub mod dist;
pub mod env_var;
pub mod errors;
pub mod fallback_settings;
mod install;
mod notifications;
pub mod settings;
pub mod toolchain;
pub mod utils;
<|endoftext|>


<commit_before>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Client- and server-side abstractions for HTTP `multipart/form-data` requests.
//!
//! Features:
//!
//! * `client` (default): Enable the client-side abstractions for multipart requests. If the
//! `hyper` feature is also set, enables integration with the Hyper HTTP client API.
//!
//! * `server` (default): Enable the server-side abstractions for multipart requests. If the
//! `hyper` feature is also set, enables integration with the Hyper HTTP server API.
//!
//! * `hyper` (default): Enable integration with the [Hyper](https:://github.com/hyperium/hyper) HTTP library
//! for client and/or server depending on which other feature flags are set.
//!
//! * `iron`: Enable integration with the [Iron](http://ironframework.io) web application
//! framework. See the [`server::iron`](server/iron/index.html) module for more information.
//!
//! * `tiny_http`: Enable integration with the [`tiny_http`](https://github.com/frewsxcv/tiny-http)
//! crate. See the [`server::tiny_http`](server/tiny_http/index.html) module for more information.
#![warn(missing_docs)]
#[macro_use] extern crate log;
extern crate env_logger;

extern crate mime;
extern crate mime_guess;
extern crate rand;

extern crate tempdir;

#[cfg(feature = "hyper")]
extern crate hyper;

#[cfg(feature = "iron")]
extern crate iron;

#[cfg(feature = "nickel")]
extern crate nickel;

#[cfg(feature = "tiny_http")]
extern crate tiny_http;

use rand::Rng;

/// Chain a series of results together, with or without previous results.
///
/// ```
/// #[macro_use] extern crate multipart;
///
/// fn try_add_one(val: u32) -> Result<u32, u32> {
///     if val < 5 {
///         Ok(val + 1)
///     } else {
///         Err(val)
///     }
/// }
///
/// fn main() {
///     let res = chain_result! {
///         try_add_one(1),
///         prev -> try_add_one(prev),
///         prev -> try_add_one(prev),
///         prev -> try_add_one(prev)
///     };
///
///     println!("{:?}", res);
/// }
///
/// ```
#[macro_export]
macro_rules! chain_result {
    ($first_expr:expr, $($try_expr:expr),*) => (
        $first_expr $(.and_then(|_| $try_expr))*
    );
    ($first_expr:expr, $($($arg:ident),+ -> $try_expr:expr),*) => (
        $first_expr $(.and_then(|$($arg),+| $try_expr))*
    );
}

#[cfg(feature = "client")]
pub mod client;
#[cfg(feature = "server")]
pub mod server;

#[cfg(all(test, feature = "client", feature = "server"))]
mod local_test;

fn random_alphanumeric(len: usize) -> String {
    rand::thread_rng().gen_ascii_chars().take(len).collect()
}

<commit_msg>Fix typo that breaks the link to the Hyper repo<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Client- and server-side abstractions for HTTP `multipart/form-data` requests.
//!
//! Features:
//!
//! * `client` (default): Enable the client-side abstractions for multipart requests. If the
//! `hyper` feature is also set, enables integration with the Hyper HTTP client API.
//!
//! * `server` (default): Enable the server-side abstractions for multipart requests. If the
//! `hyper` feature is also set, enables integration with the Hyper HTTP server API.
//!
//! * `hyper` (default): Enable integration with the [Hyper](https://github.com/hyperium/hyper) HTTP library
//! for client and/or server depending on which other feature flags are set.
//!
//! * `iron`: Enable integration with the [Iron](http://ironframework.io) web application
//! framework. See the [`server::iron`](server/iron/index.html) module for more information.
//!
//! * `tiny_http`: Enable integration with the [`tiny_http`](https://github.com/frewsxcv/tiny-http)
//! crate. See the [`server::tiny_http`](server/tiny_http/index.html) module for more information.
#![warn(missing_docs)]
#[macro_use] extern crate log;
extern crate env_logger;

extern crate mime;
extern crate mime_guess;
extern crate rand;

extern crate tempdir;

#[cfg(feature = "hyper")]
extern crate hyper;

#[cfg(feature = "iron")]
extern crate iron;

#[cfg(feature = "nickel")]
extern crate nickel;

#[cfg(feature = "tiny_http")]
extern crate tiny_http;

use rand::Rng;

/// Chain a series of results together, with or without previous results.
///
/// ```
/// #[macro_use] extern crate multipart;
///
/// fn try_add_one(val: u32) -> Result<u32, u32> {
///     if val < 5 {
///         Ok(val + 1)
///     } else {
///         Err(val)
///     }
/// }
///
/// fn main() {
///     let res = chain_result! {
///         try_add_one(1),
///         prev -> try_add_one(prev),
///         prev -> try_add_one(prev),
///         prev -> try_add_one(prev)
///     };
///
///     println!("{:?}", res);
/// }
///
/// ```
#[macro_export]
macro_rules! chain_result {
    ($first_expr:expr, $($try_expr:expr),*) => (
        $first_expr $(.and_then(|_| $try_expr))*
    );
    ($first_expr:expr, $($($arg:ident),+ -> $try_expr:expr),*) => (
        $first_expr $(.and_then(|$($arg),+| $try_expr))*
    );
}

#[cfg(feature = "client")]
pub mod client;
#[cfg(feature = "server")]
pub mod server;

#[cfg(all(test, feature = "client", feature = "server"))]
mod local_test;

fn random_alphanumeric(len: usize) -> String {
    rand::thread_rng().gen_ascii_chars().take(len).collect()
}

<|endoftext|>


<commit_before>#![feature(test)]
#![feature(integer_atomics)]
#![allow(match_ref_pats)]
#![allow(too_many_arguments)]
#![allow(unknown_lints)]

#[macro_use] extern crate nom;
#[macro_use] extern crate lazy_static;

extern crate ignore;
extern crate regex;
extern crate colored;

#[macro_use] mod macros;
pub mod test;
pub mod types;
pub mod error;
pub mod cli_helpers;
pub mod gitignore;

pub mod prelude {

    //use std::os::unix::fs::{MetadataExt};
    use std::sync::Arc;
    use std::fs;
    use std::path::{PathBuf, Path};
    use regex::{Regex, RegexSet};
    use types::*;
    use gitignore::*;
    use colored::*;
    use std::io::prelude::*;
    use std::process::exit;
    use ignore::{WalkBuilder, WalkState};
    use std::fs::{Metadata, File};
    use std::sync::atomic::{AtomicU64, Ordering};

    #[cfg(not(target_os = "windows"))]
    use std::os::unix::fs::PermissionsExt;

    pub use cli_helpers::*;
    pub use error::*;

    /// Helper function to determine whether a path points
    ///
    /// Rules:
    /// - if the file extension of that is that of an artifact, return true
    /// - if the file is executable and included in the .gitignore, return true
    /// - return false otherwise
    ///
    /// Explanation of extensions:
    /// - `.a`, `.la`, `.o`, `.lo`, `.so.*`:
    /// - `.S`: assembly
    /// - .ll, `.bc`: llvm
    /// - `.keter`: keter
    /// - `.d`: make
    /// - `.rlib`, `.crate`: rust
    /// - `.hi`, `.dyn_hi`, `.dyn_o`, `.p_hi`, `.p_o`, `.prof`, `.dump-.*`, `.tix`: GHC
    /// - `.webapp`: Web app manifest
    /// - `.js.externs`, `.jsexe`, `.min.js`:
    /// - `.ibc`: Idris
    /// - `.toc`, `.aux`, `.fdb_latexmk`, `.fls`: TeX
    /// - `.egg-info`, `.whl`, `.pyc`: python
    /// - `.js_a`, `.js_hi`, `.js_o`: GHCJS
    /// - `.vmb`: Vim
    /// - `.crx`: chrome
    /// - `.elmo`, `.elmi`: Elm
    /// - `.mod`: FORTRAN
    /// - `.ji`, `.jld`: julia
    #[cfg(not(target_os = "windows"))]
    pub fn is_artifact(path_str: &str, full_path: &str, re: Option<&Regex>, metadata: &Metadata, gitignore: &Option<RegexSet>) -> bool {

        // match on the user's expression if it exists
        if let Some(r) = re {
            r.is_match(path_str) // FIXME include .gitignore as well?
        }

        // otherwise, use builtin expressions
        else {
            lazy_static! {
                static ref REGEX: Regex =
                    Regex::new(r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$") // TODO reorder regex
                    .unwrap();
            }
            lazy_static! {
                static ref REGEX_GITIGNORE: Regex =
                    Regex::new(r".*?\.(stats|conf|h|cache.*|dat|pc|info)$")
                    .unwrap();
            }
            if REGEX.is_match(path_str) { true }
            else if let &Some(ref x) = gitignore {
                if metadata.permissions().mode() == 0o755 || REGEX_GITIGNORE.is_match(path_str)
                    { x.is_match(full_path) }
                else { false }
            }
            else { false }
        }
    }

    #[cfg(target_os = "windows")]
    pub fn is_artifact(path_str: &str, full_path: &str, re: Option<&Regex>, _: &Metadata, gitignore:&Option<RegexSet>) -> bool {
        if let Some(r) = re {
            r.is_match(path_str)
        }
        else {
            lazy_static! {
                static ref REGEX: Regex =
                    Regex::new(r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$")
                    .unwrap();
            }
            lazy_static! {
                static ref REGEX_GITIGNORE: Regex =
                    Regex::new(r".*?\.(stats|conf|h|cache.*)$")
                    .unwrap();
            }
            if REGEX.is_match(&path_str) { true }

            else if let &Some(ref x) = gitignore {
                if REGEX_GITIGNORE.is_match(path_str) {
                    x.is_match(full_path)
                } else { false }
            }
            else { false }
        }
    }

    pub fn read_parallel(in_paths: &Path,
                         max_depth: Option<usize>, // optionally include a max depth to which to recurse
                         _: Option<&Regex>,
                         show_hidden: bool,
                         //maybe_gitignore: Option<RegexSet>,
                         //with_gitignore: bool,
                         silent: bool,
                         artifacts_only: bool,
                         follow_symlinks: bool) -> FileSize {

        // create new walk + set file size to zero
        let mut builder = WalkBuilder::new(in_paths);
        //let mut dir_size = AtomicU64::new(0);
        let dir_size = Arc::new(AtomicU64::new(0));

        // set options for our walk
        builder.max_depth(max_depth);
        builder.hidden(show_hidden);
        builder.follow_links(follow_symlinks);
        builder.ignore(false);
        builder.git_ignore(false);
        builder.git_exclude(false);
        builder.git_global(false);

        // runs loop
        builder.build_parallel().run(|| { let filesize_dir = dir_size.clone() ; Box::new(move |path| {

            if let Ok(p) = path {
                if p.path().is_file() {
                    if let Ok (f) = p.file_name().to_owned().into_string() {
                        if let Ok(metadata) = p.metadata() {
                            if !artifacts_only || is_artifact(&f, "", None, &metadata, &None) {
                                let file_size = FileSize::new(metadata.len());
                                filesize_dir.fetch_add(metadata.len(), Ordering::SeqCst);
                                if !silent {
                                    let formatted = format!("{}", file_size);
                                    if let Ok(s) = p.path().as_os_str().to_owned().into_string() {
                                        println!("{}\t {}", formatted.green(), s);
                                    }
                                    else {
                                        eprintln!("{}: ignoring invalid unicode {:?}", "Warning".yellow(), p.path())
                                    }
                                }
                            }
                        }
                        else if follow_symlinks {
                            let s = p.path().as_os_str().to_owned().into_string().expect("OS String failed to resolve");
                            eprintln!("{}: ignoring broken symlink at {}", "Warning".yellow(), s);
                        }
                    }
                    else {
                        eprintln!("{}: ignoring invalid unicode {:?}", "Warning".yellow(), p.path())
                    }
                }
            }
            else if let Err(e) = path {
                eprintln!("{}: failed to get path data from:\n{:?}", "Warning".yellow(), e);
            }
            ; WalkState::Continue }) } );

        FileSize::new(Arc::try_unwrap(dir_size).unwrap().into_inner())

    }

    /// Function to process directory contents and return a `FileTree` struct.
    pub fn read_all(in_paths: &PathBuf,
                          depth: u8,
                          max_depth: Option<u8>,
                          min_bytes: Option<u64>,
                          artifact_regex: Option<&Regex>,
                          excludes: Option<&Regex>,
                          silent: bool,
                          maybe_gitignore: &Option<RegexSet>,
                          with_gitignore: bool,
                          artifacts_only: bool) -> FileTree {

        // make this an input later
        let force_parallel = false;

        // attempt to read the .gitignore
        let mut tree = FileTree::new();
        let min_size = min_bytes.map(FileSize::new);
        let gitignore = if with_gitignore {
            if let Some(ref gitignore) = *maybe_gitignore { Some(gitignore.to_owned()) } // TODO get rid of this
            else {
                let mut gitignore_path = in_paths.clone();
                gitignore_path.push(".gitignore");
                if let Ok(mut file) = File::open(gitignore_path.clone()) {
                    let mut contents = String::new();
                    file.read_to_string(&mut contents)
                        .expect("File read failed.");
                    Some(file_contents_to_regex(&contents, &gitignore_path))
                } else { None }
            }
        } else { None };

        // try to read directory contents
        if let Ok(paths) = fs::read_dir(in_paths) {

            // iterate over all the entries in the directory
            for p in paths {
                let path = p.unwrap().path(); // TODO no unwraps; idk what this error would be though.
                let (path_string, bool_loop): (String, bool) = if let Ok(x) = path.clone().into_os_string().into_string() {
                    let bool_loop = match excludes {
                        Some(ex) => !ex.is_match(&x),
                        _ => true,
                    };

                    (x, bool_loop)
                }
                else {
                    eprintln!("{}: skipping invalid unicode filepath at {:?}", "Warning".yellow(), path); // TODO consider byte matching here?
                    ("".to_string(), false)
                };

                // only consider path if we're not using regex excludes or if they don't match the
                // exclusion regex
                if bool_loop {

                    // if this fails, it's probably because `path` is a broken symlink
                    if let Ok(metadata) = fs::symlink_metadata(&path) {

                        // append file size/name for a file
                        if metadata.is_file() {
                            let file = path.file_name().unwrap().to_owned().into_string().unwrap(); // ok because we already checked // TODO
                            if !artifacts_only || is_artifact(&file, &path_string, artifact_regex, &metadata, &gitignore) { // should check size before whether it's an artifact?
                                let file_size = FileSize::new(metadata.len());//blocks() * 512);
                                if let Some(b) = min_bytes {
                                    if file_size >= FileSize::new(b) {
                                            tree.push(path_string, file_size, None, depth + 1, false, min_size);
                                        }
                                    }
                                else {
                                    tree.push(path_string, file_size, None, depth + 1, false, min_size);
                                }
                            }
                        }

                        // otherwise, go deeper
                        else if metadata.is_dir() { // TODO iterate in parallel if we've hit max depth.
                            if let Some(d) = max_depth {
                                if depth + 1 > d && force_parallel {
                                    let dir_size = if !artifacts_only {
                                        read_parallel(&path, None, None, true, true, artifacts_only, false)
                                    }
                                    else {
                                        let subtree = read_all(&path, depth + 1, max_depth, min_bytes, artifact_regex, excludes, silent, &gitignore, with_gitignore, artifacts_only);
                                        subtree.file_size
                                    };
                                    if let Some(b) = min_bytes {
                                        if dir_size >= FileSize::new(b) {
                                            tree.push(path_string, dir_size, None, depth + 1, true, min_size);
                                        }
                                    }
                                    else {
                                    tree.push(path_string, dir_size, None, depth + 1, true, min_size); }
                                }
                                else {
                                    let mut subtree = read_all(&path, depth + 1, max_depth, min_bytes, artifact_regex, excludes, silent, &gitignore, with_gitignore, artifacts_only);
                                    let dir_size = subtree.file_size;
                                    if let Some(b) = min_bytes {
                                        if dir_size >= FileSize::new(b) {
                                            tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, true, min_size);
                                        }
                                    }
                                    else { tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, true, min_size); }
                                }
                            }
                            else {
                                let mut subtree = read_all(&path, depth + 1, max_depth, min_bytes, artifact_regex, excludes, silent, &gitignore, with_gitignore, artifacts_only);
                                let dir_size = subtree.file_size;
                                if let Some(b) = min_bytes {
                                    if dir_size >= FileSize::new(b) {
                                        tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, true, min_size);
                                    }
                                }
                                else { tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, true, min_size); }
                            }
                        }
                    }
                    else if !silent { eprintln!("{}: ignoring symlink at {}", "Warning".yellow(), path.display()); }
                }
            }
        }

        // if we can't read the directory contents, figure out why
        // 1: check the path exists
        else if !in_paths.exists() {
            eprintln!("{}: path '{}' does not exist.", "Error".red(), &in_paths.display());
            exit(0x0001);
        }
        // 2: check the path is actually a directory
        else if !in_paths.is_dir() {
            eprintln!("{}: {} is not a directory.", "Error".red(), &in_paths.display());
            exit(0x0001);
        }
        // 3: otherwise, give a warning about permissions
        else if !silent {
            eprintln!("{}: permission denied for directory: {}", "Warning".yellow(), &in_paths.display());
        }

        tree
    }
}
<commit_msg>speed improvements from better recursing<commit_after>#![feature(test)]
#![feature(integer_atomics)]
#![allow(match_ref_pats)]
#![allow(too_many_arguments)]
#![allow(unknown_lints)]

#[macro_use] extern crate nom;
#[macro_use] extern crate lazy_static;

extern crate ignore;
extern crate regex;
extern crate colored;

#[macro_use] mod macros;
pub mod test;
pub mod types;
pub mod error;
pub mod cli_helpers;
pub mod gitignore;

pub mod prelude {

    //use std::os::unix::fs::{MetadataExt};
    use std::sync::Arc;
    use std::fs;
    use std::path::{PathBuf, Path};
    use regex::{Regex, RegexSet};
    use types::*;
    use gitignore::*;
    use colored::*;
    use std::io::prelude::*;
    use std::process::exit;
    use ignore::{WalkBuilder, WalkState};
    use std::fs::{Metadata, File};
    use std::sync::atomic::{AtomicU64, Ordering};

    #[cfg(not(target_os = "windows"))]
    use std::os::unix::fs::PermissionsExt;

    pub use cli_helpers::*;
    pub use error::*;

    /// Helper function to determine whether a path points
    ///
    /// Rules:
    /// - if the file extension of that is that of an artifact, return true
    /// - if the file is executable and included in the .gitignore, return true
    /// - return false otherwise
    ///
    /// Explanation of extensions:
    /// - `.a`, `.la`, `.o`, `.lo`, `.so.*`:
    /// - `.S`: assembly
    /// - .ll, `.bc`: llvm
    /// - `.keter`: keter
    /// - `.d`: make
    /// - `.rlib`, `.crate`: rust
    /// - `.hi`, `.dyn_hi`, `.dyn_o`, `.p_hi`, `.p_o`, `.prof`, `.dump-.*`, `.tix`: GHC
    /// - `.webapp`: Web app manifest
    /// - `.js.externs`, `.jsexe`, `.min.js`:
    /// - `.ibc`: Idris
    /// - `.toc`, `.aux`, `.fdb_latexmk`, `.fls`: TeX
    /// - `.egg-info`, `.whl`, `.pyc`: python
    /// - `.js_a`, `.js_hi`, `.js_o`: GHCJS
    /// - `.vmb`: Vim
    /// - `.crx`: chrome
    /// - `.elmo`, `.elmi`: Elm
    /// - `.mod`: FORTRAN
    /// - `.ji`, `.jld`: julia
    #[cfg(not(target_os = "windows"))]
    pub fn is_artifact(path_str: &str, full_path: &str, re: Option<&Regex>, metadata: &Metadata, gitignore: &Option<RegexSet>) -> bool {

        // match on the user's expression if it exists
        if let Some(r) = re {
            r.is_match(path_str) // FIXME include .gitignore as well?
        }

        // otherwise, use builtin expressions
        else {
            lazy_static! {
                static ref REGEX: Regex =
                    Regex::new(r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$") // TODO reorder regex
                    .unwrap();
            }
            lazy_static! {
                static ref REGEX_GITIGNORE: Regex =
                    Regex::new(r".*?\.(stats|conf|h|cache.*|dat|pc|info)$")
                    .unwrap();
            }
            if REGEX.is_match(path_str) { true }
            else if let &Some(ref x) = gitignore {
                if metadata.permissions().mode() == 0o755 || REGEX_GITIGNORE.is_match(path_str)
                    { x.is_match(full_path) }
                else { false }
            }
            else { false }
        }
    }

    #[cfg(target_os = "windows")]
    pub fn is_artifact(path_str: &str, full_path: &str, re: Option<&Regex>, _: &Metadata, gitignore:&Option<RegexSet>) -> bool {
        if let Some(r) = re {
            r.is_match(path_str)
        }
        else {
            lazy_static! {
                static ref REGEX: Regex =
                    Regex::new(r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$")
                    .unwrap();
            }
            lazy_static! {
                static ref REGEX_GITIGNORE: Regex =
                    Regex::new(r".*?\.(stats|conf|h|cache.*)$")
                    .unwrap();
            }
            if REGEX.is_match(&path_str) { true }

            else if let &Some(ref x) = gitignore {
                if REGEX_GITIGNORE.is_match(path_str) {
                    x.is_match(full_path)
                } else { false }
            }
            else { false }
        }
    }

    pub fn read_parallel(in_paths: &Path,
                         max_depth: Option<usize>, // optionally include a max depth to which to recurse
                         _: Option<&Regex>,
                         show_hidden: bool,
                         //maybe_gitignore: Option<RegexSet>,
                         //with_gitignore: bool,
                         silent: bool,
                         artifacts_only: bool,
                         follow_symlinks: bool) -> FileSize {

        // create new walk + set file size to zero
        let mut builder = WalkBuilder::new(in_paths);
        //let mut dir_size = AtomicU64::new(0);
        let dir_size = Arc::new(AtomicU64::new(0));

        // set options for our walk
        builder.max_depth(max_depth);
        builder.hidden(show_hidden);
        builder.follow_links(follow_symlinks);
        builder.ignore(false);
        builder.git_ignore(false);
        builder.git_exclude(false);
        builder.git_global(false);

        // runs loop
        builder.build_parallel().run(|| { let filesize_dir = dir_size.clone() ; Box::new(move |path| {

            if let Ok(p) = path {
                if p.path().is_file() {
                    if let Ok (f) = p.file_name().to_owned().into_string() {
                        if let Ok(metadata) = p.metadata() {
                            if !artifacts_only || is_artifact(&f, "", None, &metadata, &None) {
                                let file_size = FileSize::new(metadata.len());
                                filesize_dir.fetch_add(metadata.len(), Ordering::SeqCst);
                                if !silent {
                                    let formatted = format!("{}", file_size);
                                    if let Ok(s) = p.path().as_os_str().to_owned().into_string() {
                                        println!("{}\t {}", formatted.green(), s);
                                    }
                                    else {
                                        eprintln!("{}: ignoring invalid unicode {:?}", "Warning".yellow(), p.path())
                                    }
                                }
                            }
                        }
                        else if follow_symlinks {
                            let s = p.path().as_os_str().to_owned().into_string().expect("OS String failed to resolve");
                            eprintln!("{}: ignoring broken symlink at {}", "Warning".yellow(), s);
                        }
                    }
                    else {
                        eprintln!("{}: ignoring invalid unicode {:?}", "Warning".yellow(), p.path())
                    }
                }
            }
            else if let Err(e) = path {
                eprintln!("{}: failed to get path data from:\n{:?}", "Warning".yellow(), e);
            }
            ; WalkState::Continue }) } );

        FileSize::new(Arc::try_unwrap(dir_size).unwrap().into_inner())

    }

    /// Function to process directory contents and return a `FileTree` struct.
    pub fn read_all(in_paths: &PathBuf,
                          depth: u8,
                          max_depth: Option<u8>,
                          min_bytes: Option<u64>,
                          artifact_regex: Option<&Regex>,
                          excludes: Option<&Regex>,
                          silent: bool,
                          maybe_gitignore: &Option<RegexSet>,
                          with_gitignore: bool,
                          artifacts_only: bool) -> FileTree {

        // make this an input later
        let force_parallel = false;

        // attempt to read the .gitignore
        let mut tree = FileTree::new();
        let min_size = min_bytes.map(FileSize::new);
        let gitignore = if with_gitignore {
            if let Some(ref gitignore) = *maybe_gitignore { Some(gitignore.to_owned()) } // TODO get rid of this
            else {
                let mut gitignore_path = in_paths.clone();
                gitignore_path.push(".gitignore");
                if let Ok(mut file) = File::open(gitignore_path.clone()) {
                    let mut contents = String::new();
                    file.read_to_string(&mut contents)
                        .expect("File read failed.");
                    Some(file_contents_to_regex(&contents, &gitignore_path))
                } else { None }
            }
        } else { None };

        // try to read directory contents
        if let Ok(paths) = fs::read_dir(in_paths) {

            // iterate over all the entries in the directory
            for p in paths {
                let path = p.unwrap().path(); // TODO no unwraps; idk what this error would be though.
                let (path_string, bool_loop): (String, bool) = if let Ok(x) = path.clone().into_os_string().into_string() {
                    let bool_loop = match excludes {
                        Some(ex) => !ex.is_match(&x),
                        _ => true,
                    };

                    (x, bool_loop)
                }
                else {
                    eprintln!("{}: skipping invalid unicode filepath at {:?}", "Warning".yellow(), path); // TODO consider byte matching here?
                    ("".to_string(), false)
                };

                // only consider path if we're not using regex excludes or if they don't match the
                // exclusion regex
                if bool_loop {

                    // if this fails, it's probably because `path` is a broken symlink
                    if let Ok(metadata) = fs::symlink_metadata(&path) {

                        // append file size/name for a file
                        if metadata.is_file() {
                            let file = path.file_name().unwrap().to_owned().into_string().unwrap(); // ok because we already checked // TODO
                            if !artifacts_only || is_artifact(&file, &path_string, artifact_regex, &metadata, &gitignore) { // should check size before whether it's an artifact?
                                let file_size = FileSize::new(metadata.len());//blocks() * 512);
                                if let Some(b) = min_bytes {
                                    if file_size >= FileSize::new(b) {
                                            tree.push(path_string, file_size, None, depth + 1, false, min_size);
                                        }
                                    }
                                else {
                                    tree.push(path_string, file_size, None, depth + 1, false, min_size);
                                }
                            }
                        }

                        // otherwise, go deeper
                        else if metadata.is_dir() { // TODO iterate in parallel if we've hit max depth.
                            if let Some(d) = max_depth {
                                if depth + 1 > d {
                                    let dir_size = if !artifacts_only && force_parallel {
                                        read_parallel(&path, None, None, true, true, artifacts_only, false)
                                    }
                                    else {
                                        let subtree = read_all(&path, depth + 1, max_depth, min_bytes, artifact_regex, excludes, silent, &gitignore, with_gitignore, artifacts_only);
                                        subtree.file_size
                                    };
                                    if let Some(b) = min_bytes {
                                        if dir_size >= FileSize::new(b) {
                                            tree.push(path_string, dir_size, None, depth + 1, true, min_size);
                                        }
                                    }
                                    else {
                                    tree.push(path_string, dir_size, None, depth + 1, true, min_size); }
                                }
                                else {
                                    let mut subtree = read_all(&path, depth + 1, max_depth, min_bytes, artifact_regex, excludes, silent, &gitignore, with_gitignore, artifacts_only);
                                    let dir_size = subtree.file_size;
                                    if let Some(b) = min_bytes {
                                        if dir_size >= FileSize::new(b) {
                                            tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, true, min_size);
                                        }
                                    }
                                    else { tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, true, min_size); }
                                }
                            }
                            else {
                                let mut subtree = read_all(&path, depth + 1, max_depth, min_bytes, artifact_regex, excludes, silent, &gitignore, with_gitignore, artifacts_only);
                                let dir_size = subtree.file_size;
                                if let Some(b) = min_bytes {
                                    if dir_size >= FileSize::new(b) {
                                        tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, true, min_size);
                                    }
                                }
                                else { tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, true, min_size); }
                            }
                        }
                    }
                    else if !silent { eprintln!("{}: ignoring symlink at {}", "Warning".yellow(), path.display()); }
                }
            }
        }

        // if we can't read the directory contents, figure out why
        // 1: check the path exists
        else if !in_paths.exists() {
            eprintln!("{}: path '{}' does not exist.", "Error".red(), &in_paths.display());
            exit(0x0001);
        }
        // 2: check the path is actually a directory
        else if !in_paths.is_dir() {
            eprintln!("{}: {} is not a directory.", "Error".red(), &in_paths.display());
            exit(0x0001);
        }
        // 3: otherwise, give a warning about permissions
        else if !silent {
            eprintln!("{}: permission denied for directory: {}", "Warning".yellow(), &in_paths.display());
        }

        tree
    }
}
<|endoftext|>


<commit_before>//! Does all the magic to have you potentially long output piped through the
//! external pager. Similar to what git does for its output.
//!
//! # Quick Start
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::new().setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! Under the hood this forks the current process, connects child' stdout
//! to parent's stdin, and then replaces the parent with the pager of choice
//! (environment variable PAGER). The child just continues as normal. If PAGER
//! environment variable is not present `Pager` probes current PATH for `more`.
//! If found it is used as a default pager.
//!
//! You can control pager to a limited degree. For example you can change the
//! environment variable used for finding pager executable.
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::env("MY_PAGER").setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! Alternatively you can specify directly the desired pager command, exactly
//! as it would appear in PAGER environment variable. This is useful if you
//! need some specific pager and/or flags (like "less -r") and would like to
//! avoid forcing your consumers into modifying their existing PAGER
//! configuration just for your application.
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::with_pager("less -r").setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! If no suitable pager found `setup()` does nothing and your executable keeps
//! running as usual. `Pager` cleans after itself and doesn't leak resources in
//! case of setup failure.
//!
//! If you need to disable pager altogether set environment variable `NOPAGER` and `Pager::setup()`
//! will skip initialization. The host application will continue as normal. `Pager::is_on()` will
//! reflect the fact that no Pager is active.

extern crate errno;
extern crate libc;

mod utils;

use std::ffi::OsString;

const DEFAULT_PAGER_ENV: &str = "PAGER";

#[derive(Debug, Default)]
pub struct Pager {
    pager: Option<OsString>,
    env: Option<String>,
    on: bool,
}

impl Pager {
    /// Creates new instance of pager with default settings
    pub fn new() -> Self {
        Pager::env(DEFAULT_PAGER_ENV)
    }

    /// Creates new instance of pager using `env` environment variable instead of PAGER
    pub fn env(env: &str) -> Self {
        let pager = utils::find_pager(env);

        Pager {
            pager: pager,
            env: String::from(env).into(),
            on: true,
        }
    }

    /// Creates a new pager instance directly specifying the desired pager
    pub fn with_pager(pager: &str) -> Self {
        Pager {
            pager: OsString::from(pager).into(),
            env: None,
            on: true,
        }
    }

    /// Gives quick assessment of successful Pager setup
    pub fn is_on(&self) -> bool {
        self.on
    }

    /// Initiates Pager framework and sets up all the necessary environment for sending standard
    /// output to the activated pager.
    pub fn setup(&mut self) {
        if let Some(ref pager) = self.pager {
            let (pager_stdin, main_stdout) = utils::pipe();
            let pid = utils::fork();
            match pid {
                -1 => {
                    // Fork failed
                    utils::close(pager_stdin);
                    utils::close(main_stdout);
                    self.on = false
                }
                0 => {
                    // I am child
                    utils::dup2(main_stdout, libc::STDOUT_FILENO);
                    utils::close(pager_stdin);
                }
                _ => {
                    // I am parent
                    utils::dup2(pager_stdin, libc::STDIN_FILENO);
                    utils::close(main_stdout);
                    utils::execvp(pager);
                }
            }
        }
    }
}
<commit_msg>Introduce with_env() and deprecate env()<commit_after>//! Does all the magic to have you potentially long output piped through the
//! external pager. Similar to what git does for its output.
//!
//! # Quick Start
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::new().setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! Under the hood this forks the current process, connects child' stdout
//! to parent's stdin, and then replaces the parent with the pager of choice
//! (environment variable PAGER). The child just continues as normal. If PAGER
//! environment variable is not present `Pager` probes current PATH for `more`.
//! If found it is used as a default pager.
//!
//! You can control pager to a limited degree. For example you can change the
//! environment variable used for finding pager executable.
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::with_env("MY_PAGER").setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! Alternatively you can specify directly the desired pager command, exactly
//! as it would appear in PAGER environment variable. This is useful if you
//! need some specific pager and/or flags (like "less -r") and would like to
//! avoid forcing your consumers into modifying their existing PAGER
//! configuration just for your application.
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::with_pager("less -r").setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! If no suitable pager found `setup()` does nothing and your executable keeps
//! running as usual. `Pager` cleans after itself and doesn't leak resources in
//! case of setup failure.
//!
//! If you need to disable pager altogether set environment variable `NOPAGER` and `Pager::setup()`
//! will skip initialization. The host application will continue as normal. `Pager::is_on()` will
//! reflect the fact that no Pager is active.

extern crate errno;
extern crate libc;

mod utils;

use std::ffi::OsString;

const DEFAULT_PAGER_ENV: &str = "PAGER";

#[derive(Debug, Default)]
pub struct Pager {
    pager: Option<OsString>,
    env: Option<String>,
    on: bool,
}

impl Pager {
    /// Creates new instance of pager with default settings
    pub fn new() -> Self {
        Pager::with_env(DEFAULT_PAGER_ENV)
    }

    /// Creates new instance of pager using `env` environment variable instead of PAGER
    pub fn with_env(env: &str) -> Self {
        let pager = utils::find_pager(env);

        Pager {
            pager: pager,
            env: String::from(env).into(),
            on: true,
        }
    }

    #[deprecated(since = "0.12.0", note = "use with_env() instead")]
    pub fn env(env: &str) -> Self {
        Pager::with_env(env)
    }

    /// Creates a new pager instance directly specifying the desired pager
    pub fn with_pager(pager: &str) -> Self {
        Pager {
            pager: OsString::from(pager).into(),
            env: None,
            on: true,
        }
    }

    /// Gives quick assessment of successful Pager setup
    pub fn is_on(&self) -> bool {
        self.on
    }

    /// Initiates Pager framework and sets up all the necessary environment for sending standard
    /// output to the activated pager.
    pub fn setup(&mut self) {
        if let Some(ref pager) = self.pager {
            let (pager_stdin, main_stdout) = utils::pipe();
            let pid = utils::fork();
            match pid {
                -1 => {
                    // Fork failed
                    utils::close(pager_stdin);
                    utils::close(main_stdout);
                    self.on = false
                }
                0 => {
                    // I am child
                    utils::dup2(main_stdout, libc::STDOUT_FILENO);
                    utils::close(pager_stdin);
                }
                _ => {
                    // I am parent
                    utils::dup2(pager_stdin, libc::STDIN_FILENO);
                    utils::close(main_stdout);
                    utils::execvp(pager);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

pub fn execute_steps(filename: &str) {
    println!("Reading file {:?}", filename);
}
<commit_msg>New function to parse toml file, unimplemented<commit_after>#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

#[derive(Debug)]
enum Steps {
    Echo,
    Run,
    Shell,
    SetEnv,
}

fn parse_toml(filename: &str) -> Vec<Steps> {

    println!("Reading toml file: {}", filename);

    unimplemented!();
}

pub fn execute_steps(filename: &str) {
    println!("Reading file {:?}", filename);

    let steps = parse_toml(filename);

    println!("Steps: {:?}", steps);
}
<|endoftext|>


<commit_before>//! Asynchnous HTTP/2 client and server implementation.
//!
//! Based on futures/tokio.

#[macro_use]
extern crate log;
extern crate log_ndc;

extern crate tls_api;
extern crate tls_api_stub;

extern crate bytes;
extern crate net2;
extern crate rand;
extern crate void;

mod solicit;

mod error;
mod result;

mod client;
mod codec;
mod server;
mod socket;
mod socket_tcp;

mod socket_unix;

mod ascii;

mod client_died_error_holder;
mod common;

mod data_or_headers;
mod data_or_headers_with_flag;
mod data_or_trailers;
mod message;

mod futures_misc;

mod headers_place;
mod req_resp;

mod assert_types;

mod hpack;
mod solicit_async;
mod solicit_misc;

mod display_comma_separated;
mod misc;

mod resp;

mod exec;

mod log_ndc_future;

pub use crate::socket::AnySocketAddr;

pub use crate::solicit::error_code::ErrorCode;
pub use crate::solicit::header::name::HeaderName;
pub use crate::solicit::header::name::PseudoHeaderName;
pub use crate::solicit::header::Header;
pub use crate::solicit::header::HeaderValue;
pub use crate::solicit::header::Headers;
pub use crate::solicit::stream_id::StreamId;
pub use crate::solicit::HttpScheme;

pub use crate::client::conf::ClientConf;
pub use crate::client::req::ClientRequest;
pub use crate::client::tls::ClientTlsOption;
pub use crate::client::Client;
pub use crate::client::ClientBuilder;
pub use crate::client::ClientInterface;
pub use crate::common::sender::SendError;
pub use crate::common::sender::SenderState;
pub use crate::common::window_size::StreamDead;

pub use crate::server::conf::ServerAlpn;
pub use crate::server::conf::ServerConf;
pub use crate::server::handler::ServerHandler;
pub use crate::server::handler::ServerHandlerContext;
pub use crate::server::handler_paths::ServerHandlerPaths;
pub use crate::server::increase_in_window::ServerIncreaseInWindow;
pub use crate::server::req::ServerRequest;
pub use crate::server::resp::ServerResponse;
pub use crate::server::stream_handler::ServerStreamHandler;
pub use crate::server::tls::ServerTlsOption;
pub use crate::server::Server;
pub use crate::server::ServerBuilder;

pub use crate::data_or_trailers::DataOrTrailers;
pub use crate::data_or_trailers::HttpStreamAfterHeaders;
pub use crate::resp::Response;

pub use crate::message::SimpleHttpMessage;

pub use crate::error::Error;
pub use crate::result::Result;

/// Functions used in tests
#[doc(hidden)]
pub mod for_test {
    pub use crate::common::conn::ConnStateSnapshot;
    pub use crate::common::stream::HttpStreamStateSnapshot;
    pub use crate::server::conn::ServerConn;
    pub use crate::solicit_async::recv_raw_frame_sync;

    pub use crate::solicit::frame::settings::HttpSettings;
    pub use crate::solicit::window_size::WindowSize;
    pub use crate::solicit::DEFAULT_SETTINGS;

    pub mod solicit {
        pub use crate::solicit::*;
    }
    pub mod hpack {
        pub use crate::hpack::*;
    }
}
<commit_msg>deny intra_doc_link_resolution_failure<commit_after>#![deny(intra_doc_link_resolution_failure)]

//! Asynchnous HTTP/2 client and server implementation.
//!
//! Based on futures/tokio.

#[macro_use]
extern crate log;
extern crate log_ndc;

extern crate tls_api;
extern crate tls_api_stub;

extern crate bytes;
extern crate net2;
extern crate rand;
extern crate void;

mod solicit;

mod error;
mod result;

mod client;
mod codec;
mod server;
mod socket;
mod socket_tcp;

mod socket_unix;

mod ascii;

mod client_died_error_holder;
mod common;

mod data_or_headers;
mod data_or_headers_with_flag;
mod data_or_trailers;
mod message;

mod futures_misc;

mod headers_place;
mod req_resp;

mod assert_types;

mod hpack;
mod solicit_async;
mod solicit_misc;

mod display_comma_separated;
mod misc;

mod resp;

mod exec;

mod log_ndc_future;

pub use crate::socket::AnySocketAddr;

pub use crate::solicit::error_code::ErrorCode;
pub use crate::solicit::header::name::HeaderName;
pub use crate::solicit::header::name::PseudoHeaderName;
pub use crate::solicit::header::Header;
pub use crate::solicit::header::HeaderValue;
pub use crate::solicit::header::Headers;
pub use crate::solicit::stream_id::StreamId;
pub use crate::solicit::HttpScheme;

pub use crate::client::conf::ClientConf;
pub use crate::client::req::ClientRequest;
pub use crate::client::tls::ClientTlsOption;
pub use crate::client::Client;
pub use crate::client::ClientBuilder;
pub use crate::client::ClientInterface;
pub use crate::common::sender::SendError;
pub use crate::common::sender::SenderState;
pub use crate::common::window_size::StreamDead;

pub use crate::server::conf::ServerAlpn;
pub use crate::server::conf::ServerConf;
pub use crate::server::handler::ServerHandler;
pub use crate::server::handler::ServerHandlerContext;
pub use crate::server::handler_paths::ServerHandlerPaths;
pub use crate::server::increase_in_window::ServerIncreaseInWindow;
pub use crate::server::req::ServerRequest;
pub use crate::server::resp::ServerResponse;
pub use crate::server::stream_handler::ServerStreamHandler;
pub use crate::server::tls::ServerTlsOption;
pub use crate::server::Server;
pub use crate::server::ServerBuilder;

pub use crate::data_or_trailers::DataOrTrailers;
pub use crate::data_or_trailers::HttpStreamAfterHeaders;
pub use crate::resp::Response;

pub use crate::message::SimpleHttpMessage;

pub use crate::error::Error;
pub use crate::result::Result;

/// Functions used in tests
#[doc(hidden)]
pub mod for_test {
    pub use crate::common::conn::ConnStateSnapshot;
    pub use crate::common::stream::HttpStreamStateSnapshot;
    pub use crate::server::conn::ServerConn;
    pub use crate::solicit_async::recv_raw_frame_sync;

    pub use crate::solicit::frame::settings::HttpSettings;
    pub use crate::solicit::window_size::WindowSize;
    pub use crate::solicit::DEFAULT_SETTINGS;

    pub mod solicit {
        pub use crate::solicit::*;
    }
    pub mod hpack {
        pub use crate::hpack::*;
    }
}
<|endoftext|>


<commit_before>#![crate_name = "shader_version"]
#![deny(missing_doc)]

//! Documentation goes here.

<commit_msg>Changed doc description<commit_after>#![crate_name = "shader_version"]
#![deny(missing_doc)]

//! A helper library for detecting and picking compatible shaders.

<|endoftext|>


<commit_before>/*!
Miscellaneous utilities grab-bag.

 */

#![crate_name="calx"]

#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate time;
extern crate rand;
extern crate num;
extern crate vec_map;
extern crate nalgebra;
extern crate image;
extern crate bincode;
extern crate calx_alg;

#[macro_use] extern crate glium;

use std::path::{Path, PathBuf};

pub use rgb::{Rgba, SRgba, color, scolor, NAMED_COLORS};
pub use geom::{V2, V3, Rect, RectIter, IterTiles};
pub use img::{color_key, ImageStore};
pub use atlas::{AtlasBuilder, Atlas, AtlasItem};
pub use hex::{HexGeom, Dir6, HexFov, Dir12};
pub use index_cache::{IndexCache, CacheKey};
pub use kernel::{Kernel, KernelTerrain};
pub use projection::{Projection};

mod atlas;
mod brush;
mod geom;
mod hex;
mod img;
mod index_cache;
mod kernel;
mod projection;
mod rgb;

pub mod backend;
pub mod debug;
pub mod timing;

/// Rectangle anchoring points.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Anchor {
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight,
    Top,
    Left,
    Right,
    Bottom,
    Center
}

/// Return the application data directory path for the current platform.
pub fn app_data_path(app_name: &str) -> PathBuf {
    use std::env;
    // On Windows, a portable application is just an .exe the user downloads
    // and drops somewhere. The convention here is for a portable application
    // to add its files to wherever its exe file is. An installed application
    // uses an actual installer program and deploys its files to user data
    // directories.
    let is_portable_application = true;

    // TODO: Handle not having the expected env variables.
    if cfg!(windows) {
        if is_portable_application {
            match env::current_exe() {
                Ok(mut p) => { p.pop(); p }
                // If couldn't get self exe path, just use the local relative path and
                // hope for the best.
                _ => Path::new(".").to_path_buf()
            }
        } else {
            Path::new(
                &format!("{}\\{}", env::var("APPDATA").unwrap(), app_name))
            .to_path_buf()
        }
    } else if cfg!(macos) {
        Path::new(
            &format!("{}/Library/Application Support/{}",
                    env::var("HOME").unwrap(), app_name))
        .to_path_buf()
    } else {
        Path::new(
            &format!("{}/.config/{}", env::var("HOME").unwrap(), app_name))
        .to_path_buf()
    }
}

/// Exponential moving average duration.
pub struct AverageDuration {
    weight: f64,
    last_time: f64,
    pub value: f64,
}

impl AverageDuration {
    /// Init is the initial value for the duration, somewhere in the scale you
    /// expect the actual values to be. Weight is between 0 and 1 and
    /// indicates how fast the older values should decay. Weight 1.0 causes
    /// old values to decay immediately.
    pub fn new(init: f64, weight: f64) -> AverageDuration {
        assert!(weight > 0.0 && weight <= 1.0);
        AverageDuration {
            weight: weight,
            last_time: time::precise_time_s(),
            value: init,
        }
    }

    pub fn tick(&mut self) {
        let t = time::precise_time_s();
        self.value = self.weight * (t - self.last_time) + (1.0 - self.weight) * self.value;
        self.last_time = t;
    }
}

#[macro_export]
macro_rules! count_exprs {
    () => { 0 };
    ($e:expr) => { 1 };
    ($e:expr, $($es:expr),+) => { 1 + count_exprs!($($es),*) };
}
<commit_msg>Deprecate geom and color still in main<commit_after>/*!
Miscellaneous utilities grab-bag.

 */

#![crate_name="calx"]

#![feature(deprecated)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate time;
extern crate rand;
extern crate num;
extern crate vec_map;
extern crate nalgebra;
extern crate image;
extern crate bincode;
extern crate calx_alg;

#[macro_use] extern crate glium;

use std::path::{Path, PathBuf};

pub use rgb::{Rgba, SRgba, color, scolor, NAMED_COLORS};
pub use geom::{V2, V3, Rect, RectIter, IterTiles};
pub use img::{color_key, ImageStore};
pub use atlas::{AtlasBuilder, Atlas, AtlasItem};
pub use hex::{HexGeom, Dir6, HexFov, Dir12};
pub use index_cache::{IndexCache, CacheKey};
pub use kernel::{Kernel, KernelTerrain};
pub use projection::{Projection};

mod atlas;
mod brush;
#[deprecated] mod geom;
mod hex;
mod img;
mod index_cache;
mod kernel;
mod projection;
#[deprecated] mod rgb;
pub mod backend;
pub mod debug;
pub mod timing;

/// Rectangle anchoring points.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Anchor {
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight,
    Top,
    Left,
    Right,
    Bottom,
    Center
}

/// Return the application data directory path for the current platform.
pub fn app_data_path(app_name: &str) -> PathBuf {
    use std::env;
    // On Windows, a portable application is just an .exe the user downloads
    // and drops somewhere. The convention here is for a portable application
    // to add its files to wherever its exe file is. An installed application
    // uses an actual installer program and deploys its files to user data
    // directories.
    let is_portable_application = true;

    // TODO: Handle not having the expected env variables.
    if cfg!(windows) {
        if is_portable_application {
            match env::current_exe() {
                Ok(mut p) => { p.pop(); p }
                // If couldn't get self exe path, just use the local relative path and
                // hope for the best.
                _ => Path::new(".").to_path_buf()
            }
        } else {
            Path::new(
                &format!("{}\\{}", env::var("APPDATA").unwrap(), app_name))
            .to_path_buf()
        }
    } else if cfg!(macos) {
        Path::new(
            &format!("{}/Library/Application Support/{}",
                    env::var("HOME").unwrap(), app_name))
        .to_path_buf()
    } else {
        Path::new(
            &format!("{}/.config/{}", env::var("HOME").unwrap(), app_name))
        .to_path_buf()
    }
}

/// Exponential moving average duration.
pub struct AverageDuration {
    weight: f64,
    last_time: f64,
    pub value: f64,
}

impl AverageDuration {
    /// Init is the initial value for the duration, somewhere in the scale you
    /// expect the actual values to be. Weight is between 0 and 1 and
    /// indicates how fast the older values should decay. Weight 1.0 causes
    /// old values to decay immediately.
    pub fn new(init: f64, weight: f64) -> AverageDuration {
        assert!(weight > 0.0 && weight <= 1.0);
        AverageDuration {
            weight: weight,
            last_time: time::precise_time_s(),
            value: init,
        }
    }

    pub fn tick(&mut self) {
        let t = time::precise_time_s();
        self.value = self.weight * (t - self.last_time) + (1.0 - self.weight) * self.value;
        self.last_time = t;
    }
}

#[macro_export]
macro_rules! count_exprs {
    () => { 0 };
    ($e:expr) => { 1 };
    ($e:expr, $($es:expr),+) => { 1 + count_exprs!($($es),*) };
}
<|endoftext|>


<commit_before>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;

pub type Idx = usize;

#[inline]
/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next(n_i: &[Idx], n_j: &[Idx], x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i[a] as usize, n_j[b] as usize);

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

#[inline]
/// Calculates x[k+1]
///
/// `node_color_scale((i,j))`: If two nodes `i` (of graph A) and `j` (of graph B)
/// are of different color, this can be set to return 0.0. Alternatively a
/// node-color distance (within 0...1) could be used to penalize.
fn next_x<F>(x: &DMat<f32>,
             new_x: &mut DMat<f32>,
             in_a: &[Vec<Idx>],
             in_b: &[Vec<Idx>],
             out_a: &[Vec<Idx>],
             out_b: &[Vec<Idx>],
             node_color_scale: F)
    where F: Fn((usize, usize)) -> f32
{
    let shape = x.shape();
    assert!(shape == new_x.shape());

    for i in 0..shape.0 {
        for j in 0..shape.1 {
            new_x[(i, j)] = node_color_scale((i, j)) *
                            (s_next(&in_a[i], &in_b[j], x) + s_next(&out_a[i], &out_b[j], x)) /
                            2.0;
        }
    }
}

#[inline]
/// Calculates the similarity matrix for two graphs A and B.
///
/// `in_a`:  Incoming edge list for each node of graph A
/// `in_b`:  Incoming edge list for each node of graph B
/// `out_a`: Outgoing edge list for each node of graph A
/// `out_b`: Outgoing edge list for each node of graph B
/// `eps`:   When to stop the iteration
/// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
///
/// Returns (number of iterations, similarity matrix `x`)
pub fn neighbor_matching_matrix<F>(in_a: &[Vec<Idx>],
                                   in_b: &[Vec<Idx>],
                                   out_a: &[Vec<Idx>],
                                   out_b: &[Vec<Idx>],
                                   eps: f32,
                                   stop_after_iter: usize,
                                   node_color_scale: &F)
                                   -> (usize, DMat<f32>)
    where F: Fn((usize, usize)) -> f32
{
    let (na, nb) = (in_a.len(), in_b.len());
    assert!((na, nb) == (out_a.len(), out_b.len()));

    // `x` is the node-similarity matrix.
    // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
    // B.edges().
    let mut x: DMat<f32> = DMat::from_fn(na, nb, |i, j| {
        node_color_scale((i, j)) *
        if in_a[i].len() + out_a[i].len() > 0 && in_b[j].len() + out_b[j].len() > 0 {
            1.0
        } else {
            0.0
        }
    });

    let mut iter = 0;
    let mut new_x: DMat<f32> = DMat::new_zeros(na, nb);

    loop {
        if x.approx_eq_eps(&new_x, &eps) || iter >= stop_after_iter {
            break;
        }

        next_x(&x,
               &mut new_x,
               in_a,
               in_b,
               out_a,
               out_b,
               node_color_scale);
        mem::swap(&mut new_x, &mut x);
        iter += 1;
    }

    (iter, x)
}

/// Different similarity measures can be constructed from the node similarity matrix.
pub enum ScoreMethod {
    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    SumNormMinDegree,

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    SumNormMaxDegree,

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    Average,
}

#[inline]
/// Calculates the similiarity of two graphs.
///
/// For parameters see `neighbor_matching_matrix`.
pub fn neighbor_matching_score<F>(in_a: &[Vec<Idx>],
                                  in_b: &[Vec<Idx>],
                                  out_a: &[Vec<Idx>],
                                  out_b: &[Vec<Idx>],
                                  eps: f32,
                                  stop_after_iter: usize,
                                  node_color_scale: &F,
                                  score_method: ScoreMethod)
                                  -> (usize, f32)
    where F: Fn((usize, usize)) -> f32
{
    let (iter, x) = neighbor_matching_matrix(in_a,
                                             in_b,
                                             out_a,
                                             out_b,
                                             eps,
                                             stop_after_iter,
                                             node_color_scale);
    let n = cmp::min(x.nrows(), x.ncols());
    let m = cmp::max(x.nrows(), x.ncols());
    if n == 0 {
        return (iter, 0.0);
    }

    match score_method {
        ScoreMethod::SumNormMinDegree | ScoreMethod::SumNormMaxDegree => {
            let norm = match score_method {
                ScoreMethod::SumNormMinDegree => n as f32,
                ScoreMethod::SumNormMaxDegree => m as f32,
                _ => unreachable!(),
            };

            let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
            let assignment = solve_assignment(&mut w);
            assert!(assignment.len() == n);
            let score: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[ab]);
            (iter, score / norm)
        }
        ScoreMethod::Average => {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            (iter, sum / len as f32)
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 100, &|_| 1.0);
    println!("{:?}", mat);
    assert_eq!(iter, 1);
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 1, &|_| 1.0);
    assert_eq!(iter, 1);
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMinDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMaxDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);
}
<commit_msg>Change Idx to u32<commit_after>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;

pub type Idx = u32;

#[inline]
/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next(n_i: &[Idx], n_j: &[Idx], x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i[a] as usize, n_j[b] as usize);

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

#[inline]
/// Calculates x[k+1]
///
/// `node_color_scale((i,j))`: If two nodes `i` (of graph A) and `j` (of graph B)
/// are of different color, this can be set to return 0.0. Alternatively a
/// node-color distance (within 0...1) could be used to penalize.
fn next_x<F>(x: &DMat<f32>,
             new_x: &mut DMat<f32>,
             in_a: &[Vec<Idx>],
             in_b: &[Vec<Idx>],
             out_a: &[Vec<Idx>],
             out_b: &[Vec<Idx>],
             node_color_scale: F)
    where F: Fn((usize, usize)) -> f32
{
    let shape = x.shape();
    assert!(shape == new_x.shape());

    for i in 0..shape.0 {
        for j in 0..shape.1 {
            new_x[(i, j)] = node_color_scale((i, j)) *
                            (s_next(&in_a[i], &in_b[j], x) + s_next(&out_a[i], &out_b[j], x)) /
                            2.0;
        }
    }
}

#[inline]
/// Calculates the similarity matrix for two graphs A and B.
///
/// `in_a`:  Incoming edge list for each node of graph A
/// `in_b`:  Incoming edge list for each node of graph B
/// `out_a`: Outgoing edge list for each node of graph A
/// `out_b`: Outgoing edge list for each node of graph B
/// `eps`:   When to stop the iteration
/// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
///
/// Returns (number of iterations, similarity matrix `x`)
pub fn neighbor_matching_matrix<F>(in_a: &[Vec<Idx>],
                                   in_b: &[Vec<Idx>],
                                   out_a: &[Vec<Idx>],
                                   out_b: &[Vec<Idx>],
                                   eps: f32,
                                   stop_after_iter: usize,
                                   node_color_scale: &F)
                                   -> (usize, DMat<f32>)
    where F: Fn((usize, usize)) -> f32
{
    let (na, nb) = (in_a.len(), in_b.len());
    assert!((na, nb) == (out_a.len(), out_b.len()));

    // `x` is the node-similarity matrix.
    // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
    // B.edges().
    let mut x: DMat<f32> = DMat::from_fn(na, nb, |i, j| {
        node_color_scale((i, j)) *
        if in_a[i].len() + out_a[i].len() > 0 && in_b[j].len() + out_b[j].len() > 0 {
            1.0
        } else {
            0.0
        }
    });

    let mut iter = 0;
    let mut new_x: DMat<f32> = DMat::new_zeros(na, nb);

    loop {
        if x.approx_eq_eps(&new_x, &eps) || iter >= stop_after_iter {
            break;
        }

        next_x(&x,
               &mut new_x,
               in_a,
               in_b,
               out_a,
               out_b,
               node_color_scale);
        mem::swap(&mut new_x, &mut x);
        iter += 1;
    }

    (iter, x)
}

/// Different similarity measures can be constructed from the node similarity matrix.
pub enum ScoreMethod {
    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    SumNormMinDegree,

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    SumNormMaxDegree,

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    Average,
}

#[inline]
/// Calculates the similiarity of two graphs.
///
/// For parameters see `neighbor_matching_matrix`.
pub fn neighbor_matching_score<F>(in_a: &[Vec<Idx>],
                                  in_b: &[Vec<Idx>],
                                  out_a: &[Vec<Idx>],
                                  out_b: &[Vec<Idx>],
                                  eps: f32,
                                  stop_after_iter: usize,
                                  node_color_scale: &F,
                                  score_method: ScoreMethod)
                                  -> (usize, f32)
    where F: Fn((usize, usize)) -> f32
{
    let (iter, x) = neighbor_matching_matrix(in_a,
                                             in_b,
                                             out_a,
                                             out_b,
                                             eps,
                                             stop_after_iter,
                                             node_color_scale);
    let n = cmp::min(x.nrows(), x.ncols());
    let m = cmp::max(x.nrows(), x.ncols());
    if n == 0 {
        return (iter, 0.0);
    }

    match score_method {
        ScoreMethod::SumNormMinDegree | ScoreMethod::SumNormMaxDegree => {
            let norm = match score_method {
                ScoreMethod::SumNormMinDegree => n as f32,
                ScoreMethod::SumNormMaxDegree => m as f32,
                _ => unreachable!(),
            };

            let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
            let assignment = solve_assignment(&mut w);
            assert!(assignment.len() == n);
            let score: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[ab]);
            (iter, score / norm)
        }
        ScoreMethod::Average => {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            (iter, sum / len as f32)
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 100, &|_| 1.0);
    println!("{:?}", mat);
    assert_eq!(iter, 1);
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 1, &|_| 1.0);
    assert_eq!(iter, 1);
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMinDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMaxDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);
}
<|endoftext|>


<commit_before>#![cfg(any(target_arch="x86", target_arch="x86_64"))]

#![feature(const_fn)]
#![feature(asm)]
#![no_std]
#![cfg_attr(test, allow(unused_features))]

#[macro_use]
extern crate bitflags;
extern crate raw_cpuid;
#[cfg(feature = "performance-counter")]
#[macro_use]
extern crate phf;

macro_rules! check_flag {
    ($doc:meta, $fun:ident, $flag:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            self.contains($flag)
        }
    )
}

macro_rules! bit {
    ( $x:expr ) => {
        1 << $x
    };
}

pub mod bits16;
pub mod bits32;
pub mod bits64;

pub mod controlregs;
pub mod dtables;
pub mod io;
pub mod irq;
pub mod msr;
pub mod segmentation;
pub mod task;
pub mod tlb;
pub mod time;

#[cfg(feature = "performance-counter")]
pub mod perfcnt;

pub mod current {
  #[cfg(target_arch="x86")]
  pub use bits32::*;
  #[cfg(target_arch="x86_64")]
  pub use bits64::*;
}

pub mod cpuid {
    pub use raw_cpuid::*;
}

mod std {
    pub use core::fmt;
    pub use core::ops;
    pub use core::option;
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
/// x86 Protection levels
/// Note: This should not contain values larger than 2 bits, otherwise
/// segment descriptor code needs to be adjusted accordingly.
pub enum Ring {
    Ring0 = 0b00,
    Ring1 = 0b01,
    Ring2 = 0b10,
    Ring3 = 0b11,
}

#[inline(always)]
pub unsafe fn halt() {
    asm!("hlt" :::: "volatile");
}<commit_msg>Deny warnings by default.<commit_after>#![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#![feature(const_fn)]
#![feature(asm)]
#![no_std]
#![cfg_attr(test, allow(unused_features))]
#![deny(warnings)]

#[macro_use]
extern crate bitflags;
extern crate raw_cpuid;
#[cfg(feature = "performance-counter")]
#[macro_use]
extern crate phf;

macro_rules! check_flag {
    ($doc:meta, $fun:ident, $flag:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            self.contains($flag)
        }
    )
}

macro_rules! bit {
    ($x:expr) => {
        1 << $x
    };
}

pub mod bits16;
pub mod bits32;
pub mod bits64;

pub mod controlregs;
pub mod dtables;
pub mod io;
pub mod irq;
pub mod msr;
pub mod segmentation;
pub mod task;
pub mod time;
pub mod tlb;

#[cfg(feature = "performance-counter")]
pub mod perfcnt;

pub mod current {
    #[cfg(target_arch = "x86")]
    pub use bits32::*;
    #[cfg(target_arch = "x86_64")]
    pub use bits64::*;
}

pub mod cpuid {
    pub use raw_cpuid::*;
}

mod std {
    pub use core::fmt;
    pub use core::ops;
    pub use core::option;
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
/// x86 Protection levels
/// Note: This should not contain values larger than 2 bits, otherwise
/// segment descriptor code needs to be adjusted accordingly.
pub enum Ring {
    Ring0 = 0b00,
    Ring1 = 0b01,
    Ring2 = 0b10,
    Ring3 = 0b11,
}

#[inline(always)]
pub unsafe fn halt() {
    asm!("hlt" :::: "volatile");
}
<|endoftext|>