<commit_before>// Copyright 2016 Jeremy Mason
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! `mayda` is a library to compress integer arrays (all primitive integer
//! types are supported). The design favors decompression speed and the ability
//! to index the compressed array over the compression ratio, on the principle
//! that the runtime penalty for using compressed arrays should be as small as
//! possible.
//!
//! This crate provides three variations on a single compression algorithm. The
//! [`Uniform`] type can decompress around six billion `u32`s per second, or 24
//! GiB/s of decompressed integers, on a 2.6 GHz Intel Core i7-6700HQ processor
//! (see below for specifics). The [`Monotone`] and [`Unimodal`] types decompress
//! at a little less than half the speed, but can have much better compression
//! ratios depending on the distribution of the integers. Overall performance is
//! comparable to the fastest (known) libraries in any language.
//!
//! # Usage
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! mayda = "^0.2"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate mayda;
//! ```
//!
//! # Example: encoding and decoding
//!
//! The `Uniform` struct is recommended for general purpose integer compression.
//! Use the `Encode` trait to encode and decode the array.
//!
//! ```rust
//! use std::mem;
//! use mayda::{Uniform, Encode};
//!
//! // Integers in some interval of length 255, require one byte per integer
//! let input: Vec<u32> = (0..128).map(|x| (x * 73) % 181 + 307).collect();
//!
//! let mut uniform = Uniform::new();
//! uniform.encode(&input).unwrap();
//!
//! let i_bytes = std::mem::size_of_val(input.as_slice());
//! let u_bytes = std::mem::size_of_val(uniform.storage());
//!
//! // 128 bytes for encoded entries, 12 bytes of overhead
//! assert_eq!(i_bytes, 512);
//! assert_eq!(u_bytes, 140);
//!
//! let output: Vec<u32> = uniform.decode();
//! assert_eq!(input, output);
//! ```
//!
//! # Example: indexing
//!
//! Use the `Access` or `AccessInto` traits to index the compressed array. This
//! is similar to `Index`, but returns a vector instead of a slice.
//!
//! ```rust
//! use mayda::{Uniform, Encode, Access};
//!
//! // All primitive integer types supported
//! let input: Vec<i16> = (-64..64).collect();
//!
//! let mut uniform = Uniform::new();
//! uniform.encode(&input).unwrap();
//!
//! let val: i16 = uniform.access(64);
//! assert_eq!(val, 0);
//!
//! // Vector is returned to give ownership to the caller
//! let range: Vec<i16> = uniform.access(..10);
//! assert_eq!(range, (-64..-54).collect::<Vec<_>>());
//! ```
//!
//! # Algorithm
//!
//! The compression algorithm relies on the observation that for many integer
//! arrays, the probability distribution of a block of 128 entries is not
//! uniform over all values that can be represented by the integer type. For
//! example, an array of indices into a second array with 256 entries has
//! entries that are bounded below by 0 and above by 255. This requires only
//! eight bits per entry, rather than the 32 or 64 generally set aside for a
//! usize index. The basic idea of the compression algorithm is to represent
//! all of the entries in a block with a single minimum necessary bit width.
//! This allows SIMD operations and manual loop unrolling to avoid branches to
//! be used to accelerate encoding and decoding.
//!
//! This approach does not perform well for probability distributions with
//! outliers though, or for situations where the median value is nonzero. This
//! crate provides three types that handle this situation by applying different
//! initial transformations to the input integer array.
//!
//! The `Uniform` type targets encoding and decoding speed. The only
//! transformation is to subtract the minimum value from the entries, with the
//! result that the compression depends only on the difference between the
//! largest and smallest entries.
//!
//! The `Monotone` type is specifically intended for arrays with monotone
//! increasing entries. A blocks of entries is transformed into an offset and
//! an array of differences of successive entries, and the array of differences
//! is encoded by the approach above. The compression depends only on the
//! largest entry in the difference array.
//!
//! The `Unimodal` type performs the most extensive transformations and offers
//! the most robust compression. The median value is subtracted from the
//! entries, the entries are mapped to the unsigned integers by the zig-zag
//! encoding, and the most significant bits of any outliers are removed and
//! stored separately. The result is that the compression effectively depends
//! only on the standard deviation of the probability distribution of the block
//! entries.
//!
//! # Indexing
//!
//! Indexing an object of the `Uniform`, `Monotone` or `Unimodal` types is not
//! a simple pointer offset. Part of the header encodes the relative offsets to
//! every block in a compressed form, with the result that random access via
//! the `Access` trait is an `O(log(idx))` operation, where `idx` is the value
//! of the index (not the length of the array). The overhead of this part of
//! the header is around a tenth of a bit per encoded integer.
//!
//! If you need to access several nearby entries, consider accessing the range
//! and indexing the returned vector for performance.
//!
//! # Safety
//!
//! As a general rule, you **should not** decode or access objects of the
//! `Uniform`, `Monotone` or `Unimodal` types from untrusted sources.
//!
//! `mayda` performs wildly unsafe pointer operations during encoding and
//! decoding. Changing the header information with `mut_storage` can cause data
//! to be written to or read from arbitrary addresses in memory.
//!
//! That said, the situation is the same for any of the data structures in the
//! standard library (consider the `set_len` method of a `Vec`).

#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![feature(iter_arith)]
#![feature(specialization)]

extern crate mayda_codec;

pub mod error;
pub mod monotone;
pub mod uniform;
pub mod unimodal;
pub mod utility;

pub use self::error::Error;
pub use self::monotone::Monotone;
pub use self::uniform::Uniform;
pub use self::unimodal::Unimodal;
pub use self::utility::{Access, AccessInto, Encode};
<commit_msg>Typo in documentation<commit_after>// Copyright 2016 Jeremy Mason
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! `mayda` is a library to compress integer arrays (all primitive integer
//! types are supported). The design favors decompression speed and the ability
//! to index the compressed array over the compression ratio, on the principle
//! that the runtime penalty for using compressed arrays should be as small as
//! possible.
//!
//! This crate provides three variations on a single compression algorithm. The
//! `Uniform` type can decompress around six billion `u32`s per second, or 24
//! GiB/s of decompressed integers, on a 2.6 GHz Intel Core i7-6700HQ processor
//! (see below for specifics). The `Monotone` and `Unimodal` types decompress
//! at a little less than half the speed, but can have much better compression
//! ratios depending on the distribution of the integers. Overall performance is
//! comparable to the fastest (known) libraries in any language.
//!
//! # Usage
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! mayda = "^0.2"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate mayda;
//! ```
//!
//! # Example: encoding and decoding
//!
//! The `Uniform` struct is recommended for general purpose integer compression.
//! Use the `Encode` trait to encode and decode the array.
//!
//! ```rust
//! use std::mem;
//! use mayda::{Uniform, Encode};
//!
//! // Integers in some interval of length 255, require one byte per integer
//! let input: Vec<u32> = (0..128).map(|x| (x * 73) % 181 + 307).collect();
//!
//! let mut uniform = Uniform::new();
//! uniform.encode(&input).unwrap();
//!
//! let i_bytes = std::mem::size_of_val(input.as_slice());
//! let u_bytes = std::mem::size_of_val(uniform.storage());
//!
//! // 128 bytes for encoded entries, 12 bytes of overhead
//! assert_eq!(i_bytes, 512);
//! assert_eq!(u_bytes, 140);
//!
//! let output: Vec<u32> = uniform.decode();
//! assert_eq!(input, output);
//! ```
//!
//! # Example: indexing
//!
//! Use the `Access` or `AccessInto` traits to index the compressed array. This
//! is similar to `Index`, but returns a vector instead of a slice.
//!
//! ```rust
//! use mayda::{Uniform, Encode, Access};
//!
//! // All primitive integer types supported
//! let input: Vec<i16> = (-64..64).collect();
//!
//! let mut uniform = Uniform::new();
//! uniform.encode(&input).unwrap();
//!
//! let val: i16 = uniform.access(64);
//! assert_eq!(val, 0);
//!
//! // Vector is returned to give ownership to the caller
//! let range: Vec<i16> = uniform.access(..10);
//! assert_eq!(range, (-64..-54).collect::<Vec<_>>());
//! ```
//!
//! # Algorithm
//!
//! The compression algorithm relies on the observation that for many integer
//! arrays, the probability distribution of a block of 128 entries is not
//! uniform over all values that can be represented by the integer type. For
//! example, an array of indices into a second array with 256 entries has
//! entries that are bounded below by 0 and above by 255. This requires only
//! eight bits per entry, rather than the 32 or 64 generally set aside for a
//! usize index. The basic idea of the compression algorithm is to represent
//! all of the entries in a block with a single minimum necessary bit width.
//! This allows SIMD operations and manual loop unrolling to avoid branches to
//! be used to accelerate encoding and decoding.
//!
//! This approach does not perform well for probability distributions with
//! outliers though, or for situations where the median value is nonzero. This
//! crate provides three types that handle this situation by applying different
//! initial transformations to the input integer array.
//!
//! The `Uniform` type targets encoding and decoding speed. The only
//! transformation is to subtract the minimum value from the entries, with the
//! result that the compression depends only on the difference between the
//! largest and smallest entries.
//!
//! The `Monotone` type is specifically intended for arrays with monotone
//! increasing entries. A blocks of entries is transformed into an offset and
//! an array of differences of successive entries, and the array of differences
//! is encoded by the approach above. The compression depends only on the
//! largest entry in the difference array.
//!
//! The `Unimodal` type performs the most extensive transformations and offers
//! the most robust compression. The median value is subtracted from the
//! entries, the entries are mapped to the unsigned integers by the zig-zag
//! encoding, and the most significant bits of any outliers are removed and
//! stored separately. The result is that the compression effectively depends
//! only on the standard deviation of the probability distribution of the block
//! entries.
//!
//! # Indexing
//!
//! Indexing an object of the `Uniform`, `Monotone` or `Unimodal` types is not
//! a simple pointer offset. Part of the header encodes the relative offsets to
//! every block in a compressed form, with the result that random access via
//! the `Access` trait is an `O(log(idx))` operation, where `idx` is the value
//! of the index (not the length of the array). The overhead of this part of
//! the header is around a tenth of a bit per encoded integer.
//!
//! If you need to access several nearby entries, consider accessing the range
//! and indexing the returned vector for performance.
//!
//! # Safety
//!
//! As a general rule, you **should not** decode or access objects of the
//! `Uniform`, `Monotone` or `Unimodal` types from untrusted sources.
//!
//! `mayda` performs wildly unsafe pointer operations during encoding and
//! decoding. Changing the header information with `mut_storage` can cause data
//! to be written to or read from arbitrary addresses in memory.
//!
//! That said, the situation is the same for any of the data structures in the
//! standard library (consider the `set_len` method of a `Vec`).

#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![feature(iter_arith)]
#![feature(specialization)]

extern crate mayda_codec;

pub mod error;
pub mod monotone;
pub mod uniform;
pub mod unimodal;
pub mod utility;

pub use self::error::Error;
pub use self::monotone::Monotone;
pub use self::uniform::Uniform;
pub use self::unimodal::Unimodal;
pub use self::utility::{Access, AccessInto, Encode};
<|endoftext|>


<commit_before>extern crate serial;
use std::io::Write;
use std::time::Duration;

use serial::prelude::*;
use serial::{SystemPort, open, Error};

// Some constants used for enttec message framing.
const START_VAL: u8 = 0x7E;
const END_VAL: u8 = 0xE7;

// Universe size constraints.
const MIN_UNIVERSE_SIZE: usize = 24;
const MAX_UNIVERSE_SIZE: usize = 512;

// Port action flags.
const GET_PARAMETERS: u8 = 3;
const SET_PARAMETERS: u8 = 4;
const RECEIVE_DMX_PACKET: u8 = 5;
const SEND_DMX_PACKET: u8 = 6;

/// Format a byte buffer as an enttec message.
/// Maximum valid size for payload is 600; no check is made here that the payload is within this range.
fn make_packet(message_type: u8, payload: &[u8]) -> Vec<u8> {
    // Enttec messages are the size of the payload plus 5 bytes for type, length, and framing.
    let payload_size = payload.len();
    let mut packet = Vec::with_capacity(payload_size + 5);
    let (len_lsb, len_msb) = (payload_size as u8, (payload_size >> 8) as u8);
    packet.push(START_VAL);
    packet.push(message_type);
    packet.push(len_lsb);
    packet.push(len_msb);
    packet.extend_from_slice(payload);
    packet.push(END_VAL);
    packet
}

pub struct EnttecParams {
    /// DMX output break time in 10.67 microsecond units. Valid range is 9 to 127.
    break_time: u8,
    /// DMX output Mark After Break time in 10.67 microsecond units. Valid range is 1 to 127.
    mark_after_break_time: u8,
    /// DMX output rate in packets per second. Valid range is 1 to 40, or 0 for fastest rate
    /// possible (this will make the most difference when the output universe size is smallest).
    output_rate: u8,
}

impl Default for EnttecParams {
    /// Default parameters for the enttec port.
    /// In summary: minimum break and mark times, fastest fixed framerate.
    fn default() -> Self {
        EnttecParams {
            break_time: 9,
            mark_after_break_time: 1,
            output_rate: 40,
        }
    }
}

impl EnttecParams {
    fn as_packet(&self) -> Vec<u8> {
        let payload = [self.break_time, self.mark_after_break_time, self.output_rate];
        make_packet(SET_PARAMETERS, &payload)
    }
}

pub struct EnttecDmxPort {
    params: EnttecParams,
    port: SystemPort,
    port_name: String,
}

impl EnttecDmxPort {
    /// Open a enttec port with the specified port name.
    pub fn new(port_name: String) -> Result<EnttecDmxPort, Error> {
        let mut port = open(&port_name)?;

        // use a short 1 ms timeout to avoid blocking if, say, the port disappears
        port.set_timeout(Duration::from_millis(1))?;

        let params = EnttecParams::default();

        // send the default parameters to the port
        port.write_all(&params.as_packet())?;

        Ok(EnttecDmxPort {
            params: params,
            port: port,
            port_name: port_name,
        })
    }

    /// Write a DMX frame out to the port.  If the frame is smaller than the minimum universe size,
    /// it will be padded with zeros.  If the frame is larger than the maximum universe size, the
    /// values beyond the max size will be ignored.
    pub fn write(&mut self, frame: &[u8]) -> Result<(), Error> {
        let packet = {
            let size = frame.len();
            if size < MIN_UNIVERSE_SIZE {
                let mut padded_frame = Vec::with_capacity(MIN_UNIVERSE_SIZE);
                padded_frame.extend_from_slice(frame);
                padded_frame.resize(MIN_UNIVERSE_SIZE, 0);
                make_packet(SEND_DMX_PACKET, &padded_frame)
            }
            else {
                make_packet(SEND_DMX_PACKET, &frame[0..MAX_UNIVERSE_SIZE])
            }
        };
        self.port.write_all(&packet)?;
        Ok(())
    }
}<commit_msg>ENH: add offline mock<commit_after>extern crate serial;
use std::io::Write;
use std::time::Duration;

use serial::prelude::*;
use serial::{SystemPort, open, Error};

// Some constants used for enttec message framing.
const START_VAL: u8 = 0x7E;
const END_VAL: u8 = 0xE7;

// Universe size constraints.
const MIN_UNIVERSE_SIZE: usize = 24;
const MAX_UNIVERSE_SIZE: usize = 512;

// Port action flags.
const SET_PARAMETERS: u8 = 4;
//const RECEIVE_DMX_PACKET: u8 = 5;
const SEND_DMX_PACKET: u8 = 6;

/// Format a byte buffer as an enttec message.
/// Maximum valid size for payload is 600; no check is made here that the payload is within this range.
fn make_packet(message_type: u8, payload: &[u8]) -> Vec<u8> {
    // Enttec messages are the size of the payload plus 5 bytes for type, length, and framing.
    let payload_size = payload.len();
    let mut packet = Vec::with_capacity(payload_size + 5);
    let (len_lsb, len_msb) = (payload_size as u8, (payload_size >> 8) as u8);
    packet.push(START_VAL);
    packet.push(message_type);
    packet.push(len_lsb);
    packet.push(len_msb);
    packet.extend_from_slice(payload);
    packet.push(END_VAL);
    packet
}

pub struct EnttecParams {
    /// DMX output break time in 10.67 microsecond units. Valid range is 9 to 127.
    break_time: u8,
    /// DMX output Mark After Break time in 10.67 microsecond units. Valid range is 1 to 127.
    mark_after_break_time: u8,
    /// DMX output rate in packets per second. Valid range is 1 to 40, or 0 for fastest rate
    /// possible (this will make the most difference when the output universe size is smallest).
    output_rate: u8,
}

impl Default for EnttecParams {
    /// Default parameters for the enttec port.
    /// In summary: minimum break and mark times, fastest fixed framerate.
    fn default() -> Self {
        EnttecParams {
            break_time: 9,
            mark_after_break_time: 1,
            output_rate: 40,
        }
    }
}

impl EnttecParams {
    fn as_packet(&self) -> Vec<u8> {
        let payload = [self.break_time, self.mark_after_break_time, self.output_rate];
        make_packet(SET_PARAMETERS, &payload)
    }
}

/// Trait for the general notion of a DMX port.
/// This enables creation of an "offline" port to slot into place if an API requires an output.
pub trait DmxPort {
    /// Write a DMX frame out to the port.  If the frame is smaller than the minimum universe size,
    /// it will be padded with zeros.  If the frame is larger than the maximum universe size, the
    /// values beyond the max size will be ignored.
    fn write(&mut self, frame: &[u8]) -> Result<(), Error>;

    fn port_name(&self) -> &str;
}

pub struct EnttecDmxPort {
    params: EnttecParams,
    port: SystemPort,
    port_name: String,
}

impl EnttecDmxPort {
    /// Open a enttec port with the specified port name.
    pub fn new(port_name: String) -> Result<EnttecDmxPort, Error> {
        let mut port = open(&port_name)?;

        // use a short 1 ms timeout to avoid blocking if, say, the port disappears
        port.set_timeout(Duration::from_millis(1))?;

        let params = EnttecParams::default();

        let mut port = EnttecDmxPort {
            params: params,
            port: port,
            port_name: port_name,
        };

        // send the default parameters to the port
        port.write_params()?;
        Ok(port)
    }

    pub fn write_params(&mut self) -> Result<(), Error> {
        self.port.write_all(&self.params.as_packet())?;
        Ok(())
    }
}

impl DmxPort for EnttecDmxPort {
    fn write(&mut self, frame: &[u8]) -> Result<(), Error> {
        let packet = {
            let size = frame.len();
            if size < MIN_UNIVERSE_SIZE {
                let mut padded_frame = Vec::with_capacity(MIN_UNIVERSE_SIZE);
                padded_frame.extend_from_slice(frame);
                padded_frame.resize(MIN_UNIVERSE_SIZE, 0);
                make_packet(SEND_DMX_PACKET, &padded_frame)
            }
            else {
                make_packet(SEND_DMX_PACKET, &frame[0..MAX_UNIVERSE_SIZE])
            }
        };
        self.port.write_all(&packet)?;
        Ok(())
    }

    fn port_name(&self) -> &str {
        &self.port_name
    }
}

pub struct OfflineDmxPort {}

impl DmxPort for OfflineDmxPort {
    fn write(&mut self, _: &[u8]) -> Result<(), Error> {
        Ok(())
    }
    fn port_name(&self) -> &str {
        "offline"
    }
}<|endoftext|>


<commit_before>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! * [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are defined in this crate
//! because they cannot be used in [syn] without "full" feature.
//!
//! ## Optional features
//!
//! syn-mid in the default features aims to provide the features between "full"
//! and "derive" of [syn].
//!
//! * **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
//!   types.
//!
//! [`syn_mid::ItemFn`]: struct.ItemFn.html
//! [`syn_mid::Block`]: struct.Block.html
//! [syn]: https://github.com/dtolnay/syn
//!

#![doc(html_root_url = "https://docs.rs/syn-mid/0.2.0")]
#![deny(unsafe_code)]
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        renamed_and_removed_lints,
        redundant_field_names, // Rust 1.17+ => remove
        const_static_lifetime, // Rust 1.17+ => remove
        deprecated_cfg_attr, // Rust 1.30+ => remove
        map_clone,
        large_enum_variant
    )
)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

extern crate proc_macro2;
extern crate quote;
#[allow(unused_imports)]
#[macro_use]
extern crate syn;

#[macro_use]
mod macros;

mod arg;
mod pat;
mod path;
mod print;

pub use self::arg::*;
pub use self::pat::*;

use proc_macro2::TokenStream;
use syn::punctuated::Punctuated;
use syn::{token, Abi, AttrStyle, Attribute, Ident, Visibility};

ast_struct! {
    /// A braced block containing Rust statements.
    pub struct Block {
        pub brace_token: token::Brace,
        /// Statements in a block
        pub stmts: TokenStream,
    }
}

ast_struct! {
    /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
    /// }`.
    pub struct ItemFn {
        pub attrs: Vec<Attribute>,
        pub vis: Visibility,
        pub constness: Option<Token![const]>,
        pub unsafety: Option<Token![unsafe]>,
        pub asyncness: Option<Token![async]>,
        pub abi: Option<Abi>,
        pub ident: Ident,
        pub decl: Box<FnDecl>,
        pub block: Block,
    }
}

mod parsing {
    use syn::parse::{Parse, ParseStream, Result};
    use syn::{Abi, Attribute, Generics, Ident, ReturnType, Visibility, WhereClause};

    use super::{Block, FnArg, FnDecl, ItemFn};

    impl Parse for ItemFn {
        fn parse(input: ParseStream) -> Result<Self> {
            let outer_attrs = input.call(Attribute::parse_outer)?;
            let vis: Visibility = input.parse()?;
            let constness: Option<Token![const]> = input.parse()?;
            let unsafety: Option<Token![unsafe]> = input.parse()?;
            let asyncness: Option<Token![async]> = input.parse()?;
            let abi: Option<Abi> = input.parse()?;
            let fn_token: Token![fn] = input.parse()?;
            let ident: Ident = input.parse()?;
            let generics: Generics = input.parse()?;

            let content;
            let paren_token = parenthesized!(content in input);
            let inputs = content.parse_terminated(FnArg::parse)?;

            let output: ReturnType = input.parse()?;
            let where_clause: Option<WhereClause> = input.parse()?;

            let content;
            let brace_token = braced!(content in input);
            let stmts = content.parse()?;

            Ok(ItemFn {
                attrs: outer_attrs,
                vis: vis,
                constness: constness,
                unsafety: unsafety,
                asyncness: asyncness,
                abi: abi,
                ident: ident,
                decl: Box::new(FnDecl {
                    fn_token: fn_token,
                    paren_token: paren_token,
                    inputs: inputs,
                    output: output,
                    variadic: None,
                    generics: Generics {
                        where_clause: where_clause,
                        ..generics
                    },
                }),
                block: Block {
                    brace_token: brace_token,
                    stmts: stmts,
                },
            })
        }
    }
}

mod printing {
    use proc_macro2::TokenStream;
    use quote::{ToTokens, TokenStreamExt};
    use std::iter;

    use super::*;

    impl ToTokens for Block {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.stmts.clone());
            });
        }
    }

    trait FilterAttrs<'a> {
        type Ret: Iterator<Item = &'a Attribute>;

        fn outer(self) -> Self::Ret;
        fn inner(self) -> Self::Ret;
    }

    impl<'a, T> FilterAttrs<'a> for T
    where
        T: IntoIterator<Item = &'a Attribute>,
    {
        type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;

        fn outer(self) -> Self::Ret {
            #[cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))]
            fn is_outer(attr: &&Attribute) -> bool {
                match attr.style {
                    AttrStyle::Outer => true,
                    _ => false,
                }
            }
            self.into_iter().filter(is_outer)
        }

        fn inner(self) -> Self::Ret {
            #[cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))]
            fn is_inner(attr: &&Attribute) -> bool {
                match attr.style {
                    AttrStyle::Inner(_) => true,
                    _ => false,
                }
            }
            self.into_iter().filter(is_inner)
        }
    }

    impl ToTokens for ItemFn {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(self.attrs.outer());
            self.vis.to_tokens(tokens);
            self.constness.to_tokens(tokens);
            self.unsafety.to_tokens(tokens);
            self.asyncness.to_tokens(tokens);
            self.abi.to_tokens(tokens);
            NamedDecl(&self.decl, &self.ident).to_tokens(tokens);
            self.block.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.attrs.inner());
                tokens.append_all(self.block.stmts.clone());
            });
        }
    }

    struct NamedDecl<'a>(&'a FnDecl, &'a Ident);

    impl<'a> ToTokens for NamedDecl<'a> {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.0.fn_token.to_tokens(tokens);
            self.1.to_tokens(tokens);
            self.0.generics.to_tokens(tokens);
            self.0.paren_token.surround(tokens, |tokens| {
                self.0.inputs.to_tokens(tokens);
                if self.0.variadic.is_some() && !self.0.inputs.empty_or_trailing() {
                    <Token![,]>::default().to_tokens(tokens);
                }
                self.0.variadic.to_tokens(tokens);
            });
            self.0.output.to_tokens(tokens);
            self.0.generics.where_clause.to_tokens(tokens);
        }
    }
}
<commit_msg>Remove FilterAttrs trait<commit_after>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! * [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are defined in this crate
//! because they cannot be used in [syn] without "full" feature.
//!
//! ## Optional features
//!
//! syn-mid in the default features aims to provide the features between "full"
//! and "derive" of [syn].
//!
//! * **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
//!   types.
//!
//! [`syn_mid::ItemFn`]: struct.ItemFn.html
//! [`syn_mid::Block`]: struct.Block.html
//! [syn]: https://github.com/dtolnay/syn
//!

#![doc(html_root_url = "https://docs.rs/syn-mid/0.2.0")]
#![deny(unsafe_code)]
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        renamed_and_removed_lints,
        redundant_field_names, // Rust 1.17+ => remove
        const_static_lifetime, // Rust 1.17+ => remove
        deprecated_cfg_attr, // Rust 1.30+ => remove
        map_clone,
        large_enum_variant
    )
)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

