<commit_before>//! `gimli` is a blazing fast library for consuming the
//! [DWARF debugging format](http://dwarfstd.org/).
//!
//! * [Example Usage](#example-usage)
//! * [API Structure](#api-structure)
//! * [Using with `FallibleIterator`](#using-with-fallibleiterator)
//! * [Cargo Features](#cargo-features)
//!
//! ## Example Usage
//!
//! Print out all of the functions in the debuggee program:
//!
//! ```rust,no_run
//! extern crate gimli;
//!
//! # fn example() -> Result<(), gimli::Error> {
//! # let debug_info_buf = [];
//! # let debug_abbrev_buf = [];
//! # let read_debug_info = || &debug_info_buf;
//! # let read_debug_abbrev = || &debug_abbrev_buf;
//! // Read the .debug_info and .debug_abbrev sections with whatever object
//! // loader you're using.
//! let endian = gimli::LittleEndian;
//! let debug_info = gimli::DebugInfo::new(read_debug_info(), endian);
//! let debug_abbrev = gimli::DebugAbbrev::new(read_debug_abbrev(), endian);
//!
//! // Iterate over all compilation units.
//! let mut iter = debug_info.units();
//! while let Some(unit) = try!(iter.next()) {
//!     // Parse the abbreviations for this compilation unit.
//!     let abbrevs = try!(unit.abbreviations(&debug_abbrev));
//!
//!     // Iterate over all of this compilation unit's entries.
//!     let mut entries = unit.entries(&abbrevs);
//!     while let Some((_, entry)) = try!(entries.next_dfs()) {
//!         // If we find an entry for a function, print it.
//!         if entry.tag() == gimli::DW_TAG_subprogram {
//!             println!("Found a function: {:?}", entry);
//!         }
//!     }
//! }
//! # unreachable!()
//! # }
//! ```
//!
//! Full example programs:
//!
//!   * [A `dwarfdump`
//!     clone](https://github.com/gimli-rs/gimli/blob/master/examples/dwarfdump.rs)
//!
//!   * [An `addr2line` clone](https://github.com/gimli-rs/addr2line)
//!
//!   * [`ddbug`](https://github.com/philipc/ddbug), a utility giving insight into
//!     code generation by making debugging information readable
//!
//!   * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the
//!     compilers used to create each compilation unit within a shared library or
//!     executable (via `DW_AT_producer`)
//!
//!   * [`dwarf-validate`](http://github.com/gimli-rs/gimli/blob/master/examples/dwarf-validate.rs),
//!     a program to validate the integrity of some DWARF and its references
//!     between sections and ocmpilation units.
//!
//! ## API Structure
//!
//! * Basic familiarity with DWARF is assumed.
//!
//! * Each section gets its own type. Consider these types the entry points to
//! the library:
//!
//!   * [`DebugAbbrev`](./struct.DebugAbbrev.html): The `.debug_abbrev` section.
//!
//!   * [`DebugAranges`](./struct.DebugAranges.html): The `.debug_aranges`
//!   section.
//!
//!   * [`DebugFrame`](./struct.DebugFrame.html): The `.debug_frame` section.
//!
//!   * [`DebugInfo`](./struct.DebugInfo.html): The `.debug_info` section.
//!
//!   * [`DebugLine`](./struct.DebugLine.html): The `.debug_line` section.
//!
//!   * [`DebugLoc`](./struct.DebugLoc.html): The `.debug_loc` section.
//!
//!   * [`DebugPubNames`](./struct.DebugPubNames.html): The `.debug_pubnames`
//!   section.
//!
//!   * [`DebugPubTypes`](./struct.DebugPubTypes.html): The `.debug_pubtypes`
//!   section.
//!
//!   * [`DebugRanges`](./struct.DebugRanges.html): The `.debug_ranges` section.
//!
//!   * [`DebugStr`](./struct.DebugStr.html): The `.debug_str` section.
//!
//!   * [`DebugTypes`](./struct.DebugTypes.html): The `.debug_types` section.
//!
//!   * [`EhFrame`](./struct.EhFrame.html): The `.eh_frame` section.
//!
//!   * [`EhFrameHdr`](./struct.EhFrameHdr.html): The `.eh_frame_hdr` section.
//!
//! * Each section type exposes methods for accessing the debugging data encoded
//! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html)
//! struct has the [`units`](./struct.DebugInfo.html#method.units) method for
//! iterating over the compilation units defined within it.
//!
//! * Offsets into a section are strongly typed: an offset into `.debug_info` is
//! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be
//! used to index into the [`DebugLine`](./struct.DebugLine.html) type because
//! `DebugLine` represents the `.debug_line` section. There are similar types
//! for offsets relative to a compilation unit rather than a section.
//!
//! ## Using with `FallibleIterator`
//!
//! The standard library's `Iterator` trait and related APIs do not play well
//! with iterators where the `next` operation is fallible. One can make the
//! `Iterator`'s associated `Item` type be a `Result<T, E>`, however the
//! provided methods cannot gracefully handle the case when an `Err` is
//! returned.
//!
//! This situation led to the
//! [`fallible-iterator`](https://crates.io/crates/fallible-iterator) crate's
//! existence. You can read more of the rationale for its existence in its
//! docs. The crate provides the helpers you have come to expect (eg `map`,
//! `filter`, etc) for iterators that can fail.
//!
//! `gimli`'s many lazy parsing iterators are a perfect match for the
//! `fallible-iterator` crate's `FallibleIterator` trait because parsing is not
//! done eagerly. Parse errors later in the input might only be discovered after
//! having iterated through many items.
//!
//! To use `gimli` iterators with `FallibleIterator`, import the crate and trait
//! into your code:
//!
//! ```
//! // Add the `fallible-iterator` crate. Don't forget to add it to your
//! // `Cargo.toml`, too!
//! extern crate fallible_iterator;
//! extern crate gimli;
//!
//! // Use the `FallibleIterator` trait so its methods are in scope!
//! use fallible_iterator::FallibleIterator;
//! use gimli::{DebugAranges, EndianBuf, LittleEndian};
//!
//! fn find_sum_of_address_range_lengths(aranges: DebugAranges<EndianBuf<LittleEndian>>)
//!     -> gimli::Result<u64>
//! {
//!     // `DebugAranges::items` returns a `FallibleIterator`!
//!     aranges.items()
//!         // `map` is provided by `FallibleIterator`!
//!         .map(|arange| arange.length())
//!         // `fold` is provided by `FallibleIterator`!
//!         .fold(0, |sum, len| sum + len)
//! }
//!
//! # fn main() {}
//! ```
//!
//! ## Cargo Features
//!
//! Cargo features that can be enabled with `gimli`:
//!
//! * `std`: Enabled by default. Use the `std` library. Disabling this feature
//! allows using `gimli` in embedded environments that do not have access to
//! `std`. Note that even when `std` is disabled, `gimli` still requires an
//! implementation of the `alloc` crate, and you must enable the `nightly`
//! feature.
//!
//! * `alloc`: Nightly only. Enables usage of the unstable, nightly-only
//! `#![feature(alloc)]` Rust feature that allows `gimli` to use boxes and
//! collection types in a `#[no_std]` environment.
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
// Allow clippy warnings when we aren't building with clippy.
#![allow(unknown_lints)]
// False positives with `fallible_iterator`.
#![allow(should_implement_trait)]
// Many false positives involving `continue`.
#![allow(never_loop)]
// False positives when block expressions are used inside an assertion.
#![allow(panic_params)]
#![no_std]
#![cfg_attr(feature = "alloc", feature(alloc))]

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

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;
#[cfg(not(feature = "std"))]
#[macro_use]
extern crate core as std;

extern crate arrayvec;
extern crate byteorder;
extern crate fallible_iterator;
extern crate stable_deref_trait;

#[cfg(feature = "std")]
mod imports {
    pub use std::borrow;
    pub use std::boxed;
    pub use std::collections::btree_map;
    pub use std::rc;
    pub use std::string;
    pub use std::sync::Arc;
    pub use std::vec;
}

#[cfg(not(feature = "std"))]
mod imports {
    pub use alloc::borrow;
    pub use alloc::boxed;
    pub use alloc::collections::btree_map;
    pub use alloc::rc;
    pub use alloc::string;
    pub use alloc::sync::Arc;
    pub use alloc::vec;
}

use imports::*;

pub use stable_deref_trait::{CloneStableDeref, StableDeref};

mod arch;
pub use arch::*;

mod constants;
pub use constants::*;

mod endianity;
pub use endianity::{BigEndian, Endianity, LittleEndian, NativeEndian, RunTimeEndian};

pub mod leb128;

pub mod read;
// For backwards compat.
pub use read::*;

