<commit_before>//! Parse and write Iridium Short Burst Data (SBD) messages.
//!
//! Iridium is both a [satellite constellation](https://en.wikipedia.org/wiki/Iridium_satellite_constellation)
//! and a [company](https://en.wikipedia.org/wiki/Iridium_Communications) that provides satellite
//! communications. The Iridium network is used by phones, modems, and other communication devices.
//!
//! One mode of transmitting data over the Iridium network is via Short Burst Data (SBD) messages.
//! These messages carry a payload of some small number of bytes, usually less than one thousand.
//! Messages can be Mobile-Originated (MO), meaning that they are sent *from* an Iridium modem, or
//! Mobile-Terminated (MT), meaning that the are sent *to* an Iridium modem. Mobile-originated
//! messages are delivered either to an email address via MIME attachment, or directly to a given
//! IP address and port via TCP; this second method is called DirectIP.
//!
//! This is a simple library for reading mobile originated SBD messages from a stream, decoding
//! their headers and data payloads, and writing them back to a stream. This library does not
//! handle mobile terminated messages.
//!
//! Most of the functionality of this library is exposed by a single executable, named `sbd` that
//! is part of this package. Use the `sbd` executable to inspect raw sbd files stores on a
//! filesystem, discover sbd files on a filesystem, and start a forever-running server to receive
//! Iridium SBD DirectIP messages.

#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_extern_crates,
        unused_import_braces, unused_qualifications)]

pub mod directip;
mod information_element;
pub mod logger;
pub mod filesystem;
pub mod message;

pub use message::Message;

extern crate byteorder;
extern crate chrono;
extern crate glob;
#[macro_use] extern crate log;

use std::result;

/// Crate-specific errors
#[derive(Debug)]
pub enum SbdError {
    /// An error while reading bytes from a stream with the byteorder crate.
    Byteorder(byteorder::Error),
    /// A wrapper around a std::io::Error.
    Io(std::io::Error),
    /// Invalid IMEI number.
    InvalidImei,
    /// Invalid protocol revision number.
    InvalidProtocolRevisionNumber(u8),
    /// Wrapper around a glob error.
    Glob(glob::GlobError),
    /// Missing mobile originated header.
    MissingMobileOriginatedHeader,
    /// Missing mobile originated payload.
    MissingMobileOriginatedPayload,
    /// An oversized message.
    ///
    /// Oversized doesn't demand a size since we don't want to find out how much there really is.
    Oversized,
    /// Wrapper around a glob::PatternError.
    Pattern(glob::PatternError),
    /// An undersized message.
    Undersized(usize),
}

impl From<byteorder::Error> for SbdError {
    fn from(err: byteorder::Error) -> SbdError {
        SbdError::Byteorder(err)
    }
}

impl From<glob::PatternError> for SbdError {
    fn from(err: glob::PatternError) -> SbdError {
        SbdError::Pattern(err)
    }
}

impl From<glob::GlobError> for SbdError {
    fn from(err: glob::GlobError) -> SbdError {
        SbdError::Glob(err)
    }
}

impl From<std::io::Error> for SbdError {
    fn from(err: std::io::Error) -> SbdError {
        SbdError::Io(err)
    }
}

/// Create-specific `Result`.
pub type Result<T> = result::Result<T, SbdError>;
<commit_msg>Implement Error trait for SbdError<commit_after>//! Parse and write Iridium Short Burst Data (SBD) messages.
//!
//! Iridium is both a [satellite constellation](https://en.wikipedia.org/wiki/Iridium_satellite_constellation)
//! and a [company](https://en.wikipedia.org/wiki/Iridium_Communications) that provides satellite
//! communications. The Iridium network is used by phones, modems, and other communication devices.
//!
//! One mode of transmitting data over the Iridium network is via Short Burst Data (SBD) messages.
//! These messages carry a payload of some small number of bytes, usually less than one thousand.
//! Messages can be Mobile-Originated (MO), meaning that they are sent *from* an Iridium modem, or
//! Mobile-Terminated (MT), meaning that the are sent *to* an Iridium modem. Mobile-originated
//! messages are delivered either to an email address via MIME attachment, or directly to a given
//! IP address and port via TCP; this second method is called DirectIP.
//!
//! This is a simple library for reading mobile originated SBD messages from a stream, decoding
//! their headers and data payloads, and writing them back to a stream. This library does not
//! handle mobile terminated messages.
//!
//! Most of the functionality of this library is exposed by a single executable, named `sbd` that
//! is part of this package. Use the `sbd` executable to inspect raw sbd files stores on a
//! filesystem, discover sbd files on a filesystem, and start a forever-running server to receive
//! Iridium SBD DirectIP messages.

#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_extern_crates,
        unused_import_braces, unused_qualifications)]

pub mod directip;
mod information_element;
pub mod logger;
pub mod filesystem;
pub mod message;

pub use message::Message;

extern crate byteorder;
extern crate chrono;
extern crate glob;
#[macro_use] extern crate log;

use std::error::Error;
use std::fmt;
use std::result;

/// Crate-specific errors
#[derive(Debug)]
pub enum SbdError {
    /// An error while reading bytes from a stream with the byteorder crate.
    Byteorder(byteorder::Error),
    /// A wrapper around a std::io::Error.
    Io(std::io::Error),
    /// Invalid IMEI number.
    // TODO Include the IMEI number as an argument.
    InvalidImei,
    /// Invalid protocol revision number.
    InvalidProtocolRevisionNumber(u8),
    /// Wrapper around a glob error.
    Glob(glob::GlobError),
    /// Missing mobile originated header.
    MissingMobileOriginatedHeader,
    /// Missing mobile originated payload.
    MissingMobileOriginatedPayload,
    /// An oversized message.
    ///
    /// Oversized doesn't demand a size since we don't want to find out how much there really is.
    Oversized,
    /// Wrapper around a glob::PatternError.
    Pattern(glob::PatternError),
    /// An undersized message.
    Undersized(usize),
}

impl fmt::Display for SbdError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SbdError::Byteorder(ref err) => write!(f, "Byteorder error: {}", err),
            SbdError::Io(ref err) => write!(f, "IO error: {}", err),
            SbdError::InvalidImei => write!(f, "Invalid IMEI number"),
            SbdError::InvalidProtocolRevisionNumber(number) => write!(f, "Invalid protocl revision number: {}", number),
            SbdError::Glob(ref err) => write!(f, "Glob error: {}", err),
            SbdError::MissingMobileOriginatedHeader => write!(f, "Missing mobile origianted header"),
            SbdError::MissingMobileOriginatedPayload => write!(f, "Missing mobile orignated payload"),
            SbdError::Oversized => write!(f, "Oversized message"),
            SbdError::Pattern(ref err) => write!(f, "Glob pattern error: {}", err),
            SbdError::Undersized(size) => write!(f, "Undersized message: {}", size),
        }
    }
}

impl Error for SbdError {
    fn description(&self) -> &str {
        match *self {
            SbdError::Byteorder(ref err) => err.description(),
            SbdError::Io(ref err) => err.description(),
            SbdError::InvalidImei => "invalid IMEI number",
            SbdError::InvalidProtocolRevisionNumber(_) => "invalid protocol revision number",
            SbdError::Glob(_) => "glob error",
            SbdError::MissingMobileOriginatedHeader => "missing mobile originated header",
            SbdError::MissingMobileOriginatedPayload => "missing mobile originated payload",
            SbdError::Oversized => "oversized message",
            SbdError::Pattern(_) => "glob pattern error",
            SbdError::Undersized(_) => "undersized message",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            SbdError::Byteorder(ref err) => Some(err),
            SbdError::Io(ref err) => Some(err),
            // TODO Once glob supports the `Error` trait, include it as a cause.
            _ => None,
        }
    }
}

impl From<byteorder::Error> for SbdError {
    fn from(err: byteorder::Error) -> SbdError {
        SbdError::Byteorder(err)
    }
}

impl From<glob::PatternError> for SbdError {
    fn from(err: glob::PatternError) -> SbdError {
        SbdError::Pattern(err)
    }
}

impl From<glob::GlobError> for SbdError {
    fn from(err: glob::GlobError) -> SbdError {
        SbdError::Glob(err)
    }
}

impl From<std::io::Error> for SbdError {
    fn from(err: std::io::Error) -> SbdError {
        SbdError::Io(err)
    }
}

/// Create-specific `Result`.
pub type Result<T> = result::Result<T, SbdError>;
<|endoftext|>


<commit_before>//! The _dirs_ crate is
//!
//! - a tiny library with a minimal API (16 functions)
//! - that provides the platform-specific, user-accessible locations
//! - for finding and storing configuration, cache and other data
//! - on Linux, Windows (≥ Vista) and macOS.
//!
//! The library provides the location of these directories by leveraging the mechanisms defined by
//!
//! - the [XDG base directory](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) and the [XDG user directory](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/) specifications on Linux,
//! - the [Known Folder](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776911(v=vs.85).aspx) system on Windows, and
//! - the [Standard Directories](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6) on macOS.
//!

#![deny(missing_docs)]

use std::path::PathBuf;

#[cfg(target_os = "windows")]                                mod win;
#[cfg(target_os = "macos")]                                  mod mac;
#[cfg(not(any(target_os = "windows", target_os = "macos")))] mod lin;
#[cfg(unix)]                                                 mod unix;

#[cfg(target_os = "windows")]                                use win as sys;
#[cfg(target_os = "macos")]                                  use mac as sys;
#[cfg(not(any(target_os = "windows", target_os = "macos")))] use lin as sys;

