<commit_before>//! # Rubrail
//!
//! Rubrail is a library for building persistent, always-available UIs for the
//! Mac Touch Bar.
//!
//! Rubrail uses **private** Apple APIs to add an expandable icon to the Touch
//! Bar's "Control Strip" region, the section that is, by default, always
//! displayed on the right side of the bar.  This lets you create a Touch Bar
//! menu that is always available, regardless of which app is currently in
//! focus.  It supports a variety of common UI elements, including recursive
//! "popbar" submenus, and uses callbacks to your own functions or closures to
//! inform your app of touch interactions.
//!
//! # Execution Environment
//!
//! Rubrail can only communicate with Apple's Touch Bar service when it is
//! executed from a Mac Application environment: a valid _.app_ bundle with an
//! _Info.plist_ and the correct directory structure.
//!
//! When run outside of an app bundle, like when running with `cargo run`,
//! Rubrail will work correctly behind the scenes, but your Touch Bar will not
//! be registered with the system and will not display on the Control Strip,
//! making it inaccessible to the user.
//!
//! The examples are bundled with a script to generate a minimal valid app
//! bundle, and a wrapper example to move the real example into a bundle and
//! execute it.  You can execute the examples correctly with this comand:
//!
//! `$ cargo test && cargo run --example example_launcher`
//!
//! # Memory Management
//!
//! Rubrail manually manages the lifecycle of allocated Foundation and Cocoa
//! elements (the Objective-C classes that provide the UI features).  Because of
//! this, it is possible to leak memory.  Care should be taken to use the API
//! as intended to avoid leaks.
//!
//! The internal memory allocation strategy is to freely allocate objects
//! whenever a _create*()_ function is called, to associate all allocated
//! objects with a bar, and to register that bar with the system.  If the bar
//! is replaced (by registering a new bar with the sytem), the replacement
//! logic is responsible for recursively deallocating all items associated with
//! the bar and its subbars, and then deallocating the bar itself.
//!
//! Any objects created with a _create*()_ function that are never added to a
//! bar that is set as the system bar will be leaked.
//!

#[allow(dead_code)]
#[allow(unused_variables)]
mod interface;
pub use interface::*;

#[cfg(target_os = "macos")]
#[cfg(feature = "private_api")]
#[macro_use]
mod wrapper;

#[allow(unused_imports)]
#[macro_use]
extern crate log;

#[cfg(target_os = "macos")]
#[cfg(feature = "private_api")]
#[macro_use]
extern crate objc;

#[cfg(target_os = "macos")]
#[cfg(feature = "private_api")]
#[macro_use]
mod touchbar;

/// Main controller for creating and using Touch Bar UIs
///
/// Blah
#[cfg(target_os = "macos")]
#[cfg(feature = "private_api")]
pub use touchbar::Touchbar as Touchbar;

#[cfg(not(feature = "private_api"))]
mod dummy;

/// Main controller for creating and using Touch Bar UIs
///
/// Blah
#[cfg(not(feature = "private_api"))]
pub use dummy::DummyTouchbar as Touchbar;

/// Module for creating and running a simple Mac application
///
/// The `app` module contains helper functions for creating and running a very
/// simple Mac application environment (NSApplication) with no window or dock
/// icon.  It is provided here for the Rubrail examples to use, and may be
/// useful for simple Touch Bar-only applications, but 'real' applications
/// should probably implement the application logic themselves.
pub mod app {
    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    extern crate objc;
    extern crate log4rs;
    use std::env;

    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    /// Initialize a Mac application environment (NSApplication)
    ///
    /// This is a debug/convenience function for creating a window-less Mac
    /// application.  It can be used in simple Touch Bar-only applications,
    /// and is used by the examples, but more complex applications will want
    /// to handle the application creation themselves.
    ///
    /// It initializes an NSApplication with the
    /// _NSApplicationActivationPolicyAccessory_ policy, which means it will
    /// have no window and no dock icon.
    pub fn init_app() {
        unsafe {
            let cls = objc::runtime::Class::get("NSApplication").unwrap();
            let app: *mut objc::runtime::Object = msg_send![cls, sharedApplication];
            let _ = msg_send![app, setActivationPolicy: 1]; // NSApplicationActivationPolicyAccessory
        }
    }
    #[cfg(not(feature = "private_api"))]
    pub fn init_app() {}

    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    /// Run the application's event loop forever.
    ///
    /// This is a debug/convenience function to run the Mac application's event loop
    /// forever, without returning.  It can be used with `init_app()` to run a
    /// simple application or example, but more complicated applications should
    /// implement the run loop themselves.
    pub fn run_forever() {
        unsafe {
            let cls = objc::runtime::Class::get("NSApplication").unwrap();
            let app: *mut objc::runtime::Object = msg_send![cls, sharedApplication];
            let _ = msg_send![app, run];
        }
    }
    #[cfg(not(feature = "private_api"))]
    pub fn run_forever() { loop {} }

    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    /// Terminate the application run loop and quit.
    ///
    /// This is a debug/convenience function to terminate the Mac application and
    /// end the process.  This can be used with `init_app()` and `run_forever()` for
    /// simple applications and examples, but more complex applications will want
    /// to implement custom handling for terminating.
    pub fn quit() {
        unsafe {
            let cls = objc::runtime::Class::get("NSApplication").unwrap();
            let app: *mut objc::runtime::Object = msg_send![cls, sharedApplication];
            let _ = msg_send![app, terminate: 0];
        }
    }
    #[cfg(not(feature = "private_api"))]
    pub fn quit() {
        std::process::exit(0);
    }

    /// Enable logging to a file in the user's home directory
    ///
    /// This is a debug function which redirects the log output of Rubrail and its
    /// examples to a text file of the given name in the user's home directory.
    ///
    /// # Arguments
    ///
    /// * `filename` - the filename **without** a path.  It is always saved in the
    /// home directory.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// extern crate rubrail;
    /// #[macro_use]
    /// extern crate log;
    /// fn main() {
    ///   rubrail::app::create_logger(".rubrail.log");
    ///   info!("This message is in ~/.rubrail.log");
    /// }
    /// ```
    pub fn create_logger(filename: &str) {
        use log::LogLevelFilter;
        use self::log4rs::append::console::ConsoleAppender;
        use self::log4rs::append::file::FileAppender;
        use self::log4rs::encode::pattern::PatternEncoder;
        use self::log4rs::config::{Appender, Config, Logger, Root};

        let log_path = format!("{}/{}", env::home_dir().unwrap().display(), filename);
        let stdout = ConsoleAppender::builder()
            .encoder(Box::new(PatternEncoder::new("{m}{n}")))
            .build();
        let requests = FileAppender::builder()
            .build(&log_path)
            .unwrap();

        let config = Config::builder()
            .appender(Appender::builder().build("stdout", Box::new(stdout)))
            .appender(Appender::builder().build("requests", Box::new(requests)))
            .logger(Logger::builder().build("app::backend::db", LogLevelFilter::Info))
            .logger(Logger::builder()
                    .appender("requests")
                    .additive(false)
                    .build("app::requests", LogLevelFilter::Info))
            .build(Root::builder().appender("stdout").appender("requests").build(LogLevelFilter::Info))
            .unwrap();
        let _ = log4rs::init_config(config).unwrap();
    }
}

#[cfg(test)]
mod tests {
    use Touchbar;
    use interface::TTouchbar;
    #[test]
    fn test_alloc() {
        let mut tb = Touchbar::alloc("test");
        let _ = tb.create_bar();
    }
}
<commit_msg>Add Github and Crates links to lib documentation<commit_after>//! # Rubrail
//!
//! Rubrail is a library for building persistent, always-available UIs for the
//! Mac Touch Bar.
//!
//! Rubrail uses **private** Apple APIs to add an expandable icon to the Touch
//! Bar's "Control Strip" region, the section that is, by default, always
//! displayed on the right side of the bar.  This lets you create a Touch Bar
//! menu that is always available, regardless of which app is currently in
//! focus.  It supports a variety of common UI elements, including recursive
//! "popbar" submenus, and uses callbacks to your own functions or closures to
//! inform your app of touch interactions.
//!
//! # Getting Rubrail
//!
//! [Cargo Crate](https://crates.io/crates/rubrail)
//!
//! [GitHub Source](https://github.com/mrmekon/rubrail-rs)
//!
//! # Execution Environment
//!
//! Rubrail can only communicate with Apple's Touch Bar service when it is
//! executed from a Mac Application environment: a valid _.app_ bundle with an
//! _Info.plist_ and the correct directory structure.
//!
//! When run outside of an app bundle, like when running with `cargo run`,
//! Rubrail will work correctly behind the scenes, but your Touch Bar will not
//! be registered with the system and will not display on the Control Strip,
//! making it inaccessible to the user.
//!
//! The examples are bundled with a script to generate a minimal valid app
//! bundle, and a wrapper example to move the real example into a bundle and
//! execute it.  You can execute the examples correctly with this comand:
//!
//! `$ cargo test && cargo run --example example_launcher`
//!
//! # Memory Management
//!
//! Rubrail manually manages the lifecycle of allocated Foundation and Cocoa
//! elements (the Objective-C classes that provide the UI features).  Because of
//! this, it is possible to leak memory.  Care should be taken to use the API
//! as intended to avoid leaks.
//!
//! The internal memory allocation strategy is to freely allocate objects
//! whenever a _create*()_ function is called, to associate all allocated
//! objects with a bar, and to register that bar with the system.  If the bar
//! is replaced (by registering a new bar with the sytem), the replacement
//! logic is responsible for recursively deallocating all items associated with
//! the bar and its subbars, and then deallocating the bar itself.
//!
//! Any objects created with a _create*()_ function that are never added to a
//! bar that is set as the system bar will be leaked.
//!

