<commit_before>#![crate_id(name="nl", vers="1.0.0", author="Tobias Schottdorf")]
#![feature(macro_rules)]
/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Tobias Bohumir Schottdorf <tobias.schottdorf@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

#![feature(phase)]
#[phase(plugin)]
extern crate regex_macros;
extern crate regex;
extern crate getopts;

use std::os;
use std::io::{stdin};
use std::io::BufferedReader;
use std::io::fs::File;
use std::path::Path;
use getopts::{optopt, optflag, getopts, usage, OptGroup};

#[path="../common/util.rs"]
mod util;
mod helper;

static NAME: &'static str = "nl";
static USAGE: &'static str = "nl [OPTION]... [FILE]...";
// A regular expression matching everything.
static REGEX_DUMMY: &'static regex::Regex = &regex!(r".?");

// Settings store options used by nl to produce its output.
struct Settings {
    // The variables corresponding to the options -h, -b, and -f.
    header_numbering: NumberingStyle,
    body_numbering: NumberingStyle,
    footer_numbering: NumberingStyle,
    // The variable corresponding to -d
    section_delimiter: [char, ..2],
    // The variables corresponding to the options -v, -i, -l, -w.
    starting_line_number: u64,
    line_increment: u64,
    join_blank_lines: u64,
    number_width: uint, // Used with String::from_char, hence uint.
    // The format of the number and the (default value for)
    // renumbering each page.
    number_format: NumberFormat,
    renumber: bool,
    // The string appended to each line number output.
    number_separator: String
}

// NumberingStyle stores which lines are to be numberd.
// The possible options are:
// 1. Number all lines
// 2. Number only nonempty lines
// 3. Don't number any lines at all
// 4. Number all lines that match a basic regular expression.
enum NumberingStyle {
    NumberForAll,
    NumberForNonEmpty,
    NumberForNone,
    NumberForRegularExpression(regex::Regex)
}

// NumberFormat specifies how line numbers are output within their allocated
// space. They are justified to the left or right, in the latter case with
// the option of having all unused space to its left turned into leading zeroes.
enum NumberFormat {
    Left,
    Right,
    RightZero,
}

fn main () {
  os::set_exit_status(uumain(os::args()));
}

pub fn uumain(args: Vec<String>) -> int {
    let possible_options = [
        optopt("b", "body-numbering", "use STYLE for numbering body lines", "STYLE"),
        optopt("d", "section-delimiter", "use CC for separating logical pages", "CC"),
        optopt("f", "footer-numbering", "use STYLE for numbering footer lines", "STYLE"),
        optopt("h", "header-numbering", "use STYLE for numbering header lines", "STYLE"),
        optopt("i", "line-increment", "line number increment at each line", ""),
        optopt("l", "join-blank-lines", "group of NUMBER empty lines counted as one", "NUMBER"),
        optopt("n", "number-format", "insert line numbers according to FORMAT", "FORMAT"),
        optflag("p", "no-renumber", "do not reset line numbers at logical pages"),
        optopt("s", "number-separator", "add STRING after (possible) line number", "STRING"),
        optopt("v", "starting-line-number", "first line number on each logical page", "NUMBER"),
        optopt("w", "number-width", "use NUMBER columns for line numbers", "NUMBER"),
        optflag("", "help", "display this help and exit"),
        optflag("V", "version", "version"),
    ];

    // A mutable settings object, initialized with the defaults.
    let mut settings = Settings {
        header_numbering: NumberForNone,
        body_numbering: NumberForAll,
        footer_numbering: NumberForNone,
        section_delimiter: ['\\', ':'],
        starting_line_number: 1,
        line_increment: 1,
        join_blank_lines: 1,
        number_width: 6,
        number_format: Right,
        renumber: true,
        number_separator: String::from_str("\t"),
    };

    let given_options = match getopts(args.tail(), possible_options) {
        Ok (m) => { m }
        Err(f) => {
            show_error!("{}", f);
            print_usage(possible_options);
            return 1
        }
    };

    if given_options.opt_present("help") {
        print_usage(possible_options);
        return 0;
    }
    if given_options.opt_present("version") { version(); return 0; }

    // Update the settings from the command line options, and terminate the
    // program if some options could not successfully be parsed.
    let parse_errors = helper::parse_options(&mut settings, &given_options);
    if parse_errors.len() > 0 {
        show_error!("Invalid arguments supplied.");
        for message in parse_errors.iter() {
            println!("{}", message.as_slice());
        }
        return 1;
    }

    let files = given_options.free;
    let mut read_stdin = files.is_empty();

    for file in files.iter() {
        if file.as_slice() == "-" {
            // If both file names and '-' are specified, we choose to treat first all
            // regular files, and then read from stdin last.
            read_stdin = true;
            continue
        }
        let path = Path::new(file.as_slice());
        let reader = File::open(&path).unwrap();
        let mut buffer = BufferedReader::new(reader);
        nl(&mut buffer, &settings);
    }

    if read_stdin {
        let mut buffer = BufferedReader::new(stdin());
        nl(&mut buffer, &settings);
    }
    0
}

// nl implements the main functionality for an individual buffer.
fn nl<T: Reader> (reader: &mut BufferedReader<T>, settings: &Settings) {
    let mut line_no = settings.starting_line_number;
    // The current line number's width as a string. Using to_str is inefficient
    // but since we only do it once, it should not hurt.
    let mut line_no_width = line_no.to_str().len();
    let line_no_width_initial = line_no_width;
    // Stores the smallest integer with one more digit than line_no, so that
    // when line_no >= line_no_threshold, we need to use one more digit.
    let mut line_no_threshold = std::num::pow(10, line_no_width) as u64;
    let mut empty_line_count: u64 = 0;
    let fill_char = match settings.number_format {
        RightZero => '0',
        _ => ' '
    };
    // Initially, we use the body's line counting settings
    let mut regex_filter = match settings.body_numbering {
        NumberForRegularExpression(ref re) => re,
        _ => REGEX_DUMMY,
    };
    let mut line_filter = pass_regex;
    for mut l in reader.lines().map(|r| r.unwrap()) {
        // Sanitize the string. We want to print the newline ourselves.
        if l.as_slice().chars().rev().next().unwrap() == '\n' {
            l.pop_char();
        }
        // Next we iterate through the individual chars to see if this
        // is one of the special lines starting a new "section" in the
        // document.
        let line = l.as_slice();
        let mut odd = false;
        // matched_group counts how many copies of section_delimiter
        // this string consists of (0 if there's anything else)
        let mut matched_groups = 0u8;
        for c in line.chars() {
            // If this is a newline character, the loop should end.
            if c == '\n' {
                break;
            }
            // If we have already seen three groups (corresponding to
            // a header) or the current char does not form part of
            // a new group, then this line is not a segment indicator.
            if matched_groups >= 3
                || settings.section_delimiter[std::bool::to_bit::<uint>(odd)] != c {
                matched_groups = 0;
                break;
            }
            if odd {
                // We have seen a new group and count it.
                matched_groups += 1;
            }
            odd = !odd;
        }

        // See how many groups we matched. That will tell us if this is
        // a line starting a new segment, and the number of groups
        // indicates what type of segment.
        if matched_groups > 0 {
            // The current line is a section delimiter, so we output
            // a blank line.
            println!("");
            // However the line does not count as a blank line, so we
            // reset the counter used for --join-blank-lines.
            empty_line_count = 0;
            match *match matched_groups {
                3 => {
                    // This is a header, so we may need to reset the
                    // line number and the line width
                    if settings.renumber {
                        line_no = settings.starting_line_number;
                        line_no_width = line_no_width_initial;
                        line_no_threshold = std::num::pow(10, line_no_width) as u64;
                    }
                    &settings.header_numbering
                },
                1 => {
                    &settings.footer_numbering
                },
                // The only option left is 2, but rust wants
                // a catch-all here.
                _ => {
                    &settings.body_numbering
                }
            } {
                NumberForAll => {
                    line_filter = pass_all;
                },
                NumberForNonEmpty => {
                    line_filter = pass_nonempty;
                },
                NumberForNone => {
                    line_filter = pass_none;
                }
                NumberForRegularExpression(ref re) => {
                    line_filter = pass_regex;
                    regex_filter = re;
                }
            }
            continue;
        }
        // From this point on we format and print a "regular" line.
        if line == "" {
            // The line is empty, which means that we have to care
            // about the --join-blank-lines parameter.
            empty_line_count += 1;
        } else {
            // This saves us from having to check for an empty string
            // in the next selector.
            empty_line_count = 0;
        }
        if !line_filter(line, regex_filter)
            || ( empty_line_count > 0 && empty_line_count < settings.join_blank_lines) {
            // No number is printed for this line. Either we did not
            // want to print one in the first place, or it is a blank
            // line but we are still collecting more blank lines via
            // the option --join-blank-lines.
            println!("{}", line);
            continue;
        }
        // If we make it here, then either we are printing a non-empty
        // line or assigning a line number to an empty line. Either
        // way, start counting empties from zero once more.
        empty_line_count = 0;
        // A line number is to be printed.
        let mut w: uint = 0;
        if settings.number_width > line_no_width {
            w = settings.number_width - line_no_width;
        }
        let fill = String::from_char(w, fill_char);
        match settings.number_format {
            Left => {
                println!("{1}{0}{2}{3}", fill, line_no, settings.number_separator, line)
            },
            _ => {
                println!("{0}{1}{2}{3}", fill, line_no, settings.number_separator, line)
            }
        }
        // Now update the variables for the (potential) next
        // line.
        line_no += settings.line_increment;
        while line_no >= line_no_threshold {
            // The line number just got longer.
            line_no_threshold *= 10;
            line_no_width += 1;
        }

    }
}

fn pass_regex(line: &str, re: &regex::Regex) -> bool {
    re.is_match(line)
}

fn pass_nonempty(line: &str, _: &regex::Regex) -> bool {
    line.len() > 0
}

fn pass_none(_: &str, _: &regex::Regex) -> bool {
    false
}

fn pass_all(_: &str, _: &regex::Regex) -> bool {
    true
}

fn print_usage(opts: &[OptGroup]) {
    println!("{:s}", usage(USAGE, opts));
}

fn version () {
    println!("{} version 1.0.0", NAME);
}
<commit_msg>nl: fix dead_code warning in multicall build<commit_after>#![crate_id(name="nl", vers="1.0.0", author="Tobias Schottdorf")]
#![feature(macro_rules)]
/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Tobias Bohumir Schottdorf <tobias.schottdorf@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

#![feature(phase)]
#[phase(plugin)]
extern crate regex_macros;
extern crate regex;
extern crate getopts;

use std::os;
use std::io::{stdin};
use std::io::BufferedReader;
use std::io::fs::File;
use std::path::Path;
use getopts::{optopt, optflag, getopts, usage, OptGroup};

#[path="../common/util.rs"]
mod util;
mod helper;

static NAME: &'static str = "nl";
static USAGE: &'static str = "nl [OPTION]... [FILE]...";
// A regular expression matching everything.
static REGEX_DUMMY: &'static regex::Regex = &regex!(r".?");

// Settings store options used by nl to produce its output.
struct Settings {
    // The variables corresponding to the options -h, -b, and -f.
    header_numbering: NumberingStyle,
    body_numbering: NumberingStyle,
    footer_numbering: NumberingStyle,
    // The variable corresponding to -d
    section_delimiter: [char, ..2],
    // The variables corresponding to the options -v, -i, -l, -w.
    starting_line_number: u64,
    line_increment: u64,
    join_blank_lines: u64,
    number_width: uint, // Used with String::from_char, hence uint.
    // The format of the number and the (default value for)
    // renumbering each page.
    number_format: NumberFormat,
    renumber: bool,
    // The string appended to each line number output.
    number_separator: String
}