/// Returns the path to the user's home directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                | Example        |
/// | ------- | -------------------- | -------------- |
/// | Linux   | `$HOME`              | /home/alice    |
/// | macOS   | `$HOME`              | /Users/Alice   |
/// | Windows | `{FOLDERID_Profile}` | C:\Users\Alice |
///
/// ### Linux and macOS:
///
/// - Use `$HOME` if it is set and not empty.
/// - If `$HOME` is not set or empty, then the function `getpwuid_r` is used to determine
///   the home directory of the current user.
/// - If `getpwuid_r` lacks an entry for the current user id or the home directory field is empty,
///   then the function returns `None`.
///
/// ### Windows:
///
/// This function retrieves the user profile folder using `SHGetKnownFolderPath`.
///
/// All the examples on this page mentioning `$HOME` use this behavior.
///
/// _Note:_ This function's behavior differs from [`std::env::home_dir`],
/// which works incorrectly on Linux, macOS and Windows.
///
/// [`std::env::home_dir`]: https://doc.rust-lang.org/std/env/fn.home_dir.html
pub fn home_dir() -> Option<PathBuf> {
    sys::home_dir()
}
/// Returns the path to the user's cache directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                               | Example                      |
/// | ------- | ----------------------------------- | ---------------------------- |
/// | Linux   | `$XDG_CACHE_HOME` or `$HOME`/.cache | /home/alice/.cache           |
/// | macOS   | `$HOME`/Library/Caches              | /Users/Alice/Library/Caches  |
/// | Windows | `{FOLDERID_LocalAppData}`           | C:\Users\Alice\AppData\Local |
pub fn cache_dir() -> Option<PathBuf> {
    sys::cache_dir()
}
/// Returns the path to the user's config directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                 | Example                          |
/// | ------- | ------------------------------------- | -------------------------------- |
/// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config              |
/// | macOS   | `$HOME`/Library/Preferences           | /Users/Alice/Library/Preferences |
/// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming   |
pub fn config_dir() -> Option<PathBuf> {
    sys::config_dir()
}
/// Returns the path to the user's data directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                    | Example                                  |
/// | ------- | ---------------------------------------- | ---------------------------------------- |
/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share                 |
/// | macOS   | `$HOME`/Library/Application Support      | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_RoamingAppData}`              | C:\Users\Alice\AppData\Roaming           |
pub fn data_dir() -> Option<PathBuf> {
    sys::data_dir()
}
/// Returns the path to the user's local data directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                    | Example                                  |
/// | ------- | ---------------------------------------- | ---------------------------------------- |
/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share                 |
/// | macOS   | `$HOME`/Library/Application Support      | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_LocalAppData}`                | C:\Users\Alice\AppData\Local             |
pub fn data_local_dir() -> Option<PathBuf> {
    sys::data_local_dir()
}
/// Returns the path to the user's executable directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                                            | Example                |
/// | ------- | ---------------------------------------------------------------- | ---------------------- |
/// | Linux   | `$XDG_BIN_HOME` or `$XDG_DATA_HOME`/../bin or `$HOME`/.local/bin | /home/alice/.local/bin |
/// | macOS   | –                                                                | –                      |
/// | Windows | –                                                                | –                      |
pub fn executable_dir() -> Option<PathBuf> {
    sys::executable_dir()
}
/// Returns the path to the user's runtime directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value              | Example         |
/// | ------- | ------------------ | --------------- |
/// | Linux   | `$XDG_RUNTIME_DIR` | /run/user/1001/ |
/// | macOS   | –                  | –               |
/// | Windows | –                  | –               |
pub fn runtime_dir() -> Option<PathBuf> {
    sys::runtime_dir()
}

/// Returns the path to the user's audio directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value              | Example              |
/// | ------- | ------------------ | -------------------- |
/// | Linux   | `XDG_MUSIC_DIR`    | /home/alice/Music    |
/// | macOS   | `$HOME`/Music      | /Users/Alice/Music   |
/// | Windows | `{FOLDERID_Music}` | C:\Users\Alice\Music |
pub fn audio_dir() -> Option<PathBuf> {
    sys::audio_dir()
}
/// Returns the path to the user's desktop directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                | Example                |
/// | ------- | -------------------- | ---------------------- |
/// | Linux   | `XDG_DESKTOP_DIR`    | /home/alice/Desktop    |
/// | macOS   | `$HOME`/Desktop      | /Users/Alice/Desktop   |
/// | Windows | `{FOLDERID_Desktop}` | C:\Users\Alice\Desktop |
pub fn desktop_dir() -> Option<PathBuf> {
    sys::desktop_dir()
}
/// Returns the path to the user's document directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                  | Example                  |
/// | ------- | ---------------------- | ------------------------ |
/// | Linux   | `XDG_DOCUMENTS_DIR`    | /home/alice/Documents    |
/// | macOS   | `$HOME`/Documents      | /Users/Alice/Documents   |
/// | Windows | `{FOLDERID_Documents}` | C:\Users\Alice\Documents |
pub fn document_dir() -> Option<PathBuf> {
    sys::document_dir()
}
/// Returns the path to the user's download directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                  | Example                  |
/// | ------- | ---------------------- | ------------------------ |
/// | Linux   | `XDG_DOWNLOAD_DIR`     | /home/alice/Downloads    |
/// | macOS   | `$HOME`/Downloads      | /Users/Alice/Downloads   |
/// | Windows | `{FOLDERID_Downloads}` | C:\Users\Alice\Downloads |
pub fn download_dir() -> Option<PathBuf> {
    sys::download_dir()
}
/// Returns the path to the user's font directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                                | Example                        |
/// | ------- | ---------------------------------------------------- | ------------------------------ |
/// | Linux   | `$XDG_DATA_HOME`/fonts or `$HOME`/.local/share/fonts | /home/alice/.local/share/fonts |
/// | macOS   | `$HOME/Library/Fonts`                                | /Users/Alice/Library/Fonts     |
/// | Windows | –                                                    | –                              |
pub fn font_dir() -> Option<PathBuf> {
    sys::font_dir()
}
/// Returns the path to the user's picture directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                 | Example                 |
/// | ------- | --------------------- | ----------------------- |
/// | Linux   | `XDG_PICTURES_DIR`    | /home/alice/Pictures    |
/// | macOS   | `$HOME`/Pictures      | /Users/Alice/Pictures   |
/// | Windows | `{FOLDERID_Pictures}` | C:\Users\Alice\Pictures |
pub fn picture_dir() -> Option<PathBuf> {
    sys::picture_dir()
}
/// Returns the path to the user's public directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                 | Example             |
/// | ------- | --------------------- | ------------------- |
/// | Linux   | `XDG_PUBLICSHARE_DIR` | /home/alice/Public  |
/// | macOS   | `$HOME`/Public        | /Users/Alice/Public |
/// | Windows | `{FOLDERID_Public}`   | C:\Users\Public     |
pub fn public_dir() -> Option<PathBuf> {
    sys::public_dir()
}
/// Returns the path to the user's template directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                  | Example                                                    |
/// | ------- | ---------------------- | ---------------------------------------------------------- |
/// | Linux   | `XDG_TEMPLATES_DIR`    | /home/alice/Templates                                      |
/// | macOS   | –                      | –                                                          |
/// | Windows | `{FOLDERID_Templates}` | C:\Users\Alice\AppData\Roaming\Microsoft\Windows\Templates |
pub fn template_dir() -> Option<PathBuf> {
    sys::template_dir()
}

/// Returns the path to the user's video directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value               | Example               |
/// | ------- | ------------------- | --------------------- |
/// | Linux   | `XDG_VIDEOS_DIR`    | /home/alice/Videos    |
/// | macOS   | `$HOME`/Movies      | /Users/Alice/Movies   |
/// | Windows | `{FOLDERID_Videos}` | C:\Users\Alice\Videos |
pub fn video_dir() -> Option<PathBuf> {
    sys::video_dir()
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_dirs() {
        println!("home_dir:       {:?}", ::home_dir());
        println!("cache_dir:      {:?}", ::cache_dir());
        println!("config_dir:     {:?}", ::config_dir());
        println!("data_dir:       {:?}", ::data_dir());
        println!("data_local_dir: {:?}", ::data_local_dir());
        println!("executable_dir: {:?}", ::executable_dir());
        println!("runtime_dir:    {:?}", ::runtime_dir());
        println!("audio_dir:      {:?}", ::audio_dir());
        println!("home_dir:       {:?}", ::desktop_dir());
        println!("cache_dir:      {:?}", ::document_dir());
        println!("config_dir:     {:?}", ::download_dir());
        println!("font_dir:       {:?}", ::font_dir());
        println!("picture_dir:    {:?}", ::picture_dir());
        println!("public_dir:     {:?}", ::public_dir());
        println!("template_dir:   {:?}", ::template_dir());
        println!("video_dir:      {:?}", ::video_dir());
    }
}
<commit_msg>Fix formatting in docs for home_dir function<commit_after>//! The _dirs_ crate is
//!
//! - a tiny library with a minimal API (16 functions)
//! - that provides the platform-specific, user-accessible locations
//! - for finding and storing configuration, cache and other data
//! - on Linux, Windows (≥ Vista) and macOS.
//!
//! The library provides the location of these directories by leveraging the mechanisms defined by
//!
//! - the [XDG base directory](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) and the [XDG user directory](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/) specifications on Linux,
//! - the [Known Folder](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776911(v=vs.85).aspx) system on Windows, and
//! - the [Standard Directories](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6) on macOS.
//!

#![deny(missing_docs)]

use std::path::PathBuf;

#[cfg(target_os = "windows")]                                mod win;
#[cfg(target_os = "macos")]                                  mod mac;
#[cfg(not(any(target_os = "windows", target_os = "macos")))] mod lin;
#[cfg(unix)]                                                 mod unix;

#[cfg(target_os = "windows")]                                use win as sys;
#[cfg(target_os = "macos")]                                  use mac as sys;
#[cfg(not(any(target_os = "windows", target_os = "macos")))] use lin as sys;

/// Returns the path to the user's home directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                | Example        |
/// | ------- | -------------------- | -------------- |
/// | Linux   | `$HOME`              | /home/alice    |
/// | macOS   | `$HOME`              | /Users/Alice   |
/// | Windows | `{FOLDERID_Profile}` | C:\Users\Alice |
///
/// ### Linux and macOS:
///
/// - Use `$HOME` if it is set and not empty.
/// - If `$HOME` is not set or empty, then the function `getpwuid_r` is used to determine
///   the home directory of the current user.
/// - If `getpwuid_r` lacks an entry for the current user id or the home directory field is empty,
///   then the function returns `None`.
///
/// ### Windows:
///
/// This function retrieves the user profile folder using `SHGetKnownFolderPath`.
///
/// All the examples on this page mentioning `$HOME` use this behavior.
///
/// _Note:_ This function's behavior differs from [`std::env::home_dir`],
/// which works incorrectly on Linux, macOS and Windows.
///
/// [`std::env::home_dir`]: https://doc.rust-lang.org/std/env/fn.home_dir.html
pub fn home_dir() -> Option<PathBuf> {
    sys::home_dir()
}
/// Returns the path to the user's cache directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                               | Example                      |
/// | ------- | ----------------------------------- | ---------------------------- |
/// | Linux   | `$XDG_CACHE_HOME` or `$HOME`/.cache | /home/alice/.cache           |
/// | macOS   | `$HOME`/Library/Caches              | /Users/Alice/Library/Caches  |
/// | Windows | `{FOLDERID_LocalAppData}`           | C:\Users\Alice\AppData\Local |
pub fn cache_dir() -> Option<PathBuf> {
    sys::cache_dir()
}
/// Returns the path to the user's config directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                 | Example                          |
/// | ------- | ------------------------------------- | -------------------------------- |
/// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config              |
/// | macOS   | `$HOME`/Library/Preferences           | /Users/Alice/Library/Preferences |
/// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming   |
pub fn config_dir() -> Option<PathBuf> {
    sys::config_dir()
}
/// Returns the path to the user's data directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                    | Example                                  |
/// | ------- | ---------------------------------------- | ---------------------------------------- |
/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share                 |
/// | macOS   | `$HOME`/Library/Application Support      | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_RoamingAppData}`              | C:\Users\Alice\AppData\Roaming           |
pub fn data_dir() -> Option<PathBuf> {
    sys::data_dir()
}
/// Returns the path to the user's local data directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                    | Example                                  |
/// | ------- | ---------------------------------------- | ---------------------------------------- |
/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share                 |
/// | macOS   | `$HOME`/Library/Application Support      | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_LocalAppData}`                | C:\Users\Alice\AppData\Local             |
pub fn data_local_dir() -> Option<PathBuf> {
    sys::data_local_dir()
}
/// Returns the path to the user's executable directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                                            | Example                |
/// | ------- | ---------------------------------------------------------------- | ---------------------- |
/// | Linux   | `$XDG_BIN_HOME` or `$XDG_DATA_HOME`/../bin or `$HOME`/.local/bin | /home/alice/.local/bin |
/// | macOS   | –                                                                | –                      |
/// | Windows | –                                                                | –                      |
pub fn executable_dir() -> Option<PathBuf> {
    sys::executable_dir()
}
/// Returns the path to the user's runtime directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value              | Example         |
/// | ------- | ------------------ | --------------- |
/// | Linux   | `$XDG_RUNTIME_DIR` | /run/user/1001/ |
/// | macOS   | –                  | –               |
/// | Windows | –                  | –               |
pub fn runtime_dir() -> Option<PathBuf> {
    sys::runtime_dir()
}