#[cfg(test)]
mod test_util;
<commit_msg>Export the constants module<commit_after>//! `gimli` is a blazing fast library for consuming the
//! [DWARF debugging format](http://dwarfstd.org/).
//!
//! * [Example Usage](#example-usage)
//! * [API Structure](#api-structure)
//! * [Using with `FallibleIterator`](#using-with-fallibleiterator)
//! * [Cargo Features](#cargo-features)
//!
//! ## Example Usage
//!
//! Print out all of the functions in the debuggee program:
//!
//! ```rust,no_run
//! extern crate gimli;
//!
//! # fn example() -> Result<(), gimli::Error> {
//! # let debug_info_buf = [];
//! # let debug_abbrev_buf = [];
//! # let read_debug_info = || &debug_info_buf;
//! # let read_debug_abbrev = || &debug_abbrev_buf;
//! // Read the .debug_info and .debug_abbrev sections with whatever object
//! // loader you're using.
//! let endian = gimli::LittleEndian;
//! let debug_info = gimli::DebugInfo::new(read_debug_info(), endian);
//! let debug_abbrev = gimli::DebugAbbrev::new(read_debug_abbrev(), endian);
//!
//! // Iterate over all compilation units.
//! let mut iter = debug_info.units();
//! while let Some(unit) = try!(iter.next()) {
//!     // Parse the abbreviations for this compilation unit.
//!     let abbrevs = try!(unit.abbreviations(&debug_abbrev));
//!
//!     // Iterate over all of this compilation unit's entries.
//!     let mut entries = unit.entries(&abbrevs);
//!     while let Some((_, entry)) = try!(entries.next_dfs()) {
//!         // If we find an entry for a function, print it.
//!         if entry.tag() == gimli::DW_TAG_subprogram {
//!             println!("Found a function: {:?}", entry);
//!         }
//!     }
//! }
//! # unreachable!()
//! # }
//! ```
//!
//! Full example programs:
//!
//!   * [A `dwarfdump`
//!     clone](https://github.com/gimli-rs/gimli/blob/master/examples/dwarfdump.rs)
//!
//!   * [An `addr2line` clone](https://github.com/gimli-rs/addr2line)
//!
//!   * [`ddbug`](https://github.com/philipc/ddbug), a utility giving insight into
//!     code generation by making debugging information readable
//!
//!   * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the
//!     compilers used to create each compilation unit within a shared library or
//!     executable (via `DW_AT_producer`)
//!
//!   * [`dwarf-validate`](http://github.com/gimli-rs/gimli/blob/master/examples/dwarf-validate.rs),
//!     a program to validate the integrity of some DWARF and its references
//!     between sections and ocmpilation units.
//!
//! ## API Structure
//!
//! * Basic familiarity with DWARF is assumed.
//!
//! * Each section gets its own type. Consider these types the entry points to
//! the library:
//!
//!   * [`DebugAbbrev`](./struct.DebugAbbrev.html): The `.debug_abbrev` section.
//!
//!   * [`DebugAranges`](./struct.DebugAranges.html): The `.debug_aranges`
//!   section.
//!
//!   * [`DebugFrame`](./struct.DebugFrame.html): The `.debug_frame` section.
//!
//!   * [`DebugInfo`](./struct.DebugInfo.html): The `.debug_info` section.
//!
//!   * [`DebugLine`](./struct.DebugLine.html): The `.debug_line` section.
//!
//!   * [`DebugLoc`](./struct.DebugLoc.html): The `.debug_loc` section.
//!
//!   * [`DebugPubNames`](./struct.DebugPubNames.html): The `.debug_pubnames`
//!   section.
//!
//!   * [`DebugPubTypes`](./struct.DebugPubTypes.html): The `.debug_pubtypes`
//!   section.
//!
//!   * [`DebugRanges`](./struct.DebugRanges.html): The `.debug_ranges` section.
//!
//!   * [`DebugStr`](./struct.DebugStr.html): The `.debug_str` section.
//!
//!   * [`DebugTypes`](./struct.DebugTypes.html): The `.debug_types` section.
//!
//!   * [`EhFrame`](./struct.EhFrame.html): The `.eh_frame` section.
//!
//!   * [`EhFrameHdr`](./struct.EhFrameHdr.html): The `.eh_frame_hdr` section.
//!
//! * Each section type exposes methods for accessing the debugging data encoded
//! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html)
//! struct has the [`units`](./struct.DebugInfo.html#method.units) method for
//! iterating over the compilation units defined within it.
//!
//! * Offsets into a section are strongly typed: an offset into `.debug_info` is
//! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be
//! used to index into the [`DebugLine`](./struct.DebugLine.html) type because
//! `DebugLine` represents the `.debug_line` section. There are similar types
//! for offsets relative to a compilation unit rather than a section.
//!
//! ## Using with `FallibleIterator`
//!
//! The standard library's `Iterator` trait and related APIs do not play well
//! with iterators where the `next` operation is fallible. One can make the
//! `Iterator`'s associated `Item` type be a `Result<T, E>`, however the
//! provided methods cannot gracefully handle the case when an `Err` is
//! returned.
//!
//! This situation led to the
//! [`fallible-iterator`](https://crates.io/crates/fallible-iterator) crate's
//! existence. You can read more of the rationale for its existence in its
//! docs. The crate provides the helpers you have come to expect (eg `map`,
//! `filter`, etc) for iterators that can fail.
//!
//! `gimli`'s many lazy parsing iterators are a perfect match for the
//! `fallible-iterator` crate's `FallibleIterator` trait because parsing is not
//! done eagerly. Parse errors later in the input might only be discovered after
//! having iterated through many items.
//!
//! To use `gimli` iterators with `FallibleIterator`, import the crate and trait
//! into your code:
//!
//! ```
//! // Add the `fallible-iterator` crate. Don't forget to add it to your
//! // `Cargo.toml`, too!
//! extern crate fallible_iterator;
//! extern crate gimli;
//!
//! // Use the `FallibleIterator` trait so its methods are in scope!
//! use fallible_iterator::FallibleIterator;
//! use gimli::{DebugAranges, EndianBuf, LittleEndian};
//!
//! fn find_sum_of_address_range_lengths(aranges: DebugAranges<EndianBuf<LittleEndian>>)
//!     -> gimli::Result<u64>
//! {
//!     // `DebugAranges::items` returns a `FallibleIterator`!
//!     aranges.items()
//!         // `map` is provided by `FallibleIterator`!
//!         .map(|arange| arange.length())
//!         // `fold` is provided by `FallibleIterator`!
//!         .fold(0, |sum, len| sum + len)
//! }
//!
//! # fn main() {}
//! ```
//!
//! ## Cargo Features
//!
//! Cargo features that can be enabled with `gimli`:
//!
//! * `std`: Enabled by default. Use the `std` library. Disabling this feature
//! allows using `gimli` in embedded environments that do not have access to
//! `std`. Note that even when `std` is disabled, `gimli` still requires an
//! implementation of the `alloc` crate, and you must enable the `nightly`
//! feature.
//!
//! * `alloc`: Nightly only. Enables usage of the unstable, nightly-only
//! `#![feature(alloc)]` Rust feature that allows `gimli` to use boxes and
//! collection types in a `#[no_std]` environment.
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
// Allow clippy warnings when we aren't building with clippy.
#![allow(unknown_lints)]
// False positives with `fallible_iterator`.
#![allow(should_implement_trait)]
// Many false positives involving `continue`.
#![allow(never_loop)]
// False positives when block expressions are used inside an assertion.
#![allow(panic_params)]
#![no_std]
#![cfg_attr(feature = "alloc", feature(alloc))]

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

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;
#[cfg(not(feature = "std"))]
#[macro_use]
extern crate core as std;

extern crate arrayvec;
extern crate byteorder;
extern crate fallible_iterator;
extern crate stable_deref_trait;

#[cfg(feature = "std")]
mod imports {
    pub use std::borrow;
    pub use std::boxed;
    pub use std::collections::btree_map;
    pub use std::rc;
    pub use std::string;
    pub use std::sync::Arc;
    pub use std::vec;
}

#[cfg(not(feature = "std"))]
mod imports {
    pub use alloc::borrow;
    pub use alloc::boxed;
    pub use alloc::collections::btree_map;
    pub use alloc::rc;
    pub use alloc::string;
    pub use alloc::sync::Arc;
    pub use alloc::vec;
}

use imports::*;

pub use stable_deref_trait::{CloneStableDeref, StableDeref};

mod arch;
pub use arch::*;

pub mod constants;
// For backwards compat.
pub use constants::*;

mod endianity;
pub use endianity::{BigEndian, Endianity, LittleEndian, NativeEndian, RunTimeEndian};

pub mod leb128;

pub mod read;
// For backwards compat.
pub use read::*;

#[cfg(test)]
mod test_util;
<|endoftext|>


<commit_before>//! Rust friendly bindings to the various *nix system functions.
//!
//! Modules are structured according to the C header file that they would be
//! defined in.
#![crate_name = "nix"]
#![allow(non_camel_case_types)]

#[macro_use]
extern crate bitflags;

extern crate libc;

#[cfg(test)]
extern crate nix_test as nixtest;

// Re-export some libc constants
pub use libc::{c_int, c_void};

#[cfg(unix)]
pub mod errno;

#[cfg(unix)]
pub mod features;

#[cfg(unix)]
pub mod fcntl;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod mount;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod sched;

#[cfg(unix)]
pub mod sys;

#[cfg(unix)]
pub mod unistd;

/*
 *
 * ===== Result / Error =====
 *
 */

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

pub type Result<T> = result::Result<T, Error>;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Error {
    Sys(errno::Errno),
    InvalidPath,
}

impl Error {
    pub fn last() -> Error {
        Error::Sys(errno::Errno::last())
    }

    pub fn invalid_argument() -> Error {
        Error::Sys(errno::EINVAL)
    }

    pub fn errno(&self) -> errno::Errno {
        match *self {
            Error::Sys(errno) => errno,
            Error::InvalidPath => errno::Errno::EINVAL,
        }
    }
}

pub trait NixPath {
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&OsStr) -> T;
}

impl NixPath for [u8] {
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&OsStr) -> T {
        // TODO: Extract this size as a const
        let mut buf = [0u8; 4096];

        if self.len() >= 4096 {
            return Err(Error::InvalidPath);
        }

        match self.iter().position(|b| *b == 0) {
            Some(_) => Err(Error::InvalidPath),
            None => {
                unsafe {
                    // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
                    ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
                }

                Ok(f(<OsStr as OsStrExt>::from_bytes(&buf[..self.len()])))
            }
        }
    }
}

impl NixPath for Path {
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&OsStr) -> T {
        Ok(f(self.as_os_str()))
    }
}

impl NixPath for PathBuf {
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&OsStr) -> T {
        Ok(f(self.as_os_str()))
    }
}

#[inline]
pub fn from_ffi(res: libc::c_int) -> Result<()> {
    if res != 0 {
        return Err(Error::Sys(errno::Errno::last()));
    }

    Ok(())
}

/*
 *
 * ===== Impl utilities =====
 *
 */

use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;

/// Converts a value to an external (FFI) string representation
trait AsExtStr {
    fn as_ext_str(&self) -> *const libc::c_char;
}

impl AsExtStr for OsStr {
    fn as_ext_str(&self) -> *const libc::c_char {
        self.as_bytes().as_ptr() as *const libc::c_char
    }
}
<commit_msg>Add Error::from_errno<commit_after>//! Rust friendly bindings to the various *nix system functions.
//!
//! Modules are structured according to the C header file that they would be
//! defined in.
#![crate_name = "nix"]
#![allow(non_camel_case_types)]

#[macro_use]
extern crate bitflags;

extern crate libc;

#[cfg(test)]
extern crate nix_test as nixtest;

// Re-export some libc constants
pub use libc::{c_int, c_void};

#[cfg(unix)]
pub mod errno;

#[cfg(unix)]
pub mod features;

#[cfg(unix)]
pub mod fcntl;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod mount;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod sched;

#[cfg(unix)]
pub mod sys;

#[cfg(unix)]
pub mod unistd;

/*
 *
 * ===== Result / Error =====
 *
 */

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

pub type Result<T> = result::Result<T, Error>;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Error {
    Sys(errno::Errno),
    InvalidPath,
}

impl Error {
    pub fn from_errno(errno: errno::Errno) -> Error {
        Error::Sys(errno)
    }

    pub fn last() -> Error {
        Error::Sys(errno::Errno::last())
    }

    pub fn invalid_argument() -> Error {
        Error::Sys(errno::EINVAL)
    }

    pub fn errno(&self) -> errno::Errno {
        match *self {
            Error::Sys(errno) => errno,
            Error::InvalidPath => errno::Errno::EINVAL,
        }
    }
}

