<commit_before>import Str.sbuf;
import Vec.vbuf;

native mod libc = "libc.dylib" {

    fn open(sbuf s, int flags, uint mode) -> int;
    fn read(int fd, vbuf buf, uint count) -> int;
    fn write(int fd, vbuf buf, uint count) -> int;
    fn close(int fd) -> int;

    type FILE;
    fn fopen(sbuf path, sbuf mode) -> FILE;
    fn fdopen(int fd, sbuf mode) -> FILE;
    fn fclose(FILE f);
    fn fgetc(FILE f) -> int;
    fn ungetc(int c, FILE f);
    fn feof(FILE f) -> int;
    fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fwrite(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fseek(FILE f, int offset, int whence) -> int;
    fn ftell(FILE f) -> int;

    type dir;
    fn opendir(sbuf d) -> dir;
    fn closedir(dir d) -> int;
    type dirent;
    fn readdir(dir d) -> dirent;

    fn getenv(sbuf n) -> sbuf;
    fn setenv(sbuf n, sbuf v, int overwrite) -> int;
    fn unsetenv(sbuf n) -> int;

    fn pipe(vbuf buf) -> int;
    fn waitpid(int pid, vbuf status, int options) -> int;
}

mod libc_constants {
    fn O_RDONLY() -> int { ret 0x0000; }
    fn O_WRONLY() -> int { ret 0x0001; }
    fn O_RDWR()   -> int { ret 0x0002; }
    fn O_APPEND() -> int { ret 0x0008; }
    fn O_CREAT()  -> int { ret 0x0200; }
    fn O_EXCL()   -> int { ret 0x0800; }
    fn O_TRUNC()  -> int { ret 0x0400; }
    fn O_TEXT()   -> int { ret 0x0000; } // nonexistent in darwin libc
    fn O_BINARY() -> int { ret 0x0000; } // nonexistent in darwin libc

    fn S_IRUSR() -> uint { ret 0x0400u; }
    fn S_IWUSR() -> uint { ret 0x0200u; }
}

fn exec_suffix() -> str {
    ret "";
}

fn target_os() -> str {
    ret "macos";
}

fn dylib_filename(str base) -> str {
    ret "lib" + base + ".dylib";
}

fn pipe() -> tup(int, int) {
    let vec[mutable int] fds = vec(mutable 0, 0);
    assert (OS.libc.pipe(Vec.buf[mutable int](fds)) == 0);
    ret tup(fds.(0), fds.(1));
}

fn fd_FILE(int fd) -> libc.FILE {
    ret libc.fdopen(fd, Str.buf("r"));
}

fn waitpid(int pid) -> int {
    let vec[mutable int] status = vec(mutable 0);
    assert (OS.libc.waitpid(pid, Vec.buf[mutable int](status), 0) != -1);
    ret status.(0);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Remove a couple more spurious 'mutable' value qualifiers from macos_OS.rs.<commit_after>import Str.sbuf;
import Vec.vbuf;

native mod libc = "libc.dylib" {

    fn open(sbuf s, int flags, uint mode) -> int;
    fn read(int fd, vbuf buf, uint count) -> int;
    fn write(int fd, vbuf buf, uint count) -> int;
    fn close(int fd) -> int;

    type FILE;
    fn fopen(sbuf path, sbuf mode) -> FILE;
    fn fdopen(int fd, sbuf mode) -> FILE;
    fn fclose(FILE f);
    fn fgetc(FILE f) -> int;
    fn ungetc(int c, FILE f);
    fn feof(FILE f) -> int;
    fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fwrite(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fseek(FILE f, int offset, int whence) -> int;
    fn ftell(FILE f) -> int;

    type dir;
    fn opendir(sbuf d) -> dir;
    fn closedir(dir d) -> int;
    type dirent;
    fn readdir(dir d) -> dirent;

    fn getenv(sbuf n) -> sbuf;
    fn setenv(sbuf n, sbuf v, int overwrite) -> int;
    fn unsetenv(sbuf n) -> int;

    fn pipe(vbuf buf) -> int;
    fn waitpid(int pid, vbuf status, int options) -> int;
}

mod libc_constants {
    fn O_RDONLY() -> int { ret 0x0000; }
    fn O_WRONLY() -> int { ret 0x0001; }
    fn O_RDWR()   -> int { ret 0x0002; }
    fn O_APPEND() -> int { ret 0x0008; }
    fn O_CREAT()  -> int { ret 0x0200; }
    fn O_EXCL()   -> int { ret 0x0800; }
    fn O_TRUNC()  -> int { ret 0x0400; }
    fn O_TEXT()   -> int { ret 0x0000; } // nonexistent in darwin libc
    fn O_BINARY() -> int { ret 0x0000; } // nonexistent in darwin libc

    fn S_IRUSR() -> uint { ret 0x0400u; }
    fn S_IWUSR() -> uint { ret 0x0200u; }
}

fn exec_suffix() -> str {
    ret "";
}

fn target_os() -> str {
    ret "macos";
}

fn dylib_filename(str base) -> str {
    ret "lib" + base + ".dylib";
}

fn pipe() -> tup(int, int) {
    let vec[mutable int] fds = vec(0, 0);
    assert (OS.libc.pipe(Vec.buf[mutable int](fds)) == 0);
    ret tup(fds.(0), fds.(1));
}

fn fd_FILE(int fd) -> libc.FILE {
    ret libc.fdopen(fd, Str.buf("r"));
}

fn waitpid(int pid) -> int {
    let vec[mutable int] status = vec(0);
    assert (OS.libc.waitpid(pid, Vec.buf[mutable int](status), 0) != -1);
    ret status.(0);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use std::fmt;
use std::fmt::Display;
use std::result::Result as StdResult;
use std::io;
use std::string;

pub type Result<T> = StdResult<T, PrefetchError>;

#[derive(Debug)]
pub enum ErrorKind {
    InvalidFileSignature,
    IoError,
    Utf16Error,
    FromUtf16Error,
    DecompressionError
}
/// USN Record Parsing Error
#[derive(Debug)]
pub struct PrefetchError {
    /// Formated error message
    pub message: String,
    /// The type of error
    pub kind: ErrorKind
}

impl PrefetchError{
    #[allow(dead_code)]
    pub fn invalid_file_signature(err: String)->Self{
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::InvalidFileSignature
        }
    }
    #[allow(dead_code)]
    pub fn decompression_error(err: String)->Self{
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::DecompressionError
        }
    }
    #[allow(dead_code)]
    pub fn io_error(err: String)->Self{
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::IoError
        }
    }
    #[allow(dead_code)]
    pub fn decode_error(err: String)->Self{
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::Utf16Error
        }
    }
}

impl From<io::Error> for PrefetchError {
    fn from(err: io::Error) -> Self {
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::IoError
        }
    }
}

impl From<string::FromUtf16Error> for PrefetchError {
    fn from(err: string::FromUtf16Error) -> Self {
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::FromUtf16Error
        }
    }
}

impl Display for PrefetchError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "{:?}: {}",self.kind,self.message) }
}
<commit_msg>added parse error<commit_after>use std::fmt;
use std::fmt::Display;
use std::result::Result as StdResult;
use std::io;
use std::string;

pub type Result<T> = StdResult<T, PrefetchError>;

#[derive(Debug)]
pub enum ErrorKind {
    InvalidFileSignature,
    ParseError,
    IoError,
    Utf16Error,
    FromUtf16Error,
    DecompressionError
}
/// USN Record Parsing Error
#[derive(Debug)]
pub struct PrefetchError {
    /// Formated error message
    pub message: String,
    /// The type of error
    pub kind: ErrorKind
}

impl PrefetchError{
    #[allow(dead_code)]
    pub fn invalid_file_signature(err: String)->Self{
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::InvalidFileSignature
        }
    }
    #[allow(dead_code)]
    pub fn parse_error(err: String)->Self{
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::ParseError
        }
    }
    #[allow(dead_code)]
    pub fn decompression_error(err: String)->Self{
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::DecompressionError
        }
    }
    #[allow(dead_code)]
    pub fn io_error(err: String)->Self{
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::IoError
        }
    }
    #[allow(dead_code)]
    pub fn decode_error(err: String)->Self{
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::Utf16Error
        }
    }
}

impl From<io::Error> for PrefetchError {
    fn from(err: io::Error) -> Self {
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::IoError
        }
    }
}

impl From<string::FromUtf16Error> for PrefetchError {
    fn from(err: string::FromUtf16Error) -> Self {
        PrefetchError {
            message: format!("{}",err),
            kind: ErrorKind::FromUtf16Error
        }
    }
}

impl Display for PrefetchError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "{:?}: {}",self.kind,self.message) }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// rust - central access to other rust tools
// FIXME #2238 Make commands run and test emit proper file endings on windows
// FIXME #2238 Make run only accept source that emits an executable

#[link(name = "rust",
       vers = "0.8",
       uuid = "4a24da33-5cc8-4037-9352-2cbe9bd9d27c",
       url = "https://github.com/mozilla/rust/tree/master/src/rust")];

#[license = "MIT/ASL2"];
#[crate_type = "lib"];

extern mod rustpkg;
extern mod rustdoc;
extern mod rusti;
extern mod rustc;

use std::io;
use std::os;
use std::run;
use std::libc::exit;

enum ValidUsage {
    Valid(int), Invalid
}

impl ValidUsage {
    fn is_valid(&self) -> bool {
        match *self {
            Valid(_)   => true,
            Invalid    => false
        }
    }
}

enum Action {
    Call(extern "Rust" fn(args: &[~str]) -> ValidUsage),
    CallMain(&'static str, extern "Rust" fn(&[~str])),
}

enum UsageSource<'self> {
    UsgStr(&'self str),
    UsgCall(extern "Rust" fn()),
}

struct Command<'self> {
    cmd: &'self str,
    action: Action,
    usage_line: &'self str,
    usage_full: UsageSource<'self>,
}

static COMMANDS: &'static [Command<'static>] = &'static [
    Command {
        cmd: "build",
        action: CallMain("rustc", rustc::main_args),
        usage_line: "compile rust source files",
        usage_full: UsgCall(rustc_help),
    },
    Command {
        cmd: "run",
        action: Call(cmd_run),
        usage_line: "build an executable, and run it",
        usage_full: UsgStr(
            "The run command is an shortcut for the command line \n\
             \"rustc <filename> -o <filestem>~ && ./<filestem>~ [<arguments>...]\".\
            \n\nUsage:\trust run <filename> [<arguments>...]"
        )
    },
    Command {
        cmd: "test",
        action: Call(cmd_test),
        usage_line: "build a test executable, and run it",
        usage_full: UsgStr(
            "The test command is an shortcut for the command line \n\
            \"rustc --test <filename> -o <filestem>test~ && \
            ./<filestem>test~ [<arguments>...]\"\
            \n\nUsage:\trust test <filename> [<arguments>...]"
        )
    },
    Command {
        cmd: "doc",
        action: CallMain("rustdoc", rustdoc::main_args),
        usage_line: "generate documentation from doc comments",
        usage_full: UsgCall(rustdoc_help),
    },
    Command {
        cmd: "pkg",
        action: CallMain("rustpkg", rustpkg::main_args),
        usage_line: "download, build, install rust packages",
        usage_full: UsgCall(rustpkg::usage::general),
    },
    Command {
        cmd: "sketch",
        action: CallMain("rusti", rusti::main_args),
        usage_line: "run a rust interpreter",
        usage_full: UsgStr("\nUsage:\trusti"),
    },
    Command {
        cmd: "help",
        action: Call(cmd_help),
        usage_line: "show detailed usage of a command",
        usage_full: UsgStr(
            "The help command displays the usage text of another command.\n\
            The text is either build in, or provided by the corresponding \
            program.\n\nUsage:\trust help <command>"
        )
    }
];