/// Returns the path to the user's audio directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value              | Example              |
/// | ------- | ------------------ | -------------------- |
/// | Linux   | `XDG_MUSIC_DIR`    | /home/alice/Music    |
/// | macOS   | `$HOME`/Music      | /Users/Alice/Music   |
/// | Windows | `{FOLDERID_Music}` | C:\Users\Alice\Music |
pub fn audio_dir() -> Option<PathBuf> {
    sys::audio_dir()
}
/// Returns the path to the user's desktop directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                | Example                |
/// | ------- | -------------------- | ---------------------- |
/// | Linux   | `XDG_DESKTOP_DIR`    | /home/alice/Desktop    |
/// | macOS   | `$HOME`/Desktop      | /Users/Alice/Desktop   |
/// | Windows | `{FOLDERID_Desktop}` | C:\Users\Alice\Desktop |
pub fn desktop_dir() -> Option<PathBuf> {
    sys::desktop_dir()
}
/// Returns the path to the user's document directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                  | Example                  |
/// | ------- | ---------------------- | ------------------------ |
/// | Linux   | `XDG_DOCUMENTS_DIR`    | /home/alice/Documents    |
/// | macOS   | `$HOME`/Documents      | /Users/Alice/Documents   |
/// | Windows | `{FOLDERID_Documents}` | C:\Users\Alice\Documents |
pub fn document_dir() -> Option<PathBuf> {
    sys::document_dir()
}
/// Returns the path to the user's download directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                  | Example                  |
/// | ------- | ---------------------- | ------------------------ |
/// | Linux   | `XDG_DOWNLOAD_DIR`     | /home/alice/Downloads    |
/// | macOS   | `$HOME`/Downloads      | /Users/Alice/Downloads   |
/// | Windows | `{FOLDERID_Downloads}` | C:\Users\Alice\Downloads |
pub fn download_dir() -> Option<PathBuf> {
    sys::download_dir()
}
/// Returns the path to the user's font directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                                                | Example                        |
/// | ------- | ---------------------------------------------------- | ------------------------------ |
/// | Linux   | `$XDG_DATA_HOME`/fonts or `$HOME`/.local/share/fonts | /home/alice/.local/share/fonts |
/// | macOS   | `$HOME/Library/Fonts`                                | /Users/Alice/Library/Fonts     |
/// | Windows | –                                                    | –                              |
pub fn font_dir() -> Option<PathBuf> {
    sys::font_dir()
}
/// Returns the path to the user's picture directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                 | Example                 |
/// | ------- | --------------------- | ----------------------- |
/// | Linux   | `XDG_PICTURES_DIR`    | /home/alice/Pictures    |
/// | macOS   | `$HOME`/Pictures      | /Users/Alice/Pictures   |
/// | Windows | `{FOLDERID_Pictures}` | C:\Users\Alice\Pictures |
pub fn picture_dir() -> Option<PathBuf> {
    sys::picture_dir()
}
/// Returns the path to the user's public directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                 | Example             |
/// | ------- | --------------------- | ------------------- |
/// | Linux   | `XDG_PUBLICSHARE_DIR` | /home/alice/Public  |
/// | macOS   | `$HOME`/Public        | /Users/Alice/Public |
/// | Windows | `{FOLDERID_Public}`   | C:\Users\Public     |
pub fn public_dir() -> Option<PathBuf> {
    sys::public_dir()
}
/// Returns the path to the user's template directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value                  | Example                                                    |
/// | ------- | ---------------------- | ---------------------------------------------------------- |
/// | Linux   | `XDG_TEMPLATES_DIR`    | /home/alice/Templates                                      |
/// | macOS   | –                      | –                                                          |
/// | Windows | `{FOLDERID_Templates}` | C:\Users\Alice\AppData\Roaming\Microsoft\Windows\Templates |
pub fn template_dir() -> Option<PathBuf> {
    sys::template_dir()
}

/// Returns the path to the user's video directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None.
///
/// |Platform | Value               | Example               |
/// | ------- | ------------------- | --------------------- |
/// | Linux   | `XDG_VIDEOS_DIR`    | /home/alice/Videos    |
/// | macOS   | `$HOME`/Movies      | /Users/Alice/Movies   |
/// | Windows | `{FOLDERID_Videos}` | C:\Users\Alice\Videos |
pub fn video_dir() -> Option<PathBuf> {
    sys::video_dir()
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_dirs() {
        println!("home_dir:       {:?}", ::home_dir());
        println!("cache_dir:      {:?}", ::cache_dir());
        println!("config_dir:     {:?}", ::config_dir());
        println!("data_dir:       {:?}", ::data_dir());
        println!("data_local_dir: {:?}", ::data_local_dir());
        println!("executable_dir: {:?}", ::executable_dir());
        println!("runtime_dir:    {:?}", ::runtime_dir());
        println!("audio_dir:      {:?}", ::audio_dir());
        println!("home_dir:       {:?}", ::desktop_dir());
        println!("cache_dir:      {:?}", ::document_dir());
        println!("config_dir:     {:?}", ::download_dir());
        println!("font_dir:       {:?}", ::font_dir());
        println!("picture_dir:    {:?}", ::picture_dir());
        println!("public_dir:     {:?}", ::public_dir());
        println!("template_dir:   {:?}", ::template_dir());
        println!("video_dir:      {:?}", ::video_dir());
    }
}
<|endoftext|>


<commit_before>extern crate rand;
use std::str;
use std::fmt;
use rand::Rng;

#[derive(Debug, Eq, PartialEq, PartialOrd, Clone)]
pub struct Card {
    suit:  String,
    value: String,
}

#[derive(Debug, Eq, PartialEq, PartialOrd, Clone)]
pub struct Deck {
    cards: Vec<Card>
}

impl Card {
    pub fn new(suit: String, value: String) -> Card {
        Card { suit: suit, value: value.to_string() }
    }

    pub fn new_from_str(suit: &str, value: &str) -> Card {
        Card::new(suit.to_string(), value.to_string())
    }
}

impl Ord for Card {
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        self.value.cmp(&other.value)
    }
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Suit: {}, Value: {}", self.suit, self.value)
    }
}

impl Deck {
    pub fn new_from_vec(input: Vec<Card>) -> Deck {
        Deck { cards: input }
    }

    pub fn make_standard() -> Deck {
        let mut result = Vec::new();
        let suits  = &["♣", "♦", "♥", "♠"];
        let values = &["2", "3", "4", "5", "6", "7", "8", "9", "10",
                       "Jack", "Queen", "King", "Ace"];

        for suit in suits {
            for value in values {
                result.push(Card::new_from_str(*suit, value));
            }
        }
        return Deck::new_from_vec(result);
    }

    pub fn make_fifth_dimension() -> Deck {
        let mut result = Vec::new();
        let suits  = &["♣", "♦", "♥", "♠", "★"];
        let values = &["1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                       "Jack", "Princess", "Queen", "King", "Joker"];

        for suit in suits {
            for value in values {
                result.push(Card::new_from_str(*suit, value));
            }
        }
        return Deck::new_from_vec(result);
    }

    // destructively shuffles the internal vector
    pub fn shuffle(&mut self) {
        rand::thread_rng().shuffle(&mut self.cards);
    }

    // returns a new shuffled deck
    pub fn shuffled(&self) -> Self {
        let mut res = self.clone();
        res.shuffle();
        res
    }

    pub fn len(&self) {
        self.cards.len();
    }
}

impl Ord for Deck {
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        self.cards.cmp(&other.cards)
    }
}
<commit_msg>make fields public (oops)<commit_after>extern crate rand;
use std::str;
use std::fmt;
use rand::Rng;

#[derive(Debug, Eq, PartialEq, PartialOrd, Clone)]
pub struct Card {
    pub suit:  String,
    pub value: String,
}

#[derive(Debug, Eq, PartialEq, PartialOrd, Clone)]
pub struct Deck {
    pub cards: Vec<Card>
}

impl Card {
    pub fn new(suit: String, value: String) -> Card {
        Card { suit: suit, value: value.to_string() }
    }

    pub fn new_from_str(suit: &str, value: &str) -> Card {
        Card::new(suit.to_string(), value.to_string())
    }
}

impl Ord for Card {
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        self.value.cmp(&other.value)
    }
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Suit: {}, Value: {}", self.suit, self.value)
    }
}

impl Deck {
    pub fn new_from_vec(input: Vec<Card>) -> Deck {
        Deck { cards: input }
    }

    pub fn make_standard() -> Deck {
        let mut result = Vec::new();
        let suits  = &["♣", "♦", "♥", "♠"];
        let values = &["2", "3", "4", "5", "6", "7", "8", "9", "10",
                       "Jack", "Queen", "King", "Ace"];

        for suit in suits {
            for value in values {
                result.push(Card::new_from_str(*suit, value));
            }
        }
        return Deck::new_from_vec(result);
    }

    pub fn make_fifth_dimension() -> Deck {
        let mut result = Vec::new();
        let suits  = &["♣", "♦", "♥", "♠", "★"];
        let values = &["1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                       "Jack", "Princess", "Queen", "King", "Joker"];

        for suit in suits {
            for value in values {
                result.push(Card::new_from_str(*suit, value));
            }
        }
        return Deck::new_from_vec(result);
    }

    // destructively shuffles the internal vector
    pub fn shuffle(&mut self) {
        rand::thread_rng().shuffle(&mut self.cards);
    }

    // returns a new shuffled deck
    pub fn shuffled(&self) -> Self {
        let mut res = self.clone();
        res.shuffle();
        res
    }

    pub fn len(&self) {
        self.cards.len();
    }
}

impl Ord for Deck {
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        self.cards.cmp(&other.cards)
    }
}
<|endoftext|>


<commit_before>#![feature(lang_items)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(alloc)]
#![feature(asm)]
#![feature(abi_x86_interrupt)]
#![feature(drop_types_in_const)]
#![feature(box_syntax)]
#![feature(global_allocator)]

#![no_std]

extern crate x86;
extern crate x86_64;
extern crate rlibc;
extern crate spin;
extern crate multiboot2;
extern crate alloc_opsys;
extern crate alloc;

#[macro_use]
extern crate bitflags;

#[macro_use]
extern crate once;

use alloc_opsys::LockedAllocator;

#[global_allocator]
static ALLOCATOR: LockedAllocator = LockedAllocator::empty();

#[macro_use]
mod vga_buffer;

#[macro_use]
mod cpu;

mod memory;
mod interrupts;
mod drivers;
mod io;
mod schedule;
mod kernel;