pub trait NixPath {
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&OsStr) -> T;
}

impl NixPath for [u8] {
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&OsStr) -> T {
        // TODO: Extract this size as a const
        let mut buf = [0u8; 4096];

        if self.len() >= 4096 {
            return Err(Error::InvalidPath);
        }

        match self.iter().position(|b| *b == 0) {
            Some(_) => Err(Error::InvalidPath),
            None => {
                unsafe {
                    // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
                    ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
                }

                Ok(f(<OsStr as OsStrExt>::from_bytes(&buf[..self.len()])))
            }
        }
    }
}

impl NixPath for Path {
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&OsStr) -> T {
        Ok(f(self.as_os_str()))
    }
}

impl NixPath for PathBuf {
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&OsStr) -> T {
        Ok(f(self.as_os_str()))
    }
}

#[inline]
pub fn from_ffi(res: libc::c_int) -> Result<()> {
    if res != 0 {
        return Err(Error::Sys(errno::Errno::last()));
    }

    Ok(())
}

/*
 *
 * ===== Impl utilities =====
 *
 */

use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;

/// Converts a value to an external (FFI) string representation
trait AsExtStr {
    fn as_ext_str(&self) -> *const libc::c_char;
}

impl AsExtStr for OsStr {
    fn as_ext_str(&self) -> *const libc::c_char {
        self.as_bytes().as_ptr() as *const libc::c_char
    }
}
<|endoftext|>


<commit_before>use std::cmp;

// 2 billion junctions is good enough for now
pub type JunctionIndex = usize;
pub type Time = i64;
pub type Level = bool;

#[derive (Clone, Copy)]
pub enum GateBehavior {
	And,
	Not,
	Or,
	Xor,
}

// In the future, at time "time", junction "junction" will be set to level "level".
#[derive (Clone, Copy)]
pub struct Signal {
	junction: JunctionIndex,
	level: Level,
	time: Time,
}

#[derive (Clone, Copy)]
pub struct Wire {
	input: JunctionIndex,
	output: JunctionIndex,
	delay: Time,
}

#[derive (Clone)]
pub struct Gate {
	inputs: Vec <JunctionIndex>,
	output: JunctionIndex,
	behavior: GateBehavior,
}

#[derive (Clone)]
pub struct Circuit {
	wires: Vec <Wire>,
	gates: Vec <Gate>,
}

pub struct World {
	// These don't change at runtime
	circuit: Circuit,

	junctions: Vec <Level>,
	time: Time,
	signals: Vec <Signal>,
}

pub enum WorldCreationErr {
	// Two elements point to the same junction, this is illegal
	FanIn,
}

impl Wire {
	fn new (input: JunctionIndex, output: JunctionIndex, delay: Time) -> Wire {
		Wire {
			input: input,
			output: output,
			delay: delay,
		}
	}

	fn offset_junctions (&self, offset: JunctionIndex) -> Wire {
		Wire {
			input: self.input + offset,
			output: self.output + offset,
			delay: self.delay,
		}
	}
}

impl Gate {
	fn offset_junctions (&self, offset: JunctionIndex) -> Gate {
		Gate {
			inputs: self.inputs.iter ().map (|junction| junction + offset).collect (),
			output: self.output + offset,
			behavior: self.behavior,
		}
	}
}

impl Circuit {
	fn new_half_adder () -> Circuit {
		Circuit {
			wires: Circuit::wires_from_tuples (vec![
				(0, 1, 4),
				(0, 5, 8),
				(2, 3, 4),
				(6, 7, 3),
				(8, 4, 8),
				(8, 9, 4),
			]),
			gates: vec![
				Gate {
					inputs: vec![1, 4],
					output: 2,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![5, 9],
					output: 6,
					behavior: GateBehavior::Xor,
				},
			]
		}
	}

	fn new_full_adder () -> Circuit {
		Circuit {
			wires: Circuit::wires_from_tuples (vec![
				(0, 3, 1),
				(0, 5, 1),
				(1, 4, 1),
				(1, 6, 1),
				(2, 11, 1),
				(2, 9, 1),
				(7, 10, 1),
				(7, 8, 1),
				(12, 14, 1),
				(13, 15, 1),
			]),
			gates: vec![
				Gate {
					inputs: vec![3, 4],
					output: 7,
					behavior: GateBehavior::Xor,
				},
				Gate {
					inputs: vec![10, 11],
					output: 16,
					behavior: GateBehavior::Xor,
				},
				Gate {
					inputs: vec![8, 9],
					output: 12,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![5, 6],
					output: 13,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![14, 15],
					output: 17,
					behavior: GateBehavior::Or,
				},
			]
		}
	}

	fn wires_from_tuples (wire_tuples: Vec <(JunctionIndex, JunctionIndex, Time)>) -> Vec <Wire> {
		wire_tuples.iter ().map (|tuple| Wire::new (tuple.0, tuple.1, tuple.2)).collect ()
	}

	fn offset_junctions (&self, offset: JunctionIndex) -> Circuit {
		Circuit {
			wires: self.wires.iter ().map (|wire| wire.offset_junctions (offset)).collect (),
			gates: self.gates.iter ().map (|gate| gate.offset_junctions (offset)).collect (),
		}
	}

	fn max_junction (&self) -> JunctionIndex {
		let max_junction_wires = self.wires.iter ().fold (0, |max, wire| cmp::max (max, cmp::max (wire.input, wire.output)));
		let max_junction_gates = self.gates.iter ().fold (0, |max, gate| {
			let max_input = gate.inputs.iter ().max ();

			let max_junction_gate = match max_input {
				Option::Some (junction) => cmp::max (*junction, gate.output),
				Option::None => gate.output,
			};

			cmp::max (max, max_junction_gate)
		});

		cmp::max (max_junction_gates, max_junction_wires)
	}

	fn junction_count (&self) -> JunctionIndex {
		self.max_junction () + 1
	}

	fn has_fan_in (&self) -> bool {
		let mut junction_has_input = vec! [false; self.junction_count ()];

		for wire in self.wires.iter () {
			if junction_has_input [wire.output] {
				return true;
			}

			junction_has_input [wire.output] = true;
		}

		for gate in self.gates.iter () {
			if junction_has_input [gate.output] {
				return true;
			}

			junction_has_input [gate.output] = true;
		}

		false
	}
}

impl World {
	pub fn new_from_circuit (circuit: Circuit) -> Result <World, WorldCreationErr> {
		if circuit.has_fan_in () {
			return Err (WorldCreationErr::FanIn);
		}

		Ok (World {
			time: 0,
			signals: vec![],
			junctions: vec![false; circuit.junction_count ()],
			circuit: circuit,
		})
	}

	pub fn new (wires: Vec <Wire>, gates: Vec <Gate>) -> Result <World, WorldCreationErr> {
		World::new_from_circuit (Circuit {
			wires: wires,
			gates: gates,
		})
	}

	pub fn new_half_adder () -> World {
		World::new_from_circuit (Circuit::new_half_adder ()).ok ().expect ("Half adder circuit is invalid")
	}

	pub fn new_full_adder () -> World {
		World::new_from_circuit (Circuit::new_full_adder ()).ok ().expect ("Full adder circuit is invalid")
	}

	pub fn is_settled (& self) -> bool {
		self.signals.len () == 0
	}

	fn sort_signals (&mut self) {
		// This step is just a safety since we should be insertion sorting the delays already
		self.signals.sort_by (|a, b| a.time.cmp (&b.time));
	}

	fn step_gates (&mut self) {
		let mut new_signals = Vec::<Signal>::new ();

		// TODO: Optimize to only touch gates whose inputs have changed
		for gate in self.circuit.gates.iter () {
			let inputs: Vec <bool> = gate.inputs.iter ().map (|i| self.junctions [*i]).collect ();

			let output = match gate.behavior {
				GateBehavior::And => inputs.iter ().fold (true, |sum, a| sum && *a),
				GateBehavior::Not => ! inputs [0],
				GateBehavior::Or => inputs.iter ().fold (false, |sum, a| sum || *a),
				GateBehavior::Xor => inputs.iter ().fold (false, |sum, a| sum ^ *a),
			};

			let destiny_level = self.get_junction_destiny (gate.output);

			if destiny_level != output {
				new_signals.push (Signal {
					junction: gate.output,
					time: self.time,
					level: output,
				});
			}
		};

		// TODO: Proper insertion sorting
		// If the number of new signals is small compared to the number of
		// in-flight signals, I could do a few binary insertions sorts.
		// If the number is large, it might be better to do a mergesort.
		for signal in new_signals {
			self.signals.push (signal);
		}

		self.sort_signals ();
	}

	fn get_junction_destiny (& self, junction: JunctionIndex) -> Level {
		if self.signals.len () > 0 {
			// Find the last signal that was heading for that junction
			// Remember that junctions are not allowed to fan in
			for i in 0 .. self.signals.len () {
				let signals = self.signals [self.signals.len () - i - 1];

				if signals.junction == junction {
					return signals.level;
				}
			}
		}

		self.junctions [junction]
	}

	fn step_wires (&mut self) {
		for wire in self.circuit.wires.iter () {
			let input = self.junctions [wire.input];

			// Don't push redundant delays
			let destiny_level = self.get_junction_destiny (wire.output);

			if input != destiny_level {
				self.signals.push (Signal {
					junction: wire.output,
					time: self.time + wire.delay,
					level: input,
				});
			}
		};

		// TODO: Proper insertion sorting
		self.sort_signals ();
	}

	fn propagate_signals (&mut self) {
		let next_time = self.signals [0].time;

		for signal in self.signals.iter () {
			if signal.time == next_time {
				self.junctions [signal.junction] = signal.level;
			}
			else if signal.time > next_time {
				break;
			}
		}

		self.signals.retain (|signal| signal.time > next_time);

		self.time = next_time;
	}

	pub fn set_junction (&mut self, junction: JunctionIndex, level: Level) {
		self.signals.push (Signal {
			junction: junction,
			level: level,
			time: self.time,
		});
	}

	pub fn step (&mut self) {
		if self.is_settled () {
			return;
		}

		self.sort_signals ();

		self.propagate_signals ();

		self.step_gates ();
		self.step_wires ();
	}

	pub fn step_to_settled (&mut self) {
		while ! self.is_settled () {
			self.step ();
		}
	}
}

#[test]
pub fn test_fan_in () {
	let world_or_err = World::new (
		Circuit::wires_from_tuples (vec! [
		(0, 2, 1),
		(1, 2, 1),
		]),
		vec! []
	);

	if let Err (WorldCreationErr::FanIn) = world_or_err {
		// Good
	}
	else {
		panic! ("World creation should have thrown a FanIn error");
	}
}