extern crate proc_macro2;
extern crate quote;
#[allow(unused_imports)]
#[macro_use]
extern crate syn;

#[macro_use]
mod macros;

mod arg;
mod pat;
mod path;
mod print;

pub use self::arg::*;
pub use self::pat::*;

use proc_macro2::TokenStream;
use syn::punctuated::Punctuated;
use syn::{token, Abi, Attribute, Ident, Visibility};

ast_struct! {
    /// A braced block containing Rust statements.
    pub struct Block {
        pub brace_token: token::Brace,
        /// Statements in a block
        pub stmts: TokenStream,
    }
}

ast_struct! {
    /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
    /// }`.
    pub struct ItemFn {
        pub attrs: Vec<Attribute>,
        pub vis: Visibility,
        pub constness: Option<Token![const]>,
        pub unsafety: Option<Token![unsafe]>,
        pub asyncness: Option<Token![async]>,
        pub abi: Option<Abi>,
        pub ident: Ident,
        pub decl: Box<FnDecl>,
        pub block: Block,
    }
}

mod parsing {
    use syn::parse::{Parse, ParseStream, Result};
    use syn::{Abi, Attribute, Generics, Ident, ReturnType, Visibility, WhereClause};

    use super::{Block, FnArg, FnDecl, ItemFn};