#[allow(dead_code)]
#[allow(unused_variables)]
mod interface;
pub use interface::*;

#[cfg(target_os = "macos")]
#[cfg(feature = "private_api")]
#[macro_use]
mod wrapper;

#[allow(unused_imports)]
#[macro_use]
extern crate log;

#[cfg(target_os = "macos")]
#[cfg(feature = "private_api")]
#[macro_use]
extern crate objc;

#[cfg(target_os = "macos")]
#[cfg(feature = "private_api")]
#[macro_use]
mod touchbar;

/// Main controller for creating and using Touch Bar UIs
///
/// Blah
#[cfg(target_os = "macos")]
#[cfg(feature = "private_api")]
pub use touchbar::Touchbar as Touchbar;

#[cfg(not(feature = "private_api"))]
mod dummy;

/// Main controller for creating and using Touch Bar UIs
///
/// Blah
#[cfg(not(feature = "private_api"))]
pub use dummy::DummyTouchbar as Touchbar;

/// Module for creating and running a simple Mac application
///
/// The `app` module contains helper functions for creating and running a very
/// simple Mac application environment (NSApplication) with no window or dock
/// icon.  It is provided here for the Rubrail examples to use, and may be
/// useful for simple Touch Bar-only applications, but 'real' applications
/// should probably implement the application logic themselves.
pub mod app {
    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    extern crate objc;
    extern crate log4rs;
    use std::env;

    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    /// Initialize a Mac application environment (NSApplication)
    ///
    /// This is a debug/convenience function for creating a window-less Mac
    /// application.  It can be used in simple Touch Bar-only applications,
    /// and is used by the examples, but more complex applications will want
    /// to handle the application creation themselves.
    ///
    /// It initializes an NSApplication with the
    /// _NSApplicationActivationPolicyAccessory_ policy, which means it will
    /// have no window and no dock icon.
    pub fn init_app() {
        unsafe {
            let cls = objc::runtime::Class::get("NSApplication").unwrap();
            let app: *mut objc::runtime::Object = msg_send![cls, sharedApplication];
            let _ = msg_send![app, setActivationPolicy: 1]; // NSApplicationActivationPolicyAccessory
        }
    }
    #[cfg(not(feature = "private_api"))]
    pub fn init_app() {}

    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    /// Run the application's event loop forever.
    ///
    /// This is a debug/convenience function to run the Mac application's event loop
    /// forever, without returning.  It can be used with `init_app()` to run a
    /// simple application or example, but more complicated applications should
    /// implement the run loop themselves.
    pub fn run_forever() {
        unsafe {
            let cls = objc::runtime::Class::get("NSApplication").unwrap();
            let app: *mut objc::runtime::Object = msg_send![cls, sharedApplication];
            let _ = msg_send![app, run];
        }
    }
    #[cfg(not(feature = "private_api"))]
    pub fn run_forever() { loop {} }

    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    /// Terminate the application run loop and quit.
    ///
    /// This is a debug/convenience function to terminate the Mac application and
    /// end the process.  This can be used with `init_app()` and `run_forever()` for
    /// simple applications and examples, but more complex applications will want
    /// to implement custom handling for terminating.
    pub fn quit() {
        unsafe {
            let cls = objc::runtime::Class::get("NSApplication").unwrap();
            let app: *mut objc::runtime::Object = msg_send![cls, sharedApplication];
            let _ = msg_send![app, terminate: 0];
        }
    }
    #[cfg(not(feature = "private_api"))]
    pub fn quit() {
        std::process::exit(0);
    }

    /// Enable logging to a file in the user's home directory
    ///
    /// This is a debug function which redirects the log output of Rubrail and its
    /// examples to a text file of the given name in the user's home directory.
    ///
    /// # Arguments
    ///
    /// * `filename` - the filename **without** a path.  It is always saved in the
    /// home directory.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// extern crate rubrail;
    /// #[macro_use]
    /// extern crate log;
    /// fn main() {
    ///   rubrail::app::create_logger(".rubrail.log");
    ///   info!("This message is in ~/.rubrail.log");
    /// }
    /// ```
    pub fn create_logger(filename: &str) {
        use log::LogLevelFilter;
        use self::log4rs::append::console::ConsoleAppender;
        use self::log4rs::append::file::FileAppender;
        use self::log4rs::encode::pattern::PatternEncoder;
        use self::log4rs::config::{Appender, Config, Logger, Root};

        let log_path = format!("{}/{}", env::home_dir().unwrap().display(), filename);
        let stdout = ConsoleAppender::builder()
            .encoder(Box::new(PatternEncoder::new("{m}{n}")))
            .build();
        let requests = FileAppender::builder()
            .build(&log_path)
            .unwrap();

        let config = Config::builder()
            .appender(Appender::builder().build("stdout", Box::new(stdout)))
            .appender(Appender::builder().build("requests", Box::new(requests)))
            .logger(Logger::builder().build("app::backend::db", LogLevelFilter::Info))
            .logger(Logger::builder()
                    .appender("requests")
                    .additive(false)
                    .build("app::requests", LogLevelFilter::Info))
            .build(Root::builder().appender("stdout").appender("requests").build(LogLevelFilter::Info))
            .unwrap();
        let _ = log4rs::init_config(config).unwrap();
    }
}

#[cfg(test)]
mod tests {
    use Touchbar;
    use interface::TTouchbar;
    #[test]
    fn test_alloc() {
        let mut tb = Touchbar::alloc("test");
        let _ = tb.create_bar();
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
#![cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(write_literal))]

#[macro_use]
extern crate bitflags;
extern crate git2;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate regex;
extern crate stripper_lib;
extern crate toml;
extern crate xml;

/// Log warning only if type in generated library
macro_rules! warn_main {
    ($tid: expr, $target:expr, $($arg:tt)*) => (
        if $tid.ns_id == ::library::MAIN_NAMESPACE {
            warn!($target, $($arg)*);
        }
    );
}

//generated by build.rs
mod gir_version;

mod analysis;
mod case;
mod chunk;
mod codegen;
mod config;
mod consts;
mod custom_type_glib_priority;
mod env;
mod file_saver;
mod git;
mod library;
mod library_postprocessing;
mod library_preprocessing;
mod nameutil;
mod parser;
mod traits;
pub mod update_version;
mod version;
mod visitors;
mod writer;
mod xmlparser;

pub use analysis::class_hierarchy::run as class_hierarchy_run;
pub use analysis::namespaces::run as namespaces_run;
pub use analysis::run as analysis_run;
pub use analysis::symbols::run as symbols_run;
pub use codegen::generate as codegen_generate;
pub use config::{Config, WorkMode};
pub use env::Env;
pub use library::Library;
<commit_msg>Add pub for modules to use them from the gir library<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
#![cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(write_literal))]

#[macro_use]
extern crate bitflags;
extern crate git2;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate regex;
extern crate stripper_lib;
extern crate toml;
extern crate xml;

/// Log warning only if type in generated library
macro_rules! warn_main {
    ($tid: expr, $target:expr, $($arg:tt)*) => (
        if $tid.ns_id == ::library::MAIN_NAMESPACE {
            warn!($target, $($arg)*);
        }
    );
}

//generated by build.rs
mod gir_version;

pub mod analysis;
mod case;
mod chunk;
mod codegen;
mod config;
mod consts;
mod custom_type_glib_priority;
mod env;
mod file_saver;
mod git;
pub mod library;
mod library_postprocessing;
mod library_preprocessing;
mod nameutil;
mod parser;
mod traits;
pub mod update_version;
mod version;
mod visitors;
mod writer;
mod xmlparser;

pub use analysis::class_hierarchy::run as class_hierarchy_run;
pub use analysis::namespaces::run as namespaces_run;
pub use analysis::run as analysis_run;
pub use analysis::symbols::run as symbols_run;
pub use codegen::generate as codegen_generate;
pub use config::{Config, WorkMode};
pub use env::Env;
pub use library::Library;
<|endoftext|>


<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright 2014 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License, version 3,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Claxon, a FLAC decoding library.
//!
//! TODO: Add some examples here.

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.2
#![feature(iter_arith, zero_one)]

use std::io;
use error::fmt_err;
use frame::FrameReader;
use input::ReadExt;
use metadata::{MetadataBlock, MetadataBlockReader, StreamInfo};

mod crc;
mod input;
mod error;
pub mod frame;
pub mod sample;
pub mod subframe;
pub mod metadata;

pub use error::{Error, Result};

/// A FLAC decoder that can decode the stream from the underlying reader.
///
/// TODO: Is stream a good name? Should it be called reader/decoder?
/// TODO: Add an example.
pub struct FlacReader<R: io::Read> {
    streaminfo: StreamInfo,
    metadata_blocks: Vec<MetadataBlock>,
    input: R
}

fn read_stream_header<R: io::Read>(input: &mut R) -> Result<()> {
    // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
    const HEADER: u32 = 0x66_4c_61_43;
    let header = try!(input.read_be_u32());
    if header != HEADER {
        fmt_err("invalid stream header")
    } else {
        Ok(())
    }
}

impl<R: io::Read> FlacReader<R> {
    /// Constructs a flac stream from the given input.
    ///
    /// This will read all metadata and stop at the first audio frame.
    pub fn new(mut input: R) -> Result<FlacReader<R>> {
        // A flac stream first of all starts with a stream header.
        try!(read_stream_header(&mut input));

        // Start a new scope, because the input reader must be available again
        // for the frame reader next.
        let (streaminfo, metadata_blocks) = {
            // Next are one or more metadata blocks. The flac specification
            // dictates that the streaminfo block is the first block. The metadata
            // block reader will yield at least one element, so the unwrap is safe.
            let mut metadata_iter = MetadataBlockReader::new(&mut input);
            let streaminfo_block = try!(metadata_iter.next().unwrap());
            let streaminfo = match streaminfo_block {
                MetadataBlock::StreamInfo(info) => info,
                _ => return fmt_err("streaminfo block missing")
            };

            // There might be more metadata blocks, read and store them.
            let mut metadata_blocks = Vec::new();
            for block_result in metadata_iter {
                match block_result {
                    Err(error) => return Err(error),
                    Ok(block) => metadata_blocks.push(block)
                }
            }

            (streaminfo, metadata_blocks)
        };

        // The flac reader will contain the reader that will read frames.
        let reader = FlacReader {
            streaminfo: streaminfo,
            metadata_blocks: metadata_blocks,
            input: input
        };

        Ok(reader)
    }

    /// Returns the streaminfo metadata.
    pub fn streaminfo(&self) -> &StreamInfo {
        &self.streaminfo
    }

    /// Returns an iterator that decodes a single frame on every iteration.
    pub fn blocks<'r, S: sample::Sample>(&'r mut self) -> FrameReader<&'r mut R, S> {
        FrameReader::new(&mut self.input)
    }
}
<commit_msg>return StreamInfo by value, not by reference<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright 2014 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License, version 3,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Claxon, a FLAC decoding library.
//!
//! TODO: Add some examples here.

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.2
#![feature(iter_arith, zero_one)]