fn rustc_help() {
    rustc::usage(os::args()[0].clone())
}

fn rustdoc_help() {
    rustdoc::usage(os::args()[0].clone())
}

fn find_cmd(command_string: &str) -> Option<Command> {
    do COMMANDS.iter().find |command| {
        command.cmd == command_string
    }.map_move(|x| *x)
}

fn cmd_help(args: &[~str]) -> ValidUsage {
    fn print_usage(command_string: ~str) -> ValidUsage {
        match find_cmd(command_string) {
            Some(command) => {
                match command.action {
                    CallMain(prog, _) => printfln!(
                        "The %s command is an alias for the %s program.",
                        command.cmd, prog),
                    _       => ()
                }
                match command.usage_full {
                    UsgStr(msg) => printfln!("%s\n", msg),
                    UsgCall(f)  => f(),
                }
                Valid(0)
            },
            None => Invalid
        }
    }

    match args {
        [ref command_string] => print_usage((*command_string).clone()),
        _                    => Invalid
    }
}

fn cmd_test(args: &[~str]) -> ValidUsage {
    match args {
        [ref filename, ..prog_args] => {
            let p = Path(*filename);
            let test_exec = p.filestem().unwrap() + "test~";
            invoke("rustc", &[~"--test", filename.to_owned(),
                              ~"-o", test_exec.to_owned()], rustc::main_args);
            let exit_code = run::process_status(~"./" + test_exec, prog_args);
            Valid(exit_code)
        }
        _ => Invalid
    }
}

fn cmd_run(args: &[~str]) -> ValidUsage {
    match args {
        [ref filename, ..prog_args] => {
            let p = Path(*filename);
            let exec = p.filestem().unwrap() + "~";
            invoke("rustc", &[filename.to_owned(), ~"-o", exec.to_owned()],
                   rustc::main_args);
            let exit_code = run::process_status(~"./"+exec, prog_args);
            Valid(exit_code)
        }
        _ => Invalid
    }
}

fn invoke(prog: &str, args: &[~str], f: &fn(&[~str])) {
    let mut osargs = ~[prog.to_owned()];
    osargs.push_all_move(args.to_owned());
    f(osargs);
}

fn do_command(command: &Command, args: &[~str]) -> ValidUsage {
    match command.action {
        Call(f) => f(args),
        CallMain(prog, f) => {
            invoke(prog, args, f);
            Valid(0)
        }
    }
}

fn usage() {
    static INDENT: uint = 8;

    io::print(
        "The rust tool is a convenience for managing rust source code.\n\
        It acts as a shortcut for programs of the rust tool chain.\n\
        \n\
        Usage:\trust <command> [arguments]\n\
        \n\
        The commands are:\n\
        \n"
    );

    for command in COMMANDS.iter() {
        let padding = " ".repeat(INDENT - command.cmd.len());
        printfln!("    %s%s%s", command.cmd, padding, command.usage_line);
    }

    io::print(
        "\n\
        Use \"rust help <command>\" for more information about a command.\n\
        \n"
    );

}

pub fn main() {
    #[fixed_stack_segment]; #[inline(never)];

    let os_args = os::args();

    if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) {
        rustc::version(os_args[0]);
        unsafe { exit(0); }
    }

    let args = os_args.tail();

    if !args.is_empty() {
        let r = find_cmd(*args.head());
        for command in r.iter() {
            let result = do_command(command, args.tail());
            match result {
                Valid(exit_code) => unsafe { exit(exit_code.to_i32()) },
                _                => loop
            }
        }
    }

    usage();
}
<commit_msg>rust: Don't call libc::exit<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// rust - central access to other rust tools
// FIXME #2238 Make commands run and test emit proper file endings on windows
// FIXME #2238 Make run only accept source that emits an executable

#[link(name = "rust",
       vers = "0.8",
       uuid = "4a24da33-5cc8-4037-9352-2cbe9bd9d27c",
       url = "https://github.com/mozilla/rust/tree/master/src/rust")];

#[license = "MIT/ASL2"];
#[crate_type = "lib"];

extern mod rustpkg;
extern mod rustdoc;
extern mod rusti;
extern mod rustc;

use std::io;
use std::os;
use std::run;

enum ValidUsage {
    Valid(int), Invalid
}

impl ValidUsage {
    fn is_valid(&self) -> bool {
        match *self {
            Valid(_)   => true,
            Invalid    => false
        }
    }
}

enum Action {
    Call(extern "Rust" fn(args: &[~str]) -> ValidUsage),
    CallMain(&'static str, extern "Rust" fn(&[~str])),
}

enum UsageSource<'self> {
    UsgStr(&'self str),
    UsgCall(extern "Rust" fn()),
}

struct Command<'self> {
    cmd: &'self str,
    action: Action,
    usage_line: &'self str,
    usage_full: UsageSource<'self>,
}

static COMMANDS: &'static [Command<'static>] = &'static [
    Command {
        cmd: "build",
        action: CallMain("rustc", rustc::main_args),
        usage_line: "compile rust source files",
        usage_full: UsgCall(rustc_help),
    },
    Command {
        cmd: "run",
        action: Call(cmd_run),
        usage_line: "build an executable, and run it",
        usage_full: UsgStr(
            "The run command is an shortcut for the command line \n\
             \"rustc <filename> -o <filestem>~ && ./<filestem>~ [<arguments>...]\".\
            \n\nUsage:\trust run <filename> [<arguments>...]"
        )
    },
    Command {
        cmd: "test",
        action: Call(cmd_test),
        usage_line: "build a test executable, and run it",
        usage_full: UsgStr(
            "The test command is an shortcut for the command line \n\
            \"rustc --test <filename> -o <filestem>test~ && \
            ./<filestem>test~ [<arguments>...]\"\
            \n\nUsage:\trust test <filename> [<arguments>...]"
        )
    },
    Command {
        cmd: "doc",
        action: CallMain("rustdoc", rustdoc::main_args),
        usage_line: "generate documentation from doc comments",
        usage_full: UsgCall(rustdoc_help),
    },
    Command {
        cmd: "pkg",
        action: CallMain("rustpkg", rustpkg::main_args),
        usage_line: "download, build, install rust packages",
        usage_full: UsgCall(rustpkg::usage::general),
    },
    Command {
        cmd: "sketch",
        action: CallMain("rusti", rusti::main_args),
        usage_line: "run a rust interpreter",
        usage_full: UsgStr("\nUsage:\trusti"),
    },
    Command {
        cmd: "help",
        action: Call(cmd_help),
        usage_line: "show detailed usage of a command",
        usage_full: UsgStr(
            "The help command displays the usage text of another command.\n\
            The text is either build in, or provided by the corresponding \
            program.\n\nUsage:\trust help <command>"
        )
    }
];

fn rustc_help() {
    rustc::usage(os::args()[0].clone())
}

fn rustdoc_help() {
    rustdoc::usage(os::args()[0].clone())
}

fn find_cmd(command_string: &str) -> Option<Command> {
    do COMMANDS.iter().find |command| {
        command.cmd == command_string
    }.map_move(|x| *x)
}

fn cmd_help(args: &[~str]) -> ValidUsage {
    fn print_usage(command_string: ~str) -> ValidUsage {
        match find_cmd(command_string) {
            Some(command) => {
                match command.action {
                    CallMain(prog, _) => printfln!(
                        "The %s command is an alias for the %s program.",
                        command.cmd, prog),
                    _       => ()
                }
                match command.usage_full {
                    UsgStr(msg) => printfln!("%s\n", msg),
                    UsgCall(f)  => f(),
                }
                Valid(0)
            },
            None => Invalid
        }
    }

    match args {
        [ref command_string] => print_usage((*command_string).clone()),
        _                    => Invalid
    }
}

fn cmd_test(args: &[~str]) -> ValidUsage {
    match args {
        [ref filename, ..prog_args] => {
            let p = Path(*filename);
            let test_exec = p.filestem().unwrap() + "test~";
            invoke("rustc", &[~"--test", filename.to_owned(),
                              ~"-o", test_exec.to_owned()], rustc::main_args);
            let exit_code = run::process_status(~"./" + test_exec, prog_args);
            Valid(exit_code)
        }
        _ => Invalid
    }
}

fn cmd_run(args: &[~str]) -> ValidUsage {
    match args {
        [ref filename, ..prog_args] => {
            let p = Path(*filename);
            let exec = p.filestem().unwrap() + "~";
            invoke("rustc", &[filename.to_owned(), ~"-o", exec.to_owned()],
                   rustc::main_args);
            let exit_code = run::process_status(~"./"+exec, prog_args);
            Valid(exit_code)
        }
        _ => Invalid
    }
}

fn invoke(prog: &str, args: &[~str], f: &fn(&[~str])) {
    let mut osargs = ~[prog.to_owned()];
    osargs.push_all_move(args.to_owned());
    f(osargs);
}

fn do_command(command: &Command, args: &[~str]) -> ValidUsage {
    match command.action {
        Call(f) => f(args),
        CallMain(prog, f) => {
            invoke(prog, args, f);
            Valid(0)
        }
    }
}

fn usage() {
    static INDENT: uint = 8;

    io::print(
        "The rust tool is a convenience for managing rust source code.\n\
        It acts as a shortcut for programs of the rust tool chain.\n\
        \n\
        Usage:\trust <command> [arguments]\n\
        \n\
        The commands are:\n\
        \n"
    );

    for command in COMMANDS.iter() {
        let padding = " ".repeat(INDENT - command.cmd.len());
        printfln!("    %s%s%s", command.cmd, padding, command.usage_line);
    }

    io::print(
        "\n\
        Use \"rust help <command>\" for more information about a command.\n\
        \n"
    );

}

pub fn main() {
    #[fixed_stack_segment]; #[inline(never)];

    let os_args = os::args();

    if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) {
        rustc::version(os_args[0]);
        return;
    }

    let args = os_args.tail();

    if !args.is_empty() {
        let r = find_cmd(*args.head());
        for command in r.iter() {
            let result = do_command(command, args.tail());
            match result {
                Valid(exit_code) => {
                    os::set_exit_status(exit_code);
                    return;
                }
                _ => loop
            }
        }
    }

    usage();
}
<|endoftext|>


<commit_before>use regex::{Regex};
use std::str::{FromStr};

use super::super::metrics::*;

/// Reader that takes a log line string and returns any metrics found in it.
pub trait LogLineReader: Send + Sync {
    fn read(&self, &str) -> Vec<Metric>;
}

/// Reads metrics from log lines in the standard formats:
///
/// - Measures: `measure#metric=1.2`
/// - Counts: `count#metric=3`
pub struct StandardLogLineReader;