    impl Parse for ItemFn {
        fn parse(input: ParseStream) -> Result<Self> {
            let outer_attrs = input.call(Attribute::parse_outer)?;
            let vis: Visibility = input.parse()?;
            let constness: Option<Token![const]> = input.parse()?;
            let unsafety: Option<Token![unsafe]> = input.parse()?;
            let asyncness: Option<Token![async]> = input.parse()?;
            let abi: Option<Abi> = input.parse()?;
            let fn_token: Token![fn] = input.parse()?;
            let ident: Ident = input.parse()?;
            let generics: Generics = input.parse()?;

            let content;
            let paren_token = parenthesized!(content in input);
            let inputs = content.parse_terminated(FnArg::parse)?;

            let output: ReturnType = input.parse()?;
            let where_clause: Option<WhereClause> = input.parse()?;

            let content;
            let brace_token = braced!(content in input);
            let stmts = content.parse()?;

            Ok(ItemFn {
                attrs: outer_attrs,
                vis: vis,
                constness: constness,
                unsafety: unsafety,
                asyncness: asyncness,
                abi: abi,
                ident: ident,
                decl: Box::new(FnDecl {
                    fn_token: fn_token,
                    paren_token: paren_token,
                    inputs: inputs,
                    output: output,
                    variadic: None,
                    generics: Generics {
                        where_clause: where_clause,
                        ..generics
                    },
                }),
                block: Block {
                    brace_token: brace_token,
                    stmts: stmts,
                },
            })
        }
    }
}