// NumberingStyle stores which lines are to be numberd.
// The possible options are:
// 1. Number all lines
// 2. Number only nonempty lines
// 3. Don't number any lines at all
// 4. Number all lines that match a basic regular expression.
enum NumberingStyle {
    NumberForAll,
    NumberForNonEmpty,
    NumberForNone,
    NumberForRegularExpression(regex::Regex)
}

// NumberFormat specifies how line numbers are output within their allocated
// space. They are justified to the left or right, in the latter case with
// the option of having all unused space to its left turned into leading zeroes.
enum NumberFormat {
    Left,
    Right,
    RightZero,
}

#[allow(dead_code)]
fn main () {
  os::set_exit_status(uumain(os::args()));
}

pub fn uumain(args: Vec<String>) -> int {
    let possible_options = [
        optopt("b", "body-numbering", "use STYLE for numbering body lines", "STYLE"),
        optopt("d", "section-delimiter", "use CC for separating logical pages", "CC"),
        optopt("f", "footer-numbering", "use STYLE for numbering footer lines", "STYLE"),
        optopt("h", "header-numbering", "use STYLE for numbering header lines", "STYLE"),
        optopt("i", "line-increment", "line number increment at each line", ""),
        optopt("l", "join-blank-lines", "group of NUMBER empty lines counted as one", "NUMBER"),
        optopt("n", "number-format", "insert line numbers according to FORMAT", "FORMAT"),
        optflag("p", "no-renumber", "do not reset line numbers at logical pages"),
        optopt("s", "number-separator", "add STRING after (possible) line number", "STRING"),
        optopt("v", "starting-line-number", "first line number on each logical page", "NUMBER"),
        optopt("w", "number-width", "use NUMBER columns for line numbers", "NUMBER"),
        optflag("", "help", "display this help and exit"),
        optflag("V", "version", "version"),
    ];

    // A mutable settings object, initialized with the defaults.
    let mut settings = Settings {
        header_numbering: NumberForNone,
        body_numbering: NumberForAll,
        footer_numbering: NumberForNone,
        section_delimiter: ['\\', ':'],
        starting_line_number: 1,
        line_increment: 1,
        join_blank_lines: 1,
        number_width: 6,
        number_format: Right,
        renumber: true,
        number_separator: String::from_str("\t"),
    };

    let given_options = match getopts(args.tail(), possible_options) {
        Ok (m) => { m }
        Err(f) => {
            show_error!("{}", f);
            print_usage(possible_options);
            return 1
        }
    };

    if given_options.opt_present("help") {
        print_usage(possible_options);
        return 0;
    }
    if given_options.opt_present("version") { version(); return 0; }

    // Update the settings from the command line options, and terminate the
    // program if some options could not successfully be parsed.
    let parse_errors = helper::parse_options(&mut settings, &given_options);
    if parse_errors.len() > 0 {
        show_error!("Invalid arguments supplied.");
        for message in parse_errors.iter() {
            println!("{}", message.as_slice());
        }
        return 1;
    }

    let files = given_options.free;
    let mut read_stdin = files.is_empty();

    for file in files.iter() {
        if file.as_slice() == "-" {
            // If both file names and '-' are specified, we choose to treat first all
            // regular files, and then read from stdin last.
            read_stdin = true;
            continue
        }
        let path = Path::new(file.as_slice());
        let reader = File::open(&path).unwrap();
        let mut buffer = BufferedReader::new(reader);
        nl(&mut buffer, &settings);
    }

    if read_stdin {
        let mut buffer = BufferedReader::new(stdin());
        nl(&mut buffer, &settings);
    }
    0
}

// nl implements the main functionality for an individual buffer.
fn nl<T: Reader> (reader: &mut BufferedReader<T>, settings: &Settings) {
    let mut line_no = settings.starting_line_number;
    // The current line number's width as a string. Using to_str is inefficient
    // but since we only do it once, it should not hurt.
    let mut line_no_width = line_no.to_str().len();
    let line_no_width_initial = line_no_width;
    // Stores the smallest integer with one more digit than line_no, so that
    // when line_no >= line_no_threshold, we need to use one more digit.
    let mut line_no_threshold = std::num::pow(10, line_no_width) as u64;
    let mut empty_line_count: u64 = 0;
    let fill_char = match settings.number_format {
        RightZero => '0',
        _ => ' '
    };
    // Initially, we use the body's line counting settings
    let mut regex_filter = match settings.body_numbering {
        NumberForRegularExpression(ref re) => re,
        _ => REGEX_DUMMY,
    };
    let mut line_filter = pass_regex;
    for mut l in reader.lines().map(|r| r.unwrap()) {
        // Sanitize the string. We want to print the newline ourselves.
        if l.as_slice().chars().rev().next().unwrap() == '\n' {
            l.pop_char();
        }
        // Next we iterate through the individual chars to see if this
        // is one of the special lines starting a new "section" in the
        // document.
        let line = l.as_slice();
        let mut odd = false;
        // matched_group counts how many copies of section_delimiter
        // this string consists of (0 if there's anything else)
        let mut matched_groups = 0u8;
        for c in line.chars() {
            // If this is a newline character, the loop should end.
            if c == '\n' {
                break;
            }
            // If we have already seen three groups (corresponding to
            // a header) or the current char does not form part of
            // a new group, then this line is not a segment indicator.
            if matched_groups >= 3
                || settings.section_delimiter[std::bool::to_bit::<uint>(odd)] != c {
                matched_groups = 0;
                break;
            }
            if odd {
                // We have seen a new group and count it.
                matched_groups += 1;
            }
            odd = !odd;
        }

        // See how many groups we matched. That will tell us if this is
        // a line starting a new segment, and the number of groups
        // indicates what type of segment.
        if matched_groups > 0 {
            // The current line is a section delimiter, so we output
            // a blank line.
            println!("");
            // However the line does not count as a blank line, so we
            // reset the counter used for --join-blank-lines.
            empty_line_count = 0;
            match *match matched_groups {
                3 => {
                    // This is a header, so we may need to reset the
                    // line number and the line width
                    if settings.renumber {
                        line_no = settings.starting_line_number;
                        line_no_width = line_no_width_initial;
                        line_no_threshold = std::num::pow(10, line_no_width) as u64;
                    }
                    &settings.header_numbering
                },
                1 => {
                    &settings.footer_numbering
                },
                // The only option left is 2, but rust wants
                // a catch-all here.
                _ => {
                    &settings.body_numbering
                }
            } {
                NumberForAll => {
                    line_filter = pass_all;
                },
                NumberForNonEmpty => {
                    line_filter = pass_nonempty;
                },
                NumberForNone => {
                    line_filter = pass_none;
                }
                NumberForRegularExpression(ref re) => {
                    line_filter = pass_regex;
                    regex_filter = re;
                }
            }
            continue;
        }
        // From this point on we format and print a "regular" line.
        if line == "" {
            // The line is empty, which means that we have to care
            // about the --join-blank-lines parameter.
            empty_line_count += 1;
        } else {
            // This saves us from having to check for an empty string
            // in the next selector.
            empty_line_count = 0;
        }
        if !line_filter(line, regex_filter)
            || ( empty_line_count > 0 && empty_line_count < settings.join_blank_lines) {
            // No number is printed for this line. Either we did not
            // want to print one in the first place, or it is a blank
            // line but we are still collecting more blank lines via
            // the option --join-blank-lines.
            println!("{}", line);
            continue;
        }
        // If we make it here, then either we are printing a non-empty
        // line or assigning a line number to an empty line. Either
        // way, start counting empties from zero once more.
        empty_line_count = 0;
        // A line number is to be printed.
        let mut w: uint = 0;
        if settings.number_width > line_no_width {
            w = settings.number_width - line_no_width;
        }
        let fill = String::from_char(w, fill_char);
        match settings.number_format {
            Left => {
                println!("{1}{0}{2}{3}", fill, line_no, settings.number_separator, line)
            },
            _ => {
                println!("{0}{1}{2}{3}", fill, line_no, settings.number_separator, line)
            }
        }
        // Now update the variables for the (potential) next
        // line.
        line_no += settings.line_increment;
        while line_no >= line_no_threshold {
            // The line number just got longer.
            line_no_threshold *= 10;
            line_no_width += 1;
        }

    }
}

fn pass_regex(line: &str, re: &regex::Regex) -> bool {
    re.is_match(line)
}

fn pass_nonempty(line: &str, _: &regex::Regex) -> bool {
    line.len() > 0
}

fn pass_none(_: &str, _: &regex::Regex) -> bool {
    false
}

fn pass_all(_: &str, _: &regex::Regex) -> bool {
    true
}

fn print_usage(opts: &[OptGroup]) {
    println!("{:s}", usage(USAGE, opts));
}

fn version () {
    println!("{} version 1.0.0", NAME);
}
<|endoftext|>


<commit_before>
use ndarray::*;

use super::error::*;
use lapack::c::Layout as FFI_Layout;

pub enum Layout {
    C((usize, usize)),
    F((usize, usize)),
}

impl Layout {
    pub fn size(&self) -> (usize, usize) {
        match self {
            &Layout::C(s) => s,
            &Layout::F(s) => s,
        }
    }

    pub fn ffi_size(&self) -> (i32, i32) {
        let (n, m) = self.size();
        (m as i32, n as i32)
    }

    pub fn ffi_layout(&self) -> FFI_Layout {
        match self {
            &Layout::C(_) => FFI_Layout::RowMajor,
            &Layout::F(_) => FFI_Layout::ColumnMajor,
        }
    }
}

pub trait AllocatedArray2D {
    type Scalar;
    fn layout(&self) -> LResult<Layout>;
    fn square_layout(&self) -> LResult<Layout>;
    fn as_allocated(&self) -> LResult<&[Self::Scalar]>;
}

impl<A, S> AllocatedArray2D for ArrayBase<S, Ix2>
    where S: Data<Elem = A>
{
    type Scalar = A;

    fn layout(&self) -> LResult<Layout> {
        let strides = self.strides();
        if ::std::cmp::min(strides[0], strides[1]) != 1 {
            return Err(StrideError::new(strides[0], strides[1]).into());
        }
        if strides[0] < strides[1] {
            Ok(Layout::C((self.rows(), self.cols())))
        } else {
            Ok(Layout::F((self.rows(), self.cols())))
        }
    }

    fn square_layout(&self) -> LResult<Layout> {
        let l = self.layout()?;
        let (n, m) = l.size();
        if n == m {
            Ok(l)
        } else {
            Err(NotSquareError::new(n, m).into())
        }
    }

    fn as_allocated(&self) -> LResult<&[A]> {
        let slice = self.as_slice_memory_order().ok_or(MemoryContError::new())?;
        Ok(slice)
    }
}
<commit_msg>Naming integers<commit_after>
use ndarray::*;

use super::error::*;
use lapack::c::Layout as Layout_;

pub type Row = usize;
pub type Col = usize;

pub type Row_ = i32;
pub type Col_ = i32;

pub enum Layout {
    C((Row, Col)),
    F((Row, Col)),
}

impl Layout {
    pub fn size(&self) -> (Row, Col) {
        match self {
            &Layout::C(s) => s,
            &Layout::F(s) => s,
        }
    }

    pub fn ffi_size(&self) -> (Col_, Row_) {
        let (n, m) = self.size();
        (m as Col_, n as Row_)
    }