// Main entry point, need no_mangle so we can call from assembly
// Extern to abide with C calling convention
#[no_mangle]
pub extern "C" fn kernel_main(multiboot_info_address: usize) {
    // Initialise the hardware
    init_cpu();

    // Initialise the memory paging and instantiate a new memory manager
    let memory_manager = memory::init(multiboot_info_address);

    // Setup the heap allocator
    unsafe {
        ALLOCATOR.init(memory::KERN_HEAP_START, memory::KERN_HEAP_SIZE);
    }

    vga_buffer::clear_screen();

    // Setup the kernel
    kernel::init(memory_manager);

    // Initialize interrupts
    interrupts::init();

    kprintln!("opsys v{}", "0.0.1");

    // This thread now becomess the System 'Idle' thread.
    hang!();
}

fn init_cpu() {
    // Configure the CPU flags as required
    enable_nxe_bit(); // Allow the NO_EXECUTABLE flag
    enable_write_protect_bit(); // Ensure non-writable by default
}

fn enable_nxe_bit() {
    use x86::msr::{IA32_EFER, rdmsr, wrmsr};

    let nxe_bit = 1 << 11;
    unsafe {
        let efer = rdmsr(IA32_EFER);
        wrmsr(IA32_EFER, efer | nxe_bit);
    }
}

fn enable_write_protect_bit() {
    use x86::controlregs::{cr0, cr0_write};

    let wp_bit = 1 << 16;
    unsafe { cr0_write(cr0() | wp_bit) };
}

// For stack-unwinding, not supported currently
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

// For panic!
#[no_mangle]
#[lang = "panic_fmt"]
pub extern "C" fn panic_fmt(fmt: core::fmt::Arguments, file: &str, line: u32) -> ! {
    kprintln!("\n\nPANIC in {} at line {}:", file, line);
    kprintln!("    {}", fmt);

    // Hang here.
    loop {}
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
    // Hang here.
    loop {}
}
<commit_msg>Added feature declaration for const_unsafe_cell_new<commit_after>#![feature(lang_items)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(alloc)]
#![feature(asm)]
#![feature(abi_x86_interrupt)]
#![feature(drop_types_in_const)]
#![feature(box_syntax)]
#![feature(global_allocator)]
#![feature(const_unsafe_cell_new)]

#![no_std]

extern crate x86;
extern crate x86_64;
extern crate rlibc;
extern crate spin;
extern crate multiboot2;
extern crate alloc_opsys;
extern crate alloc;

#[macro_use]
extern crate bitflags;

#[macro_use]
extern crate once;

use alloc_opsys::LockedAllocator;

#[global_allocator]
static ALLOCATOR: LockedAllocator = LockedAllocator::empty();

#[macro_use]
mod vga_buffer;

#[macro_use]
mod cpu;

mod memory;
mod interrupts;
mod drivers;
mod io;
mod schedule;
mod kernel;

// Main entry point, need no_mangle so we can call from assembly
// Extern to abide with C calling convention
#[no_mangle]
pub extern "C" fn kernel_main(multiboot_info_address: usize) {
    // Initialise the hardware
    init_cpu();

    // Initialise the memory paging and instantiate a new memory manager
    let memory_manager = memory::init(multiboot_info_address);

    // Setup the heap allocator
    unsafe {
        ALLOCATOR.init(memory::KERN_HEAP_START, memory::KERN_HEAP_SIZE);
    }

    vga_buffer::clear_screen();

    // Setup the kernel
    kernel::init(memory_manager);

    // Initialize interrupts
    interrupts::init();

    kprintln!("opsys v{}", "0.0.1");

    // This thread now becomess the System 'Idle' thread.
    hang!();
}

fn init_cpu() {
    // Configure the CPU flags as required
    enable_nxe_bit(); // Allow the NO_EXECUTABLE flag
    enable_write_protect_bit(); // Ensure non-writable by default
}

fn enable_nxe_bit() {
    use x86::msr::{IA32_EFER, rdmsr, wrmsr};

    let nxe_bit = 1 << 11;
    unsafe {
        let efer = rdmsr(IA32_EFER);
        wrmsr(IA32_EFER, efer | nxe_bit);
    }
}

fn enable_write_protect_bit() {
    use x86::controlregs::{cr0, cr0_write};

    let wp_bit = 1 << 16;
    unsafe { cr0_write(cr0() | wp_bit) };
}

// For stack-unwinding, not supported currently
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

// For panic!
#[no_mangle]
#[lang = "panic_fmt"]
pub extern "C" fn panic_fmt(fmt: core::fmt::Arguments, file: &str, line: u32) -> ! {
    kprintln!("\n\nPANIC in {} at line {}:", file, line);
    kprintln!("    {}", fmt);

    // Hang here.
    loop {}
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
    // Hang here.
    loop {}
}
<|endoftext|>


<commit_before>// XXX: Use a ref-counted gene Pool.
// A population is then only a collection of pool item ids.
// This prevents from duplicating potential large genes.
//
// Use typing to make sure that individuals are evaluated when required.
// fn evaluate(self, evaluator) -> EvaluatedPopulation
// fn add(self, ind) -> Population

#![feature(num_bits_bytes)]
extern crate bit_vec;
extern crate rand;
extern crate simple_parallel;
use rand::{Rand, Rng};
use std::cmp::PartialOrd;

pub mod bit_string;

/// A probability is a value in the range [0.0, 1.0].
/// A probability of 1.0 means `always`, that of 0.0
/// means `never`.
#[derive(Copy, Clone, Debug)]
pub struct Probability(f32);

impl Probability {
    #[inline]
    pub fn new(pb: f32) -> Probability {
        assert!(pb >= 0.0 && pb <= 1.0);
        Probability(pb)
    }
}

impl std::ops::Add<Probability> for Probability {
    type Output = Probability;
    #[inline]
    fn add(self, rhs: Probability) -> Probability {
        Probability::new(self.0 + rhs.0)
    }
}

/// A probability value is a random value in the
/// range [0.0, 1.0).
#[derive(Copy, Clone, Debug)]
pub struct ProbabilityValue(f32);

impl Rand for ProbabilityValue {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> ProbabilityValue {
        let val = rng.gen::<f32>();
        assert!(val >= 0.0 && val < 1.0);
        ProbabilityValue(val)
    }
}

impl ProbabilityValue {
    pub fn is_probable_with(self, pb: Probability) -> bool {
        self.0 < pb.0
    }
}

/// Represents a fitness value.
pub trait Fitness: Clone+Send {
    fn fitter_than(&self, other: &Self) -> bool;
}

/// Maximizes the fitness value as objective.
#[derive(Copy, Clone, Debug)]
pub struct MaxFitness<T: PartialOrd + Clone + Send>(pub T);
impl<T:PartialOrd+Clone+Send> Fitness for MaxFitness<T> {
    fn fitter_than(&self, other: &MaxFitness<T>) -> bool {
        self.0 > other.0
    }
}

/// Minimizes the fitness value as objective.
#[derive(Copy, Clone, Debug)]
pub struct MinFitness<T: PartialOrd + Clone + Send>(pub T);
impl<T:PartialOrd+Clone+Send> Fitness for MinFitness<T> {
    fn fitter_than(&self, other: &MinFitness<T>) -> bool {
        self.0 < other.0
    }
}

/// Represents an individual in a Population.
pub trait Individual: Clone+Send {
}

/// Evaluates the fitness of an Individual.
pub trait Evaluator<I:Individual, F:Fitness>: Sync {
    fn fitness(&self, individual: &I) -> F;
}

/// Caches the `fitness` value for an individual.
#[derive(Clone, Debug)]
pub struct EvaluatedIndividual<I: Individual, F: Fitness> {
    individual: I,
    fitness: Option<F>,
}

impl<I:Individual, F:Fitness>  EvaluatedIndividual<I,F> {
    pub fn new(ind: I) -> EvaluatedIndividual<I, F> {
        EvaluatedIndividual {
            individual: ind,
            fitness: None,
        }
    }
    pub fn fitness(&self) -> Option<F> {
        self.fitness.clone()
    }
    pub fn individual<'a>(&'a self) -> &'a I {
        &self.individual
    }
}

/// Manages a population of individuals.
#[derive(Clone, Debug)]
pub struct Population<I: Individual, F: Fitness> {
    population: Vec<EvaluatedIndividual<I, F>>,
}

// XXX: Have Population and EvaluatedPopulation. This avoids having two arrays.
impl<I:Individual, F:Fitness> Population<I,F> {
    pub fn new() -> Population<I, F> {
        Population { population: Vec::new() }
    }

    pub fn with_capacity(capa: usize) -> Population<I, F> {
        Population { population: Vec::with_capacity(capa) }
    }

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

    /// Return individual with best fitness.
    pub fn fittest(&self) -> Option<(usize, F)> {
        let mut fittest: Option<(usize, F)> = None;

        for (i, ref ind) in self.population.iter().enumerate() {
            if let Some(ref f) = ind.fitness {
                let mut is_better = true;
                if let Some((_, ref best_f)) = fittest {
                    if !f.fitter_than(best_f) {
                        is_better = false;
                    }
                }
                if is_better {
                    fittest = Some((i, f.clone()));
                }
            }
        }
        return fittest;
    }

    pub fn get_ref<'a>(&'a self, idx: usize) -> &'a EvaluatedIndividual<I, F> {
        &self.population[idx]
    }

    pub fn add_individual(&mut self, ind: I) {
        self.population.push(EvaluatedIndividual::new(ind));
    }

    pub fn add(&mut self, ind: EvaluatedIndividual<I, F>) {
        self.population.push(ind);
    }

    /// Evaluates the whole population, i.e. determines the fitness of
    /// each `individual` (unless already calculated).
    /// Returns the number of evaluations performed.
    pub fn evaluate<E>(&mut self, evaluator: &E) -> usize
        where E: Evaluator<I, F>
    {
        let mut nevals = 0;
        for i in self.population.iter_mut() {
            if i.fitness.is_some() {
                continue;
            }
            i.fitness = Some(evaluator.fitness(&i.individual));
            nevals += 1;
        }
        return nevals;
    }

    /// Evaluate the population in parallel using a pool of `nthreads`.
    pub fn evaluate_in_parallel<E>(&mut self, evaluator: &E, nthreads: usize) -> usize
        where E: Evaluator<I, F>
    {
        const CHUNK_SIZE: usize = 10;

        let mut nevals = 0;
        for i in self.population.iter() {
            if i.fitness.is_none() {
                nevals += 1;
            }
        }

        // XXX split population into two arrays. one evaluated, one not evaluated. this should speed up parallel evaluation a lot.
        let mut pool = simple_parallel::Pool::new(nthreads);
        pool.for_(self.population.chunks_mut(CHUNK_SIZE), |chunk| {
            for ind in chunk.iter_mut() {
                if ind.fitness.is_some() { continue; }
                ind.fitness = Some(evaluator.fitness(&ind.individual));
            }
        });

        return nevals;
    }

    fn add_population(&mut self, p: &Population<I, F>) {
        for ind in p.population.iter() {
            self.add(ind.clone());
        }
    }
}