mod printing {
    use proc_macro2::TokenStream;
    use quote::{ToTokens, TokenStreamExt};

    use super::*;

    impl ToTokens for Block {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.stmts.clone());
            });
        }
    }

    impl ToTokens for ItemFn {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(&self.attrs);
            self.vis.to_tokens(tokens);
            self.constness.to_tokens(tokens);
            self.unsafety.to_tokens(tokens);
            self.asyncness.to_tokens(tokens);
            self.abi.to_tokens(tokens);
            NamedDecl(&self.decl, &self.ident).to_tokens(tokens);
            self.block.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.block.stmts.clone());
            });
        }
    }

    struct NamedDecl<'a>(&'a FnDecl, &'a Ident);

    impl<'a> ToTokens for NamedDecl<'a> {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.0.fn_token.to_tokens(tokens);
            self.1.to_tokens(tokens);
            self.0.generics.to_tokens(tokens);
            self.0.paren_token.surround(tokens, |tokens| {
                self.0.inputs.to_tokens(tokens);
                if self.0.variadic.is_some() && !self.0.inputs.empty_or_trailing() {
                    <Token![,]>::default().to_tokens(tokens);
                }
                self.0.variadic.to_tokens(tokens);
            });
            self.0.output.to_tokens(tokens);
            self.0.generics.where_clause.to_tokens(tokens);
        }
    }
}
<|endoftext|>


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

extern crate nalgebra;
extern crate munkres;

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

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

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

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

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

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

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

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

    return sum / max_deg as f32;
}

// Calculates x[k+1]
fn next_x(x: &DMat<f32>,
          new_x: &mut DMat<f32>,
          in_a: &[Vec<usize>],
          in_b: &[Vec<usize>],
          out_a: &[Vec<usize>],
          out_b: &[Vec<usize>]) {
    let shape = x.shape();
    assert!(shape == new_x.shape());

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

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

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

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

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

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

    (iter, x)
}