    pub fn ffi_layout(&self) -> Layout_ {
        match self {
            &Layout::C(_) => Layout_::RowMajor,
            &Layout::F(_) => Layout_::ColumnMajor,
        }
    }
}

pub trait AllocatedArray2D {
    type Scalar;
    fn layout(&self) -> LResult<Layout>;
    fn square_layout(&self) -> LResult<Layout>;
    fn as_allocated(&self) -> LResult<&[Self::Scalar]>;
}

impl<A, S> AllocatedArray2D for ArrayBase<S, Ix2>
    where S: Data<Elem = A>
{
    type Scalar = A;

    fn layout(&self) -> LResult<Layout> {
        let strides = self.strides();
        if ::std::cmp::min(strides[0], strides[1]) != 1 {
            return Err(StrideError::new(strides[0], strides[1]).into());
        }
        if strides[0] < strides[1] {
            Ok(Layout::C((self.rows(), self.cols())))
        } else {
            Ok(Layout::F((self.rows(), self.cols())))
        }
    }

    fn square_layout(&self) -> LResult<Layout> {
        let l = self.layout()?;
        let (n, m) = l.size();
        if n == m {
            Ok(l)
        } else {
            Err(NotSquareError::new(n, m).into())
        }
    }

    fn as_allocated(&self) -> LResult<&[A]> {
        let slice = self.as_slice_memory_order().ok_or(MemoryContError::new())?;
        Ok(slice)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust-Windows Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

#[macro_export]
macro_rules! wnd_proc_thunk(
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_CREATE) => (
        if $msg == 0x0001 { // WM_CREATE
            let cs = unsafe {
                let pcs = ::std::mem::transmute::<::winapi::LPARAM,
                                                   *const ::winapi::CREATESTRUCTW>($l);
                &(*pcs)
            };
            let ret = $self_.on_create(cs);
            if ret {
                return 0 as ::winapi::LRESULT;
            } else {
                return -1 as ::winapi::LRESULT;
            }
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_DESTROY) => (
        if $msg == 0x0002 { // WM_DESTROY
            $self_.on_destroy();
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SIZE) => (
        if $msg == 0x0005 { // WM_SIZE
            let l = $l as u32;
            let width = (l & 0xFFFF) as isize;
            let height = (l >> 16) as isize;
            $self_.on_size(width, height);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SETFOCUS) => (
        if $msg == 0x0007 { // WM_SETFOCUS
            let w = ::windows::window::Window { wnd: $w as ::winapi::HWND };
            $self_.on_focus(w);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_PAINT) => (
        if $msg == 0x000F { // WM_PAINT
            $self_.on_paint();
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONDOWN) => (
        if $msg == 0x0201 { // WM_LBUTTONDOWN
            let l = $l as u32;
            let x = (l & 0xFFFF) as isize;
            let y = (l >> 16) as isize;
            let flags = $w as u32;
            $self_.on_left_button_down(x, y, flags);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONUP) => (
        if $msg == 0x0202 { // WM_LBUTTONUP
            let l = $l as u32;
            let x = (l & 0xFFFF) as isize;
            let y = (l >> 16) as isize;
            let flags = $w as u32;
            $self_.on_left_button_up(x, y, flags);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYDOWN) => (
        if $msg == 0x0100 { // WM_KEYDOWN
            return $self_.on_key_down($w as u8, $l as u32) as ::winapi::::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYUP) => (
        if $msg == 0x0101 { // WM_KEYUP
            return $self_.on_key_up($w as u8, $l as u32) as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_ERASEBKGND) => (
        if $msg == 0x0014 { // WM_ERASEBKGND
            // Returning 1 means that the background no longer needs erasing.
            return $self_.on_erase_background() as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, ANY) => (
        if let Some(result) = $self_.on_message($msg, $w, $l) {
            return result;
        }
    );
);

#[macro_export]
macro_rules! wnd_proc(
    ($wnd:ident, $win:ident, $($msg:ident),+) => (

    impl ::windows::window::WindowImpl for $wnd {
        fn wnd<'a>(&'a self) -> &'a ::windows::window::Window {
            &self.$win
        }

        fn wnd_mut<'a>(&'a mut self) -> &'a mut ::windows::window::Window {
            &mut self.$win
        }

        fn wnd_proc(&self, msg: ::winapi::UINT, w: ::winapi::WPARAM,
                    l: ::winapi::LPARAM) -> ::winapi::LRESULT {
            $(
                wnd_proc_thunk!(self, msg, w, l, $msg);
            )+
            ::windows::def_window_proc(self.wnd().wnd, msg, w, l)
        }
    }

    )
);
<commit_msg>Find find-and-replace error in keydown handler<commit_after>// Copyright 2015 The Rust-Windows Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

#[macro_export]
macro_rules! wnd_proc_thunk(
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_CREATE) => (
        if $msg == 0x0001 { // WM_CREATE
            let cs = unsafe {
                let pcs = ::std::mem::transmute::<::winapi::LPARAM,
                                                   *const ::winapi::CREATESTRUCTW>($l);
                &(*pcs)
            };
            let ret = $self_.on_create(cs);
            if ret {
                return 0 as ::winapi::LRESULT;
            } else {
                return -1 as ::winapi::LRESULT;
            }
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_DESTROY) => (
        if $msg == 0x0002 { // WM_DESTROY
            $self_.on_destroy();
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SIZE) => (
        if $msg == 0x0005 { // WM_SIZE
            let l = $l as u32;
            let width = (l & 0xFFFF) as isize;
            let height = (l >> 16) as isize;
            $self_.on_size(width, height);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SETFOCUS) => (
        if $msg == 0x0007 { // WM_SETFOCUS
            let w = ::windows::window::Window { wnd: $w as ::winapi::HWND };
            $self_.on_focus(w);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_PAINT) => (
        if $msg == 0x000F { // WM_PAINT
            $self_.on_paint();
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONDOWN) => (
        if $msg == 0x0201 { // WM_LBUTTONDOWN
            let l = $l as u32;
            let x = (l & 0xFFFF) as isize;
            let y = (l >> 16) as isize;
            let flags = $w as u32;
            $self_.on_left_button_down(x, y, flags);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONUP) => (
        if $msg == 0x0202 { // WM_LBUTTONUP
            let l = $l as u32;
            let x = (l & 0xFFFF) as isize;
            let y = (l >> 16) as isize;
            let flags = $w as u32;
            $self_.on_left_button_up(x, y, flags);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYDOWN) => (
        if $msg == 0x0100 { // WM_KEYDOWN
            return $self_.on_key_down($w as u8, $l as u32) as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYUP) => (
        if $msg == 0x0101 { // WM_KEYUP
            return $self_.on_key_up($w as u8, $l as u32) as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_ERASEBKGND) => (
        if $msg == 0x0014 { // WM_ERASEBKGND
            // Returning 1 means that the background no longer needs erasing.
            return $self_.on_erase_background() as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, ANY) => (
        if let Some(result) = $self_.on_message($msg, $w, $l) {
            return result;
        }
    );
);

#[macro_export]
macro_rules! wnd_proc(
    ($wnd:ident, $win:ident, $($msg:ident),+) => (

    impl ::windows::window::WindowImpl for $wnd {
        fn wnd<'a>(&'a self) -> &'a ::windows::window::Window {
            &self.$win
        }

        fn wnd_mut<'a>(&'a mut self) -> &'a mut ::windows::window::Window {
            &mut self.$win
        }

        fn wnd_proc(&self, msg: ::winapi::UINT, w: ::winapi::WPARAM,
                    l: ::winapi::LPARAM) -> ::winapi::LRESULT {
            $(
                wnd_proc_thunk!(self, msg, w, l, $msg);
            )+
            ::windows::def_window_proc(self.wnd().wnd, msg, w, l)
        }
    }

    )
);
<|endoftext|>


<commit_before>//! Data structure for a small block of terrain.

use cgmath;
use cgmath::{Point, Point3, Vector3, Vector, EuclideanVector, Matrix, Aabb, Aabb3};
use isosurface_extraction::dual_contouring;
use num::iter::range_inclusive;
use rand;
use rand::Rng;
use std::f32;
use std::sync::{Arc, Mutex};
use stopwatch;

use common::entity_id;
use common::id_allocator;
use common::voxel;
// TODO: Move the server-only parts to the server, like BLOCK_WIDTH and sample_info.

use block_position;
use lod;

/// Number of LODs
pub const LOD_COUNT: usize = 4;
/// lg(WIDTH)
pub const LG_WIDTH: i16 = 3;
/// The width of a block of terrain.
pub const WIDTH: i32 = 1 << LG_WIDTH;

/// lg(EDGE_SAMPLES)
// NOTE: If there are duplicates here, weird invariants will fail.
// Just remove the LODs if you don't want duplicates.
pub const LG_EDGE_SAMPLES: [u16; LOD_COUNT] = [3, 2, 1, 0];
/// The number of voxels along an axis within a block, indexed by LOD.
pub const EDGE_SAMPLES: [u16; LOD_COUNT] = [
  1 << LG_EDGE_SAMPLES[0],
  1 << LG_EDGE_SAMPLES[1],
  1 << LG_EDGE_SAMPLES[2],
  1 << LG_EDGE_SAMPLES[3],
];

/// The width of a voxel within a block, indexed by LOD.
pub const LG_SAMPLE_SIZE: [i16; LOD_COUNT] = [
  LG_WIDTH - LG_EDGE_SAMPLES[0] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[1] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[2] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[3] as i16,
];

#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
/// [T; 3], but serializable.
pub struct Triangle<T> {
  #[allow(missing_docs)]
  pub v1: T,
  #[allow(missing_docs)]
  pub v2: T,
  #[allow(missing_docs)]
  pub v3: T,
}

/// Construct a triangle.
pub fn tri<T>(v1: T, v2: T, v3: T) -> Triangle<T> {
  Triangle {
    v1: v1,
    v2: v2,
    v3: v3,
  }
}

fn make_bounds(
  v1: &Point3<f32>,
  v2: &Point3<f32>,
  v3: &Point3<f32>,
) -> Aabb3<f32> {
  let minx = f32::min(v1.x, f32::min(v2.x, v3.x));
  let maxx = f32::max(v1.x, f32::max(v2.x, v3.x));

  let miny = f32::min(v1.y, f32::min(v2.y, v3.y));
  let maxy = f32::max(v1.y, f32::max(v2.y, v3.y));

  let minz = f32::min(v1.z, f32::min(v2.z, v3.z));
  let maxz = f32::max(v1.z, f32::max(v2.z, v3.z));

  Aabb3::new(
    // TODO: Remove this - 1.0. It's a temporary hack until voxel collisions work,
    // to avoid zero-height Aabb3s.
    Point3::new(minx, miny - 1.0, minz),
    Point3::new(maxx, maxy, maxz),
  )
}

pub fn voxels_in(bounds: &Aabb3<i32>, lg_size: i16) -> Vec<voxel::bounds::T> {
  let delta = bounds.max().sub_p(bounds.min());

  // assert that lg_size samples fit neatly into the bounds.
  let mod_size = (1 << lg_size) - 1;
  assert!(bounds.min().x & mod_size == 0);
  assert!(bounds.min().y & mod_size == 0);
  assert!(bounds.min().z & mod_size == 0);
  assert!(bounds.max().x & mod_size == 0);
  assert!(bounds.max().y & mod_size == 0);
  assert!(bounds.max().z & mod_size == 0);

  let x_len = delta.x >> lg_size;
  let y_len = delta.y >> lg_size;
  let z_len = delta.z >> lg_size;

  let x_off = bounds.min().x >> lg_size;
  let y_off = bounds.min().y >> lg_size;
  let z_off = bounds.min().z >> lg_size;

  let mut voxels =
    Vec::with_capacity(x_len as usize + y_len as usize + z_len as usize);

  for dx in 0 .. x_len {
  for dy in 0 .. y_len {
  for dz in 0 .. z_len {
    let x = x_off + dx;
    let y = y_off + dy;
    let z = z_off + dz;
    voxels.push(voxel::bounds::new(x, y, z, lg_size));
  }}}
  voxels
}

mod voxel_storage {
  use isosurface_extraction::dual_contouring;

  use common::voxel;

  pub struct T<'a> {
    pub voxels: &'a voxel::tree::T,
  }

  fn get_voxel<'a>(this: &mut T<'a>, bounds: &voxel::bounds::T) -> Option<&'a voxel::T> {
    trace!("fetching {:?}", bounds);
    Some(this.voxels.get(bounds).unwrap_or_else(|| panic!("No entry for {:?}", bounds)))
  }

  impl<'a> dual_contouring::voxel_storage::T<voxel::Material> for T<'a> {
    fn get_material(&mut self, bounds: &voxel::bounds::T) -> Option<voxel::Material> {
      match get_voxel(self, bounds) {
        None => None,
        Some(&voxel::Surface(ref voxel)) => Some(voxel.corner),
        Some(&voxel::Volume(ref material)) => Some(*material),
      }
    }

    fn get_voxel_data(&mut self, bounds: &voxel::bounds::T) -> Option<dual_contouring::voxel_storage::VoxelData> {
      match get_voxel(self, bounds) {
        None => None,
        Some(&voxel::Volume(_)) => panic!("Can't extract voxel data from a volume"),
        Some(&voxel::Surface(ref voxel)) =>
          Some({
            dual_contouring::voxel_storage::VoxelData {
              bounds: *bounds,
              vertex: voxel.surface_vertex.to_world_vertex(&bounds),
              normal: voxel.normal.to_float_normal(),
            }
          })
      }
    }
  }
}

fn place_grass<T, Rng: rand::Rng>(
  polygon: &dual_contouring::polygon::T<T>,
  rng: &mut Rng,
) -> Vec<Grass> {
  let v = &polygon.vertices;
  let normal = v[1].sub_p(&v[0]).cross(&v[2].sub_p(&v[0]));
  let to_middle =
    &v[0].to_vec()
    .add_v(&v[1].to_vec())
    .add_v(&v[2].to_vec())
    .div_s(3.0)
  ;

  let tangent = polygon.vertices[1].sub_p(&polygon.vertices[0]).div_s(2.0);
  // TODO: Point straight up
  let normal = normal.normalize().mul_s(tangent.length());
  let rotate_up: cgmath::Quaternion<f32> = cgmath::Rotation::between_vectors(&cgmath::Vector3::new(0.0, 1.0, 0.0), &normal);
  let rotate_up: cgmath::Matrix4<f32> = From::from(rotate_up);
  let rotate_root: cgmath::Quaternion<f32> = cgmath::Rotation3::from_axis_angle(&normal, cgmath::rad(2.0 * f32::consts::PI * rng.next_f32()));
  let rotate_root: cgmath::Matrix4<f32> = From::from(rotate_root);
  let translate = cgmath::Matrix4::from_translation(&to_middle);
  let model = From::from(translate * rotate_root * rotate_up);

  let billboard_indices = [
    rng.gen_range(0, 9),
    rng.gen_range(0, 9),
    rng.gen_range(0, 9),
  ];
  vec!(
    Grass {
      model_matrix: model,
      tex_ids: billboard_indices,
    }
  )
}

pub fn generate<Rng: rand::Rng>(
  voxels: &voxel::tree::T,
  block_position: &block_position::T,
  lod: lod::T,
  id_allocator: &Mutex<id_allocator::T<entity_id::T>>,
  rng: &mut Rng,
) -> T
{
  stopwatch::time("terrain_mesh::generate", || {
    let mut block = empty();
    {
      let block2 = Arc::make_mut(&mut block);

      let lg_edge_samples = LG_EDGE_SAMPLES[lod.0 as usize];
      let lg_sample_size = LG_SAMPLE_SIZE[lod.0 as usize];

      let low = *block_position.as_pnt();
      let high = low.add_v(&Vector3::new(1, 1, 1));
      let low =
        Point3::new(
          low.x << lg_edge_samples,
          low.y << lg_edge_samples,
          low.z << lg_edge_samples,
        );
      let high =
        Point3::new(
          high.x << lg_edge_samples,
          high.y << lg_edge_samples,
          high.z << lg_edge_samples,
        );

      trace!("low {:?}", low);
      trace!("high {:?}", high);

      {
        let mut edges = |direction, low_x, high_x, low_y, high_y, low_z, high_z| {
          for x in range_inclusive(low_x, high_x) {
          for y in range_inclusive(low_y, high_y) {
          for z in range_inclusive(low_z, high_z) {
            trace!("edge: {:?} {:?}", direction, Point3::new(x, y, z));
            let edge =
              dual_contouring::edge::T {
                low_corner: Point3::new(x, y, z),
                direction: direction,
                lg_size: lg_sample_size,
              };

            let _ =
              dual_contouring::edge::extract(
                &mut voxel_storage::T { voxels: voxels },
                &edge,
                &mut |polygon: dual_contouring::polygon::T<voxel::Material>| {
                  let id = id_allocator::allocate(id_allocator);

                  block2.vertex_coordinates.push(tri(polygon.vertices[0], polygon.vertices[1], polygon.vertices[2]));
                  block2.normals.push(tri(polygon.normals[0], polygon.normals[1], polygon.normals[2]));
                  block2.materials.push(polygon.material as i32);
                  block2.ids.push(id);
                  let v = &polygon.vertices;
                  block2.bounds.push((id, make_bounds(&v[0], &v[1], &v[2])));

                  if polygon.material == voxel::Material::Terrain && lod <= lod::T(1) {
                    for grass in place_grass(&polygon, rng) {
                      let id = id_allocator::allocate(id_allocator);
                      block2.grass.push(grass);
                      block2.grass_ids.push(id);
                    }
                  }
                }
              );
          }}}
        };

        edges(
          dual_contouring::edge::Direction::X,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
        edges(
          dual_contouring::edge::Direction::Y,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
        edges(
          dual_contouring::edge::Direction::Z,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
      }
    }
    block
  })
}

#[derive(Debug, Clone)]
pub struct Grass {
  pub model_matrix: cgmath::Matrix4<f32>,
  pub tex_ids: [u32; 3],
}

#[derive(Debug, Clone)]
/// A small continguous chunk of terrain.
pub struct T2 {
  // These Vecs must all be ordered the same way; each entry is the next triangle.

  /// Position of each vertex.
  pub vertex_coordinates: Vec<Triangle<Point3<f32>>>,
  /// Vertex normals. These should be normalized!
  pub normals: Vec<Triangle<Vector3<f32>>>,
  /// Entity IDs for each triangle.
  pub ids: Vec<entity_id::T>,
  /// Material IDs for each triangle.
  pub materials: Vec<i32>,
  // TODO: Change this back to a HashMap once initial capacity is zero for those.
  /// Per-triangle bounding boxes.
  pub bounds: Vec<(entity_id::T, Aabb3<f32>)>,

  pub grass: Vec<Grass>,
  pub grass_ids: Vec<entity_id::T>,
}

pub type T = Arc<T2>;

/// Construct an empty `T`.
pub fn empty() -> T {
  Arc::new(T2 {
    vertex_coordinates: Vec::new(),
    normals: Vec::new(),

    ids: Vec::new(),
    materials: Vec::new(),
    bounds: Vec::new(),

    grass: Vec::new(),
    grass_ids: Vec::new(),
  })
}
<commit_msg>grass scaling<commit_after>//! Data structure for a small block of terrain.

use cgmath;
use cgmath::{Point, Point3, Vector3, Vector, EuclideanVector, Matrix, Aabb, Aabb3};
use isosurface_extraction::dual_contouring;
use num::iter::range_inclusive;
use rand;
use rand::Rng;
use std::f32;
use std::sync::{Arc, Mutex};
use stopwatch;

use common::entity_id;
use common::id_allocator;
use common::voxel;
// TODO: Move the server-only parts to the server, like BLOCK_WIDTH and sample_info.

use block_position;
use lod;

/// Number of LODs
pub const LOD_COUNT: usize = 4;
/// lg(WIDTH)
pub const LG_WIDTH: i16 = 3;
/// The width of a block of terrain.
pub const WIDTH: i32 = 1 << LG_WIDTH;

/// lg(EDGE_SAMPLES)
// NOTE: If there are duplicates here, weird invariants will fail.
// Just remove the LODs if you don't want duplicates.
pub const LG_EDGE_SAMPLES: [u16; LOD_COUNT] = [3, 2, 1, 0];
/// The number of voxels along an axis within a block, indexed by LOD.
pub const EDGE_SAMPLES: [u16; LOD_COUNT] = [
  1 << LG_EDGE_SAMPLES[0],
  1 << LG_EDGE_SAMPLES[1],
  1 << LG_EDGE_SAMPLES[2],
  1 << LG_EDGE_SAMPLES[3],
];

/// The width of a voxel within a block, indexed by LOD.
pub const LG_SAMPLE_SIZE: [i16; LOD_COUNT] = [
  LG_WIDTH - LG_EDGE_SAMPLES[0] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[1] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[2] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[3] as i16,
];

#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
/// [T; 3], but serializable.
pub struct Triangle<T> {
  #[allow(missing_docs)]
  pub v1: T,
  #[allow(missing_docs)]
  pub v2: T,
  #[allow(missing_docs)]
  pub v3: T,
}

/// Construct a triangle.
pub fn tri<T>(v1: T, v2: T, v3: T) -> Triangle<T> {
  Triangle {
    v1: v1,
    v2: v2,
    v3: v3,
  }
}

fn make_bounds(
  v1: &Point3<f32>,
  v2: &Point3<f32>,
  v3: &Point3<f32>,
) -> Aabb3<f32> {
  let minx = f32::min(v1.x, f32::min(v2.x, v3.x));
  let maxx = f32::max(v1.x, f32::max(v2.x, v3.x));

  let miny = f32::min(v1.y, f32::min(v2.y, v3.y));
  let maxy = f32::max(v1.y, f32::max(v2.y, v3.y));

  let minz = f32::min(v1.z, f32::min(v2.z, v3.z));
  let maxz = f32::max(v1.z, f32::max(v2.z, v3.z));

  Aabb3::new(
    // TODO: Remove this - 1.0. It's a temporary hack until voxel collisions work,
    // to avoid zero-height Aabb3s.
    Point3::new(minx, miny - 1.0, minz),
    Point3::new(maxx, maxy, maxz),
  )
}

pub fn voxels_in(bounds: &Aabb3<i32>, lg_size: i16) -> Vec<voxel::bounds::T> {
  let delta = bounds.max().sub_p(bounds.min());

  // assert that lg_size samples fit neatly into the bounds.
  let mod_size = (1 << lg_size) - 1;
  assert!(bounds.min().x & mod_size == 0);
  assert!(bounds.min().y & mod_size == 0);
  assert!(bounds.min().z & mod_size == 0);
  assert!(bounds.max().x & mod_size == 0);
  assert!(bounds.max().y & mod_size == 0);
  assert!(bounds.max().z & mod_size == 0);

  let x_len = delta.x >> lg_size;
  let y_len = delta.y >> lg_size;
  let z_len = delta.z >> lg_size;

  let x_off = bounds.min().x >> lg_size;
  let y_off = bounds.min().y >> lg_size;
  let z_off = bounds.min().z >> lg_size;

  let mut voxels =
    Vec::with_capacity(x_len as usize + y_len as usize + z_len as usize);

  for dx in 0 .. x_len {
  for dy in 0 .. y_len {
  for dz in 0 .. z_len {
    let x = x_off + dx;
    let y = y_off + dy;
    let z = z_off + dz;
    voxels.push(voxel::bounds::new(x, y, z, lg_size));
  }}}
  voxels
}

mod voxel_storage {
  use isosurface_extraction::dual_contouring;

  use common::voxel;

  pub struct T<'a> {
    pub voxels: &'a voxel::tree::T,
  }

  fn get_voxel<'a>(this: &mut T<'a>, bounds: &voxel::bounds::T) -> Option<&'a voxel::T> {
    trace!("fetching {:?}", bounds);
    Some(this.voxels.get(bounds).unwrap_or_else(|| panic!("No entry for {:?}", bounds)))
  }

  impl<'a> dual_contouring::voxel_storage::T<voxel::Material> for T<'a> {
    fn get_material(&mut self, bounds: &voxel::bounds::T) -> Option<voxel::Material> {
      match get_voxel(self, bounds) {
        None => None,
        Some(&voxel::Surface(ref voxel)) => Some(voxel.corner),
        Some(&voxel::Volume(ref material)) => Some(*material),
      }
    }

    fn get_voxel_data(&mut self, bounds: &voxel::bounds::T) -> Option<dual_contouring::voxel_storage::VoxelData> {
      match get_voxel(self, bounds) {
        None => None,
        Some(&voxel::Volume(_)) => panic!("Can't extract voxel data from a volume"),
        Some(&voxel::Surface(ref voxel)) =>
          Some({
            dual_contouring::voxel_storage::VoxelData {
              bounds: *bounds,
              vertex: voxel.surface_vertex.to_world_vertex(&bounds),
              normal: voxel.normal.to_float_normal(),
            }
          })
      }
    }
  }
}

fn place_grass<T, Rng: rand::Rng>(
  polygon: &dual_contouring::polygon::T<T>,
  rng: &mut Rng,
) -> Vec<Grass> {
  let v = &polygon.vertices;
  let normal = v[1].sub_p(&v[0]).cross(&v[2].sub_p(&v[0]));
  let to_middle =
    &v[0].to_vec()
    .add_v(&v[1].to_vec())
    .add_v(&v[2].to_vec())
    .div_s(3.0)
  ;

  let scale =
    (rng.next_f32() + 1.0) *
         (v[1].sub_p(&v[0]).length())
    .max((v[2].sub_p(&v[0]).length())
    .max((v[2].sub_p(&v[1]).length())));
  let scale = cgmath::Vector3::new(1.0, 0.5, 1.0) * cgmath::Vector3::from_value(scale);
  // TODO: Point straight up
  let normal = normal.normalize();
  let y = cgmath::Vector3::new(0.0, 1.0, 0.0);
  let rotate_up: cgmath::Quaternion<f32> = cgmath::Rotation::between_vectors(&y, &normal);
  let rotate_up: cgmath::Matrix4<f32> = From::from(rotate_up);
  let rotate_root: cgmath::Quaternion<f32> = cgmath::Rotation3::from_axis_angle(&y, cgmath::rad(2.0 * f32::consts::PI * rng.next_f32()));
  let rotate_root: cgmath::Matrix4<f32> = From::from(rotate_root);
  let translate = cgmath::Matrix4::from_translation(&to_middle);
  let mut scale_mat = cgmath::Matrix4::from_value(1.0);
  scale_mat[0][0] = scale[0];
  scale_mat[1][1] = scale[1];
  scale_mat[2][2] = scale[2];
  let model = From::from(translate * rotate_up * rotate_root * scale_mat);

  let billboard_indices = [
    rng.gen_range(0, 9),
    rng.gen_range(0, 9),
    rng.gen_range(0, 9),
  ];
  vec!(
    Grass {
      model_matrix: model,
      tex_ids: billboard_indices,
    }
  )
}

pub fn generate<Rng: rand::Rng>(
  voxels: &voxel::tree::T,
  block_position: &block_position::T,
  lod: lod::T,
  id_allocator: &Mutex<id_allocator::T<entity_id::T>>,
  rng: &mut Rng,
) -> T
{
  stopwatch::time("terrain_mesh::generate", || {
    let mut block = empty();
    {
      let block2 = Arc::make_mut(&mut block);

      let lg_edge_samples = LG_EDGE_SAMPLES[lod.0 as usize];
      let lg_sample_size = LG_SAMPLE_SIZE[lod.0 as usize];

      let low = *block_position.as_pnt();
      let high = low.add_v(&Vector3::new(1, 1, 1));
      let low =
        Point3::new(
          low.x << lg_edge_samples,
          low.y << lg_edge_samples,
          low.z << lg_edge_samples,
        );
      let high =
        Point3::new(
          high.x << lg_edge_samples,
          high.y << lg_edge_samples,
          high.z << lg_edge_samples,
        );

      trace!("low {:?}", low);
      trace!("high {:?}", high);

      {
        let mut edges = |direction, low_x, high_x, low_y, high_y, low_z, high_z| {
          for x in range_inclusive(low_x, high_x) {
          for y in range_inclusive(low_y, high_y) {
          for z in range_inclusive(low_z, high_z) {
            trace!("edge: {:?} {:?}", direction, Point3::new(x, y, z));
            let edge =
              dual_contouring::edge::T {
                low_corner: Point3::new(x, y, z),
                direction: direction,
                lg_size: lg_sample_size,
              };

            let _ =
              dual_contouring::edge::extract(
                &mut voxel_storage::T { voxels: voxels },
                &edge,
                &mut |polygon: dual_contouring::polygon::T<voxel::Material>| {
                  let id = id_allocator::allocate(id_allocator);

                  block2.vertex_coordinates.push(tri(polygon.vertices[0], polygon.vertices[1], polygon.vertices[2]));
                  block2.normals.push(tri(polygon.normals[0], polygon.normals[1], polygon.normals[2]));
                  block2.materials.push(polygon.material as i32);
                  block2.ids.push(id);
                  let v = &polygon.vertices;
                  block2.bounds.push((id, make_bounds(&v[0], &v[1], &v[2])));

                  if polygon.material == voxel::Material::Terrain && lod <= lod::T(1) {
                    for grass in place_grass(&polygon, rng) {
                      let id = id_allocator::allocate(id_allocator);
                      block2.grass.push(grass);
                      block2.grass_ids.push(id);
                    }
                  }
                }
              );
          }}}
        };

        edges(
          dual_contouring::edge::Direction::X,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
        edges(
          dual_contouring::edge::Direction::Y,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
        edges(
          dual_contouring::edge::Direction::Z,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
      }
    }
    block
  })
}

#[derive(Debug, Clone)]
pub struct Grass {
  pub model_matrix: cgmath::Matrix4<f32>,
  pub tex_ids: [u32; 3],
}

#[derive(Debug, Clone)]
/// A small continguous chunk of terrain.
pub struct T2 {
  // These Vecs must all be ordered the same way; each entry is the next triangle.

  /// Position of each vertex.
  pub vertex_coordinates: Vec<Triangle<Point3<f32>>>,
  /// Vertex normals. These should be normalized!
  pub normals: Vec<Triangle<Vector3<f32>>>,
  /// Entity IDs for each triangle.
  pub ids: Vec<entity_id::T>,
  /// Material IDs for each triangle.
  pub materials: Vec<i32>,
  // TODO: Change this back to a HashMap once initial capacity is zero for those.
  /// Per-triangle bounding boxes.
  pub bounds: Vec<(entity_id::T, Aabb3<f32>)>,

  pub grass: Vec<Grass>,
  pub grass_ids: Vec<entity_id::T>,
}

pub type T = Arc<T2>;

/// Construct an empty `T`.
pub fn empty() -> T {
  Arc::new(T2 {
    vertex_coordinates: Vec::new(),
    normals: Vec::new(),

    ids: Vec::new(),
    materials: Vec::new(),
    bounds: Vec::new(),

    grass: Vec::new(),
    grass_ids: Vec::new(),
  })
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::cell::RefCell;
use std::rc::Rc;
use std::collections::HashMap;

use futures::Future;
use tokio_core::reactor::Handle;
use hyper::{Client, Uri};
use hyper_tls::HttpsConnector;

use pool::{Pool, Backend};
use config::Config;
use mgmt::Manager;

#[derive(Clone, Debug)]
pub struct BackendHealth {
    inner: Rc<RefCell<Inner>>,
}

impl BackendHealth {
    pub fn new() -> BackendHealth {
        BackendHealth {
            inner: Rc::new(RefCell::new(Inner {
                pending_active: HashMap::new(),
                pending_down: HashMap::new(),
            }))
        }
    }
}

#[derive(Debug)]
struct Inner {
    pending_active: HashMap<Backend, u64>,
    pending_down: HashMap<Backend, u64>,
}

pub fn run(pool: Pool, handle: &Handle, conf: &Config, manager: Manager, health: BackendHealth) {
    let client = Client::configure()
        .connector(HttpsConnector::new(4, &handle))
        .build(&handle);

    let backends = pool.all();
    let handle1 = handle.clone();
    for backend in backends {
        let manager = manager.clone();
        let handle1 = handle1.clone();
        let server = backend.server();
        let health = health.clone();
        let url = format!("{}{}", server.url(), &conf.health_check.uri_path);
        let url = match Uri::from_str(&url) {
            Ok(url) => url,
            Err(e) => {
                error!("Invalid health check url: {:?}",e);
                if backend.is_active() {
                    let ref mut pending_down = health.inner.borrow_mut().pending_down;
                    let failures = pending_down.entry(backend.clone()).or_insert(0);
                    *failures += 1;

                    if *failures >= conf.health_check.failures {
                        info!("Disabling {:?} in pool", backend);
                        backend.mark_down();
                        let uri = backend.server().url();
                        manager.publish_server_state_down(&uri, handle.clone());
                    }
                }
                continue;
            }
        };

        let allowed_failures = conf.health_check.failures;
        debug!("Health check {:?}", url);
        let req = client.get(url).then(move |res| {
            match res {
                Ok(res) => {
                    debug!("Response: {}", res.status());
                    debug!("Headers: \n{}", res.headers());

                    if res.status().is_success() {
                        if backend.is_down() {
                            let ref mut pending_down = health.inner.borrow_mut().pending_down;
                            let failures = pending_down.entry(backend.clone()).or_insert(0);
                            *failures += 1;

                            if *failures >= allowed_failures {
                                info!("Enabling {:?} in pool", backend);
                                backend.mark_active();
                                let uri = backend.server().url();
                                manager.publish_server_state_active(&uri, handle1.clone());
                            }
                        }
                    } else {
                        if backend.is_active() {
                            let ref mut pending_down = health.inner.borrow_mut().pending_down;
                            let failures = pending_down.entry(backend.clone()).or_insert(0);
                            *failures += 1;

                            if *failures >= allowed_failures {
                                info!("Disabling {:?} in pool", backend);
                                backend.mark_down();
                                let uri = backend.server().url();
                                manager.publish_server_state_down(&uri, handle1.clone());
                            }
                        }
                    }
                    ::futures::finished(())
                }
                Err(e) => {
                    error!("Error connecting to backend: {:?}", e);
                    let ref mut pending_down = health.inner.borrow_mut().pending_down;
                    let failures = pending_down.entry(backend.clone()).or_insert(0);
                    *failures += 1;

                    if *failures >= allowed_failures {
                        info!("Disabling {:?} in pool", backend);
                        backend.mark_down();
                        let uri = backend.server().url();
                        manager.publish_server_state_down(&uri, handle1.clone());
                    }
                    ::futures::finished(())
                }
            }
        });

        handle.spawn(req);
    }
}
<commit_msg>Health check honors consecutive requirement<commit_after>use std::str::FromStr;
use std::cell::RefCell;
use std::rc::Rc;
use std::collections::HashMap;

use futures::Future;
use tokio_core::reactor::Handle;
use hyper::{Client, Uri};
use hyper_tls::HttpsConnector;

use pool::{Pool, Backend};
use config::Config;
use mgmt::Manager;

#[derive(Debug, Clone, Copy)]
enum HealthState {
    Passing(u64),
    Failing(u64)
}

#[derive(Clone, Debug)]
pub struct BackendHealth {
    inner: Rc<RefCell<Inner>>,
}

#[derive(Debug)]
struct Inner {
    health_state: HashMap<Backend, HealthState>,
}

impl BackendHealth {
    pub fn new() -> BackendHealth {
        BackendHealth {
            inner: Rc::new(RefCell::new(Inner {
                health_state: HashMap::new(),
            }))
        }
    }

    pub fn should_mark_active(&self, backend: Backend, required_passes: u64) -> bool {
        let ref mut health_state = self.inner.borrow_mut().health_state;
        let state = health_state.entry(backend.clone()).or_insert(HealthState::Passing(0));

        // rules
        // - if active and passing, then do nothing
        // - if active and failing, then we had a passed health check so reset
        // - if down and passing, then check if we can change state or update consec passes
        // - if down and failing, then increment concsec passing

        if backend.is_active() {
            if let &mut HealthState::Failing(_) = state {
                *state = HealthState::Passing(0);
            }
        } else {
            match state {
                &mut HealthState::Passing(mut consec_passes) => {
                    consec_passes += 1;
                    if consec_passes >= required_passes {
                        *state = HealthState::Passing(0);
                        return true;
                    } else {
                        *state = HealthState::Passing(consec_passes);
                    }
                }
                &mut HealthState::Failing(_) => {
                    *state = HealthState::Passing(1);
                }
            }
        }

        false
    }

    pub fn should_mark_down(&self, backend: Backend, required_failures: u64) -> bool {
        let ref mut health_state = self.inner.borrow_mut().health_state;
        let state = health_state.entry(backend.clone()).or_insert(HealthState::Passing(0));

        // rules
        // - if down and failing, then do nothing
        // - if down and passing, then we had a failed health check so reset
        // - if active and failing, then check if we can change state or update consec failures
        // - if active and passing, then increment consec failing

        if backend.is_down() {
            if let &mut HealthState::Passing(_) = state {
                *state = HealthState::Failing(0);
            }
        } else {
            match state {
                &mut HealthState::Failing(mut consec_failures) => {
                    consec_failures += 1;
                    if consec_failures >= required_failures {
                        *state = HealthState::Failing(0);
                        return true;
                    } else {
                        *state = HealthState::Failing(consec_failures);
                    }
                }
                &mut HealthState::Passing(_) => {
                    *state = HealthState::Failing(1);
                }
            }
        }

        false
    }
}

pub fn run(pool: Pool, handle: &Handle, conf: &Config, manager: Manager, health: BackendHealth) {
    let client = Client::configure()
        .connector(HttpsConnector::new(4, &handle))
        .build(&handle);

    let backends = pool.all();
    let handle1 = handle.clone();
    for backend in backends {
        let manager = manager.clone();
        let handle1 = handle1.clone();
        let server = backend.server();
        let health = health.clone();
        let url = format!("{}{}", server.url(), &conf.health_check.uri_path);
        let url = match Uri::from_str(&url) {
            Ok(url) => url,
            Err(e) => {
                error!("Invalid health check url: {:?}",e);
                if backend.is_active() {
                    info!("Disabling {:?} in pool", backend);
                    backend.mark_down();
                    let uri = backend.server().url();
                    manager.publish_server_state_down(&uri, handle1.clone());
                }
                continue;
            }
        };

        let allowed_failures = conf.health_check.failures;
        let allowed_successes = conf.health_check.passes;
        debug!("Health check {:?}", url);
        let req = client.get(url).then(move |res| {
            match res {
                Ok(res) => {
                    debug!("Response: {}", res.status());
                    debug!("Headers: \n{}", res.headers());

                    if res.status().is_success() {
                        if health.should_mark_active(backend.clone(), allowed_successes) {
                            info!("Enabling {:?} in pool", backend);
                            backend.mark_active();
                            let uri = backend.server().url();
                            manager.publish_server_state_active(&uri, handle1.clone());
                        }
                    } else {
                        if health.should_mark_down(backend.clone(), allowed_failures) {
                            info!("Disabling {:?} in pool", backend);
                            backend.mark_down();
                            let uri = backend.server().url();
                            manager.publish_server_state_down(&uri, handle1.clone());
                        }
                    }
                    ::futures::finished(())
                }
                Err(e) => {
                    error!("Error connecting to backend: {:?}", e);
                    if health.should_mark_down(backend.clone(), allowed_failures) {
                        info!("Disabling {:?} in pool", backend);
                        backend.mark_down();
                        let uri = backend.server().url();
                        manager.publish_server_state_down(&uri, handle1.clone());
                    }
                    ::futures::finished(())
                }
            }
        });

        handle.spawn(req);
    }
}

#[cfg(test)]
mod tests {
    use super::BackendHealth;
    use pool::Backend;
    use server::Server;
    use std::str::FromStr;

    fn backend() -> Backend {
        Backend::new(
            Server::new(
                FromStr::from_str(
                    "http://127.0.0.1:6000
                ").unwrap(),
                false
            )
        )
    }

    #[test]
    fn test_should_mark_active() {
        let backend = backend();
        let passes = 2;

        let health = BackendHealth::new();
        backend.mark_down();
        assert_eq!(false, health.should_mark_active(backend.clone(), passes));
        assert_eq!(true, health.should_mark_active(backend.clone(), passes));
    }

    #[test]
    fn test_should_mark_down() {
        let backend = backend();
        let failures = 2;

        let health = BackendHealth::new();
        assert_eq!(false, health.should_mark_down(backend.clone(), failures));
        assert_eq!(true, health.should_mark_down(backend.clone(), failures));
    }

    #[test]
    fn test_backend_flapping() {
        let backend = backend();
        let passes = 3;
        let failures = 2;

        let health = BackendHealth::new();
        assert_eq!(false, health.should_mark_down(backend.clone(), failures));
        assert_eq!(false, health.should_mark_active(backend.clone(), passes));
        // should not be marked down here because the failures need to be consecutive
        assert_eq!(false, health.should_mark_down(backend.clone(), failures));
        assert_eq!(true, health.should_mark_down(backend.clone(), failures));
    }
}
<|endoftext|>


<commit_before>use prometheus::{Registry, Gauge, Encoder, TextEncoder};
use std::collections::HashMap;

use super::*;
pub struct PrometheusRenderer {
    pub buffer: Vec<u8>,
    registry: prometheus::Registry,
    encoder: prometheus::TextEncoder,
    count: prometheus::Gauge,
    max: prometheus::Gauge,
    min: prometheus::Gauge,
    avg: prometheus::Gauge,
    median: prometheus::Gauge,
    percentile90: prometheus::Gauge,
}

impl PrometheusRenderer {
    pub fn new() -> PrometheusRenderer {
        let registry = prometheus::Registry::new();

        let gauge_names =
            vec!["count", "time_max", "time_min", "time_avg", "time_median", "time_percentile90"];
        let mut gauges = HashMap::new();

        for gauge_name in gauge_names {
            let gauge_name = format!("request_{}", gauge_name);
            let gauge = prometheus::Gauge::new(gauge_name.clone(),
                                               format!("The {} of response times.", gauge_name))
                .unwrap();
            registry.register(Box::new(gauge.clone()));
            gauges.insert(gauge_name, gauge);
        }

        PrometheusRenderer {
            registry: registry,
            buffer: Vec::new(),
            encoder: prometheus::TextEncoder::new(),
            count: gauges.remove("request_count").unwrap(),
            max: gauges.remove("request_time_max").unwrap(),
            min: gauges.remove("request_time_min").unwrap(),
            avg: gauges.remove("request_time_avg").unwrap(),
            median: gauges.remove("request_time_median").unwrap(),
            percentile90: gauges.remove("request_time_percentile90").unwrap(),
        }
    }
}

impl Renderer for PrometheusRenderer {
    fn render(&mut self, result: analyzer::RequestLogAnalyzerResult) {
        self.count.set(result.count as f64);
        self.max.set(result.max as f64);
        self.min.set(result.min as f64);
        self.avg.set(result.avg as f64);
        self.median.set(result.median as f64);
        self.percentile90.set(result.percentile90 as f64);

        let metric_familys = self.registry.gather();

        self.encoder.encode(&metric_familys, &mut self.buffer);
    }
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::prelude::*;
    use std::str;

    use super::*;

    struct MockBuffer {
        write_calls: Vec<String>,
    }

    impl Write for MockBuffer {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            self.write_calls.push(str::from_utf8(buf).unwrap().to_string());
            Ok(buf.len())
        }

        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    fn get_result_fixture() -> analyzer::RequestLogAnalyzerResult {
        analyzer::RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        }
    }

    #[test]
    fn test_instantiation() {
        let renderer = PrometheusRenderer::new();
    }

    #[test]
    fn test_render() {
        let result = get_result_fixture();

        let mut renderer = PrometheusRenderer::new();

        renderer.render(result);

        let buffer_text = str::from_utf8(&renderer.buffer).unwrap();
        assert!(buffer_text.contains("request_count 3"));
        assert!(buffer_text.contains("request_time_max 100"));
        assert!(buffer_text.contains("request_time_min 1"));
        assert!(buffer_text.contains("request_time_avg 37"));
        assert!(buffer_text.contains("request_time_median 10"));
        assert!(buffer_text.contains("request_time_percentile90 100"));
    }
}
<commit_msg>Cleaner creation and more complete tests<commit_after>use prometheus::{Registry, Gauge, Encoder, TextEncoder};
use std::collections::HashMap;

use super::*;
pub struct PrometheusRenderer {
    pub buffer: Vec<u8>,
    registry: prometheus::Registry,
    encoder: prometheus::TextEncoder,
    count: prometheus::Gauge,
    max: prometheus::Gauge,
    min: prometheus::Gauge,
    avg: prometheus::Gauge,
    median: prometheus::Gauge,
    percentile90: prometheus::Gauge,
}

impl PrometheusRenderer {
    pub fn new() -> PrometheusRenderer {
        fn make_and_register_gauge(gauge_name: &str,
                                   registry: &prometheus::Registry)
                                   -> prometheus::Gauge {
            let gauge = prometheus::Gauge::new(String::from(gauge_name),
                                               format!("The {} of response times.", gauge_name))
                .expect("Failed to create Prometheus gauge.");

            registry.register(Box::new(gauge.clone()));
            gauge
        }

        let registry = prometheus::Registry::new();

        PrometheusRenderer {
            buffer: Vec::new(),
            encoder: prometheus::TextEncoder::new(),
            count: make_and_register_gauge("request_count", &registry),
            max: make_and_register_gauge("request_time_max", &registry),
            min: make_and_register_gauge("request_time_min", &registry),
            avg: make_and_register_gauge("request_time_avg", &registry),
            median: make_and_register_gauge("request_time_median", &registry),
            percentile90: make_and_register_gauge("request_time_percentile90", &registry),
            registry: registry,
        }
    }
}

impl Renderer for PrometheusRenderer {
    fn render(&mut self, result: analyzer::RequestLogAnalyzerResult) {
        self.count.set(result.count as f64);
        self.max.set(result.max as f64);
        self.min.set(result.min as f64);
        self.avg.set(result.avg as f64);
        self.median.set(result.median as f64);
        self.percentile90.set(result.percentile90 as f64);

        let metric_familys = self.registry.gather();

        self.encoder.encode(&metric_familys, &mut self.buffer);
    }
}

#[cfg(test)]
mod tests {
    use std::str;
    use super::*;

    #[test]
    fn test_render_1() {
        let result = analyzer::RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        };

        let mut renderer = PrometheusRenderer::new();
        renderer.render(result);

        let buffer_text = str::from_utf8(&renderer.buffer).unwrap();
        assert!(buffer_text.contains("request_count 3"));
        assert!(buffer_text.contains("request_time_max 100"));
        assert!(buffer_text.contains("request_time_min 1"));
        assert!(buffer_text.contains("request_time_avg 37"));
        assert!(buffer_text.contains("request_time_median 10"));
        assert!(buffer_text.contains("request_time_percentile90 100"));
    }

    #[test]
    fn test_render_2() {
        let result = analyzer::RequestLogAnalyzerResult {
            count: 300,
            max: 1000,
            min: 10,
            avg: 42,
            median: 75,
            percentile90: 900,
        };

        let mut renderer = PrometheusRenderer::new();
        renderer.render(result);

        let buffer_text = str::from_utf8(&renderer.buffer).unwrap();
        assert!(buffer_text.contains("request_count 300"));
        assert!(buffer_text.contains("request_time_max 1000"));
        assert!(buffer_text.contains("request_time_min 10"));
        assert!(buffer_text.contains("request_time_avg 42"));
        assert!(buffer_text.contains("request_time_median 75"));
        assert!(buffer_text.contains("request_time_percentile90 900"));
    }
}
<|endoftext|>


<commit_before>/// Parser

use std::char;

/// A regular expression AST.
#[deriving(ToStr)]
pub enum Expr {
    Empty,
    Range(char, char),
    Concatenate(~[Expr]),
    Alternate(~[Expr]),
    Repeat(~Expr, uint, Option<uint>, Greedy),
    Capture(~Expr),
    Assertion(AssertType, ~Expr)
}

#[deriving(ToStr)]
pub enum Greedy {
    NonGreedy,
    Greedy
}

#[deriving(ToStr)]
pub enum AssertType {
    Positive,
    Negative
}

/// Parse a regular expression into an AST.  Fails on invalid syntax.
pub fn parse(input: &str) -> Expr {
    let mut s = State::new(input);
    let e = p_alternate(&mut s);
    if s.has_input() {
        // p_alternate() only terminates on an empty string or an extra
        // paren.  Since the string isn't empty, we infer the latter.
        fail!("unbalanced parenthesis")
    } else {
        e
    }
}

/// The parser state.  This tracks the position in the input string.
#[deriving(Clone)]
struct State<'a> {
    input: &'a str,
    prev: Option<&'a str>  // See `State::retreat`
}

impl<'a> State<'a> {
    fn new<'a>(input: &'a str) -> State<'a> {
        State {
            input: input,
            prev: None
        }
    }

    /// Consume and return the next character in the input, returning
    /// `None` if empty.
    fn advance(&mut self) -> Option<char> {
        self.prev = Some(self.input);
        if self.has_input() {
            let (c, input_) = self.input.slice_shift_char();
            self.input = input_;
            Some(c)
        } else {
            None
        }
    }

    /// Push the previously read character back onto the input.  This
    /// can only be called immediately after `advance`.
    fn retreat(&mut self) {
        self.input = self.prev.expect("nowhere to retreat");
        self.prev = None;
    }

    /// Return `true` if there is input remaining.
    fn has_input(&self) -> bool {
        self.input.len() > 0
    }
}

/// Parse alternation, e.g. `ducks|geese|swans`.
///
/// An alternation consists of zero or more concatenations, separated by
/// vertical bars `|`.
///
fn p_alternate(s: &mut State) -> Expr {
    let mut items: ~[Expr] = ~[];

    loop {
        items.push(p_concatenate(s));
        match s.advance() {
            Some(c) => {
                match c {
                    ')' => { s.retreat(); break },
                    '|' => continue,
                    _ => fail!("something bad happened; it's really bad")
                }
            },
            None => break
        }
    }

    match items {
        [] => Empty,
        [e] => e,
        _ => Alternate(items)
    }
}

/// Parse concatenation, e.g. `abc`.
fn p_concatenate(s: &mut State) -> Expr {
    let mut items: ~[Expr] = ~[];

    loop {
        match s.advance() {
            Some(c) => match c {
                '|' | ')' => { s.retreat(); break },
                '(' => push_ignore_empty(&mut items, p_group(s)),
                '.' => items.push(Range('\0', char::MAX)),
                '?' => {
                    let e = pop_expr(&mut items);
                    items.push(match e {
                        Repeat(_, _, _, NonGreedy) => fail!("multiple repeat"),
                        Repeat(inner, min, max, Greedy) =>
                            Repeat(inner, min, max, NonGreedy),
                        _ => Repeat(~e, 0, Some(1), Greedy)
                    })
                },
                '+' => add_repeat(&mut items, 1, None),
                '*' => add_repeat(&mut items, 0, None),
                '{' => match p_repetition(s) {
                    Some((min, max)) => add_repeat(&mut items, min, max),
                    None => items.push(Range(c, c))
                },
                _ => items.push(Range(c, c))
            },
            None => break
        }
    }

    match items {
        [] => Empty,
        [e] => e,
        _ => Concatenate(items)
    }
}

#[inline]
fn push_ignore_empty(items: &mut ~[Expr], e: Expr) {
    match e {
        Empty => {},
        _ => items.push(e)
    }
}

#[inline]
fn pop_expr(items: &mut ~[Expr]) -> Expr {
    items.pop_opt().expect("nothing to repeat")
}

#[inline]
fn add_repeat(items: &mut ~[Expr], min: uint, max: Option<uint>) {
    let e = pop_expr(items);
    items.push(match e {
        Repeat(..) => fail!("multiple repeat"),
        _ => Repeat(~e, min, max, Greedy)
    })
}

/// Parse a counted repetition (e.g. `a{2,3}`), sans the opening brace.
///
/// The following syntaxes are accepted:
///
/// * `{N}` – match exactly N repetitions;
/// * `{M,}` – at least M;
/// * `{,N}` – at most N;
/// * `{M,N}` – from M to N inclusive;
/// * `{,}` – zero or more (synonymous with `*`).
///
/// If parsing fails, return `None` without consuming input.  This
/// matches Python behavior, where invalid repetitions are ignored.
///
fn p_repetition(s_outer: &mut State) -> Option<(uint, Option<uint>)> {
    // Clone the parser state, so we can backtrack on failure
    let mut s = s_outer.clone();

    let result = {
        let min = p_number(&mut s);
        match s.advance() {
            Some(',') => {
                let max = p_number(&mut s);
                match s.advance() {
                    // {} or {N,} or {,M} or {N,M}
                    Some('}') => Some((min.unwrap_or(0), max)),
                    _ => None
                }
            },
            Some('}') => match min {
                // {N}
                Some(n) => Some((n, Some(n))),
                _ => None
            },
            _ => None
        }
    };

    if result.is_some() {
        // Only consume input if parsing was successful
        s_outer.clone_from(&s);
    }

    result
}

/// Parse a non-negative integer, returning `None` on failure.
fn p_number(s: &mut State) -> Option<uint> {
    let mut acc = None;
    loop {
        match s.advance() {
            Some(c) if '0' <= c && c <= '9' => {
                let digit = c as uint - '0' as uint;
                acc = Some(match acc {
                    Some(n) => 10 * n + digit,
                    None => digit
                });
            },
            _ => { s.retreat(); break }
        }
    }
    acc
}

/// Parse a group (e.g. `(hello)`), sans the opening parenthesis.
fn p_group(s: &mut State) -> Expr {
    let result = match s.advance() {
        Some('?') => match s.advance() {
            Some(c) => match c {
                ':' => p_alternate(s),
                '#' => p_comment(s),
                '=' => Assertion(Positive, ~p_alternate(s)),
                '!' => Assertion(Negative, ~p_alternate(s)),
                _ => fail!(format!("unknown extension: ?{}", c))
            },
            None => fail!("unexpected end of pattern")
        },
        _ => { s.retreat(); Capture(~p_alternate(s)) }
    };

    // Match the closing paren
    match s.advance() {
        Some(')') => result,
        _ => fail!("mismatched parenthesis")
    }
}

/// Consume all input up to the first closing parenthesis, and return
/// `Empty`.
fn p_comment(s: &mut State) -> Expr {
    loop {
        match s.advance() {
            Some(c) if c != ')' => continue,
            _ => { s.retreat(); break }
        }
    }
    Empty
}
<commit_msg>Parse escape sequences<commit_after>/// Parser

use std::char;

use charclass::CharClass;
use charclass::ascii;

/// A regular expression AST.
#[deriving(ToStr)]
pub enum Expr {
    Empty,
    Range(char, char),
    Concatenate(~[Expr]),
    Alternate(~[Expr]),
    Repeat(~Expr, uint, Option<uint>, Greedy),
    Capture(~Expr),
    Assertion(AssertType, ~Expr)
}

#[deriving(ToStr)]
pub enum Greedy {
    NonGreedy,
    Greedy
}

#[deriving(ToStr)]
pub enum AssertType {
    Positive,
    Negative
}

/// Parse a regular expression into an AST.  Fails on invalid syntax.
pub fn parse(input: &str) -> Expr {
    let mut s = State::new(input);
    let e = p_alternate(&mut s);
    if s.has_input() {
        // p_alternate() only terminates on an empty string or an extra
        // paren.  Since the string isn't empty, we infer the latter.
        fail!("unbalanced parenthesis")
    } else {
        e
    }
}

/// The parser state.  This tracks the position in the input string.
#[deriving(Clone)]
struct State<'a> {
    input: &'a str,
    prev: Option<&'a str>  // See `State::retreat`
}

impl<'a> State<'a> {
    fn new<'a>(input: &'a str) -> State<'a> {
        State {
            input: input,
            prev: None
        }
    }

    /// Consume and return the next character in the input, returning
    /// `None` if empty.
    fn advance(&mut self) -> Option<char> {
        self.prev = Some(self.input);
        if self.has_input() {
            let (c, input_) = self.input.slice_shift_char();
            self.input = input_;
            Some(c)
        } else {
            None
        }
    }

    /// Push the previously read character back onto the input.  This
    /// can only be called immediately after `advance`.
    fn retreat(&mut self) {
        self.input = self.prev.expect("nowhere to retreat");
        self.prev = None;
    }

    /// Return `true` if there is input remaining.
    fn has_input(&self) -> bool {
        self.input.len() > 0
    }
}

/// Parse alternation, e.g. `ducks|geese|swans`.
///
/// An alternation consists of zero or more concatenations, separated by
/// vertical bars `|`.
///
fn p_alternate(s: &mut State) -> Expr {
    let mut items: ~[Expr] = ~[];

    loop {
        items.push(p_concatenate(s));
        match s.advance() {
            Some(c) => {
                match c {
                    ')' => { s.retreat(); break },
                    '|' => continue,
                    _ => fail!("something bad happened; it's really bad")
                }
            },
            None => break
        }
    }

    match items {
        [] => Empty,
        [e] => e,
        _ => Alternate(items)
    }
}

/// Parse concatenation, e.g. `abc`.
fn p_concatenate(s: &mut State) -> Expr {
    let mut items: ~[Expr] = ~[];

    loop {
        match s.advance() {
            Some(c) => match c {
                '|' | ')' => { s.retreat(); break },
                '(' => push_ignore_empty(&mut items, p_group(s)),
                '.' => items.push(Range('\0', char::MAX)),
                '\\' => items.push(cc_to_expr(p_escape(s))),
                '?' => {
                    let e = pop_expr(&mut items);
                    items.push(match e {
                        Repeat(_, _, _, NonGreedy) => fail!("multiple repeat"),
                        Repeat(inner, min, max, Greedy) =>
                            Repeat(inner, min, max, NonGreedy),
                        _ => Repeat(~e, 0, Some(1), Greedy)
                    })
                },
                '+' => add_repeat(&mut items, 1, None),
                '*' => add_repeat(&mut items, 0, None),
                '{' => match p_repetition(s) {
                    Some((min, max)) => add_repeat(&mut items, min, max),
                    None => items.push(Range(c, c))
                },
                _ => items.push(Range(c, c))
            },
            None => break
        }
    }

    match items {
        [] => Empty,
        [e] => e,
        _ => Concatenate(items)
    }
}

#[inline]
fn push_ignore_empty(items: &mut ~[Expr], e: Expr) {
    match e {
        Empty => {},
        _ => items.push(e)
    }
}

#[inline]
fn pop_expr(items: &mut ~[Expr]) -> Expr {
    items.pop_opt().expect("nothing to repeat")
}

#[inline]
fn add_repeat(items: &mut ~[Expr], min: uint, max: Option<uint>) {
    let e = pop_expr(items);
    items.push(match e {
        Repeat(..) => fail!("multiple repeat"),
        _ => Repeat(~e, min, max, Greedy)
    })
}

/// Parse a counted repetition (e.g. `a{2,3}`), sans the opening brace.
///
/// The following syntaxes are accepted:
///
/// * `{N}` – match exactly N repetitions;
/// * `{M,}` – at least M;
/// * `{,N}` – at most N;
/// * `{M,N}` – from M to N inclusive;
/// * `{,}` – zero or more (synonymous with `*`).
///
/// If parsing fails, return `None` without consuming input.  This
/// matches Python behavior, where invalid repetitions are ignored.
///
fn p_repetition(s_outer: &mut State) -> Option<(uint, Option<uint>)> {
    // Clone the parser state, so we can backtrack on failure
    let mut s = s_outer.clone();

    let result = {
        let min = p_number(&mut s);
        match s.advance() {
            Some(',') => {
                let max = p_number(&mut s);
                match s.advance() {
                    // {} or {N,} or {,M} or {N,M}
                    Some('}') => Some((min.unwrap_or(0), max)),
                    _ => None
                }
            },
            Some('}') => match min {
                // {N}
                Some(n) => Some((n, Some(n))),
                _ => None
            },
            _ => None
        }
    };

    if result.is_some() {
        // Only consume input if parsing was successful
        s_outer.clone_from(&s);
    }

    result
}

/// Parse a non-negative integer, returning `None` on failure.
fn p_number(s: &mut State) -> Option<uint> {
    let mut acc = None;
    loop {
        match s.advance() {
            Some(c) if '0' <= c && c <= '9' => {
                let digit = c as uint - '0' as uint;
                acc = Some(match acc {
                    Some(n) => 10 * n + digit,
                    None => digit
                });
            },
            _ => { s.retreat(); break }
        }
    }
    acc
}

/// Parse a group (e.g. `(hello)`), sans the opening parenthesis.
fn p_group(s: &mut State) -> Expr {
    let result = match s.advance() {
        Some('?') => match s.advance() {
            Some(c) => match c {
                ':' => p_alternate(s),
                '#' => p_comment(s),
                '=' => Assertion(Positive, ~p_alternate(s)),
                '!' => Assertion(Negative, ~p_alternate(s)),
                _ => fail!(format!("unknown extension: ?{}", c))
            },
            None => fail!("unexpected end of pattern")
        },
        _ => { s.retreat(); Capture(~p_alternate(s)) }
    };

    // Match the closing paren
    match s.advance() {
        Some(')') => result,
        _ => fail!("mismatched parenthesis")
    }
}

/// Consume all input up to the first closing parenthesis, and return
/// `Empty`.
fn p_comment(s: &mut State) -> Expr {
    loop {
        match s.advance() {
            Some(c) if c != ')' => continue,
            _ => { s.retreat(); break }
        }
    }
    Empty
}

/// Parse an escape sequence (e.g. `\d`), sans the leading backslash.
fn p_escape(s: &mut State) -> CharClass {
    match s.advance() {
        Some(c) => match c {
            'n' => CharClass::from_char('\n'),
            'r' => CharClass::from_char('\r'),
            't' => CharClass::from_char('\t'),

            'd' => ascii::digit,
            's' => ascii::space,
            'w' => ascii::word,

            'x' => p_hex_escape(s, 2),
            'u' => p_hex_escape(s, 4),
            'U' => p_hex_escape(s, 8),

            _ => fail!("invalid escape")
        },
        None => fail!("invalid escape")
    }
}

fn p_hex_escape(s: &mut State, n_digits: uint) -> CharClass {
    let mut acc = 0u32;
    for _ in range(0, n_digits) {
        acc = 16 * acc + match s.advance() {
            Some(c) => c.to_digit(16).expect("invalid escape") as u32,
            _ => fail!("invalid escape")
        };
    }
    let c = char::from_u32(acc).expect("character out of range");
    CharClass::from_char(c)
}

/// Reify a character class as an `Expr`.
fn cc_to_expr(cc: CharClass) -> Expr {
    Alternate(cc.ranges().iter().map(|&(lo, hi)| Range(lo, hi)).collect())
}
<|endoftext|>


<commit_before>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
//! this ALWAYS GENERATED file contains the definitions for the interfaces
#[repr(i32)] #[derive(Clone, Copy, Debug)]
pub enum EDataFlow {
    eRender,
    eCapture,
    eAll,
    EDataFlow_enum_count,
}
#[repr(i32)] #[derive(Clone, Copy, Debug)]
pub enum ERole {
    eConsole,
    eMultimedia,
    eCommunications,
    ERole_enum_count,
}
DEFINE_GUID!(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C,
    0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
DEFINE_GUID!(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35,
    0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
RIDL!(
interface IMMDevice(IMMDeviceVtbl): IUnknown(IUnknownVtbl) {
    fn Activate(
        &mut self, iid: ::REFIID, dwClsCtx: ::DWORD, pActivationParams: *mut ::PROPVARIANT,
        ppInterface: *mut ::LPVOID
    ) -> ::HRESULT,
    fn OpenPropertyStore(
        &mut self, stgmAccess: ::DWORD, ppProperties: *mut *mut ::IPropertyStore
    ) -> ::HRESULT,
    fn GetId(&mut self, ppstrId: *mut ::LPWSTR) -> ::HRESULT,
    fn GetState(&mut self, pdwState: *mut ::DWORD) -> ::HRESULT
}
);
RIDL!(
interface IMMDeviceEnumerator(IMMDeviceEnumeratorVtbl): IUnknown(IUnknownVtbl) {
    fn EnumAudioEndpoints(
        &mut self, dataFlow: EDataFlow, dwStateMask: ::DWORD,
        ppDevices: *mut *mut IMMDeviceCollection
    ) -> ::HRESULT,
    fn GetDefaultAudioEndpoint(
        &mut self, dataFlow: EDataFlow, role: ERole, ppEndpoint: *mut *mut IMMDevice
    ) -> ::HRESULT,
    fn GetDevice(&mut self, pwstrId: ::LPCWSTR, ppDevices: *mut *mut IMMDevice) -> ::HRESULT,
    fn RegisterEndpointNotificationCallback(
        &mut self, pClient: *mut IMMNotificationClient
    ) -> ::HRESULT,
    fn UnregisterEndpointNotificationCallback(
        &mut self, pClient: *mut IMMNotificationClient
    ) -> ::HRESULT
}
);
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct IMMDeviceCollection;
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct IMMNotificationClient;
<commit_msg>Add some definitions to mmdeviceapi<commit_after>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
//! this ALWAYS GENERATED file contains the definitions for the interfaces
pub const DEVICE_STATE_ACTIVE: ::DWORD = 0x00000001;
pub const DEVICE_STATE_DISABLED: ::DWORD = 0x00000002;
pub const DEVICE_STATE_NOTPRESENT: ::DWORD = 0x00000004;
pub const DEVICE_STATE_UNPLUGGED: ::DWORD = 0x00000008;
pub const DEVICE_STATEMASK_ALL: ::DWORD = 0x0000000F;

#[repr(i32)] #[derive(Clone, Copy, Debug)]
pub enum EDataFlow {
    eRender,
    eCapture,
    eAll,
    EDataFlow_enum_count,
}
#[repr(i32)] #[derive(Clone, Copy, Debug)]
pub enum ERole {
    eConsole,
    eMultimedia,
    eCommunications,
    ERole_enum_count,
}
DEFINE_GUID!(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C,
    0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
DEFINE_GUID!(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35,
    0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
RIDL!(
interface IMMDevice(IMMDeviceVtbl): IUnknown(IUnknownVtbl) {
    fn Activate(
        &mut self, iid: ::REFIID, dwClsCtx: ::DWORD, pActivationParams: *mut ::PROPVARIANT,
        ppInterface: *mut ::LPVOID
    ) -> ::HRESULT,
    fn OpenPropertyStore(
        &mut self, stgmAccess: ::DWORD, ppProperties: *mut *mut ::IPropertyStore
    ) -> ::HRESULT,
    fn GetId(&mut self, ppstrId: *mut ::LPWSTR) -> ::HRESULT,
    fn GetState(&mut self, pdwState: *mut ::DWORD) -> ::HRESULT
}
);
RIDL!(
interface IMMDeviceEnumerator(IMMDeviceEnumeratorVtbl): IUnknown(IUnknownVtbl) {
    fn EnumAudioEndpoints(
        &mut self, dataFlow: EDataFlow, dwStateMask: ::DWORD,
        ppDevices: *mut *mut IMMDeviceCollection
    ) -> ::HRESULT,
    fn GetDefaultAudioEndpoint(
        &mut self, dataFlow: EDataFlow, role: ERole, ppEndpoint: *mut *mut IMMDevice
    ) -> ::HRESULT,
    fn GetDevice(&mut self, pwstrId: ::LPCWSTR, ppDevices: *mut *mut IMMDevice) -> ::HRESULT,
    fn RegisterEndpointNotificationCallback(
        &mut self, pClient: *mut IMMNotificationClient
    ) -> ::HRESULT,
    fn UnregisterEndpointNotificationCallback(
        &mut self, pClient: *mut IMMNotificationClient
    ) -> ::HRESULT
}
);
RIDL!(
interface IMMDeviceCollection(IMMDeviceCollectionVtbl): IUnknown(IUnknownVtbl) {
    fn GetCount(&mut self, pcDevices: *const ::UINT) -> ::HRESULT,
    fn Item(&mut self, nDevice: ::UINT, ppDevice: *mut *mut IMMDevice) -> ::HRESULT
}
);

#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct IMMNotificationClient;
<|endoftext|>