lazy_static! {
    static ref LOG_MEASURE_REGEX: Regex =
        Regex::new(r"measure#([a-zA-Z0-9._]+)=(\d+(?:\.\d+)?)").unwrap();

    static ref LOG_SAMPLE_REGEX: Regex =
        Regex::new(r"sample#([a-zA-Z0-9._]+)=(\d+(?:\.\d+)?)").unwrap();

    static ref LOG_COUNT_REGEX: Regex =
        Regex::new(r"count#([a-zA-Z0-9._]+)=(\d+)").unwrap();

    static ref SOURCE_REGEX: Regex =
        Regex::new(r"source=([\w.]+)").unwrap();
}

impl StandardLogLineReader {
    fn parse_source<'a>(line: &'a str) -> Option<&'a str> {
        SOURCE_REGEX.captures(line)
                    .and_then(|c| c.at(1))
    }
}

impl LogLineReader for StandardLogLineReader {
    fn read(&self, line: &str) -> Vec<Metric> {
        let source = StandardLogLineReader::parse_source(line).map(|s| s.to_owned());
        let dimension = |name: &str| {
            Dimension { name: name.to_owned(), source: source.clone() }
        };

        let mut metrics = vec![];

        // Look for counts
        for cap in LOG_COUNT_REGEX.captures_iter(line) {
            let name = cap.at(1).unwrap();

            if let Ok(value) = u64::from_str(cap.at(2).unwrap()) {
                metrics.push(Count(dimension(name), value))
            }
        }

        // Look for measures
        for cap in LOG_MEASURE_REGEX.captures_iter(line) {
            let name = cap.at(1).unwrap();

            if let Ok(value) = f64::from_str(cap.at(2).unwrap()) {
                metrics.push(Measure(dimension(name), value))
            }
        }

        // Look for samples
        for cap in LOG_SAMPLE_REGEX.captures_iter(line) {
            let name = cap.at(1).unwrap();

            if let Ok(value) = f64::from_str(cap.at(2).unwrap()) {
                metrics.push(Sample(dimension(name), value))
            }
        }

        metrics
    } // fn read
}

/// Reads Heroku's logging metrics.
pub struct HerokuLogLineReader;

lazy_static! {
    static ref DYNO_TYPE_REGEX: Regex =
        Regex::new(r"dyno=(\w+)").unwrap();

    static ref SERVICE_REGEX: Regex =
        Regex::new(r"service=(\d+)ms").unwrap();

    static ref STATUS_REGEX: Regex =
        Regex::new(r"status=(\d+)").unwrap();

    static ref HEROKU_HTTP_ERROR_CODE_REGEX: Regex =
        Regex::new(r"code=(H\d+)").unwrap();

    static ref HEROKU_RUNTIME_ERROR_CODE_REGEX: Regex =
        Regex::new(r"Error (R\d+)").unwrap();

    static ref LOAD_AVG_1M_REGEX: Regex =
        Regex::new(r"sample#load_avg_1m=([0-9.]+)").unwrap();
}

impl HerokuLogLineReader {
    /// Parses Heroku router status lines for the response service time (how
    /// long it took) and the HTTP response status.
    pub fn parse_status(line: &str) -> Option<Vec<Metric>> {
        let mut metrics: Vec<Metric> = vec![];

        let status = match STATUS_REGEX.captures(line)
            .and_then(|c| c.at(1))
            .and_then(|s| u16::from_str(s).ok()) {
                Some(s) => s,
                None => return None,
            };

        let service = match SERVICE_REGEX.captures(line)
            .and_then(|c| c.at(1))
            .and_then(|s| u32::from_str(s).ok()) {
                Some(s) => s,
                None => return None,
            };

        let dyno_type = match DYNO_TYPE_REGEX.captures(line)
            .and_then(|c| c.at(1)) {
                Some(d) => d,
                None => return None,
            };

        let base = format!("dyno.{}", dyno_type);

        // Counting a 499 as a 500
        let is_500 = status >= 499 && status < 600;

        // Don't record timing for 499 and 5xx errors
        if !is_500 {
            let service_time_name = format!("{}.service_time", base);
            metrics.push(Measure(Dimension::with_name_and_source(service_time_name, dyno_type), service as f64));
        }

        // Count the status
        let status_name = format!("{}.status.{}", base, status);
        metrics.push(Count(Dimension::with_name_and_source(status_name, dyno_type), 1));

        Some(metrics)
    }

    /// Parses Heroku warning and error codes like "Hxx" and "Rxx" where "xx" is a pair
    /// of numbers. See the [Heroku][] site for more details.
    ///
    /// [Heroku]: https://devcenter.heroku.com/articles/error-codes
    pub fn parse_heroku_code(line: &str) -> Option<Metric> {
        let code: &str;

        if let Some(http_code) = HEROKU_HTTP_ERROR_CODE_REGEX.captures(line).and_then(|c| c.at(1)) {
            code = http_code;

        } else if let Some(runtime_code) = HEROKU_RUNTIME_ERROR_CODE_REGEX.captures(line).and_then(|c| c.at(1)) {
            code = runtime_code;

        } else {
            return None
        }

        let name = format!("heroku.error.{}", code);
        Some(Count(Dimension::with_name(name), 1))
    }

    /// Parses the `sample#load_avg_1m=` metrics from Heroku logs.
    pub fn parse_load(line: &str) -> Option<Metric> {
        let load_avg_1m = match LOAD_AVG_1M_REGEX.captures(line)
                                                 .and_then(|c| c.at(1))
                                                 .and_then(|c| f64::from_str(c).ok()) {
            Some(l) => l,
            None => return None,
        };

        let source = match StandardLogLineReader::parse_source(line) {
            Some(s) => s,
            None => return None,
        };

        let dyno_type = match source.split('.').nth(0) {
            Some(s) => s,
            None => return None,
        };

        let dim = Dimension::with_name_and_source(format!("dyno.{}.load_avg_1m", dyno_type), source);
        Some(Measure(dim, load_avg_1m))
    }
}

impl LogLineReader for HerokuLogLineReader {
    fn read(&self, line: &str) -> Vec<Metric> {
        if !line.contains("heroku") { return vec![] }

        let mut metrics: Vec<Metric> = vec![];

        if let Some(statuses) = HerokuLogLineReader::parse_status(line)      { metrics.extend(statuses) }
        if let Some(code)     = HerokuLogLineReader::parse_heroku_code(line) { metrics.push(code) }
        if let Some(load)     = HerokuLogLineReader::parse_load(line)        { metrics.push(load) }

        metrics
    }
}

#[cfg(test)]
mod tests {
    use super::{
        LogLineReader,
        StandardLogLineReader,
        HerokuLogLineReader
    };
    use super::super::super::metrics::*;

    #[test]
    fn standard_reader_reads_measure() {
        let reader = StandardLogLineReader;
        let line = "measure#foo=1.2\n";

        assert_eq!(
            reader.read(line),
            vec![ Measure(Dimension::with_name("foo"), 1.2) ]
        )
    }

    #[test]
    fn standard_reader_reads_measure_with_source() {
        let reader = StandardLogLineReader;
        let line = "source=web measure#foo=1.2\n";

        assert_eq!(
            reader.read(line),
            vec![ Measure(Dimension::with_name_and_source("foo", "web"), 1.2) ]
        )
    }

    #[test]
    fn standard_reader_reads_count() {
        let reader = StandardLogLineReader;
        let line = "count#foo=1\n";

        assert_eq!(
            reader.read(line),
            vec![ Count(Dimension::with_name("foo"), 1) ]
        )
    }

    #[test]
    fn standard_reader_reads_sample() {
        let reader = StandardLogLineReader;
        let line = "sample#bar=3.4\n";

        assert_eq!(
            reader.read(line),
            vec![ Sample(Dimension::with_name("bar"), 3.4) ]
        )
    }

    #[test]
    fn standard_reader_returns_nothing_on_failed_read() {
        let reader = StandardLogLineReader;
        let line = "metric#bar=3.4\n";

        assert_eq!(
            reader.read(line),
            vec![]
        )
    }

    #[test]
    fn standard_reader_parses_source() {
        let line = "source=something metric#other=5.6\n";

        assert_eq!(
            StandardLogLineReader::parse_source(line),
            Some("something")
        )
    }

    #[test]
    fn heroku_reader_reads_loads() {
        let reader = HerokuLogLineReader;
        let line = "2016-02-26 21:34:59.429615+00:00 heroku web.2 - - source=web.2 dyno=heroku.123.XYZ sample#load_avg_1m=0.56 sample#load_avg_5m=0.26 sample#load_avg_15m=0.17\n";

        assert_eq!(
            reader.read(line),
            vec![ Measure(Dimension::with_name_and_source("dyno.web.load_avg_1m", "web.2"), 0.56) ]
        )
    }

    #[test]
    fn heroku_reader_reads_http_errors() {
        let reader = HerokuLogLineReader;
        let line = "2016-02-26 21:50:36.352129+00:00 heroku router - - sock=backend at=error code=H18 desc=\"Server Request Interrupted\" method=GET path=\"/\" host=www.example.com request_id=XYZ fwd=\"1.2.3.4\" dyno=web.5 connect=0ms service=495ms status=503 bytes=1648\n";

        assert_eq!(
            reader.read(line),
            vec![
                Count(Dimension::with_name_and_source("dyno.web.status.503", "web"), 1),
                Count(Dimension::with_name("heroku.error.H18"), 1),
            ]
        )
    }

    #[test]
    fn heroku_reader_reads_runtime_errors() {
        let reader = HerokuLogLineReader;
        let line = "2016-02-25 21:35:34.990292+00:00 heroku scheduler.5451 - - Error R14 (Memory quota exceeded)\n";

        assert_eq!(
            reader.read(line),
            vec![
                Count(Dimension::with_name("heroku.error.R14"), 1),
            ]
        )
    }

    #[test]
    fn heroku_reader_reads_service_times() {
        let reader = HerokuLogLineReader;
        let line = "2016-02-26 21:34:59.370813+00:00 heroku router - - at=info method=PUT path=\"/\" host=www.example.com request_id=XYZ fwd=\"1.2.3.4\" dyno=web.1 connect=0ms service=39ms status=200 bytes=1627\n";

        assert_eq!(
            reader.read(line),
            vec![
                Measure(Dimension::with_name_and_source("dyno.web.service_time", "web"), 39.0),
                Count(Dimension::with_name_and_source("dyno.web.status.200", "web"), 1),
            ]
        )
    }
}
<commit_msg>Track connect times reported by Heroku router<commit_after>use regex::{Regex};
use std::str::{FromStr};

use super::super::metrics::*;

/// Reader that takes a log line string and returns any metrics found in it.
pub trait LogLineReader: Send + Sync {
    fn read(&self, &str) -> Vec<Metric>;
}

/// Reads metrics from log lines in the standard formats:
///
/// - Measures: `measure#metric=1.2`
/// - Counts: `count#metric=3`
pub struct StandardLogLineReader;