/// Whether the sum of weights is divided by min(degree A, degree B) or max(degree A, degree B)
pub enum ScoreNormalization {
    /// Used as default in the paper.
    MinDegree,

    /// Penalizes the difference in size of graphs.
    MaxDegree,
}

/// Calculates the similiarity of two graphs.
///
/// For parameters see `neighbor_matching_matrix`.
pub fn neighbor_matching_score(in_a: &[Vec<usize>],
                               in_b: &[Vec<usize>],
                               out_a: &[Vec<usize>],
                               out_b: &[Vec<usize>],
                               eps: f32,
                               stop_after_iter: usize,
                               norm: ScoreNormalization)
                               -> (usize, f32) {
    let (iter, x) = neighbor_matching_matrix(in_a, in_b, out_a, out_b, eps, stop_after_iter);
    let n = cmp::min(x.nrows(), x.ncols());
    let m = cmp::max(x.nrows(), x.ncols());
    if n == 0 {
        return (iter, 0.0);
    }
    let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);

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

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

    (iter,
     score /
     match norm {
        ScoreNormalization::MinDegree => n as f32,
        ScoreNormalization::MaxDegree => m as f32,
    })
}

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

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

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

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

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

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

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

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

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

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                ScoreNormalization::MinDegree);
    assert_eq!(iter, 1);

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

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                ScoreNormalization::MaxDegree);
    assert_eq!(iter, 1);

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

extern crate nalgebra;
extern crate munkres;

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

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

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

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

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

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

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

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

    return sum / max_deg as f32;
}

// Calculates x[k+1]
fn next_x(x: &DMat<f32>,
          new_x: &mut DMat<f32>,
          in_a: &[Vec<usize>],
          in_b: &[Vec<usize>],
          out_a: &[Vec<usize>],
          out_b: &[Vec<usize>]) {
    let shape = x.shape();
    assert!(shape == new_x.shape());

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

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

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

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

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

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

    (iter, x)
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


<commit_before>use std::error::FromError;

use std::str::Utf8Error;
use std::string::FromUtf8Error;

use std::io::{Reader, BufReader, IoError};
use std::io::net::ip::IpAddr;

#[derive(Show)]
pub enum Error {
    Io(IoError),
    FormatError(FormatError)
}

#[derive(Show, Copy)]
pub enum FormatError {
    UnknownBlock(u32),
    UnknownOption(u16),
    Utf8Error(Utf8Error)
}

impl FromError<IoError> for Error {
    fn from_error(err: IoError) -> Error {
        Error::Io(err)
    }
}

impl FromError<FromUtf8Error> for Error {
    fn from_error(err: FromUtf8Error) -> Error {
        Error::FormatError(FormatError::Utf8Error(err.utf8_error()))
    }
}

impl FromError<FormatError> for Error {
    fn from_error(err: FormatError) -> Error {
        Error::FormatError(err)
    }
}

#[derive(Show)]
pub enum Block {
    SectionHeader(SectionHeaderBlock),
    InterfaceDescription(InterfaceDescriptionBlock),
    InterfaceStatistics(InterfaceStatisticsBlock),
    EnhancedPacket(EnhancedPacketBlock)
}

#[derive(Show)]
pub struct SectionHeaderBlock {
    /// Magic number equal to 0x1A2B3C4D. This field can be used to detect
    /// sections saved on systems with different endianness.
    pub magic: u32,

    pub major_version: u16,
    pub minor_version: u16,

    /// Length in bytes of the following section excluding this block.
    ///
    /// This block can be used to skip the section for faster navigation in
    /// large files. Length of -1u64 means that the length is unspecified.
    pub section_length: u64,
    pub options: Vec<SectionHeaderOption>
}

#[derive(Show)]
pub enum SectionHeaderOption {
    /// Comment associated with the current block
    Comment(String),

    /// Description of the hardware used to create this section
    Hardware(String),

    /// Name of the operating system used to create this section
    OS(String),

    /// Name of the application used to create this section
    UserApplication(String)
}

/// Block type 1
#[derive(Show)]
pub struct InterfaceDescriptionBlock {
    /// Link layer type of the interface
    pub link_type: u16,

    /// Maximum number of bytes stored from each packet
    pub snap_len: u32,

    pub options: Vec<InterfaceDescriptionOption>
}

#[derive(Show)]
pub enum InterfaceDescriptionOption {
    /// Comment associated with the current block
    Comment(String),

    /// Name of the device used to capture data
    Name(String),

    /// Description of the device used to capture data
    Description(String),

    /// IPv4 interface address and netmask
    Ipv4Addr(u32, u32),

    /// IPv6 interface address and prefix length
    Ipv6Addr(IpAddr, u8),

    /// Hardware MAC address (48 bits)
    MacAddr(u64),

    /// Hardware EUI address
    EuiAddr(u64),

    /// Interface speed in bps
    Speed(u64),

    /// Resolution of timestamps.
    ///
    /// If the MSB is equal to zero, the remaining bits indicate the resolution
    /// as a negative power of 10 (e.g. 6 means microsecond resolution,
    /// timestamps are teh number of microseconds since 1/1/1970).
    ///
    /// If the MSB is equal to one, the remaining bits indicate the resolution
    /// as a negative power of 2 (e.g. 10 means 1/1024 of a second).
    ///
    /// If this options is not present, microsecond resolution is assumed.
    TsResolution(u8),

    /// Timezone for GMT support (?)
    Timezone(u32),

    /// The filter used to capture traffic. The first byte specifies the type
    /// of filter used (e.g. libpcap string, BPF bytecode, etc)
    Filter(u8, Vec<u8>),

    /// Operating system of the machine in which this interface is installed.
    /// This can be different from the Section Header Block if the capture
    /// was done remotely.
    OS(String),

    /// Length of Frame Check Sequence in bits for this interface. For link
    /// layers whose FCS length can change during time, the Packet Block
    /// flags be used.
    FcsLen(u8),

    /// Offset pf the timestamp in seconds
    TsOffset(u64)
}

/// Block type 5
#[derive(Show)]
pub struct InterfaceStatisticsBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    pub options: Vec<InterfaceStatisticsOption>
}

#[derive(Show)]
pub enum InterfaceStatisticsOption {
    /// Comment associated with the current block
    Comment(String),

    /// Time when capture started
    StartTime(u64),

    /// Time when capture ended
    EndTime(u64),

    /// Number of packets received from the physical interface
    Received(u64),

    /// Number of packets dropped by the interface due to the lack of resources
    Dropped(u64),

    /// Number of packets accepted by the filter
    FilterAccepted(u64),

    /// Number of packets dropped by the operating system
    OSDropped(u64),

    /// Number of packets delivered to the user starting. The value in this
    /// field can be different from 'Accepted - Dropped' because some packets
    /// could still be in the OS buffers when the capture ended.
    Delivered(u64)
}

#[derive(Show)]
pub struct EnhancedPacketBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    /// Actual length of the packet when it was transmitted on the network
    pub len: u32,

    pub data: Vec<u8>,
    pub options: Vec<EnhancedPacketBlockOption>
}

#[derive(Show)]
pub enum EnhancedPacketBlockOption {
    Comment(String),
    Flags(u32),
    Hash,

    /// Number of packets lost between the last packet
    DropCount(u64)
}

#[inline(always)]
fn dword_aligned(n: uint) -> uint {
    (n + 3) & !3
}

pub fn read_raw_block(r: &mut Reader) -> Result<(u32, Vec<u8>), IoError> {
    let block_type = try!(r.read_le_u32());

    let total_len = try!(r.read_le_u32());
    let data_len = total_len - 12; // 12 = type + 2*length

    let mut data = try!(r.read_exact(dword_aligned(data_len as uint)));
    data.truncate(data_len as uint);

    assert!(total_len == try!(r.read_le_u32()));

    Ok((block_type, data))
}