use std::io;
use error::fmt_err;
use frame::FrameReader;
use input::ReadExt;
use metadata::{MetadataBlock, MetadataBlockReader, StreamInfo};

mod crc;
mod input;
mod error;
pub mod frame;
pub mod sample;
pub mod subframe;
pub mod metadata;

pub use error::{Error, Result};

/// A FLAC decoder that can decode the stream from the underlying reader.
///
/// TODO: Is stream a good name? Should it be called reader/decoder?
/// TODO: Add an example.
pub struct FlacReader<R: io::Read> {
    streaminfo: StreamInfo,
    metadata_blocks: Vec<MetadataBlock>,
    input: R
}

fn read_stream_header<R: io::Read>(input: &mut R) -> Result<()> {
    // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
    const HEADER: u32 = 0x66_4c_61_43;
    let header = try!(input.read_be_u32());
    if header != HEADER {
        fmt_err("invalid stream header")
    } else {
        Ok(())
    }
}

impl<R: io::Read> FlacReader<R> {
    /// Constructs a flac stream from the given input.
    ///
    /// This will read all metadata and stop at the first audio frame.
    pub fn new(mut input: R) -> Result<FlacReader<R>> {
        // A flac stream first of all starts with a stream header.
        try!(read_stream_header(&mut input));

        // Start a new scope, because the input reader must be available again
        // for the frame reader next.
        let (streaminfo, metadata_blocks) = {
            // Next are one or more metadata blocks. The flac specification
            // dictates that the streaminfo block is the first block. The metadata
            // block reader will yield at least one element, so the unwrap is safe.
            let mut metadata_iter = MetadataBlockReader::new(&mut input);
            let streaminfo_block = try!(metadata_iter.next().unwrap());
            let streaminfo = match streaminfo_block {
                MetadataBlock::StreamInfo(info) => info,
                _ => return fmt_err("streaminfo block missing")
            };

            // There might be more metadata blocks, read and store them.
            let mut metadata_blocks = Vec::new();
            for block_result in metadata_iter {
                match block_result {
                    Err(error) => return Err(error),
                    Ok(block) => metadata_blocks.push(block)
                }
            }

            (streaminfo, metadata_blocks)
        };

        // The flac reader will contain the reader that will read frames.
        let reader = FlacReader {
            streaminfo: streaminfo,
            metadata_blocks: metadata_blocks,
            input: input
        };

        Ok(reader)
    }

    /// Returns the streaminfo metadata.
    pub fn streaminfo(&self) -> StreamInfo {
        self.streaminfo
    }

    /// Returns an iterator that decodes a single frame on every iteration.
    pub fn blocks<'r, S: sample::Sample>(&'r mut self) -> FrameReader<&'r mut R, S> {
        FrameReader::new(&mut self.input)
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Victor Brekenfeld
//
// 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.

//!
//! `simplelog` provides a series of logging facilities, that can be easily combined.
//!
//! - `SimpleLogger` (very basic logger that logs to stdout)
//! - `TermLogger` (advanced terminal logger, that splits to stdout/err and has color support) (can be excluded on unsupported platforms)
//! - `WriteLogger` (logs to a given struct implementing `Write`, e.g. a file)
//! - `CombinedLogger` (can be used to form combinations of the above loggers)
//! - `TestLogger` (specialized logger for tests. Uses print!() / println!() for tests to be able to capture the output)
//!
//! Only one Logger should be initialized of the start of your program
//! through the `Logger::init(...)` method. For the actual calling syntax
//! take a look at the documentation of the specific implementation(s) you wanna use.
//!

#![deny(missing_docs, rust_2018_idioms)]

mod config;
mod loggers;

pub use self::config::{Config, ConfigBuilder, LevelPadding, ThreadLogMode, ThreadPadding};
#[cfg(feature = "test")]
pub use self::loggers::TestLogger;
pub use self::loggers::{CombinedLogger, SimpleLogger, WriteLogger};
#[cfg(feature = "termcolor")]
pub use self::loggers::{TermLogger, TerminalMode};
#[cfg(feature = "termcolor")]
pub use termcolor::{Color, ColorChoice};

pub use log::{Level, LevelFilter};

use log::Log;
#[cfg(test)]
use log::*;

#[cfg(feature = "paris")]
mod paris_macros;
#[cfg(feature = "paris")]
pub extern crate paris;

/// Trait to have a common interface to obtain the Level of Loggers
///
/// Necessary for CombinedLogger to calculate
/// the lowest used Level.
///
pub trait SharedLogger: Log {
    /// Returns the set Level for this Logger
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let logger = SimpleLogger::new(LevelFilter::Info, Config::default());
    /// println!("{}", logger.level());
    /// # }
    /// ```
    fn level(&self) -> LevelFilter;

    /// Inspect the config of a running Logger
    ///
    /// An Option is returned, because some Logger may not contain a Config
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let logger = SimpleLogger::new(LevelFilter::Info, Config::default());
    /// println!("{:?}", logger.config());
    /// # }
    /// ```
    fn config(&self) -> Option<&Config>;

    /// Returns the logger as a Log trait object
    fn as_log(self: Box<Self>) -> Box<dyn Log>;
}

#[cfg(test)]
mod tests {
    use std::fs::File;
    use std::io::Read;

    use super::*;