/// Select the best individual out of `k` randomly choosen.
/// This gives individuals with better fitness a higher chance to reproduce.
/// `n` is the total number of individuals.
///
/// NOTE: We are not using `sample(rng, 0..n, k)` as it is *very* expensive.
/// Instead we call `rng.gen_range()` k-times. The drawn items could be the same,
/// but the probability is very low if `n` high compared to `k`.
pub fn tournament_selection<R: Rng, F, E>(rng: &mut R,
                                          fitness: E,
                                          n: usize,
                                          k: usize)
                                          -> Option<(usize, F)>
    where F: Fitness,
          E: Fn(usize) -> F
{
    assert!(n >= k);

    let mut best: Option<(usize, F)> = None;

    for _ in 0..k {
        let i = rng.gen_range(0, n);
        let fitness = fitness(i);
        let better = match best {
            Some((_, ref current_best_fitness)) => {
                fitness.fitter_than(current_best_fitness)
            }
            None => {
                true
            }
        };
        if better {
            best = Some((i, fitness));
        }
    }
    return best;
}

pub enum VariationMethod {
    Crossover,
    Mutation,
    Reproduction,
}

/// Mates two individual, producing two children.
pub trait OpCrossover<I: Individual> {
    fn crossover(&mut self, parent1: &I, parent2: &I) -> (I, I);
}

/// Mutates an individual.
pub trait OpMutate<I: Individual> {
    fn mutate(&mut self, ind: &I) -> I;
}

/// Selects a variation method to use.
pub trait OpVariation {
    fn variation(&mut self) -> VariationMethod;
}

/// Selects a random individual from the population.
pub trait OpSelectRandomIndividual<I: Individual, F: Fitness> {
    fn select_random_individual<'a>(&mut self,
                                    population: &'a Population<I, F>)
                                    -> &'a EvaluatedIndividual<I, F>;
}

/// Produce new generation through selection of \mu individuals from population.
pub trait OpSelect<I: Individual, F: Fitness> {
    fn select(&mut self, population: &Population<I, F>, mu: usize) -> Population<I, F>;
}

pub fn variation_or<I, F, T>(toolbox: &mut T,
                             population: &Population<I, F>,
                             lambda: usize)
                             -> Population<I, F>
    where I: Individual,
          F: Fitness,
          T: OpCrossover<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I, F>
{
    let mut offspring = Population::with_capacity(lambda);
    // Each step produces exactly one child.
    for _ in 0..lambda {
        let method = toolbox.variation();
        let child = match method {
            VariationMethod::Crossover => {
                // select two individuals and mate them.
                // only the first offspring is used, the second is thrown away.
                let parent1 = toolbox.select_random_individual(population);
                let parent2 = toolbox.select_random_individual(population);
                let (child1, _child2) = toolbox.crossover(&parent1.individual, &parent2.individual);
                EvaluatedIndividual::new(child1)
            }
            VariationMethod::Mutation => {
                // select a single individual and mutate it.
                let ind = toolbox.select_random_individual(population);
                let child = toolbox.mutate(&ind.individual);
                EvaluatedIndividual::new(child)
            }
            VariationMethod::Reproduction => {
                let ind = toolbox.select_random_individual(population);
                ind.clone()
            }
        };
        offspring.add(child);
    }
    return offspring;
}

// The (\mu + \lambda) algorithm.
// From `population`, \lambda offspring is produced, through either
// mutation, crossover or random reproduction.
// For the next generation, \mu individuals are selected from the \mu + \lambda
// (parents and offspring).
pub fn ea_mu_plus_lambda<I,F,T,E,S>(toolbox: &mut T, evaluator: &E, population: &Population<I,F>, mu: usize, lambda: usize, num_generations: usize, stat: S)
    -> Population<I,F>
where I: Individual,
      F: Fitness,
      T: OpCrossover<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I,F> + OpSelect<I,F>,
      E: Evaluator<I,F>+Sync,
      S: Fn(usize, &Population<I,F>)
{
    let mut nevals = 0;
    let mut p = population.clone();
    nevals += p.evaluate_in_parallel(evaluator, 8);
    stat(0, &p);

    for gen in 0..num_generations {
        // evaluate population. make sure that every individual has been rated.
        let mut offspring = variation_or(toolbox, &p, lambda);
        offspring.add_population(&p);
        nevals += offspring.evaluate_in_parallel(evaluator, 8);
        // select from offspring the `best` individuals
        p = toolbox.select(&offspring, mu);
        stat(gen + 1, &p);
    }

    let _ = nevals;

    return p;
}
<commit_msg>Pass the simple_parallel::Pool instead of number of threads.<commit_after>// XXX: Use a ref-counted gene Pool.
// A population is then only a collection of pool item ids.
// This prevents from duplicating potential large genes.
//
// Use typing to make sure that individuals are evaluated when required.
// fn evaluate(self, evaluator) -> EvaluatedPopulation
// fn add(self, ind) -> Population

#![feature(num_bits_bytes)]
extern crate bit_vec;
extern crate rand;
extern crate simple_parallel;
use rand::{Rand, Rng};
use std::cmp::PartialOrd;
use simple_parallel::Pool;

pub mod bit_string;

/// A probability is a value in the range [0.0, 1.0].
/// A probability of 1.0 means `always`, that of 0.0
/// means `never`.
#[derive(Copy, Clone, Debug)]
pub struct Probability(f32);

impl Probability {
    #[inline]
    pub fn new(pb: f32) -> Probability {
        assert!(pb >= 0.0 && pb <= 1.0);
        Probability(pb)
    }
}

impl std::ops::Add<Probability> for Probability {
    type Output = Probability;
    #[inline]
    fn add(self, rhs: Probability) -> Probability {
        Probability::new(self.0 + rhs.0)
    }
}

/// A probability value is a random value in the
/// range [0.0, 1.0).
#[derive(Copy, Clone, Debug)]
pub struct ProbabilityValue(f32);

impl Rand for ProbabilityValue {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> ProbabilityValue {
        let val = rng.gen::<f32>();
        assert!(val >= 0.0 && val < 1.0);
        ProbabilityValue(val)
    }
}

impl ProbabilityValue {
    pub fn is_probable_with(self, pb: Probability) -> bool {
        self.0 < pb.0
    }
}

/// Represents a fitness value.
pub trait Fitness: Clone+Send {
    fn fitter_than(&self, other: &Self) -> bool;
}

/// Maximizes the fitness value as objective.
#[derive(Copy, Clone, Debug)]
pub struct MaxFitness<T: PartialOrd + Clone + Send>(pub T);
impl<T:PartialOrd+Clone+Send> Fitness for MaxFitness<T> {
    fn fitter_than(&self, other: &MaxFitness<T>) -> bool {
        self.0 > other.0
    }
}

/// Minimizes the fitness value as objective.
#[derive(Copy, Clone, Debug)]
pub struct MinFitness<T: PartialOrd + Clone + Send>(pub T);
impl<T:PartialOrd+Clone+Send> Fitness for MinFitness<T> {
    fn fitter_than(&self, other: &MinFitness<T>) -> bool {
        self.0 < other.0
    }
}

/// Represents an individual in a Population.
pub trait Individual: Clone+Send {
}

/// Evaluates the fitness of an Individual.
pub trait Evaluator<I:Individual, F:Fitness>: Sync {
    fn fitness(&self, individual: &I) -> F;
}

/// Caches the `fitness` value for an individual.
#[derive(Clone, Debug)]
pub struct EvaluatedIndividual<I: Individual, F: Fitness> {
    individual: I,
    fitness: Option<F>,
}

impl<I:Individual, F:Fitness>  EvaluatedIndividual<I,F> {
    pub fn new(ind: I) -> EvaluatedIndividual<I, F> {
        EvaluatedIndividual {
            individual: ind,
            fitness: None,
        }
    }
    pub fn fitness(&self) -> Option<F> {
        self.fitness.clone()
    }
    pub fn individual<'a>(&'a self) -> &'a I {
        &self.individual
    }
}

/// Manages a population of individuals.
#[derive(Clone, Debug)]
pub struct Population<I: Individual, F: Fitness> {
    population: Vec<EvaluatedIndividual<I, F>>,
}

// XXX: Have Population and EvaluatedPopulation. This avoids having two arrays.
impl<I:Individual, F:Fitness> Population<I,F> {
    pub fn new() -> Population<I, F> {
        Population { population: Vec::new() }
    }

    pub fn with_capacity(capa: usize) -> Population<I, F> {
        Population { population: Vec::with_capacity(capa) }
    }

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

    /// Return individual with best fitness.
    pub fn fittest(&self) -> Option<(usize, F)> {
        let mut fittest: Option<(usize, F)> = None;

        for (i, ref ind) in self.population.iter().enumerate() {
            if let Some(ref f) = ind.fitness {
                let mut is_better = true;
                if let Some((_, ref best_f)) = fittest {
                    if !f.fitter_than(best_f) {
                        is_better = false;
                    }
                }
                if is_better {
                    fittest = Some((i, f.clone()));
                }
            }
        }
        return fittest;
    }

    pub fn get_ref<'a>(&'a self, idx: usize) -> &'a EvaluatedIndividual<I, F> {
        &self.population[idx]
    }

    pub fn add_individual(&mut self, ind: I) {
        self.population.push(EvaluatedIndividual::new(ind));
    }

    pub fn add(&mut self, ind: EvaluatedIndividual<I, F>) {
        self.population.push(ind);
    }

    /// Evaluates the whole population, i.e. determines the fitness of
    /// each `individual` (unless already calculated).
    /// Returns the number of evaluations performed.
    pub fn evaluate<E>(&mut self, evaluator: &E) -> usize
        where E: Evaluator<I, F>
    {
        let mut nevals = 0;
        for i in self.population.iter_mut() {
            if i.fitness.is_some() {
                continue;
            }
            i.fitness = Some(evaluator.fitness(&i.individual));
            nevals += 1;
        }
        return nevals;
    }

    /// Evaluate the population in parallel using the threadpool `pool`.
    pub fn evaluate_in_parallel<E>(&mut self, evaluator: &E, pool: &mut Pool) -> usize
        where E: Evaluator<I, F>
    {
        const CHUNK_SIZE: usize = 10;

        let mut nevals = 0;
        for i in self.population.iter() {
            if i.fitness.is_none() {
                nevals += 1;
            }
        }

        // XXX split population into two arrays. one evaluated, one not evaluated. this should speed up parallel evaluation a lot.
        pool.for_(self.population.chunks_mut(CHUNK_SIZE), |chunk| {
            for ind in chunk.iter_mut() {
                if ind.fitness.is_some() { continue; }
                ind.fitness = Some(evaluator.fitness(&ind.individual));
            }
        });

        return nevals;
    }

    fn add_population(&mut self, p: &Population<I, F>) {
        for ind in p.population.iter() {
            self.add(ind.clone());
        }
    }
}

/// Select the best individual out of `k` randomly choosen.
/// This gives individuals with better fitness a higher chance to reproduce.
/// `n` is the total number of individuals.
///
/// NOTE: We are not using `sample(rng, 0..n, k)` as it is *very* expensive.
/// Instead we call `rng.gen_range()` k-times. The drawn items could be the same,
/// but the probability is very low if `n` high compared to `k`.
pub fn tournament_selection<R: Rng, F, E>(rng: &mut R,
                                          fitness: E,
                                          n: usize,
                                          k: usize)
                                          -> Option<(usize, F)>
    where F: Fitness,
          E: Fn(usize) -> F
{
    assert!(n >= k);

    let mut best: Option<(usize, F)> = None;

    for _ in 0..k {
        let i = rng.gen_range(0, n);
        let fitness = fitness(i);
        let better = match best {
            Some((_, ref current_best_fitness)) => {
                fitness.fitter_than(current_best_fitness)
            }
            None => {
                true
            }
        };
        if better {
            best = Some((i, fitness));
        }
    }
    return best;
}