fn read_option(r: &mut Reader) -> Result<(u16, Vec<u8>), IoError> {
    let code = try!(r.read_le_u16());
    let len = try!(r.read_le_u16()) as uint;

    let mut data = try!(r.read_exact(dword_aligned(len)));
    data.truncate(len as uint);

    Ok((code, data))
}

pub fn read_block(r: &mut Reader) -> Result<Block, Error> {
    use Block::*;

    let (block_type, data) = try!(read_raw_block(r));
    let mut r = BufReader::new(&*data);

    let r = match block_type {
        0x0A0D0D0A => SectionHeader(try!(SectionHeaderBlock::read(&mut r))),
        1 => InterfaceDescription(try!(InterfaceDescriptionBlock::read(&mut r))),
        5 => InterfaceStatistics(try!(InterfaceStatisticsBlock::read(&mut r))),
        6 => EnhancedPacket(try!(EnhancedPacketBlock::read(&mut r))),
        _ => return Err(FromError::from_error(FormatError::UnknownBlock(block_type)))
    };

    Ok(r)
}

pub struct BlockIter<'a> {
    r: &'a mut (Reader + 'a)
}

pub struct PacketIter<'a> {
    r: &'a mut SimpleReader<'a>
}

pub struct SimpleReader<'a> {
    r: &'a mut (Reader + 'a),

    interfaces: Vec<InterfaceDescriptionBlock>,
    if_offset: uint
}

impl<'a> Iterator for BlockIter<'a> {
    type Item = Block;

    fn next(&mut self) -> Option<Block> {
        match read_block(self.r) {
            Ok(block) => Some(block),
            Err(_) => None
        }
    }
}

type IterPacket<'a> = (&'a InterfaceDescriptionBlock, EnhancedPacketBlock);

impl<'a> Iterator for PacketIter<'a> {
    type Item = IterPacket<'a>;

    fn next(&mut self) -> Option<IterPacket<'a>> {
        while let Ok(block) = read_block(self.r.r) {
            match block {
                Block::SectionHeader(_) => {
                    // Each section is independent from another,
                    // however we might still have live references
                    // to the old interface descriptions so we
                    // can't just clear the vector
                    self.r.if_offset = self.r.interfaces.len()
                },

                Block::InterfaceDescription(id) => self.r.interfaces.push(id),

                Block::EnhancedPacket(ep) => {
                    let iface = &self.r.interfaces[self.r.if_offset + ep.interface_id as uint];
                    unsafe {
                        // The interface description should live as long as
                        // SimpleReader, so this should be safe.
                        let iface = std::mem::transmute(iface);

                        return Some((iface, ep))
                    }
                },
                _ => {}
            }
        }

        None
    }
}

impl<'a> SimpleReader<'a> {
    pub fn new(r: &mut Reader) -> SimpleReader {
        SimpleReader { r: r, interfaces: Vec::new(), if_offset: 0}
    }

    pub fn blocks(&mut self) -> BlockIter {
        BlockIter { r: self.r }
    }

    pub fn packets(&'a mut self) -> PacketIter<'a> {
        PacketIter { r: self }
    }
}

impl SectionHeaderBlock {
    pub fn read(r: &mut BufReader) -> Result<SectionHeaderBlock, Error> {
        let magic = try!(r.read_le_u32());

        assert!(magic == 0x1A2B3C4D, "unsupported endianness");

        let major_version = try!(r.read_le_u16());
        let minor_version = try!(r.read_le_u16());
        let section_length = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use SectionHeaderOption::*;

                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,

                    1...4 => {
                        let s = try!(String::from_utf8(data));

                        match code {
                            1 => Comment(s),
                            2 => Hardware(s),
                            3 => OS(s),
                            4 => UserApplication(s),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(SectionHeaderBlock {
            magic: magic,
            major_version: major_version,
            minor_version: minor_version,
            section_length: section_length,

            options: options
        })
    }
}

impl InterfaceDescriptionBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceDescriptionBlock, Error> {
        let link_type = try!(r.read_le_u16());
        try!(r.read_le_u16()); // reserved
        let snap_len = try!(r.read_le_u32());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceDescriptionOption::*;
                let (code, data) = try!(read_option(r));

                let mut d = &*data;

                let opt = match code {
                    0 => break,
                    1...3 | 12 => {
                        let s = try!(String::from_utf8(data.clone()));

                        match code {
                            1 => Comment(s),
                            2 => Name(s),
                            3 => Description(s),
                            12 => OS(s),
                            _ => unreachable!()
                        }
                    }

                    4 => {
                        let ip = try!(d.read_le_u32());
                        let mask = try!(d.read_le_u32());

                        Ipv4Addr(ip, mask)
                    }

                    6 => MacAddr(try!(d.read_le_uint_n(6))),
                    9 => TsResolution(try!(d.read_byte())),

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceDescriptionBlock {
            link_type: link_type,
            snap_len: snap_len,
            options: options
        })
    }
}

impl EnhancedPacketBlock {
    pub fn read(r: &mut BufReader) -> Result<EnhancedPacketBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());
        let cap_len = try!(r.read_le_u32());
        let len = try!(r.read_le_u32());

        let aligned_len = dword_aligned(cap_len as uint);

        let mut packet_data = try!(r.read_exact(aligned_len));
        packet_data.truncate(cap_len as uint);

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use EnhancedPacketBlockOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    // TODO: rest of the options
                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(EnhancedPacketBlock {
            interface_id: interface_id,
            timestamp: ts,
            len: len,
            data: packet_data,
            options: options
        })
    }
}

impl InterfaceStatisticsBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceStatisticsBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceStatisticsOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    2...8 => {
                        let data = try!((&*data).read_le_u64());

                        match code {
                            2 => StartTime(data),
                            3 => EndTime(data),
                            4 => Received(data),
                            5 => Dropped(data),
                            6 => FilterAccepted(data),
                            7 => OSDropped(data),
                            8 => Delivered(data),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceStatisticsBlock {
            interface_id: interface_id,
            timestamp: ts,
            options: options
        })
    }
}
<commit_msg>Use usize instead of uint<commit_after>use std::error::FromError;

use std::str::Utf8Error;
use std::string::FromUtf8Error;

use std::io::{Reader, BufReader, IoError};
use std::io::net::ip::IpAddr;

#[derive(Show)]
pub enum Error {
    Io(IoError),
    FormatError(FormatError)
}

#[derive(Show, Copy)]
pub enum FormatError {
    UnknownBlock(u32),
    UnknownOption(u16),
    Utf8Error(Utf8Error)
}

impl FromError<IoError> for Error {
    fn from_error(err: IoError) -> Error {
        Error::Io(err)
    }
}

impl FromError<FromUtf8Error> for Error {
    fn from_error(err: FromUtf8Error) -> Error {
        Error::FormatError(FormatError::Utf8Error(err.utf8_error()))
    }
}

impl FromError<FormatError> for Error {
    fn from_error(err: FormatError) -> Error {
        Error::FormatError(err)
    }
}

#[derive(Show)]
pub enum Block {
    SectionHeader(SectionHeaderBlock),
    InterfaceDescription(InterfaceDescriptionBlock),
    InterfaceStatistics(InterfaceStatisticsBlock),
    EnhancedPacket(EnhancedPacketBlock)
}

#[derive(Show)]
pub struct SectionHeaderBlock {
    /// Magic number equal to 0x1A2B3C4D. This field can be used to detect
    /// sections saved on systems with different endianness.
    pub magic: u32,

    pub major_version: u16,
    pub minor_version: u16,