#[test]
pub fn test_half_adder () {
	let mut world = World::new_half_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &World, msb: Level, lsb: Level| {
		assert_eq! (world.junctions [3], msb);
		assert_eq! (world.junctions [7], lsb);
	};

	assert_outputs (&world, false, false);

	// Junctions 0 and 8 are the input bits

	world.set_junction (0, true);
	world.step_to_settled ();
	assert_outputs (&world, false, true);

	world.set_junction (8, true);
	world.step_to_settled ();
	assert_outputs (&world, true, false);

	world.set_junction (0, false);
	world.step_to_settled ();
	assert_outputs (&world, false, true);
}

#[test]
pub fn test_full_adder () {
	let mut world = World::new_full_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &mut World, a: Level, b: Level, c: Level, carry: Level, sum: Level| {
		world.set_junction (0, a);
		world.set_junction (1, b);
		world.set_junction (2, c);

		world.step_to_settled ();

		assert_eq! (world.junctions [17], carry);
		assert_eq! (world.junctions [16], sum);
	};

	// Truth table for a full adder
	assert_outputs (&mut world, false, false, false, false, false);
	assert_outputs (&mut world, false, false, true, false, true);
	assert_outputs (&mut world, false, true, true, true, false);
	assert_outputs (&mut world, false, true, false, false, true);

	assert_outputs (&mut world, true, true, false, true, false);
	assert_outputs (&mut world, true, true, true, true, true);
	assert_outputs (&mut world, true, false, true, true, false);
	assert_outputs (&mut world, true, false, false, false, true);
}

#[test]
pub fn test_ripple_adder () {
	let adders = vec![Circuit::new_full_adder (); 8];
}<commit_msg>8-bit Ripple adder test passed<commit_after>use std::cmp;

// 2 billion junctions is good enough for now
pub type JunctionIndex = usize;
pub type Time = i64;
pub type Level = bool;

#[derive (Clone, Copy)]
pub enum GateBehavior {
	And,
	Not,
	Or,
	Xor,
}

// In the future, at time "time", junction "junction" will be set to level "level".
#[derive (Clone, Copy)]
pub struct Signal {
	junction: JunctionIndex,
	level: Level,
	time: Time,
}

#[derive (Clone, Copy)]
pub struct Wire {
	input: JunctionIndex,
	output: JunctionIndex,
	delay: Time,
}

#[derive (Clone)]
pub struct Gate {
	inputs: Vec <JunctionIndex>,
	output: JunctionIndex,
	behavior: GateBehavior,
}

#[derive (Clone)]
pub struct Circuit {
	wires: Vec <Wire>,
	gates: Vec <Gate>,
}

pub struct AssembledCircuit {
	circuit: Circuit,
	offsets: Vec <JunctionIndex>,
}

pub struct World {
	// These don't change at runtime
	circuit: Circuit,

	junctions: Vec <Level>,
	time: Time,
	signals: Vec <Signal>,
}

pub enum WorldCreationErr {
	// Two elements point to the same junction, this is illegal
	FanIn,
}

impl Wire {
	fn new (input: JunctionIndex, output: JunctionIndex, delay: Time) -> Wire {
		Wire {
			input: input,
			output: output,
			delay: delay,
		}
	}

	fn offset_junctions (&self, offset: JunctionIndex) -> Wire {
		Wire {
			input: self.input + offset,
			output: self.output + offset,
			delay: self.delay,
		}
	}
}

impl Gate {
	fn offset_junctions (&self, offset: JunctionIndex) -> Gate {
		Gate {
			inputs: self.inputs.iter ().map (|junction| junction + offset).collect (),
			output: self.output + offset,
			behavior: self.behavior,
		}
	}
}

impl Circuit {
	fn new_half_adder () -> Circuit {
		Circuit {
			wires: Circuit::wires_from_tuples (vec![
				(0, 1, 4),
				(0, 5, 8),
				(2, 3, 4),
				(6, 7, 3),
				(8, 4, 8),
				(8, 9, 4),
			]),
			gates: vec![
				Gate {
					inputs: vec![1, 4],
					output: 2,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![5, 9],
					output: 6,
					behavior: GateBehavior::Xor,
				},
			]
		}
	}

	fn new_full_adder () -> Circuit {
		Circuit {
			wires: Circuit::wires_from_tuples (vec![
				(0, 3, 1),
				(0, 5, 1),
				(1, 4, 1),
				(1, 6, 1),
				(2, 11, 1),
				(2, 9, 1),
				(7, 10, 1),
				(7, 8, 1),
				(12, 14, 1),
				(13, 15, 1),
			]),
			gates: vec![
				Gate {
					inputs: vec![3, 4],
					output: 7,
					behavior: GateBehavior::Xor,
				},
				Gate {
					inputs: vec![10, 11],
					output: 16,
					behavior: GateBehavior::Xor,
				},
				Gate {
					inputs: vec![8, 9],
					output: 12,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![5, 6],
					output: 13,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![14, 15],
					output: 17,
					behavior: GateBehavior::Or,
				},
			]
		}
	}

	fn wires_from_tuples (wire_tuples: Vec <(JunctionIndex, JunctionIndex, Time)>) -> Vec <Wire> {
		wire_tuples.iter ().map (|tuple| Wire::new (tuple.0, tuple.1, tuple.2)).collect ()
	}

	fn assemble (circuits: & Vec <Circuit>) -> AssembledCircuit {
		let mut offset = 0;

		let mut output = AssembledCircuit {
			circuit: Circuit {
				wires: vec![],
				gates: vec![],
			},
			offsets: vec![],
		};

		for circuit in circuits.iter () {
			let offset_circuit = circuit.offset_junctions (offset);

			for wire in offset_circuit.wires.iter () {
				output.circuit.wires.push (wire.clone ());
			}

			for gate in offset_circuit.gates.iter () {
				output.circuit.gates.push (gate.clone ());
			}

			output.offsets.push (offset);

			offset += circuit.junction_count ();
		}

		output
	}

	fn offset_junctions (&self, offset: JunctionIndex) -> Circuit {
		Circuit {
			wires: self.wires.iter ().map (|wire| wire.offset_junctions (offset)).collect (),
			gates: self.gates.iter ().map (|gate| gate.offset_junctions (offset)).collect (),
		}
	}

	fn max_junction (&self) -> JunctionIndex {
		let max_junction_wires = self.wires.iter ().fold (0, |max, wire| cmp::max (max, cmp::max (wire.input, wire.output)));
		let max_junction_gates = self.gates.iter ().fold (0, |max, gate| {
			let max_input = gate.inputs.iter ().max ();

			let max_junction_gate = match max_input {
				Option::Some (junction) => cmp::max (*junction, gate.output),
				Option::None => gate.output,
			};

			cmp::max (max, max_junction_gate)
		});

		cmp::max (max_junction_gates, max_junction_wires)
	}

	fn junction_count (&self) -> JunctionIndex {
		self.max_junction () + 1
	}

	fn has_fan_in (&self) -> bool {
		let mut junction_has_input = vec! [false; self.junction_count ()];

		for wire in self.wires.iter () {
			if junction_has_input [wire.output] {
				return true;
			}

			junction_has_input [wire.output] = true;
		}

		for gate in self.gates.iter () {
			if junction_has_input [gate.output] {
				return true;
			}

			junction_has_input [gate.output] = true;
		}

		false
	}
}

impl World {
	pub fn new_from_circuit (circuit: Circuit) -> Result <World, WorldCreationErr> {
		if circuit.has_fan_in () {
			return Err (WorldCreationErr::FanIn);
		}

		Ok (World {
			time: 0,
			signals: vec![],
			junctions: vec![false; circuit.junction_count ()],
			circuit: circuit,
		})
	}

	pub fn new (wires: Vec <Wire>, gates: Vec <Gate>) -> Result <World, WorldCreationErr> {
		World::new_from_circuit (Circuit {
			wires: wires,
			gates: gates,
		})
	}

	pub fn new_half_adder () -> World {
		World::new_from_circuit (Circuit::new_half_adder ()).ok ().expect ("Half adder circuit is invalid")
	}

	pub fn new_full_adder () -> World {
		World::new_from_circuit (Circuit::new_full_adder ()).ok ().expect ("Full adder circuit is invalid")
	}

	pub fn is_settled (& self) -> bool {
		self.signals.len () == 0
	}

	fn sort_signals (&mut self) {
		// This step is just a safety since we should be insertion sorting the delays already
		self.signals.sort_by (|a, b| a.time.cmp (&b.time));
	}

	fn step_gates (&mut self) {
		let mut new_signals = Vec::<Signal>::new ();

		// TODO: Optimize to only touch gates whose inputs have changed
		for gate in self.circuit.gates.iter () {
			let inputs: Vec <bool> = gate.inputs.iter ().map (|i| self.junctions [*i]).collect ();

			let output = match gate.behavior {
				GateBehavior::And => inputs.iter ().fold (true, |sum, a| sum && *a),
				GateBehavior::Not => ! inputs [0],
				GateBehavior::Or => inputs.iter ().fold (false, |sum, a| sum || *a),
				GateBehavior::Xor => inputs.iter ().fold (false, |sum, a| sum ^ *a),
			};

			let destiny_level = self.get_junction_destiny (gate.output);

			if destiny_level != output {
				new_signals.push (Signal {
					junction: gate.output,
					time: self.time,
					level: output,
				});
			}
		};

		// TODO: Proper insertion sorting
		// If the number of new signals is small compared to the number of
		// in-flight signals, I could do a few binary insertions sorts.
		// If the number is large, it might be better to do a mergesort.
		for signal in new_signals {
			self.signals.push (signal);
		}

		self.sort_signals ();
	}

	fn get_junction_destiny (& self, junction: JunctionIndex) -> Level {
		if self.signals.len () > 0 {
			// Find the last signal that was heading for that junction
			// Remember that junctions are not allowed to fan in
			for i in 0 .. self.signals.len () {
				let signals = self.signals [self.signals.len () - i - 1];

				if signals.junction == junction {
					return signals.level;
				}
			}
		}

		self.junctions [junction]
	}

	fn step_wires (&mut self) {
		for wire in self.circuit.wires.iter () {
			let input = self.junctions [wire.input];

			// Don't push redundant delays
			let destiny_level = self.get_junction_destiny (wire.output);

			if input != destiny_level {
				self.signals.push (Signal {
					junction: wire.output,
					time: self.time + wire.delay,
					level: input,
				});
			}
		};

		// TODO: Proper insertion sorting
		self.sort_signals ();
	}