pub enum VariationMethod {
    Crossover,
    Mutation,
    Reproduction,
}

/// Mates two individual, producing two children.
pub trait OpCrossover<I: Individual> {
    fn crossover(&mut self, parent1: &I, parent2: &I) -> (I, I);
}

/// Mutates an individual.
pub trait OpMutate<I: Individual> {
    fn mutate(&mut self, ind: &I) -> I;
}

/// Selects a variation method to use.
pub trait OpVariation {
    fn variation(&mut self) -> VariationMethod;
}

/// Selects a random individual from the population.
pub trait OpSelectRandomIndividual<I: Individual, F: Fitness> {
    fn select_random_individual<'a>(&mut self,
                                    population: &'a Population<I, F>)
                                    -> &'a EvaluatedIndividual<I, F>;
}

/// Produce new generation through selection of \mu individuals from population.
pub trait OpSelect<I: Individual, F: Fitness> {
    fn select(&mut self, population: &Population<I, F>, mu: usize) -> Population<I, F>;
}

pub fn variation_or<I, F, T>(toolbox: &mut T,
                             population: &Population<I, F>,
                             lambda: usize)
                             -> Population<I, F>
    where I: Individual,
          F: Fitness,
          T: OpCrossover<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I, F>
{
    let mut offspring = Population::with_capacity(lambda);
    // Each step produces exactly one child.
    for _ in 0..lambda {
        let method = toolbox.variation();
        let child = match method {
            VariationMethod::Crossover => {
                // select two individuals and mate them.
                // only the first offspring is used, the second is thrown away.
                let parent1 = toolbox.select_random_individual(population);
                let parent2 = toolbox.select_random_individual(population);
                let (child1, _child2) = toolbox.crossover(&parent1.individual, &parent2.individual);
                EvaluatedIndividual::new(child1)
            }
            VariationMethod::Mutation => {
                // select a single individual and mutate it.
                let ind = toolbox.select_random_individual(population);
                let child = toolbox.mutate(&ind.individual);
                EvaluatedIndividual::new(child)
            }
            VariationMethod::Reproduction => {
                let ind = toolbox.select_random_individual(population);
                ind.clone()
            }
        };
        offspring.add(child);
    }
    return offspring;
}

// The (\mu + \lambda) algorithm.
// From `population`, \lambda offspring is produced, through either
// mutation, crossover or random reproduction.
// For the next generation, \mu individuals are selected from the \mu + \lambda
// (parents and offspring).
pub fn ea_mu_plus_lambda<I,F,T,E,S>(toolbox: &mut T, evaluator: &E, population: &Population<I,F>, mu: usize, lambda: usize, num_generations: usize, stat: S)
    -> Population<I,F>
where I: Individual,
      F: Fitness,
      T: OpCrossover<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I,F> + OpSelect<I,F>,
      E: Evaluator<I,F>+Sync,
      S: Fn(usize, &Population<I,F>)
{
    let mut nevals = 0;
    let mut p = population.clone();
    let mut pool = simple_parallel::Pool::new(8);

    nevals += p.evaluate_in_parallel(evaluator, &mut pool);
    stat(0, &p);

    for gen in 0..num_generations {
        // evaluate population. make sure that every individual has been rated.
        let mut offspring = variation_or(toolbox, &p, lambda);
        offspring.add_population(&p);
        nevals += offspring.evaluate_in_parallel(evaluator, &mut pool);
        // select from offspring the `best` individuals
        p = toolbox.select(&offspring, mu);
        stat(gen + 1, &p);
    }

    let _ = nevals;

    return p;
}
<|endoftext|>


<commit_before>#![deny(missing_debug_implementations)]

extern crate jansson_sys;
extern crate janus_plugin_sys as ffi;

pub use debug::LogLevel;
pub use debug::log;
pub use jansson::JanssonValue;
pub use ffi::JANUS_PLUGIN_API_VERSION as API_VERSION;
pub use ffi::janus_callbacks as PluginCallbacks;
pub use ffi::janus_plugin as Plugin;
pub use ffi::janus_plugin_result as PluginResultInfo;
pub use ffi::janus_plugin_result_type as PluginResultType;
pub use ffi::janus_plugin_session as PluginHandle;
use std::error::Error;
use std::ffi::CStr;
use std::os::raw::{c_char, c_int};

pub mod debug;
pub mod sdp;
pub mod session;
pub mod jansson;

/// Converts a Janus gateway result code to either success or a potential error.
pub fn get_result(error: i32) -> Result<(), Box<Error+Send+Sync>> {
    match error {
        0 => Ok(()),
        e => {
            let msg = unsafe { CStr::from_ptr(ffi::janus_get_api_error(e)).to_str()? };
            Err(From::from(format!("{} (code: {})", msg, e)))
        }
    }
}

/// Allocates a Janus plugin result. Should be destroyed with destroy_result.
pub fn create_result(type_: PluginResultType, text: *const c_char, content: &JanssonValue) -> Box<PluginResultInfo> {
    unsafe { Box::from_raw(ffi::janus_plugin_result_new(type_, text, content.ptr)) }
}

/// Destroys a Janus plugin result.
pub fn destroy_result(result: Box<PluginResultInfo>) {
    unsafe { ffi::janus_plugin_result_destroy(Box::into_raw(result)) }
}

#[derive(Debug)]
/// Represents metadata about this plugin which Janus can query at runtime.
pub struct PluginMetadata {
    pub version: c_int,
    pub version_str: *const c_char,
    pub description: *const c_char,
    pub name: *const c_char,
    pub author: *const c_char,
    pub package: *const c_char,
}

/// Helper macro to produce a Janus plugin instance. Should be called with
/// a PluginMetadata instance and a series of exported plugin event handlers.
#[macro_export]
macro_rules! build_plugin {
    ($md:expr, $($cb:ident),*) => {{
        extern fn get_api_compatibility() -> c_int { $crate::API_VERSION }
        extern fn get_version() -> c_int { $md.version }
        extern fn get_version_string() -> *const c_char { $md.version_str }
        extern fn get_description() -> *const c_char { $md.description }
        extern fn get_name() -> *const c_char { $md.name }
        extern fn get_author() -> *const c_char { $md.author }
        extern fn get_package() -> *const c_char { $md.package }
        $crate::Plugin {
            get_api_compatibility,
            get_version,
            get_version_string,
            get_description,
            get_name,
            get_author,
            get_package,
            $($cb,)*
        }
    }}
}

/// Macro to export a Janus plugin instance from this module.
#[macro_export]
macro_rules! export_plugin {
    ($pl:expr) => {
        /// Called by Janus to create an instance of this plugin, using the provided callbacks to dispatch events.
        #[no_mangle]
        pub extern "C" fn create() -> *const $crate::Plugin { $pl }
    }
}
<commit_msg>Expose RawJanssonValue<commit_after>#![deny(missing_debug_implementations)]

extern crate jansson_sys;
extern crate janus_plugin_sys as ffi;

pub use debug::LogLevel;
pub use debug::log;
pub use jansson::{JanssonValue, RawJanssonValue};
pub use ffi::JANUS_PLUGIN_API_VERSION as API_VERSION;
pub use ffi::janus_callbacks as PluginCallbacks;
pub use ffi::janus_plugin as Plugin;
pub use ffi::janus_plugin_result as PluginResultInfo;
pub use ffi::janus_plugin_result_type as PluginResultType;
pub use ffi::janus_plugin_session as PluginHandle;
use std::error::Error;
use std::ffi::CStr;
use std::os::raw::{c_char, c_int};

pub mod debug;
pub mod sdp;
pub mod session;
pub mod jansson;

/// Converts a Janus gateway result code to either success or a potential error.
pub fn get_result(error: i32) -> Result<(), Box<Error+Send+Sync>> {
    match error {
        0 => Ok(()),
        e => {
            let msg = unsafe { CStr::from_ptr(ffi::janus_get_api_error(e)).to_str()? };
            Err(From::from(format!("{} (code: {})", msg, e)))
        }
    }
}

/// Allocates a Janus plugin result. Should be destroyed with destroy_result.
pub fn create_result(type_: PluginResultType, text: *const c_char, content: &JanssonValue) -> Box<PluginResultInfo> {
    unsafe { Box::from_raw(ffi::janus_plugin_result_new(type_, text, content.ptr)) }
}

/// Destroys a Janus plugin result.
pub fn destroy_result(result: Box<PluginResultInfo>) {
    unsafe { ffi::janus_plugin_result_destroy(Box::into_raw(result)) }
}

#[derive(Debug)]
/// Represents metadata about this plugin which Janus can query at runtime.
pub struct PluginMetadata {
    pub version: c_int,
    pub version_str: *const c_char,
    pub description: *const c_char,
    pub name: *const c_char,
    pub author: *const c_char,
    pub package: *const c_char,
}

/// Helper macro to produce a Janus plugin instance. Should be called with
/// a PluginMetadata instance and a series of exported plugin event handlers.
#[macro_export]
macro_rules! build_plugin {
    ($md:expr, $($cb:ident),*) => {{
        extern fn get_api_compatibility() -> c_int { $crate::API_VERSION }
        extern fn get_version() -> c_int { $md.version }
        extern fn get_version_string() -> *const c_char { $md.version_str }
        extern fn get_description() -> *const c_char { $md.description }
        extern fn get_name() -> *const c_char { $md.name }
        extern fn get_author() -> *const c_char { $md.author }
        extern fn get_package() -> *const c_char { $md.package }
        $crate::Plugin {
            get_api_compatibility,
            get_version,
            get_version_string,
            get_description,
            get_name,
            get_author,
            get_package,
            $($cb,)*
        }
    }}
}

/// Macro to export a Janus plugin instance from this module.
#[macro_export]
macro_rules! export_plugin {
    ($pl:expr) => {
        /// Called by Janus to create an instance of this plugin, using the provided callbacks to dispatch events.
        #[no_mangle]
        pub extern "C" fn create() -> *const $crate::Plugin { $pl }
    }
}
<|endoftext|>


<commit_before>//! A crate that re-exports various types defined in both `libc` and `winapi`.
//!
//! Stop having to write code like this:
//!
//! ```
//! #[cfg(unix)]
//! use libc::some_type;
//!
//! #[cfg(windows)]
//! use winapi::some_type;
//! ```
//!
//! Instead, write code like this:
//!
//! ```
//! use c_types::some_type;
//! ```
#![allow(non_camel_case_types)]

#[cfg(unix)]
mod unix {
  extern crate libc;

  pub type fd_set = libc::fd_set;

  #[repr(C)]
  #[derive(Debug)]
  #[allow(raw_pointer_derive)]
  pub struct hostent {
      pub h_name: *mut libc::c_char,
      pub h_aliases: *mut *mut libc::c_char,
      pub h_addrtype: libc::c_int,
      pub h_length: libc::c_int,
      pub h_addr_list: *mut *mut libc::c_char,
  }

  pub type in_addr = libc::in_addr;
  pub type in6_addr = libc::in6_addr;
  pub type sa_family_t = libc::sa_family_t;
  pub type sockaddr = libc::sockaddr;
  pub type sockaddr_in = libc::sockaddr_in;
  pub type sockaddr_in6 = libc::sockaddr_in6;