lazy_static! {
    static ref LOG_MEASURE_REGEX: Regex =
        Regex::new(r"measure#([a-zA-Z0-9._]+)=(\d+(?:\.\d+)?)").unwrap();

    static ref LOG_SAMPLE_REGEX: Regex =
        Regex::new(r"sample#([a-zA-Z0-9._]+)=(\d+(?:\.\d+)?)").unwrap();

    static ref LOG_COUNT_REGEX: Regex =
        Regex::new(r"count#([a-zA-Z0-9._]+)=(\d+)").unwrap();

    static ref SOURCE_REGEX: Regex =
        Regex::new(r"source=([\w.]+)").unwrap();
}

impl StandardLogLineReader {
    fn parse_source<'a>(line: &'a str) -> Option<&'a str> {
        SOURCE_REGEX.captures(line)
                    .and_then(|c| c.at(1))
    }
}

impl LogLineReader for StandardLogLineReader {
    fn read(&self, line: &str) -> Vec<Metric> {
        let source = StandardLogLineReader::parse_source(line).map(|s| s.to_owned());
        let dimension = |name: &str| {
            Dimension { name: name.to_owned(), source: source.clone() }
        };

        let mut metrics = vec![];

        // Look for counts
        for cap in LOG_COUNT_REGEX.captures_iter(line) {
            let name = cap.at(1).unwrap();

            if let Ok(value) = u64::from_str(cap.at(2).unwrap()) {
                metrics.push(Count(dimension(name), value))
            }
        }

        // Look for measures
        for cap in LOG_MEASURE_REGEX.captures_iter(line) {
            let name = cap.at(1).unwrap();

            if let Ok(value) = f64::from_str(cap.at(2).unwrap()) {
                metrics.push(Measure(dimension(name), value))
            }
        }

        // Look for samples
        for cap in LOG_SAMPLE_REGEX.captures_iter(line) {
            let name = cap.at(1).unwrap();

            if let Ok(value) = f64::from_str(cap.at(2).unwrap()) {
                metrics.push(Sample(dimension(name), value))
            }
        }

        metrics
    } // fn read
}

/// Reads Heroku's logging metrics.
pub struct HerokuLogLineReader;

lazy_static! {
    static ref DYNO_TYPE_REGEX: Regex =
        Regex::new(r"dyno=(\w+)").unwrap();

    static ref CONNECT_REGEX: Regex =
        Regex::new(r"connect=(\d+)ms").unwrap();

    static ref SERVICE_REGEX: Regex =
        Regex::new(r"service=(\d+)ms").unwrap();

    static ref STATUS_REGEX: Regex =
        Regex::new(r"status=(\d+)").unwrap();

    static ref HEROKU_HTTP_ERROR_CODE_REGEX: Regex =
        Regex::new(r"code=(H\d+)").unwrap();

    static ref HEROKU_RUNTIME_ERROR_CODE_REGEX: Regex =
        Regex::new(r"Error (R\d+)").unwrap();

    static ref LOAD_AVG_1M_REGEX: Regex =
        Regex::new(r"sample#load_avg_1m=([0-9.]+)").unwrap();
}

impl HerokuLogLineReader {
    /// Parses Heroku router status lines for the response service time (how
    /// long it took) and the HTTP response status.
    pub fn parse_status(line: &str) -> Option<Vec<Metric>> {
        let mut metrics: Vec<Metric> = vec![];

        let connect = match CONNECT_REGEX.captures(line)
            .and_then(|c| c.at(1))
            .and_then(|c| u16::from_str(c).ok()) {
                Some(c) => c,
                None => return None,
            };

        let status = match STATUS_REGEX.captures(line)
            .and_then(|c| c.at(1))
            .and_then(|s| u16::from_str(s).ok()) {
                Some(s) => s,
                None => return None,
            };

        let service = match SERVICE_REGEX.captures(line)
            .and_then(|c| c.at(1))
            .and_then(|s| u32::from_str(s).ok()) {
                Some(s) => s,
                None => return None,
            };

        let dyno_type = match DYNO_TYPE_REGEX.captures(line)
            .and_then(|c| c.at(1)) {
                Some(d) => d,
                None => return None,
            };

        let base = format!("dyno.{}", dyno_type);

        // Counting a 499 as a 500
        let is_500 = status >= 499 && status < 600;

        // Don't record timing for 499 and 5xx errors
        if !is_500 {
            let service_time_name = format!("{}.service_time", base);
            metrics.push(Measure(Dimension::with_name_and_source(service_time_name, dyno_type), service as f64));
        }

        // Track the connect time (how long it took to pick up the request)
        let connect_time_name = format!("{}.connect_time", base);
        metrics.push(Measure(Dimension::with_name_and_source(connect_time_name, dyno_type), connect as f64));

        // Count the status
        let status_name = format!("{}.status.{}", base, status);
        metrics.push(Count(Dimension::with_name_and_source(status_name, dyno_type), 1));

        Some(metrics)
    }

    /// Parses Heroku warning and error codes like "Hxx" and "Rxx" where "xx" is a pair
    /// of numbers. See the [Heroku][] site for more details.
    ///
    /// [Heroku]: https://devcenter.heroku.com/articles/error-codes
    pub fn parse_heroku_code(line: &str) -> Option<Metric> {
        let code: &str;

        if let Some(http_code) = HEROKU_HTTP_ERROR_CODE_REGEX.captures(line).and_then(|c| c.at(1)) {
            code = http_code;

        } else if let Some(runtime_code) = HEROKU_RUNTIME_ERROR_CODE_REGEX.captures(line).and_then(|c| c.at(1)) {
            code = runtime_code;

        } else {
            return None
        }

        let name = format!("heroku.error.{}", code);
        Some(Count(Dimension::with_name(name), 1))
    }

    /// Parses the `sample#load_avg_1m=` metrics from Heroku logs.
    pub fn parse_load(line: &str) -> Option<Metric> {
        let load_avg_1m = match LOAD_AVG_1M_REGEX.captures(line)
                                                 .and_then(|c| c.at(1))
                                                 .and_then(|c| f64::from_str(c).ok()) {
            Some(l) => l,
            None => return None,
        };

        let source = match StandardLogLineReader::parse_source(line) {
            Some(s) => s,
            None => return None,
        };

        let dyno_type = match source.split('.').nth(0) {
            Some(s) => s,
            None => return None,
        };

        let dim = Dimension::with_name_and_source(format!("dyno.{}.load_avg_1m", dyno_type), source);
        Some(Measure(dim, load_avg_1m))
    }
}

impl LogLineReader for HerokuLogLineReader {
    fn read(&self, line: &str) -> Vec<Metric> {
        if !line.contains("heroku") { return vec![] }

        let mut metrics: Vec<Metric> = vec![];

        if let Some(statuses) = HerokuLogLineReader::parse_status(line)      { metrics.extend(statuses) }
        if let Some(code)     = HerokuLogLineReader::parse_heroku_code(line) { metrics.push(code) }
        if let Some(load)     = HerokuLogLineReader::parse_load(line)        { metrics.push(load) }

        metrics
    }
}

#[cfg(test)]
mod tests {
    use super::{
        LogLineReader,
        StandardLogLineReader,
        HerokuLogLineReader
    };
    use super::super::super::metrics::*;

    #[test]
    fn standard_reader_reads_measure() {
        let reader = StandardLogLineReader;
        let line = "measure#foo=1.2\n";

        assert_eq!(
            reader.read(line),
            vec![ Measure(Dimension::with_name("foo"), 1.2) ]
        )
    }

    #[test]
    fn standard_reader_reads_measure_with_source() {
        let reader = StandardLogLineReader;
        let line = "source=web measure#foo=1.2\n";

        assert_eq!(
            reader.read(line),
            vec![ Measure(Dimension::with_name_and_source("foo", "web"), 1.2) ]
        )
    }

    #[test]
    fn standard_reader_reads_count() {
        let reader = StandardLogLineReader;
        let line = "count#foo=1\n";

        assert_eq!(
            reader.read(line),
            vec![ Count(Dimension::with_name("foo"), 1) ]
        )
    }

    #[test]
    fn standard_reader_reads_sample() {
        let reader = StandardLogLineReader;
        let line = "sample#bar=3.4\n";

        assert_eq!(
            reader.read(line),
            vec![ Sample(Dimension::with_name("bar"), 3.4) ]
        )
    }

    #[test]
    fn standard_reader_returns_nothing_on_failed_read() {
        let reader = StandardLogLineReader;
        let line = "metric#bar=3.4\n";

        assert_eq!(
            reader.read(line),
            vec![]
        )
    }

    #[test]
    fn standard_reader_parses_source() {
        let line = "source=something metric#other=5.6\n";

        assert_eq!(
            StandardLogLineReader::parse_source(line),
            Some("something")
        )
    }

    #[test]
    fn heroku_reader_reads_loads() {
        let reader = HerokuLogLineReader;
        let line = "2016-02-26 21:34:59.429615+00:00 heroku web.2 - - source=web.2 dyno=heroku.123.XYZ sample#load_avg_1m=0.56 sample#load_avg_5m=0.26 sample#load_avg_15m=0.17\n";

        assert_eq!(
            reader.read(line),
            vec![ Measure(Dimension::with_name_and_source("dyno.web.load_avg_1m", "web.2"), 0.56) ]
        )
    }

    #[test]
    fn heroku_reader_reads_http_errors() {
        let reader = HerokuLogLineReader;
        let line = "2016-02-26 21:50:36.352129+00:00 heroku router - - sock=backend at=error code=H18 desc=\"Server Request Interrupted\" method=GET path=\"/\" host=www.example.com request_id=XYZ fwd=\"1.2.3.4\" dyno=web.5 connect=0ms service=495ms status=503 bytes=1648\n";

        assert_eq!(
            reader.read(line),
            vec![
                Measure(Dimension::with_name_and_source("dyno.web.connect_time", "web"), 0.0),
                Count(Dimension::with_name_and_source("dyno.web.status.503", "web"), 1),
                Count(Dimension::with_name("heroku.error.H18"), 1),
            ]
        )
    }

    #[test]
    fn heroku_reader_reads_runtime_errors() {
        let reader = HerokuLogLineReader;
        let line = "2016-02-25 21:35:34.990292+00:00 heroku scheduler.5451 - - Error R14 (Memory quota exceeded)\n";

        assert_eq!(
            reader.read(line),
            vec![
                Count(Dimension::with_name("heroku.error.R14"), 1),
            ]
        )
    }

    #[test]
    fn heroku_reader_reads_service_times() {
        let reader = HerokuLogLineReader;
        let line = "2016-02-26 21:34:59.370813+00:00 heroku router - - at=info method=PUT path=\"/\" host=www.example.com request_id=XYZ fwd=\"1.2.3.4\" dyno=web.1 connect=1ms service=39ms status=200 bytes=1627\n";

        assert_eq!(
            reader.read(line),
            vec![
                Measure(Dimension::with_name_and_source("dyno.web.service_time", "web"), 39.0),
                Measure(Dimension::with_name_and_source("dyno.web.connect_time", "web"), 1.0),
                Count(Dimension::with_name_and_source("dyno.web.status.200", "web"), 1),
            ]
        )
    }
}
<|endoftext|>


<commit_before>//! Pattern-sequence data structures and implementations.

use std;
use std::ops::Index;
use std::iter::FromIterator;

use util::set::{self, Contains};
use super::{Anchor, Atom, Class, Element, Repetition, Union};
use super::{Reduce, flatten_and_reduce};