    /// Length in bytes of the following section excluding this block.
    ///
    /// This block can be used to skip the section for faster navigation in
    /// large files. Length of -1u64 means that the length is unspecified.
    pub section_length: u64,
    pub options: Vec<SectionHeaderOption>
}

#[derive(Show)]
pub enum SectionHeaderOption {
    /// Comment associated with the current block
    Comment(String),

    /// Description of the hardware used to create this section
    Hardware(String),

    /// Name of the operating system used to create this section
    OS(String),

    /// Name of the application used to create this section
    UserApplication(String)
}

/// Block type 1
#[derive(Show)]
pub struct InterfaceDescriptionBlock {
    /// Link layer type of the interface
    pub link_type: u16,

    /// Maximum number of bytes stored from each packet
    pub snap_len: u32,

    pub options: Vec<InterfaceDescriptionOption>
}

#[derive(Show)]
pub enum InterfaceDescriptionOption {
    /// Comment associated with the current block
    Comment(String),

    /// Name of the device used to capture data
    Name(String),

    /// Description of the device used to capture data
    Description(String),

    /// IPv4 interface address and netmask
    Ipv4Addr(u32, u32),

    /// IPv6 interface address and prefix length
    Ipv6Addr(IpAddr, u8),

    /// Hardware MAC address (48 bits)
    MacAddr(u64),

    /// Hardware EUI address
    EuiAddr(u64),

    /// Interface speed in bps
    Speed(u64),

    /// Resolution of timestamps.
    ///
    /// If the MSB is equal to zero, the remaining bits indicate the resolution
    /// as a negative power of 10 (e.g. 6 means microsecond resolution,
    /// timestamps are teh number of microseconds since 1/1/1970).
    ///
    /// If the MSB is equal to one, the remaining bits indicate the resolution
    /// as a negative power of 2 (e.g. 10 means 1/1024 of a second).
    ///
    /// If this options is not present, microsecond resolution is assumed.
    TsResolution(u8),

    /// Timezone for GMT support (?)
    Timezone(u32),

    /// The filter used to capture traffic. The first byte specifies the type
    /// of filter used (e.g. libpcap string, BPF bytecode, etc)
    Filter(u8, Vec<u8>),

    /// Operating system of the machine in which this interface is installed.
    /// This can be different from the Section Header Block if the capture
    /// was done remotely.
    OS(String),

    /// Length of Frame Check Sequence in bits for this interface. For link
    /// layers whose FCS length can change during time, the Packet Block
    /// flags be used.
    FcsLen(u8),

    /// Offset pf the timestamp in seconds
    TsOffset(u64)
}

/// Block type 5
#[derive(Show)]
pub struct InterfaceStatisticsBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    pub options: Vec<InterfaceStatisticsOption>
}

#[derive(Show)]
pub enum InterfaceStatisticsOption {
    /// Comment associated with the current block
    Comment(String),

    /// Time when capture started
    StartTime(u64),

    /// Time when capture ended
    EndTime(u64),

    /// Number of packets received from the physical interface
    Received(u64),

    /// Number of packets dropped by the interface due to the lack of resources
    Dropped(u64),

    /// Number of packets accepted by the filter
    FilterAccepted(u64),

    /// Number of packets dropped by the operating system
    OSDropped(u64),

    /// Number of packets delivered to the user starting. The value in this
    /// field can be different from 'Accepted - Dropped' because some packets
    /// could still be in the OS buffers when the capture ended.
    Delivered(u64)
}

#[derive(Show)]
pub struct EnhancedPacketBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    /// Actual length of the packet when it was transmitted on the network
    pub len: u32,

    pub data: Vec<u8>,
    pub options: Vec<EnhancedPacketBlockOption>
}

#[derive(Show)]
pub enum EnhancedPacketBlockOption {
    Comment(String),
    Flags(u32),
    Hash,

    /// Number of packets lost between the last packet
    DropCount(u64)
}

#[inline(always)]
fn dword_aligned(n: usize) -> usize {
    (n + 3) & !3
}

pub fn read_raw_block(r: &mut Reader) -> Result<(u32, Vec<u8>), IoError> {
    let block_type = try!(r.read_le_u32());

    let total_len = try!(r.read_le_u32()) as usize;
    let data_len = total_len - 12; // 12 = type + 2*length

    let mut data = try!(r.read_exact(dword_aligned(data_len)));
    data.truncate(data_len);

    assert!(total_len == try!(r.read_le_u32()) as usize);

    Ok((block_type, data))
}

fn read_option(r: &mut Reader) -> Result<(u16, Vec<u8>), IoError> {
    let code = try!(r.read_le_u16());
    let len = try!(r.read_le_u16()) as usize;

    let mut data = try!(r.read_exact(dword_aligned(len)));
    data.truncate(len);

    Ok((code, data))
}

pub fn read_block(r: &mut Reader) -> Result<Block, Error> {
    use Block::*;

    let (block_type, data) = try!(read_raw_block(r));
    let mut r = BufReader::new(&*data);

    let r = match block_type {
        0x0A0D0D0A => SectionHeader(try!(SectionHeaderBlock::read(&mut r))),
        1 => InterfaceDescription(try!(InterfaceDescriptionBlock::read(&mut r))),
        5 => InterfaceStatistics(try!(InterfaceStatisticsBlock::read(&mut r))),
        6 => EnhancedPacket(try!(EnhancedPacketBlock::read(&mut r))),
        _ => return Err(FromError::from_error(FormatError::UnknownBlock(block_type)))
    };

    Ok(r)
}

pub struct BlockIter<'a> {
    r: &'a mut (Reader + 'a)
}

pub struct PacketIter<'a> {
    r: &'a mut SimpleReader<'a>
}

pub struct SimpleReader<'a> {
    r: &'a mut (Reader + 'a),

    interfaces: Vec<InterfaceDescriptionBlock>,
    if_offset: usize
}

impl<'a> Iterator for BlockIter<'a> {
    type Item = Block;

    fn next(&mut self) -> Option<Block> {
        match read_block(self.r) {
            Ok(block) => Some(block),
            Err(_) => None
        }
    }
}

type IterPacket<'a> = (&'a InterfaceDescriptionBlock, EnhancedPacketBlock);

impl<'a> Iterator for PacketIter<'a> {
    type Item = IterPacket<'a>;

    fn next(&mut self) -> Option<IterPacket<'a>> {
        while let Ok(block) = read_block(self.r.r) {
            match block {
                Block::SectionHeader(_) => {
                    // Each section is independent from another,
                    // however we might still have live references
                    // to the old interface descriptions so we
                    // can't just clear the vector
                    self.r.if_offset = self.r.interfaces.len()
                },

                Block::InterfaceDescription(id) => self.r.interfaces.push(id),

                Block::EnhancedPacket(ep) => {
                    let iface = &self.r.interfaces[self.r.if_offset + ep.interface_id as usize];
                    unsafe {
                        // The interface description should live as long as
                        // SimpleReader, so this should be safe.
                        let iface = std::mem::transmute(iface);

                        return Some((iface, ep))
                    }
                },
                _ => {}
            }
        }

        None
    }
}

impl<'a> SimpleReader<'a> {
    pub fn new(r: &mut Reader) -> SimpleReader {
        SimpleReader { r: r, interfaces: Vec::new(), if_offset: 0}
    }

    pub fn blocks(&mut self) -> BlockIter {
        BlockIter { r: self.r }
    }