  pub const AF_INET: i32 = libc::AF_INET;
  pub const AF_INET6: i32 = libc::AF_INET6;
}

#[cfg(windows)]
mod windows {
  extern crate winapi;

  pub type fd_set = winapi::fd_set;
  pub type hostent = winapi::winsock2::hostent;
  pub type in_addr = winapi::in_addr;
  pub type in6_addr = winapi::in6_addr;
  pub type sa_family_t = winapi::ws2def::ADDRESS_FAMILY;
  pub type sockaddr = winapi::SOCKADDR;
  pub type sockaddr_in = winapi::ws2def::SOCKADDR_IN;
  pub type sockaddr_in6 = winapi::ws2ipdef::sockaddr_in6;

  pub const AF_INET: i32 = winapi::ws2def::AF_INET;
  pub const AF_INET6: i32 = winapi::ws2def::AF_INET6;
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;
<commit_msg>Add socklen_t<commit_after>//! A crate that re-exports various types defined in both `libc` and `winapi`.
//!
//! Stop having to write code like this:
//!
//! ```
//! #[cfg(unix)]
//! use libc::some_type;
//!
//! #[cfg(windows)]
//! use winapi::some_type;
//! ```
//!
//! Instead, write code like this:
//!
//! ```
//! use c_types::some_type;
//! ```
#![allow(non_camel_case_types)]

#[cfg(unix)]
mod unix {
  extern crate libc;

  pub type fd_set = libc::fd_set;

  #[repr(C)]
  #[derive(Debug)]
  #[allow(raw_pointer_derive)]
  pub struct hostent {
      pub h_name: *mut libc::c_char,
      pub h_aliases: *mut *mut libc::c_char,
      pub h_addrtype: libc::c_int,
      pub h_length: libc::c_int,
      pub h_addr_list: *mut *mut libc::c_char,
  }

  pub type in_addr = libc::in_addr;
  pub type in6_addr = libc::in6_addr;
  pub type sa_family_t = libc::sa_family_t;
  pub type sockaddr = libc::sockaddr;
  pub type sockaddr_in = libc::sockaddr_in;
  pub type sockaddr_in6 = libc::sockaddr_in6;
  pub type socklen_t = libc::socklen_t;

  pub const AF_INET: i32 = libc::AF_INET;
  pub const AF_INET6: i32 = libc::AF_INET6;
}

#[cfg(windows)]
mod windows {
  extern crate winapi;

  pub type fd_set = winapi::fd_set;
  pub type hostent = winapi::winsock2::hostent;
  pub type in_addr = winapi::in_addr;
  pub type in6_addr = winapi::in6_addr;
  pub type sa_family_t = winapi::ws2def::ADDRESS_FAMILY;
  pub type sockaddr = winapi::SOCKADDR;
  pub type sockaddr_in = winapi::ws2def::SOCKADDR_IN;
  pub type sockaddr_in6 = winapi::ws2ipdef::sockaddr_in6;
  pub type socklen_t = winapi::socklen_t;

  pub const AF_INET: i32 = winapi::ws2def::AF_INET;
  pub const AF_INET6: i32 = winapi::ws2def::AF_INET6;
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;
<|endoftext|>


<commit_before>//! Heatmap provides a time-series of Histograms, which is useful for
//! recording distributions over time and reporting percentiles over time
//!
//!
//! # Goals
//! * pre-allocated datastructure
//! * report time-series percentiles
//! * auto-slicing by record time
//!
//! # Future work
//! * make it work
//! * make it awesome
//! * add roll-up
//!
//! # Usage
//! Create a heatmap. Insert values over time. Profit.
//!
//! ```
//!
//! use heatmap::*;

#![crate_type = "lib"]

#![crate_name = "heatmap"]

extern crate histogram;
extern crate time;

use histogram::*;
use time::*;

#[derive(Clone, Copy)]
pub struct HeatmapConfig {
    precision: u32,
    max_memory: u32,
    max_value: u64,
    slice_duration: u64,
    num_slices: usize,
    start: u64,
}

impl HeatmapConfig {
    pub fn new() -> HeatmapConfig {
        HeatmapConfig {
            precision: 3,
            max_memory: 0,
            max_value: 1_000_000_000,
            slice_duration: 60_000_000_000,
            num_slices: 60,
            start: 0,
        }
    }

    pub fn precision(&mut self, precision: u32) -> &mut Self {
        self.precision = precision;
        self
    }

    pub fn max_memory(&mut self, bytes: u32) -> &mut Self {
        self.max_memory = bytes;
        self
    }

    pub fn max_value(&mut self, value: u64) -> &mut Self {
        self.max_value = value;
        self
    }

    pub fn slice_duration(&mut self, duration: u64) -> &mut Self {
        self.slice_duration = duration;
        self
    }

    pub fn num_slices(&mut self, count: usize) -> &mut Self {
        self.num_slices = count;
        self
    }

    pub fn start(&mut self, time: u64) -> &mut Self {
        self.start = time;
        self
    }
}

#[derive(Clone, Copy)]
pub struct HeatmapCounters {
    entries_total: u64,
}

impl HeatmapCounters {
    pub fn new() -> HeatmapCounters {
        HeatmapCounters { entries_total: 0 }
    }

    pub fn clear(&mut self) {
        self.entries_total = 0;
    }
}

#[derive(Clone)]
pub struct HeatmapData {
    data: Vec<Histogram>,
    counters: HeatmapCounters,
    iterator: usize,
    start: u64,
    stop: u64,
}

#[derive(Clone, Copy)]
pub struct HeatmapProperties;

#[derive(Clone)]
pub struct Heatmap {
    config: HeatmapConfig,
    data: HeatmapData,
    properties: HeatmapProperties,
}

#[derive(Clone)]
pub struct HeatmapSlice {
    pub start: u64,
    pub stop: u64,
    pub histogram: Histogram,
}

impl HeatmapSlice {
    pub fn start(self) -> u64 {
        self.start
    }

    pub fn stop(self) -> u64 {
        self.stop
    }

    pub fn histogram(self) -> Histogram {
        self.histogram
    }
}

impl Iterator for Heatmap {
    type Item = HeatmapSlice;

    fn next(&mut self) -> Option<HeatmapSlice> {
        let current = self.data.iterator;
        self.data.iterator += 1;

        if current == (self.config.num_slices as usize) {
            self.data.iterator = 0;
            None
        } else {
            let start = (self.data.iterator as u64 * self.config.slice_duration) + self.data.start;
            Some(HeatmapSlice {
                start: start,
                stop: start + self.config.slice_duration,
                histogram: self.data.data[current].clone(),
            })
        }
    }
}

impl Heatmap {

    /// create a new Heatmap with defaults
    ///
    /// # Example
    /// ```
    /// # use heatmap::Heatmap;
    ///
    /// let mut h = Heatmap::new().unwrap();
    pub fn new() -> Option<Heatmap> {
        Heatmap::configured(HeatmapConfig::new())
    }

    /// create a new Heatmap
    ///
    /// # Example
    /// ```
    /// # use heatmap::{Heatmap,HeatmapConfig};
    ///
    /// let mut c = HeatmapConfig::new();
    /// c.precision(4); // set precision to 4 digits
    /// c.max_value(1_000_000_000); // store values up to 1 Million
    /// c.slice_duration(1_000_000_000); // 1 second slices
    /// c.num_slices(300); // 300 slices => 5 minutes of records
    ///
    /// let mut h = Heatmap::configured(c).unwrap();
    pub fn configured(config: HeatmapConfig) -> Option<Heatmap> {

        let mut data = Vec::with_capacity(config.num_slices);

        unsafe {
            data.set_len(config.num_slices);
        }

        for i in 0..config.num_slices {
            let mut c = HistogramConfig::new();
            c.max_value(config.max_value);
            c.precision(config.precision);
            c.max_memory(config.max_memory / config.num_slices as u32);

            data[i] = Histogram::configured(c).unwrap();
        }

        let start = config.start;

        Some(Heatmap {
            config: config,
            data: HeatmapData {
                data: data,
                counters: HeatmapCounters::new(),
                iterator: 0,
                start: start,
                stop: start + config.slice_duration * config.num_slices as u64,
            },
            properties: HeatmapProperties,
        })
    }

    /// clear the heatmap data
    ///
    /// # Example
    /// ```
    /// # use heatmap::{Heatmap,HeatmapConfig};
    ///
    /// let mut h = Heatmap::new().unwrap();
    ///
    /// h.increment(1, 1);
    /// assert_eq!(h.entries(), 1);
    /// h.clear();
    /// assert_eq!(h.entries(), 0);
    pub fn clear(&mut self) -> Result<(), &'static str> {
        for i in 0..self.config.num_slices {
            match self.data.data[i].clear() {
                Ok(_) => {}
                Err(e) => {
                    return Err(e);
                }
            }
        }

        self.data.counters.clear();
        self.data.start = time::precise_time_ns();
        self.data.stop = self.data.start +
                         self.config.slice_duration * self.config.num_slices as u64;
        Ok(())
    }

    /// increment the count for a value at a time
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// h.increment(time::precise_time_ns(), 1);
    /// assert_eq!(h.entries(), 1);
    pub fn increment(&mut self, time: u64, value: u64) -> Result<(), &'static str> {
        self.record(time, value, 1_u64)
    }

    /// record additional counts for value at a time
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// h.record(time::precise_time_ns(), 1, 1);
    /// assert_eq!(h.entries(), 1);
    ///
    /// h.record(time::precise_time_ns(), 2, 2);
    /// assert_eq!(h.entries(), 3);
    ///
    /// h.record(time::precise_time_ns(), 10, 10);
    /// assert_eq!(h.entries(), 13);
    pub fn record(&mut self, time: u64, value: u64, count: u64) -> Result<(), &'static str> {
        self.data.counters.entries_total = self.data.counters.entries_total.saturating_add(count);