// To hide the implementation details, we wrap the type alias in
// a private submodule.
mod seq_impl {
    use ::pattern::Element;
    pub type Inner<T> = Vec<Element<T>>;
}

/// Sequence of patterns.
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct Sequence<T: Atom>(seq_impl::Inner<T>);

impl<T: Atom> Sequence<T> {
    /// Create a new sequence from the given vector.
    ///
    /// This method will **panic** if the given vector is not at least two
    /// elements long.
    pub fn new(v: Vec<Element<T>>) -> Self {
        if v.len() < 2 {
            panic!("Sequences must have at least two elements");
        }
        Sequence(v)
    }

    /// Get the number of elements in the sequence.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Fetch an iterator over the elements in the sequence
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a Element<T>> {
        self.0.iter()
    }

    fn into_inner(self) -> seq_impl::Inner<T> {
        self.0
    }

    /// Transforms each contained atom using the supplied function or closure
    /// to produce a new sequence.
    pub fn map_atoms<U, F>(self, f: F) -> Sequence<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        self.0.into_iter().map(|elt| elt.map_atoms(&f)).collect()
    }
}

impl<T: Atom> Reduce for Sequence<T> {
    type Output = Option<Element<T>>;

    /// Flatten the sequence and apply implementation-defined optimizations.
    fn reduce(mut self) -> Self::Output {
        // Flatten and reduce the vector *first* so we can reduce `self` based
        // on the size of the *reduced* vector.
       flatten_and_reduce(&mut self.0, Element::Wildcard,
                           |elt| match elt { &Element::Sequence(ref s) => Some(s.len()), _ => None },
                           |elt| match elt { Element::Sequence(s) => s.into_inner(), _ => unreachable!() });
        match self.0.len() {
            0 => None,
            1 => Some(self.0.swap_remove(0)),
            _ => Some(Element::Sequence(self))
        }
    }
}

impl<T: Atom> Index<usize> for Sequence<T> {
    type Output = Element<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }

}

impl<T: Atom> IntoIterator for Sequence<T> {
    type Item = Element<T>;
    type IntoIter = std::vec::IntoIter<Element<T>>;
    #[inline(always)]
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<T: Atom> FromIterator<Element<T>> for Sequence<T> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Element<T>>
    {
        Sequence(iter.into_iter().collect())
    }
}

impl<T: Atom> set::Contains<T> for Sequence<T> {
    /// A sequence always contains at least two elements, and thus will never
    /// match a single atom.
    #[inline(always)]
    fn contains(&self, _: T) -> bool {
        false
    }
}

// ----------------------------------------------------------------
// set::IsSubsetOf

macro_rules! is_subset_if_length_1_and_first_element_is_subset {
    ($T: ident,$Other: ty, $name: ident; $doc: expr) => {
        impl<$T: Atom> set::IsSubsetOf<$Other> for Sequence<$T> {
            #[doc = $doc]
            #[inline]
            fn is_subset_of(&self, $name: &$Other) -> bool {
                self.len() == 1 && self[0].is_subset_of($name)
            }
        }}}

is_subset_if_length_1_and_first_element_is_subset! {
    T, T, atom;
    "A sequence is a subset of a particular atom whenever the sequence has length one, and the first element is a subset of that atom."}

is_subset_if_length_1_and_first_element_is_subset! {
    T, Anchor<T>, anchor;
    "A sequence is a subset of an anchor whenever the sequence has length one, and the first element is a subset of that atom."}

is_subset_if_length_1_and_first_element_is_subset! {
    T, Class<T>, class;
    "A sequence is a subset of an atom class whenever the sequence has length one, and the first element is a subset of that class."}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Sequence<T> {
    /// A sequence `A` can be a subset of another sequence `B` *if* both have the
    /// same length and each element in `A` is a subset of the corresponding element
    /// in `B`:
    ///
    /// A ⊂ B ⇔ |A|=|B|=n ∧ Aᵢ ⊂ Bᵢ ∀ i∈[0,n]
    fn is_subset_of(&self, other: &Sequence<T>) -> bool {
        other.len() == self.len() &&
            self.iter().zip(other.iter()).all(|(u, v)| u.is_subset_of(v))
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Sequence<T> {
    /// A sequence is a subset of a union whenever it is a subset of one of the
    /// union's members.
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Sequence<T> {
    /// A sequence is a subset of a repetition if the sequence's length is
    /// contained by the repetition's count and all members of the sequence are
    /// subsets of the repeated element.
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        rep.count().contains(self.len()) && self.iter().all(|elt| elt.is_subset_of(rep.element()))
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Sequence<T> {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref s) => self.is_subset_of(s),
            &Element::Union(ref u) => self.is_subset_of(u),
            &Element::Repeat(ref r) => self.is_subset_of(r),

            &Element::Anchor(ref a) => self.is_subset_of(a),
            &Element::Atom(ref a) => self.is_subset_of(a),
            &Element::Class(ref c) => self.is_subset_of(c),
            &Element::Wildcard => self.len() == 1 && self[0].is_subset_of(elt),
        }
    }
}
        }
    }
}
<commit_msg>pattern/sequence: removed duplicate set of closing braces<commit_after>//! Pattern-sequence data structures and implementations.

use std;
use std::ops::Index;
use std::iter::FromIterator;

use util::set::{self, Contains};
use super::{Anchor, Atom, Class, Element, Repetition, Union};
use super::{Reduce, flatten_and_reduce};

// To hide the implementation details, we wrap the type alias in
// a private submodule.
mod seq_impl {
    use ::pattern::Element;
    pub type Inner<T> = Vec<Element<T>>;
}

/// Sequence of patterns.
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct Sequence<T: Atom>(seq_impl::Inner<T>);

impl<T: Atom> Sequence<T> {
    /// Create a new sequence from the given vector.
    ///
    /// This method will **panic** if the given vector is not at least two
    /// elements long.
    pub fn new(v: Vec<Element<T>>) -> Self {
        if v.len() < 2 {
            panic!("Sequences must have at least two elements");
        }
        Sequence(v)
    }

    /// Get the number of elements in the sequence.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Fetch an iterator over the elements in the sequence
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a Element<T>> {
        self.0.iter()
    }

    fn into_inner(self) -> seq_impl::Inner<T> {
        self.0
    }

    /// Transforms each contained atom using the supplied function or closure
    /// to produce a new sequence.
    pub fn map_atoms<U, F>(self, f: F) -> Sequence<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        self.0.into_iter().map(|elt| elt.map_atoms(&f)).collect()
    }
}

impl<T: Atom> Reduce for Sequence<T> {
    type Output = Option<Element<T>>;

    /// Flatten the sequence and apply implementation-defined optimizations.
    fn reduce(mut self) -> Self::Output {
        // Flatten and reduce the vector *first* so we can reduce `self` based
        // on the size of the *reduced* vector.
       flatten_and_reduce(&mut self.0, Element::Wildcard,
                           |elt| match elt { &Element::Sequence(ref s) => Some(s.len()), _ => None },
                           |elt| match elt { Element::Sequence(s) => s.into_inner(), _ => unreachable!() });
        match self.0.len() {
            0 => None,
            1 => Some(self.0.swap_remove(0)),
            _ => Some(Element::Sequence(self))
        }
    }
}

impl<T: Atom> Index<usize> for Sequence<T> {
    type Output = Element<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }

}

impl<T: Atom> IntoIterator for Sequence<T> {
    type Item = Element<T>;
    type IntoIter = std::vec::IntoIter<Element<T>>;
    #[inline(always)]
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<T: Atom> FromIterator<Element<T>> for Sequence<T> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Element<T>>
    {
        Sequence(iter.into_iter().collect())
    }
}

impl<T: Atom> set::Contains<T> for Sequence<T> {
    /// A sequence always contains at least two elements, and thus will never
    /// match a single atom.
    #[inline(always)]
    fn contains(&self, _: T) -> bool {
        false
    }
}

// ----------------------------------------------------------------
// set::IsSubsetOf

macro_rules! is_subset_if_length_1_and_first_element_is_subset {
    ($T: ident,$Other: ty, $name: ident; $doc: expr) => {
        impl<$T: Atom> set::IsSubsetOf<$Other> for Sequence<$T> {
            #[doc = $doc]
            #[inline]
            fn is_subset_of(&self, $name: &$Other) -> bool {
                self.len() == 1 && self[0].is_subset_of($name)
            }
        }}}

is_subset_if_length_1_and_first_element_is_subset! {
    T, T, atom;
    "A sequence is a subset of a particular atom whenever the sequence has length one, and the first element is a subset of that atom."}

is_subset_if_length_1_and_first_element_is_subset! {
    T, Anchor<T>, anchor;
    "A sequence is a subset of an anchor whenever the sequence has length one, and the first element is a subset of that atom."}