    pub fn packets(&'a mut self) -> PacketIter<'a> {
        PacketIter { r: self }
    }
}

impl SectionHeaderBlock {
    pub fn read(r: &mut BufReader) -> Result<SectionHeaderBlock, Error> {
        let magic = try!(r.read_le_u32());

        assert!(magic == 0x1A2B3C4D, "unsupported endianness");

        let major_version = try!(r.read_le_u16());
        let minor_version = try!(r.read_le_u16());
        let section_length = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use SectionHeaderOption::*;

                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,

                    1...4 => {
                        let s = try!(String::from_utf8(data));

                        match code {
                            1 => Comment(s),
                            2 => Hardware(s),
                            3 => OS(s),
                            4 => UserApplication(s),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(SectionHeaderBlock {
            magic: magic,
            major_version: major_version,
            minor_version: minor_version,
            section_length: section_length,

            options: options
        })
    }
}

impl InterfaceDescriptionBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceDescriptionBlock, Error> {
        let link_type = try!(r.read_le_u16());
        try!(r.read_le_u16()); // reserved
        let snap_len = try!(r.read_le_u32());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceDescriptionOption::*;
                let (code, data) = try!(read_option(r));

                let mut d = &*data;

                let opt = match code {
                    0 => break,
                    1...3 | 12 => {
                        let s = try!(String::from_utf8(data.clone()));

                        match code {
                            1 => Comment(s),
                            2 => Name(s),
                            3 => Description(s),
                            12 => OS(s),
                            _ => unreachable!()
                        }
                    }

                    4 => {
                        let ip = try!(d.read_le_u32());
                        let mask = try!(d.read_le_u32());

                        Ipv4Addr(ip, mask)
                    }

                    6 => MacAddr(try!(d.read_le_uint_n(6))),
                    9 => TsResolution(try!(d.read_byte())),

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceDescriptionBlock {
            link_type: link_type,
            snap_len: snap_len,
            options: options
        })
    }
}

impl EnhancedPacketBlock {
    pub fn read(r: &mut BufReader) -> Result<EnhancedPacketBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());
        let cap_len = try!(r.read_le_u32()) as usize;
        let len = try!(r.read_le_u32());

        let aligned_len = dword_aligned(cap_len);

        let mut packet_data = try!(r.read_exact(aligned_len));
        packet_data.truncate(cap_len);

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use EnhancedPacketBlockOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    // TODO: rest of the options
                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(EnhancedPacketBlock {
            interface_id: interface_id,
            timestamp: ts,
            len: len,
            data: packet_data,
            options: options
        })
    }
}

impl InterfaceStatisticsBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceStatisticsBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceStatisticsOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    2...8 => {
                        let data = try!((&*data).read_le_u64());

                        match code {
                            2 => StartTime(data),
                            3 => EndTime(data),
                            4 => Received(data),
                            5 => Dropped(data),
                            6 => FilterAccepted(data),
                            7 => OSDropped(data),
                            8 => Delivered(data),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceStatisticsBlock {
            interface_id: interface_id,
            timestamp: ts,
            options: options
        })
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate rustc_serialize;

mod bot;<commit_msg>make mod pub<commit_after>extern crate hyper;
extern crate rustc_serialize;

pub mod bot;<|endoftext|>


<commit_before>#![feature(pub_restricted)]
#![feature(inclusive_range_syntax, inclusive_range)]
#![feature(type_ascription)]
#![feature(slice_patterns)]

#![allow(unreachable_patterns)]

/// (Macro imports need to appear at the crate root.)
#[macro_use] extern crate lazy_static;

#[macro_use]
extern crate log;

extern crate lalrpop_util;

/// Literate programming stuff goes in `mod lit`.
#[path="lit/src/mod.rs"]
mod lit;

use lit::{attrs};
pub use lit::{directions, find_text, find_path, format};
pub use lit::{grid, path};
pub use lit::{render, svg, text, test_data};

#[cfg(test)]
use lit::{env_logger};
use lit::{regex, treexml};

pub use lit::scene::{Scene, SceneOpts};

pub use lit::default_input::DEFAULT_INPUT as DEFAULT_RULES;

/// LalrPop grammar and its generated goes in `mod grammar`.
mod grammar;

pub use grammar::parse_rules;
<commit_msg>pub_restricted is stable.<commit_after>#![feature(inclusive_range_syntax, inclusive_range)]
#![feature(type_ascription)]
#![feature(slice_patterns)]

#![allow(unreachable_patterns)]

/// (Macro imports need to appear at the crate root.)
#[macro_use] extern crate lazy_static;

#[macro_use]
extern crate log;

extern crate lalrpop_util;

/// Literate programming stuff goes in `mod lit`.
#[path="lit/src/mod.rs"]
mod lit;

use lit::{attrs};
pub use lit::{directions, find_text, find_path, format};
pub use lit::{grid, path};
pub use lit::{render, svg, text, test_data};

#[cfg(test)]
use lit::{env_logger};
use lit::{regex, treexml};

pub use lit::scene::{Scene, SceneOpts};

pub use lit::default_input::DEFAULT_INPUT as DEFAULT_RULES;

/// LalrPop grammar and its generated goes in `mod grammar`.
mod grammar;

pub use grammar::parse_rules;
<|endoftext|>


<commit_before>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![experimental]

use std::slice::bytes::copy_memory;

mod ops;

static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static FONTSET: [u8, .. 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut ch8 = VirtualMachine::new(dump_pixels);
///     // ...
/// ```
pub type DrawCallback<'a> = |pixels: &[u8]|: 'a;

struct KeypressWait {
    wait: bool,
    vx: uint
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>,
    keys: [bool, .. 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false, .. 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(ch8.ram.slice_mut(0u, 5 * 0x10), FONTSET);
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.slice_mut(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as uint),
            0x3 => ops::skip_next_vx_eq(self, x as uint, kk),
            0x4 => ops::skip_next_vx_ne(self, x as uint, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as uint, kk),
            0x7 => ops::add_vx_byte(self, x as uint, kk),
            0x8 => {
                let (x, y) = (x as uint, y as uint);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => fail!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as uint, kk),
            0xD => ops::display_sprite(self, x as uint, y as uint, n as uint),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as uint),
                0x9E => ops::skip_next_key_vx_pressed(self, x as uint),
                _ => fail!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as uint),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as uint),
                    0x15 => ops::set_delay_timer(self, x as uint),
                    0x18 => ops::set_sound_timer(self, x as uint),
                    0x1E => ops::add_vx_to_i(self, x as uint),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as uint),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as uint),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as uint),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as uint),
                    _ => fail!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => fail!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        self.pc += 2;
        b1 as u16 << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<commit_msg>Remove superfluous type annotations from some integer literals<commit_after>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![experimental]

use std::slice::bytes::copy_memory;

mod ops;

static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static FONTSET: [u8, .. 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut ch8 = VirtualMachine::new(dump_pixels);
///     // ...
/// ```
pub type DrawCallback<'a> = |pixels: &[u8]|: 'a;

struct KeypressWait {
    wait: bool,
    vx: uint
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>,
    keys: [bool, .. 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0, .. MEM_SIZE],
            v: [0, .. 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0, .. 16],
            display: [0, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false, .. 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(ch8.ram.slice_mut(0u, 5 * 0x10), FONTSET);
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.slice_mut(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as uint),
            0x3 => ops::skip_next_vx_eq(self, x as uint, kk),
            0x4 => ops::skip_next_vx_ne(self, x as uint, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as uint, kk),
            0x7 => ops::add_vx_byte(self, x as uint, kk),
            0x8 => {
                let (x, y) = (x as uint, y as uint);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => fail!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as uint, kk),
            0xD => ops::display_sprite(self, x as uint, y as uint, n as uint),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as uint),
                0x9E => ops::skip_next_key_vx_pressed(self, x as uint),
                _ => fail!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as uint),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as uint),
                    0x15 => ops::set_delay_timer(self, x as uint),
                    0x18 => ops::set_sound_timer(self, x as uint),
                    0x1E => ops::add_vx_to_i(self, x as uint),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as uint),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as uint),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as uint),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as uint),
                    _ => fail!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => fail!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        self.pc += 2;
        b1 as u16 << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<|endoftext|>