        match self.histogram_index(time) {
            Ok(histogram_index) => {
                self.data.data[histogram_index].record(value, count)
            }
            Err(e) => {
                Err(e)
            }
        }
    }

    pub fn get(&mut self, time: u64, value: u64) -> Result<u64, &'static str> {
        match self.histogram_index(time) {
            Ok(histogram_index) => {
                match self.data.data[histogram_index].get(value) {
                    Some(count) => {
                        Ok(count)
                    }
                    None => {
                        Err("histogram didn't have")
                    }
                }
            }
            Err(e) => {
                Err(e)
            }
        }
    }

    /// internal function to find the index of the histogram in the heatmap
    fn histogram_index(&mut self, time: u64) -> Result<usize, &'static str> {
        if time < self.data.start {
            return Err("sample too early");
        } else if time > self.data.stop {
            return Err("sample too late");
        }
        let index: usize = ((time - self.data.start) as f64 /
                            self.config.slice_duration as f64)
                               .floor() as usize;
        println!("index: time: {} is {}", time, index);
        Ok(index)
    }

    /// return the number of entries in the Histogram
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// assert_eq!(h.entries(), 0);
    /// h.record(time::precise_time_ns(), 1, 1);
    /// assert_eq!(h.entries(), 1);
    pub fn entries(&mut self) -> u64 {
        self.data.counters.entries_total
    }

    /// merge one Heatmap into another Heatmap
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut c = heatmap::HeatmapConfig::new();
    /// c.num_slices(61);
    ///
    /// let mut a = heatmap::Heatmap::configured(c).unwrap();
    ///
    /// let mut b = heatmap::Heatmap::new().unwrap();
    ///
    /// assert_eq!(a.entries(), 0);
    /// assert_eq!(b.entries(), 0);
    ///
    /// let _ = a.increment(1, 1);
    /// let _ = b.increment(1, 1);
    ///
    /// assert_eq!(a.entries(), 1);
    /// assert_eq!(b.entries(), 1);
    ///
    /// a.merge(&mut b);
    ///
    /// assert_eq!(a.entries(), 2);
    /// assert_eq!(a.get(1, 1).unwrap(), 1);
    /// assert_eq!(a.get(2, 1).unwrap(), 1);
    pub fn merge(&mut self, other: &mut Heatmap) {
        loop {
            match other.next() {
                Some(other_slice) => {
                    match self.histogram_index(other_slice.clone().start()) {
                        Ok(i) => {
                            self.data.data[i].merge(&mut other_slice.clone().histogram.clone());
                            self.data.counters.entries_total += other_slice.clone()
                                                                           .histogram
                                                                           .clone()
                                                                           .entries();
                        }
                        Err(e) => {}
                    }

                }
                None => {
                    break;
                }
            }
        }
    }
}
<commit_msg>more doc<commit_after>//! Heatmap provides a time-series of Histograms, which is useful for
//! recording distributions over time and reporting percentiles over time
//!
//!
//! # Goals
//! * pre-allocated datastructure
//! * report time-series percentiles
//! * auto-slicing by record time
//!
//! # Future work
//! * make it work
//! * make it awesome
//! * add roll-up
//!
//! # Usage
//! Create a heatmap. Insert values over time. Profit.
//!
//! ```
//!
//! use heatmap::*;

#![crate_type = "lib"]

#![crate_name = "heatmap"]

extern crate histogram;
extern crate time;

use histogram::*;
use time::*;

#[derive(Clone, Copy)]
pub struct HeatmapConfig {
    precision: u32,
    max_memory: u32,
    max_value: u64,
    slice_duration: u64,
    num_slices: usize,
    start: u64,
}

impl HeatmapConfig {
    /// create a new HeatmapConfig with the defaults
    ///
    /// # Defaults
    /// * precision => 3
    /// * max_memory => 0 (unlimited)
    /// * max_value => 1_000_000_000 (1 second in nanoseconds)
    /// * slice_duration => 60_000_000_000 (1 minute in nanoseconds)
    /// * num_slices => 60 (1 hour of heatmap)
    /// * start => 0 (start from time 0)
    pub fn new() -> HeatmapConfig {
        HeatmapConfig {
            precision: 3,
            max_memory: 0,
            max_value: 1_000_000_000,
            slice_duration: 60_000_000_000,
            num_slices: 60,
            start: 0,
        }
    }

    pub fn precision(&mut self, precision: u32) -> &mut Self {
        self.precision = precision;
        self
    }

    pub fn max_memory(&mut self, bytes: u32) -> &mut Self {
        self.max_memory = bytes;
        self
    }

    pub fn max_value(&mut self, value: u64) -> &mut Self {
        self.max_value = value;
        self
    }

    pub fn slice_duration(&mut self, duration: u64) -> &mut Self {
        self.slice_duration = duration;
        self
    }

    pub fn num_slices(&mut self, count: usize) -> &mut Self {
        self.num_slices = count;
        self
    }

    pub fn start(&mut self, time: u64) -> &mut Self {
        self.start = time;
        self
    }
}

#[derive(Clone, Copy)]
pub struct HeatmapCounters {
    entries_total: u64,
}

impl HeatmapCounters {
    pub fn new() -> HeatmapCounters {
        HeatmapCounters { entries_total: 0 }
    }

    pub fn clear(&mut self) {
        self.entries_total = 0;
    }
}

#[derive(Clone)]
pub struct HeatmapData {
    data: Vec<Histogram>,
    counters: HeatmapCounters,
    iterator: usize,
    start: u64,
    stop: u64,
}

#[derive(Clone, Copy)]
pub struct HeatmapProperties;

#[derive(Clone)]
pub struct Heatmap {
    config: HeatmapConfig,
    data: HeatmapData,
    properties: HeatmapProperties,
}

#[derive(Clone)]
pub struct HeatmapSlice {
    pub start: u64,
    pub stop: u64,
    pub histogram: Histogram,
}

impl HeatmapSlice {
    pub fn start(self) -> u64 {
        self.start
    }

    pub fn stop(self) -> u64 {
        self.stop
    }

    pub fn histogram(self) -> Histogram {
        self.histogram
    }
}

impl Iterator for Heatmap {
    type Item = HeatmapSlice;

    fn next(&mut self) -> Option<HeatmapSlice> {
        let current = self.data.iterator;
        self.data.iterator += 1;

        if current == (self.config.num_slices as usize) {
            self.data.iterator = 0;
            None
        } else {
            let start = (self.data.iterator as u64 * self.config.slice_duration) + self.data.start;
            Some(HeatmapSlice {
                start: start,
                stop: start + self.config.slice_duration,
                histogram: self.data.data[current].clone(),
            })
        }
    }
}

impl Heatmap {

    /// create a new Heatmap with defaults
    ///
    /// # Example
    /// ```
    /// # use heatmap::Heatmap;
    ///
    /// let mut h = Heatmap::new().unwrap();
    pub fn new() -> Option<Heatmap> {
        Heatmap::configured(HeatmapConfig::new())
    }

    /// create a new Heatmap
    ///
    /// # Example
    /// ```
    /// # use heatmap::{Heatmap,HeatmapConfig};
    ///
    /// let mut c = HeatmapConfig::new();
    /// c.precision(4); // set precision to 4 digits
    /// c.max_value(1_000_000_000); // store values up to 1 Million
    /// c.slice_duration(1_000_000_000); // 1 second slices
    /// c.num_slices(300); // 300 slices => 5 minutes of records
    ///
    /// let mut h = Heatmap::configured(c).unwrap();
    pub fn configured(config: HeatmapConfig) -> Option<Heatmap> {

        let mut data = Vec::with_capacity(config.num_slices);

        unsafe {
            data.set_len(config.num_slices);
        }

        for i in 0..config.num_slices {
            let mut c = HistogramConfig::new();
            c.max_value(config.max_value);
            c.precision(config.precision);
            c.max_memory(config.max_memory / config.num_slices as u32);

            data[i] = Histogram::configured(c).unwrap();
        }

        let start = config.start;

        Some(Heatmap {
            config: config,
            data: HeatmapData {
                data: data,
                counters: HeatmapCounters::new(),
                iterator: 0,
                start: start,
                stop: start + config.slice_duration * config.num_slices as u64,
            },
            properties: HeatmapProperties,
        })
    }

    /// clear the heatmap data
    ///
    /// # Example
    /// ```
    /// # use heatmap::{Heatmap,HeatmapConfig};
    ///
    /// let mut h = Heatmap::new().unwrap();
    ///
    /// h.increment(1, 1);
    /// assert_eq!(h.entries(), 1);
    /// h.clear();
    /// assert_eq!(h.entries(), 0);
    pub fn clear(&mut self) -> Result<(), &'static str> {
        for i in 0..self.config.num_slices {
            match self.data.data[i].clear() {
                Ok(_) => {}
                Err(e) => {
                    return Err(e);
                }
            }
        }

        self.data.counters.clear();
        self.data.start = time::precise_time_ns();
        self.data.stop = self.data.start +
                         self.config.slice_duration * self.config.num_slices as u64;
        Ok(())
    }

    /// increment the count for a value at a time
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// h.increment(time::precise_time_ns(), 1);
    /// assert_eq!(h.entries(), 1);
    pub fn increment(&mut self, time: u64, value: u64) -> Result<(), &'static str> {
        self.record(time, value, 1_u64)
    }

    /// record additional counts for value at a time
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// h.record(time::precise_time_ns(), 1, 1);
    /// assert_eq!(h.entries(), 1);
    ///
    /// h.record(time::precise_time_ns(), 2, 2);
    /// assert_eq!(h.entries(), 3);
    ///
    /// h.record(time::precise_time_ns(), 10, 10);
    /// assert_eq!(h.entries(), 13);
    pub fn record(&mut self, time: u64, value: u64, count: u64) -> Result<(), &'static str> {
        self.data.counters.entries_total = self.data.counters.entries_total.saturating_add(count);

        match self.histogram_index(time) {
            Ok(histogram_index) => {
                self.data.data[histogram_index].record(value, count)
            }
            Err(e) => {
                Err(e)
            }
        }
    }

    pub fn get(&mut self, time: u64, value: u64) -> Result<u64, &'static str> {
        match self.histogram_index(time) {
            Ok(histogram_index) => {
                match self.data.data[histogram_index].get(value) {
                    Some(count) => {
                        Ok(count)
                    }
                    None => {
                        Err("histogram didn't have")
                    }
                }
            }
            Err(e) => {
                Err(e)
            }
        }
    }

    /// internal function to find the index of the histogram in the heatmap
    fn histogram_index(&mut self, time: u64) -> Result<usize, &'static str> {
        if time < self.data.start {
            return Err("sample too early");
        } else if time > self.data.stop {
            return Err("sample too late");
        }
        let index: usize = ((time - self.data.start) as f64 /
                            self.config.slice_duration as f64)
                               .floor() as usize;
        println!("index: time: {} is {}", time, index);
        Ok(index)
    }

    /// return the number of entries in the Histogram
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// assert_eq!(h.entries(), 0);
    /// h.record(time::precise_time_ns(), 1, 1);
    /// assert_eq!(h.entries(), 1);
    pub fn entries(&mut self) -> u64 {
        self.data.counters.entries_total
    }

    /// merge one Heatmap into another Heatmap
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut c = heatmap::HeatmapConfig::new();
    /// c.num_slices(61);
    ///
    /// let mut a = heatmap::Heatmap::configured(c).unwrap();
    ///
    /// let mut b = heatmap::Heatmap::new().unwrap();
    ///
    /// assert_eq!(a.entries(), 0);
    /// assert_eq!(b.entries(), 0);
    ///
    /// let _ = a.increment(1, 1);
    /// let _ = b.increment(1, 1);
    ///
    /// assert_eq!(a.entries(), 1);
    /// assert_eq!(b.entries(), 1);
    ///
    /// a.merge(&mut b);
    ///
    /// assert_eq!(a.entries(), 2);
    /// assert_eq!(a.get(1, 1).unwrap(), 1);
    /// assert_eq!(a.get(2, 1).unwrap(), 1);
    pub fn merge(&mut self, other: &mut Heatmap) {
        loop {
            match other.next() {
                Some(other_slice) => {
                    match self.histogram_index(other_slice.clone().start()) {
                        Ok(i) => {
                            self.data.data[i].merge(&mut other_slice.clone().histogram.clone());
                            self.data.counters.entries_total += other_slice.clone()
                                                                           .histogram
                                                                           .clone()
                                                                           .entries();
                        }
                        Err(e) => {}
                    }

                }
                None => {
                    break;
                }
            }
        }
    }
}
<|endoftext|>