	fn propagate_signals (&mut self) {
		let next_time = self.signals [0].time;

		for signal in self.signals.iter () {
			if signal.time == next_time {
				self.junctions [signal.junction] = signal.level;
			}
			else if signal.time > next_time {
				break;
			}
		}

		self.signals.retain (|signal| signal.time > next_time);

		self.time = next_time;
	}

	pub fn set_junction (&mut self, junction: JunctionIndex, level: Level) {
		self.signals.push (Signal {
			junction: junction,
			level: level,
			time: self.time,
		});
	}

	pub fn step (&mut self) {
		if self.is_settled () {
			return;
		}

		self.sort_signals ();

		self.propagate_signals ();

		self.step_gates ();
		self.step_wires ();
	}

	pub fn step_to_settled (&mut self) {
		while ! self.is_settled () {
			self.step ();
		}
	}
}

#[test]
pub fn test_fan_in () {
	let world_or_err = World::new (
		Circuit::wires_from_tuples (vec! [
		(0, 2, 1),
		(1, 2, 1),
		]),
		vec! []
	);

	if let Err (WorldCreationErr::FanIn) = world_or_err {
		// Good
	}
	else {
		panic! ("World creation should have thrown a FanIn error");
	}
}

#[test]
pub fn test_half_adder () {
	let mut world = World::new_half_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &World, msb: Level, lsb: Level| {
		assert_eq! (world.junctions [3], msb);
		assert_eq! (world.junctions [7], lsb);
	};

	assert_outputs (&world, false, false);

	// Junctions 0 and 8 are the input bits

	world.set_junction (0, true);
	world.step_to_settled ();
	assert_outputs (&world, false, true);

	world.set_junction (8, true);
	world.step_to_settled ();
	assert_outputs (&world, true, false);

	world.set_junction (0, false);
	world.step_to_settled ();
	assert_outputs (&world, false, true);
}

#[test]
pub fn test_full_adder () {
	let mut world = World::new_full_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &mut World, a: Level, b: Level, c: Level, carry: Level, sum: Level| {
		world.set_junction (0, a);
		world.set_junction (1, b);
		world.set_junction (2, c);

		world.step_to_settled ();

		assert_eq! (world.junctions [17], carry);
		assert_eq! (world.junctions [16], sum);
	};

	// Truth table for a full adder
	assert_outputs (&mut world, false, false, false, false, false);
	assert_outputs (&mut world, false, false, true, false, true);
	assert_outputs (&mut world, false, true, true, true, false);
	assert_outputs (&mut world, false, true, false, false, true);

	assert_outputs (&mut world, true, true, false, true, false);
	assert_outputs (&mut world, true, true, true, true, true);
	assert_outputs (&mut world, true, false, true, true, false);
	assert_outputs (&mut world, true, false, false, false, true);
}

#[test]
pub fn test_ripple_adder () {
	// Construct a little-endian 8-bit ripple adder
	let num_bits = 8;

	let adders = vec![Circuit::new_full_adder (); num_bits];

	let mut ripple_circuit = Circuit::assemble (&adders);

	// This only works because every block is identical and is a full adder
	let input_a: Vec <JunctionIndex> = ripple_circuit.offsets.iter ().map (|offset| offset + 0).collect ();
	let input_b: Vec <JunctionIndex> = ripple_circuit.offsets.iter ().map (|offset| offset + 1).collect ();

	for i in 0 .. num_bits - 1 {
		// Tie each adder's carry output to the next adder's carry input, except for the last one
		ripple_circuit.circuit.wires.push (Wire {
			input: ripple_circuit.offsets [i] + 17,
			output: ripple_circuit.offsets [i + 1] + 2,
			delay: 1,
		});
	}

	let output = {
		let mut output: Vec <JunctionIndex> = ripple_circuit.offsets.iter ().map (|offset| offset + 16).collect ();
		// We get an extra MSB because of the carry
		output.push (ripple_circuit.offsets [num_bits - 1] + 17);
		output
	};

	let mut world = World::new_from_circuit (ripple_circuit.circuit).ok ().expect ("Ripple adder circuit is invalid");
	world.step_to_settled ();

	// 93
	// LSB
	world.set_junction (input_a [0], true);
	world.set_junction (input_a [2], true);
	world.set_junction (input_a [3], true);
	world.set_junction (input_a [4], true);
	// MSB
	world.set_junction (input_a [6], true);

	// 19
	// LSB
	world.set_junction (input_b [0], true);
	world.set_junction (input_b [1], true);
	world.set_junction (input_b [4], true);

	world.step_to_settled ();

	// 19 + 93 = 112
	assert_eq! (world.junctions [output [0]], false);
	assert_eq! (world.junctions [output [1]], false);
	assert_eq! (world.junctions [output [2]], false);
	assert_eq! (world.junctions [output [3]], false);
	assert_eq! (world.junctions [output [4]], true);
	assert_eq! (world.junctions [output [5]], true);
	assert_eq! (world.junctions [output [6]], true);
	assert_eq! (world.junctions [output [7]], false);
	assert_eq! (world.junctions [output [8]], false);
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::borrow::Borrow;
use std::hash::{Hash,Hasher};

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Param {
    Short(char),
    Long(String),
}

impl Borrow<str> for Param {
    fn borrow(&self) -> &str {
        if let Param::Long(ref string) = *self {
            string
        } else {
            ""
        }
    }
}

impl Borrow<char> for Param {
    fn borrow(&self) -> &char {
        if let Param::Short(ref ch) = *self {
            ch
        } else {
            const CH: &'static char = &'\0';
            CH
        }
    }
}

impl Hash for Param {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match *self {
            Param::Short(ref c) => c.hash(state),
            Param::Long(ref s) => s.hash(state)
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
enum OptArg {
    With(String, bool),
    Empty,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
enum Value {
    Flag(bool),
    Opt(OptArg),
}

/// Our homebrewed Arg Parser
#[derive(Clone, Debug, Default)]
pub struct ArgParser {
    params: HashMap<Param, Value>,
    invalid: Vec<Param>,
    pub args: Vec<String>,
}

impl ArgParser {
    /// Create a new ArgParser object
    ///
    /// The capacity specifies the initial capacity of the number parameters.
    /// Always good to set it at the number of flags and opts total.
    pub fn new(capacity: usize) -> Self {
        ArgParser {
            params: HashMap::with_capacity(capacity),
            invalid: Vec::new(),
            args: Vec::new(),
        }
    }

    /// Builder method for adding both short and long flags
    ///
    /// Flags are just parameters that have no assigned values. They are used
    /// for when certain features or options have been enabled for the application
    ///
    /// For example
    /// > ls -l --human-readable
    ///   ^  ^  ^
    ///   |  |  |
    ///   |  |  `-- A long flag to enable human readable numbers.
    ///   |  `-- A short flag to enable the long format.
    ///   `-- The command to list files.
    pub fn add_flag(mut self, short: &str, long: &str) -> Self {
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::Flag(false));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::Flag(false));
        }
        self
    }

    /// Builder method for adding both short and long opts
    ///
    /// Opts are parameters that hold assigned values. They are used
    /// for when certain features or options have been enabled for the application
    ///
    /// For example
    /// > ls -T 4 --color=always
    ///   ^  ^    ^
    ///   |  |    |
    ///   |  |    `-- A long opt to enable the use of color with value `always`.
    ///   |  `-- A short opt to set tab size to the value `4`.
    ///   `-- The command to list files.
    pub fn add_opt(mut self, short: &str, long: &str) -> Self {
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::Opt(OptArg::Empty));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::Opt(OptArg::Empty));
        }
        self
    }

    pub fn add_opt_default(mut self, short: &str, long: &str, default: &str) -> Self {
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::Opt(OptArg::With(default.to_owned(), false)));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::Opt(OptArg::With(default.to_owned(), false)));
        }
        self
    }

    /// Start parsing user inputted args for which flags and opts are used at
    /// runtime. The rest of the args that are not associated to opts get added
    /// to `ArgParser.args`.
    pub fn initialize<A: Iterator<Item=String>>(&mut self, args: A) {
        let mut args = args.skip(1);
        while let Some(arg) = args.next() {
            if arg.starts_with("--") {
                // Remove both dashes
                let arg = &arg[2..];
                if arg.is_empty() {
                    //Arg `--` means we are done parsing args, collect the rest
                    self.args.extend(args);
                    break;
                }
                if let Some(i) = arg.find('=') {
                    let (lhs, rhs) = arg.split_at(i);
                    let rhs = &rhs[1..]; // slice off the `=` char
                    match self.params.get_mut(lhs) {
                        Some(&mut Value::Opt(ref mut value)) => {
                            match value {
                                &mut OptArg::With(ref mut value, ref mut occur) => {
                                    *value = rhs.to_owned();
                                    *occur = true;
                                }
                                &mut OptArg::Empty => *value = OptArg::With(rhs.to_owned(), true),
                            }
                        }
                        _ => self.invalid.push(Param::Long(lhs.to_owned())),
                    }
                }
                else {
                    match self.params.get_mut(arg) {
                        Some(&mut Value::Flag(ref mut switch)) => *switch = true,
                        Some(&mut Value::Opt(OptArg::With(_, ref mut occur))) => *occur = true,
                        _ => self.invalid.push(Param::Long(arg.to_owned())),
                    }
                }
            }
            else if arg.starts_with("-") {
                let mut chars = arg[1..].chars();
                while let Some(ch) = chars.next() {
                    match self.params.get_mut(&ch) {
                        Some(&mut Value::Flag(ref mut switch)) => *switch = true,
                        Some(&mut Value::Opt(ref mut value)) => {
                            let rest: String = chars.collect();
                            if !rest.is_empty() {
                                *value = OptArg::With(rest, true);
                            } else {
                                *value = args.next().map(|a| OptArg::With(a, true)).unwrap_or(OptArg::Empty);
                            }
                            break;
                        },
                        None => self.invalid.push(Param::Short(ch)),
                    }
                }
            }
            else {
                self.args.push(arg);
            }
        }
    }

    /// Check if a Flag or Opt has been found after initialization.
    pub fn flagged