    #[test]
    fn test() {
        let mut i = 0;

        CombinedLogger::init({
            let mut vec = Vec::new();
            let mut conf_builder = ConfigBuilder::new();

            let conf_thread_name = ConfigBuilder::new()
                .set_time_level(LevelFilter::Off)
                .set_thread_level(LevelFilter::Error)
                .set_thread_mode(ThreadLogMode::Names)
                .build();

            vec.push(WriteLogger::new(
                LevelFilter::Error,
                conf_thread_name,
                File::create("thread_naming.log").unwrap(),
            ) as Box<dyn SharedLogger>);

            for elem in vec![
                LevelFilter::Off,
                LevelFilter::Trace,
                LevelFilter::Debug,
                LevelFilter::Info,
                LevelFilter::Warn,
                LevelFilter::Error,
            ] {
                let conf = conf_builder
                    .set_location_level(elem)
                    .set_target_level(elem)
                    .set_max_level(elem)
                    .set_time_level(elem)
                    .build();
                i += 1;

                //error
                vec.push(
                    SimpleLogger::new(LevelFilter::Error, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Error,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Error,
                    conf.clone(),
                    File::create(&format!("error_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Error, conf.clone()));

                //warn
                vec.push(
                    SimpleLogger::new(LevelFilter::Warn, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Warn,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Warn,
                    conf.clone(),
                    File::create(&format!("warn_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Warn, conf.clone()));

                //info
                vec.push(
                    SimpleLogger::new(LevelFilter::Info, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Info,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Info,
                    conf.clone(),
                    File::create(&format!("info_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Info, conf.clone()));

                //debug
                vec.push(
                    SimpleLogger::new(LevelFilter::Debug, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Debug,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Debug,
                    conf.clone(),
                    File::create(&format!("debug_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Debug, conf.clone()));

                //trace
                vec.push(
                    SimpleLogger::new(LevelFilter::Trace, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Trace,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Trace,
                    conf.clone(),
                    File::create(&format!("trace_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Trace, conf.clone()));
            }

            vec
        })
        .unwrap();

        error!("Test Error");
        warn!("Test Warning");
        info!("Test Information");
        debug!("Test Debug");
        trace!("Test Trace");

        let mut thread_naming = String::new();
        File::open("thread_naming.log")
            .unwrap()
            .read_to_string(&mut thread_naming)
            .unwrap();

        if let Some(name) = std::thread::current().name() {
            assert!(thread_naming.contains(&format!("({})", name)));
        }

        for j in 1..i {
            let mut error = String::new();
            File::open(&format!("error_{}.log", j))
                .unwrap()
                .read_to_string(&mut error)
                .unwrap();
            let mut warn = String::new();
            File::open(&format!("warn_{}.log", j))
                .unwrap()
                .read_to_string(&mut warn)
                .unwrap();
            let mut info = String::new();
            File::open(&format!("info_{}.log", j))
                .unwrap()
                .read_to_string(&mut info)
                .unwrap();
            let mut debug = String::new();
            File::open(&format!("debug_{}.log", j))
                .unwrap()
                .read_to_string(&mut debug)
                .unwrap();
            let mut trace = String::new();
            File::open(&format!("trace_{}.log", j))
                .unwrap()
                .read_to_string(&mut trace)
                .unwrap();

            assert!(error.contains("Test Error"));
            assert!(!error.contains("Test Warning"));
            assert!(!error.contains("Test Information"));
            assert!(!error.contains("Test Debug"));
            assert!(!error.contains("Test Trace"));

            assert!(warn.contains("Test Error"));
            assert!(warn.contains("Test Warning"));
            assert!(!warn.contains("Test Information"));
            assert!(!warn.contains("Test Debug"));
            assert!(!warn.contains("Test Trace"));

            assert!(info.contains("Test Error"));
            assert!(info.contains("Test Warning"));
            assert!(info.contains("Test Information"));
            assert!(!info.contains("Test Debug"));
            assert!(!info.contains("Test Trace"));

            assert!(debug.contains("Test Error"));
            assert!(debug.contains("Test Warning"));
            assert!(debug.contains("Test Information"));
            assert!(debug.contains("Test Debug"));
            assert!(!debug.contains("Test Trace"));

            assert!(trace.contains("Test Error"));
            assert!(trace.contains("Test Warning"));
            assert!(trace.contains("Test Information"));
            assert!(trace.contains("Test Debug"));
            assert!(trace.contains("Test Trace"));
        }
    }
}
<commit_msg>paris: make the paris_macros module public<commit_after>// Copyright 2016 Victor Brekenfeld
//
// 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.

//!
//! `simplelog` provides a series of logging facilities, that can be easily combined.
//!
//! - `SimpleLogger` (very basic logger that logs to stdout)
//! - `TermLogger` (advanced terminal logger, that splits to stdout/err and has color support) (can be excluded on unsupported platforms)
//! - `WriteLogger` (logs to a given struct implementing `Write`, e.g. a file)
//! - `CombinedLogger` (can be used to form combinations of the above loggers)
//! - `TestLogger` (specialized logger for tests. Uses print!() / println!() for tests to be able to capture the output)
//!
//! Only one Logger should be initialized of the start of your program
//! through the `Logger::init(...)` method. For the actual calling syntax
//! take a look at the documentation of the specific implementation(s) you wanna use.
//!

#![deny(missing_docs, rust_2018_idioms)]

mod config;
mod loggers;

pub use self::config::{Config, ConfigBuilder, LevelPadding, ThreadLogMode, ThreadPadding};
#[cfg(feature = "test")]
pub use self::loggers::TestLogger;
pub use self::loggers::{CombinedLogger, SimpleLogger, WriteLogger};
#[cfg(feature = "termcolor")]
pub use self::loggers::{TermLogger, TerminalMode};
#[cfg(feature = "termcolor")]
pub use termcolor::{Color, ColorChoice};

pub use log::{Level, LevelFilter};

use log::Log;
#[cfg(test)]
use log::*;

#[cfg(feature = "paris")]
pub(crate) mod paris_macros;
#[cfg(feature = "paris")]
pub extern crate paris;

/// Trait to have a common interface to obtain the Level of Loggers
///
/// Necessary for CombinedLogger to calculate
/// the lowest used Level.
///
pub trait SharedLogger: Log {
    /// Returns the set Level for this Logger
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let logger = SimpleLogger::new(LevelFilter::Info, Config::default());
    /// println!("{}", logger.level());
    /// # }
    /// ```
    fn level(&self) -> LevelFilter;

    /// Inspect the config of a running Logger
    ///
    /// An Option is returned, because some Logger may not contain a Config
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let logger = SimpleLogger::new(LevelFilter::Info, Config::default());
    /// println!("{:?}", logger.config());
    /// # }
    /// ```
    fn config(&self) -> Option<&Config>;

    /// Returns the logger as a Log trait object
    fn as_log(self: Box<Self>) -> Box<dyn Log>;
}

#[cfg(test)]
mod tests {
    use std::fs::File;
    use std::io::Read;

    use super::*;

    #[test]
    fn test() {
        let mut i = 0;

        CombinedLogger::init({
            let mut vec = Vec::new();
            let mut conf_builder = ConfigBuilder::new();

            let conf_thread_name = ConfigBuilder::new()
                .set_time_level(LevelFilter::Off)
                .set_thread_level(LevelFilter::Error)
                .set_thread_mode(ThreadLogMode::Names)
                .build();

            vec.push(WriteLogger::new(
                LevelFilter::Error,
                conf_thread_name,
                File::create("thread_naming.log").unwrap(),
            ) as Box<dyn SharedLogger>);

            for elem in vec![
                LevelFilter::Off,
                LevelFilter::Trace,
                LevelFilter::Debug,
                LevelFilter::Info,
                LevelFilter::Warn,
                LevelFilter::Error,
            ] {
                let conf = conf_builder
                    .set_location_level(elem)
                    .set_target_level(elem)
                    .set_max_level(elem)
                    .set_time_level(elem)
                    .build();
                i += 1;

                //error
                vec.push(
                    SimpleLogger::new(LevelFilter::Error, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Error,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Error,
                    conf.clone(),
                    File::create(&format!("error_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Error, conf.clone()));

                //warn
                vec.push(
                    SimpleLogger::new(LevelFilter::Warn, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Warn,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Warn,
                    conf.clone(),
                    File::create(&format!("warn_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Warn, conf.clone()));

                //info
                vec.push(
                    SimpleLogger::new(LevelFilter::Info, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Info,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Info,
                    conf.clone(),
                    File::create(&format!("info_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Info, conf.clone()));

                //debug
                vec.push(
                    SimpleLogger::new(LevelFilter::Debug, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Debug,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Debug,
                    conf.clone(),
                    File::create(&format!("debug_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Debug, conf.clone()));

                //trace
                vec.push(
                    SimpleLogger::new(LevelFilter::Trace, conf.clone()) as Box<dyn SharedLogger>
                );
                #[cfg(feature = "termcolor")]
                vec.push(TermLogger::new(
                    LevelFilter::Trace,
                    conf.clone(),
                    TerminalMode::Mixed,
                    ColorChoice::Auto,
                ) as Box<dyn SharedLogger>);
                vec.push(WriteLogger::new(
                    LevelFilter::Trace,
                    conf.clone(),
                    File::create(&format!("trace_{}.log", i)).unwrap(),
                ) as Box<dyn SharedLogger>);
                #[cfg(feature = "test")]
                vec.push(TestLogger::new(LevelFilter::Trace, conf.clone()));
            }

            vec
        })
        .unwrap();

        error!("Test Error");
        warn!("Test Warning");
        info!("Test Information");
        debug!("Test Debug");
        trace!("Test Trace");

        let mut thread_naming = String::new();
        File::open("thread_naming.log")
            .unwrap()
            .read_to_string(&mut thread_naming)
            .unwrap();

        if let Some(name) = std::thread::current().name() {
            assert!(thread_naming.contains(&format!("({})", name)));
        }

        for j in 1..i {
            let mut error = String::new();
            File::open(&format!("error_{}.log", j))
                .unwrap()
                .read_to_string(&mut error)
                .unwrap();
            let mut warn = String::new();
            File::open(&format!("warn_{}.log", j))
                .unwrap()
                .read_to_string(&mut warn)
                .unwrap();
            let mut info = String::new();
            File::open(&format!("info_{}.log", j))
                .unwrap()
                .read_to_string(&mut info)
                .unwrap();
            let mut debug = String::new();
            File::open(&format!("debug_{}.log", j))
                .unwrap()
                .read_to_string(&mut debug)
                .unwrap();
            let mut trace = String::new();
            File::open(&format!("trace_{}.log", j))
                .unwrap()
                .read_to_string(&mut trace)
                .unwrap();

            assert!(error.contains("Test Error"));
            assert!(!error.contains("Test Warning"));
            assert!(!error.contains("Test Information"));
            assert!(!error.contains("Test Debug"));
            assert!(!error.contains("Test Trace"));

            assert!(warn.contains("Test Error"));
            assert!(warn.contains("Test Warning"));
            assert!(!warn.contains("Test Information"));
            assert!(!warn.contains("Test Debug"));
            assert!(!warn.contains("Test Trace"));

            assert!(info.contains("Test Error"));
            assert!(info.contains("Test Warning"));
            assert!(info.contains("Test Information"));
            assert!(!info.contains("Test Debug"));
            assert!(!info.contains("Test Trace"));

            assert!(debug.contains("Test Error"));
            assert!(debug.contains("Test Warning"));
            assert!(debug.contains("Test Information"));
            assert!(debug.contains("Test Debug"));
            assert!(!debug.contains("Test Trace"));

            assert!(trace.contains("Test Error"));
            assert!(trace.contains("Test Warning"));
            assert!(trace.contains("Test Information"));
            assert!(trace.contains("Test Debug"));
            assert!(trace.contains("Test Trace"));
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate rayon;
extern crate time;

use std::cmp;
use rand::Rng;
use selection::tournament_selection_fast;
use mo::MultiObjective;
pub use self::domination::{Domination, Dominate, DominationHelper};
use domination::fast_non_dominated_sort;
use rayon::par_iter::*;
use std::convert::{AsRef, From};
use std::iter::FromIterator;
use crowding_distance::{crowding_distance_assignment, SolutionRankDist};

pub mod selection;
pub mod mo;
pub mod domination;
mod crowding_distance;

/// Select `n` out of the `solutions`, assigning rank and distance using the first `num_objectives`
/// objectives.
fn select_solutions<T, D>(solutions: &[T],
                          n: usize,
                          num_objectives: usize,
                          domination: &mut D)
                          -> Vec<SolutionRankDist>
    where T: MultiObjective,
          D: Domination<T>
{
    let mut selection = Vec::with_capacity(cmp::min(solutions.len(), n));

    let pareto_fronts = fast_non_dominated_sort(solutions, n, domination);

    for (rank, front) in pareto_fronts.iter().enumerate() {
        if selection.len() >= n {
            break;
        }
        let missing: usize = n - selection.len();

        let mut solution_rank_dist = crowding_distance_assignment(solutions,
                                                                  rank as u32,
                                                                  &front,
                                                                  num_objectives);
        if solution_rank_dist.len() <= missing {
            // whole front fits into result.
            // XXX: should we sort?
            selection.extend(solution_rank_dist);
            assert!(selection.len() <= n);
        } else {
            // choose only best from this front, according to the crowding distance.
            solution_rank_dist.sort_by(|a, b| {
                debug_assert!(a.rank == b.rank);
                a.partial_cmp(b).unwrap()
            });
            selection.extend(solution_rank_dist.into_iter().take(missing));
            assert!(selection.len() == n);
            break;
        }
    }

    return selection;
}

/// An unrated Population of individuals.
pub struct UnratedPopulation<I>
    where I: Clone
{
    individuals: Vec<I>,
}

/// A rated Population of individuals, i.e.
/// each individual has a fitness assigned.
pub struct RatedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
}

/// A selected (ranked) Population.
pub struct SelectedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
    rank_dist: Vec<SolutionRankDist>,
}

impl<I> From<Vec<I>> for UnratedPopulation<I> where I: Clone
{
    fn from(v: Vec<I>) -> UnratedPopulation<I> {
        UnratedPopulation { individuals: v }
    }
}

impl<I> FromIterator<I> for UnratedPopulation<I> where I: Clone
{
    fn from_iter<T>(iterator: T) -> UnratedPopulation<I>
        where T: IntoIterator<Item = I>
    {
        UnratedPopulation { individuals: iterator.into_iter().collect() }
    }
}

impl<I> AsRef<[I]> for UnratedPopulation<I> where I: Clone
{
    fn as_ref(&self) -> &[I] {
        &self.individuals
    }
}

impl<I> UnratedPopulation<I> where I: Clone + Sync
{
    pub fn individuals(&self) -> &[I] {
        &self.individuals
    }

    pub fn new() -> UnratedPopulation<I> {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, ind: I) {
        self.individuals.push(ind);
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    /// Rate the individuals.
    pub fn rate<F, E>(self, eval: &E) -> RatedPopulation<I, F>
        where F: Dominate + MultiObjective + Clone,
              E: Fn(&I) -> F
    {
        let fitness = self.individuals.iter().map(eval).collect();
        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }

    /// Rate the individuals in parallel.
    pub fn rate_in_parallel<F, E>(self, eval: &E, weight: f64) -> RatedPopulation<I, F>
        where F: Dominate + MultiObjective + Clone + Send,
              E: Sync + Fn(&I) -> F
    {
        let mut fitness = Vec::new();
        self.individuals.into_par_iter().map(eval).weight(weight).collect_into(&mut fitness);
        assert!(fitness.len() == self.individuals.len());

        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }
}

impl<I, F> RatedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    pub fn select<D>(self,
                     population_size: usize,
                     num_objectives: usize,
                     domination: &mut D)
                     -> SelectedPopulation<I, F>
        where D: Domination<F>
    {
        // evaluate rank and crowding distance
        let rank_dist = select_solutions(&self.fitness,
                                         population_size,
                                         num_objectives,
                                         domination);
        assert!(rank_dist.len() <= population_size);
        SelectedPopulation {
            individuals: self.individuals,
            fitness: self.fitness,
            rank_dist: rank_dist,
        }
    }

    pub fn new() -> RatedPopulation<I, F> {
        RatedPopulation {
            individuals: Vec::new(),
            fitness: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    pub fn fitness(&self) -> &[F] {
        &self.fitness
    }
}

impl<I, F> SelectedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    /// Generate an offspring population.
    /// XXX: Factor out selection into a separate Trait  SelectionMethod
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &M)
                           -> UnratedPopulation<I>
        where R: Rng,
              M: Fn(&mut R, &I, &I) -> I
    {
        assert!(self.individuals.len() == self.fitness.len());
        assert!(self.individuals.len() >= self.rank_dist.len());
        assert!(tournament_k > 0);

        let rank_dist = &self.rank_dist[..];

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<I> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if rank_dist[p1] < rank_dist[p2] {
                        (p1, p2)
                    } else if rank_dist[p2] < rank_dist[p1] {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    mate(rng, &self.individuals[p1], &self.individuals[p2])
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> SelectedPopulation<I, F> {
        SelectedPopulation {
            individuals: Vec::new(),
            fitness: Vec::new(),
            rank_dist: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        // NOTE: the population and fitness arrays might still be larger.
        self.rank_dist.len()
    }

    /// Merging a selected population result in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<I, F>) -> RatedPopulation<I, F> {
        let mut new_ind = Vec::with_capacity(self.len() + offspring.len());
        let mut new_fit = Vec::with_capacity(self.len() + offspring.len());
        self.all(&mut |ind, fit| {
            // XXX: Optimize. Avoid clone
            new_ind.push(ind.clone());
            new_fit.push(fit.clone());
        });

        new_ind.extend(offspring.individuals);
        new_fit.extend(offspring.fitness);

        assert!(new_ind.len() == new_fit.len());

        RatedPopulation {
            individuals: new_ind,
            fitness: new_fit,
        }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
        }
    }

    pub fn all_with_rank_dist<C>(&self, f: &mut C)
        where C: FnMut(&I, &F, usize, f32)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx],
              &self.fitness[rd.idx],
              rd.rank as usize,
              rd.dist);
        }
    }

    // XXX: fitness_iter()
    pub fn fitness_to_vec(&self) -> Vec<F> {
        let mut v = Vec::new();
        self.all(&mut |_, f| v.push(f.clone()));
        v
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.rank_dist.iter().map(|rd| rd.rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            if rd.rank as usize == rank {
                f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
            }
        }
    }
}

pub struct DriverConfig {
    pub mu: usize,
    pub lambda: usize,
    pub k: usize,
    pub ngen: usize,
    pub num_objectives: usize,
}

pub trait Driver<I, F>: Sync
where I: Clone + Sync,
      F: Dominate + MultiObjective + Clone + Send
{
    fn random_individual<R: Rng>(&self, rng: &mut R) -> I;
    fn random_population<R: Rng>(&self, rng: &mut R, n: usize) -> UnratedPopulation<I> {
        (0..n).map(|_| self.random_individual(rng)).collect()
    }
    fn fitness(&self, ind: &I) -> F;
    fn mate<R: Rng>(&self, rng: &mut R, parent1: &I, parent2: &I) -> I;
    fn is_solution(&self, _ind: &I, _fit: &F) -> bool {
        false
    }

    fn run<R, D, L>(&self,
                    rng: &mut R,
                    config: &DriverConfig,
                    weight: f64,
                    domination: &mut D,
                    logger: &L)
                    -> SelectedPopulation<I, F>
        where R: Rng,
              D: Domination<F>,
              L: Fn(usize, u64, usize, &SelectedPopulation<I, F>)
    {
        // this is generation 0. it's empty
        let mut time_last = time::precise_time_ns();
        let mut parents = SelectedPopulation::<I, F>::new();
        let mut offspring = self.random_population(rng, config.mu);
        let mut gen: usize = 0;

        loop {
            let rated_offspring = offspring.rate_in_parallel(&|ind| self.fitness(ind), weight);
            let next_generation = parents.merge(rated_offspring);
            parents = next_generation.select(config.mu, config.num_objectives, domination);

            let mut found_solutions = 0;
            parents.all(&mut |ind, fit| {
                if self.is_solution(ind, fit) {
                    found_solutions += 1;
                }
            });

            let now = time::precise_time_ns();
            let duration = now - time_last;
            time_last = now;

            logger(gen, duration, found_solutions, &parents);

            if found_solutions > 0 {
                break;
            }

            gen += 1;
            if gen > config.ngen {
                break;
            }

            offspring = parents.reproduce(rng,
                                          config.lambda,
                                          config.k,
                                          &|rng, p1, p2| self.mate(rng, p1, p2));
        }

        return parents;
    }
}

#[test]
fn test_dominates() {
    use mo::MultiObjective2;

    let a = MultiObjective2::from((1.0f32, 0.1));
    let b = MultiObjective2::from((0.1f32, 0.1));
    let c = MultiObjective2::from((0.1f32, 1.0));

    assert_eq!(false, a.dominates(&a));
    assert_eq!(false, a.dominates(&b));
    assert_eq!(false, a.dominates(&c));

    assert_eq!(true, b.dominates(&a));
    assert_eq!(false, b.dominates(&b));
    assert_eq!(true, b.dominates(&c));

    assert_eq!(false, c.dominates(&a));
    assert_eq!(false, c.dominates(&b));
    assert_eq!(false, c.dominates(&c));
}

#[test]
fn test_abc() {
    use mo::MultiObjective2;

    let mut solutions: Vec<MultiObjective2<f32>> = Vec::new();
    solutions.push(MultiObjective2::from((1.0, 0.1)));
    solutions.push(MultiObjective2::from((0.1, 0.1)));
    solutions.push(MultiObjective2::from((0.1, 1.0)));
    solutions.push(MultiObjective2::from((0.5, 0.5)));
    solutions.push(MultiObjective2::from((0.5, 0.5)));

    println!("solutions: {:?}", solutions);
    let selection = select_solutions(&solutions[..], 5, 2, &mut DominationHelper);
    println!("selection: {:?}", selection);

    let fronts = fast_non_dominated_sort(&solutions[..], 10, &mut DominationHelper);
    println!("solutions: {:?}", solutions);
    println!("fronts: {:?}", fronts);

    for (rank, front) in fronts.iter().enumerate() {
        let distances = crowding_distance_assignment(&solutions[..], rank as u32, &front[..], 2);
        println!("front: {:?}", front);
        println!("distances: {:?}", distances);
    }
}
<commit_msg>Use FastNonDominatedSorter<commit_after>extern crate rand;
extern crate rayon;
extern crate time;

use std::cmp;
use rand::Rng;
use selection::tournament_selection_fast;
use mo::MultiObjective;
pub use self::domination::{Domination, Dominate, DominationHelper};
use domination::FastNonDominatedSorter;
use rayon::par_iter::*;
use std::convert::{AsRef, From};
use std::iter::FromIterator;
use crowding_distance::{crowding_distance_assignment, SolutionRankDist};

pub mod selection;
pub mod mo;
pub mod domination;
mod crowding_distance;

/// Select `n` out of the `solutions`, assigning rank and distance using the first `num_objectives`
/// objectives.

fn select_solutions<T, D>(solutions: &[T],
                          n: usize,
                          num_objectives: usize,
                          domination: &mut D)
                          -> Vec<SolutionRankDist>
    where T: MultiObjective,
          D: Domination<T>
{
    let mut selection = Vec::with_capacity(cmp::min(solutions.len(), n));

    let pareto_fronts = FastNonDominatedSorter::new(solutions, domination);

    for (rank, front) in pareto_fronts.enumerate() {
        if selection.len() >= n {
            break;
        }
        let missing = n - selection.len();

        let mut solution_rank_dist = crowding_distance_assignment(solutions,
                                                                  rank as u32,
                                                                  &front,
                                                                  num_objectives);
        if solution_rank_dist.len() <= missing {
            // whole front fits into result.
            // XXX: should we sort?
            selection.extend(solution_rank_dist);
            assert!(selection.len() <= n);
        } else {
            // choose only best from this front, according to the crowding distance.
            solution_rank_dist.sort_by(|a, b| {
                debug_assert!(a.rank == b.rank);
                a.partial_cmp(b).unwrap()
            });
            selection.extend(solution_rank_dist.into_iter().take(missing));
            assert!(selection.len() == n);
            break;
        }
    }

    return selection;
}

/// An unrated Population of individuals.
pub struct UnratedPopulation<I>
    where I: Clone
{
    individuals: Vec<I>,
}

/// A rated Population of individuals, i.e.
/// each individual has a fitness assigned.
pub struct RatedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
}

/// A selected (ranked) Population.
pub struct SelectedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
    rank_dist: Vec<SolutionRankDist>,
}

impl<I> From<Vec<I>> for UnratedPopulation<I> where I: Clone
{
    fn from(v: Vec<I>) -> UnratedPopulation<I> {
        UnratedPopulation { individuals: v }
    }
}

impl<I> FromIterator<I> for UnratedPopulation<I> where I: Clone
{
    fn from_iter<T>(iterator: T) -> UnratedPopulation<I>
        where T: IntoIterator<Item = I>
    {
        UnratedPopulation { individuals: iterator.into_iter().collect() }
    }
}

impl<I> AsRef<[I]> for UnratedPopulation<I> where I: Clone
{
    fn as_ref(&self) -> &[I] {
        &self.individuals
    }
}

impl<I> UnratedPopulation<I> where I: Clone + Sync
{
    pub fn individuals(&self) -> &[I] {
        &self.individuals
    }

    pub fn new() -> UnratedPopulation<I> {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, ind: I) {
        self.individuals.push(ind);
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    /// Rate the individuals.
    pub fn rate<F, E>(self, eval: &E) -> RatedPopulation<I, F>
        where F: Dominate + MultiObjective + Clone,
              E: Fn(&I) -> F
    {
        let fitness = self.individuals.iter().map(eval).collect();
        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }

    /// Rate the individuals in parallel.
    pub fn rate_in_parallel<F, E>(self, eval: &E, weight: f64) -> RatedPopulation<I, F>
        where F: Dominate + MultiObjective + Clone + Send,
              E: Sync + Fn(&I) -> F
    {
        let mut fitness = Vec::new();
        self.individuals.into_par_iter().map(eval).weight(weight).collect_into(&mut fitness);
        assert!(fitness.len() == self.individuals.len());

        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }
}

impl<I, F> RatedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    pub fn select<D>(self,
                     population_size: usize,
                     num_objectives: usize,
                     domination: &mut D)
                     -> SelectedPopulation<I, F>
        where D: Domination<F>
    {
        // evaluate rank and crowding distance
        let rank_dist = select_solutions(&self.fitness,
                                         population_size,
                                         num_objectives,
                                         domination);
        assert!(rank_dist.len() <= population_size);
        SelectedPopulation {
            individuals: self.individuals,
            fitness: self.fitness,
            rank_dist: rank_dist,
        }
    }

    pub fn new() -> RatedPopulation<I, F> {
        RatedPopulation {
            individuals: Vec::new(),
            fitness: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    pub fn fitness(&self) -> &[F] {
        &self.fitness
    }
}

impl<I, F> SelectedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    /// Generate an offspring population.
    /// XXX: Factor out selection into a separate Trait  SelectionMethod
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &M)
                           -> UnratedPopulation<I>
        where R: Rng,
              M: Fn(&mut R, &I, &I) -> I
    {
        assert!(self.individuals.len() == self.fitness.len());
        assert!(self.individuals.len() >= self.rank_dist.len());
        assert!(tournament_k > 0);

        let rank_dist = &self.rank_dist[..];

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<I> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if rank_dist[p1] < rank_dist[p2] {
                        (p1, p2)
                    } else if rank_dist[p2] < rank_dist[p1] {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    mate(rng, &self.individuals[p1], &self.individuals[p2])
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> SelectedPopulation<I, F> {
        SelectedPopulation {
            individuals: Vec::new(),
            fitness: Vec::new(),
            rank_dist: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        // NOTE: the population and fitness arrays might still be larger.
        self.rank_dist.len()
    }

    /// Merging a selected population result in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<I, F>) -> RatedPopulation<I, F> {
        let mut new_ind = Vec::with_capacity(self.len() + offspring.len());
        let mut new_fit = Vec::with_capacity(self.len() + offspring.len());
        self.all(&mut |ind, fit| {
            // XXX: Optimize. Avoid clone
            new_ind.push(ind.clone());
            new_fit.push(fit.clone());
        });

        new_ind.extend(offspring.individuals);
        new_fit.extend(offspring.fitness);

        assert!(new_ind.len() == new_fit.len());

        RatedPopulation {
            individuals: new_ind,
            fitness: new_fit,
        }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
        }
    }

    pub fn all_with_rank_dist<C>(&self, f: &mut C)
        where C: FnMut(&I, &F, usize, f32)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx],
              &self.fitness[rd.idx],
              rd.rank as usize,
              rd.dist);
        }
    }

    // XXX: fitness_iter()
    pub fn fitness_to_vec(&self) -> Vec<F> {
        let mut v = Vec::new();
        self.all(&mut |_, f| v.push(f.clone()));
        v
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.rank_dist.iter().map(|rd| rd.rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            if rd.rank as usize == rank {
                f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
            }
        }
    }
}

pub struct DriverConfig {
    pub mu: usize,
    pub lambda: usize,
    pub k: usize,
    pub ngen: usize,
    pub num_objectives: usize,
}

pub trait Driver<I, F>: Sync
where I: Clone + Sync,
      F: Dominate + MultiObjective + Clone + Send
{
    fn random_individual<R: Rng>(&self, rng: &mut R) -> I;
    fn random_population<R: Rng>(&self, rng: &mut R, n: usize) -> UnratedPopulation<I> {
        (0..n).map(|_| self.random_individual(rng)).collect()
    }
    fn fitness(&self, ind: &I) -> F;
    fn mate<R: Rng>(&self, rng: &mut R, parent1: &I, parent2: &I) -> I;
    fn is_solution(&self, _ind: &I, _fit: &F) -> bool {
        false
    }

    fn run<R, D, L>(&self,
                    rng: &mut R,
                    config: &DriverConfig,
                    weight: f64,
                    domination: &mut D,
                    logger: &L)
                    -> SelectedPopulation<I, F>
        where R: Rng,
              D: Domination<F>,
              L: Fn(usize, u64, usize, &SelectedPopulation<I, F>)
    {
        // this is generation 0. it's empty
        let mut time_last = time::precise_time_ns();
        let mut parents = SelectedPopulation::<I, F>::new();
        let mut offspring = self.random_population(rng, config.mu);
        let mut gen: usize = 0;

        loop {
            let rated_offspring = offspring.rate_in_parallel(&|ind| self.fitness(ind), weight);
            let next_generation = parents.merge(rated_offspring);
            parents = next_generation.select(config.mu, config.num_objectives, domination);

            let mut found_solutions = 0;
            parents.all(&mut |ind, fit| {
                if self.is_solution(ind, fit) {
                    found_solutions += 1;
                }
            });

            let now = time::precise_time_ns();
            let duration = now - time_last;
            time_last = now;

            logger(gen, duration, found_solutions, &parents);

            if found_solutions > 0 {
                break;
            }

            gen += 1;
            if gen > config.ngen {
                break;
            }

            offspring = parents.reproduce(rng,
                                          config.lambda,
                                          config.k,
                                          &|rng, p1, p2| self.mate(rng, p1, p2));
        }

        return parents;
    }
}

#[test]
fn test_dominates() {
    use mo::MultiObjective2;

    let a = MultiObjective2::from((1.0f32, 0.1));
    let b = MultiObjective2::from((0.1f32, 0.1));
    let c = MultiObjective2::from((0.1f32, 1.0));

    assert_eq!(false, a.dominates(&a));
    assert_eq!(false, a.dominates(&b));
    assert_eq!(false, a.dominates(&c));

    assert_eq!(true, b.dominates(&a));
    assert_eq!(false, b.dominates(&b));
    assert_eq!(true, b.dominates(&c));

    assert_eq!(false, c.dominates(&a));
    assert_eq!(false, c.dominates(&b));
    assert_eq!(false, c.dominates(&c));
}

#[test]
fn test_abc() {
    use mo::MultiObjective2;
    use domination::fast_non_dominated_sort;

    let mut solutions: Vec<MultiObjective2<f32>> = Vec::new();
    solutions.push(MultiObjective2::from((1.0, 0.1)));
    solutions.push(MultiObjective2::from((0.1, 0.1)));
    solutions.push(MultiObjective2::from((0.1, 1.0)));
    solutions.push(MultiObjective2::from((0.5, 0.5)));
    solutions.push(MultiObjective2::from((0.5, 0.5)));

    println!("solutions: {:?}", solutions);
    let selection = select_solutions(&solutions[..], 5, 2, &mut DominationHelper);
    println!("selection: {:?}", selection);

    let fronts = fast_non_dominated_sort(&solutions[..], 10, &mut DominationHelper);
    println!("solutions: {:?}", solutions);
    println!("fronts: {:?}", fronts);

    for (rank, front) in fronts.iter().enumerate() {
        let distances = crowding_distance_assignment(&solutions[..], rank as u32, &front[..], 2);
        println!("front: {:?}", front);
        println!("distances: {:?}", distances);
    }
}
<|endoftext|>


<commit_before>//! # RdxSort
//!
//! This crate implements [Radix Sort](https://en.wikipedia.org/wiki/Radix_sort) for slices of
//! different data types, either directly or by exploiting the implementation of other data types.
//!
//! The main reason for implementing yet another sorting algorithm is that most sorting algorithms
//! are comparative methods. To sort data, they rely on a function that compares data elements. It
//! can be proven that this leads to a runtime complexity of `O(n*log(n))` in avarage and `O(n^2)`
//! in the worst case. In contrast to that, Radix Sort exploits that fact that many data types have
//! a limited range of possible values and within that range a limited resolution (that also holds
//! for floating point numbers). For a detailed explaination see the
//! [Wikipedia article](https://en.wikipedia.org/wiki/Radix_sort). The result of this special
//! treatment is a lowered and constant complexity of `O(n*k)` where `k` is the number of fixed
//! rounds required to sort a specific data type.
//!
//!
//! ## Supported Data Types
//!
//! Currently, the following data types are supported:
//!
//! - **bool:** native implementation
//! - **unsigned integers:** native implementation
//! - **signed integers:** splitting into positive and negative parts and using the unsigned
//!   implementation
//! - **floats:** splits data into `-∞`, `(-∞,-0)`, `-0`, `+0`, `(+0,+∞)`, `+∞` and treating the two
//!   ranges as unsigned integer values. [Subnormals](https://en.wikipedia.org/wiki/Denormal_number)
//!   and `NaN`s are not supported!
//!
//!
//! ## Example
//!
//! ```
//! use rdxsort::*;
//!
//! fn main() {
//!     let mut data = vec![2, 10, 0, 1];
//!     data.rdxsort();
//!     assert!(data == vec![0, 1, 2, 10]);
//! }
//! ```
//!
//!
//! ## Performance
//!
//! Of course the lower runtime complexity of Radix Sort shows its power when sorting certain data
//! types. The advantage depends on the size and complexity of the type. While short unsigned
//! integers benifit the most, long types do not show that huge improvements. The following listing
//! shows the runtime in ns required for sorting data sets of different sizes. The data sets are
//! sampled using an uniform distribution. The best algorithm out of the following is marked:
//!
//! - [quicksort](https://crates.io/crates/quicksort)
//! - rdxsort (this crate)
//! - [standard library](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort_by)
//!
//! Keep in mind that the results may vary depending on the hardware, compiler version, operating
//! system version and configuration and the weather.
//!
//!
//! ### Small (1'000 elements)
//!
//! For small data sets Radix Sort can be an advantage for data types with up to 32 bits size. For
//! 64 bits, standard library sorting should be preferred.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `4,199` | **`3,579`** | `27,786` |
//! | `char` | `33,897` | **`32,842`** | `35,840` |
//! | `f32` | `82,225` | **`28,867`** | `82,526` |
//! | `f64` | `88,772` | **`60,041`** | `85,664` |
//! | `i16` | `34,817` | **`15,149`** | `33,171` |
//! | `i32` | `34,192` | **`27,006`** | `31,786` |
//! | `i64` | `36,417` | `54,626` | **`33,133`** |
//! | `i8` | `26,135` | **`8,535`** | `47,711` |
//! | `u16` | `35,892` | **`16,160`** | `34,442` |
//! | `u32` | `33,380` | **`32,779`** | `34,081` |
//! | `u64` | `35,047` | `69,763` | **`34,880`** |
//! | `u8` | `26,974` | **`9,127`** | `48,248` |
//!
//!
//! ### Medium (10'000 elements)
//!
//! For medium data sets Radix Sort could be blindly used for all data types since the disadvantage
//! for types with 64 bits is quite small.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `57,110` | **`33,837`** | `424,807` |
//! | `char` | `701,575` | **`300,163`** | `533,560` |
//! | `f32` | `1,144,874` | **`249,719`** | `1,178,341` |
//! | `f64` | `1,164,848` | **`452,096`** | `1,223,874` |
//! | `i16` | `697,117` | **`151,539`** | `479,502` |
//! | `i32` | `697,657` | **`256,532`** | `480,306` |
//! | `i64` | `704,445` | **`472,059`** | `498,994` |
//! | `i8` | `398,733` | **`103,897`** | `653,829` |
//! | `u16` | `709,508` | **`144,522`** | `529,706` |
//! | `u32` | `704,948` | **`310,517`** | `533,432` |
//! | `u64` | `703,639` | `582,066` | **`550,873`** |
//! | `u8` | `407,994` | **`77,790`** | `683,931` |
//!
//!
//! ### Large (100'000 elements)
//!
//! For large data sets, Radix Sort is great for all data types.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `872,380` | **`352,250`** | `5,273,593` |
//! | `char` | `8,718,712` | **`3,674,520`** | `6,808,558` |
//! | `f32` | `14,525,882` | **`3,602,960`** | `14,794,566` |
//! | `f64` | `14,388,793` | **`7,507,376`** | `16,555,355` |
//! | `i16` | `8,839,427` | **`1,552,497`** | `5,977,884` |
//! | `i32` | `8,729,181` | **`2,784,668`** | `6,371,906` |
//! | `i64` | `8,670,213` | **`5,962,087`** | `7,001,072` |
//! | `i8` | `3,823,044` | **`1,063,651`** | `7,584,821` |
//! | `u16` | `8,899,513` | **`1,521,481`** | `6,715,678` |
//! | `u32` | `8,497,530` | **`3,407,685`** | `6,751,882` |
//! | `u64` | `8,560,613` | **`6,788,488`** | `7,689,427` |
//! | `u8` | `3,918,831` | **`775,895`** | `8,283,952` |
//!
//!
//! ## Implementing New Types
//!
//! This crate enables you to add support for new types by implementing `RdxSortTemplate`. It
//! describes how data is sorted into buckets and how many rounds of sorting are scheduled.
//!
//! ```
//! use rdxsort::*;
//!
//! // `Clone` is required for `RdxSort`
//! // `PartialEq` is only required for the equality assert, not for the actual sorting
//! #[derive(Clone, PartialEq)]
//! struct Foo {
//!     a: u8,
//!     b: u8,
//! }
//!
//! impl RdxSortTemplate for Foo {
//!     fn cfg_nbuckets() -> usize {
//!         // usually too high, but works as a simple demonstration
//!         // `256 = 2^8`
//!         256
//!     }
//!
//!     fn cfg_nrounds() -> usize {
//!         // one per sub-type
//!         2
//!     }
//!
//!     fn get_bucket(&self, round: usize) -> usize {
//!         // return the least significant digit first
//!         if round == 0 {
//!             self.b as usize
//!         } else {
//!             self.a as usize
//!         }
//!     }
//! }
//!
//! fn main() {
//!     let mut data = vec![
//!         Foo{a: 5, b: 2},
//!         Foo{a: 0, b: 1},
//!         Foo{a: 5, b: 1},
//!         Foo{a: 0, b: 2},
//!     ];
//!     data.rdxsort();
//!
//!     let reference = vec![
//!         Foo{a: 0, b: 1},
//!         Foo{a: 0, b: 2},
//!         Foo{a: 5, b: 1},
//!         Foo{a: 5, b: 2},
//!     ];
//!     assert!(data == reference);
//! }
//! ```

extern crate core;

/// Radix Sort implementation for some type
pub trait RdxSort {
    /// Execute Radix Sort, overwrites (unsorted) content of the type.
    fn rdxsort(&mut self);
}

mod template;
mod bool;
mod char;
mod unsigned_integer;
mod signed_integer;
mod floats;

pub use template::RdxSortTemplate;
<commit_msg>mention char in docs<commit_after>//! # RdxSort
//!
//! This crate implements [Radix Sort](https://en.wikipedia.org/wiki/Radix_sort) for slices of
//! different data types, either directly or by exploiting the implementation of other data types.
//!
//! The main reason for implementing yet another sorting algorithm is that most sorting algorithms
//! are comparative methods. To sort data, they rely on a function that compares data elements. It
//! can be proven that this leads to a runtime complexity of `O(n*log(n))` in avarage and `O(n^2)`
//! in the worst case. In contrast to that, Radix Sort exploits that fact that many data types have
//! a limited range of possible values and within that range a limited resolution (that also holds
//! for floating point numbers). For a detailed explaination see the
//! [Wikipedia article](https://en.wikipedia.org/wiki/Radix_sort). The result of this special
//! treatment is a lowered and constant complexity of `O(n*k)` where `k` is the number of fixed
//! rounds required to sort a specific data type.
//!
//!
//! ## Supported Data Types
//!
//! Currently, the following data types are supported:
//!
//! - **bool:** native implementation
//! - **char:** native implementation
//! - **unsigned integers:** native implementation
//! - **signed integers:** splitting into positive and negative parts and using the unsigned
//!   implementation
//! - **floats:** splits data into `-∞`, `(-∞,-0)`, `-0`, `+0`, `(+0,+∞)`, `+∞` and treating the two
//!   ranges as unsigned integer values. [Subnormals](https://en.wikipedia.org/wiki/Denormal_number)
//!   and `NaN`s are not supported!
//!
//!
//! ## Example
//!
//! ```
//! use rdxsort::*;
//!
//! fn main() {
//!     let mut data = vec![2, 10, 0, 1];
//!     data.rdxsort();
//!     assert!(data == vec![0, 1, 2, 10]);
//! }
//! ```
//!
//!
//! ## Performance
//!
//! Of course the lower runtime complexity of Radix Sort shows its power when sorting certain data
//! types. The advantage depends on the size and complexity of the type. While short unsigned
//! integers benifit the most, long types do not show that huge improvements. The following listing
//! shows the runtime in ns required for sorting data sets of different sizes. The data sets are
//! sampled using an uniform distribution. The best algorithm out of the following is marked:
//!
//! - [quicksort](https://crates.io/crates/quicksort)
//! - rdxsort (this crate)
//! - [standard library](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort_by)
//!
//! Keep in mind that the results may vary depending on the hardware, compiler version, operating
//! system version and configuration and the weather.
//!
//!
//! ### Small (1'000 elements)
//!
//! For small data sets Radix Sort can be an advantage for data types with up to 32 bits size. For
//! 64 bits, standard library sorting should be preferred.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `4,199` | **`3,579`** | `27,786` |
//! | `char` | `33,897` | **`32,842`** | `35,840` |
//! | `f32` | `82,225` | **`28,867`** | `82,526` |
//! | `f64` | `88,772` | **`60,041`** | `85,664` |
//! | `i16` | `34,817` | **`15,149`** | `33,171` |
//! | `i32` | `34,192` | **`27,006`** | `31,786` |
//! | `i64` | `36,417` | `54,626` | **`33,133`** |
//! | `i8` | `26,135` | **`8,535`** | `47,711` |
//! | `u16` | `35,892` | **`16,160`** | `34,442` |
//! | `u32` | `33,380` | **`32,779`** | `34,081` |
//! | `u64` | `35,047` | `69,763` | **`34,880`** |
//! | `u8` | `26,974` | **`9,127`** | `48,248` |
//!
//!
//! ### Medium (10'000 elements)
//!
//! For medium data sets Radix Sort could be blindly used for all data types since the disadvantage
//! for types with 64 bits is quite small.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `57,110` | **`33,837`** | `424,807` |
//! | `char` | `701,575` | **`300,163`** | `533,560` |
//! | `f32` | `1,144,874` | **`249,719`** | `1,178,341` |
//! | `f64` | `1,164,848` | **`452,096`** | `1,223,874` |
//! | `i16` | `697,117` | **`151,539`** | `479,502` |
//! | `i32` | `697,657` | **`256,532`** | `480,306` |
//! | `i64` | `704,445` | **`472,059`** | `498,994` |
//! | `i8` | `398,733` | **`103,897`** | `653,829` |
//! | `u16` | `709,508` | **`144,522`** | `529,706` |
//! | `u32` | `704,948` | **`310,517`** | `533,432` |
//! | `u64` | `703,639` | `582,066` | **`550,873`** |
//! | `u8` | `407,994` | **`77,790`** | `683,931` |
//!
//!
//! ### Large (100'000 elements)
//!
//! For large data sets, Radix Sort is great for all data types.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `872,380` | **`352,250`** | `5,273,593` |
//! | `char` | `8,718,712` | **`3,674,520`** | `6,808,558` |
//! | `f32` | `14,525,882` | **`3,602,960`** | `14,794,566` |
//! | `f64` | `14,388,793` | **`7,507,376`** | `16,555,355` |
//! | `i16` | `8,839,427` | **`1,552,497`** | `5,977,884` |
//! | `i32` | `8,729,181` | **`2,784,668`** | `6,371,906` |
//! | `i64` | `8,670,213` | **`5,962,087`** | `7,001,072` |
//! | `i8` | `3,823,044` | **`1,063,651`** | `7,584,821` |
//! | `u16` | `8,899,513` | **`1,521,481`** | `6,715,678` |
//! | `u32` | `8,497,530` | **`3,407,685`** | `6,751,882` |
//! | `u64` | `8,560,613` | **`6,788,488`** | `7,689,427` |
//! | `u8` | `3,918,831` | **`775,895`** | `8,283,952` |
//!
//!
//! ## Implementing New Types
//!
//! This crate enables you to add support for new types by implementing `RdxSortTemplate`. It
//! describes how data is sorted into buckets and how many rounds of sorting are scheduled.
//!
//! ```
//! use rdxsort::*;
//!
//! // `Clone` is required for `RdxSort`
//! // `PartialEq` is only required for the equality assert, not for the actual sorting
//! #[derive(Clone, PartialEq)]
//! struct Foo {
//!     a: u8,
//!     b: u8,
//! }
//!
//! impl RdxSortTemplate for Foo {
//!     fn cfg_nbuckets() -> usize {
//!         // usually too high, but works as a simple demonstration
//!         // `256 = 2^8`
//!         256
//!     }
//!
//!     fn cfg_nrounds() -> usize {
//!         // one per sub-type
//!         2
//!     }
//!
//!     fn get_bucket(&self, round: usize) -> usize {
//!         // return the least significant digit first
//!         if round == 0 {
//!             self.b as usize
//!         } else {
//!             self.a as usize
//!         }
//!     }
//! }
//!
//! fn main() {
//!     let mut data = vec![
//!         Foo{a: 5, b: 2},
//!         Foo{a: 0, b: 1},
//!         Foo{a: 5, b: 1},
//!         Foo{a: 0, b: 2},
//!     ];
//!     data.rdxsort();
//!
//!     let reference = vec![
//!         Foo{a: 0, b: 1},
//!         Foo{a: 0, b: 2},
//!         Foo{a: 5, b: 1},
//!         Foo{a: 5, b: 2},
//!     ];
//!     assert!(data == reference);
//! }
//! ```

extern crate core;

/// Radix Sort implementation for some type
pub trait RdxSort {
    /// Execute Radix Sort, overwrites (unsorted) content of the type.
    fn rdxsort(&mut self);
}

mod template;
mod bool;
mod char;
mod unsigned_integer;
mod signed_integer;
mod floats;

pub use template::RdxSortTemplate;
<|endoftext|>


<commit_before>extern crate asnom;

extern crate bytes;
extern crate byteorder;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate log;
extern crate native_tls;
#[macro_use]
extern crate nom;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_proto;
extern crate tokio_service;
extern crate tokio_tls;
extern crate url;

mod add;
mod bind;
mod conn;
mod delete;
mod ldap;
mod modify;
mod modifydn;
mod protocol;
mod search;
mod filter;

pub use conn::{EntryStream, LdapConn, LdapConnAsync};
pub use ldap::Ldap;
pub use modify::Mod;
pub use protocol::LdapResult;
pub use search::{DerefAliases, Scope, SearchEntry, SearchOptions};
<commit_msg>Reexport ASN.1 types<commit_after>extern crate asnom;

extern crate bytes;
extern crate byteorder;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate log;
extern crate native_tls;
#[macro_use]
extern crate nom;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_proto;
extern crate tokio_service;
extern crate tokio_tls;
extern crate url;

mod add;
mod bind;
mod conn;
mod delete;
mod ldap;
mod modify;
mod modifydn;
mod protocol;
mod search;
mod filter;

pub use conn::{EntryStream, LdapConn, LdapConnAsync};
pub use ldap::Ldap;
pub use modify::Mod;
pub use protocol::LdapResult;
pub use search::{DerefAliases, Scope, SearchEntry, SearchOptions};

pub mod asn1 {
    pub use asnom::structure::StructureTag;
    pub use asnom::structures::{ASNTag, Boolean, Enumerated, ExplicitTag, Integer, Null, OctetString, Sequence, Set, Tag};
    pub use asnom::common::TagClass;
}
<|endoftext|>