is_subset_if_length_1_and_first_element_is_subset! {
    T, Class<T>, class;
    "A sequence is a subset of an atom class whenever the sequence has length one, and the first element is a subset of that class."}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Sequence<T> {
    /// A sequence `A` can be a subset of another sequence `B` *if* both have the
    /// same length and each element in `A` is a subset of the corresponding element
    /// in `B`:
    ///
    /// A ⊂ B ⇔ |A|=|B|=n ∧ Aᵢ ⊂ Bᵢ ∀ i∈[0,n]
    fn is_subset_of(&self, other: &Sequence<T>) -> bool {
        other.len() == self.len() &&
            self.iter().zip(other.iter()).all(|(u, v)| u.is_subset_of(v))
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Sequence<T> {
    /// A sequence is a subset of a union whenever it is a subset of one of the
    /// union's members.
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Sequence<T> {
    /// A sequence is a subset of a repetition if the sequence's length is
    /// contained by the repetition's count and all members of the sequence are
    /// subsets of the repeated element.
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        rep.count().contains(self.len()) && self.iter().all(|elt| elt.is_subset_of(rep.element()))
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Sequence<T> {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref s) => self.is_subset_of(s),
            &Element::Union(ref u) => self.is_subset_of(u),
            &Element::Repeat(ref r) => self.is_subset_of(r),

            &Element::Anchor(ref a) => self.is_subset_of(a),
            &Element::Atom(ref a) => self.is_subset_of(a),
            &Element::Class(ref c) => self.is_subset_of(c),
            &Element::Wildcard => self.len() == 1 && self[0].is_subset_of(elt),
        }
    }
}
<|endoftext|>


<commit_before>extern mod extra;

use std::io;
use extra::net;
use extra::uv;

struct Client {
    writer: @io::WriterUtil,
    reader: @io::ReaderUtil
}

impl Client {
    fn flush(&self) -> Result<~str, ~str> {
        self.writer.write_str("flush_all\r\n");
        let result_str = self.reader.read_line();
        if result_str == ~"OK\r" {  // XXX: read_line dose not remove \r, is it a bug?
            return Ok(result_str);
        }
        else {
            return Err(result_str);
        }
    }

    fn delete(&self, key: ~str, time: uint) -> Result<~str, ~str> {
        self.writer.write_str(fmt!("delete %s %u\r\n", key, time));
        let result_str = self.reader.read_line();
        if result_str == ~ "DELETED\r" {
            return Ok(result_str);
        }
        else {
            return Err(result_str);
        }
    }

    fn get(&self, key: ~str) -> Result<~str, ~str> {
        self.writer.write_str(fmt!("get %s\r\n", key));
        let result_str = self.reader.read_line();
        if result_str == ~"END\r" {
            return Err(~"NOT_FOUND");
        }
        // TODO:
        let result_str = self.reader.read_line();
        return Ok(result_str);

    }

    fn incr(&self, key: ~str, value: int) -> Result<~str, ~str> {
        self.writer.write_str(fmt!("incr %s %i\r\n", key, value));
        let result_str = self.reader.read_line();
        if result_str == ~"NOT_FOUND\r" {
            return Err(result_str);
        }
        else {
            return Ok(result_str);
        }
    }

    fn _store(&self, action: ~str, key: ~str, value: ~str, exp_time: uint) -> Result<~str, ~str> {
        self.writer.write_str(fmt!("%s %s 0 %u %u\r\n", action, key, exp_time, value.len()));
        self.writer.write_str(fmt!("%s\r\n", value));
        let result_str = self.reader.read_line();
        if result_str == ~"STORED\r" {
            return Ok(result_str);
        }
        else {
            return Err(result_str);
        }
    }

    fn set(&self, key: ~str, value: ~str, exp_time: uint) -> Result<~str, ~str> {
        self._store(~"set", key, value, exp_time)
    }

    fn add(&self, key: ~str, value: ~str, exp_time: uint) -> Result<~str, ~str> {
        self._store(~"add", key, value, exp_time)
    }

    fn replace(&self, key: ~str, value: ~str, exp_time: uint) -> Result<~str, ~str> {
        self._store(~"replace", key, value, exp_time)
    }
}

fn main() {
    let client = connect(~"127.0.0.1", 11211).get();

    client.flush();
    client.set(~"foo", ~"bar", 0);
    client.add(~"foo", ~"bar", 0);
    client.get(~"foo").get();
    client.replace(~"foo", ~"0", 0);
    client.incr(~"foo", 1);
    client.delete(~"foo", 0);

}

fn connect(addr: ~str, port: uint) -> Result<Client, net::tcp::TcpConnectErrData> {
    match net::tcp::connect(net::ip::v4::parse_addr(addr), port, &uv::global_loop::get()) {
        Err(err) => {
            //match err {
            //    net::tcp::GenericConnectErr(name,msg) => io::println(fmt!("Connection error %s: %s", name, msg)),
            //    net::tcp::ConnectionRefused => io::println("Connection refused")
            //}
            return Err(err);
        },
        Ok(socket) => {
            let socket_buf = net::tcp::socket_buf(socket);
            let writer = @socket_buf as @io::WriterUtil;
            let reader = @socket_buf as @io::ReaderUtil;
            let client = Client{writer: writer, reader: reader};
            return Ok(client);
        }
    }

}
<commit_msg>add test<commit_after>extern mod extra;

use std::io;
use extra::net;
use extra::uv;

struct Client {
    writer: @io::WriterUtil,
    reader: @io::ReaderUtil
}

impl Client {
    fn flush(&self) -> Result<~str, ~str> {
        self.writer.write_str("flush_all\r\n");
        let result_str = self.reader.read_line();
        if result_str == ~"OK\r" {  // XXX: read_line dose not remove \r, is it a bug?
            return Ok(result_str);
        }
        else {
            return Err(result_str);
        }
    }

    fn delete(&self, key: ~str, time: uint) -> Result<~str, ~str> {
        self.writer.write_str(fmt!("delete %s %u\r\n", key, time));
        let result_str = self.reader.read_line();
        if result_str == ~ "DELETED\r" {
            return Ok(result_str);
        }
        else {
            return Err(result_str);
        }
    }

    fn get(&self, key: ~str) -> Result<~str, ~str> {
        self.writer.write_str(fmt!("get %s\r\n", key));
        let result_str = self.reader.read_line();
        if result_str == ~"END\r" {
            return Err(~"NOT_FOUND");
        }
        // TODO:
        let result_str = self.reader.read_line();
        return Ok(result_str);

    }

    fn incr(&self, key: ~str, value: int) -> Result<~str, ~str> {
        self.writer.write_str(fmt!("incr %s %i\r\n", key, value));
        let result_str = self.reader.read_line();
        if result_str == ~"NOT_FOUND\r" {
            return Err(result_str);
        }
        else {
            return Ok(result_str);
        }
    }

    fn _store(&self, action: ~str, key: ~str, value: ~str, exp_time: uint) -> Result<~str, ~str> {
        self.writer.write_str(fmt!("%s %s 0 %u %u\r\n", action, key, exp_time, value.len()));
        self.writer.write_str(fmt!("%s\r\n", value));
        let result_str = self.reader.read_line();
        if result_str == ~"STORED\r" {
            return Ok(result_str);
        }
        else {
            return Err(result_str);
        }
    }

    fn set(&self, key: ~str, value: ~str, exp_time: uint) -> Result<~str, ~str> {
        self._store(~"set", key, value, exp_time)
    }

    fn add(&self, key: ~str, value: ~str, exp_time: uint) -> Result<~str, ~str> {
        self._store(~"add", key, value, exp_time)
    }

    fn replace(&self, key: ~str, value: ~str, exp_time: uint) -> Result<~str, ~str> {
        self._store(~"replace", key, value, exp_time)
    }
}

#[test]
fn test_client() {
    let client = connect(~"127.0.0.1", 11211).get();

    client.flush();
    client.set(~"foo", ~"bar", 0);
    client.add(~"foo", ~"bar", 0);
    client.get(~"foo").get();
    client.replace(~"foo", ~"0", 0);
    client.incr(~"foo", 1);
    client.delete(~"foo", 0);

}

fn connect(addr: ~str, port: uint) -> Result<Client, net::tcp::TcpConnectErrData> {
    match net::tcp::connect(net::ip::v4::parse_addr(addr), port, &uv::global_loop::get()) {
        Err(err) => {
            //match err {
            //    net::tcp::GenericConnectErr(name,msg) => io::println(fmt!("Connection error %s: %s", name, msg)),
            //    net::tcp::ConnectionRefused => io::println("Connection refused")
            //}
            return Err(err);
        },
        Ok(socket) => {
            let socket_buf = net::tcp::socket_buf(socket);
            let writer = @socket_buf as @io::WriterUtil;
            let reader = @socket_buf as @io::ReaderUtil;
            let client = Client{writer: writer, reader: reader};
            return Ok(client);
        }
    }

}
<|endoftext|>


<commit_before>use baseline::codegen::CondCode;
use cpu::asm;
use cpu::emit;
use cpu::*;
use lexer::position::Position;
use masm::{MacroAssembler, Label};
use mem::ptr_width;
use object::IntArray;
use ty::MachineMode;
use vtable::VTable;

impl MacroAssembler {
    pub fn prolog(&mut self, stacksize: i32) {
        asm::emit_pushq_reg(self, RBP);
        asm::emit_movq_reg_reg(self, RSP, RBP);

        if stacksize > 0 {
            asm::emit_subq_imm_reg(self, stacksize, RSP);
        }
    }

    pub fn epilog(&mut self, stacksize: i32) {
        if stacksize > 0 {
            asm::emit_addq_imm_reg(self, stacksize, RSP);
        }

        asm::emit_popq_reg(self, RBP);
        asm::emit_retq(self);
    }

    pub fn direct_call(&mut self, ptr: *const u8) {
        let disp = self.add_addr(ptr);
        let pos = self.pos() as i32;

        emit::load_constpool(self, REG_RESULT, disp + pos);
        emit::call_reg(self, REG_RESULT);
    }

    pub fn indirect_call(&mut self, index: u32) {
        let obj = REG_PARAMS[0];

        // REG_RESULT = [obj] (load vtable)
        emit::load_mem(self, MachineMode::Ptr, REG_RESULT, Mem::Base(obj, 0));

        // calculate offset of VTable entry
        let disp = VTable::offset_of_method_table() + (index as i32) * ptr_width();

        // load vtable entry
        emit::load_mem(self, MachineMode::Ptr, REG_RESULT, Mem::Base(REG_RESULT, disp));

        // call *REG_RESULT
        emit::call_reg(self, REG_RESULT);
    }

    pub fn load_array_elem(&mut self, mode: MachineMode, dest: Reg, array: Reg, index: Reg) {
        assert!(mode == MachineMode::Int32);

        emit::load_mem(self, mode, dest, Mem::Index(array, index,
                       mode.size(), IntArray::offset_of_data()));
    }

    pub fn store_array_elem(&mut self, mode: MachineMode, array: Reg, index: Reg, value: Reg) {
        assert!(mode == MachineMode::Int32);

        emit::store_mem(self, MachineMode::Int32, Mem::Index(array, index,
                        4, IntArray::offset_of_data()), value);
    }

    pub fn test_if_nil_bailout(&mut self, pos: Position, reg: Reg) {
        asm::emit_testq_reg_reg(self, reg, reg);

        let lbl = self.create_label();
        emit::jump_if(self, CondCode::Zero, lbl);
        self.emit_bailout(lbl, trap::NIL, pos);
    }

    pub fn test_if_nil(&mut self, reg: Reg) -> Label {
        asm::emit_testq_reg_reg(self, reg, reg);

        let lbl = self.create_label();
        emit::jump_if(self, CondCode::Zero, lbl);

        lbl
    }

    pub fn set(&mut self, dest: Reg, op: CondCode) {
        asm::emit_setb_reg(self, op, dest);
        asm::emit_movzbl_reg_reg(self, dest, dest);
    }

    pub fn cmp_mem(&mut self, mode: MachineMode, mem: Mem, rhs: Reg) {
        match mem {
            Mem::Local(offset) => asm::emit_cmp_mem_reg(self, mode, REG_FP, offset, rhs),
            Mem::Base(base, disp) => asm::emit_cmp_mem_reg(self, mode, base, disp, rhs),
            Mem::Index(base, index, scale, disp) =>
                asm::emit_cmp_memindex_reg(self, mode, base, index, scale, disp, rhs)
        }
    }

    pub fn cmp_mem_imm(&mut self, mode: MachineMode, mem: Mem, imm: i32) {
        match mem {
            Mem::Local(_) => unimplemented!(),
            Mem::Base(base, disp) => asm::emit_cmp_mem_imm(self, mode, base, disp, imm),
            Mem::Index(_, _, _, _) => unimplemented!(),
        }
    }

    pub fn cmp_reg(&mut self, mode: MachineMode, lhs: Reg, rhs: Reg) {
        match mode {
            MachineMode::Int8
                | MachineMode::Int32 => asm::emit_cmpl_reg_reg(self, rhs, lhs),
            MachineMode::Ptr => asm::emit_cmpq_reg_reg(self, rhs, lhs),
        }
    }
}<commit_msg>move more code into MacroAssembler<commit_after>use baseline::codegen::CondCode;
use cpu::asm;
use cpu::emit;
use cpu::*;
use lexer::position::Position;
use masm::{MacroAssembler, Label};
use mem::ptr_width;
use object::IntArray;
use ty::MachineMode;
use vtable::VTable;

impl MacroAssembler {
    pub fn prolog(&mut self, stacksize: i32) {
        asm::emit_pushq_reg(self, RBP);
        asm::emit_movq_reg_reg(self, RSP, RBP);

        if stacksize > 0 {
            asm::emit_subq_imm_reg(self, stacksize, RSP);
        }
    }

    pub fn epilog(&mut self, stacksize: i32) {
        if stacksize > 0 {
            asm::emit_addq_imm_reg(self, stacksize, RSP);
        }

        asm::emit_popq_reg(self, RBP);
        asm::emit_retq(self);
    }

    pub fn direct_call(&mut self, ptr: *const u8) {
        let disp = self.add_addr(ptr);
        let pos = self.pos() as i32;

        emit::load_constpool(self, REG_RESULT, disp + pos);
        emit::call_reg(self, REG_RESULT);
    }

    pub fn indirect_call(&mut self, index: u32) {
        let obj = REG_PARAMS[0];

        // REG_RESULT = [obj] (load vtable)
        emit::load_mem(self, MachineMode::Ptr, REG_RESULT, Mem::Base(obj, 0));

        // calculate offset of VTable entry
        let disp = VTable::offset_of_method_table() + (index as i32) * ptr_width();

        // load vtable entry
        emit::load_mem(self, MachineMode::Ptr, REG_RESULT, Mem::Base(REG_RESULT, disp));

        // call *REG_RESULT
        emit::call_reg(self, REG_RESULT);
    }

    pub fn load_array_elem(&mut self, mode: MachineMode, dest: Reg, array: Reg, index: Reg) {
        assert!(mode == MachineMode::Int32);

        emit::load_mem(self, mode, dest, Mem::Index(array, index,
                       mode.size(), IntArray::offset_of_data()));
    }

    pub fn store_array_elem(&mut self, mode: MachineMode, array: Reg, index: Reg, value: Reg) {
        assert!(mode == MachineMode::Int32);

        emit::store_mem(self, MachineMode::Int32, Mem::Index(array, index,
                        4, IntArray::offset_of_data()), value);
    }

    pub fn test_if_nil_bailout(&mut self, pos: Position, reg: Reg) {
        asm::emit_testq_reg_reg(self, reg, reg);

        let lbl = self.create_label();
        emit::jump_if(self, CondCode::Zero, lbl);
        self.emit_bailout(lbl, trap::NIL, pos);
    }

    pub fn test_if_nil(&mut self, reg: Reg) -> Label {
        asm::emit_testq_reg_reg(self, reg, reg);

        let lbl = self.create_label();
        emit::jump_if(self, CondCode::Zero, lbl);

        lbl
    }

    pub fn set(&mut self, dest: Reg, op: CondCode) {
        asm::emit_setb_reg(self, op, dest);
        asm::emit_movzbl_reg_reg(self, dest, dest);
    }

    pub fn cmp_mem(&mut self, mode: MachineMode, mem: Mem, rhs: Reg) {
        match mem {
            Mem::Local(offset) => asm::emit_cmp_mem_reg(self, mode, REG_FP, offset, rhs),
            Mem::Base(base, disp) => asm::emit_cmp_mem_reg(self, mode, base, disp, rhs),
            Mem::Index(base, index, scale, disp) =>
                asm::emit_cmp_memindex_reg(self, mode, base, index, scale, disp, rhs)
        }
    }

    pub fn cmp_mem_imm(&mut self, mode: MachineMode, mem: Mem, imm: i32) {
        match mem {
            Mem::Local(_) => unimplemented!(),
            Mem::Base(base, disp) => asm::emit_cmp_mem_imm(self, mode, base, disp, imm),
            Mem::Index(_, _, _, _) => unimplemented!(),
        }
    }

    pub fn cmp_reg(&mut self, mode: MachineMode, lhs: Reg, rhs: Reg) {
        match mode {
            MachineMode::Int8
                | MachineMode::Int32 => asm::emit_cmpl_reg_reg(self, rhs, lhs),
            MachineMode::Ptr => asm::emit_cmpq_reg_reg(self, rhs, lhs),
        }
    }

    pub fn test_and_jump_if(&mut self, cond: CondCode, reg: Reg, lbl: Label) {
        assert!(cond == CondCode::Zero || cond == CondCode::NonZero);

        asm::emit_testl_reg_reg(self, reg, reg);
        asm::emit_jcc(self, cond, lbl);
    }

    pub fn jump_if(&mut self, cond: CondCode, lbl: Label) {
        asm::emit_jcc(self, cond, lbl);
    }

    pub fn jump(&mut self, lbl: Label) {
        asm::emit_jmp(self, lbl);
    }

    pub fn int_div(&mut self, dest: Reg, lhs: Reg, rhs: Reg) {
        assert_eq!(RAX, lhs);

        asm::emit_cltd(self);
        asm::emit_idivl_reg_reg(self, rhs);

        if dest != RAX {
            asm::emit_movl_reg_reg(self, RAX, dest);
        }
    }

    pub fn int_mod(&mut self, dest: Reg, lhs: Reg, rhs: Reg) {
        assert_eq!(RAX, lhs);

        asm::emit_cltd(self);
        asm::emit_idivl_reg_reg(self, rhs);

        if dest != RDX {
            asm::emit_movl_reg_reg(self, RDX, dest);
        }
    }

    pub fn int_mul(&mut self, dest: Reg, lhs: Reg, rhs: Reg) {
        asm::emit_imull_reg_reg(self, rhs, lhs);

        if dest != lhs {
            asm::emit_movl_reg_reg(self, lhs, dest);
        }
    }

    pub fn int_add(&mut self, dest: Reg, lhs: Reg, rhs: Reg) {
        asm::emit_addl_reg_reg(self, rhs, lhs);

        if dest != lhs {
            asm::emit_movl_reg_reg(self, lhs, dest);
        }
    }

    pub fn int_sub(&mut self, dest: Reg, lhs: Reg, rhs: Reg) {
        asm::emit_subl_reg_reg(self, rhs, lhs);

        if dest != lhs {
            asm::emit_movl_reg_reg(self, lhs, dest);
        }
    }

    pub fn int_shl(&mut self, dest: Reg, lhs: Reg, rhs: Reg) {
        if rhs != RCX {
            assert!(lhs != RCX);
            asm::emit_movq_reg_reg(self, rhs, RCX);
        }

        asm::emit_shll_reg_cl(self, lhs);

        if dest != lhs {
            asm::emit_movl_reg_reg(self, lhs, dest);
        }
    }

    pub fn int_or(&mut self, dest: Reg, lhs: Reg, rhs: Reg) {
        asm::emit_orl_reg_reg(self, rhs, lhs);

        if dest != lhs {
            asm::emit_movl_reg_reg(self, lhs, dest);
        }
    }

    pub fn int_and(&mut self, dest: Reg, lhs: Reg, rhs: Reg) {
        asm::emit_andl_reg_reg(self, rhs, lhs);

        if dest != lhs {
            asm::emit_movl_reg_reg(self, lhs, dest);
        }
    }

    pub fn int_xor(&mut self, dest: Reg, lhs: Reg, rhs: Reg) {
        asm::emit_xorl_reg_reg(self, rhs, lhs);

        if dest != lhs {
            asm::emit_movl_reg_reg(self, lhs, dest);
        }
    }
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2019 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use crate::model::zobrist::ZobristHash;

const TABLE_SIZE: usize = 1 << 20;
const TABLE_MASK: u64 = TABLE_SIZE as u64 - 1;

// This could just by an array, but because arrays are allocated on the stack (even when
// doing Box::new(array)), we need to use a Vec
pub struct TTable {
    table: Vec<Entry>,
    age: u8,
}

impl TTable {
    pub fn new() -> Self {
        Self {
            table: vec![Entry::default(); TABLE_SIZE],
            age: 0,
        }
    }
    pub fn inc_age(&mut self) {
        self.age.wrapping_add(1);
    }
    pub fn get(&self, zobrist: ZobristHash, depth: i8) -> Option<Score> {
        let hash = (zobrist & TABLE_MASK) as usize;
        let entry = self.table[hash];
        if entry.zobrist == zobrist && entry.depth >= depth {
            Some(entry.score)
        } else {
            None
        }
    }
    pub fn set(&mut self, zobrist: ZobristHash, score: Score, depth: i8) {
        let hash = (zobrist & TABLE_MASK) as usize;
        let mut entry = self.table[hash];
        let mut replace = false;
        if entry.zobrist != 0 {
            if self.age != entry.age || depth > entry.depth {
                replace = true;
            }
        } else {
            replace = true;
        }

        if replace {
            entry.score = score;
            entry.age = self.age;
            entry.depth = depth;
            entry.zobrist = zobrist;
        }
    }
}

#[derive(Clone, Copy)]
pub enum Score {
    Exact(i16),
    Beta(i16),
}

// TODO: Store best move for move ordering?
// TODO: Use lower bits of ZobristHash to save space?
#[derive(Clone, Copy)]
pub struct Entry {
    pub score: Score,
    pub age: u8,
    pub depth: i8,
    pub zobrist: ZobristHash,
}

impl Default for Entry {
    fn default() -> Self {
        Self {
            score: Score::Exact(0),
            age: 0,
            depth: 0,
            // The only field that matters for determining if this is an empty entry or not.
            // Assume (and hope) that no valid board ever hashes to 0.
            zobrist: 0,
        }
    }
}
<commit_msg>Actually update TTable ages<commit_after>/*
 * Copyright (C) 2017-2019 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use crate::model::zobrist::ZobristHash;

const TABLE_SIZE: usize = 1 << 20;
const TABLE_MASK: u64 = TABLE_SIZE as u64 - 1;

// This could just by an array, but because arrays are allocated on the stack (even when
// doing Box::new(array)), we need to use a Vec
pub struct TTable {
    table: Vec<Entry>,
    age: u8,
}

impl TTable {
    pub fn new() -> Self {
        Self {
            table: vec![Entry::default(); TABLE_SIZE],
            age: 0,
        }
    }
    pub fn inc_age(&mut self) {
        self.age = self.age.wrapping_add(1);
    }
    pub fn get(&self, zobrist: ZobristHash, depth: i8) -> Option<Score> {
        let hash = (zobrist & TABLE_MASK) as usize;
        let entry = self.table[hash];
        if entry.zobrist == zobrist && entry.depth >= depth {
            Some(entry.score)
        } else {
            None
        }
    }
    pub fn set(&mut self, zobrist: ZobristHash, score: Score, depth: i8) {
        let hash = (zobrist & TABLE_MASK) as usize;
        let mut entry = self.table[hash];
        let mut replace = false;
        if entry.zobrist != 0 {
            if self.age != entry.age || depth > entry.depth {
                replace = true;
            }
        } else {
            replace = true;
        }

        if replace {
            entry.score = score;
            entry.age = self.age;
            entry.depth = depth;
            entry.zobrist = zobrist;
        }
    }
}

#[derive(Clone, Copy)]
pub enum Score {
    Exact(i16),
    Beta(i16),
}

// TODO: Store best move for move ordering?
// TODO: Use lower bits of ZobristHash to save space?
#[derive(Clone, Copy)]
pub struct Entry {
    pub score: Score,
    pub age: u8,
    pub depth: i8,
    pub zobrist: ZobristHash,
}

impl Default for Entry {
    fn default() -> Self {
        Self {
            score: Score::Exact(0),
            age: 0,
            depth: 0,
            // The only field that matters for determining if this is an empty entry or not.
            // Assume (and hope) that no valid board ever hashes to 0.
            zobrist: 0,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::mem;
use std::os::unix::io::{RawFd, AsRawFd};
use std::io::{Read, Write, Error, ErrorKind};

use libc;
use errno::errno;
use libc::{c_int, c_void};

#[derive(Clone)]
pub struct Socket {
    /// This socket's file descriptor
    pub fd: c_int,
}

impl Socket {

    unsafe pub fn set_tcp_keepalive(&self, keepalive: bool) {
        let optval: c_int = match keepalive {
            true => 1,
            false => 0
        };
        let opt_result = libc::setsockopt(self.fd,
                                          libc::SOL_SOCKET,
                                          libc::SO_KEEPALIVE,
                                          &optval as *const _ as *const c_void,
                                          mem::size_of::<c_int>() as u32);
        if opt_result < 0 {
            error!("Setting SO_KEEPALIVE: {}",
                   Error::from_raw_os_error(errno().0 as i32));
        }
    }

    unsafe pub fn set_tcp_nodelay(&self, nodelay: bool) {
        const SOL_TCP: c_int = 6;

        let optval: c_int = match nodelay {
            true => 1,
            false => 0
        };
        let opt_result = libc::setsockopt(self.fd,
                                          SOL_TCP,
                                          libc::SO_KEEPALIVE,
                                          &optval as *const _ as *const c_void,
                                          mem::size_of::<c_int>() as u32);
        if opt_result < 0 {
            error!("Setting TCP_NODELAY: {}",
                   Error::from_raw_os_error(errno().0 as i32));
        }
    }
}

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
        if buf.len() < 1 {
            return Err(Error::new(ErrorKind::Other, "Invalid buffer"));
        }

        let result = unsafe { libc::read(self.fd, buf as *mut _ as *mut c_void, buf.len()) };

        if result < 0 {
            return Err(Error::from_raw_os_error(errno().0 as i32));
        }

        if result == 0 {
            return Err(Error::new(ErrorKind::Other, "EOF"));
        }

        Ok(result as usize)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
        let result = unsafe { libc::write(self.fd, buf as *const _ as *const c_void, buf.len()) };

        if result < 0 {
            return Err(Error::from_raw_os_error(errno().0 as i32));
        }

        Ok(result as usize)
    }

    fn flush(&mut self) -> Result<(), Error> {
        Ok(())
    }
}

impl AsRawFd for Socket {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}
<commit_msg>Remote debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::mem;
use std::os::unix::io::{RawFd, AsRawFd};
use std::io::{Read, Write, Error, ErrorKind};

use libc;
use errno::errno;
use libc::{c_int, c_void};

#[derive(Clone)]
pub struct Socket {
    /// This socket's file descriptor
    pub fd: c_int,
}

impl Socket {

    pub unsafe fn set_tcp_keepalive(&self, keepalive: bool) {
        let optval: c_int = match keepalive {
            true => 1,
            false => 0
        };
        let opt_result = libc::setsockopt(self.fd,
                                          libc::SOL_SOCKET,
                                          libc::SO_KEEPALIVE,
                                          &optval as *const _ as *const c_void,
                                          mem::size_of::<c_int>() as u32);
        if opt_result < 0 {
            error!("Setting SO_KEEPALIVE: {}",
                   Error::from_raw_os_error(errno().0 as i32));
        }
    }

    pub unsafe fn set_tcp_nodelay(&self, nodelay: bool) {
        const SOL_TCP: c_int = 6;

        let optval: c_int = match nodelay {
            true => 1,
            false => 0
        };
        let opt_result = libc::setsockopt(self.fd,
                                          SOL_TCP,
                                          libc::SO_KEEPALIVE,
                                          &optval as *const _ as *const c_void,
                                          mem::size_of::<c_int>() as u32);
        if opt_result < 0 {
            error!("Setting TCP_NODELAY: {}",
                   Error::from_raw_os_error(errno().0 as i32));
        }
    }
}

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
        if buf.len() < 1 {
            return Err(Error::new(ErrorKind::Other, "Invalid buffer"));
        }

        let result = unsafe { libc::read(self.fd, buf as *mut _ as *mut c_void, buf.len()) };

        if result < 0 {
            return Err(Error::from_raw_os_error(errno().0 as i32));
        }

        if result == 0 {
            return Err(Error::new(ErrorKind::Other, "EOF"));
        }

        Ok(result as usize)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
        let result = unsafe { libc::write(self.fd, buf as *const _ as *const c_void, buf.len()) };

        if result < 0 {
            return Err(Error::from_raw_os_error(errno().0 as i32));
        }

        Ok(result as usize)
    }

    fn flush(&mut self) -> Result<(), Error> {
        Ok(())
    }
}

impl AsRawFd for Socket {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}
<|endoftext|>


<commit_before>pub use expectest::prelude::be_ok;

pub use sql::lexer::Token::{IdentT, NumberT, StringT, Semicolon, EqualSign, LeftParenthesis, RightParenthesis, Comma};
pub use sql::parser::Condition::{Eq};
pub use sql::parser::Parser;
pub use sql::parser::Node::{Delete, From, Where, Id, Const, Table, Values, Insert, Column};

describe! parser {

    describe! delete_statements {

        it "parses delete statement" {
            let tokens = vec![
                IdentT("delete".to_owned()),
                IdentT("from".to_owned()),
                IdentT("table_name".to_owned()), Semicolon
            ];

            expect!(tokens.parse())
                .to(be_ok().value(
                    Delete(
                        Box::new(From("table_name".to_owned())),
                        Box::new(Where(None))
                    )
                ));
        }

        it "parses delete statement with predicate" {
            let tokens = vec![
                IdentT("delete".to_owned()),
                IdentT("from".to_owned()),
                IdentT("table_name".to_owned()),
                IdentT("where".to_owned()),
                IdentT("col".to_owned()),
                EqualSign,
                NumberT("5".to_owned()),
                Semicolon
            ];

            expect!(tokens.parse())
                .to(be_ok().value(
                    Delete(
                        Box::new(From("table_name".to_owned())),
                        Box::new(Where(Some(
                            Eq(
                                Box::new(Id("col".to_owned())),
                                Box::new(Const("5".to_owned()))
                            )
                        )))
                    )
                ));
        }
    }

    describe! insert_statements {

        it "parses insert statement" {
            let tokens = vec![
                IdentT("insert".to_owned()),
                IdentT("into".to_owned()),
                IdentT("table_name".to_owned()),
                IdentT("values".to_owned()),
                LeftParenthesis,
                NumberT("10".to_owned()),
                Comma,
                StringT("string".to_owned()),
                RightParenthesis,
                Semicolon
            ];

            expect!(tokens.parse())
                .to(be_ok().value(
                    Insert(
                        Box::new(Table("table_name".to_owned(), None)),
                        Box::new(Values(vec![Const("10".to_owned()), Const("string".to_owned())]))
                    )
                ));
        }

        it "parses insert statement with columns" {
            let tokens = vec![
                IdentT("insert".to_owned()),
                IdentT("into".to_owned()),
                IdentT("table_name".to_owned()),
                LeftParenthesis,
                IdentT("col1".to_owned()),
                Comma,
                IdentT("col2".to_owned()),
                RightParenthesis,
                IdentT("values".to_owned()),
                LeftParenthesis,
                NumberT("10".to_owned()),
                Comma,
                StringT("string".to_owned()),
                RightParenthesis,
                Semicolon
            ];

            expect!(tokens.parse())
                .to(be_ok().value(
                    Insert(
                        Box::new(Table("table_name".to_owned(), Some(vec![Column("col1".to_owned(), None), Column("col2".to_owned(), None)]))),
                        Box::new(Values(vec![Const("10".to_owned()), Const("string".to_owned())]))
                    )
                ));
        }
    }
}
<commit_msg>parser test refactoring<commit_after>pub use expectest::prelude::be_ok;

pub use sql::lexer::Token::{self, IdentT, NumberT, StringT, Semicolon, EqualSign, LeftParenthesis, RightParenthesis, Comma};
pub use sql::parser::Condition::{Eq};
pub use sql::parser::Parser;
pub use sql::parser::Node::{Delete, From, Where, Id, Const, Table, Values, Insert, Column};

describe! parser {

    describe! delete_statements {

        it "parses delete statement" {
            let tokens = vec![delete(), from(), table_name(), Semicolon];

            expect!(tokens.parse())
                .to(be_ok().value(
                    Delete(
                        Box::new(From("table_name".to_owned())),
                        Box::new(Where(None))
                    )
                ));
        }

        it "parses delete statement with predicate" {
            let tokens = vec![delete(), from(), table_name(), where_t(), column_name(), EqualSign, five_int(), Semicolon];

            expect!(tokens.parse())
                .to(be_ok().value(
                    Delete(
                        Box::new(From("table_name".to_owned())),
                        Box::new(Where(Some(
                            Eq(
                                Box::new(Id("col".to_owned())),
                                Box::new(Const("5".to_owned()))
                            )
                        )))
                    )
                ));
        }
    }

    describe! insert_statements {

        it "parses insert statement" {
            let tokens = vec![insert(), into(), table_name(), values(), LeftParenthesis, ten_int(), Comma, string(), RightParenthesis, Semicolon];

            expect!(tokens.parse())
                .to(be_ok().value(
                    Insert(
                        Box::new(Table("table_name".to_owned(), None)),
                        Box::new(Values(vec![Const("10".to_owned()), Const("string".to_owned())]))
                    )
                ));
        }

        it "parses insert statement with columns" {
            let tokens = vec![
                insert(), into(), table_name(), LeftParenthesis, column_1_name(), Comma, column_2_name(), RightParenthesis,
                                    values(), LeftParenthesis, ten_int(), Comma, string(), RightParenthesis, Semicolon
            ];

            expect!(tokens.parse())
                .to(be_ok().value(
                    Insert(
                        Box::new(Table("table_name".to_owned(), Some(vec![Column("col1".to_owned()), Column("col2".to_owned())]))),
                        Box::new(Values(vec![Const("10".to_owned()), Const("string".to_owned())]))
                    )
                ));
        }
    }
}

pub fn delete() -> Token {
    IdentT("delete".to_owned())
}

pub fn from() -> Token {
    IdentT("from".to_owned())
}

pub fn where_t() -> Token {
    IdentT("where".to_owned())
}

pub fn column_name() -> Token {
    IdentT("col".to_owned())
}

pub fn five_int() -> Token {
    NumberT("5".to_owned())
}

pub fn insert() -> Token {
    IdentT("insert".to_owned())
}

pub fn into() -> Token {
    IdentT("into".to_owned())
}

pub fn table_name() -> Token {
    IdentT("table_name".to_owned())
}

pub fn column_1_name() -> Token {
    IdentT("col1".to_owned())
}

pub fn column_2_name() -> Token {
    IdentT("col2".to_owned())
}

pub fn values() -> Token {
    IdentT("values".to_owned())
}

pub fn ten_int() -> Token {
    NumberT("10".to_owned())
}

pub fn string() -> Token {
    StringT("string".to_owned())
}
<|endoftext|>