(&self, name: &P) -> bool
        where Param: Borrow

    {
        match self.params.get(name) {
            Some(&Value::Flag(switch)) => switch,
            Some(&Value::Opt(OptArg::With(_, occur))) => occur,
            _ => false,
        }
    }

    /// Modify the state of a flag. Use `true` if the flag is to be enabled. Use `false` to
    /// disable its use.
    pub fn set_flag<F: Hash + Eq + ?Sized>(&mut self, flag: &F, state: bool)
        where Param: Borrow<F>
    {
        if let Some(&mut Value::Flag(ref mut switch)) = self.params.get_mut(flag) {
            *switch = state;
        }
    }

    /// Modify the state value of an opt. Use `Some(String)` to set if the opt is to be enabled and
    /// has been assigned a value from `String`. Use `None` to disable the opt's use.
    pub fn set_opt<O: Hash + Eq + ?Sized>(&mut self, opt: &O, state: Option<String>)
        where Param: Borrow<O>
    {
        if let Some(&mut Value::Opt(OptArg::With(ref mut value, ref mut occur))) = self.params.get_mut(opt) {
            match state {
                Some(input) => {
                    *value = input;
                    *occur = true;
                }
                None => *occur = false,
            }
        }
    }

    /// Get the value of an Opt. If it has been set or defaulted, it will return a `Some(String)`
    /// value otherwise it will return None.
    pub fn get_opt<O: Hash + Eq + ?Sized>(&self, opt: &O) -> Option<String>
        where Param: Borrow<O>
    {
        if let Some(&Value::Opt(OptArg::With(ref value, _))) = self.params.get(opt) {
            return Some(value.clone());
        }
        None
    }

    pub fn flagged_invalid(&self) -> Result<(), String> {
        if self.invalid.is_empty() {
            return Ok(());
        }

        let mut and: bool = false;
        let mut output =
            if self.invalid.len() == 1 {
                "Invalid parameter"
            } else {
                and = true;
                "Invalid parameters"
            }.to_owned();

        let mut iter = self.invalid.iter().peekable();
        while let Some(param) = iter.next() {
            match param {
                &Param::Short(ch) => {
                    output += " '-";
                    output.push(ch);
                    output.push('\'');
                }
                &Param::Long(ref s) => {
                    output += " '--";
                    output += s;
                    output.push('\'');
                }
            }
            if and && iter.peek().is_some() {
                output += " and";
            }
        }
        output.push('\n');
        Err(output)
    }
}

pub fn to_human_readable_string(size: u64) -> String {
    if size < 1024 {
        return format!("{}", size);
    }

    static UNITS: [&'static str; 7] = ["", "K", "M", "G", "T", "P", "E"];

    let sizef = size as f64;
    let digit_groups = (sizef.log10() / 1024f64.log10()) as i32;
    format!("{:.1}{}",
            sizef / 1024f64.powf(digit_groups as f64),
            UNITS[digit_groups as usize])
}

#[cfg(test)]
mod tests {
    use super::ArgParser;

    #[test]
    fn stop_parsing() {
        let args = vec![String::from("binname"), String::from("-a"), String::from("--"), String::from("-v")];
        let mut parser = ArgParser::new(2);
        parser = parser.add_flag("a", "")
                       .add_flag("v", "");
        parser.initialize(args.into_iter());
        assert!(parser.flagged(&'a'));
        assert!(!parser.flagged(&'v'));
        assert!(parser.args[0] == "-v");
    }

    #[test]
    fn short_opts() {
        let args = vec![String::from("binname"), String::from("-asdf"), String::from("-f"), String::from("foo")];
        let mut parser = ArgParser::new(4);
        parser = parser.add_flag("a", "")
                       .add_flag("d", "")
                       .add_opt("s", "")
                       .add_opt("f", "");
        parser.initialize(args.into_iter());
        assert!(parser.flagged(&'a'));
        assert!(!parser.flagged(&'d'));
        assert!(parser.get_opt(&'s') == Some(String::from("df")));
        assert!(parser.get_opt(&'f') == Some(String::from("foo")));
    }

    #[test]
    fn long_opts() {
        let args = vec![String::from("binname"), String::from("--foo=bar")];
        let mut parser = ArgParser::new(4);
        parser = parser.add_opt("", "foo");
        parser.initialize(args.into_iter());
        assert!(parser.get_opt("foo") == Some(String::from("bar")));
    }
}
<commit_msg>Add capability to keep track of multi flag/opt occurrences<commit_after>use std::collections::HashMap;
use std::borrow::Borrow;
use std::hash::{Hash,Hasher};

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Param {
    Short(char),
    Long(String),
}

impl Borrow<str> for Param {
    fn borrow(&self) -> &str {
        if let Param::Long(ref string) = *self {
            string
        } else {
            ""
        }
    }
}

impl Borrow<char> for Param {
    fn borrow(&self) -> &char {
        if let Param::Short(ref ch) = *self {
            ch
        } else {
            const CH: &'static char = &'\0';
            CH
        }
    }
}

impl Hash for Param {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match *self {
            Param::Short(ref c) => c.hash(state),
            Param::Long(ref s) => s.hash(state)
        }
    }
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
struct Rhs<T> {
    value: T,
    occurrences: usize,
}

impl<T> Rhs<T> {
    fn new<U: Into<T>>(value: U) -> Self {
        Rhs { value: value.into(), occurrences: 0 }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
enum OptRhs {
    With(Rhs<String>, bool),
    Empty,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
enum Value {
    Flag(Rhs<bool>),
    Opt(OptRhs),
}

/// Our homebrewed Arg Parser
#[derive(Clone, Debug, Default)]
pub struct ArgParser {
    params: HashMap<Param, Value>,
    invalid: Vec<Param>,
    pub args: Vec<String>,
}

impl ArgParser {
    /// Create a new ArgParser object
    ///
    /// The capacity specifies the initial capacity of the number parameters.
    /// Always good to set it at the number of flags and opts total.
    pub fn new(capacity: usize) -> Self {
        ArgParser {
            params: HashMap::with_capacity(capacity),
            invalid: Vec::new(),
            args: Vec::new(),
        }
    }

    /// Builder method for adding both short and long flags
    ///
    /// Flags are just parameters that have no assigned values. They are used
    /// for when certain features or options have been enabled for the application
    ///
    /// For example
    /// > ls -l --human-readable
    ///   ^  ^  ^
    ///   |  |  |
    ///   |  |  `-- A long flag to enable human readable numbers.
    ///   |  `-- A short flag to enable the long format.
    ///   `-- The command to list files.
    pub fn add_flag(mut self, short: &str, long: &str) -> Self {
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::Flag(Rhs::default()));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::Flag(Rhs::default()));
        }
        self
    }

    /// Builder method for adding both short and long opts
    ///
    /// Opts are parameters that hold assigned values. They are used
    /// for when certain features or options have been enabled for the application
    ///
    /// For example
    /// > ls -T 4 --color=always
    ///   ^  ^    ^
    ///   |  |    |
    ///   |  |    `-- A long opt to enable the use of color with value `always`.
    ///   |  `-- A short opt to set tab size to the value `4`.
    ///   `-- The command to list files.
    pub fn add_opt(mut self, short: &str, long: &str) -> Self {
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::Opt(OptRhs::Empty));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::Opt(OptRhs::Empty));
        }
        self
    }

    pub fn add_opt_default(mut self, short: &str, long: &str, default: &str) -> Self {
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::Opt(OptRhs::With(Rhs::new(default), false)));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::Opt(OptRhs::With(Rhs::new(default), false)));
        }
        self
    }

    /// Start parsing user inputted args for which flags and opts are used at
    /// runtime. The rest of the args that are not associated to opts get added
    /// to `ArgParser.args`.
    pub fn initialize<A: Iterator<Item=String>>(&mut self, args: A) {
        let mut args = args.skip(1);
        while let Some(arg) = args.next() {
            if arg.starts_with("--") {
                // Remove both dashes
                let arg = &arg[2..];
                if arg.is_empty() {
                    //Arg `--` means we are done parsing args, collect the rest
                    self.args.extend(args);
                    break;
                }
                if let Some(i) = arg.find('=') {
                    let (lhs, rhs) = arg.split_at(i);
                    let rhs = &rhs[1..]; // slice off the `=` char
                    match self.params.get_mut(lhs) {
                        Some(&mut Value::Opt(ref mut value)) => {
                            match value {
                                &mut OptRhs::With(ref mut opt_rhs, ref mut occur) => {
                                    opt_rhs.value.clear();
                                    opt_rhs.value.push_str(rhs);
                                    opt_rhs.occurrences += 1;
                                    *occur = true;
                                }
                                &mut OptRhs::Empty => {
                                    let mut rhs = Rhs::new(rhs);
                                    rhs.occurrences = 1;
                                    *value = OptRhs::With(rhs, true);
                                }
                            }
                        }
                        _ => self.invalid.push(Param::Long(lhs.to_owned())),
                    }
                }
                else {
                    match self.params.get_mut(arg) {
                        Some(&mut Value::Flag(ref mut rhs)) => {
                            rhs.value = true;
                            rhs.occurrences += 1;
                        }
                        Some(&mut Value::Opt(OptRhs::With(ref mut rhs, ref mut occur))) => {
                            rhs.occurrences += 1;
                            *occur = true;
                        }
                        _ => self.invalid.push(Param::Long(arg.to_owned())),
                    }
                }
            }
            else if arg.starts_with("-") {
                let mut chars = arg[1..].chars();
                while let Some(ch) = chars.next() {
                    match self.params.get_mut(&ch) {
                        Some(&mut Value::Flag(ref mut rhs)) => {
                            rhs.value = true;
                            rhs.occurrences += 1;
                        }
                        Some(&mut Value::Opt(OptRhs::With(ref mut rhs, ref mut occur))) => {
                            let rest: String = chars.collect();
                            if !rest.is_empty() {
                                rhs.value = rest;
                                *occur = true;
                            } else if let Some(arg) = args.next() {
                                rhs.value = arg;
                                *occur = true;
                            }
                            break;
                        },
                        _ => self.invalid.push(Param::Short(ch)),
                    }
                }
            }
            else {
                self.args.push(arg);
            }
        }
    }

    /// Check if a Flag or Opt has been found after initialization.
    pub fn flagged
(&self, name: &P) -> bool
        where Param: Borrow

    {
        match self.params.get(name) {
            Some(&Value::Flag(ref rhs)) => rhs.value,
            Some(&Value::Opt(OptRhs::With(_, occur))) => occur,
            _ => false,
        }
    }

    /// Modify the state of a flag. Use `true` if the flag is to be enabled. Use `false` to
    /// disable its use.
    pub fn set_flag<F: Hash + Eq + ?Sized>(&mut self, flag: &F, state: bool)
        where Param: Borrow<F>
    {
        if let Some(&mut Value::Flag(ref mut rhs)) = self.params.get_mut(flag) {
            rhs.value = state;
        }
    }

    /// Modify the state value of an opt. Use `Some(String)` to set if the opt is to be enabled and
    /// has been assigned a value from `String`. Use `None` to disable the opt's use.
    pub fn set_opt<O: Hash + Eq + ?Sized>(&mut self, opt: &O, state: Option<String>)
        where Param: Borrow<O>
    {
        if let Some(&mut Value::Opt(OptRhs::With(ref mut rhs, ref mut occur))) = self.params.get_mut(opt) {
            match state {
                Some(input) => {
                    rhs.value = input;
                    *occur = true;
                }
                None => *occur = false,
            }
        }
    }

    /// Get the value of an Opt. If it has been set or defaulted, it will return a `Some(String)`
    /// value otherwise it will return None.
    pub fn get_opt<O: Hash + Eq + ?Sized>(&self, opt: &O) -> Option<String>
        where Param: Borrow<O>
    {
        if let Some(&Value::Opt(OptRhs::With(ref rhs, _))) = self.params.get(opt) {
            return Some(rhs.value.clone());
        }
        None
    }

    pub fn flagged_invalid(&self) -> Result<(), String> {
        if self.invalid.is_empty() {
            return Ok(());
        }

        let mut and: bool = false;
        let mut output =
            if self.invalid.len() == 1 {
                "Invalid parameter"
            } else {
                and = true;
                "Invalid parameters"
            }.to_owned();

        let mut iter = self.invalid.iter().peekable();
        while let Some(param) = iter.next() {
            match param {
                &Param::Short(ch) => {
                    output += " '-";
                    output.push(ch);
                    output.push('\'');
                }
                &Param::Long(ref s) => {
                    output += " '--";
                    output += s;
                    output.push('\'');
                }
            }
            if and && iter.peek().is_some() {
                output += " and";
            }
        }
        output.push('\n');
        Err(output)
    }
}

pub fn to_human_readable_string(size: u64) -> String {
    if size < 1024 {
        return format!("{}", size);
    }

    static UNITS: [&'static str; 7] = ["", "K", "M", "G", "T", "P", "E"];

    let sizef = size as f64;
    let digit_groups = (sizef.log10() / 1024f64.log10()) as i32;
    format!("{:.1}{}",
            sizef / 1024f64.powf(digit_groups as f64),
            UNITS[digit_groups as usize])
}

#[cfg(test)]
mod tests {
    use super::ArgParser;

    #[test]
    fn stop_parsing() {
        let args = vec![String::from("binname"), String::from("-a"), String::from("--"), String::from("-v")];
        let mut parser = ArgParser::new(2);
        parser = parser.add_flag("a", "")
                       .add_flag("v", "");
        parser.initialize(args.into_iter());
        assert!(parser.flagged(&'a'));
        assert!(!parser.flagged(&'v'));
        assert!(parser.args[0] == "-v");
    }

    #[test]
    fn short_opts() {
        let args = vec![String::from("binname"), String::from("-asdf"), String::from("-f"), String::from("foo")];
        let mut parser = ArgParser::new(4);
        parser = parser.add_flag("a", "")
                       .add_flag("d", "")
                       .add_opt("s", "")
                       .add_opt("f", "");
        parser.initialize(args.into_iter());
        assert!(parser.flagged(&'a'));
        assert!(!parser.flagged(&'d'));
        assert!(parser.get_opt(&'s') == Some(String::from("df")));
        assert!(parser.get_opt(&'f') == Some(String::from("foo")));
    }

    #[test]
    fn long_opts() {
        let args = vec![String::from("binname"), String::from("--foo=bar")];
        let mut parser = ArgParser::new(4);
        parser = parser.add_opt("", "foo");
        parser.initialize(args.into_iter());
        assert!(parser.get_opt("foo") == Some(String::from("bar")));
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]
#![feature(ip_addr)]
#[allow(dead_code)]

use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

// A network
#[derive(Debug)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

pub struct Ipv4Network {
    addr: Ipv4Addr,
    prefix: u8,
}

pub struct Ipv6Network {
    addr: Ipv6Addr,
    prefix: u8,
}

impl Ipv4Network {
    pub fn new(addr: Ipv4Addr, prefix: u8) -> Ipv4Network {
        Ipv4Network {
            addr: addr,
            prefix: prefix,
        }
    }

    pub fn ip(&self) -> Ipv4Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }

    pub fn mask(&self) -> (Ipv4Addr, u32) {
        let prefix = self.prefix;
        let mask = !(0xffffffff >> prefix);
        (Ipv4Addr::from(mask), mask)
    }

    pub fn network(&self) -> (Ipv4Addr, u32) {
        let (_, mask) = self.mask();
        let ip = u32::from(self.addr) & mask;
        (Ipv4Addr::from(ip), ip)
    }

    pub fn broadcast(&self) -> (Ipv4Addr, u32) {
        let (_, network) = self.network();
        let (_, mask) = self.mask();
        let broadcast = network | !mask;
        (Ipv4Addr::from(broadcast), broadcast)
    }

    pub fn contains(&self, ip: Ipv4Addr) -> bool {
        let (_, net) = self.network();
        (u32::from(ip) & net) == net
    }
}

impl Ipv6Network {
    pub fn new(addr: Ipv6Addr, prefix: u8) -> Ipv6Network {
        Ipv6Network {
            addr: addr,
            prefix: prefix,
        }
    }

    pub fn ip(&self) -> Ipv6Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }
}

impl IpNetwork {
    pub fn new(ip: IpAddr, prefix: u8) -> IpNetwork {
        match ip {
            IpAddr::V4(a) => IpNetwork::V4(Ipv4Network::new(a, prefix)),
            IpAddr::V6(a) => IpNetwork::V6(Ipv6Network::new(a, prefix)),
        }
    }

    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }
}

impl fmt::Debug for Ipv4Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

impl fmt::Debug for Ipv6Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

#[cfg(test)]
mod test {
    use std::net::{Ipv4Addr, Ipv6Addr};
    use super::*;

    #[test]
    fn create_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(77, 88, 21, 11), 24);
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24);
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn mask_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 29);
        let (ip, int) = cidr.mask();
        assert_eq!(ip, Ipv4Addr::new(255, 255, 255, 248));
        assert_eq!(int, 4294967288);
    }

    #[test]
    fn network_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23);
        let (ip, int) = cidr.network();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 0, 0));
        assert_eq!(int, 168427520);
    }

    #[test]
    fn broadcast_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23);
        let (ip, int) = cidr.broadcast();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 1, 255));
        assert_eq!(int, 168428031);
    }

    #[test]
    fn contains_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 25);
        let ip = Ipv4Addr::new(74, 125, 227, 4);
        assert!(cidr.contains(ip));
    }
}
<commit_msg>Remove redundant feature<commit_after>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]
#[allow(dead_code)]

use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

// A network
#[derive(Debug)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

pub struct Ipv4Network {
    addr: Ipv4Addr,
    prefix: u8,
}

pub struct Ipv6Network {
    addr: Ipv6Addr,
    prefix: u8,
}

impl Ipv4Network {
    pub fn new(addr: Ipv4Addr, prefix: u8) -> Ipv4Network {
        Ipv4Network {
            addr: addr,
            prefix: prefix,
        }
    }

    pub fn ip(&self) -> Ipv4Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }

    pub fn mask(&self) -> (Ipv4Addr, u32) {
        let prefix = self.prefix;
        let mask = !(0xffffffff >> prefix);
        (Ipv4Addr::from(mask), mask)
    }

    pub fn network(&self) -> (Ipv4Addr, u32) {
        let (_, mask) = self.mask();
        let ip = u32::from(self.addr) & mask;
        (Ipv4Addr::from(ip), ip)
    }

    pub fn broadcast(&self) -> (Ipv4Addr, u32) {
        let (_, network) = self.network();
        let (_, mask) = self.mask();
        let broadcast = network | !mask;
        (Ipv4Addr::from(broadcast), broadcast)
    }

    pub fn contains(&self, ip: Ipv4Addr) -> bool {
        let (_, net) = self.network();
        (u32::from(ip) & net) == net
    }
}

impl Ipv6Network {
    pub fn new(addr: Ipv6Addr, prefix: u8) -> Ipv6Network {
        Ipv6Network {
            addr: addr,
            prefix: prefix,
        }
    }

    pub fn ip(&self) -> Ipv6Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }
}

impl IpNetwork {
    pub fn new(ip: IpAddr, prefix: u8) -> IpNetwork {
        match ip {
            IpAddr::V4(a) => IpNetwork::V4(Ipv4Network::new(a, prefix)),
            IpAddr::V6(a) => IpNetwork::V6(Ipv6Network::new(a, prefix)),
        }
    }

    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }
}

impl fmt::Debug for Ipv4Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

impl fmt::Debug for Ipv6Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

#[cfg(test)]
mod test {
    use std::net::{Ipv4Addr, Ipv6Addr};
    use super::*;

    #[test]
    fn create_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(77, 88, 21, 11), 24);
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24);
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn mask_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 29);
        let (ip, int) = cidr.mask();
        assert_eq!(ip, Ipv4Addr::new(255, 255, 255, 248));
        assert_eq!(int, 4294967288);
    }

    #[test]
    fn network_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23);
        let (ip, int) = cidr.network();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 0, 0));
        assert_eq!(int, 168427520);
    }

    #[test]
    fn broadcast_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23);
        let (ip, int) = cidr.broadcast();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 1, 255));
        assert_eq!(int, 168428031);
    }

    #[test]
    fn contains_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 25);
        let ip = Ipv4Addr::new(74, 125, 227, 4);
        assert!(cidr.contains(ip));
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate url;

use libc::gethostname;
use serde_json::Value;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::net::TcpStream;
use std::sync::Mutex;
use std::io;

lazy_static!
{
    pub static ref EMITTER: Mutex<Emitter<'static>> = Mutex::new(Emitter::empty());
}

pub fn emitter() -> std::sync::MutexGuard<'static, Emitter<'static>>
{
    EMITTER.lock().unwrap()
}

pub type Point<'a> = BTreeMap<&'a str, serde_json::Value>;

pub struct Emitter<'e>
{
    defaults: Point<'e>,
    output: Option<TcpStream>,
    destination: String,
    app: String,
}

impl<'e> Emitter<'e>
{
    pub fn empty() -> Emitter<'e>
    {
        Emitter
        {
            defaults: get_defaults(Point::new()),
            output: None,
            app: String::from(""),
            destination: String::from("")
        }
    }

    pub fn for_app(app: &str) -> Emitter<'e>
    {
        let mut t = String::from(app);
        t.push('.');

        Emitter
        {
            defaults: get_defaults(Point::new()),
            output: None,
            app: t,
            destination: String::from("")
        }
    }

    pub fn init(&mut self, tmpl: Point<'e>, app: &str)
    {
        let mut defaults = tmpl.clone();
        let hostname = hostname();
        defaults.insert("host", serde_json::to_value(hostname));

        let mut t = String::from(app);
        t.push('.');

        self.defaults = defaults;
        self.app = t;
    }

    pub fn new(tmpl: Point<'e>, app: &str) -> Emitter<'e>
    {
        let mut defaults = tmpl.clone();
        let hostname = hostname();
        defaults.insert("host", serde_json::to_value(hostname));

        let mut t = String::from(app);
        t.push('.');

        Emitter
        {
            defaults: get_defaults(tmpl),
            output: None,
            app: t,
            destination: String::from("")
        }
    }

    pub fn connect(&mut self, dest: &str)
    {
        self.destination = String::from(dest);
        self.output = create_connection(dest);
    }

    // The default write_all implementation doesn't do useful things.
    fn write_all(conn: &mut TcpStream, mut buf: &[u8]) -> Result<usize, io::Error>
    {
        // let total = buf.len();
        let mut written: usize = 0;
        while !buf.is_empty()
        {
            match conn.write(buf)
            {
                Ok(0) => return Err(io::Error::new(io::ErrorKind::Other, "zero bytes written")),
                Ok(n) => {
                    // println!("bytes={} of {}", n, total);
                    written += n;
                    buf = &buf[n..]
                },
                Err(e) => return Err(e),
            }
        }
        Ok(written)
    }

    fn write(&mut self, metric: BTreeMap<&'e str, Value>)
    {
        match self.output
        {
            None => { self.output = create_connection(&self.destination); },
            Some(_) => {},
        };

        match self.output
        {
            None => {},
            Some(ref mut conn) =>
            {
                let mline = serde_json::to_string(&metric).unwrap() + "\n";
                match Emitter::write_all(conn, mline.as_bytes())
                {
                    Ok(_) => {},
                    Err(e) => println!("ERR {:?}", e),
                }
            }
        }
    }

    pub fn emit_point(&mut self, point: BTreeMap<&'e str, Value>)
    {
        let mut metric = self.defaults.clone();
        metric.append(&mut point.clone());

        // Failing to set a name means the metrics point is invalid; we decline to send it.
        let name = match metric.remove("name")
        {
            Some(v) => v,
            None => { return; },
        };
        let mut fullname = self.app.clone();
        fullname.push_str(name.as_str().unwrap());

        metric.insert("name", serde_json::to_value(fullname));
        metric.entry("value").or_insert(serde_json::to_value(1));

        let now = time::get_time();
        let millis = now.sec * 1000 + (now.nsec / 1000000) as i64;
        metric.entry("time").or_insert(serde_json::to_value(millis));

        self.write(metric);
    }

    pub fn emit<T>(&mut self, name: &str, value: T)
        where T: serde::ser::Serialize
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        self.emit_point(metric);
    }

    pub fn emit_name(&mut self, name: &'e str)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        self.emit_point(metric);
    }

    pub fn emit_name_val_tag<T>(&mut self, name: &'e str, value: T, tag: &'e str, tagv: T)
        where T: serde::ser::Serialize
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        metric.insert(tag, serde_json::to_value(tagv));
        self.emit_point(metric);
    }
}

fn create_connection(dest: &str) -> Option<std::net::TcpStream>
{
    // TODO udp vs tcp for full compatibility
    // TODO reconnect on error
    let target = url::Url::parse(dest).ok().unwrap();
    match TcpStream::connect((target.host_str().unwrap(), target.port().unwrap()))
    {
        Ok(v) => { Some(v) },
        Err(_) => { None },
    }
}

pub fn hostname<'a>() -> String
{
    let bufsize = 255;
    let mut buf = Vec::<u8>::with_capacity(bufsize);
    let ptr = buf.as_mut_slice().as_mut_ptr();

    let err = unsafe
        { gethostname(ptr as *mut libc::c_char, bufsize as libc::size_t) }
        as libc::size_t;

    if err != 0
    {
        return "localhost".into();
    }

    let mut len = bufsize;
    let mut i = 0;

    loop
    {
        let byte = unsafe { *(((ptr as u64) + (i as u64)) as *const u8) };
        if byte == 0
        {
            len = i;
            break;
        }
        if i == bufsize { break; }
        i += 1;
    }

    unsafe { buf.set_len(len); }
    String::from_utf8_lossy(buf.as_slice()).into_owned()
}

fn get_defaults(tmpl: Point) -> Point {
    let defaults = tmpl.clone();
    defaults.insert("host", serde_json::to_value(hostname()));
    defaults
}

impl<'e> Clone for Emitter<'e>
{
    fn clone(&self) -> Self
    {
        Emitter
        {
            defaults: self.defaults.clone(),
            destination: self.destination.clone(),
            app: self.app.clone(),
            output: match self.output
            {
                None => None,
                Some(ref o) => Some(o.try_clone().expect("expected TcpStream to clone"))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>chore: replace all `Point` definitions with `Point`<commit_after>#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate url;

use libc::gethostname;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::net::TcpStream;
use std::sync::Mutex;
use std::io;

lazy_static!
{
    pub static ref EMITTER: Mutex<Emitter<'static>> = Mutex::new(Emitter::empty());
}

pub fn emitter() -> std::sync::MutexGuard<'static, Emitter<'static>>
{
    EMITTER.lock().unwrap()
}

pub type Point<'a> = BTreeMap<&'a str, serde_json::Value>;

pub struct Emitter<'e>
{
    defaults: Point<'e>,
    output: Option<TcpStream>,
    destination: String,
    app: String,
}

impl<'e> Emitter<'e>
{
    pub fn empty() -> Emitter<'e>
    {
        Emitter
        {
            defaults: get_defaults(Point::new()),
            output: None,
            app: String::from(""),
            destination: String::from("")
        }
    }

    pub fn for_app(app: &str) -> Emitter<'e>
    {
        let mut t = String::from(app);
        t.push('.');

        Emitter
        {
            defaults: get_defaults(Point::new()),
            output: None,
            app: t,
            destination: String::from("")
        }
    }

    pub fn init(&mut self, tmpl: Point<'e>, app: &str)
    {
        let mut defaults = tmpl.clone();
        let hostname = hostname();
        defaults.insert("host", serde_json::to_value(hostname));

        let mut t = String::from(app);
        t.push('.');

        self.defaults = defaults;
        self.app = t;
    }

    pub fn new(tmpl: Point<'e>, app: &str) -> Emitter<'e>
    {
        let mut defaults = tmpl.clone();
        let hostname = hostname();
        defaults.insert("host", serde_json::to_value(hostname));

        let mut t = String::from(app);
        t.push('.');

        Emitter
        {
            defaults: get_defaults(tmpl),
            output: None,
            app: t,
            destination: String::from("")
        }
    }

    pub fn connect(&mut self, dest: &str)
    {
        self.destination = String::from(dest);
        self.output = create_connection(dest);
    }

    // The default write_all implementation doesn't do useful things.
    fn write_all(conn: &mut TcpStream, mut buf: &[u8]) -> Result<usize, io::Error>
    {
        // let total = buf.len();
        let mut written: usize = 0;
        while !buf.is_empty()
        {
            match conn.write(buf)
            {
                Ok(0) => return Err(io::Error::new(io::ErrorKind::Other, "zero bytes written")),
                Ok(n) => {
                    // println!("bytes={} of {}", n, total);
                    written += n;
                    buf = &buf[n..]
                },
                Err(e) => return Err(e),
            }
        }
        Ok(written)
    }

    fn write(&mut self, metric: Point)
    {
        match self.output
        {
            None => { self.output = create_connection(&self.destination); },
            Some(_) => {},
        };

        match self.output
        {
            None => {},
            Some(ref mut conn) =>
            {
                let mline = serde_json::to_string(&metric).unwrap() + "\n";
                match Emitter::write_all(conn, mline.as_bytes())
                {
                    Ok(_) => {},
                    Err(e) => println!("ERR {:?}", e),
                }
            }
        }
    }

    pub fn emit_point(&mut self, point: Point)
    {
        let mut metric = self.defaults.clone();
        metric.append(&mut point.clone());

        // Failing to set a name means the metrics point is invalid; we decline to send it.
        let name = match metric.remove("name")
        {
            Some(v) => v,
            None => { return; },
        };
        let mut fullname = self.app.clone();
        fullname.push_str(name.as_str().unwrap());

        metric.insert("name", serde_json::to_value(fullname));
        metric.entry("value").or_insert(serde_json::to_value(1));

        let now = time::get_time();
        let millis = now.sec * 1000 + (now.nsec / 1000000) as i64;
        metric.entry("time").or_insert(serde_json::to_value(millis));

        self.write(metric);
    }

    pub fn emit<T>(&mut self, name: &str, value: T)
        where T: serde::ser::Serialize
    {
        let mut metric: Point = Point::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        self.emit_point(metric);
    }

    pub fn emit_name(&mut self, name: &str)
    {
        let mut metric: Point = Point::new();
        metric.insert("name", serde_json::to_value(name));
        self.emit_point(metric);
    }

    pub fn emit_name_val_tag<T>(&mut self, name: &str, value: T, tag: &str, tagv: T)
        where T: serde::ser::Serialize
    {
        let mut metric: Point = Point::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        metric.insert(tag, serde_json::to_value(tagv));
        self.emit_point(metric);
    }
}

fn create_connection(dest: &str) -> Option<std::net::TcpStream>
{
    // TODO udp vs tcp for full compatibility
    // TODO reconnect on error
    let target = url::Url::parse(dest).ok().unwrap();
    match TcpStream::connect((target.host_str().unwrap(), target.port().unwrap()))
    {
        Ok(v) => { Some(v) },
        Err(_) => { None },
    }
}

pub fn hostname<'a>() -> String
{
    let bufsize = 255;
    let mut buf = Vec::<u8>::with_capacity(bufsize);
    let ptr = buf.as_mut_slice().as_mut_ptr();

    let err = unsafe
        { gethostname(ptr as *mut libc::c_char, bufsize as libc::size_t) }
        as libc::size_t;

    if err != 0
    {
        return "localhost".into();
    }

    let mut len = bufsize;
    let mut i = 0;

    loop
    {
        let byte = unsafe { *(((ptr as u64) + (i as u64)) as *const u8) };
        if byte == 0
        {
            len = i;
            break;
        }
        if i == bufsize { break; }
        i += 1;
    }

    unsafe { buf.set_len(len); }
    String::from_utf8_lossy(buf.as_slice()).into_owned()
}

fn get_defaults(tmpl: Point) -> Point {
    let mut defaults = tmpl.clone();
    defaults.insert("host", serde_json::to_value(hostname()));
    defaults
}

impl<'e> Clone for Emitter<'e>
{
    fn clone(&self) -> Self
    {
        Emitter
        {
            defaults: self.defaults.clone(),
            destination: self.destination.clone(),
            app: self.app.clone(),
            output: match self.output
            {
                None => None,
                Some(ref o) => Some(o.try_clone().expect("expected TcpStream to clone"))
            }
        }
    }
}

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